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