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