1 // Copyright Leandro Lucarella 2008 - 2010.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file COPYING or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
7 #ifndef POSIXX_SOCKET_BASIC_SOCKET_HPP_
8 #define POSIXX_SOCKET_BASIC_SOCKET_HPP_
10 #include "../error.hpp" // posixx::error
11 #include "../static_assert.hpp" // static_assert
13 #include <string> // std::string
14 #include <utility> // std::pair
15 #include <sys/socket.h> // socket, send, recv, etc.
19 /// POSIX thin wrapper
34 * Connectionless, unreliable messages of a fixed maximum
39 * Reliable datagram layer that does not guarantee ordering.
43 * Sequenced, reliable, two-way connection-based datagram
46 * Sequenced, reliable, two-way connection-based data
47 * transmission path for datagrams of fixed maximum length;
48 * a consumer is required to read an entire packet with each
51 SEQPACKET = SOCK_SEQPACKET,
53 * Sequenced, reliable, two-way, connection-based byte streams.
55 * An out-of-band data transmission mechanism may be supported.
59 * Raw network protocol access.
67 * @see socket::shutdown().
72 RD = SHUT_RD, ///< Further receptions will be disallowed.
73 WR = SHUT_WR, ///< Further transmissions will be disallowed.
74 RDWR = SHUT_RDWR ///< Both will be disallowed.
78 * Generic socket interface.
80 * This class is thread-safe as it just stores a file descriptor for the socket.
84 template < typename TSockTraits >
88 /// Traits used by this socket
89 typedef TSockTraits traits;
92 * Create an endpoint for communication.
94 * @param type Type of socket.
95 * @param protocol Protocol number.
97 * @see socket(2), socket(7)
99 basic_socket(type type, int protocol = 0) throw (error);
102 * Create a socket instance from a file descriptor.
104 * This is mainly used by the accept() method and pair() function and
105 * should be used with care because it takes "ownership" of the file
106 * descriptor (it's closed by the destructor).
110 * @param fd Socket file descriptor.
112 explicit basic_socket(int fd) throw ();
115 * Bind a name to the socket.
117 * @param addr Protocol-dependant name to bind on.
121 void bind(const typename TSockTraits::sockaddr& addr) throw (error);
124 * Initiate a connection on the socket.
126 * @param addr Protocol-dependant name to connect to.
130 void connect(const typename TSockTraits::sockaddr& addr) throw (error);
133 * Get the socket name.
135 * @return Protocol-dependant name binded.
137 * @see getsockname(2)
139 typename TSockTraits::sockaddr name() const throw (error);
142 * Get the name of connected peer socket.
144 * @return Protocol-dependant name of the peer.
146 * @see getpeername(2)
148 typename TSockTraits::sockaddr peer_name() const throw (error);
151 * Send a message on the socket.
153 * @param buf Message buffer.
154 * @param n Message length.
155 * @param flags Sending options.
157 * @return The number of characters sent.
159 * @see send(2), connect()
161 * @todo make an enum for the flags (are they protocol-dependant?)
163 ssize_t send(const void* buf, size_t n, int flags = 0) throw (error);
166 * Receive a message on the socket.
168 * @param buf Message buffer.
169 * @param n Maximum message length.
170 * @param flags Receiving options.
172 * @return The number of characters received.
174 * @see recv(2), connect()
176 * @todo make an enum for the flags (are they protocol-dependant?)
178 ssize_t recv(void* buf, size_t n, int flags = 0) throw (error);
181 * Send a message on the socket to a specific name.
183 * @param buf Message buffer.
184 * @param n Message length.
185 * @param to Name to send the message to.
186 * @param flags Sending options.
188 * @return The number of characters sent.
192 * @todo make an enum for the flags (are they protocol-dependant?)
194 ssize_t send(const void* buf, size_t n,
195 const typename TSockTraits::sockaddr& to,
196 int flags = 0) throw (error);
199 * Receive a message on the socket from a specific name.
201 * @param buf Message buffer.
202 * @param n Maximum message length.
203 * @param from Name to receive the message from.
204 * @param flags Receiving options.
206 * @return The number of characters received.
210 * @todo make an enum for the flags (are they protocol-dependant?)
212 ssize_t recv(void* buf, size_t n, typename TSockTraits::sockaddr& from,
213 int flags = 0) throw (error);
216 * Get options on the socket.
218 * @param level Level at which the option reside.
219 * @param optname Name of the option.
220 * @param opt Where to store the option value.
224 template< typename TSockOpt >
225 void getsockopt(int level, int optname, TSockOpt& opt) const
229 * Set options on the socket.
231 * @param level Level at which the option reside.
232 * @param optname Name of the option.
233 * @param opt New option value.
237 template< typename TSockOpt >
238 void setsockopt(int level, int optname, const TSockOpt& opt)
242 * Get option on the socket (type-safe).
244 * Note that template argument must be specified explicitly, and the
245 * template argument must be a valid socket option, which is a struct
246 * with 5 members: level, optname, read, write and type. level and
247 * optname must be the corresponding SOL_* and SO_* constants. read and
248 * write must be boolean constants indicating if the options can be
249 * read or written. type should be the type of the option's argument.
251 * See sockopt namespaces for available options.
253 * @return Option value
257 template< typename TSockOpt >
258 typename TSockOpt::type opt() const throw (error);
261 * Set option on the socket (type-safe).
263 * See getsockopt() for details on how options can be constructed.
265 * @param opt Option value
269 template< typename TSockOpt >
270 void opt(const typename TSockOpt::type& opt) throw (error);
273 * Listen for connections on the socket.
275 * @param backlog Maximum length the queue of pending
276 * connections may grow to.
278 * @see accept(), listen(2)
280 void listen(int backlog = 5) throw (error);
283 * Accept a connection on the socket.
285 * @see listen(), accept(2)
287 basic_socket* accept() throw (error);
290 * Accept a connection on the socket.
292 * @param addr Address of the peer socket, as known to the
293 * communications layer.
295 * @see listen(), accept(2)
297 basic_socket* accept(typename TSockTraits::sockaddr& addr)
301 * Shut down part of a full-duplex connection.
303 * @param how How the connection is shutted down.
307 void shutdown(shutdown_mode how = RDWR) throw (error);
310 * Close the socket file descriptor.
314 void close() throw (error);
321 * @see shutdown(), close()
323 ~basic_socket() throw ();
328 * Send a message on the socket.
330 * The message could be any struct and is sent as binary data without
331 * any concerns about the byte-order.
333 * This is a shortcut for the low-level send() method, where the
334 * message length is calculated as sizeof(TPacket).
336 * Of course, TPacket should be a POD type, without pointers or
339 * This method loops on the low-level send() until all the data is
340 * sent, or throws an exception if the send() can't be completed.
342 * @param packet Message struct to send.
343 * @param flags Sending options.
347 * @todo make an enum for the flags (are they protocol-dependant?)
349 template< typename TPacket >
350 void send_struct(const TPacket& packet, int flags = MSG_NOSIGNAL)
354 * Receive a message on the socket.
356 * The message could be any struct and is received as binary data
357 * without any concerns about the byte-order.
359 * This is a shortcut for the low-level recv() method, where the
360 * message length is calculated as sizeof(TPacket).
362 * Of course, TPacket should be a POD type, without pointers or
365 * This method loops on the low-level recv() until all the data is
366 * received, or throws an exception if the recv() can't be completed.
368 * @param packet Message struct to receive on.
369 * @param flags Sending options.
373 * @todo make an enum for the flags (are they protocol-dependant?)
375 template< typename TPacket >
376 void recv_struct(TPacket& packet,
377 int flags = MSG_NOSIGNAL | MSG_WAITALL) throw (error);
380 * Send a message on the socket to a specific name.
382 * This method behaves the same as send(const TPacket& packet, int
383 * flags) but sending to a specific name.
385 * @param packet Message struct to send.
386 * @param to Name to send the message to.
387 * @param flags Sending options.
391 * @todo make an enum for the flags (are they protocol-dependant?)
393 template< typename TPacket >
394 void send_struct(const TPacket& packet,
395 const typename TSockTraits::sockaddr& to,
396 int flags = MSG_NOSIGNAL) throw (error);
399 * Receive a message on the socket from a specific name.
401 * This method behaves the same as recv(TPacket& packet, int flags) but
402 * receiving from a specific name.
404 * @param packet Message struct to receive to.
405 * @param from Name to receive the message from.
406 * @param flags Receiving options.
410 * @todo make an enum for the flags (are they protocol-dependant?)
412 template< typename TPacket >
413 void recv_struct(TPacket& packet, typename TSockTraits::sockaddr& from,
414 int flags = MSG_NOSIGNAL | MSG_WAITALL) throw (error);
417 * Get the socket file descriptor.
419 * You should be careful when using the socket file descriptor, and you
420 * should not close it since it's closed by the destructor.
422 * @return Socket file descriptor.
424 int fd() const throw ();
427 * Convert the socket to a file descriptor.
429 * This is really a shortcut to fd(), useful to pass a socket to a low
432 * @return Socket file descriptor.
434 operator int () const throw ();
438 /// Hidden copy constructor (it has non-copiable behavior).
439 basic_socket(const basic_socket& s);
441 /// Hidden assign operator (it has non-assignable behavior).
442 basic_socket& operator=(const basic_socket& s);
444 /// Socket file descriptor.
450 * Create a pair of connected sockets.
452 * @param type Type of socket.
453 * @param protocol Protocol number.
455 * @return The new connected pair of sockets.
459 template < typename TSock >
461 std::pair< TSock*, TSock* > pair(type type, int protocol = 0) throw (error);
463 } } // namespace posixx::socket
468 template < typename TSock >
469 std::pair< TSock*, TSock* > posixx::socket::pair(type type, int protocol)
470 throw (posixx::error)
473 if (::socketpair(TSock::traits::PF, type, protocol, fds) == -1)
474 throw error("socketpair");
475 return std::make_pair(new TSock(fds[0]), new TSock(fds[1]));
479 template< typename TSockTraits >
481 posixx::socket::basic_socket< TSockTraits >::basic_socket(int fd) throw ():
486 template< typename TSockTraits >
488 posixx::socket::basic_socket< TSockTraits >::basic_socket(type type,
489 int protocol) throw (posixx::error)
491 _fd = ::socket(TSockTraits::PF, type, protocol);
493 throw error("socket");
496 template< typename TSockTraits >
498 void posixx::socket::basic_socket< TSockTraits >::bind(
499 const typename TSockTraits::sockaddr& addr)
500 throw (posixx::error)
502 if (::bind(_fd, reinterpret_cast< const ::sockaddr* >(&addr),
503 addr.length()) == -1)
507 template< typename TSockTraits >
509 void posixx::socket::basic_socket< TSockTraits >::connect(
510 const typename TSockTraits::sockaddr& addr)
511 throw (posixx::error)
513 if (::connect(_fd, reinterpret_cast< const ::sockaddr* >(&addr),
514 addr.length()) == -1)
515 throw error("connect");
518 template< typename TSockTraits >
520 typename TSockTraits::sockaddr posixx::socket::basic_socket< TSockTraits >::name()
521 const throw (posixx::error)
523 typename TSockTraits::sockaddr addr;
524 socklen_t len = sizeof(typename TSockTraits::sockaddr);
525 // TODO assert len == sizeof(typename TSockTraits::sockaddr)
526 if (::getsockname(_fd, reinterpret_cast< ::sockaddr* >(&addr), &len) == -1)
527 throw error("getsockname");
531 template< typename TSockTraits >
533 typename TSockTraits::sockaddr
534 posixx::socket::basic_socket< TSockTraits >::peer_name() const throw (posixx::error)
536 typename TSockTraits::sockaddr addr;
537 socklen_t len = sizeof(typename TSockTraits::sockaddr);
538 // TODO assert len == sizeof(typename TSockTraits::sockaddr)
539 if (::getpeername(_fd, reinterpret_cast< ::sockaddr* >(&addr), &len) == -1)
540 throw error("getpeername");
544 template< typename TSockTraits >
546 ssize_t posixx::socket::basic_socket< TSockTraits >::send(const void* buf,
547 size_t n, int flags) throw (posixx::error)
549 ssize_t s = ::send(_fd, buf, n, flags);
553 throw error("send connection shutdown"); // XXX
557 template< typename TSockTraits >
559 ssize_t posixx::socket::basic_socket< TSockTraits >::recv(void* buf, size_t n, int flags)
560 throw (posixx::error)
562 ssize_t s = ::recv(_fd, buf, n, flags);
566 throw error("recv connection shutdown"); // XXX
570 template< typename TSockTraits >
572 ssize_t posixx::socket::basic_socket< TSockTraits >::send(const void* buf,
573 size_t n, const typename TSockTraits::sockaddr& to, int flags)
574 throw (posixx::error)
576 ssize_t s = ::sendto(_fd, buf, n, flags,
577 reinterpret_cast< const ::sockaddr* >(&to),
580 throw error("sendto");
582 error e("sendto client shutdown"); // XXX
589 template< typename TSockTraits >
591 ssize_t posixx::socket::basic_socket< TSockTraits >::recv(void* buf, size_t n,
592 typename TSockTraits::sockaddr& from, int flags)
593 throw (posixx::error)
595 socklen_t len = sizeof(typename TSockTraits::sockaddr);
596 ssize_t s = ::recvfrom(_fd, buf, n, flags,
597 reinterpret_cast< ::sockaddr* >(&from), &len);
599 throw error("recvfrom");
601 error e("recvfrom client shutdown"); // XXX
609 template< typename TSockTraits >
611 ssize_t posixx::socket::basic_socket< TSockTraits >::send(const msghdr* msg, int flags)
613 ssize_t s = ::sendmsg(_fd, msg, flags);
615 throw error("sendmsg");
621 template< typename TSockTraits >
623 ssize_t posixx::socket::basic_socket< TSockTraits >::recv(struct msghdr* msg, int flags)
625 ssize_t s = ::recvmsg(_fd, msg, flags);
627 throw error("recvmsg");
634 template< typename TSockTraits >
635 template< typename TSockOpt >
637 void posixx::socket::basic_socket< TSockTraits >::getsockopt(int level, int optname,
638 TSockOpt& opt) const throw (posixx::error)
640 socklen_t len = sizeof(TSockOpt);
641 if (::getsockopt(_fd, level, optname, &opt, &len) == -1) // TODO assert len == sizeof(TSockOpt)
642 throw error("getsockopt");
645 template< typename TSockTraits >
646 template< typename TSockOpt >
648 void posixx::socket::basic_socket< TSockTraits >::setsockopt(int level, int optname,
649 const TSockOpt& opt) throw (posixx::error)
651 if (::setsockopt(_fd, level, optname, &opt, sizeof(TSockOpt)) == -1)
652 throw error("setsockopt");
655 template< typename TSockTraits >
656 template< typename TSockOpt >
658 typename TSockOpt::type posixx::socket::basic_socket< TSockTraits >::opt() const
659 throw (posixx::error)
661 static_assert(TSockOpt::read, "Option is not readable");
662 typename TSockOpt::type opt;
663 socklen_t len = sizeof(opt);
664 // TODO assert len == sizeof(TSockOpt)
665 if (::getsockopt(_fd, TSockOpt::level, TSockOpt::optname, &opt, &len) == -1)
666 throw error("getsockopt");
670 template< typename TSockTraits >
671 template< typename TSockOpt >
673 void posixx::socket::basic_socket< TSockTraits >::opt(
674 const typename TSockOpt::type& opt) throw (posixx::error)
676 static_assert(TSockOpt::write, "Option is not writable");
677 if (::setsockopt(_fd, TSockOpt::level, TSockOpt::optname, &opt,
678 sizeof(typename TSockOpt::type)) == -1)
679 throw error("setsockopt");
682 template< typename TSockTraits >
684 void posixx::socket::basic_socket< TSockTraits >::listen(int backlog) throw (posixx::error)
686 if (::listen(_fd, backlog) == -1)
687 throw error("listen");
690 template< typename TSockTraits >
692 posixx::socket::basic_socket< TSockTraits >* posixx::socket::basic_socket< TSockTraits >::accept()
693 throw (posixx::error)
695 int fd = ::accept(_fd, 0, 0);
697 throw error("accept");
698 return new basic_socket(fd);
701 template< typename TSockTraits >
703 posixx::socket::basic_socket< TSockTraits >*
704 posixx::socket::basic_socket< TSockTraits >::accept(typename TSockTraits::sockaddr& addr)
705 throw (posixx::error)
707 socklen_t len = sizeof(typename TSockTraits::sockaddr);
708 // TODO assert len = sizeof(typename TSockTraits::sockaddr)
709 int fd = ::accept(_fd, reinterpret_cast< ::sockaddr* >(&addr), &len);
711 throw error("accept");
712 return new basic_socket(fd);
715 template< typename TSockTraits >
717 void posixx::socket::basic_socket< TSockTraits >::shutdown(shutdown_mode how)
718 throw (posixx::error)
720 if (::shutdown(_fd, how) == -1)
721 throw error("shutdown");
724 template< typename TSockTraits >
726 void posixx::socket::basic_socket< TSockTraits >::close() throw (posixx::error)
728 if (::close(_fd) == -1)
729 throw error("close");
733 template< typename TSockTraits >
735 posixx::socket::basic_socket< TSockTraits >::~basic_socket() throw ()
741 template< typename TSockTraits >
742 template< typename TPacket >
743 void posixx::socket::basic_socket< TSockTraits >::send_struct(
744 const TPacket& packet, int flags) throw (posixx::error)
747 while (static_cast< unsigned >(s) < sizeof(TPacket))
751 s += send(&packet + s, sizeof(TPacket) - s, flags);
753 catch (const error& e)
755 if (e.no != EINTR && e.no != EAGAIN)
759 if (static_cast< unsigned >(s) != sizeof(TPacket))
760 throw error("send size not match");
763 template< typename TSockTraits >
764 template< typename TPacket >
766 void posixx::socket::basic_socket< TSockTraits >::recv_struct(TPacket& packet, int flags)
767 throw (posixx::error)
770 while (static_cast< unsigned >(s) < sizeof(TPacket))
774 s += recv(&packet + s, sizeof(TPacket) - s, flags);
776 catch (const error& e)
778 if (e.no != EINTR && e.no != EAGAIN && e.no != EWOULDBLOCK)
782 if (static_cast< unsigned >(s) != sizeof(TPacket))
783 throw error("recv size not match");
786 template< typename TSockTraits >
787 template< typename TPacket >
789 void posixx::socket::basic_socket< TSockTraits >::send_struct(
790 const TPacket& packet,
791 const typename TSockTraits::sockaddr& to,
792 int flags) throw (posixx::error)
795 while (static_cast< unsigned >(s) < sizeof(TPacket))
799 s += send(&packet + s, sizeof(TPacket) - s, to, flags);
801 catch (const error& e)
803 if (e.no != EINTR && e.no != EAGAIN)
807 if (static_cast< unsigned >(s) != sizeof(TPacket))
808 throw error("send size not match");
811 template< typename TSockTraits >
812 template< typename TPacket >
814 void posixx::socket::basic_socket< TSockTraits >::recv_struct(TPacket& packet,
815 typename TSockTraits::sockaddr& from, int flags)
816 throw (posixx::error)
819 while (static_cast< unsigned >(s) < sizeof(TPacket))
823 s += recv(&packet + s, sizeof(TPacket) - s, from, flags);
825 catch (const error& e)
827 if (e.no != EINTR && e.no != EAGAIN && e.no != EWOULDBLOCK)
831 if (static_cast< unsigned >(s) != sizeof(TPacket))
832 throw error("recv size not match");
835 template< typename TSockTraits >
837 int posixx::socket::basic_socket< TSockTraits >::fd() const throw ()
842 template< typename TSockTraits >
844 posixx::socket::basic_socket< TSockTraits >::operator int () const throw ()
851 template< typename TSockTraits >
852 template< typename TPacket >
854 void send(const TPacket& packet) // TODO specialize with std::string
858 template< typename TSockTraits >
859 template< typename TPacket >
861 void recv(TPacket& packet) // TODO specialize with std::string
865 template< typename TSockTraits >
867 void recv(std::string& buf, size_t n)
872 #endif // _POSIXX_SOCKET_BASIC_SOCKET_HPP_