Mercurial > code
changeset 454:781494d9c807
Socket: rework connection process
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 03 Nov 2015 09:37:19 +0100 |
parents | 2d95f0c8fd1d |
children | 03778e85f455 |
files | C++/modules/Socket/Sockets.h |
diffstat | 1 files changed, 58 insertions(+), 29 deletions(-) [+] |
line wrap: on
line diff
--- a/C++/modules/Socket/Sockets.h Mon Nov 02 19:16:26 2015 +0100 +++ b/C++/modules/Socket/Sockets.h Tue Nov 03 09:37:19 2015 +0100 @@ -472,6 +472,7 @@ */ inline Socket(Socket &&other) noexcept : m_handle{other.m_handle} + , m_type{std::move(other.m_type)} { /* Invalidate other */ other.m_handle = -1; @@ -803,6 +804,7 @@ Socket &operator=(Socket &&other) noexcept { m_handle = other.m_handle; + m_type = std::move(other.m_type); /* Invalidate other */ other.m_handle = Invalid; @@ -1162,6 +1164,13 @@ * @brief Clear TCP implementation. */ class Tcp { +private: + enum { + Undefined, + Connecting, + Connected + } m_state{Undefined}; + protected: /** * Standard accept. @@ -1215,17 +1224,21 @@ int error = WSAGetLastError(); if (error == WSAEWOULDBLOCK) { + m_state = Connecting; throw Error{Error::WouldBlockWrite, "connect", error}; } throw Error{Error::System, "connect", error}; #else if (errno == EINPROGRESS) { + m_state = Connecting; throw Error{Error::WouldBlockWrite, "connect"}; } throw Error{Error::System, "connect"}; #endif + } else { + m_state = Connected; } } @@ -1278,7 +1291,15 @@ template <typename Address> void connect(Socket<Address, Tcp> &sc, const Address &address) { - connect(sc.handle(), address.address(), address.length()); + if (m_state == Undefined) { + connect(sc.handle(), address.address(), address.length()); + } else if (m_state == Connecting) { + int error = sc.template get<int>(SOL_SOCKET, SO_ERROR); + + if (error == Failure) { + throw Error{Error::System, "connect", error}; + } + } } /** @@ -1587,7 +1608,7 @@ void connect(Socket<Address, Tls> &sc, const Address &address) { /* 1. Standard connect */ - Tcp::connect(sc.handle(), address.address(), address.length()); + Tcp::connect(sc, address); /* 2. OpenSSL handshake */ auto ret = SSL_connect(m_ssl.get()); @@ -2541,6 +2562,7 @@ using ReadHandler = Callback<const std::string &>; using WriteHandler = Callback<const std::string &>; using DisconnectionHandler = Callback<>; + using ErrorHandler = Callback<const Error &>; private: /* Signals */ @@ -2548,9 +2570,11 @@ ReadHandler m_onRead; WriteHandler m_onWrite; DisconnectionHandler m_onDisconnection; + ErrorHandler m_onError; /* Socket */ Socket<Address, Type> m_socket; + Address m_address; Listener<> m_listener; /* Connection status and output buffer */ @@ -2559,20 +2583,23 @@ void processConnect() { - /* 1. Remove from listener the write flag */ - m_listener.unset(m_socket.handle(), FlagWrite); - - /* 2. Check for an error */ - if (m_socket.template get<int>(SOL_SOCKET, SO_ERROR) == Failure) { - // TODO: ????? m_onDisconnection(); + try { + m_socket.connect(m_address); + m_connected = true; + m_onConnection(); + + if (m_output.empty()) { + m_listener.unset(m_socket.handle(), FlagWrite); + } + } catch (const Error &error) { + if (error.code() == Error::WouldBlockRead) { + m_listener.set(m_socket.handle(), FlagRead); + } else if (error.code() == Error::WouldBlockWrite) { + m_listener.set(m_socket.handle(), FlagWrite); + } else { + m_onError(error); + } } - - /* 3. Listen for input */ - m_listener.set(m_socket.handle(), FlagRead); - - /* 4. Notify */ - m_connected = true; - m_onConnection(); } void processSync(int flags) @@ -2596,9 +2623,10 @@ /* 4. Notify user */ m_onWrite(sent); } - } catch (const std::exception &ex) { + } catch (const Error &error) { m_listener.remove(m_socket.handle()); m_connected = false; + m_onError(error); } } @@ -2614,6 +2642,7 @@ : m_socket{address, std::move(type)} { m_socket.setBlockMode(false); + m_listener.set(m_socket.handle(), FlagRead); } /** @@ -2657,6 +2686,16 @@ } /** + * Set the error handler, called when unexpected error occurs. + * + * @param handler the handler + */ + inline void setErrorHandler(ErrorHandler handler) + { + m_onError = std::move(handler); + } + + /** * Connect to a server, this function may connect immediately or not in any case the connection handler * will be called when the connection completed. * @@ -2669,19 +2708,9 @@ return; } - try { - m_socket.connect(address); - m_connected = true; - m_onConnection(); - } catch (const Error &error) { - if (error.code() == Error::WouldBlockRead) { - m_listener.set(m_socket.handle(), FlagRead); - } else if (error.code() == Error::WouldBlockWrite) { - m_listener.set(m_socket.handle(), FlagWrite); - } else { - throw; - } - } + m_address = address; + + processConnect(); } /**