]> Dogcows Code - chaz/yoink/blob - src/Moof/Socket.hh
60fd8e054531aa080f7cc1740d6075664f3ffb18
[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 /**
13 * \file Socket.hh
14 * Network-related classes, including a reinterpreted sockets API.
15 */
16
17 #ifndef _MOOF_SOCKET_HH_
18 #define _MOOF_SOCKET_HH_
19
20 #include <algorithm>
21 #include <cstring>
22 #include <iostream>
23 #include <sstream>
24 #include <string>
25 #include <vector>
26
27 #if HAVE_FCNTL_H
28 #include <fcntl.h>
29 #else
30 #error No alternative to fcntl implemented yet.
31 #endif
32
33 #if defined(_WIN32)
34 #include <winsock2.h>
35 #include <ws2tcpip.h>
36 #include <wspiapi.h>
37 #define SHUT_RD SD_RECEIVE
38 #define SHUT_WR SD_SEND
39 #define SHUT_RDWR SD_BOTH
40 #else
41 #include <arpa/inet.h>
42 #include <netdb.h>
43 #include <sys/socket.h>
44 #include <sys/types.h>
45 #endif
46
47 #include <Moof/Log.hh>
48 #include <Moof/Packet.hh>
49 #include <Moof/Thread.hh>
50
51
52 #ifndef AI_ADDRCONFIG
53 #define AI_ADDRCONFIG 0
54 #endif
55
56 #ifndef AI_V4MAPPED
57 #define AI_V4MAPPED 0
58 #endif
59
60
61 namespace Mf {
62
63
64 /**
65 * A class to represent the address of a remote host, including the type of
66 * service and socket communication.
67 */
68 class SocketAddress
69 {
70 public:
71
72 /**
73 * Construct an unspecified address.
74 */
75 SocketAddress() :
76 mSize(0),
77 mType(0)
78 {
79 mAddr.sa.sa_family = AF_UNSPEC;
80 mAddr.in.sin_port = 0;
81 }
82
83 /**
84 * Construct an address with a specified host. The address can be used
85 * to connect to a host.
86 * \param service The service name or port number.
87 * \param name The numeric IP address of the host.
88 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
89 * \param family The family; can be AF_INET or AF_INET6.
90 */
91 SocketAddress(const std::string& service,
92 const std::string& name,
93 int type = SOCK_STREAM,
94 int family = AF_UNSPEC)
95 {
96 init(service, name, type, family);
97 }
98
99 /**
100 * Construct an address without a specified host. The address can be
101 * used to accept on a local port.
102 * \param service The service name or port number.
103 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
104 * \param family The family; can be AF_INET or AF_INET6.
105 */
106 explicit SocketAddress(const std::string& service,
107 int type = SOCK_STREAM,
108 int family = AF_UNSPEC)
109 {
110 init(service, type, family);
111 }
112
113 /**
114 * Construct an address from the information in an addrinfo structure.
115 * \param addr The addrinfo structure.
116 */
117 SocketAddress(const struct addrinfo* addr) :
118 mSize(addr->ai_addrlen),
119 mType(addr->ai_socktype)
120 {
121 memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen);
122 getNameAndService(mName, mService);
123 }
124
125 /**
126 * Construct an address from a sockaddr structure.
127 * \param addr The sockaddr structure.
128 * \param size The size of the sockaddr structure.
129 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
130 */
131 SocketAddress(const struct sockaddr* addr,
132 size_t size,
133 int type = SOCK_STREAM) :
134 mSize(size),
135 mType(type)
136 {
137 memcpy(&mAddr.sa, addr, size);
138 getNameAndService(mName, mService);
139 }
140
141
142 /**
143 * Get an IPv4 broadcast address.
144 * \param service The service name or port number.
145 * \return The socket address.
146 */
147 static SocketAddress broadcast(const std::string& service)
148 {
149 std::istringstream stream(service);
150 unsigned short port;
151 stream >> port;
152
153 struct sockaddr_in addr;
154 addr.sin_family = AF_INET;
155 addr.sin_port = htons(port);
156 addr.sin_addr.s_addr = INADDR_BROADCAST;
157 memset(&addr.sin_zero, 0, sizeof(addr.sin_zero));
158 return SocketAddress((sockaddr*)&addr, sizeof(addr), SOCK_DGRAM);
159 }
160
161
162 /**
163 * Initialize the address with a specified host. The address can be
164 * used to connect to a host.
165 * \param service The service name or port number.
166 * \param name The numeric IP address of the host.
167 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
168 * \param family The family; can be AF_INET or AF_INET6.
169 */
170 void init(const std::string& service,
171 const std::string& name,
172 int type = SOCK_STREAM,
173 int family = AF_UNSPEC)
174 {
175 struct addrinfo* addr = resolve(service.c_str(), name.c_str(),
176 type, family,
177 AI_ADDRCONFIG | AI_NUMERICHOST | AI_V4MAPPED);
178 if (addr)
179 {
180 mSize = addr->ai_addrlen;
181 mType = addr->ai_socktype;
182 memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen);
183
184 mService = service;
185 mName = name;
186
187 freeaddrinfo(addr);
188 }
189 else
190 {
191 mType = 0;
192 mSize = 0;
193 mAddr.sa.sa_family = AF_UNSPEC;
194 mAddr.in.sin_port = 0;
195 }
196 }
197
198 /**
199 * Initialize the address without a specified host. The address can be
200 * used to accept on a local port.
201 * \param service The service name or port number.
202 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
203 * \param family The family; can be AF_INET or AF_INET6.
204 */
205 void init(const std::string& service,
206 int type = SOCK_STREAM,
207 int family = AF_UNSPEC)
208 {
209 struct addrinfo* addr = resolve(service.c_str(), 0,
210 type, family,
211 AI_PASSIVE);
212 if (addr)
213 {
214 mSize = addr->ai_addrlen;
215 mType = addr->ai_socktype;
216 memcpy(&mAddr.sa, addr->ai_addr, addr->ai_addrlen);
217
218 mService = service;
219 getName(mName);
220
221 freeaddrinfo(addr);
222 }
223 else
224 {
225 mType = 0;
226 mSize = 0;
227 mAddr.sa.sa_family = AF_UNSPEC;
228 mAddr.in.sin_port = 0;
229 }
230 }
231
232
233 /**
234 * Get the name of the service. This could also be a port number if
235 * there is no service name associated with the number.
236 * \return The service.
237 */
238 const std::string& service() const
239 {
240 return mService;
241 }
242
243 /**
244 * Get the name of the host. This may be the host used to construct
245 * the address, or a resolved numeric host if none was used.
246 * \return The host.
247 */
248 const std::string& name() const
249 {
250 return mName;
251 }
252
253 /**
254 * Get the port number of the address service.
255 * \return Port number.
256 */
257 unsigned short port() const
258 {
259 return ntohs(mAddr.in.sin_port);
260 }
261
262 /**
263 * Get the type of socket associated with the service of this address.
264 * \return Socket type; either SOCK_STREAM or SOCK_DGRAM.
265 */
266 int type() const
267 {
268 return mType;
269 }
270
271 /**
272 * Get the family of the protocol associated with the address.
273 * \return Protocol family; either AF_INET, AF_INET6, or AF_UNSPEC.
274 */
275 int family() const
276 {
277 return mAddr.sa.sa_family;
278 }
279
280
281 /**
282 * Get the sockaddr structure of the address.
283 * \return The sockaddr structure.
284 */
285 const struct sockaddr* address() const
286 {
287 return mSize != 0 ? &mAddr.sa : 0;
288 }
289
290 /**
291 * Get the size of the sockaddr structure of the address.
292 * \return The size of the sockaddr structure.
293 */
294 size_t size() const
295 {
296 return mSize;
297 }
298
299
300 /**
301 * Get a list of addresses resolved to by the given search criteria.
302 * This can be used to perform lookups for name resolution, so this
303 * method may take some time to return. Use the ResolveTask class to
304 * resolve addresses asynchronously.
305 * \param service The service name or port number.
306 * \param name The name of the local or remote host.
307 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
308 * \param family The family; can be AF_INET or AF_INET6.
309 * \param resolved The list to be filled with addresses.
310 * \return 0 on success, -1 on error.
311 */
312 static int resolve(const std::string& service,
313 const std::string& name,
314 int type,
315 int family,
316 std::vector<SocketAddress>& resolved)
317 {
318 struct addrinfo* list = resolve(service.c_str(), name.c_str(),
319 type, family,
320 AI_ADDRCONFIG | AI_V4MAPPED);
321 int result = collectAddresses(list, resolved);
322 freeaddrinfo(list);
323 return result;
324 }
325
326 /**
327 * Get a list of addresses resolved to by the given search criteria.
328 * The addresses will be suitable for accepting on a local port.
329 * \param service The service name or port number.
330 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
331 * \param family The family; can be AF_INET or AF_INET6.
332 * \param resolved The list to be filled with addresses.
333 * \return 0 on success, -1 on error.
334 */
335 static int resolve(const std::string& service,
336 int type,
337 int family,
338 std::vector<SocketAddress>& resolved)
339 {
340 struct addrinfo* list = resolve(service.c_str(), 0,
341 type, family,
342 AI_PASSIVE);
343 int result = collectAddresses(list, resolved);
344 freeaddrinfo(list);
345 return result;
346 }
347
348
349 /**
350 * Resolve the hostname of the address. The default behavior is to
351 * avoid a reverse lookup by giving the numeric address. You can
352 * change that behavior with the getnameinfo flags.
353 * \param name The place to store the hostname or IP address.
354 * \param flags The getnameinfo flags.
355 */
356 void getName(std::string& name, int flags = NI_NUMERICHOST)
357 {
358 char node[256] = {'\0'};
359 int result = getnameinfo(&mAddr.sa, mSize,
360 node, sizeof(node),
361 0, 0,
362 flags);
363 if (result == 0) name.assign(node);
364 }
365
366 /**
367 * Resolve the service name of the address.
368 * \param service The place to store the service name or port number.
369 * \param flags The getnameinfo flags.
370 */
371 void getService(std::string& service, int flags)
372 {
373 flags |= mType == SOCK_DGRAM ? NI_DGRAM : 0;
374
375 char serv[64] = {'\0'};
376 int result = getnameinfo(&mAddr.sa, mSize,
377 0, 0,
378 serv, sizeof(serv),
379 flags);
380 if (result == 0) service.assign(serv);
381 }
382
383 /**
384 * Resolve the service and hostname of the address. The default
385 * behavior is to avoid a reverse lookup by giving the numeric address.
386 * You can change that behavior with the getnameinfo flags.
387 * \param name The place to store the hostname or IP address.
388 * \param service The place to store the service name or port number.
389 * \param flags The getnameinfo flags.
390 */
391 void getNameAndService(std::string& name,
392 std::string& service,
393 int flags = NI_NUMERICHOST)
394 {
395 flags |= mType == SOCK_DGRAM ? NI_DGRAM : 0;
396
397 char serv[64] = {'\0'};
398 char node[256] = {'\0'};
399 int result = getnameinfo(&mAddr.sa, mSize,
400 node, sizeof(node),
401 serv, sizeof(serv),
402 flags);
403 if (result == 0)
404 {
405 service.assign(serv);
406 name.assign(node);
407 }
408 }
409
410
411 private:
412
413 static struct addrinfo* resolve(const char* service,
414 const char* node,
415 int type,
416 int family,
417 int flags)
418 {
419 ASSERT(type == SOCK_STREAM || type == SOCK_DGRAM);
420 ASSERT(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
421
422 struct addrinfo hints;
423 memset(&hints, 0, sizeof(hints));
424 hints.ai_family = family;
425 hints.ai_socktype = type;
426 hints.ai_flags = flags;
427
428 struct addrinfo* addr;
429 int status = getaddrinfo(node, service, &hints, &addr);
430
431 if (status == 0)
432 {
433 return addr;
434 }
435 else
436 {
437 Mf::logWarning(gai_strerror(status));
438 return 0;
439 }
440 }
441
442 static int collectAddresses(struct addrinfo* addresses,
443 std::vector<SocketAddress>& resolved)
444 {
445 if (addresses)
446 {
447 resolved.clear();
448
449 for (struct addrinfo* addr = addresses;
450 addr != 0;
451 addr = addr->ai_next)
452 {
453 resolved.push_back(SocketAddress(addr));
454 }
455
456 return 0;
457 }
458 else return -1;
459 }
460
461
462 union
463 {
464 sockaddr sa;
465 sockaddr_in in;
466 sockaddr_storage storage;
467 } mAddr;
468 size_t mSize;
469 int mType;
470
471 std::string mName;
472 std::string mService;
473 };
474
475
476 /**
477 * The socket class represents a connection or between this node and a
478 * remote node.
479 */
480 class Socket
481 {
482 struct Impl
483 {
484 SocketAddress address;
485 int fd;
486 bool isConnected;
487
488 Impl() :
489 fd(-1),
490 isConnected(false) {}
491
492 Impl(const SocketAddress& address, int flags = 0) :
493 address(address),
494 fd(::socket(address.family(), address.type(), flags)),
495 isConnected(false) {}
496 } mImpl;
497
498
499 public:
500
501 /**
502 * Construct a socket with no associated peer.
503 */
504 Socket() {}
505
506 /**
507 * Construct a socket with an address.
508 * \param address The address.
509 * \param flags The socket options.
510 */
511 Socket(const SocketAddress& address, int flags = 0) :
512 mImpl(address, flags) {}
513
514 /**
515 * Construct a socket with a specified host. The socket can be used to
516 * connect to a host.
517 * \param service The service name or port number.
518 * \param name The numeric IP address of the host.
519 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
520 * \param family The family; can be AF_INET or AF_INET6.
521 * \param flags The socket options.
522 */
523 Socket(const std::string& service,
524 const std::string& name,
525 int type = SOCK_STREAM,
526 int family = AF_UNSPEC,
527 int flags = 0) :
528 mImpl(SocketAddress(service, name, type, family), flags) {}
529
530 /**
531 * Construct a socket without a specified host. The socket can be used
532 * to accept sockets on a local port.
533 * \param service The service name or port number.
534 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
535 * \param family The family; can be AF_INET or AF_INET6.
536 * \param flags The socket options.
537 */
538 explicit Socket(const std::string& service,
539 int type = SOCK_STREAM,
540 int family = AF_UNSPEC,
541 int flags = 0) :
542 mImpl(SocketAddress(service, type, family), flags) {}
543
544
545 /**
546 * Deconstruct the socket, closing it.
547 */
548 ~Socket()
549 {
550 close();
551 }
552
553
554 /**
555 * Get whether or not the socket is connected.
556 * \return True if the socket is connected, false otherwise.
557 */
558 bool isConnected() const
559 {
560 return mImpl.isConnected;
561 }
562
563 /**
564 * Get the address associated with the socket.
565 */
566 const SocketAddress& address() const
567 {
568 return mImpl.address;
569 }
570
571
572 /**
573 * Connect the socket to its peer.
574 * \return 0 on success, -1 on failure.
575 */
576 int connect()
577 {
578 int result = ::connect(mImpl.fd,
579 mImpl.address.address(),
580 mImpl.address.size());
581 mImpl.isConnected = result != -1;
582 return result;
583 }
584
585 /**
586 * Disconnect a connected socket from its peer.
587 * \param flags Specify the socket directions to close.
588 * \return 0 on success, -1 on failure.
589 */
590 int disconnect(int flags = SHUT_RDWR)
591 {
592 return shutdown(mImpl.fd, flags);
593 }
594
595
596 /**
597 * Bind the socket to interface and port number specified in the
598 * address.
599 * \return 0 on success, -1 on failure.
600 */
601 int bind()
602 {
603 return ::bind(mImpl.fd,
604 mImpl.address.address(),
605 mImpl.address.size());
606 }
607
608 /**
609 * Listen on the socket for incoming connections. This is only useful
610 * for sockets of type SOCK_STREAM.
611 * \param backlog The number of unaccepted connections to queue.
612 * \return 0 on success, -1 on failure.
613 */
614 int listen(int backlog = SOMAXCONN)
615 {
616 return ::listen(mImpl.fd, backlog > 0 ? backlog : SOMAXCONN);
617 }
618
619 /**
620 * Accept a new connection on the socket. This is only useful for
621 * sockets of type SOCK_STREAM.
622 * \param socket Set to the new socket on return.
623 * \return 0 on success, -1 on failure.
624 */
625 int accept(Socket& socket)
626 {
627 Socket temp = Socket(mImpl.fd);
628 if (temp.mImpl.fd != -1)
629 {
630 socket = temp;
631 return socket.mImpl.fd;
632 }
633 return -1;
634 }
635
636
637 /**
638 * Set an integer socket option.
639 * \param option The option to set.
640 * \param value The new value.
641 * \param level The layer to handle the option.
642 * \return 0 on success, -1 on failure.
643 */
644 template <class T>
645 int set(int option, const T& value, int level = SOL_SOCKET)
646 {
647 #if defined(_WIN32)
648 return setsockopt(mImpl.fd,
649 level,
650 option,
651 reinterpret_cast<const char*>(&value),
652 sizeof(value));
653 #else
654 return setsockopt(mImpl.fd, level, option, &value, sizeof(value));
655 #endif
656 }
657
658 /**
659 * Set a string socket option.
660 * \param option The option to set.
661 * \param value The new value.
662 * \param level The layer to handle the option.
663 * \return 0 on success, -1 on failure.
664 */
665 int set(int option, const std::string& value, int level = SOL_SOCKET)
666 {
667 return setsockopt(mImpl.fd, level, option,
668 value.data(), value.length());
669 }
670
671 /**
672 * Get an integer socket option.
673 * \param option The option to set.
674 * \param value The new value.
675 * \param level The layer to handle the option.
676 * \return 0 on success, -1 on failure.
677 */
678 template <class T>
679 int get(int option, T& value, int level = SOL_SOCKET) const
680 {
681 int size = sizeof(value);
682 return getsockopt(mImpl.fd, level, option, &value, &size);
683 }
684
685 /**
686 * Get a string socket option.
687 * \param option The option to set.
688 * \param value The new value.
689 * \param level The layer to handle the option.
690 * \return 0 on success, -1 on failure.
691 */
692 int get(int option, std::string& value, int level = SOL_SOCKET) const
693 {
694 char str[256] = {'\0'};
695 socklen_t size = sizeof(str);
696
697 #if defined(_WIN32)
698 int result = getsockopt(mImpl.fd,
699 level,
700 option,
701 reinterpret_cast<char*>(&str),
702 &size);
703 #else
704 int result = getsockopt(mImpl.fd, level, option, &str, &size);
705 #endif
706 value.assign(str, size);
707 return result;
708 }
709
710
711 /**
712 * Set the socket IO mode to either blocking or non-blocking.
713 * \param isBlocking True if the socket blocks, false otherwise.
714 */
715 void setBlocking(bool isBlocking)
716 {
717 #ifdef HAVE_FCNTL
718 int flags = fcntl(mImpl.fd, F_GETFL);
719 flags = isBlocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
720 fcntl(mImpl.fd, F_SETFL, flags);
721 #elif defined(_WIN32)
722 u_long value = isBlocking;
723 ioctlsocket(mImpl.fd, FIONBIO, &value);
724 #endif
725 }
726
727 /**
728 * Get whether or not the socket is blocking or non-blocking. If the
729 * IO mode can't be determined, this method will assume the socket is
730 * a blocking socket.
731 * \return True if the socket blocks, false otherwise.
732 */
733 bool isBlocking() const
734 {
735 #ifdef HAVE_FCNTL
736 int flags = fcntl(mImpl.fd, F_GETFL);
737 return !(flags & O_NONBLOCK);
738 #endif
739 return true;
740 }
741
742
743 /**
744 * Write some bytes to the socket. Use this for connected sockets.
745 * \param bytes The bytes.
746 * \param size The number of bytes.
747 * \param flags The send options.
748 * \return The number of bytes written.
749 */
750 ssize_t write(const void* bytes, size_t size, int flags = 0)
751 {
752 #if defined(_WIN32)
753 return send(mImpl.fd,
754 reinterpret_cast<const char *>(bytes), size,
755 flags);
756 #else
757 return send(mImpl.fd, bytes, size, flags);
758 #endif
759 }
760
761 /**
762 * Write some bytes to the socket using the given address. Use this
763 * for unconnected sockets.
764 * \param bytes The bytes.
765 * \param size The number of bytes.
766 * \param address The address to send to.
767 * \param flags The send options.
768 * \return The number of bytes written.
769 */
770 ssize_t write(const void* bytes,
771 size_t size,
772 const SocketAddress& address,
773 int flags = 0)
774 {
775 #if defined(_WIN32)
776 return sendto(mImpl.fd,
777 reinterpret_cast<const char*>(bytes), size,
778 flags,
779 address.address(), address.size());
780 #else
781 return sendto(mImpl.fd, bytes, size, flags,
782 address.address(), address.size());
783 #endif
784 }
785
786 /**
787 * Write a packet to the socket. Use this for connected sockets.
788 * \param packet The packet.
789 * \param flags The send options.
790 * \return The number of bytes written.
791 */
792 ssize_t write(const Packet& packet, int flags = 0)
793 {
794 return write(packet.bytes(), packet.size(), flags);
795 }
796
797 /**
798 * Write a packet to the socket using the given address. Use this for
799 * unconnected sockets.
800 * \param packet The packet.
801 * \param address The address to send to.
802 * \param flags The send options.
803 * \return The number of bytes written.
804 */
805 ssize_t write(const Packet& packet,
806 const SocketAddress& address,
807 int flags = 0)
808 {
809 return write(packet.bytes(), packet.size(), address, flags);
810 }
811
812
813 /**
814 * Read some bytes from the socket. Use this for connected sockets.
815 * \param bytes The buffer to store the bytes.
816 * \param size The size of the buffer.
817 * \param flags The recv options.
818 * \return The number of bytes read.
819 */
820 ssize_t read(void* bytes, size_t size, int flags = 0)
821 {
822 #if defined(_WIN32)
823 ssize_t result = recv(mImpl.fd,
824 reinterpret_cast<char*>(bytes), size,
825 flags);
826 #else
827 ssize_t result = recv(mImpl.fd, bytes, size, flags);
828 #endif
829 if (result == 0) mImpl.isConnected = false;
830 return result;
831 }
832
833 /**
834 * Read some bytes from the socket using the given address. Use this
835 * for unconnected sockets.
836 * \param bytes The buffer to store the bytes.
837 * \param size The size of the buffer.
838 * \param address The address to read from.
839 * \param flags The recv options.
840 * \return The number of bytes read.
841 */
842 ssize_t read(void* bytes,
843 size_t size,
844 SocketAddress& address,
845 int flags = 0)
846 {
847 union
848 {
849 sockaddr sa;
850 sockaddr_storage storage;
851 } addr;
852 socklen_t length = sizeof(addr);
853
854 #if defined(_WIN32)
855 ssize_t result = recvfrom(mImpl.fd,
856 reinterpret_cast<char*>(bytes), size,
857 flags,
858 &addr.sa, &length);
859 #else
860 ssize_t result = recvfrom(mImpl.fd, bytes, size, flags,
861 &addr.sa, &length);
862 #endif
863 if (result != -1)
864 {
865 address = SocketAddress(&addr.sa, length, mImpl.address.type());
866 }
867 else if (result == 0)
868 {
869 mImpl.isConnected = false;
870 }
871 return result;
872 }
873
874 /**
875 * Read a packet from the socket. Use this for connected sockets.
876 * \param packet Set to the packet read on return.
877 * \param flags The recv options.
878 * \return The number of bytes read.
879 */
880 ssize_t read(Packet& packet, int flags = 0)
881 {
882 char buffer[65536];
883 ssize_t result = read(buffer, sizeof(buffer), flags);
884 if (result != -1) packet = Packet(buffer, result);
885 return result;
886 }
887
888 /**
889 * Read a packet from the socket using the given address. Use this for
890 * unconnected sockets.
891 * \param packet Set to the packet read on return.
892 * \param address The address to read from.
893 * \param flags The recv options.
894 * \return The number of bytes read.
895 */
896 ssize_t read(Packet& packet, SocketAddress& address, int flags = 0)
897 {
898 char buffer[65536];
899 ssize_t result = read(buffer, sizeof(buffer), address, flags);
900 if (result != -1) packet = Packet(buffer, result);
901 return result;
902 }
903
904
905 // The rest of this junk is used to implement the "move" semantics
906 // correctly, since it makes no sense for socket objects to be copied.
907
908 Socket(Socket& move) :
909 mImpl(move.mImpl)
910 {
911 move.mImpl.fd = -1;
912 move.mImpl.isConnected = false;
913 }
914
915 Socket(Impl move) :
916 mImpl(move) {}
917
918 Socket& operator=(Socket& move)
919 {
920 close();
921 mImpl = move.mImpl;
922 move.mImpl.fd = -1;
923 move.mImpl.isConnected = false;
924 return *this;
925 }
926
927 Socket& operator=(Impl move)
928 {
929 close();
930 mImpl = move;
931 return *this;
932 }
933
934 operator Impl()
935 {
936 Impl impl(mImpl);
937 mImpl.fd = -1;
938 mImpl.isConnected = false;
939 return impl;
940 }
941
942
943 private:
944
945 Socket(int fd)
946 {
947 // for accepting a socket from fd
948 union
949 {
950 sockaddr sa;
951 sockaddr_storage storage;
952 } addr;
953 socklen_t length = sizeof(addr);
954
955 mImpl.fd = ::accept(fd, &addr.sa, &length);
956 if (mImpl.fd != -1)
957 {
958 mImpl.isConnected = true;
959 mImpl.address = SocketAddress(&addr.sa, length);
960 }
961 }
962
963 void close()
964 {
965 #if defined(_WIN32)
966 if (mImpl.fd != -1) closesocket(mImpl.fd);
967 #else
968 if (mImpl.fd != -1) ::close(mImpl.fd);
969 #endif
970 }
971 };
972
973
974 class SocketMultiplexer
975 {
976 public:
977
978 typedef boost::function<int(SocketMultiplexer&,
979 Packet&,
980 const SocketAddress&)> Function;
981
982 explicit SocketMultiplexer(Socket sock) :
983 mSocket(sock) {}
984
985
986 void setSocket(Socket sock)
987 {
988 Mutex::ScopedLock lock(mMutex);
989 mSocket = sock;
990 }
991
992 Socket& socket()
993 {
994 return mSocket;
995 }
996
997
998 std::vector<Function>& protocols()
999 {
1000 return mProtocols;
1001 }
1002
1003
1004 void update(Scalar t, Scalar dt)
1005 {
1006 SocketAddress address;
1007 Packet packet;
1008 ssize_t bytes = mSocket.read(packet, address);
1009
1010 if (bytes > 0)
1011 {
1012 std::vector<Function>::iterator it;
1013 for (it = mProtocols.begin(); it < mProtocols.end(); ++it)
1014 {
1015 packet.reset();
1016 if ((*it)(*this, packet, address)) break;
1017 }
1018 }
1019 }
1020
1021
1022 int background()
1023 {
1024 return 0;
1025 }
1026
1027
1028 private:
1029
1030 Socket mSocket;
1031 std::vector<Function> mProtocols;
1032 Mutex mMutex;
1033 };
1034
1035
1036 /**
1037 * An asynchronous task to resolve addresses.
1038 */
1039 class ResolverTask : public ThreadedTask
1040 {
1041 public:
1042
1043 /**
1044 * Construct a resolver task from a service and hostname.
1045 * \param service Server name or port number.
1046 * \param name The hostname or numeric address.
1047 * \param type The type of communication.
1048 * \param family The requested protocol family.
1049 */
1050 ResolverTask(const std::string& service,
1051 const std::string& name,
1052 int type = SOCK_STREAM,
1053 int family = AF_UNSPEC) :
1054 mIsDone(false)
1055 {
1056 mFunction = boost::bind(&ResolverTask::resolve,
1057 this, service, name, type, family);
1058 }
1059
1060
1061 /**
1062 * Get whether or not the task is done.
1063 * \return True if the task has finished, false otherwise.
1064 */
1065 bool isDone() const
1066 {
1067 return mIsDone;
1068 }
1069
1070 /**
1071 * Start the task. This does nothing if the task was already run or is
1072 * currently running.
1073 */
1074 void run()
1075 {
1076 if (!isDone() && !mThread.isValid())
1077 {
1078 mThread = Thread::detach(mFunction);
1079 }
1080 }
1081
1082
1083 /**
1084 * Get the addresses resolved. This is filled and safe to access after
1085 * the task finishes.
1086 * \return List of addresses.
1087 * \see isDone()
1088 */
1089 const std::vector<SocketAddress>& addresses() const
1090 {
1091 return mAddressList;
1092 }
1093
1094
1095 private:
1096
1097 int resolve(const std::string& service,
1098 const std::string& name,
1099 int type,
1100 int family)
1101 {
1102 int status = SocketAddress::resolve(service, name,
1103 type, family,
1104 mAddressList);
1105 mIsDone = true;
1106 return status;
1107 }
1108
1109
1110 std::vector<SocketAddress> mAddressList;
1111 bool mIsDone;
1112 Thread::Function mFunction;
1113 };
1114
1115
1116 std::ostream& operator<<(std::ostream& stream, const SocketAddress& addr)
1117 {
1118 stream << addr.name() << ":" << addr.service();
1119 return stream;
1120 }
1121
1122 std::ostream& operator<<(std::ostream& stream, const Socket& sock)
1123 {
1124 stream << sock.address();
1125 return stream;
1126 }
1127
1128
1129 } // namespace Mf
1130
1131 #endif // _MOOF_SOCKET_HH_
1132
This page took 0.080111 seconds and 3 git commands to generate.