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