Mercurial > code
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(); }