diff C++/Socket.cpp @ 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 ff2db0ed78f1
children 9cfa6fbc9c03
line wrap: on
line diff
--- 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();
 }