packet copy bugfix
[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 <algorithm>
16 #include <cstring>
17 #include <sstream>
18 #include <string>
19 #include <vector>
20
21 #if defined(_WIN32)
22 #include <winsock2.h>
23 #include <ws2tcpip.h>
24 #include <wspiapi.h>
25 #else
26 #include <arpa/inet.h>
27 #include <netdb.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
30 #if HAVE_FCNTL_H
31 #include <fcntl.h>
32 #else
33 #include <sys/ioctl.h>
34 #endif
35 #endif
36
37 #include <Moof/Log.hh>
38 #include <Moof/Packet.hh>
39 #include <Moof/Thread.hh>
40
41
42 #ifndef SO_NONBLOCK
43 #define SO_NONBLOCK 1024
44 #endif
45
46
47 namespace Mf {
48
49
50 class SocketAddress
51 {
52 public:
53
54 SocketAddress() :
55 mSize(0),
56 mType(0)
57 {
58 mAddr.sa.sa_family = AF_UNSPEC;
59 mAddr.in.sin_port = 0;
60 }
61
62 SocketAddress(const std::string& service, const std::string& name,
63 int type = SOCK_STREAM, int family = AF_UNSPEC)
64 {
65 init(service, name, type, family);
66 }
67
68 SocketAddress(const std::string& service,
69 int type = SOCK_STREAM, int family = AF_UNSPEC)
70 {
71 init(service, type, family);
72 }
73
74 SocketAddress(const struct addrinfo* addr, const std::string& name)
75 {
76 mType = addr->ai_socktype;
77 memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen);
78 mName = name;
79 mSize = addr->ai_addrlen;
80 }
81
82 SocketAddress(const struct sockaddr* addr, size_t size,
83 int type = SOCK_STREAM)
84 {
85 mType = type;
86 memcpy(&mAddr.sa, addr, size);
87 mSize = size;
88 setNameFromAddress();
89 }
90
91
92 static SocketAddress broadcast(const std::string& service)
93 {
94 std::istringstream stream(service);
95 unsigned short port;
96 stream >> port;
97
98 struct sockaddr_in addr;
99 addr.sin_family = AF_INET;
100 addr.sin_port = htons(port);
101 addr.sin_addr.s_addr = INADDR_BROADCAST;
102 memset(&addr.sin_zero, 0, sizeof(addr.sin_zero));
103 return SocketAddress((sockaddr*)&addr, sizeof(addr), SOCK_DGRAM);
104 }
105
106
107 void init(const std::string& service, const std::string& name = "",
108 int type = SOCK_STREAM, int family = AF_UNSPEC)
109 {
110 ASSERT(type == SOCK_STREAM || type == SOCK_DGRAM);
111 ASSERT(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
112
113 struct addrinfo hints;
114 memset(&hints, 0, sizeof(hints));
115 hints.ai_family = family;
116 hints.ai_socktype = type;
117 hints.ai_flags = AI_PASSIVE;
118
119 struct addrinfo* addr;
120 int status = getaddrinfo(name.length() > 0 ? name.c_str() : 0,
121 service.c_str(), &hints, &addr);
122 if (status == 0)
123 {
124 mType = addr->ai_socktype;
125 memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen);
126 mSize = addr->ai_addrlen;
127
128 if (name != "") mName = name;
129 else setNameFromAddress();
130
131 freeaddrinfo(addr);
132 }
133 else
134 {
135 Mf::logWarning(gai_strerror(status));
136 mType = 0;
137 mSize = 0;
138 mAddr.sa.sa_family = AF_UNSPEC;
139 mAddr.in.sin_port = 0;
140 }
141 }
142
143 void init(const std::string& service,
144 int type = SOCK_STREAM, int family = AF_UNSPEC)
145 {
146 init(service, "", type, family);
147 }
148
149
150 const std::string& name() const
151 {
152 return mName;
153 }
154
155 void setName(const std::string& name)
156 {
157 mName = name;
158 }
159
160 unsigned short port() const
161 {
162 return ntohs(mAddr.in.sin_port);
163 }
164
165 int type() const
166 {
167 return mType;
168 }
169
170 int family() const
171 {
172 return mAddr.sa.sa_family;
173 }
174
175
176 const struct sockaddr* address() const
177 {
178 return mSize != 0 ? &mAddr.sa : 0;
179 }
180
181 size_t size() const
182 {
183 return mSize;
184 }
185
186
187 static int resolve(const std::string& service, const std::string& name,
188 int type, int family, std::vector<SocketAddress>& resolved)
189 {
190 ASSERT(type == SOCK_STREAM || type == SOCK_DGRAM);
191 ASSERT(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
192
193 resolved.clear();
194
195 struct addrinfo hints;
196 memset(&hints, 0, sizeof(hints));
197 hints.ai_family = family;
198 hints.ai_socktype = type;
199 hints.ai_flags = AI_PASSIVE;
200
201 struct addrinfo* list;
202 int status = getaddrinfo(name.length() > 0 ? name.c_str() : 0,
203 service.length() > 0 ? service.c_str() : 0, &hints, &list);
204 if (status == 0)
205 {
206 for (struct addrinfo* addr = list;
207 addr != 0; addr = addr->ai_next)
208 {
209 resolved.push_back(SocketAddress(addr, name));
210 }
211
212 freeaddrinfo(list);
213 }
214 else
215 {
216 Mf::logWarning(gai_strerror(status));
217 return -1;
218 }
219
220 return 0;
221 }
222
223
224 private:
225
226 void setNameFromAddress()
227 {
228 #if defined(_WIN32)
229 // inet_ntop was introduced in Vista
230 mName = inet_ntoa(mAddr.in.sin_addr);
231 #else
232 char name[INET6_ADDRSTRLEN] = {'\0'};
233 inet_ntop(mAddr.sa.sa_family, &mAddr.sa, name, sizeof(name));
234 mName = name;
235 #endif
236 }
237
238
239 union
240 {
241 sockaddr sa;
242 sockaddr_in in;
243 sockaddr_storage storage;
244 } mAddr;
245 size_t mSize;
246 std::string mName;
247 int mType;
248 };
249
250
251 class Socket
252 {
253 struct Impl
254 {
255 int fd;
256 bool isConnected;
257 SocketAddress address;
258 };
259
260
261 public:
262
263 Socket() :
264 mFd(-1),
265 mIsConnected(false) {}
266
267 Socket(const SocketAddress& address) :
268 mFd(-1),
269 mIsConnected(false),
270 mAddress(address) {}
271
272 Socket(const std::string& service, const std::string& name,
273 int type = SOCK_STREAM, int family = AF_UNSPEC) :
274 mFd(-1),
275 mIsConnected(false),
276 mAddress(SocketAddress(service, name, type, family)) {}
277
278 Socket(const std::string& service,
279 int type = SOCK_STREAM, int family = AF_UNSPEC) :
280 mFd(-1),
281 mIsConnected(false),
282 mAddress(SocketAddress(service, type, family)) {}
283
284
285 Socket(Socket& move) :
286 mFd(move.mFd),
287 mIsConnected(move.mIsConnected),
288 mAddress(move.mAddress)
289 {
290 move.mFd = -1;
291 move.mIsConnected = false;
292 }
293
294 Socket(Impl move) :
295 mFd(move.fd),
296 mIsConnected(move.isConnected),
297 mAddress(move.address) {}
298
299 Socket& operator=(Socket& move)
300 {
301 #if defined(_WIN32)
302 if (mFd != -1) closesocket(mFd);
303 #else
304 if (mFd != -1) close(mFd);
305 #endif
306 mFd = move.mFd;
307 mIsConnected = move.mIsConnected;
308 mAddress = move.mAddress;
309 move.mFd = -1;
310 move.mIsConnected = false;
311 return *this;
312 }
313
314 Socket& operator=(Impl move)
315 {
316 #if defined(_WIN32)
317 if (mFd != -1) closesocket(mFd);
318 #else
319 if (mFd != -1) close(mFd);
320 #endif
321 mFd = move.fd;
322 mIsConnected = move.isConnected;
323 mAddress = move.address;
324 return *this;
325 }
326
327 operator Impl()
328 {
329 Impl impl;
330 impl.fd = mFd;
331 impl.isConnected = mIsConnected;
332 impl.address = mAddress;
333 mFd = -1;
334 mIsConnected = false;
335 return impl;
336 }
337
338
339 ~Socket()
340 {
341 #if defined(_WIN32)
342 if (mFd != -1) closesocket(mFd);
343 #else
344 if (mFd != -1) close(mFd);
345 #endif
346 }
347
348
349 bool isConnected() const
350 {
351 return mIsConnected;
352 }
353
354 const SocketAddress& address() const
355 {
356 return mAddress;
357 }
358
359
360 int connect()
361 {
362 if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0);
363 int result = ::connect(mFd, mAddress.address(), mAddress.size());
364 mIsConnected = result != -1;
365 return result;
366 }
367
368 int bind()
369 {
370 if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0);
371 return ::bind(mFd, mAddress.address(), mAddress.size());
372 }
373
374 int listen(int backlog = SOMAXCONN)
375 {
376 return ::listen(mFd, backlog > 0 ? backlog : SOMAXCONN);
377 }
378
379 int accept(Socket& socket)
380 {
381 Socket temp = Socket(mFd);
382 if (temp.mFd != -1)
383 {
384 socket = temp;
385 return socket.mFd;
386 }
387 return -1;
388 }
389
390
391 int set(int option, int value = 0)
392 {
393 if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0);
394 if (option == SO_NONBLOCK)
395 {
396 #ifdef HAVE_FCNTL
397 int flags = fcntl(mFd, F_GETFL);
398 return fcntl(mFd, F_SETFL, (value ? O_NONBLOCK : 0) | flags);
399 #else
400 return ioctl(mFd, FIONBIO, value);
401 #endif
402 }
403 return setsockopt(mFd, SOL_SOCKET, option, &value, sizeof(value));
404 }
405
406 int set(int option, const std::string& value)
407 {
408 if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0);
409 return setsockopt(mFd, SOL_SOCKET, option,
410 value.data(), value.length());
411 }
412
413 int get(int option, int& value)
414 {
415 if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0);
416 if (option == SO_NONBLOCK)
417 {
418 #ifdef HAVE_FCNTL
419 int flags = fcntl(mFd, F_GETFL);
420 return flags & O_NONBLOCK;
421 #else
422 return ioctl(mFd, FIONBIO, &value);
423 #endif
424 }
425 socklen_t optlen = sizeof(value);
426 return getsockopt(mFd, SOL_SOCKET, option, &value, &optlen);
427 }
428
429 int get(int option, std::string& value)
430 {
431 if (mFd == -1) mFd = socket(mAddress.family(), mAddress.type(), 0);
432 char str[64] = {'\0'};
433 socklen_t optlen = sizeof(str);
434 int result = getsockopt(mFd, SOL_SOCKET, option, &str, &optlen);
435 value = str;
436 return result;
437 }
438
439
440 ssize_t write(const void* bytes, size_t size)
441 {
442 return send(mFd, bytes, size, 0);
443 }
444 ssize_t write(const void* bytes, size_t size,
445 const SocketAddress& address)
446 {
447 return sendto(mFd, bytes, size, 0,
448 address.address(), address.size());
449 }
450
451 ssize_t write(const Packet& packet)
452 {
453 return write(packet.bytes(), packet.size());
454 }
455
456 ssize_t write(const Packet& packet, const SocketAddress& address)
457 {
458 return write(packet.bytes(), packet.size(), address);
459 }
460
461
462 ssize_t read(void* bytes, size_t size)
463 {
464 return recv(mFd, bytes, size, 0);
465 }
466
467 ssize_t read(void* bytes, size_t size, SocketAddress& address)
468 {
469 union
470 {
471 sockaddr sa;
472 sockaddr_storage storage;
473 } addr;
474 socklen_t length = sizeof(addr);
475
476 ssize_t result = recvfrom(mFd, bytes, size, 0, &addr.sa, &length);
477 if (result != -1)
478 {
479 address = SocketAddress(&addr.sa, length, mAddress.type());
480 }
481 return result;
482 }
483
484 ssize_t read(Packet& packet)
485 {
486 char buffer[65536];
487 ssize_t result = read(buffer, sizeof(buffer));
488 if (result != -1) packet = Packet(buffer, result);
489 return result;
490 }
491
492 ssize_t read(Packet& packet, SocketAddress& address)
493 {
494 char buffer[65536];
495 ssize_t result = read(buffer, sizeof(buffer), address);
496 if (result != -1) packet = Packet(buffer, result);
497 return result;
498 }
499
500
501 private:
502
503 Socket(int fd)
504 {
505 // for accepting a socket from fd
506 union
507 {
508 sockaddr sa;
509 sockaddr_storage storage;
510 } addr;
511 socklen_t length = sizeof(addr);
512
513 mFd = ::accept(fd, &addr.sa, &length);
514 if (mFd != -1)
515 {
516 mIsConnected = true;
517 mAddress = SocketAddress(&addr.sa, length);
518 }
519 }
520
521
522 int mFd;
523 bool mIsConnected;
524 SocketAddress mAddress;
525 };
526
527
528 class ResolverTask : public ThreadedTask
529 {
530 public:
531
532 ResolverTask(const std::string& service, const std::string& name,
533 int type = SOCK_STREAM, int family = AF_UNSPEC) :
534 mIsDone(false)
535 {
536 mFunction = boost::bind(&ResolverTask::resolve,
537 this, service, name, type, family);
538 }
539
540
541 bool isDone() const
542 {
543 return mIsDone;
544 }
545
546 void run()
547 {
548 if (!mThread) mThread = Mf::detachFunction(mFunction);
549 }
550
551
552 const std::vector<SocketAddress>& addresses() const
553 {
554 return mAddressList;
555 }
556
557
558 private:
559
560 int resolve(const std::string& service, const std::string& name,
561 int type, int family)
562 {
563 int status = SocketAddress::resolve(service, name,
564 type, family, mAddressList);
565 mIsDone = true;
566 return status;
567 }
568
569
570 std::vector<SocketAddress> mAddressList;
571 bool mIsDone;
572 Function mFunction;
573 };
574
575
576 } // namespace Mf
577
578 #endif // _MOOF_SOCKET_HH_
579
This page took 0.05719 seconds and 4 git commands to generate.