changeset 245:3c12f0e8bbb9

Converter: add cstring missing Sockets: * Starts a PIMPL idiom to safely cast Socket with the future SocketSsl and be able to return a class of type "Socket" whilst the interface returns effectively a SocketSsl. * Rename some function to be more cute to use like getDomain -> domain(). * SocketListener now owns completely sockets and must be moved to it, the dedicated function select() always return a socket owned by SocketListener. * Operation close is not needed anymore but the function stays in case it's needed.
author David Demelier <markand@malikania.fr>
date Sun, 28 Sep 2014 21:15:26 +0200
parents 777bc3cb665a
children 9cfa6fbc9c03 d157f4747676
files C++/Converter.cpp C++/Socket.cpp C++/Socket.h C++/SocketAddress.cpp C++/SocketAddress.h C++/SocketListener.cpp C++/SocketListener.h
diffstat 7 files changed, 498 insertions(+), 330 deletions(-) [+]
line wrap: on
line diff
--- a/C++/Converter.cpp	Sat Sep 13 19:42:15 2014 +0200
+++ b/C++/Converter.cpp	Sun Sep 28 21:15:26 2014 +0200
@@ -17,6 +17,7 @@
  */
 
 #include <cerrno>
+#include <cstring>
 #include <string>
 #include <iterator>
 #include <memory>
--- a/C++/Socket.cpp	Sat Sep 13 19:42:15 2014 +0200
+++ b/C++/Socket.cpp	Sun Sep 28 21:15:26 2014 +0200
@@ -31,7 +31,7 @@
 	m_error = error;
 }
 
-const char *SocketError::what() const throw()
+const char *SocketError::what() const noexcept
 {
 	return m_error.c_str();
 }
@@ -54,7 +54,7 @@
 
 #if defined(_WIN32)
 
-std::string Socket::getLastSysError()
+std::string Socket::syserror()
 {
 	LPSTR str = nullptr;
 	std::string errmsg = "Unknown error";
@@ -77,7 +77,9 @@
 
 #else
 
-std::string Socket::getLastSysError()
+#include <cerrno>
+
+std::string Socket::syserror()
 {
 	return strerror(errno);
 }
@@ -91,6 +93,128 @@
 #endif
 }
 
+/* --------------------------------------------------------
+ * Standard clear implementation
+ * -------------------------------------------------------- */
+
+class Standard final : public SocketInterface {
+public:
+	void bind(Socket &s, const SocketAddress &address) override;
+	void close(Socket &s) override;
+	void connect(Socket &s, const SocketAddress &address) override;
+	Socket accept(Socket &s, SocketAddress &info) override;
+	void listen(Socket &s, int max) override;
+	unsigned recv(Socket &s, void *data, unsigned len) override;
+	unsigned recvfrom(Socket &s, void *data, unsigned len, SocketAddress &info) override ;
+	unsigned send(Socket &s, const void *data, unsigned len) override;
+	unsigned sendto(Socket &s, const void *data, unsigned len, const SocketAddress &info) override;
+};
+
+void Standard::bind(Socket &s, const SocketAddress &addr)
+{
+	auto &sa = addr.address();
+	auto addrlen = addr.length();
+
+
+	if (::bind(s.handle(), (sockaddr *)&sa, addrlen) == SOCKET_ERROR)
+		throw SocketError(Socket::syserror());
+}
+
+void Standard::connect(Socket &s, const SocketAddress &addr)
+{
+	auto &sa = addr.address();
+	auto addrlen = addr.length();
+
+	if (::connect(s.handle(), (sockaddr *)&sa, addrlen) == SOCKET_ERROR)
+		throw SocketError(Socket::syserror());
+}
+
+Socket Standard::accept(Socket &s, SocketAddress &info)
+{
+	Socket c;
+	Socket::Handle handle;
+
+	// Store the information
+	sockaddr_storage address;
+	socklen_t addrlen;
+
+	addrlen = sizeof (sockaddr_storage);
+	handle = ::accept(s.handle(), (sockaddr *)&address, &addrlen);
+
+	if (handle == INVALID_SOCKET)
+		throw SocketError(Socket::syserror());
+
+	// Usually accept works only with SOCK_STREAM
+	info = SocketAddress(address, addrlen);
+
+	return Socket(handle, address.ss_family, s.type(), s.protocol());
+}
+
+void Standard::listen(Socket &s, int max)
+{
+	if (::listen(s.handle(), max) == SOCKET_ERROR)
+		throw SocketError(Socket::syserror());
+}
+
+unsigned Standard::recv(Socket &s, void *data, unsigned dataLen)
+{
+	int nbread;
+
+	nbread = ::recv(s.handle(), (Socket::Arg)data, dataLen, 0);
+	if (nbread == SOCKET_ERROR)
+		throw SocketError(Socket::syserror());
+
+	return (unsigned)nbread;
+}
+
+unsigned Standard::send(Socket &s, const void *data, unsigned dataLen)
+{
+	int nbsent;
+
+	nbsent = ::send(s.handle(), (Socket::ConstArg)data, dataLen, 0);
+	if (nbsent == SOCKET_ERROR)
+		throw SocketError(Socket::syserror());
+
+	return (unsigned)nbsent;
+}
+
+unsigned Standard::recvfrom(Socket &s, void *data, unsigned dataLen, SocketAddress &info)
+{
+	int nbread;
+
+	// Store information
+	sockaddr_storage address;
+	socklen_t addrlen;
+
+	addrlen = sizeof (struct sockaddr_storage);
+	nbread = ::recvfrom(s.handle(), (Socket::Arg)data, dataLen, 0, (sockaddr *)&address, &addrlen);
+
+	if (nbread == SOCKET_ERROR)
+		throw SocketError(Socket::syserror());
+
+	return (unsigned)nbread;
+}
+
+unsigned Standard::sendto(Socket &s, const void *data, unsigned dataLen, const SocketAddress &info)
+{
+	int nbsent;
+
+	nbsent = ::sendto(s.handle(), (Socket::ConstArg)data, dataLen, 0, (const sockaddr *)&info.address(), info.length());
+	if (nbsent == SOCKET_ERROR)
+		throw SocketError(Socket::syserror());
+
+	return (unsigned)nbsent;
+}
+
+void Standard::close(Socket &s)
+{
+	(void)closesocket(s.handle());
+}
+
+/* --------------------------------------------------------
+ * Socket code
+ * -------------------------------------------------------- */
+
 Socket::Socket()
 	: m_domain(0)
 	, m_type(0)
@@ -99,42 +223,86 @@
 }
 
 Socket::Socket(int domain, int type, int protocol)
-	: m_domain(domain)
+	: m_interface(std::make_unique<Standard>())
+	, m_domain(domain)
 	, m_type(type)
 	, m_protocol(protocol)
 {
-	Type s = socket(domain, type, protocol);
+	m_handle = socket(domain, type, protocol);
+
+	if (m_handle == INVALID_SOCKET)
+		throw SocketError(syserror());
+
+	m_open = true;
+}
 
-	if (s == INVALID_SOCKET)
-		throw SocketError(getLastSysError());
-
-	m_socket = std::shared_ptr<Type>(new Type(s), deleter);
+Socket::Socket(Handle handle, int domain, int type, int protocol)
+	: m_handle(handle)
+	, m_domain(domain)
+	, m_type(type)
+	, m_protocol(protocol)
+	, m_open(true)
+{
 }
 
-Socket::Type Socket::getSocket() const
+Socket::Socket(Socket &&other) noexcept
+	: m_interface(std::move(other.m_interface))
+	, m_handle(std::move(other.m_handle))
+	, m_domain(other.m_domain)
+	, m_type(other.m_type)
+	, m_protocol(other.m_protocol)
+	, m_open(true)
 {
-	return *m_socket;
+	// invalidate other
+	other.m_handle = 0;
+	other.m_open = false;
 }
 
-int Socket::getDomain() const
+Socket &Socket::operator=(Socket &&other) noexcept
+{
+	m_interface = std::move(other.m_interface);
+	m_handle = std::move(other.m_handle);
+	m_domain = other.m_domain;
+	m_type = other.m_type;
+	m_protocol = other.m_protocol;
+	m_open = true;
+
+	// invalidate other
+	other.m_handle = 0;
+	other.m_open = false;
+
+	return *this;
+}
+
+Socket::~Socket()
+{
+	close();
+}
+
+Socket::Handle Socket::handle() const
+{
+	return m_handle;
+}
+
+int Socket::domain() const
 {
 	return m_domain;
 }
 
-int Socket::getType() const
+int Socket::type() const
 {
 	return m_type;
 }
 
-int Socket::getProtocol() const
+int Socket::protocol() const
 {
 	return m_protocol;
 }
 
 void Socket::set(int level, int name, const void *arg, unsigned argLen)
 {
-	if (setsockopt(*m_socket, level, name, (Socket::ConstArg)arg, argLen) == SOCKET_ERROR)
-		throw SocketError(getLastSysError());
+	if (setsockopt(m_handle, level, name, (Socket::ConstArg)arg, argLen) == SOCKET_ERROR)
+		throw SocketError(syserror());
 }
 
 void Socket::blockMode(bool block)
@@ -142,7 +310,7 @@
 #if defined(O_NONBLOCK) && !defined(_WIN32)
 	int flags;
 
-	if ((flags = fcntl(*m_socket, F_GETFL, 0)) == -1)
+	if ((flags = fcntl(m_handle, F_GETFL, 0)) == -1)
 		flags = 0;
 
 	if (!block)
@@ -150,86 +318,21 @@
 	else
 		flags |= O_NONBLOCK;
 
-	if (fcntl(*m_socket, F_SETFL, flags) == -1)
-		throw SocketError(getLastSysError());
+	if (fcntl(m_handle, F_SETFL, flags) == -1)
+		throw SocketError(Socket::syserror());
 #else
 	unsigned long flags = (block) ? 0 : 1;
 
-	if (ioctlsocket(*m_socket, FIONBIO, &flags) == SOCKET_ERROR)
-		throw SocketError(getLastSysError());
+	if (ioctlsocket(m_handle, FIONBIO, &flags) == SOCKET_ERROR)
+		throw SocketError(Socket::syserror());
 #endif
 }
 
-void Socket::bind(const SocketAddress &addr)
-{
-	const sockaddr_storage &sa = addr.address();
-	size_t addrlen = addr.length();
-
-	if (::bind(*m_socket, (sockaddr *)&sa, addrlen) == SOCKET_ERROR)
-		throw SocketError(getLastSysError());
-}
-
-void Socket::connect(const SocketAddress &addr)
-{
-	const sockaddr_storage &sa = addr.address();
-	size_t addrlen = addr.length();
-
-	if (::connect(*m_socket, (sockaddr *)&sa, addrlen) == SOCKET_ERROR)
-		throw SocketError(getLastSysError());
-}
-
 Socket Socket::accept()
 {
 	SocketAddress dummy;
 
-	return accept(dummy);
-}
-
-Socket Socket::accept(SocketAddress &info)
-{
-	Socket s;
-	Type handle;
-
-	info.m_addrlen = sizeof (sockaddr_storage);
-	handle = ::accept(*m_socket, (sockaddr *)&info.m_addr, &info.m_addrlen);
-
-	if (handle == INVALID_SOCKET)
-		throw SocketError(getLastSysError());
-
-	// Usually accept works only with SOCK_STREAM
-	s.m_socket	= std::shared_ptr<Type>(new Type(handle), deleter);
-	s.m_domain	= info.m_addr.ss_family;
-	s.m_type	= SOCK_STREAM;
-
-	return s;
-}
-
-void Socket::listen(int max)
-{
-	if (::listen(*m_socket, max) == SOCKET_ERROR)
-		throw SocketError(getLastSysError());
-}
-
-unsigned Socket::recv(void *data, unsigned dataLen)
-{
-	int nbread;
-
-	nbread = ::recv(*m_socket, (Socket::Arg)data, dataLen, 0);
-	if (nbread == SOCKET_ERROR)
-		throw SocketError(getLastSysError());
-
-	return (unsigned)nbread;
-}
-
-unsigned Socket::send(const void *data, unsigned dataLen)
-{
-	int nbsent;
-
-	nbsent = ::send(*m_socket, (Socket::ConstArg)data, dataLen, 0);
-	if (nbsent == SOCKET_ERROR)
-		throw SocketError(getLastSysError());
-
-	return (unsigned)nbsent;
+	return m_interface->accept(*this, dummy);
 }
 
 unsigned Socket::send(const std::string &message)
@@ -241,33 +344,7 @@
 {
 	SocketAddress dummy;
 
-	return recvfrom(data, dataLen, dummy);
-}
-
-unsigned Socket::recvfrom(void *data, unsigned dataLen, SocketAddress &info)
-{
-	int nbread;
-
-	info.m_addrlen = sizeof (struct sockaddr_storage);
-	nbread = ::recvfrom(*m_socket, (Socket::Arg)data, dataLen, 0,
-	    (sockaddr *)&info.m_addr, &info.m_addrlen);
-
-	if (nbread == SOCKET_ERROR)
-		throw SocketError(getLastSysError());
-
-	return (unsigned)nbread;
-}
-
-unsigned Socket::sendto(const void *data, unsigned dataLen, const SocketAddress &info)
-{
-	int nbsent;
-
-	nbsent = ::sendto(*m_socket, (Socket::ConstArg)data, dataLen, 0,
-	    (const sockaddr *)&info.m_addr, info.m_addrlen);
-	if (nbsent == SOCKET_ERROR)
-		throw SocketError(getLastSysError());
-
-	return (unsigned)nbsent;
+	return m_interface->recvfrom(*this, data, dataLen, dummy);
 }
 
 unsigned Socket::sendto(const std::string &message, const SocketAddress &info)
@@ -275,17 +352,12 @@
 	return sendto(message.c_str(), message.length(), info);
 }
 
-void Socket::close()
-{
-	(void)closesocket(*m_socket);
-}
-
 bool operator==(const Socket &s1, const Socket &s2)
 {
-	return s1.getSocket() == s2.getSocket();
+	return s1.handle() == s2.handle();
 }
 
 bool operator<(const Socket &s1, const Socket &s2)
 {
-	return s1.getSocket() < s2.getSocket();
+	return s1.handle() < s2.handle();
 }
--- a/C++/Socket.h	Sat Sep 13 19:42:15 2014 +0200
+++ b/C++/Socket.h	Sun Sep 28 21:15:26 2014 +0200
@@ -48,6 +48,7 @@
 #  define SOCKET_ERROR		-1
 #endif
 
+class Socket;
 class SocketAddress;
 
 /**
@@ -56,14 +57,114 @@
  *
  * This class is mainly used in all socket operations that may fail.
  */
-class SocketError : public std::exception {
+class SocketError final : public std::exception {
 private:
 	std::string m_error;
 
 public:
 	SocketError(const std::string &error);
 
-	virtual const char * what(void) const throw();
+	const char * what(void) const noexcept override;
+};
+
+/**
+ * @class SocketInterface
+ * @brief Interface to implement
+ *
+ * This class implements the socket functions.
+ */
+class SocketInterface {
+public:
+	/**
+	 * Bind the socket.
+	 *
+	 * @param s the socket
+	 * @param address the address
+	 * @throw SocketError error
+	 */
+	virtual void bind(Socket &s, const SocketAddress &address) = 0;
+
+	/**
+	 * Close the socket.
+	 *
+	 * @param s the socket
+	 */
+	virtual void close(Socket &s) = 0;
+
+	/**
+	 * Try to connect to the specific address
+	 *
+	 * @param s the socket
+	 * @param addr the address
+	 * @throw SocketError on error
+	 */
+	virtual void connect(Socket &s, const SocketAddress &address) = 0;
+
+	/**
+	 * Accept a client.
+	 *
+	 * @param s the socket
+	 * @param info the optional client info
+	 * @return a client ready to use
+	 * @throw SocketError on error
+	 */
+	virtual Socket accept(Socket &s, SocketAddress &info) = 0;
+
+	/**
+	 * Listen to a specific number of pending connections.
+	 *
+	 * @param s the socket
+	 * @param max the max number of clients
+	 * @throw SocketError on error
+	 */
+	virtual void listen(Socket &s, int max) = 0;
+
+	/**
+	 * Receive some data.
+	 *
+	 * @param s the socket
+	 * @param data the destination pointer
+	 * @param dataLen max length to receive
+	 * @return the number of bytes received
+	 * @throw SocketError on error
+	 */
+	virtual unsigned recv(Socket &s, void *data, unsigned len) = 0;
+
+	/**
+	 * Receive from a connection-less socket and get the client
+	 * information.
+	 *
+	 * @param s the socket
+	 * @param data the destination pointer
+	 * @param dataLen max length to receive
+	 * @param info the client info
+	 * @return the number of bytes received
+	 * @throw SocketError on error
+	 */
+	virtual unsigned recvfrom(Socket &s, void *data, unsigned len, SocketAddress &info) = 0;
+
+	/**
+	 * Send some data.
+	 *
+	 * @param s the socket
+	 * @param data the data to send
+	 * @param dataLen the data length
+	 * @return the number of bytes sent
+	 * @throw SocketError on error
+	 */
+	virtual unsigned send(Socket &s, const void *data, unsigned len) = 0;
+
+	/**
+	 * Send some data to a connection-less socket.
+	 *
+	 * @param s the socket
+	 * @param data the data to send
+	 * @param dataLen the data length
+	 * @param address the address
+	 * @return the number of bytes sent
+	 * @throw SocketError on error
+	 */
+	virtual unsigned sendto(Socket &s, const void *data, unsigned len, const SocketAddress &info) = 0;
 };
 
 /**
@@ -72,34 +173,36 @@
  *
  * This class is a big wrapper around sockets functions but portable,
  * there is some functions that helps for getting error reporting.
+ *
+ * This class is implemented as a PIMPL idiom, it is perfectly
+ * safe to cast the object to any other derivate children.
  */
 class Socket {
 public:
 #if defined(_WIN32)
-	using Type	= SOCKET;
+	using Handle	= SOCKET;
 	using ConstArg	= const char *;
 	using Arg	= char *;
 #else
-	using Type	= int;
+	using Handle	= int;
 	using ConstArg	= const void *;
 	using Arg	= void *;
 #endif
 
-	using Ptr	= std::shared_ptr<Type>;
+	using Iface	= std::unique_ptr<SocketInterface>;
 
 private:
-	static inline void deleter(Type *t)
-	{
-		closesocket(*t);
-
-		delete t;
-	}
+	// Be sure to not copy the socket
+	Socket(const Socket &) = delete;
+	Socket &operator=(const Socket &) = delete;
 
 protected:
-	Ptr	m_socket;	//!< the socket shared pointer
-	int	m_domain;	//!< the family
-	int	m_type;		//!< the type
-	int	m_protocol;	//!< the protocol
+	Iface	m_interface;		//!< the interface
+	Handle	m_handle;		//!< the socket shared pointer
+	int	m_domain;		//!< the domain
+	int	m_type;			//!< the type
+	int	m_protocol;		//!< the protocol
+	bool	m_open { false };	//!< socket is valid and open
 
 public:
 	/**
@@ -112,7 +215,7 @@
 	 *
 	 * @return a string message
 	 */
-	static std::string getLastSysError();
+	static std::string syserror();
 
 	/**
 	 * To be called before exiting.
@@ -135,37 +238,62 @@
 	Socket(int domain, int type, int protocol);
 
 	/**
-	 * Destruct the socket and the handle.
+	 * Create a socket object with a already initialized socket.
+	 *
+	 * @param handle the handle
+	 * @param domain the domain
+	 * @param type the type
+	 * @param protocol the protocol
+	 */
+	Socket(Handle handle, int domain, int type, int protocol);
+
+	/**
+	 * Move constructor, transfers the socket handle.
+	 *
+	 * @param other the other
 	 */
-	virtual ~Socket() = default;
+	Socket(Socket &&other) noexcept;
+
+	/**
+	 * Move operator, transfers the socket handle.
+	 *
+	 * @param other the other
+	 * @return *this
+	 */
+	Socket &operator=(Socket &&) noexcept;
+
+	/**
+	 * Close the socket.
+	 */
+	virtual ~Socket();
 
 	/**
 	 * Get the socket.
 	 *
 	 * @return the socket
 	 */
-	Type getSocket() const;
+	Handle handle() const;
 
 	/**
 	 * Get the domain.
 	 *
 	 * @return the domain
 	 */
-	int getDomain() const;
+	int domain() const;
 
 	/**
 	 * Get the type of socket.
 	 *
 	 * @return the type
 	 */
-	int getType() const;
+	int type() const;
 
 	/**
 	 * Get the protocol.
 	 *
 	 * @return the protocol
 	 */
-	int getProtocol() const;
+	int protocol() const;
 
 	/**
 	 * Set an option for the socket.
@@ -186,20 +314,31 @@
 	void blockMode(bool block = true);
 
 	/**
-	 * Bind the socket.
-	 *
-	 * @param location a IP or Unix location
-	 * @throw SocketError error
+	 * @copydoc SocketInterface::bind
 	 */
-	void bind(const SocketAddress &address);
+	inline void bind(const SocketAddress &address)
+	{
+		m_interface->bind(*this, address);
+	}
 
 	/**
-	 * Try to connect to the specific address
-	 *
-	 * @param addr the address
-	 * @throw SocketError on error
+	 * @copydoc SocketInterface::close
 	 */
-	virtual void connect(const SocketAddress &address);
+	inline void close()
+	{
+		if (m_open) {
+			m_interface->close(*this);
+			m_open = false;
+		}
+	}
+
+	/**
+	 * @copydoc SocketInterface::connect
+	 */
+	inline void connect(const SocketAddress &address)
+	{
+		m_interface->connect(*this, address);
+	}
 
 	/**
 	 * Accept a client without getting its info.
@@ -207,53 +346,31 @@
 	 * @return a client ready to use
 	 * @throw SocketError on error
 	 */
-	virtual Socket accept();
+	Socket accept();
 
 	/**
-	 * Accept a client.
-	 *
-	 * @param info the optional client info
-	 * @return a client ready to use
-	 * @throw SocketError on error
+	 * @copydoc SocketInterface::accept
 	 */
-	virtual Socket accept(SocketAddress &info);
-
-	/**
-	 * Listen to a specific number of pending connections.
-	 *
-	 * @param max the max number of clients
-	 * @throw SocketError on error
-	 */
-	void listen(int max);
+	inline Socket accept(SocketAddress &info)
+	{
+		return m_interface->accept(*this, info);
+	}
 
 	/**
-	 * Receive some data.
-	 *
-	 * @param data the destination pointer
-	 * @param dataLen max length to receive
-	 * @return the number of bytes received
-	 * @throw SocketError on error
+	 * @copydoc SocketInterface::listen
 	 */
-	virtual unsigned recv(void *data, unsigned dataLen);
+	inline void listen(int max)
+	{
+		m_interface->listen(*this, max);
+	}
 
 	/**
-	 * Send some data.
-	 *
-	 * @param data the data to send
-	 * @param dataLen the data length
-	 * @return the number of bytes sent
-	 * @throw SocketError on error
+	 * @copydoc SocketInterface::recv
 	 */
-	virtual unsigned send(const void *data, unsigned dataLen);
-
-	/**
-	 * Send a message as a string.
-	 *
-	 * @param message the message
-	 * @return the number of bytes sent
-	 * @throw SocketError on error
-	 */
-	unsigned send(const std::string &message);
+	inline unsigned recv(void *data, unsigned dataLen)
+	{
+		return m_interface->recv(*this, data, dataLen);
+	}
 
 	/**
 	 * Receive from a connection-less socket without getting
@@ -267,27 +384,37 @@
 	unsigned recvfrom(void *data, unsigned dataLen);
 
 	/**
-	 * Receive from a connection-less socket and get the client
-	 * information.
-	 *
-	 * @param data the destination pointer
-	 * @param dataLen max length to receive
-	 * @param info the client info
-	 * @return the number of bytes received
-	 * @throw SocketError on error
+	 * @copydoc SocketInterface::recvfrom
 	 */
-	unsigned recvfrom(void *data, unsigned dataLen, SocketAddress &info);
+	inline unsigned recvfrom(void *data, unsigned dataLen, SocketAddress &info)
+	{
+		return m_interface->recvfrom(*this, data, dataLen, info);
+	}
 
 	/**
-	 * Send some data to a connection-less socket.
+	 * @copydoc SocketInterface::send
+	 */
+	inline unsigned send(const void *data, unsigned dataLen)
+	{
+		return m_interface->send(*this, data, dataLen);
+	}
+
+	/**
+	 * Send a message as a string.
 	 *
-	 * @param data the data to send
-	 * @param dataLen the data length
-	 * @param address the address
+	 * @param message the message
 	 * @return the number of bytes sent
 	 * @throw SocketError on error
 	 */
-	unsigned sendto(const void *data, unsigned dataLen, const SocketAddress &info);
+	unsigned send(const std::string &message);
+
+	/**
+	 * @copydoc SocketInterface::sendto
+	 */
+	inline unsigned sendto(const void *data, unsigned dataLen, const SocketAddress &info)
+	{
+		return m_interface->sendto(*this, data, dataLen, info);
+	}
 
 	/**
 	 * Send a message to a connection-less socket.
@@ -298,11 +425,6 @@
 	 * @throw SocketError on error
 	 */
 	unsigned sendto(const std::string &message, const SocketAddress &info);
-
-	/**
-	 * Close the socket.
-	 */
-	virtual void close();
 };
 
 bool operator==(const Socket &s1, const Socket &s2);
--- a/C++/SocketAddress.cpp	Sat Sep 13 19:42:15 2014 +0200
+++ b/C++/SocketAddress.cpp	Sun Sep 28 21:15:26 2014 +0200
@@ -16,80 +16,56 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <cerrno>
-#include <cstdio>
 #include <cstring>
 
+#include "Socket.h"
 #include "SocketAddress.h"
 
+namespace address {
+
 /* --------------------------------------------------------
- * BindAddressIP implementation
+ * Internet implementation
  * -------------------------------------------------------- */
 
-BindAddressIP::BindAddressIP(const std::string &iface, unsigned port, int family)
-	: m_host(iface)
-	, m_family(family)
-	, m_port(port)
+Internet::Internet(const std::string &host, unsigned port, int domain)
 {
-	if (m_family == AF_INET6) {
-		sockaddr_in6 *ptr = (sockaddr_in6 *)&m_addr;
+	if (host == "*") {
+		if (domain == AF_INET6) {
+			sockaddr_in6 *ptr = (sockaddr_in6 *)&m_addr;
 
-		ptr->sin6_family = AF_INET6;
-		ptr->sin6_port = htons(m_port);
+			ptr->sin6_family = AF_INET6;
+			ptr->sin6_port = htons(port);
+		} else {
+			sockaddr_in *ptr = (sockaddr_in *)&m_addr;
 
-		if (m_host == "*")
-			ptr->sin6_addr = in6addr_any;
-		else if (inet_pton(AF_INET6, m_host.c_str(), &ptr->sin6_addr) <= 0)
-			throw SocketError(Socket::getLastSysError());
-
-		m_addrlen = sizeof (sockaddr_in6);
+			ptr->sin_family = AF_INET;
+			ptr->sin_port = htons(port);
+		}
 	} else {
-		sockaddr_in *ptr = (sockaddr_in *)&m_addr;
+		addrinfo hints, *res;
 
-		ptr->sin_family = AF_INET;
-		ptr->sin_port = htons(m_port);
+		std::memset(&hints, 0, sizeof (addrinfo));
+		hints.ai_family = domain;
 
-		if (m_host == "*")
-			ptr->sin_addr.s_addr = INADDR_ANY;
-		else if (inet_pton(AF_INET, m_host.c_str(), &ptr->sin_addr) <= 0)
-			throw SocketError(Socket::getLastSysError());
+		auto error = getaddrinfo(host.c_str(), std::to_string(port).c_str(), &hints, &res);
+		if (error != 0)
+			throw std::runtime_error(gai_strerror(error));
 
-		m_addrlen = sizeof (sockaddr_in);
+		std::memcpy(&m_addr, res->ai_addr, res->ai_addrlen);
+		m_addrlen = res->ai_addrlen;
+		freeaddrinfo(res);
 	}
 }
 
 /* --------------------------------------------------------
- * ConnectAddressIP implementation
- * -------------------------------------------------------- */
-
-ConnectAddressIP::ConnectAddressIP(const std::string &host, unsigned port, int family, int type)
-{
-	addrinfo hints, *res;
-	int error;
-
-	memset(&hints, 0, sizeof (hints));
-	hints.ai_family = family;
-	hints.ai_socktype = type;
-
-	error = getaddrinfo(host.c_str(), std::to_string(port).c_str(), &hints, &res);
-	if (error)
-		throw SocketError(gai_strerrorA(error));
-
-	memcpy(&m_addr, res->ai_addr, res->ai_addrlen);
-	m_addrlen = res->ai_addrlen;
-
-	freeaddrinfo(res);
-}
-
-/* --------------------------------------------------------
- * AddressUnix implementation
+ * Unix implementation
  * -------------------------------------------------------- */
 
 #if !defined(_WIN32)
 
 #include <sys/un.h>
 
-AddressUnix::AddressUnix(const std::string &path, bool rm)
+Unix::Unix(const std::string &path, bool rm)
 {
 	sockaddr_un *sun = (sockaddr_un *)&m_addr;
 
@@ -103,12 +79,13 @@
 
 	// Set the parameters
 	sun->sun_family = AF_UNIX;
-	sun->sun_len = SUN_LEN(sun);
 	m_addrlen = SUN_LEN(sun);
 }
 
 #endif // _WIN32
 
+} // !address
+
 /* --------------------------------------------------------
  * SocketAddress implementation
  * -------------------------------------------------------- */
@@ -125,10 +102,6 @@
 {
 }
 
-SocketAddress::~SocketAddress()
-{
-}
-
 const sockaddr_storage &SocketAddress::address() const
 {
 	return m_addr;
--- a/C++/SocketAddress.h	Sat Sep 13 19:42:15 2014 +0200
+++ b/C++/SocketAddress.h	Sun Sep 28 21:15:26 2014 +0200
@@ -19,8 +19,6 @@
 #ifndef _SOCKET_ADDRESS_H_
 #define _SOCKET_ADDRESS_H_
 
-#include "Socket.h"
-
 /**
  * @class SocketAddress
  * @brief base class for socket addresses
@@ -28,9 +26,8 @@
  * This class is mostly used to bind, connect or getting information
  * on socket clients.
  *
- * @see BindAddressIP
- * @see ConnectAddressIP
- * @see AddressUnix
+ * @see Internet
+ * @see Unix
  */
 class SocketAddress {
 protected:
@@ -38,9 +35,6 @@
 	socklen_t m_addrlen;
 
 public:
-	// Friends.
-	friend class Socket;
-
 	/**
 	 * Default constructor.
 	 */
@@ -57,7 +51,7 @@
 	/**
 	 * Default destructor.
 	 */
-	virtual ~SocketAddress();
+	virtual ~SocketAddress() = default;
 
 	/**
 	 * Get the address length
@@ -74,61 +68,37 @@
 	const sockaddr_storage &address() const;
 };
 
-/**
- * @class BindAddressIP
- * @brief internet protocol bind class
- *
- * Create a bind address for internet protocol,
- * IPv4 or IPv6.
- */
-class BindAddressIP : public SocketAddress {
-private:
-	std::string m_host;
-	int m_family;
-	unsigned m_port;
-
-public:
-	/**
-	 * Create a bind end point.
-	 *
-	 * @param addr the interface to bind
-	 * @param port the port
-	 * @param family AF_INET or AF_INET6
-	 * @throw SocketError on error
-	 */
-	BindAddressIP(const std::string &addr, unsigned port, int family);
-};
+namespace address {
 
 /**
- * @class ConnectAddressIP
+ * @class Internet
  * @brief internet protocol connect class
  *
  * Create a connect address for internet protocol,
  * using getaddrinfo(3).
  */
-class ConnectAddressIP : public SocketAddress {
+class Internet final : public SocketAddress {
 public:
 	/**
-	 * Create a connect end point.
+	 * Create an IPv4 or IPV6 end point.
 	 *
 	 * @param host the hostname
 	 * @param port the port
 	 * @param family AF_INET, AF_INET6, ...
-	 * @param type of socket SOCK_STREAM, SOCK_DGRAM, ...
 	 * @throw SocketError on error
 	 */
-	ConnectAddressIP(const std::string &host, unsigned port, int family, int type = SOCK_STREAM);
+	Internet(const std::string &host, unsigned port, int family);
 };
 
 #if !defined(_WIN32)
 
 /**
- * @class AddressUnix
+ * @class Unix
  * @brief unix family sockets
  *
  * Create an address to a specific path. Only available on Unix.
  */
-class AddressUnix : public SocketAddress {
+class Unix final : public SocketAddress {
 public:
 	/**
 	 * Construct an address to a path.
@@ -136,9 +106,11 @@
 	 * @param path the path
 	 * @param rm remove the file before (default: false)
 	 */
-	AddressUnix(const std::string &path, bool rm = false);
+	Unix(const std::string &path, bool rm = false);
 };
 
+} // !address
+
 #endif // ! !_WIN32
 
 #endif // !_SOCKET_ADDRESS_H_
--- a/C++/SocketListener.cpp	Sat Sep 13 19:42:15 2014 +0200
+++ b/C++/SocketListener.cpp	Sun Sep 28 21:15:26 2014 +0200
@@ -20,43 +20,47 @@
 
 #include "SocketListener.h"
 
-const char *SocketTimeout::what() const throw()
+const char *SocketTimeout::what() const noexcept
 {
 	return "Timeout occured";
 }
 
-void SocketListener::add(Socket &s)
+SocketListener::SocketListener(int count)
 {
-	m_clients.push_back(s);
+	m_sockets.reserve(count);
 }
 
-void SocketListener::remove(Socket &s)
+void SocketListener::add(Socket &&s)
 {
-	m_clients.erase(std::remove(m_clients.begin(), m_clients.end(), s), m_clients.end());
+	m_sockets.push_back(std::move(s));
+}
+
+void SocketListener::remove(const Socket &s)
+{
+	m_sockets.erase(std::remove(m_sockets.begin(), m_sockets.end(), s), m_sockets.end());
 }
 
 void SocketListener::clear()
 {
-	m_clients.clear();
+	m_sockets.clear();
 }
 
 unsigned SocketListener::size()
 {
-	return m_clients.size();
+	return m_sockets.size();
 }
 
 Socket &SocketListener::select(int s, int us)
 {
 	fd_set fds;
 	timeval maxwait, *towait;
-	int error;
-	int fdmax = m_clients.front().getSocket();
+	auto fdmax = m_sockets.front().handle();
 
 	FD_ZERO(&fds);
-	for (Socket &c : m_clients) {
-		FD_SET(c.getSocket(), &fds);
-		if ((int)c.getSocket() > fdmax)
-			fdmax = c.getSocket();
+	for (auto &c : m_sockets) {
+		FD_SET(c.handle(), &fds);
+		if ((int)c.handle() > fdmax)
+			fdmax = c.handle();
 	}
 
 	maxwait.tv_sec = s;
@@ -65,14 +69,14 @@
         // Set to NULL for infinite timeout.
 	towait = (s == 0 && us == 0) ? nullptr : &maxwait;
 
-	error = ::select(fdmax + 1, &fds, NULL, NULL, towait);
+	auto error = ::select(fdmax + 1, &fds, NULL, NULL, towait);
 	if (error == SOCKET_ERROR)
-		throw SocketError(Socket::getLastSysError());
+		throw SocketError(Socket::syserror());
 	if (error == 0)
 		throw SocketTimeout();
 
-	for (Socket &c : m_clients)
-		if (FD_ISSET(c.getSocket(), &fds))
+	for (Socket &c : m_sockets)
+		if (FD_ISSET(c.handle(), &fds))
 			return c;
 
 	throw SocketError("No socket found");
--- a/C++/SocketListener.h	Sat Sep 13 19:42:15 2014 +0200
+++ b/C++/SocketListener.h	Sun Sep 28 21:15:26 2014 +0200
@@ -27,9 +27,9 @@
  * @class SocketTimeout
  * @brief thrown when a timeout occured
  */
-class SocketTimeout : public std::exception {
+class SocketTimeout final : public std::exception {
 public:
-	virtual const char * what(void) const throw();
+	const char *what() const noexcept override;
 };
 
 /**
@@ -38,24 +38,31 @@
  *
  * Convenient wrapper around the select() system call.
  */
-class SocketListener {
+class SocketListener final {
 private:
-	std::vector<Socket> m_clients;
+	std::vector<Socket> m_sockets;
 
 public:
 	/**
+	 * Create a socket listener with a specific number of sockets to reserve.
+	 *
+	 * @param count the number of socket to reserve (default: 0)
+	 */
+	SocketListener(int count = 0);
+
+	/**
 	 * Add a socket to listen to.
 	 *
 	 * @param s the socket
 	 */
-	void add(Socket &s);
+	void add(Socket &&s);
 
 	/**
 	 * Remove a socket from the list.
 	 *
 	 * @param s the socket
 	 */
-	void remove(Socket &s);
+	void remove(const Socket &s);
 
 	/**
 	 * Remove every sockets in the listener.
@@ -73,13 +80,30 @@
 	 * Wait for an event in the socket list. If both s and us are set to 0 then
 	 * it waits indefinitely.
 	 *
+	 * Taking ownership of the returned socket is undefined behaviour.
+	 *
 	 * @param s the timeout in seconds
 	 * @param us the timeout in milliseconds
-	 * @return the socket ready
+	 * @see take
+	 * @return the socket ready owner by the SocketListener
 	 * @throw SocketError on error
 	 * @throw SocketTimeout on timeout
 	 */
 	Socket &select(int s = 0, int us = 0);
+
+	/**
+	 * Take back all sockets that listener own.
+	 *
+	 * @param func the function to call (void f(Socket &&s))
+	 */
+	template <typename Func>
+	void take(Func func)
+	{
+		for (auto &x : m_sockets)
+			func(std::move(x));
+
+		clear();
+	}	
 };
 
 #endif // !_SOCKET_LISTENER_H_