]>
Dogcows Code - chaz/yoink/blob - src/moof/socket.hh
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
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.
10 **************************************************************************/
12 #ifndef _MOOF_SOCKET_HH_
13 #define _MOOF_SOCKET_HH_
17 * Network-related classes, including a reinterpreted sockets API.
33 #define SHUT_RD SD_RECEIVE
34 #define SHUT_WR SD_SEND
35 #define SHUT_RDWR SD_BOTH
37 #include <arpa/inet.h>
39 #include <sys/socket.h>
40 #include <sys/types.h>
43 #include <moof/debug.hh>
44 #include <moof/packet.hh>
45 #include <moof/thread.hh>
49 #define AI_ADDRCONFIG 0
61 * The socket class represents a connection or between this node and a
69 * A class to represent the address of a remote host, including the
70 * type of service and socket communication.
77 * Construct an unspecified address.
83 addr_
.sa
.sa_family
= AF_UNSPEC
;
84 addr_
.in
.sin_port
= 0;
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
94 * \param family The family; can be AF_INET or AF_INET6.
96 address(const std::string
& service
,
97 const std::string
& name
,
98 int type
= SOCK_STREAM
,
99 int family
= AF_UNSPEC
)
101 init(service
, name
, type
, family
);
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
110 * \param family The family; can be AF_INET or AF_INET6.
112 explicit address(const std::string
& service
,
113 int type
= SOCK_STREAM
,
114 int family
= AF_UNSPEC
)
116 init(service
, type
, family
);
120 * Construct an address from the information in an addrinfo
122 * \param addr The addrinfo structure.
124 address(const struct addrinfo
* addr
) :
125 size_(addr
->ai_addrlen
),
126 type_(addr
->ai_socktype
)
128 memcpy(&addr_
.sa
, addr
->ai_addr
, addr
->ai_addrlen
);
129 get_name_and_service(name_
, service_
);
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
139 address(const struct sockaddr
* addr
,
141 int type
= SOCK_STREAM
) :
145 memcpy(&addr_
.sa
, addr
, size
);
146 get_name_and_service(name_
, service_
);
151 * Get an IPv4 broadcast address.
152 * \param service The service name or port number.
153 * \return The socket address.
155 static address
broadcast(const std::string
& service
)
157 std::istringstream
stream(service
);
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
),
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
178 * \param family The family; can be AF_INET or AF_INET6.
180 void init(const std::string
& service
,
181 const std::string
& name
,
182 int type
= SOCK_STREAM
,
183 int family
= AF_UNSPEC
)
185 const int flags
= AI_ADDRCONFIG
| AI_NUMERICHOST
| AI_V4MAPPED
;
186 struct addrinfo
* addr
= resolve(service
.c_str(), name
.c_str(),
191 size_
= addr
->ai_addrlen
;
192 type_
= addr
->ai_socktype
;
193 memcpy(&addr_
.sa
, addr
->ai_addr
, addr
->ai_addrlen
);
204 addr_
.sa
.sa_family
= AF_UNSPEC
;
205 addr_
.in
.sin_port
= 0;
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
215 * \param family The family; can be AF_INET or AF_INET6.
217 void init(const std::string
& service
,
218 int type
= SOCK_STREAM
,
219 int family
= AF_UNSPEC
)
221 struct addrinfo
* addr
= resolve(service
.c_str(), 0,
226 size_
= addr
->ai_addrlen
;
227 type_
= addr
->ai_socktype
;
228 memcpy(&addr_
.sa
, addr
->ai_addr
, addr
->ai_addrlen
);
239 addr_
.sa
.sa_family
= AF_UNSPEC
;
240 addr_
.in
.sin_port
= 0;
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.
250 const std::string
& service() const
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
261 const std::string
& name() const
267 * Get the port number of the address service.
268 * \return Port number.
270 unsigned short port() const
272 return ntohs(addr_
.in
.sin_port
);
276 * Get the type of socket associated with the service of this
278 * \return Socket type; either SOCK_STREAM or SOCK_DGRAM.
286 * Get the family of the protocol associated with the address.
287 * \return Protocol family; either AF_INET, AF_INET6, or AF_UNSPEC.
291 return addr_
.sa
.sa_family
;
296 * Get the sockaddr structure of the address.
297 * \return The sockaddr structure.
299 const struct sockaddr
* sockaddr() const
301 return size_
!= 0 ? &addr_
.sa
: 0;
305 * Get the size of the sockaddr structure of the address.
306 * \return The size of the sockaddr structure.
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
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.
327 static int resolve(const std::string
& service
,
328 const std::string
& name
,
331 std::vector
<address
>& resolved
)
333 struct addrinfo
* list
= resolve(service
.c_str(), name
.c_str(),
335 AI_ADDRCONFIG
| AI_V4MAPPED
);
336 int result
= collect_addresses(list
, resolved
);
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
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.
351 static int resolve(const std::string
& service
,
354 std::vector
<address
>& resolved
)
356 struct addrinfo
* list
= resolve(service
.c_str(), 0,
359 int result
= collect_addresses(list
, resolved
);
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.
372 void get_name(std::string
& name
, int flags
= NI_NUMERICHOST
)
374 char node
[256] = {'\0'};
375 int result
= getnameinfo(&addr_
.sa
, size_
,
379 if (result
== 0) name
.assign(node
);
383 * Resolve the service name of the address.
384 * \param service The place to store the service name or port
386 * \param flags The getnameinfo flags.
388 void get_service(std::string
& service
, int flags
)
390 flags
|= type_
== SOCK_DGRAM
? NI_DGRAM
: 0;
392 char serv
[64] = {'\0'};
393 int result
= getnameinfo(&addr_
.sa
, size_
,
397 if (result
== 0) service
.assign(serv
);
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
405 * \param name The place to store the hostname or IP address.
406 * \param service The place to store the service name or port
408 * \param flags The getnameinfo flags.
410 void get_name_and_service(std::string
& name
,
411 std::string
& service
,
412 int flags
= NI_NUMERICHOST
)
414 flags
|= type_
== SOCK_DGRAM
? NI_DGRAM
: 0;
416 char serv
[64] = {'\0'};
417 char node
[256] = {'\0'};
418 int result
= getnameinfo(&addr_
.sa
, size_
,
424 service
.assign(serv
);
432 static struct addrinfo
* resolve(const char* service
,
438 ASSERT(type
== SOCK_STREAM
|| type
== SOCK_DGRAM
);
439 ASSERT(family
== AF_INET
|| family
== AF_INET6
|| family
== AF_UNSPEC
);
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
;
447 struct addrinfo
* addr
;
448 int status
= getaddrinfo(node
, service
, &hints
, &addr
);
456 log_warning(gai_strerror(status
));
461 static int collect_addresses(struct addrinfo
* addresses
,
462 std::vector
<address
>& resolved
)
468 for (struct addrinfo
* addr
= addresses
;
470 addr
= addr
->ai_next
)
472 resolved
.push_back(address(addr
));
484 struct sockaddr_in in
;
485 struct sockaddr_storage storage
;
491 std::string service_
;
499 socket::address address
;
505 is_connected(false) {}
507 impl(const socket::address
& address
, int flags
= 0) :
509 fd(::socket(address
.family(), address
.type(), flags
)),
510 is_connected(false) {}
517 * Construct a socket with no associated peer.
522 * Construct a socket with an address.
523 * \param address The address.
524 * \param flags The socket options.
526 socket(const address
& address
, int flags
= 0) :
527 impl_(address
, flags
) {}
530 * Construct a socket with a specified host. The socket can be used to
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.
538 socket(const std::string
& service
,
539 const std::string
& name
,
540 int type
= SOCK_STREAM
,
541 int family
= AF_UNSPEC
,
543 impl_(address(service
, name
, type
, family
), flags
) {}
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.
553 explicit socket(const std::string
& service
,
554 int type
= SOCK_STREAM
,
555 int family
= AF_UNSPEC
,
557 impl_(address(service
, type
, family
), flags
) {}
561 * Deconstruct the socket, closing it.
570 * Get whether or not the socket is connected.
571 * \return True if the socket is connected, false otherwise.
573 bool is_connected() const
575 return impl_
.is_connected
;
579 * Get the address associated with the socket.
581 const address
& peer_address() const
583 return impl_
.address
;
588 * Connect the socket to its peer.
589 * \return 0 on success, -1 on failure.
593 int result
= ::connect(impl_
.fd
,
594 impl_
.address
.sockaddr(),
595 impl_
.address
.size());
596 impl_
.is_connected
= result
!= -1;
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.
605 int disconnect(int flags
= SHUT_RDWR
)
607 return shutdown(impl_
.fd
, flags
);
612 * Bind the socket to interface and port number specified in the
614 * \return 0 on success, -1 on failure.
618 return ::bind(impl_
.fd
,
619 impl_
.address
.sockaddr(),
620 impl_
.address
.size());
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.
629 int listen(int backlog
= SOMAXCONN
)
631 return ::listen(impl_
.fd
, backlog
> 0 ? backlog
: SOMAXCONN
);
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.
640 int accept(socket
& socket
)
642 moof::socket temp
= moof::socket(impl_
.fd
);
643 if (temp
.impl_
.fd
!= -1)
646 return socket
.impl_
.fd
;
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.
660 int set(int option
, const T
& value
, int level
= SOL_SOCKET
)
663 return setsockopt(impl_
.fd
,
666 reinterpret_cast<const char*>(&value
),
669 return setsockopt(impl_
.fd
, level
, option
, &value
, sizeof(value
));
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.
680 int set(int option
, const std::string
& value
, int level
= SOL_SOCKET
)
682 return setsockopt(impl_
.fd
, level
, option
,
683 value
.data(), value
.length());
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.
694 int get(int option
, T
& value
, int level
= SOL_SOCKET
) const
696 int size
= sizeof(value
);
697 return getsockopt(impl_
.fd
, level
, option
, &value
, &size
);
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.
707 int get(int option
, std::string
& value
, int level
= SOL_SOCKET
) const
709 char str
[256] = {'\0'};
710 socklen_t size
= sizeof(str
);
713 int result
= getsockopt(impl_
.fd
,
716 reinterpret_cast<char*>(&str
),
719 int result
= getsockopt(impl_
.fd
, level
, option
, &str
, &size
);
721 value
.assign(str
, size
);
727 * Set the socket IO mode to either blocking or non-blocking.
728 * \param is_blocking True if the socket should block, false otherwise.
730 void is_blocking(bool is_blocking
)
733 u_long value
= is_blocking
;
734 ioctlsocket(impl_
.fd
, FIONBIO
, &value
);
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
);
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
746 * \return True if the socket blocks, false otherwise.
748 bool is_blocking() const
753 int flags
= fcntl(impl_
.fd
, F_GETFL
);
754 return !(flags
& O_NONBLOCK
);
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.
766 ssize_t
write(const void* bytes
, size_t size
, int flags
= 0)
769 return send(impl_
.fd
,
770 reinterpret_cast<const char *>(bytes
), size
,
773 return send(impl_
.fd
, bytes
, size
, flags
);
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.
786 ssize_t
write(const void* bytes
,
788 const address
& address
,
792 return sendto(impl_
.fd
,
793 reinterpret_cast<const char*>(bytes
), size
,
795 address
.sockaddr(), address
.size());
797 return sendto(impl_
.fd
, bytes
, size
, flags
,
798 address
.sockaddr(), address
.size());
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.
808 ssize_t
write(const packet
& packet
, int flags
= 0)
810 return write(packet
.bytes(), packet
.size(), flags
);
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.
821 ssize_t
write(const packet
& packet
,
822 const address
& address
,
825 return write(packet
.bytes(), packet
.size(), address
, flags
);
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.
836 ssize_t
read(void* bytes
, size_t size
, int flags
= 0)
839 ssize_t result
= recv(impl_
.fd
,
840 reinterpret_cast<char*>(bytes
), size
,
843 ssize_t result
= recv(impl_
.fd
, bytes
, size
, flags
);
845 if (result
== 0) impl_
.is_connected
= false;
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.
858 ssize_t
read(void* bytes
,
860 socket::address
& address
,
866 struct sockaddr_storage storage
;
868 socklen_t length
= sizeof(addr
);
871 ssize_t result
= recvfrom(impl_
.fd
,
872 reinterpret_cast<char*>(bytes
), size
,
876 ssize_t result
= recvfrom(impl_
.fd
, bytes
, size
, flags
,
881 address
= socket::address(&addr
.sa
, length
,
882 impl_
.address
.type());
884 else if (result
== 0)
886 impl_
.is_connected
= false;
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.
897 ssize_t
read(packet
& packet
, int flags
= 0)
900 ssize_t result
= read(buffer
, sizeof(buffer
), flags
);
901 if (result
!= -1) packet
= moof::packet(buffer
, result
);
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.
913 ssize_t
read(packet
& packet
, address
& address
, int flags
= 0)
916 ssize_t result
= read(buffer
, sizeof(buffer
), address
, flags
);
917 if (result
!= -1) packet
= moof::packet(buffer
, result
);
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.
925 socket(socket
& move
) :
929 move
.impl_
.is_connected
= false;
935 socket
& operator=(socket
& move
)
940 move
.impl_
.is_connected
= false;
944 socket
& operator=(impl move
)
955 impl_
.is_connected
= false;
964 // for accepting a socket from fd
968 struct sockaddr_storage storage
;
970 socklen_t length
= sizeof(addr
);
972 impl_
.fd
= ::accept(fd
, &addr
.sa
, &length
);
975 impl_
.is_connected
= true;
976 impl_
.address
= address(&addr
.sa
, length
);
983 if (impl_
.fd
!= -1) closesocket(impl_
.fd
);
985 if (impl_
.fd
!= -1) ::close(impl_
.fd
);
991 class socket_multiplexer
995 typedef boost::function
<int(socket_multiplexer
&,
997 const socket::address
&)> function
;
999 explicit socket_multiplexer(moof::socket sock
) :
1003 void socket(moof::socket sock
)
1005 MOOF_MUTEX_LOCK(mutex_
);
1009 moof::socket
& socket()
1015 std::vector
<function
>& protocols()
1021 void update(scalar t
, scalar dt
)
1023 socket::address address
;
1025 ssize_t bytes
= socket_
.read(packet
, address
);
1029 std::vector
<function
>::iterator it
;
1030 for (it
= protocols_
.begin(); it
< protocols_
.end(); ++it
)
1033 if ((*it
)(*this, packet
, address
)) break;
1047 moof::socket socket_
;
1048 std::vector
<function
> protocols_
;
1050 MOOF_DECLARE_MUTEX(mutex_
);
1055 * An asynchronous task to resolve addresses.
1057 class resolver_task
: public threaded_task
1062 * Construct a resolver task from a service and hostname.
1063 * \param service Server name or port number.
1064 * \param name The hostname or numeric address.
1065 * \param type The type of communication.
1066 * \param family The requested protocol family.
1068 resolver_task(const std::string
& service
,
1069 const std::string
& name
,
1070 int type
= SOCK_STREAM
,
1071 int family
= AF_UNSPEC
) :
1074 function_
= boost::bind(&resolver_task::resolve
,
1075 this, service
, name
, type
, family
);
1080 * Get whether or not the task is done.
1081 * \return True if the task has finished, false otherwise.
1083 bool is_done() const
1089 * Start the task. This does nothing if the task was already run or is
1090 * currently running.
1094 if (!is_done() && !thread_
.is_valid())
1096 thread_
= thread::detach(function_
);
1102 * Get the addresses resolved. This is filled and safe to access after
1103 * the task finishes.
1104 * \return List of addresses.
1107 const std::vector
<socket::address
>& addresses() const
1109 return address_list_
;
1115 int resolve(const std::string
& service
,
1116 const std::string
& name
,
1120 int status
= socket::address::resolve(service
, name
,
1128 std::vector
<socket::address
> address_list_
;
1130 thread::function function_
;
1135 * Insert a string representation of a socket address into a stream.
1136 * \param stream The output stream.
1137 * \param addr The socket address.
1138 * \return The stream.
1140 std::ostream
& operator << (std::ostream
& stream
, const socket::address
& addr
)
1142 stream
<< addr
.name() << ":" << addr
.service();
1147 * Insert a string representation of a socket into a stream.
1148 * \param stream The output stream.
1149 * \param addr The socket.
1150 * \return The stream.
1152 std::ostream
& operator << (std::ostream
& stream
, const socket
& sock
)
1154 stream
<< sock
.peer_address();
1161 #endif // _MOOF_SOCKET_HH_
This page took 0.109919 seconds and 4 git commands to generate.