]> Dogcows Code - chaz/yoink/blob - src/Moof/Socket.hh
exception-aware packets; other misc socket changes
[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 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(mService, mName);
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(mService, mName);
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 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, size_t size,
733 const SocketAddress& address, int flags = 0)
734 {
735 return sendto(mImpl.fd, bytes, size, flags,
736 address.address(), address.size());
737 }
738
739 /**
740 * Write a packet to the socket. Use this for connected sockets.
741 * \param packet The packet.
742 * \param flags The send options.
743 * \return The number of bytes written.
744 */
745 ssize_t write(const Packet& packet, int flags = 0)
746 {
747 return write(packet.bytes(), packet.size(), flags);
748 }
749
750 /**
751 * Write a packet to the socket using the given address. Use this for
752 * unconnected sockets.
753 * \param packet The packet.
754 * \param address The address to send to.
755 * \param flags The send options.
756 * \return The number of bytes written.
757 */
758 ssize_t write(const Packet& packet, const SocketAddress& address,
759 int flags = 0)
760 {
761 return write(packet.bytes(), packet.size(), address, flags);
762 }
763
764
765 /**
766 * Read some bytes from the socket. Use this for connected sockets.
767 * \param bytes The buffer to store the bytes.
768 * \param size The size of the buffer.
769 * \param flags The recv options.
770 * \return The number of bytes read.
771 */
772 ssize_t read(void* bytes, size_t size, int flags = 0)
773 {
774 return recv(mImpl.fd, bytes, size, flags);
775 }
776
777 /**
778 * Read some bytes from the socket using the given address. Use this
779 * for unconnected sockets.
780 * \param bytes The buffer to store the bytes.
781 * \param size The size of the buffer.
782 * \param address The address to read from.
783 * \param flags The recv options.
784 * \return The number of bytes read.
785 */
786 ssize_t read(void* bytes, size_t size, SocketAddress& address,
787 int flags = 0)
788 {
789 union
790 {
791 sockaddr sa;
792 sockaddr_storage storage;
793 } addr;
794 socklen_t length = sizeof(addr);
795
796 ssize_t result = recvfrom(mImpl.fd, bytes, size, flags,
797 &addr.sa, &length);
798 if (result != -1)
799 {
800 address = SocketAddress(&addr.sa, length, mImpl.address.type());
801 }
802 return result;
803 }
804
805 /**
806 * Read a packet from the socket. Use this for connected sockets.
807 * \param packet Set to the packet read on return.
808 * \param flags The recv options.
809 * \return The number of bytes read.
810 */
811 ssize_t read(Packet& packet, int flags = 0)
812 {
813 char buffer[65536];
814 ssize_t result = read(buffer, sizeof(buffer), flags);
815 if (result != -1) packet = Packet(buffer, result);
816 return result;
817 }
818
819 /**
820 * Read a packet from the socket using the given address. Use this for
821 * unconnected sockets.
822 * \param packet Set to the packet read on return.
823 * \param address The address to read from.
824 * \param flags The recv options.
825 * \return The number of bytes read.
826 */
827 ssize_t read(Packet& packet, SocketAddress& address, int flags = 0)
828 {
829 char buffer[65536];
830 ssize_t result = read(buffer, sizeof(buffer), address, flags);
831 if (result != -1) packet = Packet(buffer, result);
832 return result;
833 }
834
835
836 // The rest of this junk is used to implement the "move" semantics
837 // correctly, since it makes no sense for socket objects to be copied.
838
839 Socket(Socket& move) :
840 mImpl(move.mImpl)
841 {
842 move.mImpl.fd = -1;
843 move.mImpl.isConnected = false;
844 }
845
846 Socket(Impl move) :
847 mImpl(move) {}
848
849 Socket& operator=(Socket& move)
850 {
851 close();
852 mImpl = move.mImpl;
853 move.mImpl.fd = -1;
854 move.mImpl.isConnected = false;
855 return *this;
856 }
857
858 Socket& operator=(Impl move)
859 {
860 close();
861 mImpl = move;
862 return *this;
863 }
864
865 operator Impl()
866 {
867 Impl impl(mImpl);
868 mImpl.fd = -1;
869 mImpl.isConnected = false;
870 return impl;
871 }
872
873
874 private:
875
876 Socket(int fd)
877 {
878 // for accepting a socket from fd
879 union
880 {
881 sockaddr sa;
882 sockaddr_storage storage;
883 } addr;
884 socklen_t length = sizeof(addr);
885
886 mImpl.fd = ::accept(fd, &addr.sa, &length);
887 if (mImpl.fd != -1)
888 {
889 mImpl.isConnected = true;
890 mImpl.address = SocketAddress(&addr.sa, length);
891 }
892 }
893
894 void close()
895 {
896 #if defined(_WIN32)
897 if (mImpl.fd != -1) closesocket(mImpl.fd);
898 #else
899 if (mImpl.fd != -1) ::close(mImpl.fd);
900 #endif
901 }
902 };
903
904
905 class SocketMultiplexer
906 {
907 public:
908
909 typedef boost::function<int(SocketMultiplexer&,
910 Packet&,
911 const SocketAddress&)> Function;
912
913 SocketMultiplexer(Socket sock) :
914 mSocket(sock) {}
915
916
917 void setSocket(Socket sock)
918 {
919 Mutex::ScopedLock lock(mMutex);
920 mSocket = sock;
921 }
922
923 Socket& socket()
924 {
925 return mSocket;
926 }
927
928
929 std::vector<Function>& protocols()
930 {
931 return mProtocols;
932 }
933
934
935 void update(Scalar t, Scalar dt)
936 {
937 SocketAddress address;
938 Packet packet;
939 ssize_t bytes = mSocket.read(packet, address);
940
941 if (bytes > 0)
942 {
943 std::vector<Function>::iterator it;
944 for (it = mProtocols.begin(); it < mProtocols.end(); ++it)
945 {
946 packet.reset();
947 if ((*it)(*this, packet, address)) break;
948 }
949 }
950 }
951
952
953 int background()
954 {
955 return 0;
956 }
957
958
959 private:
960
961 Socket mSocket;
962 std::vector<Function> mProtocols;
963 Mutex mMutex;
964 };
965
966
967 /**
968 * An asynchronous task to resolve addresses.
969 */
970 class ResolverTask : public ThreadedTask
971 {
972 public:
973
974 /**
975 * Construct a resolver task from a service and hostname.
976 * \param service Server name or port number.
977 * \param name The hostname or numeric address.
978 * \param type The type of communication.
979 * \param family The requested protocol family.
980 */
981 ResolverTask(const std::string& service,
982 const std::string& name,
983 int type = SOCK_STREAM,
984 int family = AF_UNSPEC) :
985 mIsDone(false)
986 {
987 mFunction = boost::bind(&ResolverTask::resolve,
988 this, service, name, type, family);
989 }
990
991
992 /**
993 * Get whether or not the task is done.
994 * \return True if the task has finished, false otherwise.
995 */
996 bool isDone() const
997 {
998 return mIsDone;
999 }
1000
1001 /**
1002 * Start the task. This does nothing if the task was already run or is
1003 * currently running.
1004 */
1005 void run()
1006 {
1007 if (!isDone() && !mThread.isValid())
1008 {
1009 mThread = Thread::detach(mFunction);
1010 }
1011 }
1012
1013
1014 /**
1015 * Get the addresses resolved. This is filled and safe to access after
1016 * the task finishes.
1017 * \return List of addresses.
1018 * \see isDone()
1019 */
1020 const std::vector<SocketAddress>& addresses() const
1021 {
1022 return mAddressList;
1023 }
1024
1025
1026 private:
1027
1028 int resolve(const std::string& service,
1029 const std::string& name,
1030 int type,
1031 int family)
1032 {
1033 int status = SocketAddress::resolve(service, name,
1034 type, family,
1035 mAddressList);
1036 mIsDone = true;
1037 return status;
1038 }
1039
1040
1041 std::vector<SocketAddress> mAddressList;
1042 bool mIsDone;
1043 Thread::Function mFunction;
1044 };
1045
1046
1047 std::ostream& operator<<(std::ostream& stream, const SocketAddress& addr)
1048 {
1049 stream << addr.name() << ":" << addr.service();
1050 return stream;
1051 }
1052
1053 std::ostream& operator<<(std::ostream& stream, const Socket& sock)
1054 {
1055 stream << sock.address();
1056 return stream;
1057 }
1058
1059
1060 } // namespace Mf
1061
1062 #endif // _MOOF_SOCKET_HH_
1063
This page took 0.088148 seconds and 5 git commands to generate.