win32 port of new sockets, with fixes
[chaz/yoink] / src / Moof / Socket.hh
1
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
4 *
5 * vi:ts=4 sw=4 tw=75
6 *
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
9 *
10 **************************************************************************/
11
12 #ifndef _MOOF_SOCKET_HH_
13 #define _MOOF_SOCKET_HH_
14
15 #include <cstring>
16 #include <sstream>
17 #include <string>
18 #include <vector>
19
20 #if defined(_WIN32)
21 #include <winsock2.h>
22 #include <ws2tcpip.h>
23 #include <wspiapi.h>
24 #else
25 #include <arpa/inet.h>
26 #include <netdb.h>
27 #include <sys/socket.h>
28 #include <sys/types.h>
29 #if HAVE_FCNTL_H
30 #include <fcntl.h>
31 #else
32 #include <sys/ioctl.h>
33 #endif
34 #endif
35
36 #include <Moof/Log.hh>
37 #include <Moof/Packet.hh>
38 #include <Moof/Thread.hh>
39
40
41 #ifndef SO_NONBLOCK
42 #define SO_NONBLOCK 1024
43 #endif
44
45
46 namespace Mf {
47
48
49 class SocketAddress
50 {
51 public:
52
53 SocketAddress() :
54 mSize(0),
55 mType(0)
56 {
57 mAddress.sa.sa_family = AF_UNSPEC;
58 mAddress.v4.sin_port = 0;
59 }
60
61 SocketAddress(const std::string& service, const std::string& name,
62 int type = SOCK_STREAM, int family = AF_UNSPEC)
63 {
64 init(service, name, type, family);
65 }
66
67 SocketAddress(const std::string& service,
68 int type = SOCK_STREAM, int family = AF_UNSPEC)
69 {
70 init(service, type, family);
71 }
72
73 SocketAddress(const struct addrinfo* addr, const std::string& name)
74 {
75 mType = addr->ai_socktype;
76 memcpy(&mAddress.sa, addr->ai_addr, addr->ai_addrlen);
77 mName = name;
78 mSize = addr->ai_addrlen;
79 }
80
81 SocketAddress(const struct sockaddr* addr, size_t size,
82 int type = SOCK_STREAM)
83 {
84 mType = type;
85 memcpy(&mAddress.sa, addr, size);
86 mSize = size;
87 setNameFromAddress();
88 }
89
90
91 static SocketAddress broadcast(const std::string& service)
92 {
93 return SocketAddress(service, "255.255.255.255", SOCK_DGRAM);
94 }
95
96
97 void init(const std::string& service, const std::string& name = "",
98 int type = SOCK_STREAM, int family = AF_UNSPEC)
99 {
100 ASSERT(type == SOCK_STREAM || type == SOCK_DGRAM);
101 ASSERT(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
102
103 struct addrinfo hints;
104 memset(&hints, 0, sizeof(hints));
105 hints.ai_family = family;
106 hints.ai_socktype = type;
107 hints.ai_flags = AI_PASSIVE;
108
109 struct addrinfo* addr;
110 int status = getaddrinfo(name.length() > 0 ? name.c_str() : 0,
111 service.c_str(), &hints, &addr);
112 if (status == 0)
113 {
114 mType = addr->ai_socktype;
115 memcpy(&mAddress.sa, addr->ai_addr, addr->ai_addrlen);
116 mSize = addr->ai_addrlen;
117
118 if (name != "") mName = name;
119 else setNameFromAddress();
120
121 freeaddrinfo(addr);
122 }
123 else
124 {
125 Mf::logWarning(gai_strerror(status));
126 mType = 0;
127 mSize = 0;
128 mAddress.sa.sa_family = AF_UNSPEC;
129 mAddress.v4.sin_port = 0;
130 }
131 }
132
133 void init(const std::string& service,
134 int type = SOCK_STREAM, int family = AF_UNSPEC)
135 {
136 init(service, "", type, family);
137 }
138
139
140 const std::string& name() const
141 {
142 return mName;
143 }
144
145 void setName(const std::string& name)
146 {
147 mName = name;
148 }
149
150 unsigned short port() const
151 {
152 return ntohs(mAddress.v4.sin_port);
153 }
154
155 int type() const
156 {
157 return mType;
158 }
159
160 int family() const
161 {
162 return mAddress.sa.sa_family;
163 }
164
165
166 const struct sockaddr* address() const
167 {
168 return mSize != 0 ? &mAddress.sa : 0;
169 }
170
171 size_t size() const
172 {
173 return mSize;
174 }
175
176
177 static int resolve(const std::string& service, const std::string& name,
178 int type, int family, std::vector<SocketAddress>& resolved)
179 {
180 ASSERT(type == SOCK_STREAM || type == SOCK_DGRAM);
181 ASSERT(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
182
183 resolved.clear();
184
185 struct addrinfo hints;
186 memset(&hints, 0, sizeof(hints));
187 hints.ai_family = family;
188 hints.ai_socktype = type;
189 hints.ai_flags = AI_PASSIVE;
190
191 struct addrinfo* list;
192 int status = getaddrinfo(name.length() > 0 ? name.c_str() : 0,
193 service.length() > 0 ? service.c_str() : 0, &hints, &list);
194 if (status == 0)
195 {
196 struct addrinfo* addr = list;
197 while (addr != 0)
198 {
199 resolved.push_back(SocketAddress(addr, name));
200 addr = addr->ai_next;
201 }
202
203 freeaddrinfo(list);
204 }
205 else
206 {
207 Mf::logWarning(gai_strerror(status));
208 }
209
210 return 0;
211 }
212
213
214 private:
215
216 void setNameFromAddress()
217 {
218 #if defined(_WIN32)
219 // inet_ntop was introduced in Vista
220 mName = inet_ntoa(mAddress.v4.sin_addr);
221 #else
222 char name[INET6_ADDRSTRLEN] = {'\0'};
223 inet_ntop(mAddress.sa.sa_family, &mAddress.sa, name, sizeof(name));
224 mName = name;
225 #endif
226 }
227
228
229 union
230 {
231 sockaddr sa;
232 sockaddr_in v4;
233 sockaddr_in6 v6;
234 sockaddr_storage storage;
235 } mAddress;
236 size_t mSize;
237 std::string mName;
238 int mType;
239 };
240
241
242 class Socket
243 {
244 public:
245
246 Socket(const SocketAddress& address) :
247 mFd(-1),
248 mAddress(address)
249 {
250 mFd = socket(address.family(), address.type(), 0);
251 }
252
253 ~Socket()
254 {
255 #if defined(_WIN32)
256 if (mFd != -1) closesocket(mFd);
257 #else
258 if (mFd != -1) close(mFd);
259 #endif
260 }
261
262
263 bool isConnected() const
264 {
265 return mFd != -1;
266 }
267
268 const SocketAddress& address() const
269 {
270 return mAddress;
271 }
272
273
274 int connect()
275 {
276 return ::connect(mFd, mAddress.address(), mAddress.size());
277 }
278
279 int bind()
280 {
281 return ::bind(mFd, mAddress.address(), mAddress.size());
282 }
283
284 int listen(int backlog = SOMAXCONN)
285 {
286 return ::listen(mFd, backlog > 0 ? backlog : SOMAXCONN);
287 }
288
289 Socket accept()
290 {
291 return Socket(mFd);
292 }
293
294
295 int set(int option, int value = 0)
296 {
297 if (option == SO_NONBLOCK)
298 {
299 #ifdef HAVE_FCNTL
300 int flags = fcntl(mFd, F_GETFL);
301 return fcntl(mFd, F_SETFL, (value ? O_NONBLOCK : 0) | flags);
302 #else
303 return ioctl(mFd, FIONBIO, value);
304 #endif
305 }
306 return setsockopt(mFd, SOL_SOCKET, option, &value, sizeof(value));
307 }
308
309 int set(int option, const std::string& value)
310 {
311 return setsockopt(mFd, SOL_SOCKET, option,
312 value.c_str(), value.length());
313 }
314
315 int get(int option, int& value)
316 {
317 if (option == SO_NONBLOCK)
318 {
319 #ifdef HAVE_FCNTL
320 int flags = fcntl(mFd, F_GETFL);
321 return flags & O_NONBLOCK;
322 #else
323 return ioctl(mFd, FIONBIO, &value);
324 #endif
325 }
326 socklen_t optlen = sizeof(value);
327 return getsockopt(mFd, SOL_SOCKET, option, &value, &optlen);
328 }
329
330 int get(int option, std::string& value)
331 {
332 char str[64] = {'\0'};
333 socklen_t optlen = sizeof(str);
334 int result = getsockopt(mFd, SOL_SOCKET, option, &str, &optlen);
335 value = str;
336 return result;
337 }
338
339 void write(const Packet& packet)
340 {
341 write(mAddress, packet);
342 }
343
344 void write(const SocketAddress& address, const Packet& packet)
345 {
346 sendto(mFd, packet.bytes(), packet.size(), 0,
347 address.address(), address.size());
348 }
349
350 Packet read()
351 {
352 char buffer[1024];
353 int size = recv(mFd, buffer, sizeof(buffer), 0);
354
355 return Packet(buffer, size);
356 }
357
358 Packet read(SocketAddress& address)
359 {
360 union
361 {
362 sockaddr sa;
363 sockaddr_storage storage;
364 } addr;
365 socklen_t length = sizeof(addr);
366
367 char buffer[1024];
368 int size = recvfrom(mFd, buffer, sizeof(buffer), 0,
369 &addr.sa, &length);
370
371 address = SocketAddress(&addr.sa, length, mAddress.type());
372 return Packet(buffer, size);
373 }
374
375
376 private:
377
378 Socket(int fd)
379 {
380 // for accepting a socket from fd
381 union
382 {
383 sockaddr sa;
384 sockaddr_storage storage;
385 } addr;
386 socklen_t length = sizeof(addr);
387
388 mFd = ::accept(fd, &addr.sa, &length);
389 mAddress = SocketAddress(&addr.sa, length);
390 }
391
392
393 int mFd;
394 SocketAddress mAddress;
395 };
396
397
398 class ResolverTask : public ThreadedTask
399 {
400 public:
401
402 ResolverTask(const std::string& service, const std::string& name,
403 int type = SOCK_STREAM, int family = AF_UNSPEC) :
404 mIsDone(false)
405 {
406 mFunction = boost::bind(&ResolverTask::resolve,
407 this, service, name, type, family);
408 }
409
410
411 bool isDone() const
412 {
413 return mIsDone;
414 }
415
416 void run()
417 {
418 if (!mThread) mThread = Mf::detachFunction(mFunction);
419 }
420
421
422 const std::vector<SocketAddress>& addresses() const
423 {
424 return mAddressList;
425 }
426
427
428 private:
429
430 int resolve(const std::string& service, const std::string& name,
431 int type, int family)
432 {
433 int status = SocketAddress::resolve(service, name,
434 type, family, mAddressList);
435 mIsDone = true;
436 return status;
437 }
438
439
440 std::vector<SocketAddress> mAddressList;
441 bool mIsDone;
442 Function mFunction;
443 };
444
445
446 } // namespace Mf
447
448 #endif // _MOOF_SOCKET_HH_
449
This page took 0.049455 seconds and 4 git commands to generate.