]>
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.
30 #error No alternative to fcntl implemented yet.
37 #define SHUT_RD SD_RECEIVE
38 #define SHUT_WR SD_SEND
39 #define SHUT_RDWR SD_BOTH
41 #include <arpa/inet.h>
43 #include <sys/socket.h>
44 #include <sys/types.h>
47 #include <moof/log.hh>
48 #include <moof/packet.hh>
49 #include <moof/thread.hh>
53 #define AI_ADDRCONFIG 0
65 * The socket class represents a connection or between this node and a
73 * A class to represent the address of a remote host, including the
74 * type of service and socket communication.
81 * Construct an unspecified address.
87 addr_
.sa
.sa_family
= AF_UNSPEC
;
88 addr_
.in
.sin_port
= 0;
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
98 * \param family The family; can be AF_INET or AF_INET6.
100 address(const std::string
& service
,
101 const std::string
& name
,
102 int type
= SOCK_STREAM
,
103 int family
= AF_UNSPEC
)
105 init(service
, name
, type
, family
);
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
114 * \param family The family; can be AF_INET or AF_INET6.
116 explicit address(const std::string
& service
,
117 int type
= SOCK_STREAM
,
118 int family
= AF_UNSPEC
)
120 init(service
, type
, family
);
124 * Construct an address from the information in an addrinfo
126 * \param addr The addrinfo structure.
128 address(const struct addrinfo
* addr
) :
129 size_(addr
->ai_addrlen
),
130 type_(addr
->ai_socktype
)
132 memcpy(&addr_
.sa
, addr
->ai_addr
, addr
->ai_addrlen
);
133 get_name_and_service(name_
, service_
);
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
143 address(const struct sockaddr
* addr
,
145 int type
= SOCK_STREAM
) :
149 memcpy(&addr_
.sa
, addr
, size
);
150 get_name_and_service(name_
, service_
);
155 * Get an IPv4 broadcast address.
156 * \param service The service name or port number.
157 * \return The socket address.
159 static address
broadcast(const std::string
& service
)
161 std::istringstream
stream(service
);
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
),
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
182 * \param family The family; can be AF_INET or AF_INET6.
184 void init(const std::string
& service
,
185 const std::string
& name
,
186 int type
= SOCK_STREAM
,
187 int family
= AF_UNSPEC
)
189 const int flags
= AI_ADDRCONFIG
| AI_NUMERICHOST
| AI_V4MAPPED
;
190 struct addrinfo
* addr
= resolve(service
.c_str(), name
.c_str(),
195 size_
= addr
->ai_addrlen
;
196 type_
= addr
->ai_socktype
;
197 memcpy(&addr_
.sa
, addr
->ai_addr
, addr
->ai_addrlen
);
208 addr_
.sa
.sa_family
= AF_UNSPEC
;
209 addr_
.in
.sin_port
= 0;
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
219 * \param family The family; can be AF_INET or AF_INET6.
221 void init(const std::string
& service
,
222 int type
= SOCK_STREAM
,
223 int family
= AF_UNSPEC
)
225 struct addrinfo
* addr
= resolve(service
.c_str(), 0,
230 size_
= addr
->ai_addrlen
;
231 type_
= addr
->ai_socktype
;
232 memcpy(&addr_
.sa
, addr
->ai_addr
, addr
->ai_addrlen
);
243 addr_
.sa
.sa_family
= AF_UNSPEC
;
244 addr_
.in
.sin_port
= 0;
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.
254 const std::string
& service() const
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
265 const std::string
& name() const
271 * Get the port number of the address service.
272 * \return Port number.
274 unsigned short port() const
276 return ntohs(addr_
.in
.sin_port
);
280 * Get the type of socket associated with the service of this
282 * \return Socket type; either SOCK_STREAM or SOCK_DGRAM.
290 * Get the family of the protocol associated with the address.
291 * \return Protocol family; either AF_INET, AF_INET6, or AF_UNSPEC.
295 return addr_
.sa
.sa_family
;
300 * Get the sockaddr structure of the address.
301 * \return The sockaddr structure.
303 const struct sockaddr
* sockaddr() const
305 return size_
!= 0 ? &addr_
.sa
: 0;
309 * Get the size of the sockaddr structure of the address.
310 * \return The size of the sockaddr structure.
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
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.
331 static int resolve(const std::string
& service
,
332 const std::string
& name
,
335 std::vector
<address
>& resolved
)
337 struct addrinfo
* list
= resolve(service
.c_str(), name
.c_str(),
339 AI_ADDRCONFIG
| AI_V4MAPPED
);
340 int result
= collect_addresses(list
, resolved
);
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
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.
355 static int resolve(const std::string
& service
,
358 std::vector
<address
>& resolved
)
360 struct addrinfo
* list
= resolve(service
.c_str(), 0,
363 int result
= collect_addresses(list
, resolved
);
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.
376 void get_name(std::string
& name
, int flags
= NI_NUMERICHOST
)
378 char node
[256] = {'\0'};
379 int result
= getnameinfo(&addr_
.sa
, size_
,
383 if (result
== 0) name
.assign(node
);
387 * Resolve the service name of the address.
388 * \param service The place to store the service name or port
390 * \param flags The getnameinfo flags.
392 void get_service(std::string
& service
, int flags
)
394 flags
|= type_
== SOCK_DGRAM
? NI_DGRAM
: 0;
396 char serv
[64] = {'\0'};
397 int result
= getnameinfo(&addr_
.sa
, size_
,
401 if (result
== 0) service
.assign(serv
);
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
409 * \param name The place to store the hostname or IP address.
410 * \param service The place to store the service name or port
412 * \param flags The getnameinfo flags.
414 void get_name_and_service(std::string
& name
,
415 std::string
& service
,
416 int flags
= NI_NUMERICHOST
)
418 flags
|= type_
== SOCK_DGRAM
? NI_DGRAM
: 0;
420 char serv
[64] = {'\0'};
421 char node
[256] = {'\0'};
422 int result
= getnameinfo(&addr_
.sa
, size_
,
428 service
.assign(serv
);
436 static struct addrinfo
* resolve(const char* service
,
442 ASSERT(type
== SOCK_STREAM
|| type
== SOCK_DGRAM
);
443 ASSERT(family
== AF_INET
|| family
== AF_INET6
|| family
== AF_UNSPEC
);
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
;
451 struct addrinfo
* addr
;
452 int status
= getaddrinfo(node
, service
, &hints
, &addr
);
460 log_warning(gai_strerror(status
));
465 static int collect_addresses(struct addrinfo
* addresses
,
466 std::vector
<address
>& resolved
)
472 for (struct addrinfo
* addr
= addresses
;
474 addr
= addr
->ai_next
)
476 resolved
.push_back(address(addr
));
488 struct sockaddr_in in
;
489 struct sockaddr_storage storage
;
495 std::string service_
;
503 socket::address address
;
509 is_connected(false) {}
511 impl(const socket::address
& address
, int flags
= 0) :
513 fd(::socket(address
.family(), address
.type(), flags
)),
514 is_connected(false) {}
521 * Construct a socket with no associated peer.
526 * Construct a socket with an address.
527 * \param address The address.
528 * \param flags The socket options.
530 socket(const address
& address
, int flags
= 0) :
531 impl_(address
, flags
) {}
534 * Construct a socket with a specified host. The socket can be used to
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.
542 socket(const std::string
& service
,
543 const std::string
& name
,
544 int type
= SOCK_STREAM
,
545 int family
= AF_UNSPEC
,
547 impl_(address(service
, name
, type
, family
), flags
) {}
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.
557 explicit socket(const std::string
& service
,
558 int type
= SOCK_STREAM
,
559 int family
= AF_UNSPEC
,
561 impl_(address(service
, type
, family
), flags
) {}
565 * Deconstruct the socket, closing it.
574 * Get whether or not the socket is connected.
575 * \return True if the socket is connected, false otherwise.
577 bool is_connected() const
579 return impl_
.is_connected
;
583 * Get the address associated with the socket.
585 const address
& peer_address() const
587 return impl_
.address
;
592 * Connect the socket to its peer.
593 * \return 0 on success, -1 on failure.
597 int result
= ::connect(impl_
.fd
,
598 impl_
.address
.sockaddr(),
599 impl_
.address
.size());
600 impl_
.is_connected
= result
!= -1;
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.
609 int disconnect(int flags
= SHUT_RDWR
)
611 return shutdown(impl_
.fd
, flags
);
616 * Bind the socket to interface and port number specified in the
618 * \return 0 on success, -1 on failure.
622 return ::bind(impl_
.fd
,
623 impl_
.address
.sockaddr(),
624 impl_
.address
.size());
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.
633 int listen(int backlog
= SOMAXCONN
)
635 return ::listen(impl_
.fd
, backlog
> 0 ? backlog
: SOMAXCONN
);
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.
644 int accept(socket
& socket
)
646 moof::socket temp
= moof::socket(impl_
.fd
);
647 if (temp
.impl_
.fd
!= -1)
650 return socket
.impl_
.fd
;
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.
664 int set(int option
, const T
& value
, int level
= SOL_SOCKET
)
667 return setsockopt(impl_
.fd
,
670 reinterpret_cast<const char*>(&value
),
673 return setsockopt(impl_
.fd
, level
, option
, &value
, sizeof(value
));
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.
684 int set(int option
, const std::string
& value
, int level
= SOL_SOCKET
)
686 return setsockopt(impl_
.fd
, level
, option
,
687 value
.data(), value
.length());
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.
698 int get(int option
, T
& value
, int level
= SOL_SOCKET
) const
700 int size
= sizeof(value
);
701 return getsockopt(impl_
.fd
, level
, option
, &value
, &size
);
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.
711 int get(int option
, std::string
& value
, int level
= SOL_SOCKET
) const
713 char str
[256] = {'\0'};
714 socklen_t size
= sizeof(str
);
717 int result
= getsockopt(impl_
.fd
,
720 reinterpret_cast<char*>(&str
),
723 int result
= getsockopt(impl_
.fd
, level
, option
, &str
, &size
);
725 value
.assign(str
, size
);
731 * Set the socket IO mode to either blocking or non-blocking.
732 * \param is_blocking True if the socket should block, false otherwise.
734 void is_blocking(bool is_blocking
)
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
);
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
750 * \return True if the socket blocks, false otherwise.
752 bool is_blocking() const
755 int flags
= fcntl(impl_
.fd
, F_GETFL
);
756 return !(flags
& O_NONBLOCK
);
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.
769 ssize_t
write(const void* bytes
, size_t size
, int flags
= 0)
772 return send(impl_
.fd
,
773 reinterpret_cast<const char *>(bytes
), size
,
776 return send(impl_
.fd
, bytes
, size
, flags
);
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.
789 ssize_t
write(const void* bytes
,
791 const address
& address
,
795 return sendto(impl_
.fd
,
796 reinterpret_cast<const char*>(bytes
), size
,
798 address
.sockaddr(), address
.size());
800 return sendto(impl_
.fd
, bytes
, size
, flags
,
801 address
.sockaddr(), address
.size());
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.
811 ssize_t
write(const packet
& packet
, int flags
= 0)
813 return write(packet
.bytes(), packet
.size(), flags
);
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.
824 ssize_t
write(const packet
& packet
,
825 const address
& address
,
828 return write(packet
.bytes(), packet
.size(), address
, flags
);
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.
839 ssize_t
read(void* bytes
, size_t size
, int flags
= 0)
842 ssize_t result
= recv(impl_
.fd
,
843 reinterpret_cast<char*>(bytes
), size
,
846 ssize_t result
= recv(impl_
.fd
, bytes
, size
, flags
);
848 if (result
== 0) impl_
.is_connected
= false;
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.
861 ssize_t
read(void* bytes
,
863 socket::address
& address
,
869 struct sockaddr_storage storage
;
871 socklen_t length
= sizeof(addr
);
874 ssize_t result
= recvfrom(impl_
.fd
,
875 reinterpret_cast<char*>(bytes
), size
,
879 ssize_t result
= recvfrom(impl_
.fd
, bytes
, size
, flags
,
884 address
= socket::address(&addr
.sa
, length
,
885 impl_
.address
.type());
887 else if (result
== 0)
889 impl_
.is_connected
= false;
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.
900 ssize_t
read(packet
& packet
, int flags
= 0)
903 ssize_t result
= read(buffer
, sizeof(buffer
), flags
);
904 if (result
!= -1) packet
= moof::packet(buffer
, result
);
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.
916 ssize_t
read(packet
& packet
, address
& address
, int flags
= 0)
919 ssize_t result
= read(buffer
, sizeof(buffer
), address
, flags
);
920 if (result
!= -1) packet
= moof::packet(buffer
, result
);
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.
928 socket(socket
& move
) :
932 move
.impl_
.is_connected
= false;
938 socket
& operator=(socket
& move
)
943 move
.impl_
.is_connected
= false;
947 socket
& operator=(impl move
)
958 impl_
.is_connected
= false;
967 // for accepting a socket from fd
971 struct sockaddr_storage storage
;
973 socklen_t length
= sizeof(addr
);
975 impl_
.fd
= ::accept(fd
, &addr
.sa
, &length
);
978 impl_
.is_connected
= true;
979 impl_
.address
= address(&addr
.sa
, length
);
986 if (impl_
.fd
!= -1) closesocket(impl_
.fd
);
988 if (impl_
.fd
!= -1) ::close(impl_
.fd
);
994 class socket_multiplexer
998 typedef boost::function
<int(socket_multiplexer
&,
1000 const socket::address
&)> function
;
1002 explicit socket_multiplexer(moof::socket sock
) :
1006 void socket(moof::socket sock
)
1008 mutex::scoped_lock
lock(mutex_
);
1012 moof::socket
& socket()
1018 std::vector
<function
>& protocols()
1024 void update(scalar t
, scalar dt
)
1026 socket::address address
;
1028 ssize_t bytes
= socket_
.read(packet
, address
);
1032 std::vector
<function
>::iterator it
;
1033 for (it
= protocols_
.begin(); it
< protocols_
.end(); ++it
)
1036 if ((*it
)(*this, packet
, address
)) break;
1050 moof::socket socket_
;
1051 std::vector
<function
> protocols_
;
1057 * An asynchronous task to resolve addresses.
1059 class resolver_task
: public threaded_task
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.
1070 resolver_task(const std::string
& service
,
1071 const std::string
& name
,
1072 int type
= SOCK_STREAM
,
1073 int family
= AF_UNSPEC
) :
1076 function_
= boost::bind(&resolver_task::resolve
,
1077 this, service
, name
, type
, family
);
1082 * Get whether or not the task is done.
1083 * \return True if the task has finished, false otherwise.
1085 bool is_done() const
1091 * Start the task. This does nothing if the task was already run or is
1092 * currently running.
1096 if (!is_done() && !thread_
.is_valid())
1098 thread_
= thread::detach(function_
);
1104 * Get the addresses resolved. This is filled and safe to access after
1105 * the task finishes.
1106 * \return List of addresses.
1109 const std::vector
<socket::address
>& addresses() const
1111 return address_list_
;
1117 int resolve(const std::string
& service
,
1118 const std::string
& name
,
1122 int status
= socket::address::resolve(service
, name
,
1130 std::vector
<socket::address
> address_list_
;
1132 thread::function function_
;
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.
1142 std::ostream
& operator << (std::ostream
& stream
, const socket::address
& addr
)
1144 stream
<< addr
.name() << ":" << addr
.service();
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.
1154 std::ostream
& operator << (std::ostream
& stream
, const socket
& sock
)
1156 stream
<< sock
.peer_address();
1163 #endif // _MOOF_SOCKET_HH_
This page took 0.080368 seconds and 5 git commands to generate.