]>
Dogcows Code - chaz/yoink/blob - src/Moof/Socket.hh
60fd8e054531aa080f7cc1740d6075664f3ffb18
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 **************************************************************************/
14 * Network-related classes, including a reinterpreted sockets API.
17 #ifndef _MOOF_SOCKET_HH_
18 #define _MOOF_SOCKET_HH_
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 * A class to represent the address of a remote host, including the type of
66 * service and socket communication.
73 * Construct an unspecified address.
79 mAddr
.sa
.sa_family
= AF_UNSPEC
;
80 mAddr
.in
.sin_port
= 0;
84 * Construct an address with a specified host. The address can be used
85 * to connect to a host.
86 * \param service The service name or port number.
87 * \param name The numeric IP address of the host.
88 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
89 * \param family The family; can be AF_INET or AF_INET6.
91 SocketAddress(const std::string
& service
,
92 const std::string
& name
,
93 int type
= SOCK_STREAM
,
94 int family
= AF_UNSPEC
)
96 init(service
, name
, type
, family
);
100 * Construct an address without a specified host. The address can be
101 * used to accept on a local port.
102 * \param service The service name or port number.
103 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
104 * \param family The family; can be AF_INET or AF_INET6.
106 explicit SocketAddress(const std::string
& service
,
107 int type
= SOCK_STREAM
,
108 int family
= AF_UNSPEC
)
110 init(service
, type
, family
);
114 * Construct an address from the information in an addrinfo structure.
115 * \param addr The addrinfo structure.
117 SocketAddress(const struct addrinfo
* addr
) :
118 mSize(addr
->ai_addrlen
),
119 mType(addr
->ai_socktype
)
121 memcpy(&mAddr
.sa
, addr
->ai_addr
, addr
->ai_addrlen
);
122 getNameAndService(mName
, mService
);
126 * Construct an address from a sockaddr structure.
127 * \param addr The sockaddr structure.
128 * \param size The size of the sockaddr structure.
129 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
131 SocketAddress(const struct sockaddr
* addr
,
133 int type
= SOCK_STREAM
) :
137 memcpy(&mAddr
.sa
, addr
, size
);
138 getNameAndService(mName
, mService
);
143 * Get an IPv4 broadcast address.
144 * \param service The service name or port number.
145 * \return The socket address.
147 static SocketAddress
broadcast(const std::string
& service
)
149 std::istringstream
stream(service
);
153 struct sockaddr_in addr
;
154 addr
.sin_family
= AF_INET
;
155 addr
.sin_port
= htons(port
);
156 addr
.sin_addr
.s_addr
= INADDR_BROADCAST
;
157 memset(&addr
.sin_zero
, 0, sizeof(addr
.sin_zero
));
158 return SocketAddress((sockaddr
*)&addr
, sizeof(addr
), SOCK_DGRAM
);
163 * Initialize the address with a specified host. The address can be
164 * used to connect to a host.
165 * \param service The service name or port number.
166 * \param name The numeric IP address of the host.
167 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
168 * \param family The family; can be AF_INET or AF_INET6.
170 void init(const std::string
& service
,
171 const std::string
& name
,
172 int type
= SOCK_STREAM
,
173 int family
= AF_UNSPEC
)
175 struct addrinfo
* addr
= resolve(service
.c_str(), name
.c_str(),
177 AI_ADDRCONFIG
| AI_NUMERICHOST
| AI_V4MAPPED
);
180 mSize
= addr
->ai_addrlen
;
181 mType
= addr
->ai_socktype
;
182 memcpy(&mAddr
.sa
, addr
->ai_addr
, addr
->ai_addrlen
);
193 mAddr
.sa
.sa_family
= AF_UNSPEC
;
194 mAddr
.in
.sin_port
= 0;
199 * Initialize the address without a specified host. The address can be
200 * used to accept on a local port.
201 * \param service The service name or port number.
202 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
203 * \param family The family; can be AF_INET or AF_INET6.
205 void init(const std::string
& service
,
206 int type
= SOCK_STREAM
,
207 int family
= AF_UNSPEC
)
209 struct addrinfo
* addr
= resolve(service
.c_str(), 0,
214 mSize
= addr
->ai_addrlen
;
215 mType
= addr
->ai_socktype
;
216 memcpy(&mAddr
.sa
, addr
->ai_addr
, addr
->ai_addrlen
);
227 mAddr
.sa
.sa_family
= AF_UNSPEC
;
228 mAddr
.in
.sin_port
= 0;
234 * Get the name of the service. This could also be a port number if
235 * there is no service name associated with the number.
236 * \return The service.
238 const std::string
& service() const
244 * Get the name of the host. This may be the host used to construct
245 * the address, or a resolved numeric host if none was used.
248 const std::string
& name() const
254 * Get the port number of the address service.
255 * \return Port number.
257 unsigned short port() const
259 return ntohs(mAddr
.in
.sin_port
);
263 * Get the type of socket associated with the service of this address.
264 * \return Socket type; either SOCK_STREAM or SOCK_DGRAM.
272 * Get the family of the protocol associated with the address.
273 * \return Protocol family; either AF_INET, AF_INET6, or AF_UNSPEC.
277 return mAddr
.sa
.sa_family
;
282 * Get the sockaddr structure of the address.
283 * \return The sockaddr structure.
285 const struct sockaddr
* address() const
287 return mSize
!= 0 ? &mAddr
.sa
: 0;
291 * Get the size of the sockaddr structure of the address.
292 * \return The size of the sockaddr structure.
301 * Get a list of addresses resolved to by the given search criteria.
302 * This can be used to perform lookups for name resolution, so this
303 * method may take some time to return. Use the ResolveTask class to
304 * resolve addresses asynchronously.
305 * \param service The service name or port number.
306 * \param name The name of the local or remote host.
307 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
308 * \param family The family; can be AF_INET or AF_INET6.
309 * \param resolved The list to be filled with addresses.
310 * \return 0 on success, -1 on error.
312 static int resolve(const std::string
& service
,
313 const std::string
& name
,
316 std::vector
<SocketAddress
>& resolved
)
318 struct addrinfo
* list
= resolve(service
.c_str(), name
.c_str(),
320 AI_ADDRCONFIG
| AI_V4MAPPED
);
321 int result
= collectAddresses(list
, resolved
);
327 * Get a list of addresses resolved to by the given search criteria.
328 * The addresses will be suitable for accepting on a local port.
329 * \param service The service name or port number.
330 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
331 * \param family The family; can be AF_INET or AF_INET6.
332 * \param resolved The list to be filled with addresses.
333 * \return 0 on success, -1 on error.
335 static int resolve(const std::string
& service
,
338 std::vector
<SocketAddress
>& resolved
)
340 struct addrinfo
* list
= resolve(service
.c_str(), 0,
343 int result
= collectAddresses(list
, resolved
);
350 * Resolve the hostname of the address. The default behavior is to
351 * avoid a reverse lookup by giving the numeric address. You can
352 * change that behavior with the getnameinfo flags.
353 * \param name The place to store the hostname or IP address.
354 * \param flags The getnameinfo flags.
356 void getName(std::string
& name
, int flags
= NI_NUMERICHOST
)
358 char node
[256] = {'\0'};
359 int result
= getnameinfo(&mAddr
.sa
, mSize
,
363 if (result
== 0) name
.assign(node
);
367 * Resolve the service name of the address.
368 * \param service The place to store the service name or port number.
369 * \param flags The getnameinfo flags.
371 void getService(std::string
& service
, int flags
)
373 flags
|= mType
== SOCK_DGRAM
? NI_DGRAM
: 0;
375 char serv
[64] = {'\0'};
376 int result
= getnameinfo(&mAddr
.sa
, mSize
,
380 if (result
== 0) service
.assign(serv
);
384 * Resolve the service and hostname of the address. The default
385 * behavior is to avoid a reverse lookup by giving the numeric address.
386 * You can change that behavior with the getnameinfo flags.
387 * \param name The place to store the hostname or IP address.
388 * \param service The place to store the service name or port number.
389 * \param flags The getnameinfo flags.
391 void getNameAndService(std::string
& name
,
392 std::string
& service
,
393 int flags
= NI_NUMERICHOST
)
395 flags
|= mType
== SOCK_DGRAM
? NI_DGRAM
: 0;
397 char serv
[64] = {'\0'};
398 char node
[256] = {'\0'};
399 int result
= getnameinfo(&mAddr
.sa
, mSize
,
405 service
.assign(serv
);
413 static struct addrinfo
* resolve(const char* service
,
419 ASSERT(type
== SOCK_STREAM
|| type
== SOCK_DGRAM
);
420 ASSERT(family
== AF_INET
|| family
== AF_INET6
|| family
== AF_UNSPEC
);
422 struct addrinfo hints
;
423 memset(&hints
, 0, sizeof(hints
));
424 hints
.ai_family
= family
;
425 hints
.ai_socktype
= type
;
426 hints
.ai_flags
= flags
;
428 struct addrinfo
* addr
;
429 int status
= getaddrinfo(node
, service
, &hints
, &addr
);
437 Mf::logWarning(gai_strerror(status
));
442 static int collectAddresses(struct addrinfo
* addresses
,
443 std::vector
<SocketAddress
>& resolved
)
449 for (struct addrinfo
* addr
= addresses
;
451 addr
= addr
->ai_next
)
453 resolved
.push_back(SocketAddress(addr
));
466 sockaddr_storage storage
;
472 std::string mService
;
477 * The socket class represents a connection or between this node and a
484 SocketAddress address
;
490 isConnected(false) {}
492 Impl(const SocketAddress
& address
, int flags
= 0) :
494 fd(::socket(address
.family(), address
.type(), flags
)),
495 isConnected(false) {}
502 * Construct a socket with no associated peer.
507 * Construct a socket with an address.
508 * \param address The address.
509 * \param flags The socket options.
511 Socket(const SocketAddress
& address
, int flags
= 0) :
512 mImpl(address
, flags
) {}
515 * Construct a socket with a specified host. The socket can be used to
517 * \param service The service name or port number.
518 * \param name The numeric IP address of the host.
519 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
520 * \param family The family; can be AF_INET or AF_INET6.
521 * \param flags The socket options.
523 Socket(const std::string
& service
,
524 const std::string
& name
,
525 int type
= SOCK_STREAM
,
526 int family
= AF_UNSPEC
,
528 mImpl(SocketAddress(service
, name
, type
, family
), flags
) {}
531 * Construct a socket without a specified host. The socket can be used
532 * to accept sockets on a local port.
533 * \param service The service name or port number.
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 explicit Socket(const std::string
& service
,
539 int type
= SOCK_STREAM
,
540 int family
= AF_UNSPEC
,
542 mImpl(SocketAddress(service
, type
, family
), flags
) {}
546 * Deconstruct the socket, closing it.
555 * Get whether or not the socket is connected.
556 * \return True if the socket is connected, false otherwise.
558 bool isConnected() const
560 return mImpl
.isConnected
;
564 * Get the address associated with the socket.
566 const SocketAddress
& address() const
568 return mImpl
.address
;
573 * Connect the socket to its peer.
574 * \return 0 on success, -1 on failure.
578 int result
= ::connect(mImpl
.fd
,
579 mImpl
.address
.address(),
580 mImpl
.address
.size());
581 mImpl
.isConnected
= result
!= -1;
586 * Disconnect a connected socket from its peer.
587 * \param flags Specify the socket directions to close.
588 * \return 0 on success, -1 on failure.
590 int disconnect(int flags
= SHUT_RDWR
)
592 return shutdown(mImpl
.fd
, flags
);
597 * Bind the socket to interface and port number specified in the
599 * \return 0 on success, -1 on failure.
603 return ::bind(mImpl
.fd
,
604 mImpl
.address
.address(),
605 mImpl
.address
.size());
609 * Listen on the socket for incoming connections. This is only useful
610 * for sockets of type SOCK_STREAM.
611 * \param backlog The number of unaccepted connections to queue.
612 * \return 0 on success, -1 on failure.
614 int listen(int backlog
= SOMAXCONN
)
616 return ::listen(mImpl
.fd
, backlog
> 0 ? backlog
: SOMAXCONN
);
620 * Accept a new connection on the socket. This is only useful for
621 * sockets of type SOCK_STREAM.
622 * \param socket Set to the new socket on return.
623 * \return 0 on success, -1 on failure.
625 int accept(Socket
& socket
)
627 Socket temp
= Socket(mImpl
.fd
);
628 if (temp
.mImpl
.fd
!= -1)
631 return socket
.mImpl
.fd
;
638 * Set an integer socket option.
639 * \param option The option to set.
640 * \param value The new value.
641 * \param level The layer to handle the option.
642 * \return 0 on success, -1 on failure.
645 int set(int option
, const T
& value
, int level
= SOL_SOCKET
)
648 return setsockopt(mImpl
.fd
,
651 reinterpret_cast<const char*>(&value
),
654 return setsockopt(mImpl
.fd
, level
, option
, &value
, sizeof(value
));
659 * Set a string socket option.
660 * \param option The option to set.
661 * \param value The new value.
662 * \param level The layer to handle the option.
663 * \return 0 on success, -1 on failure.
665 int set(int option
, const std::string
& value
, int level
= SOL_SOCKET
)
667 return setsockopt(mImpl
.fd
, level
, option
,
668 value
.data(), value
.length());
672 * Get an integer socket option.
673 * \param option The option to set.
674 * \param value The new value.
675 * \param level The layer to handle the option.
676 * \return 0 on success, -1 on failure.
679 int get(int option
, T
& value
, int level
= SOL_SOCKET
) const
681 int size
= sizeof(value
);
682 return getsockopt(mImpl
.fd
, level
, option
, &value
, &size
);
686 * Get a string 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.
692 int get(int option
, std::string
& value
, int level
= SOL_SOCKET
) const
694 char str
[256] = {'\0'};
695 socklen_t size
= sizeof(str
);
698 int result
= getsockopt(mImpl
.fd
,
701 reinterpret_cast<char*>(&str
),
704 int result
= getsockopt(mImpl
.fd
, level
, option
, &str
, &size
);
706 value
.assign(str
, size
);
712 * Set the socket IO mode to either blocking or non-blocking.
713 * \param isBlocking True if the socket blocks, false otherwise.
715 void setBlocking(bool isBlocking
)
718 int flags
= fcntl(mImpl
.fd
, F_GETFL
);
719 flags
= isBlocking
? (flags
& ~O_NONBLOCK
) : (flags
| O_NONBLOCK
);
720 fcntl(mImpl
.fd
, F_SETFL
, flags
);
721 #elif defined(_WIN32)
722 u_long value
= isBlocking
;
723 ioctlsocket(mImpl
.fd
, FIONBIO
, &value
);
728 * Get whether or not the socket is blocking or non-blocking. If the
729 * IO mode can't be determined, this method will assume the socket is
731 * \return True if the socket blocks, false otherwise.
733 bool isBlocking() const
736 int flags
= fcntl(mImpl
.fd
, F_GETFL
);
737 return !(flags
& O_NONBLOCK
);
744 * Write some bytes to the socket. Use this for connected sockets.
745 * \param bytes The bytes.
746 * \param size The number of bytes.
747 * \param flags The send options.
748 * \return The number of bytes written.
750 ssize_t
write(const void* bytes
, size_t size
, int flags
= 0)
753 return send(mImpl
.fd
,
754 reinterpret_cast<const char *>(bytes
), size
,
757 return send(mImpl
.fd
, bytes
, size
, flags
);
762 * Write some bytes to the socket using the given address. Use this
763 * for unconnected sockets.
764 * \param bytes The bytes.
765 * \param size The number of bytes.
766 * \param address The address to send to.
767 * \param flags The send options.
768 * \return The number of bytes written.
770 ssize_t
write(const void* bytes
,
772 const SocketAddress
& address
,
776 return sendto(mImpl
.fd
,
777 reinterpret_cast<const char*>(bytes
), size
,
779 address
.address(), address
.size());
781 return sendto(mImpl
.fd
, bytes
, size
, flags
,
782 address
.address(), address
.size());
787 * Write a packet to the socket. Use this for connected sockets.
788 * \param packet The packet.
789 * \param flags The send options.
790 * \return The number of bytes written.
792 ssize_t
write(const Packet
& packet
, int flags
= 0)
794 return write(packet
.bytes(), packet
.size(), flags
);
798 * Write a packet to the socket using the given address. Use this for
799 * unconnected sockets.
800 * \param packet The packet.
801 * \param address The address to send to.
802 * \param flags The send options.
803 * \return The number of bytes written.
805 ssize_t
write(const Packet
& packet
,
806 const SocketAddress
& address
,
809 return write(packet
.bytes(), packet
.size(), address
, flags
);
814 * Read some bytes from the socket. Use this for connected sockets.
815 * \param bytes The buffer to store the bytes.
816 * \param size The size of the buffer.
817 * \param flags The recv options.
818 * \return The number of bytes read.
820 ssize_t
read(void* bytes
, size_t size
, int flags
= 0)
823 ssize_t result
= recv(mImpl
.fd
,
824 reinterpret_cast<char*>(bytes
), size
,
827 ssize_t result
= recv(mImpl
.fd
, bytes
, size
, flags
);
829 if (result
== 0) mImpl
.isConnected
= false;
834 * Read some bytes from the socket using the given address. Use this
835 * for unconnected sockets.
836 * \param bytes The buffer to store the bytes.
837 * \param size The size of the buffer.
838 * \param address The address to read from.
839 * \param flags The recv options.
840 * \return The number of bytes read.
842 ssize_t
read(void* bytes
,
844 SocketAddress
& address
,
850 sockaddr_storage storage
;
852 socklen_t length
= sizeof(addr
);
855 ssize_t result
= recvfrom(mImpl
.fd
,
856 reinterpret_cast<char*>(bytes
), size
,
860 ssize_t result
= recvfrom(mImpl
.fd
, bytes
, size
, flags
,
865 address
= SocketAddress(&addr
.sa
, length
, mImpl
.address
.type());
867 else if (result
== 0)
869 mImpl
.isConnected
= false;
875 * Read a packet from the socket. Use this for connected sockets.
876 * \param packet Set to the packet read on return.
877 * \param flags The recv options.
878 * \return The number of bytes read.
880 ssize_t
read(Packet
& packet
, int flags
= 0)
883 ssize_t result
= read(buffer
, sizeof(buffer
), flags
);
884 if (result
!= -1) packet
= Packet(buffer
, result
);
889 * Read a packet from the socket using the given address. Use this for
890 * unconnected sockets.
891 * \param packet Set to the packet read on return.
892 * \param address The address to read from.
893 * \param flags The recv options.
894 * \return The number of bytes read.
896 ssize_t
read(Packet
& packet
, SocketAddress
& address
, int flags
= 0)
899 ssize_t result
= read(buffer
, sizeof(buffer
), address
, flags
);
900 if (result
!= -1) packet
= Packet(buffer
, result
);
905 // The rest of this junk is used to implement the "move" semantics
906 // correctly, since it makes no sense for socket objects to be copied.
908 Socket(Socket
& move
) :
912 move
.mImpl
.isConnected
= false;
918 Socket
& operator=(Socket
& move
)
923 move
.mImpl
.isConnected
= false;
927 Socket
& operator=(Impl move
)
938 mImpl
.isConnected
= false;
947 // for accepting a socket from fd
951 sockaddr_storage storage
;
953 socklen_t length
= sizeof(addr
);
955 mImpl
.fd
= ::accept(fd
, &addr
.sa
, &length
);
958 mImpl
.isConnected
= true;
959 mImpl
.address
= SocketAddress(&addr
.sa
, length
);
966 if (mImpl
.fd
!= -1) closesocket(mImpl
.fd
);
968 if (mImpl
.fd
!= -1) ::close(mImpl
.fd
);
974 class SocketMultiplexer
978 typedef boost::function
<int(SocketMultiplexer
&,
980 const SocketAddress
&)> Function
;
982 explicit SocketMultiplexer(Socket sock
) :
986 void setSocket(Socket sock
)
988 Mutex::ScopedLock
lock(mMutex
);
998 std::vector
<Function
>& protocols()
1004 void update(Scalar t
, Scalar dt
)
1006 SocketAddress address
;
1008 ssize_t bytes
= mSocket
.read(packet
, address
);
1012 std::vector
<Function
>::iterator it
;
1013 for (it
= mProtocols
.begin(); it
< mProtocols
.end(); ++it
)
1016 if ((*it
)(*this, packet
, address
)) break;
1031 std::vector
<Function
> mProtocols
;
1037 * An asynchronous task to resolve addresses.
1039 class ResolverTask
: public ThreadedTask
1044 * Construct a resolver task from a service and hostname.
1045 * \param service Server name or port number.
1046 * \param name The hostname or numeric address.
1047 * \param type The type of communication.
1048 * \param family The requested protocol family.
1050 ResolverTask(const std::string
& service
,
1051 const std::string
& name
,
1052 int type
= SOCK_STREAM
,
1053 int family
= AF_UNSPEC
) :
1056 mFunction
= boost::bind(&ResolverTask::resolve
,
1057 this, service
, name
, type
, family
);
1062 * Get whether or not the task is done.
1063 * \return True if the task has finished, false otherwise.
1071 * Start the task. This does nothing if the task was already run or is
1072 * currently running.
1076 if (!isDone() && !mThread
.isValid())
1078 mThread
= Thread::detach(mFunction
);
1084 * Get the addresses resolved. This is filled and safe to access after
1085 * the task finishes.
1086 * \return List of addresses.
1089 const std::vector
<SocketAddress
>& addresses() const
1091 return mAddressList
;
1097 int resolve(const std::string
& service
,
1098 const std::string
& name
,
1102 int status
= SocketAddress::resolve(service
, name
,
1110 std::vector
<SocketAddress
> mAddressList
;
1112 Thread::Function mFunction
;
1116 std::ostream
& operator<<(std::ostream
& stream
, const SocketAddress
& addr
)
1118 stream
<< addr
.name() << ":" << addr
.service();
1122 std::ostream
& operator<<(std::ostream
& stream
, const Socket
& sock
)
1124 stream
<< sock
.address();
1131 #endif // _MOOF_SOCKET_HH_
This page took 0.080111 seconds and 3 git commands to generate.