170
|
1 /* |
|
2 * Socket.cpp -- portable C++ socket wrappers |
|
3 * |
|
4 * Copyright (c) 2013, David Demelier <markand@malikania.fr> |
|
5 * |
|
6 * Permission to use, copy, modify, and/or distribute this software for any |
|
7 * purpose with or without fee is hereby granted, provided that the above |
|
8 * copyright notice and this permission notice appear in all copies. |
|
9 * |
|
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
17 */ |
|
18 |
|
19 #include <cerrno> |
|
20 |
|
21 #include "Socket.h" |
|
22 #include "SocketAddress.h" |
|
23 |
|
24 /* -------------------------------------------------------- |
|
25 * SocketError implementation |
|
26 * -------------------------------------------------------- */ |
|
27 |
|
28 SocketError::SocketError(const std::string &error) |
|
29 { |
|
30 m_error = error; |
|
31 } |
|
32 |
|
33 const char *SocketError::what() const throw() |
|
34 { |
|
35 return m_error.c_str(); |
|
36 } |
|
37 |
|
38 /* -------------------------------------------------------- |
|
39 * Socket implementation |
|
40 * -------------------------------------------------------- */ |
|
41 |
|
42 void Socket::init() |
|
43 { |
|
44 #if defined(_WIN32) |
|
45 WSADATA wsa; |
|
46 WSAStartup(MAKEWORD(2, 2), &wsa); |
|
47 #endif |
|
48 } |
|
49 |
|
50 /* -------------------------------------------------------- |
|
51 * System dependent code |
|
52 * -------------------------------------------------------- */ |
|
53 |
|
54 #if defined(_WIN32) |
|
55 |
|
56 string Socket::getLastSysError() |
|
57 { |
|
58 LPSTR str = nullptr; |
|
59 string errmsg = "Unknown error"; |
|
60 |
|
61 FormatMessageA( |
|
62 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, |
|
63 NULL, |
|
64 WSAGetLastError(), |
|
65 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
|
66 (LPSTR)&str, 0, NULL); |
|
67 |
|
68 |
|
69 if (str) |
|
70 { |
|
71 errmsg = string(str); |
|
72 LocalFree(str); |
|
73 } |
|
74 |
|
75 return errmsg; |
|
76 } |
|
77 |
|
78 #else |
|
79 |
|
80 std::string Socket::getLastSysError() |
|
81 { |
|
82 return strerror(errno); |
|
83 } |
|
84 |
|
85 #endif |
|
86 |
|
87 void Socket::finish() |
|
88 { |
|
89 #if defined(_WIN32) |
|
90 WSACleanup(); |
|
91 #endif |
|
92 } |
|
93 |
|
94 Socket::Socket() |
|
95 { |
|
96 } |
|
97 |
|
98 Socket::Socket(int domain, int type, int protocol) |
|
99 { |
|
100 m_socket = socket(domain, type, protocol); |
|
101 |
|
102 if (m_socket == INVALID_SOCKET) |
|
103 throw SocketError(getLastSysError()); |
|
104 } |
|
105 |
|
106 Socket::Socket(Socket::Type sock) |
|
107 : m_socket(sock) |
|
108 { |
|
109 } |
|
110 |
|
111 Socket::~Socket() |
|
112 { |
|
113 } |
|
114 |
|
115 Socket::Type Socket::getSocket() const |
|
116 { |
|
117 return m_socket; |
|
118 } |
|
119 |
|
120 void Socket::set(int level, int name, const void *arg, unsigned argLen) |
|
121 { |
|
122 if (setsockopt(m_socket, level, name, (Socket::ConstArg)arg, argLen) == SOCKET_ERROR) |
|
123 throw SocketError(getLastSysError()); |
|
124 } |
|
125 |
|
126 void Socket::blockMode(bool block) |
|
127 { |
|
128 #if defined(O_NONBLOCK) && !defined(_WIN32) |
|
129 int flags; |
|
130 |
|
131 if ((flags = fcntl(m_socket, F_GETFL, 0)) == -1) |
|
132 flags = 0; |
|
133 |
|
134 if (!block) |
|
135 flags &= ~(O_NONBLOCK); |
|
136 else |
|
137 flags |= O_NONBLOCK; |
|
138 |
|
139 if (fcntl(m_socket, F_SETFL, flags) == -1) |
|
140 throw SocketError(getLastSysError()); |
|
141 #else |
|
142 unsigned long flags = (block) ? 0 : 1; |
|
143 |
|
144 if (ioctlsocket(m_socket, FIONBIO, &flags) == SOCKET_ERROR) |
|
145 throw SocketError(getLastSysError()); |
|
146 #endif |
|
147 } |
|
148 |
|
149 void Socket::bind(const SocketAddress &addr) |
|
150 { |
|
151 const sockaddr_storage &sa = addr.address(); |
|
152 size_t addrlen = addr.length(); |
|
153 |
|
154 if (::bind(m_socket, (sockaddr *)&sa, addrlen) == SOCKET_ERROR) |
|
155 throw SocketError(getLastSysError()); |
|
156 } |
|
157 |
|
158 void Socket::connect(const SocketAddress &addr) |
|
159 { |
|
160 const sockaddr_storage &sa = addr.address(); |
|
161 size_t addrlen = addr.length(); |
|
162 |
|
163 if (::connect(m_socket, (sockaddr *)&sa, addrlen) == SOCKET_ERROR) |
|
164 throw SocketError(getLastSysError()); |
|
165 } |
|
166 |
|
167 Socket Socket::accept() |
|
168 { |
|
169 SocketAddress dummy; |
|
170 |
|
171 return accept(dummy); |
|
172 } |
|
173 |
|
174 Socket Socket::accept(SocketAddress &info) |
|
175 { |
|
176 Socket::Type sock; |
|
177 |
|
178 info.m_addrlen = sizeof (sockaddr_storage); |
|
179 sock = ::accept(m_socket, (sockaddr *)&info.m_addr, &info.m_addrlen); |
|
180 |
|
181 if (sock == INVALID_SOCKET) |
|
182 throw SocketError(getLastSysError()); |
|
183 |
|
184 return Socket(sock); |
|
185 } |
|
186 |
|
187 void Socket::listen(int max) |
|
188 { |
|
189 if (::listen(m_socket, max) == SOCKET_ERROR) |
|
190 throw SocketError(getLastSysError()); |
|
191 } |
|
192 |
|
193 unsigned Socket::recv(void *data, unsigned dataLen) |
|
194 { |
|
195 int nbread; |
|
196 |
|
197 nbread = ::recv(m_socket, (Socket::Arg)data, dataLen, 0); |
|
198 if (nbread == SOCKET_ERROR) |
|
199 throw SocketError(getLastSysError()); |
|
200 |
|
201 return (unsigned)nbread; |
|
202 } |
|
203 |
|
204 unsigned Socket::send(const void *data, unsigned dataLen) |
|
205 { |
|
206 int nbsent; |
|
207 |
|
208 nbsent = ::send(m_socket, (Socket::ConstArg)data, dataLen, 0); |
|
209 if (nbsent == SOCKET_ERROR) |
|
210 throw SocketError(getLastSysError()); |
|
211 |
|
212 return (unsigned)nbsent; |
|
213 } |
|
214 |
|
215 unsigned Socket::send(const std::string &message) |
|
216 { |
|
217 return Socket::send(message.c_str(), message.length()); |
|
218 } |
|
219 |
|
220 unsigned Socket::recvfrom(void *data, unsigned dataLen) |
|
221 { |
|
222 SocketAddress dummy; |
|
223 |
|
224 return recvfrom(data, dataLen, dummy); |
|
225 } |
|
226 |
|
227 unsigned Socket::recvfrom(void *data, unsigned dataLen, SocketAddress &info) |
|
228 { |
|
229 int nbread; |
|
230 |
|
231 info.m_addrlen = sizeof (struct sockaddr_storage); |
|
232 nbread = ::recvfrom(m_socket, (Socket::Arg)data, dataLen, 0, |
|
233 (sockaddr *)&info.m_addr, &info.m_addrlen); |
|
234 |
|
235 if (nbread == SOCKET_ERROR) |
|
236 throw SocketError(getLastSysError()); |
|
237 |
|
238 return (unsigned)nbread; |
|
239 } |
|
240 |
|
241 unsigned Socket::sendto(const void *data, unsigned dataLen, const SocketAddress &info) |
|
242 { |
|
243 int nbsent; |
|
244 |
|
245 nbsent = ::sendto(m_socket, (Socket::ConstArg)data, dataLen, 0, |
|
246 (const sockaddr *)&info.m_addr, info.m_addrlen); |
|
247 if (nbsent == SOCKET_ERROR) |
|
248 throw SocketError(getLastSysError()); |
|
249 |
|
250 return (unsigned)nbsent; |
|
251 } |
|
252 |
|
253 unsigned Socket::sendto(const std::string &message, const SocketAddress &info) |
|
254 { |
|
255 return sendto(message.c_str(), message.length(), info); |
|
256 } |
|
257 |
|
258 void Socket::close() |
|
259 { |
|
260 (void)closesocket(m_socket); |
|
261 } |
|
262 |
|
263 bool operator==(const Socket &s1, const Socket &s2) |
|
264 { |
|
265 return s1.getSocket() == s2.getSocket(); |
|
266 } |