changeset 459:819bccefce8e

Socket: - Two new states: ConnectingRead | ConnectingWrite, - The connect() functions does not throw anymore if the operation is in progress for simpler implementations.
author David Demelier <markand@malikania.fr>
date Tue, 03 Nov 2015 17:48:35 +0100
parents db738947f359
children f6b4c7491d18
files C++/examples/Socket/non-blocking-connect.cpp C++/modules/Socket/Sockets.h
diffstat 2 files changed, 36 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/C++/examples/Socket/non-blocking-connect.cpp	Tue Nov 03 16:38:48 2015 +0100
+++ b/C++/examples/Socket/non-blocking-connect.cpp	Tue Nov 03 17:48:35 2015 +0100
@@ -38,37 +38,30 @@
 
 	socket.setBlockMode(false);
 
-	while (socket.state() != net::State::Connected && timer.elapsed() < (WITH_TIMEOUT * 1000)) {
-		try {
-			/*
-			 * If the socket is in state Open then no connection has been attempted, otherwise if it's Connecting,
-			 * then we can just resume the connection process.
-			 */
-			if (socket.state() == net::State::Open) {
-				std::cout << "Trying to connect to " << WITH_HOST << ":" << WITH_PORT << std::endl;
-				socket.connect(net::Ipv4{WITH_HOST, WITH_PORT});
-			} else {
-				socket.connect();
-			}
-		} catch (const net::Error &error) {
+	try {
+		std::cout << "Trying to connect to " << WITH_HOST << ":" << WITH_PORT << std::endl;
+		socket.connect(net::Ipv4{WITH_HOST, WITH_PORT});
+
+		while (socket.state() != net::State::Connected) {
 			listener.remove(socket.handle());
 
-			if (error.code() == net::Error::WouldBlockRead) {
+			if (socket.state() == net::State::ConnectingRead) {
 				listener.set(socket.handle(), net::FlagRead);
-			} else if (error.code() == net::Error::WouldBlockWrite) {
+			} else if (socket.state() == net::State::ConnectingWrite) {
 				listener.set(socket.handle(), net::FlagWrite);
-			} else {
-				std::cerr << "error: " << error.what() << std::endl;
-				std::exit(1);
 			}
 
-			try {
-				listener.wait(std::chrono::seconds(WITH_TIMEOUT));
-			} catch (...) {
-				std::cerr << "timeout while connecting" << std::endl;
-				std::exit(1);
-			}
+			listener.wait(std::chrono::seconds(WITH_TIMEOUT));
+			socket.connect();
 		}
+	} catch (const net::Error &error) {
+		if (error.code() == net::Error::Timeout) {
+			std::cerr << "timeout while connecting" << std::endl;
+		} else {
+			std::cerr << "error: " << error.what() << std::endl;
+		}
+
+		std::exit(1);
 	}
 
 	std::cout << "Successfully connected!" << std::endl;
--- a/C++/modules/Socket/Sockets.h	Tue Nov 03 16:38:48 2015 +0100
+++ b/C++/modules/Socket/Sockets.h	Tue Nov 03 17:48:35 2015 +0100
@@ -399,13 +399,14 @@
  * @brief Current socket state
  */
 enum class State {
-	Open,		//!< Socket is open
-	Bound,		//!< Socket is bound to an address
-	Connecting,	//!< Connection is in progress
-	Connected,	//!< Connection is complete
-	Accepting,	//!< The socket is being accepted (client)
-	Accepted,	//!< Socket has been accepted (client)
-	Closed,		//!< The socket has been closed
+	Open,			//!< Socket is open
+	Bound,			//!< Socket is bound to an address
+	ConnectingRead,		//!< Connection is in progress but requires to bereadable
+	ConnectingWrite,	//!< Connection is in progress and requires to be writable
+	Connected,		//!< Connection is complete
+	Accepting,		//!< The socket is being accepted (client)
+	Accepted,		//!< Socket has been accepted (client)
+	Closed,			//!< The socket has been closed
 };
 
 /* }}} */
@@ -675,9 +676,9 @@
 
 	/**
 	 * Connect to the connection to the specified address. If the socket is marked non-blocking and the
-	 * connection cannot be established, an error is thrown with WouldBlockWrite or WouldBlockRead as the code. The
-	 * user is then responsible to wait that the socket is writable or readable using a listener and then call the
-	 * overloaded connect() function which takes 0 argument.
+	 * connection cannot be established, the state is set to ConnectingRead or ConnectingWrite depending
+	 * on the underlying implementation. The user is then responsible to wait that the socket is writable
+	 * or readable using a listener and then call the overloaded connect() function which takes 0 argument.
 	 *
 	 * @param address the address
 	 * @param length the address length
@@ -707,12 +708,12 @@
 	 * Continue the connection, only required with non-blocking sockets. Just like the initial connect() call,
 	 * this function can still be in progress.
 	 *
-	 * @pre state() must be State::Connecting
+	 * @pre state() must be State::ConnectingRead or State::ConnectingWrite
 	 * @throw Error on errors
 	 */
 	inline void connect()
 	{
-		assert(m_state == State::Connecting);
+		assert(m_state == State::ConnectingRead || m_state == State::ConnectingWrite);
 
 		m_type.connect(*this);
 	}
@@ -1339,18 +1340,16 @@
 			int error = WSAGetLastError();
 
 			if (error == WSAEWOULDBLOCK) {
-				sc.setState(State::Connecting);
-				throw Error{Error::WouldBlockWrite, "connect", error};
+				sc.setState(State::ConnectingWrite);
+			} else {
+				throw Error{Error::System, "connect", error};
 			}
-
-			throw Error{Error::System, "connect", error};
 #else
 			if (errno == EINPROGRESS) {
-				sc.setState(State::Connecting);
-				throw Error{Error::WouldBlockWrite, "connect"};
+				sc.setState(State::ConnectingWrite);
+			} else {
+				throw Error{Error::System, "connect"};
 			}
-
-			throw Error{Error::System, "connect"};
 #endif
 		} else {
 			sc.setState(State::Connected);