]>
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_
26 #include <arpa/inet.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
33 #include <sys/ioctl.h>
37 #include <Moof/Log.hh>
38 #include <Moof/Packet.hh>
39 #include <Moof/Thread.hh>
43 #define SO_NONBLOCK 1024
51 * A class to represent the address of a remote host, including the type of
52 * service and socket communication.
59 * Construct an unspecified address.
65 mAddr
.sa
.sa_family
= AF_UNSPEC
;
66 mAddr
.in
.sin_port
= 0;
70 * Construct an address with a specified host. The address can be used
71 * to connect to a host.
72 * \param service The service name or port number.
73 * \param host The numeric IP address of the host.
74 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
75 * \param family The family; can be AF_INET or AF_INET6.
77 SocketAddress(const std::string
& service
,
78 const std::string
& host
,
79 int type
= SOCK_STREAM
,
80 int family
= AF_UNSPEC
)
82 init(service
, host
, type
, family
);
86 * Construct an address without a specified host. The address can be
87 * used to accept on a local port.
88 * \param service The service name or port number.
89 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
90 * \param family The family; can be AF_INET or AF_INET6.
92 SocketAddress(const std::string
& service
,
93 int type
= SOCK_STREAM
,
94 int family
= AF_UNSPEC
)
96 init(service
, type
, family
);
100 * Construct an address from the information in an addrinfo structure.
101 * \param addr The addrinfo structure.
103 SocketAddress(const struct addrinfo
* addr
) :
104 mSize(addr
->ai_addrlen
),
105 mType(addr
->ai_socktype
)
107 memcpy(&mAddr
.sa
, addr
->ai_addr
, addr
->ai_addrlen
);
108 getServiceAndHostName(mService
, mHost
);
112 * Construct an address from a sockaddr structure.
113 * \param addr The sockaddr structure.
114 * \param size The size of the sockaddr structure.
115 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
117 SocketAddress(const struct sockaddr
* addr
,
119 int type
= SOCK_STREAM
) :
123 memcpy(&mAddr
.sa
, addr
, size
);
124 getServiceAndHostName(mService
, mHost
);
129 * Get an IPv4 broadcast address.
130 * \param service The service name or port number.
131 * \return The socket address.
133 static SocketAddress
broadcast(const std::string
& service
)
135 std::istringstream
stream(service
);
139 struct sockaddr_in addr
;
140 addr
.sin_family
= AF_INET
;
141 addr
.sin_port
= htons(port
);
142 addr
.sin_addr
.s_addr
= INADDR_BROADCAST
;
143 memset(&addr
.sin_zero
, 0, sizeof(addr
.sin_zero
));
144 return SocketAddress((sockaddr
*)&addr
, sizeof(addr
), SOCK_DGRAM
);
149 * Initialize the address with a specified host. The address can be
150 * used to connect to a host.
151 * \param service The service name or port number.
152 * \param host The numeric IP address of the host.
153 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
154 * \param family The family; can be AF_INET or AF_INET6.
156 void init(const std::string
& service
,
157 const std::string
& host
,
158 int type
= SOCK_STREAM
,
159 int family
= AF_UNSPEC
)
161 struct addrinfo
* addr
= resolve(service
.c_str(), host
.c_str(),
163 AI_ADDRCONFIG
| AI_NUMERICHOST
| AI_V4MAPPED
);
166 mSize
= addr
->ai_addrlen
;
167 mType
= addr
->ai_socktype
;
168 memcpy(&mAddr
.sa
, addr
->ai_addr
, addr
->ai_addrlen
);
179 mAddr
.sa
.sa_family
= AF_UNSPEC
;
180 mAddr
.in
.sin_port
= 0;
185 * Initialize the address without a specified host. The address can be
186 * used to accept on a local port.
187 * \param service The service name or port number.
188 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
189 * \param family The family; can be AF_INET or AF_INET6.
191 void init(const std::string
& service
,
192 int type
= SOCK_STREAM
,
193 int family
= AF_UNSPEC
)
195 struct addrinfo
* addr
= resolve(service
.c_str(), 0,
200 mSize
= addr
->ai_addrlen
;
201 mType
= addr
->ai_socktype
;
202 memcpy(&mAddr
.sa
, addr
->ai_addr
, addr
->ai_addrlen
);
213 mAddr
.sa
.sa_family
= AF_UNSPEC
;
214 mAddr
.in
.sin_port
= 0;
220 * Get the name of the service. This could also be a port number if
221 * there is no service name associated with the number.
222 * \return The service.
224 const std::string
& service() const
230 * Get the name of the host. This may be the host used to construct
231 * the address, or a resolved numeric host if none was used.
234 const std::string
& host() const
240 * Get the port number of the address service.
241 * \return Port number.
243 unsigned short port() const
245 return ntohs(mAddr
.in
.sin_port
);
249 * Get the type of socket associated with the service of this address.
250 * \return Socket type; either SOCK_STREAM or SOCK_DGRAM.
258 * Get the family of the protocol associated with the address.
259 * \return Protocol family; either AF_INET, AF_INET6, or AF_UNSPEC.
263 return mAddr
.sa
.sa_family
;
268 * Get the sockaddr structure of the address.
269 * \return The sockaddr structure.
271 const struct sockaddr
* address() const
273 return mSize
!= 0 ? &mAddr
.sa
: 0;
277 * Get the size of the sockaddr structure of the address.
278 * \return The size of the sockaddr structure.
287 * Get a list of addresses resolved to by the given search criteria.
288 * This can be used to perform lookups for name resolution, so this
289 * method may take some time to return. Use the ResolveTask class to
290 * resolve addresses asynchronously.
291 * \param service The service name or port number.
292 * \param host The name of the local or remote host.
293 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
294 * \param family The family; can be AF_INET or AF_INET6.
295 * \param resolved The list to be filled with addresses.
296 * \return 0 on success, -1 on error.
298 static int resolve(const std::string
& service
,
299 const std::string
& host
,
302 std::vector
<SocketAddress
>& resolved
)
304 struct addrinfo
* list
= resolve(service
.c_str(), host
.c_str(),
306 AI_ADDRCONFIG
| AI_V4MAPPED
);
307 int result
= collectAddresses(list
, resolved
);
313 * Get a list of addresses resolved to by the given search criteria.
314 * The addresses will be suitable for accepting on a local port.
315 * \param service The service name or port number.
316 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
317 * \param family The family; can be AF_INET or AF_INET6.
318 * \param resolved The list to be filled with addresses.
319 * \return 0 on success, -1 on error.
321 static int resolve(const std::string
& service
,
324 std::vector
<SocketAddress
>& resolved
)
326 struct addrinfo
* list
= resolve(service
.c_str(), 0,
329 int result
= collectAddresses(list
, resolved
);
337 static struct addrinfo
* resolve(const char* service
,
343 ASSERT(type
== SOCK_STREAM
|| type
== SOCK_DGRAM
);
344 ASSERT(family
== AF_INET
|| family
== AF_INET6
|| family
== AF_UNSPEC
);
346 struct addrinfo hints
;
347 memset(&hints
, 0, sizeof(hints
));
348 hints
.ai_family
= family
;
349 hints
.ai_socktype
= type
;
350 hints
.ai_flags
= flags
;
352 struct addrinfo
* addr
;
353 int status
= getaddrinfo(node
, service
, &hints
, &addr
);
361 Mf::logWarning(gai_strerror(status
));
366 static int collectAddresses(struct addrinfo
* addresses
,
367 std::vector
<SocketAddress
>& resolved
)
373 for (struct addrinfo
* addr
= addresses
;
375 addr
= addr
->ai_next
)
377 resolved
.push_back(SocketAddress(addr
));
386 void getService(std::string
& service
)
388 char value
[64] = {'\0'};
389 int result
= getnameinfo(&mAddr
.sa
, mSize
,
391 value
, sizeof(value
),
392 (mType
== SOCK_DGRAM
) ? NI_DGRAM
: 0);
393 if (result
== 0) service
.assign(value
);
396 void getHost(std::string
& host
)
398 char value
[256] = {'\0'};
399 int result
= getnameinfo(&mAddr
.sa
, mSize
,
400 value
, sizeof(value
),
403 if (result
== 0) host
.assign(value
);
406 void getServiceAndHostName(std::string
& service
, std::string
& host
)
408 char serv
[64] = {'\0'};
409 char node
[256] = {'\0'};
410 int result
= getnameinfo(&mAddr
.sa
, mSize
,
414 (mType
== SOCK_DGRAM
) ? NI_DGRAM
: 0);
417 service
.assign(serv
);
427 sockaddr_storage storage
;
433 std::string mService
;
438 * The socket class represents a connection or between this node and a
445 SocketAddress address
;
451 isConnected(false) {}
453 Impl(const SocketAddress
& address
, int flags
= 0) :
455 fd(::socket(address
.family(), address
.type(), flags
)),
456 isConnected(false) {}
463 * Construct a socket with no associated peer.
468 * Construct a socket with an address.
469 * \param address The address.
470 * \param flags The socket options.
472 Socket(const SocketAddress
& address
, int flags
= 0) :
473 mImpl(address
, flags
) {}
476 * Construct a socket with a specified host. The socket can be used to
478 * \param service The service name or port number.
479 * \param host The numeric IP address of the host.
480 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
481 * \param family The family; can be AF_INET or AF_INET6.
482 * \param flags The socket options.
484 Socket(const std::string
& service
, const std::string
& name
,
485 int type
= SOCK_STREAM
, int family
= AF_UNSPEC
,
487 mImpl(SocketAddress(service
, name
, type
, family
), flags
) {}
490 * Construct a socket without a specified host. The socket can be used
491 * to accept sockets on a local port.
492 * \param service The service name or port number.
493 * \param type The type of socket; either SOCK_STREAM or SOCK_DGRAM.
494 * \param family The family; can be AF_INET or AF_INET6.
495 * \param flags The socket options.
497 Socket(const std::string
& service
, int type
= SOCK_STREAM
,
498 int family
= AF_UNSPEC
, int flags
= 0) :
499 mImpl(SocketAddress(service
, type
, family
), flags
) {}
503 * Deconstruct the socket, closing it.
512 * Get whether or not the socket is connected.
513 * \return True if the socket is connected, false otherwise.
515 bool isConnected() const
517 return mImpl
.isConnected
;
521 * Get the address associated with the socket.
523 const SocketAddress
& address() const
525 return mImpl
.address
;
530 * Connect the socket to its peer.
531 * \return 0 on success, -1 on failure.
535 int result
= ::connect(mImpl
.fd
,
536 mImpl
.address
.address(),
537 mImpl
.address
.size());
538 mImpl
.isConnected
= result
!= -1;
543 * Disconnect a connected socket from its peer.
544 * \param flags Specify the socket directions to close.
545 * \return 0 on success, -1 on failure.
547 int disconnect(int flags
= SHUT_RDWR
)
549 return shutdown(mImpl
.fd
, flags
);
554 * Bind the socket to interface and port number specified in the
556 * \return 0 on success, -1 on failure.
560 return ::bind(mImpl
.fd
,
561 mImpl
.address
.address(),
562 mImpl
.address
.size());
566 * Listen on the socket for incoming connections. This is only useful
567 * for sockets of type SOCK_STREAM.
568 * \param backlog The number of unaccepted connections to queue.
569 * \return 0 on success, -1 on failure.
571 int listen(int backlog
= SOMAXCONN
)
573 return ::listen(mImpl
.fd
, backlog
> 0 ? backlog
: SOMAXCONN
);
577 * Accept a new connection on the socket. This is only useful for
578 * sockets of type SOCK_STREAM.
579 * \param socket Set to the new socket on return.
580 * \return 0 on success, -1 on failure.
582 int accept(Socket
& socket
)
584 Socket temp
= Socket(mImpl
.fd
);
585 if (temp
.mImpl
.fd
!= -1)
588 return socket
.mImpl
.fd
;
595 * Set an integer socket option.
596 * \param option The option to set.
597 * \param value The new value.
598 * \return 0 on success, -1 on failure.
600 int set(int option
, int value
= 0)
602 if (option
== SO_NONBLOCK
)
605 int flags
= fcntl(mImpl
.fd
, F_GETFL
);
606 return fcntl(mImpl
.fd
,
608 flags
| (value
? O_NONBLOCK
: 0));
610 return ioctl(mImpl
.fd
, FIONBIO
, value
);
613 return setsockopt(mImpl
.fd
, SOL_SOCKET
, option
,
614 &value
, sizeof(value
));
618 * Set a string socket option.
619 * \param option The option to set.
620 * \param value The new value.
621 * \return 0 on success, -1 on failure.
623 int set(int option
, const std::string
& value
)
625 return setsockopt(mImpl
.fd
, SOL_SOCKET
, option
,
626 value
.data(), value
.length());
630 * Get an integer socket option.
631 * \param option The option to set.
632 * \param value The new value.
633 * \return 0 on success, -1 on failure.
635 int get(int option
, int& value
)
637 if (option
== SO_NONBLOCK
)
640 int flags
= fcntl(mImpl
.fd
, F_GETFL
);
641 return flags
& O_NONBLOCK
;
643 return ioctl(mImpl
.fd
, FIONBIO
, &value
);
646 socklen_t optlen
= sizeof(value
);
647 return getsockopt(mImpl
.fd
, SOL_SOCKET
, option
, &value
, &optlen
);
651 * Get a string socket option.
652 * \param option The option to set.
653 * \param value The new value.
654 * \return 0 on success, -1 on failure.
656 int get(int option
, std::string
& value
)
658 char str
[256] = {'\0'};
659 socklen_t optlen
= sizeof(str
);
660 int result
= getsockopt(mImpl
.fd
, SOL_SOCKET
, option
,
668 * Write some bytes to the socket. Use this for connected sockets.
669 * \param bytes The bytes.
670 * \param size The number of bytes.
671 * \param flags The send options.
672 * \return The number of bytes written.
674 ssize_t
write(const void* bytes
, size_t size
, int flags
= 0)
676 return send(mImpl
.fd
, bytes
, size
, flags
);
680 * Write some bytes to the socket using the given address. Use this
681 * for unconnected sockets.
682 * \param bytes The bytes.
683 * \param size The number of bytes.
684 * \param address The address to send to.
685 * \param flags The send options.
686 * \return The number of bytes written.
688 ssize_t
write(const void* bytes
, size_t size
,
689 const SocketAddress
& address
, int flags
= 0)
691 return sendto(mImpl
.fd
, bytes
, size
, flags
,
692 address
.address(), address
.size());
696 * Write a packet to the socket. Use this for connected sockets.
697 * \param packet The packet.
698 * \param flags The send options.
699 * \return The number of bytes written.
701 ssize_t
write(const Packet
& packet
, int flags
= 0)
703 return write(packet
.bytes(), packet
.size(), flags
);
707 * Write a packet to the socket using the given address. Use this for
708 * unconnected sockets.
709 * \param packet The packet.
710 * \param address The address to send to.
711 * \param flags The send options.
712 * \return The number of bytes written.
714 ssize_t
write(const Packet
& packet
, const SocketAddress
& address
,
717 return write(packet
.bytes(), packet
.size(), address
, flags
);
722 * Read some bytes from the socket. Use this for connected sockets.
723 * \param bytes The buffer to store the bytes.
724 * \param size The size of the buffer.
725 * \param flags The recv options.
726 * \return The number of bytes read.
728 ssize_t
read(void* bytes
, size_t size
, int flags
= 0)
730 return recv(mImpl
.fd
, bytes
, size
, flags
);
734 * Read some bytes from the socket using the given address. Use this
735 * for unconnected sockets.
736 * \param bytes The buffer to store the bytes.
737 * \param size The size of the buffer.
738 * \param address The address to read from.
739 * \param flags The recv options.
740 * \return The number of bytes read.
742 ssize_t
read(void* bytes
, size_t size
, SocketAddress
& address
,
748 sockaddr_storage storage
;
750 socklen_t length
= sizeof(addr
);
752 ssize_t result
= recvfrom(mImpl
.fd
, bytes
, size
, flags
,
756 address
= SocketAddress(&addr
.sa
, length
, mImpl
.address
.type());
762 * Read a packet from the socket. Use this for connected sockets.
763 * \param packet Set to the packet read on return.
764 * \param flags The recv options.
765 * \return The number of bytes read.
767 ssize_t
read(Packet
& packet
, int flags
= 0)
770 ssize_t result
= read(buffer
, sizeof(buffer
), flags
);
771 if (result
!= -1) packet
= Packet(buffer
, result
);
776 * Read a packet from the socket using the given address. Use this for
777 * unconnected sockets.
778 * \param packet Set to the packet read on return.
779 * \param address The address to read from.
780 * \param flags The recv options.
781 * \return The number of bytes read.
783 ssize_t
read(Packet
& packet
, SocketAddress
& address
, int flags
= 0)
786 ssize_t result
= read(buffer
, sizeof(buffer
), address
, flags
);
787 if (result
!= -1) packet
= Packet(buffer
, result
);
792 // The rest of this junk is used to implement the "move" semantics
793 // correctly, since it makes no sense for socket objects to be copied.
795 Socket(Socket
& move
) :
799 move
.mImpl
.isConnected
= false;
805 Socket
& operator=(Socket
& move
)
810 move
.mImpl
.isConnected
= false;
814 Socket
& operator=(Impl move
)
825 mImpl
.isConnected
= false;
834 // for accepting a socket from fd
838 sockaddr_storage storage
;
840 socklen_t length
= sizeof(addr
);
842 mImpl
.fd
= ::accept(fd
, &addr
.sa
, &length
);
845 mImpl
.isConnected
= true;
846 mImpl
.address
= SocketAddress(&addr
.sa
, length
);
853 if (mImpl
.fd
!= -1) closesocket(mImpl
.fd
);
855 if (mImpl
.fd
!= -1) ::close(mImpl
.fd
);
862 * An asynchronous task to resolve addresses.
864 class ResolverTask
: public ThreadedTask
869 * Construct a resolver task from a service and hostname.
870 * \param service Server name or port number.
871 * \param host The hostname or numeric address.
872 * \param type The type of communication.
873 * \param family The requested protocol family.
875 ResolverTask(const std::string
& service
,
876 const std::string
& host
,
877 int type
= SOCK_STREAM
,
878 int family
= AF_UNSPEC
) :
881 mFunction
= boost::bind(&ResolverTask::resolve
,
882 this, service
, host
, type
, family
);
887 * Get whether or not the task is done.
888 * \return True if the task has finished, false otherwise.
896 * Start the task. This does nothing if the task was already run or is
901 if (!isDone() && !mThread
.isValid())
903 mThread
= Thread::detach(mFunction
);
909 * Get the addresses resolved. This is filled and safe to access after
911 * \return List of addresses.
914 const std::vector
<SocketAddress
>& addresses() const
922 int resolve(const std::string
& service
,
923 const std::string
& host
,
927 int status
= SocketAddress::resolve(service
, host
,
935 std::vector
<SocketAddress
> mAddressList
;
937 Thread::Function mFunction
;
943 #endif // _MOOF_SOCKET_HH_
This page took 0.075114 seconds and 5 git commands to generate.