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