]>
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 **************************************************************************/
14 * Network-related classes, including a reinterpreted sockets API.
17 #ifndef _MOOF_SOCKET_HH_
18 #define _MOOF_SOCKET_HH_
32 #include <arpa/inet.h>
34 #include <sys/socket.h>
35 #include <sys/types.h>
39 #include <sys/ioctl.h>
43 #include <Moof/Log.hh>
44 #include <Moof/Packet.hh>
45 #include <Moof/Thread.hh>
49 #define SO_NONBLOCK 1024
57 * A class to represent the address of a remote host, including the type of
58 * service and socket communication.
65 * Construct an unspecified address.
71 mAddr
.sa
.sa_family
= AF_UNSPEC
;
72 mAddr
.in
.sin_port
= 0;
76 * Construct an address with a specified host. The address can be used
77 * to connect to a host.
78 * \param service The service name or port number.
79 * \param name The numeric IP address of the host.
80 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
81 * \param family The family; can be AF_INET or AF_INET6.
83 SocketAddress(const std::string
& service
,
84 const std::string
& name
,
85 int type
= SOCK_STREAM
,
86 int family
= AF_UNSPEC
)
88 init(service
, name
, type
, family
);
92 * Construct an address without a specified host. The address can be
93 * used to accept on a local port.
94 * \param service The service name or port number.
95 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
96 * \param family The family; can be AF_INET or AF_INET6.
98 SocketAddress(const std::string
& service
,
99 int type
= SOCK_STREAM
,
100 int family
= AF_UNSPEC
)
102 init(service
, type
, family
);
106 * Construct an address from the information in an addrinfo structure.
107 * \param addr The addrinfo structure.
109 SocketAddress(const struct addrinfo
* addr
) :
110 mSize(addr
->ai_addrlen
),
111 mType(addr
->ai_socktype
)
113 memcpy(&mAddr
.sa
, addr
->ai_addr
, addr
->ai_addrlen
);
114 getNameAndService(mService
, mName
);
118 * Construct an address from a sockaddr structure.
119 * \param addr The sockaddr structure.
120 * \param size The size of the sockaddr structure.
121 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
123 SocketAddress(const struct sockaddr
* addr
,
125 int type
= SOCK_STREAM
) :
129 memcpy(&mAddr
.sa
, addr
, size
);
130 getNameAndService(mService
, mName
);
135 * Get an IPv4 broadcast address.
136 * \param service The service name or port number.
137 * \return The socket address.
139 static SocketAddress
broadcast(const std::string
& service
)
141 std::istringstream
stream(service
);
145 struct sockaddr_in addr
;
146 addr
.sin_family
= AF_INET
;
147 addr
.sin_port
= htons(port
);
148 addr
.sin_addr
.s_addr
= INADDR_BROADCAST
;
149 memset(&addr
.sin_zero
, 0, sizeof(addr
.sin_zero
));
150 return SocketAddress((sockaddr
*)&addr
, sizeof(addr
), SOCK_DGRAM
);
155 * Initialize the address with a specified host. The address can be
156 * used to connect to a host.
157 * \param service The service name or port number.
158 * \param name The numeric IP address of the host.
159 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
160 * \param family The family; can be AF_INET or AF_INET6.
162 void init(const std::string
& service
,
163 const std::string
& name
,
164 int type
= SOCK_STREAM
,
165 int family
= AF_UNSPEC
)
167 struct addrinfo
* addr
= resolve(service
.c_str(), name
.c_str(),
169 AI_ADDRCONFIG
| AI_NUMERICHOST
| AI_V4MAPPED
);
172 mSize
= addr
->ai_addrlen
;
173 mType
= addr
->ai_socktype
;
174 memcpy(&mAddr
.sa
, addr
->ai_addr
, addr
->ai_addrlen
);
185 mAddr
.sa
.sa_family
= AF_UNSPEC
;
186 mAddr
.in
.sin_port
= 0;
191 * Initialize the address without a specified host. The address can be
192 * used to accept on a local port.
193 * \param service The service name or port number.
194 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
195 * \param family The family; can be AF_INET or AF_INET6.
197 void init(const std::string
& service
,
198 int type
= SOCK_STREAM
,
199 int family
= AF_UNSPEC
)
201 struct addrinfo
* addr
= resolve(service
.c_str(), 0,
206 mSize
= addr
->ai_addrlen
;
207 mType
= addr
->ai_socktype
;
208 memcpy(&mAddr
.sa
, addr
->ai_addr
, addr
->ai_addrlen
);
219 mAddr
.sa
.sa_family
= AF_UNSPEC
;
220 mAddr
.in
.sin_port
= 0;
226 * Get the name of the service. This could also be a port number if
227 * there is no service name associated with the number.
228 * \return The service.
230 const std::string
& service() const
236 * Get the name of the host. This may be the host used to construct
237 * the address, or a resolved numeric host if none was used.
240 const std::string
& name() const
246 * Get the port number of the address service.
247 * \return Port number.
249 unsigned short port() const
251 return ntohs(mAddr
.in
.sin_port
);
255 * Get the type of socket associated with the service of this address.
256 * \return Socket type; either SOCK_STREAM or SOCK_DGRAM.
264 * Get the family of the protocol associated with the address.
265 * \return Protocol family; either AF_INET, AF_INET6, or AF_UNSPEC.
269 return mAddr
.sa
.sa_family
;
274 * Get the sockaddr structure of the address.
275 * \return The sockaddr structure.
277 const struct sockaddr
* address() const
279 return mSize
!= 0 ? &mAddr
.sa
: 0;
283 * Get the size of the sockaddr structure of the address.
284 * \return The size of the sockaddr structure.
293 * Get a list of addresses resolved to by the given search criteria.
294 * This can be used to perform lookups for name resolution, so this
295 * method may take some time to return. Use the ResolveTask class to
296 * resolve addresses asynchronously.
297 * \param service The service name or port number.
298 * \param name The name of the local or remote host.
299 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
300 * \param family The family; can be AF_INET or AF_INET6.
301 * \param resolved The list to be filled with addresses.
302 * \return 0 on success, -1 on error.
304 static int resolve(const std::string
& service
,
305 const std::string
& name
,
308 std::vector
<SocketAddress
>& resolved
)
310 struct addrinfo
* list
= resolve(service
.c_str(), name
.c_str(),
312 AI_ADDRCONFIG
| AI_V4MAPPED
);
313 int result
= collectAddresses(list
, resolved
);
319 * Get a list of addresses resolved to by the given search criteria.
320 * The addresses will be suitable for accepting on a local port.
321 * \param service The service name or port number.
322 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
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
,
330 std::vector
<SocketAddress
>& resolved
)
332 struct addrinfo
* list
= resolve(service
.c_str(), 0,
335 int result
= collectAddresses(list
, resolved
);
342 * Resolve the hostname of the address. The default behavior is to
343 * avoid a reverse lookup by giving the numeric address. You can
344 * change that behavior with the getnameinfo flags.
345 * \param name The place to store the hostname or IP address.
346 * \param flags The getnameinfo flags.
348 void getName(std::string
& name
, int flags
= NI_NUMERICHOST
)
350 char node
[256] = {'\0'};
351 int result
= getnameinfo(&mAddr
.sa
, mSize
,
355 if (result
== 0) name
.assign(node
);
359 * Resolve the service name of the address.
360 * \param service The place to store the service name or port number.
361 * \param flags The getnameinfo flags.
363 void getService(std::string
& service
, int flags
)
365 flags
|= mType
== SOCK_DGRAM
? NI_DGRAM
: 0;
367 char serv
[64] = {'\0'};
368 int result
= getnameinfo(&mAddr
.sa
, mSize
,
372 if (result
== 0) service
.assign(serv
);
376 * Resolve the service and hostname of the address. The default
377 * behavior is to avoid a reverse lookup by giving the numeric address.
378 * You can change that behavior with the getnameinfo flags.
379 * \param name The place to store the hostname or IP address.
380 * \param service The place to store the service name or port number.
381 * \param flags The getnameinfo flags.
383 void getNameAndService(std::string
& name
,
384 std::string
& service
,
385 int flags
= NI_NUMERICHOST
)
387 flags
|= mType
== SOCK_DGRAM
? NI_DGRAM
: 0;
389 char serv
[64] = {'\0'};
390 char node
[256] = {'\0'};
391 int result
= getnameinfo(&mAddr
.sa
, mSize
,
397 service
.assign(serv
);
405 static struct addrinfo
* resolve(const char* service
,
411 ASSERT(type
== SOCK_STREAM
|| type
== SOCK_DGRAM
);
412 ASSERT(family
== AF_INET
|| family
== AF_INET6
|| family
== AF_UNSPEC
);
414 struct addrinfo hints
;
415 memset(&hints
, 0, sizeof(hints
));
416 hints
.ai_family
= family
;
417 hints
.ai_socktype
= type
;
418 hints
.ai_flags
= flags
;
420 struct addrinfo
* addr
;
421 int status
= getaddrinfo(node
, service
, &hints
, &addr
);
429 Mf::logWarning(gai_strerror(status
));
434 static int collectAddresses(struct addrinfo
* addresses
,
435 std::vector
<SocketAddress
>& resolved
)
441 for (struct addrinfo
* addr
= addresses
;
443 addr
= addr
->ai_next
)
445 resolved
.push_back(SocketAddress(addr
));
458 sockaddr_storage storage
;
464 std::string mService
;
469 * The socket class represents a connection or between this node and a
476 SocketAddress address
;
482 isConnected(false) {}
484 Impl(const SocketAddress
& address
, int flags
= 0) :
486 fd(::socket(address
.family(), address
.type(), flags
)),
487 isConnected(false) {}
494 * Construct a socket with no associated peer.
499 * Construct a socket with an address.
500 * \param address The address.
501 * \param flags The socket options.
503 Socket(const SocketAddress
& address
, int flags
= 0) :
504 mImpl(address
, flags
) {}
507 * Construct a socket with a specified host. The socket can be used to
509 * \param service The service name or port number.
510 * \param name The numeric IP address of the host.
511 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
512 * \param family The family; can be AF_INET or AF_INET6.
513 * \param flags The socket options.
515 Socket(const std::string
& service
,
516 const std::string
& name
,
517 int type
= SOCK_STREAM
,
518 int family
= AF_UNSPEC
,
520 mImpl(SocketAddress(service
, name
, type
, family
), flags
) {}
523 * Construct a socket without a specified host. The socket can be used
524 * to accept sockets on a local port.
525 * \param service The service name or port number.
526 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
527 * \param family The family; can be AF_INET or AF_INET6.
528 * \param flags The socket options.
530 Socket(const std::string
& service
,
531 int type
= SOCK_STREAM
,
532 int family
= AF_UNSPEC
,
534 mImpl(SocketAddress(service
, type
, family
), flags
) {}
538 * Deconstruct the socket, closing it.
547 * Get whether or not the socket is connected.
548 * \return True if the socket is connected, false otherwise.
550 bool isConnected() const
552 return mImpl
.isConnected
;
556 * Get the address associated with the socket.
558 const SocketAddress
& address() const
560 return mImpl
.address
;
565 * Connect the socket to its peer.
566 * \return 0 on success, -1 on failure.
570 int result
= ::connect(mImpl
.fd
,
571 mImpl
.address
.address(),
572 mImpl
.address
.size());
573 mImpl
.isConnected
= result
!= -1;
578 * Disconnect a connected socket from its peer.
579 * \param flags Specify the socket directions to close.
580 * \return 0 on success, -1 on failure.
582 int disconnect(int flags
= SHUT_RDWR
)
584 return shutdown(mImpl
.fd
, flags
);
589 * Bind the socket to interface and port number specified in the
591 * \return 0 on success, -1 on failure.
595 return ::bind(mImpl
.fd
,
596 mImpl
.address
.address(),
597 mImpl
.address
.size());
601 * Listen on the socket for incoming connections. This is only useful
602 * for sockets of type SOCK_STREAM.
603 * \param backlog The number of unaccepted connections to queue.
604 * \return 0 on success, -1 on failure.
606 int listen(int backlog
= SOMAXCONN
)
608 return ::listen(mImpl
.fd
, backlog
> 0 ? backlog
: SOMAXCONN
);
612 * Accept a new connection on the socket. This is only useful for
613 * sockets of type SOCK_STREAM.
614 * \param socket Set to the new socket on return.
615 * \return 0 on success, -1 on failure.
617 int accept(Socket
& socket
)
619 Socket temp
= Socket(mImpl
.fd
);
620 if (temp
.mImpl
.fd
!= -1)
623 return socket
.mImpl
.fd
;
630 * Set an integer socket option.
631 * \param option The option to set.
632 * \param value The new value.
633 * \param level The layer to handle the option.
634 * \return 0 on success, -1 on failure.
637 int set(int option
, const T
& value
, int level
= SOL_SOCKET
)
639 return setsockopt(mImpl
.fd
, level
, option
, &value
, sizeof(value
));
643 * Set a string socket option.
644 * \param option The option to set.
645 * \param value The new value.
646 * \param level The layer to handle the option.
647 * \return 0 on success, -1 on failure.
649 int set(int option
, const std::string
& value
, int level
= SOL_SOCKET
)
651 return setsockopt(mImpl
.fd
, level
, option
,
652 value
.data(), value
.length());
656 * Get an integer socket option.
657 * \param option The option to set.
658 * \param value The new value.
659 * \param level The layer to handle the option.
660 * \return 0 on success, -1 on failure.
663 int get(int option
, T
& value
, int level
= SOL_SOCKET
) const
665 int size
= sizeof(value
);
666 return getsockopt(mImpl
.fd
, level
, option
, &value
, &size
);
670 * Get a string socket option.
671 * \param option The option to set.
672 * \param value The new value.
673 * \param level The layer to handle the option.
674 * \return 0 on success, -1 on failure.
676 int get(int option
, std::string
& value
, int level
= SOL_SOCKET
) const
678 char str
[256] = {'\0'};
679 socklen_t size
= sizeof(str
);
681 int result
= getsockopt(mImpl
.fd
, level
, option
, &str
, &size
);
682 value
.assign(str
, size
);
687 void setBlocking(bool isBlocking
)
689 int value
= isBlocking
;
691 int flags
= fcntl(mImpl
.fd
, F_GETFL
);
692 fcntl(mImpl
.fd
, F_SETFL
, flags
| (value
? O_NONBLOCK
: 0));
694 ioctl(mImpl
.fd
, FIONBIO
, value
);
698 bool isBlocking() const
701 int flags
= fcntl(mImpl
.fd
, F_GETFL
);
702 return flags
& O_NONBLOCK
;
705 ioctl(mImpl
.fd
, FIONBIO
, &value
);
712 * Write some bytes to the socket. Use this for connected sockets.
713 * \param bytes The bytes.
714 * \param size The number of bytes.
715 * \param flags The send options.
716 * \return The number of bytes written.
718 ssize_t
write(const void* bytes
, size_t size
, int flags
= 0)
720 return send(mImpl
.fd
, bytes
, size
, flags
);
724 * Write some bytes to the socket using the given address. Use this
725 * for unconnected sockets.
726 * \param bytes The bytes.
727 * \param size The number of bytes.
728 * \param address The address to send to.
729 * \param flags The send options.
730 * \return The number of bytes written.
732 ssize_t
write(const void* bytes
, size_t size
,
733 const SocketAddress
& address
, int flags
= 0)
735 return sendto(mImpl
.fd
, bytes
, size
, flags
,
736 address
.address(), address
.size());
740 * Write a packet to the socket. Use this for connected sockets.
741 * \param packet The packet.
742 * \param flags The send options.
743 * \return The number of bytes written.
745 ssize_t
write(const Packet
& packet
, int flags
= 0)
747 return write(packet
.bytes(), packet
.size(), flags
);
751 * Write a packet to the socket using the given address. Use this for
752 * unconnected sockets.
753 * \param packet The packet.
754 * \param address The address to send to.
755 * \param flags The send options.
756 * \return The number of bytes written.
758 ssize_t
write(const Packet
& packet
, const SocketAddress
& address
,
761 return write(packet
.bytes(), packet
.size(), address
, flags
);
766 * Read some bytes from the socket. Use this for connected sockets.
767 * \param bytes The buffer to store the bytes.
768 * \param size The size of the buffer.
769 * \param flags The recv options.
770 * \return The number of bytes read.
772 ssize_t
read(void* bytes
, size_t size
, int flags
= 0)
774 return recv(mImpl
.fd
, bytes
, size
, flags
);
778 * Read some bytes from the socket using the given address. Use this
779 * for unconnected sockets.
780 * \param bytes The buffer to store the bytes.
781 * \param size The size of the buffer.
782 * \param address The address to read from.
783 * \param flags The recv options.
784 * \return The number of bytes read.
786 ssize_t
read(void* bytes
, size_t size
, SocketAddress
& address
,
792 sockaddr_storage storage
;
794 socklen_t length
= sizeof(addr
);
796 ssize_t result
= recvfrom(mImpl
.fd
, bytes
, size
, flags
,
800 address
= SocketAddress(&addr
.sa
, length
, mImpl
.address
.type());
806 * Read a packet from the socket. Use this for connected sockets.
807 * \param packet Set to the packet read on return.
808 * \param flags The recv options.
809 * \return The number of bytes read.
811 ssize_t
read(Packet
& packet
, int flags
= 0)
814 ssize_t result
= read(buffer
, sizeof(buffer
), flags
);
815 if (result
!= -1) packet
= Packet(buffer
, result
);
820 * Read a packet from the socket using the given address. Use this for
821 * unconnected sockets.
822 * \param packet Set to the packet read on return.
823 * \param address The address to read from.
824 * \param flags The recv options.
825 * \return The number of bytes read.
827 ssize_t
read(Packet
& packet
, SocketAddress
& address
, int flags
= 0)
830 ssize_t result
= read(buffer
, sizeof(buffer
), address
, flags
);
831 if (result
!= -1) packet
= Packet(buffer
, result
);
836 // The rest of this junk is used to implement the "move" semantics
837 // correctly, since it makes no sense for socket objects to be copied.
839 Socket(Socket
& move
) :
843 move
.mImpl
.isConnected
= false;
849 Socket
& operator=(Socket
& move
)
854 move
.mImpl
.isConnected
= false;
858 Socket
& operator=(Impl move
)
869 mImpl
.isConnected
= false;
878 // for accepting a socket from fd
882 sockaddr_storage storage
;
884 socklen_t length
= sizeof(addr
);
886 mImpl
.fd
= ::accept(fd
, &addr
.sa
, &length
);
889 mImpl
.isConnected
= true;
890 mImpl
.address
= SocketAddress(&addr
.sa
, length
);
897 if (mImpl
.fd
!= -1) closesocket(mImpl
.fd
);
899 if (mImpl
.fd
!= -1) ::close(mImpl
.fd
);
905 class SocketMultiplexer
909 typedef boost::function
<int(SocketMultiplexer
&,
911 const SocketAddress
&)> Function
;
913 SocketMultiplexer(Socket sock
) :
917 void setSocket(Socket sock
)
919 Mutex::ScopedLock
lock(mMutex
);
929 std::vector
<Function
>& protocols()
935 void update(Scalar t
, Scalar dt
)
937 SocketAddress address
;
939 ssize_t bytes
= mSocket
.read(packet
, address
);
943 std::vector
<Function
>::iterator it
;
944 for (it
= mProtocols
.begin(); it
< mProtocols
.end(); ++it
)
947 if ((*it
)(*this, packet
, address
)) break;
962 std::vector
<Function
> mProtocols
;
968 * An asynchronous task to resolve addresses.
970 class ResolverTask
: public ThreadedTask
975 * Construct a resolver task from a service and hostname.
976 * \param service Server name or port number.
977 * \param name The hostname or numeric address.
978 * \param type The type of communication.
979 * \param family The requested protocol family.
981 ResolverTask(const std::string
& service
,
982 const std::string
& name
,
983 int type
= SOCK_STREAM
,
984 int family
= AF_UNSPEC
) :
987 mFunction
= boost::bind(&ResolverTask::resolve
,
988 this, service
, name
, type
, family
);
993 * Get whether or not the task is done.
994 * \return True if the task has finished, false otherwise.
1002 * Start the task. This does nothing if the task was already run or is
1003 * currently running.
1007 if (!isDone() && !mThread
.isValid())
1009 mThread
= Thread::detach(mFunction
);
1015 * Get the addresses resolved. This is filled and safe to access after
1016 * the task finishes.
1017 * \return List of addresses.
1020 const std::vector
<SocketAddress
>& addresses() const
1022 return mAddressList
;
1028 int resolve(const std::string
& service
,
1029 const std::string
& name
,
1033 int status
= SocketAddress::resolve(service
, name
,
1041 std::vector
<SocketAddress
> mAddressList
;
1043 Thread::Function mFunction
;
1047 std::ostream
& operator<<(std::ostream
& stream
, const SocketAddress
& addr
)
1049 stream
<< addr
.name() << ":" << addr
.service();
1053 std::ostream
& operator<<(std::ostream
& stream
, const Socket
& sock
)
1055 stream
<< sock
.address();
1062 #endif // _MOOF_SOCKET_HH_
This page took 0.081079 seconds and 4 git commands to generate.