changeset 464:61a6f3518c55

Socket: - Condition is now reused for Listener, - Add bitwise operators.
author David Demelier <markand@malikania.fr>
date Wed, 04 Nov 2015 20:27:17 +0100
parents 214f03b47d4e
children 55b3ec952c53
files C++/modules/Socket/Sockets.cpp C++/modules/Socket/Sockets.h C++/tests/Socket/main.cpp
diffstat 3 files changed, 303 insertions(+), 190 deletions(-) [+]
line wrap: on
line diff
--- a/C++/modules/Socket/Sockets.cpp	Wed Nov 04 18:01:22 2015 +0100
+++ b/C++/modules/Socket/Sockets.cpp	Wed Nov 04 20:27:17 2015 +0100
@@ -262,8 +262,12 @@
 
 /* }}} */
 
-const int FlagRead{1 << 0};
-const int FlagWrite{1 << 1};
+/*
+ * Select
+ * ------------------------------------------------------------------
+ */
+
+/* {{{ Select */
 
 std::vector<ListenerStatus> Select::wait(const ListenerTable &table, int ms)
 {
@@ -277,10 +281,10 @@
 	Handle max = 0;
 
 	for (const auto &pair : table) {
-		if (pair.second & FlagRead) {
+		if ((pair.second & Condition::Readable) == Condition::Readable) {
 			FD_SET(pair.first, &readset);
 		}
-		if (pair.second & FlagWrite) {
+		if ((pair.second & Condition::Writable) == Condition::Writable) {
 			FD_SET(pair.first, &writeset);
 		}
 
@@ -307,19 +311,24 @@
 
 	for (const auto &pair : table) {
 		if (FD_ISSET(pair.first, &readset)) {
-			sockets.push_back(ListenerStatus{pair.first, FlagRead});
+			sockets.push_back(ListenerStatus{pair.first, Condition::Readable});
 		}
 		if (FD_ISSET(pair.first, &writeset)) {
-			sockets.push_back(ListenerStatus{pair.first, FlagWrite});
+			sockets.push_back(ListenerStatus{pair.first, Condition::Writable});
 		}
 	}
 
 	return sockets;
 }
 
-/* --------------------------------------------------------
+/* }}} */
+
+/* {{{ Poll */
+
+/*
  * Poll implementation
- * -------------------------------------------------------- */
+ * ------------------------------------------------------------------
+ */
 
 #if defined(SOCKET_HAVE_POLL)
 
@@ -327,23 +336,23 @@
 #  define poll WSAPoll
 #endif
 
-short Poll::topoll(int flags) const noexcept
+short Poll::toPoll(Condition condition) const noexcept
 {
 	short result(0);
 
-	if (flags & FlagRead) {
+	if ((condition & Condition::Readable) == Condition::Readable) {
 		result |= POLLIN;
 	}
-	if (flags & FlagWrite) {
+	if ((condition & Condition::Writable) == Condition::Writable) {
 		result |= POLLOUT;
 	}
 
 	return result;
 }
 
-int Poll::toflags(short &event) const noexcept
+Condition Poll::toCondition(short &event) const noexcept
 {
-	int flags = 0;
+	Condition condition{Condition::None};
 
 	/*
 	 * Poll implementations mark the socket differently regarding
@@ -353,32 +362,32 @@
 	 * return 0 so we mark the socket as readable.
 	 */
 	if ((event & POLLIN) || (event & POLLHUP)) {
-		flags |= FlagRead;
+		condition |= Condition::Readable;
 	}
 	if (event & POLLOUT) {
-		flags |= FlagWrite;
+		condition |= Condition::Writable;
 	}
 
 	/* Reset event for safety */
 	event = 0;
 
-	return flags;
+	return condition;
 }
 
-void Poll::set(const ListenerTable &, Handle h, int flags, bool add)
+void Poll::set(const ListenerTable &, Handle h, Condition condition, bool add)
 {
 	if (add) {
-		m_fds.push_back(pollfd{h, topoll(flags), 0});
+		m_fds.push_back(pollfd{h, toPoll(condition), 0});
 	} else {
 		auto it = std::find_if(m_fds.begin(), m_fds.end(), [&] (const pollfd &pfd) {
 			return pfd.fd == h;
 		});
 
-		it->events |= topoll(flags);
+		it->events |= toPoll(condition);
 	}
 }
 
-void Poll::unset(const ListenerTable &, Handle h, int flags, bool remove)
+void Poll::unset(const ListenerTable &, Handle h, Condition condition, bool remove)
 {
 	auto it = std::find_if(m_fds.begin(), m_fds.end(), [&] (const pollfd &pfd) {
 		return pfd.fd == h;
@@ -387,7 +396,7 @@
 	if (remove) {
 		m_fds.erase(it);
 	} else {
-		it->events &= ~(topoll(flags));
+		it->events &= ~(toPoll(condition));
 	}
 }
 
@@ -404,7 +413,7 @@
 	std::vector<ListenerStatus> sockets;
 	for (auto &fd : m_fds) {
 		if (fd.revents != 0) {
-			sockets.push_back(ListenerStatus{fd.fd, toflags(fd.revents)});
+			sockets.push_back(ListenerStatus{fd.fd, toCondition(fd.revents)});
 		}
 	}
 
@@ -413,47 +422,48 @@
 
 #endif // !SOCKET_HAVE_POLL
 
-/* --------------------------------------------------------
+/*
  * Epoll implementation
- * -------------------------------------------------------- */
+ * ------------------------------------------------------------------
+ */
 
 #if defined(SOCKET_HAVE_EPOLL)
 
-uint32_t Epoll::toepoll(int flags) const noexcept
+uint32_t Epoll::toEpoll(Condition condition) const noexcept
 {
 	uint32_t events = 0;
 
-	if (flags & FlagRead) {
+	if ((condition & Condition::Readable) == Condition::Readable) {
 		events |= EPOLLIN;
 	}
-	if (flags & FlagWrite) {
+	if ((condition & Condition::Writable) == Condition::Writable) {
 		events |= EPOLLOUT;
 	}
 
 	return events;
 }
 
-int Epoll::toflags(uint32_t events) const noexcept
+Condition Epoll::toCondition(uint32_t events) const noexcept
 {
-	int flags = 0;
+	Condition condition{Condition::None};
 
 	if ((events & EPOLLIN) || (events & EPOLLHUP)) {
-		flags |= FlagRead;
+		condition |= Condition::Readable;
 	}
 	if (events & EPOLLOUT) {
-		flags |= FlagWrite;
+		condition |= Condition::Writable;
 	}
 
-	return flags;
+	return condition;
 }
 
-void Epoll::update(Handle h, int op, int flags)
+void Epoll::update(Handle h, int op, int eflags)
 {
 	epoll_event ev;
 
 	std::memset(&ev, 0, sizeof (epoll_event));
 
-	ev.events = flags;
+	ev.events = eflags;
 	ev.data.fd = h;
 
 	if (epoll_ctl(m_handle, op, h, &ev) < 0) {
@@ -462,7 +472,7 @@
 }
 
 Epoll::Epoll()
-	: m_handle(epoll_create1(0))
+	: m_handle{epoll_create1(0)}
 {
 	if (m_handle < 0) {
 		throw Error{Error::System, "epoll_create"};
@@ -477,9 +487,9 @@
 /*
  * Add a new epoll_event or just update it.
  */
-void Epoll::set(const ListenerTable &, Handle h, int flags, bool add)
+void Epoll::set(const ListenerTable &, Handle h, Condition condition, bool add)
 {
-	update(h, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, toepoll(flags));
+	update(h, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, toEpoll(condition));
 
 	if (add) {
 		m_events.resize(m_events.size() + 1);
@@ -487,20 +497,20 @@
 }
 
 /*
- * Unset is a bit complicated case because SocketListener tells us which
+ * Unset is a bit complicated case because Listener tells us which
  * flag to remove but to update epoll descriptor we need to pass
  * the effective flags that we want to be applied.
  *
  * So we put the same flags that are currently effective and remove the
  * requested one.
  */
-void Epoll::unset(const ListenerTable &table, Handle sc, int flags, bool remove)
+void Epoll::unset(const ListenerTable &table, Handle sc, Condition condition, bool remove)
 {
 	if (remove) {
 		update(sc, EPOLL_CTL_DEL, 0);
 		m_events.resize(m_events.size() - 1);
 	} else {
-		update(sc, EPOLL_CTL_MOD, table.at(sc) & ~(toepoll(flags)));
+		update(sc, EPOLL_CTL_MOD, toEpoll(table.at(sc)) & ~(toEpoll(condition)));
 	}
 }
 
@@ -517,7 +527,7 @@
 	}
 
 	for (int i = 0; i < ret; ++i) {
-		result.push_back(ListenerStatus{m_events[i].data.fd, toflags(m_events[i].events)});
+		result.push_back(ListenerStatus{m_events[i].data.fd, toCondition(m_events[i].events)});
 	}
 
 	return result;
@@ -544,7 +554,7 @@
 	close(m_handle);
 }
 
-void Kqueue::update(Handle h, int filter, int flags)
+void Kqueue::update(Handle h, int filter, int kflags)
 {
 	kevent ev;
 
@@ -555,12 +565,12 @@
 	}
 }
 
-void Kqueue::set(const ListenerTable &, Handle h, int flags, bool add)
+void Kqueue::set(const ListenerTable &, Handle h, Condition condition, bool add)
 {
-	if (flags & FlagRead) {
+	if ((condition & Condition::Readable) == Condition::Readable) {
 		update(h, EVFILT_READ, EV_ADD | EV_ENABLE);
 	}
-	if (flags & FlagWrite) {
+	if ((condition & Condition::Writable) == Condition::Writable) {
 		update(h, EVFILT_WRITE, EV_ADD | EV_ENABLE);
 	}
 
@@ -569,12 +579,12 @@
 	}
 }
 
-void Kqueue::unset(const ListenerTable &, Handle h, int flags, bool remove)
+void Kqueue::unset(const ListenerTable &, Handle h, Condition condition, bool remove)
 {
-	if (flags & FlagRead) {
+	if ((flags & Condition::Readable) == Condition::Readable) {
 		update(h, EVFILT_READ, EV_DELETE);
 	}
-	if (flags & FlagWrite) {
+	if ((flags & Condition::Writable) == Condition::Writable) {
 		update(h, EVFILT_WRITE, EV_DELETE);
 	}
 
@@ -604,7 +614,7 @@
 	for (int i = 0; i < nevents; ++i) {
 		sockets.push_back(ListenerStatus{
 			static_cast<Handle>(m_result[i].ident),
-			m_result[i].filter == EVFILT_READ ? FlagRead : FlagWrite
+			m_result[i].filter == EVFILT_READ ? Condition::Readable : Condition::Writable
 		});
 	}
 
--- a/C++/modules/Socket/Sockets.h	Wed Nov 04 18:01:22 2015 +0100
+++ b/C++/modules/Socket/Sockets.h	Wed Nov 04 20:27:17 2015 +0100
@@ -408,6 +408,15 @@
 
 /* }}} */
 
+/*
+ * Action enum
+ * ------------------------------------------------------------------
+ *
+ * Defines the pending operation.
+ */
+
+/* {{{ Action */
+
 /**
  * @enum Action
  * @brief Define the current operation that must complete.
@@ -430,6 +439,17 @@
 	Send		//!< The send operation has not succeded yet, caller must call send() or sendto() again
 };
 
+/* }}} */
+
+/*
+ * Condition enum
+ * ------------------------------------------------------------------
+ *
+ * Defines if we must wait for reading or writing.
+ */
+
+/* {{{ Condition */
+
 /**
  * @enum Condition
  * @brief Define the required condition for the socket.
@@ -438,11 +458,102 @@
  * operations, the user must wait the socket to be readable or writable. This can be checked with Socket::condition.
  */
 enum class Condition {
-	None,		//!< No condition is required
-	Readable,	//!< The socket must be readable
-	Writable	//!< The socket must be writable
+	None,			//!< No condition is required
+	Readable = (1 << 0),	//!< The socket must be readable
+	Writable = (1 << 1)	//!< The socket must be writable
 };
 
+/**
+ * Apply bitwise XOR.
+ *
+ * @param v1 the first value
+ * @param v2 the second value
+ * @return the new value
+ */
+constexpr Condition operator^(Condition v1, Condition v2) noexcept
+{
+	return static_cast<Condition>(static_cast<int>(v1) ^ static_cast<int>(v2));
+}
+
+/**
+ * Apply bitwise AND.
+ *
+ * @param v1 the first value
+ * @param v2 the second value
+ * @return the new value
+ */
+constexpr Condition operator&(Condition v1, Condition v2) noexcept
+{
+	return static_cast<Condition>(static_cast<int>(v1) & static_cast<int>(v2));
+}
+
+/**
+ * Apply bitwise OR.
+ *
+ * @param v1 the first value
+ * @param v2 the second value
+ * @return the new value
+ */
+constexpr Condition operator|(Condition v1, Condition v2) noexcept
+{
+	return static_cast<Condition>(static_cast<int>(v1) | static_cast<int>(v2));
+}
+
+/**
+ * Apply bitwise NOT.
+ *
+ * @param v the value
+ * @return the complement
+ */
+constexpr Condition operator~(Condition v) noexcept
+{
+	return static_cast<Condition>(~static_cast<int>(v));
+}
+
+/**
+ * Assign bitwise OR.
+ *
+ * @param v1 the first value
+ * @param v2 the second value
+ * @return the new value
+ */
+constexpr Condition &operator|=(Condition &v1, Condition v2) noexcept
+{
+	v1 = static_cast<Condition>(static_cast<int>(v1) | static_cast<int>(v2));
+
+	return v1;
+}
+
+/**
+ * Assign bitwise AND.
+ *
+ * @param v1 the first value
+ * @param v2 the second value
+ * @return the new value
+ */
+constexpr Condition &operator&=(Condition &v1, Condition v2) noexcept
+{
+	v1 = static_cast<Condition>(static_cast<int>(v1) & static_cast<int>(v2));
+
+	return v1;
+}
+
+/**
+ * Assign bitwise XOR.
+ *
+ * @param v1 the first value
+ * @param v2 the second value
+ * @return the new value
+ */
+constexpr Condition &operator^=(Condition &v1, Condition v2) noexcept
+{
+	v1 = static_cast<Condition>(static_cast<int>(v1) ^ static_cast<int>(v2));
+
+	return v1;
+}
+
+/* }}} */
+
 /*
  * Base Socket class
  * ------------------------------------------------------------------
@@ -2169,14 +2280,14 @@
 class ListenerStatus {
 public:
 	Handle socket;		//!< which socket is ready
-	int flags;		//!< the flags
+	Condition flags;	//!< the flags
 };
 
 /**
  * Table used in the socket listener to store which sockets have been
  * set in which directions.
  */
-using ListenerTable = std::map<Handle, int>;
+using ListenerTable = std::map<Handle, Condition>;
 
 /**
  * @class Select
@@ -2187,27 +2298,27 @@
 class Select {
 public:
 	/**
+	 * No-op, uses the ListenerTable directly.
+	 */
+	inline void set(const ListenerTable &, Handle, Condition, bool) noexcept {}
+
+	/**
+	 * No-op, uses the ListenerTable directly.
+	 */
+	inline void unset(const ListenerTable &, Handle, Condition, bool) noexcept {}
+
+	/**
+	 * Return the sockets
+	 */
+	std::vector<ListenerStatus> wait(const ListenerTable &table, int ms);
+
+	/**
 	 * Backend identifier
 	 */
 	inline const char *name() const noexcept
 	{
 		return "select";
 	}
-
-	/**
-	 * No-op, uses the ListenerTable directly.
-	 */
-	inline void set(const ListenerTable &, Handle, int, bool) noexcept {}
-
-	/**
-	 * No-op, uses the ListenerTable directly.
-	 */
-	inline void unset(const ListenerTable &, Handle, int, bool) noexcept {}
-
-	/**
-	 * Return the sockets
-	 */
-	std::vector<ListenerStatus> wait(const ListenerTable &table, int ms);
 };
 
 #if defined(SOCKET_HAVE_POLL)
@@ -2223,19 +2334,19 @@
 private:
 	std::vector<pollfd> m_fds;
 
-	short topoll(int flags) const noexcept;
-	int toflags(short &event) const noexcept;
+	short toPoll(Condition flags) const noexcept;
+	Condition toCondition(short &event) const noexcept;
 
 public:
 	/**
 	 * Set the handle.
 	 */
-	void set(const ListenerTable &, Handle, int, bool);
+	void set(const ListenerTable &, Handle, Condition, bool);
 
 	/**
 	 * Unset the handle.
 	 */
-	void unset(const ListenerTable &, Handle, int, bool);
+	void unset(const ListenerTable &, Handle, Condition, bool);
 
 	/**
 	 * Wait for events.
@@ -2269,9 +2380,9 @@
 	Epoll(const Epoll &&) = delete;
 	Epoll &operator=(const Epoll &&) = delete;
 
-	uint32_t toepoll(int flags) const noexcept;
-	int toflags(uint32_t events) const noexcept;
-	void update(Handle sc, int op, int flags);
+	uint32_t toEpoll(Condition flags) const noexcept;
+	Condition toCondition(uint32_t events) const noexcept;
+	void update(Handle sc, int op, int eflags);
 
 public:
 	/**
@@ -2287,12 +2398,12 @@
 	/**
 	 * Set the handle.
 	 */
-	void set(const ListenerTable &, Handle, int, bool);
+	void set(const ListenerTable &, Handle, Condition, bool);
 
 	/**
 	 * Unset the handle.
 	 */
-	void unset(const ListenerTable &, Handle, int, bool);
+	void unset(const ListenerTable &, Handle, Condition, bool);
 
 	/**
 	 * Wait for events.
@@ -2329,7 +2440,7 @@
 	Kqueue(Kqueue &&) = delete;
 	Kqueue &operator=(Kqueue &&) = delete;
 
-	void update(Handle sc, int filter, int flags);
+	void update(Handle sc, int filter, int kflags);
 
 public:
 	/**
@@ -2345,12 +2456,12 @@
 	/**
 	 * Set the handle.
 	 */
-	void set(const ListenerTable &, Handle, int, bool);
+	void set(const ListenerTable &, Handle, Condition, bool);
 
 	/**
 	 * Unset the handle.
 	 */
-	void unset(const ListenerTable &, Handle, int, bool);
+	void unset(const ListenerTable &, Handle, Condition, bool);
 
 	/**
 	 * Wait for events.
@@ -2369,16 +2480,6 @@
 #endif
 
 /**
- * Mark the socket for read operation.
- */
-extern const int FlagRead;
-
-/**
- * Mark the socket for write operation.
- */
-extern const int FlagWrite;
-
-/**
  * @class Listener
  * @brief Synchronous multiplexing
  *
@@ -2398,10 +2499,10 @@
  * ### Set
  *
  * @code
- * void set(const ListenerTable &, Handle sc, int flags, bool add);
+ * void set(const ListenerTable &, Handle sc, Condition condition, bool add);
  * @endcode
  *
- * This function, takes the socket to be added and the flags. The flags are
+ * This function, takes the socket to be added and the flags. The condition is
  * always guaranteed to be correct and the function will never be called twice
  * even if the user tries to set the same flag again.
  *
@@ -2412,10 +2513,10 @@
  * ### Unset
  *
  * @code
- * void unset(const ListenerTable &, Handle sc, int flags, bool remove);
+ * void unset(const ListenerTable &, Handle sc, Condition condition, bool remove);
  * @endcode
  *
- * Like set, this function is only called if the flags are actually set and will
+ * Like set, this function is only called if the condition is actually set and will
  * not be called multiple times.
  *
  * Also like set, an optional remove argument is set if the socket is being
@@ -2440,8 +2541,6 @@
  */
 template <typename Backend = SOCKET_DEFAULT_BACKEND>
 class Listener {
-public:
-
 private:
 	Backend m_backend;
 	ListenerTable m_table;
@@ -2521,13 +2620,13 @@
 	 * If incorrect flags are passed, the function does nothing.
 	 *
 	 * @param sc the socket
-	 * @param flags (may be OR'ed)
+	 * @param condition the condition (may be OR'ed)
 	 * @throw Error if the backend failed to set
 	 */
-	void set(Handle sc, int flags)
+	void set(Handle sc, Condition condition)
 	{
 		/* Invalid or useless flags */
-		if (flags == 0 || flags > 0x3)
+		if (condition == Condition::None || static_cast<int>(condition) > 0x3)
 			return;
 
 		auto it = m_table.find(sc);
@@ -2537,20 +2636,23 @@
 		 * or update.
 		 */
 		if (it == m_table.end()) {
-			m_backend.set(m_table, sc, flags, true);
-			m_table.emplace(sc, flags);
+			m_backend.set(m_table, sc, condition, true);
+			m_table.emplace(sc, condition);
 		} else {
-			if ((flags & FlagRead) && (it->second & FlagRead)) {
-				flags &= ~(FlagRead);
+			/* Remove flag if already present */
+			if ((condition & Condition::Readable) == Condition::Readable &&
+			    (it->second & Condition::Readable) == Condition::Readable) {
+				condition &= ~(Condition::Readable);
 			}
-			if ((flags & FlagWrite) && (it->second & FlagWrite)) {
-				flags &= ~(FlagWrite);
+			if ((condition & Condition::Writable) == Condition::Writable &&
+			    (it->second & Condition::Writable) == Condition::Writable) {
+				condition &= ~(Condition::Writable);
 			}
 
 			/* Still need a call? */
-			if (flags != 0) {
-				m_backend.set(m_table, sc, flags, false);
-				it->second |= flags;
+			if (condition != Condition::None) {
+				m_backend.set(m_table, sc, condition, false);
+				it->second |= condition;
 			}
 		}
 	}
@@ -2563,38 +2665,40 @@
 	 * unsetting the write flags will keep the socket for reading.
 	 *
 	 * @param sc the socket
-	 * @param flags the flags (may be OR'ed)
+	 * @param condition the condition (may be OR'ed)
 	 * @see remove
 	 */
-	void unset(Handle sc, int flags)
+	void unset(Handle sc, Condition condition)
 	{
 		auto it = m_table.find(sc);
 
 		/* Invalid or useless flags */
-		if (flags == 0 || flags > 0x3 || it == m_table.end())
+		if (condition == Condition::None || static_cast<int>(condition) > 0x3 || it == m_table.end())
 			return;
 
 		/*
 		 * Like set, do not update if the socket is already at the appropriate
 		 * state.
 		 */
-		if ((flags & FlagRead) && !(it->second & FlagRead)) {
-			flags &= ~(FlagRead);
-		}
-		if ((flags & FlagWrite) && !(it->second & FlagWrite)) {
-			flags &= ~(FlagWrite);
+		if ((condition & Condition::Readable) == Condition::Readable &&
+		    (it->second & Condition::Readable) != Condition::Readable) {
+			condition &= ~(Condition::Readable);
 		}
-
-		if (flags != 0) {
+		if ((condition & Condition::Writable) == Condition::Writable &&
+		    (it->second & Condition::Writable) != Condition::Writable) {
+			condition &= ~(Condition::Writable);
+		}
+
+		if (condition != Condition::None) {
 			/* Determine if it's a complete removal */
-			bool removal = ((it->second) & ~(flags)) == 0;
-
-			m_backend.unset(m_table, sc, flags, removal);
+			bool removal = ((it->second) & ~(condition)) == Condition::None;
+
+			m_backend.unset(m_table, sc, condition, removal);
 
 			if (removal) {
 				m_table.erase(it);
 			} else {
-				it->second &= ~(flags);
+				it->second &= ~(condition);
 			}
 		}
 	}
@@ -2602,13 +2706,13 @@
 	/**
 	 * Remove completely the socket from the listener.
 	 *
-	 * It is a shorthand for unset(sc, FlagRead | FlagWrite);
+	 * It is a shorthand for unset(sc, Condition::Readable | Condition::Writable);
 	 *
 	 * @param sc the socket
 	 */
 	inline void remove(Handle sc)
 	{
-		unset(sc, FlagRead | FlagWrite);
+		unset(sc, Condition::Readable | Condition::Writable);
 	}
 
 	/**
@@ -2727,7 +2831,7 @@
  * Client connected on the server side.
  */
 
-/* {{{ */
+/* {{{ StreamConnection */
 
 /**
  * @class StreamConnection
@@ -2834,7 +2938,7 @@
  * Convenient stream oriented server.
  */
 
-/* {{{ */
+/* {{{ StreamServer */
 
 /**
  * @class StreamServer
@@ -2881,9 +2985,9 @@
 		m_listener.remove(client->socket().handle());
 
 		if (client->socket().condition() == Condition::Readable) {
-			m_listener.set(client->socket().handle(), FlagRead);
+			m_listener.set(client->socket().handle(), Condition::Readable);
 		} else {
-			m_listener.set(client->socket().handle(), FlagWrite);
+			m_listener.set(client->socket().handle(), Condition::Writable);
 		}
 	}
 
@@ -2903,7 +3007,7 @@
 			/* 2. If accept is not finished, wait for the appropriate condition */
 			if (client->socket().state() == State::Accepted) {
 				/* 3. Client is accepted, notify the user */
-				m_listener.set(client->socket().handle(), FlagRead);
+				m_listener.set(client->socket().handle(), Condition::Readable);
 				m_onConnection(client);
 			} else {
 				/* Operation still in progress */
@@ -2932,7 +3036,7 @@
 
 			/* Do not update the listener immediately if an action is pending */
 			if (client && client->socket().action() == Action::None && !client->output().empty()) {
-				m_listener.set(client->socket().handle(), FlagWrite);
+				m_listener.set(client->socket().handle(), Condition::Writable);
 			}
 		});
 
@@ -2975,7 +3079,7 @@
 				 * case the write flag may be removed, add it if required.
 				 */
 				if (!client->output().empty()) {
-					m_listener.set(client->socket().handle(), FlagWrite);
+					m_listener.set(client->socket().handle(), Condition::Writable);
 				}
 
 				m_onRead(client, buffer);
@@ -3003,7 +3107,7 @@
 
 			/* 3. Update listener */
 			if (output.empty()) {
-				m_listener.unset(client->socket().handle(), FlagWrite);
+				m_listener.unset(client->socket().handle(), Condition::Writable);
 			}
 
 			/* 4. Notify user */
@@ -3012,16 +3116,16 @@
 			updateFlags(client);
 		}
 	}
-
 	
-	void processSync(std::shared_ptr<StreamConnection<Address, Type>> &client, int flags)
+	void processSync(std::shared_ptr<StreamConnection<Address, Type>> &client, Condition flags)
 	{
 		try {
 			auto action = client->socket().action();
 
-			if (action == Action::Receive || (action == Action::None && (flags & FlagRead))) {
+			if (action == Action::Receive ||
+			    (action == Action::None && (flags & Condition::Readable) == Condition::Readable)) {
 				processRead(client);
-			} else if (flags & FlagWrite) {
+			} else if ((flags & Condition::Writable) == Condition::Writable) {
 				processWrite(client);
 			}
 		} catch (const Error &error) {
@@ -3046,7 +3150,7 @@
 		m_master.set(SOL_SOCKET, SO_REUSEADDR, 1);
 		m_master.bind(address);
 		m_master.listen(max);
-		m_listener.set(m_master.handle(), FlagRead);
+		m_listener.set(m_master.handle(), Condition::Readable);
 	}
 
 	/**
@@ -3218,9 +3322,9 @@
 		m_listener.remove(m_socket.handle());
 
 		if (m_socket.condition() == Condition::Readable) {
-			m_listener.set(m_socket.handle(), FlagRead);
+			m_listener.set(m_socket.handle(), Condition::Readable);
 		} else {
-			m_listener.set(m_socket.handle(), FlagWrite);
+			m_listener.set(m_socket.handle(), Condition::Writable);
 		}
 	}
 
@@ -3244,7 +3348,7 @@
 
 		if (m_socket.state() == State::Connected) {
 			m_onConnection();
-			m_listener.set(m_socket.handle(), FlagRead);
+			m_listener.set(m_socket.handle(), Condition::Readable);
 		} else {
 			/* Connection still in progress */
 			updateFlags();
@@ -3269,7 +3373,7 @@
 				 * case the write flag may be removed, add it if required.
 				 */
 				if (!m_output.empty()) {
-					m_listener.set(m_socket.handle(), FlagWrite);
+					m_listener.set(m_socket.handle(), Condition::Writable);
 				}
 
 				m_onRead(received);
@@ -3297,7 +3401,7 @@
 
 			/* 3. Update flags if needed */
 			if (m_output.empty()) {
-				m_listener.unset(m_socket.handle(), FlagWrite);
+				m_listener.unset(m_socket.handle(), Condition::Writable);
 			}
 
 			/* 4. Notify user */
@@ -3311,9 +3415,10 @@
 	/*
 	 * Receive or send.
 	 */
-	void processSync(int flags)
+	void processSync(Condition condition)
 	{
-		if ((m_socket.action() == Action::Receive) || (m_socket.action() == Action::None && (flags & FlagRead))) {
+		if ((m_socket.action() == Action::Receive) ||
+		    (m_socket.action() == Action::None && (condition & Condition::Readable) == Condition::Readable)) {
 			processRead();
 		} else {
 			processWrite();
@@ -3332,7 +3437,7 @@
 		: m_socket{address, std::move(type)}
 	{
 		m_socket.setBlockMode(false);
-		m_listener.set(m_socket.handle(), FlagRead);
+		m_listener.set(m_socket.handle(), Condition::Readable);
 	}
 
 	/**
@@ -3409,7 +3514,7 @@
 
 		/* Don't update the listener if there is a pending operation */
 		if (m_socket.state() == State::Connected && m_socket.action() == Action::None && !m_output.empty()) {
-			m_listener.set(m_socket.handle(), FlagWrite);
+			m_listener.set(m_socket.handle(), Condition::Writable);
 		}
 	}
 
--- a/C++/tests/Socket/main.cpp	Wed Nov 04 18:01:22 2015 +0100
+++ b/C++/tests/Socket/main.cpp	Wed Nov 04 20:27:17 2015 +0100
@@ -101,6 +101,8 @@
  * UDP tests
  * -------------------------------------------------------- */
 
+#if 0
+
 class UdpServerTest : public testing::Test {
 protected:
 	SocketUdp<Ipv4> m_server;
@@ -152,6 +154,8 @@
 	});
 }
 
+#endif
+
 /* --------------------------------------------------------
  * Listener: set function
  * -------------------------------------------------------- */
@@ -160,16 +164,16 @@
 public:
 	int m_callcount{0};
 	bool m_added{false};
-	int m_flags{0};
+	Condition m_flags{Condition::None};
 
-	inline void set(const ListenerTable &, Handle, int flags, bool add) noexcept
+	inline void set(const ListenerTable &, Handle, Condition flags, bool add) noexcept
 	{
 		m_callcount ++;
 		m_added = add;
 		m_flags |= flags;
 	}
 
-	inline void unset(const ListenerTable &, Handle, int, bool) noexcept
+	inline void unset(const ListenerTable &, Handle, Condition, bool) noexcept
 	{
 	}
 
@@ -181,12 +185,12 @@
 
 class TestBackendSetFail {
 public:
-	inline void set(const ListenerTable &, Handle, int, bool)
+	inline void set(const ListenerTable &, Handle, Condition, bool)
 	{
 		throw "fail";
 	}
 
-	inline void unset(const ListenerTable &, Handle, int, bool) noexcept
+	inline void unset(const ListenerTable &, Handle, Condition, bool) noexcept
 	{
 	}
 
@@ -201,12 +205,12 @@
 	Listener<TestBackendSet> listener;
 	Handle s{0};
 
-	listener.set(s, FlagRead);
+	listener.set(s, Condition::Readable);
 
 	ASSERT_EQ(1U, listener.size());
 	ASSERT_EQ(1, listener.backend().m_callcount);
 	ASSERT_TRUE(listener.backend().m_added);
-	ASSERT_TRUE(listener.backend().m_flags == FlagRead);
+	ASSERT_TRUE(listener.backend().m_flags == Condition::Readable);
 }
 
 TEST(ListenerSet, readThenWrite)
@@ -214,13 +218,13 @@
 	Listener<TestBackendSet> listener;
 	Handle s{0};
 
-	listener.set(s, FlagRead);
-	listener.set(s, FlagWrite);
+	listener.set(s, Condition::Readable);
+	listener.set(s, Condition::Writable);
 
 	ASSERT_EQ(1U, listener.size());
 	ASSERT_EQ(2, listener.backend().m_callcount);
 	ASSERT_FALSE(listener.backend().m_added);
-	ASSERT_TRUE(listener.backend().m_flags == 0x3);
+	ASSERT_TRUE(static_cast<int>(listener.backend().m_flags) == 0x3);
 }
 
 TEST(ListenerSet, allOneShot)
@@ -228,12 +232,12 @@
 	Listener<TestBackendSet> listener;
 	Handle s{0};
 
-	listener.set(s, FlagRead | FlagWrite);
+	listener.set(s, Condition::Readable | Condition::Writable);
 
 	ASSERT_EQ(1U, listener.size());
 	ASSERT_EQ(1, listener.backend().m_callcount);
 	ASSERT_TRUE(listener.backend().m_added);
-	ASSERT_TRUE(listener.backend().m_flags == 0x3);
+	ASSERT_TRUE(static_cast<int>(listener.backend().m_flags) == 0x3);
 }
 
 TEST(ListenerSet, readTwice)
@@ -241,13 +245,13 @@
 	Listener<TestBackendSet> listener;
 	Handle s{0};
 
-	listener.set(s, FlagRead);
-	listener.set(s, FlagRead);
+	listener.set(s, Condition::Readable);
+	listener.set(s, Condition::Readable);
 
 	ASSERT_EQ(1U, listener.size());
 	ASSERT_EQ(1, listener.backend().m_callcount);
 	ASSERT_TRUE(listener.backend().m_added);
-	ASSERT_TRUE(listener.backend().m_flags == FlagRead);
+	ASSERT_TRUE(listener.backend().m_flags == Condition::Readable);
 }
 
 TEST(ListenerSet, failure)
@@ -256,7 +260,7 @@
 	Handle s{0};
 
 	try {
-		listener.set(s, FlagRead);
+		listener.set(s, Condition::Readable);
 		FAIL() << "exception expected";
 	} catch (...) {
 	}
@@ -272,16 +276,16 @@
 public:
 	bool m_isset{false};
 	bool m_isunset{false};
-	int m_flags{0};
+	Condition m_flags{Condition::None};
 	bool m_removal{false};
 
-	inline void set(const ListenerTable &, Handle &, int flags, bool) noexcept
+	inline void set(const ListenerTable &, Handle &, Condition flags, bool) noexcept
 	{
 		m_isset = true;
 		m_flags |= flags;
 	}
 
-	inline void unset(const ListenerTable &, Handle &, int flags, bool remove) noexcept
+	inline void unset(const ListenerTable &, Handle &, Condition flags, bool remove) noexcept
 	{
 		m_isunset = true;
 		m_flags &= ~(flags);
@@ -296,11 +300,11 @@
 
 class TestBackendUnsetFail {
 public:
-	inline void set(const ListenerTable &, Handle &, int, bool) noexcept
+	inline void set(const ListenerTable &, Handle &, Condition, bool) noexcept
 	{
 	}
 
-	inline void unset(const ListenerTable &, Handle &, int, bool)
+	inline void unset(const ListenerTable &, Handle &, Condition, bool)
 	{
 		throw "fail";
 	}
@@ -316,13 +320,13 @@
 	Listener<TestBackendUnset> listener;
 	Handle s{0};
 
-	listener.set(s, FlagRead);
-	listener.unset(s, FlagRead);
+	listener.set(s, Condition::Readable);
+	listener.unset(s, Condition::Readable);
 
 	ASSERT_EQ(0U, listener.size());
 	ASSERT_TRUE(listener.backend().m_isset);
 	ASSERT_TRUE(listener.backend().m_isunset);
-	ASSERT_TRUE(listener.backend().m_flags == 0);
+	ASSERT_TRUE(listener.backend().m_flags == Condition::None);
 	ASSERT_TRUE(listener.backend().m_removal);
 }
 
@@ -331,13 +335,13 @@
 	Listener<TestBackendUnset> listener;
 	Handle s{0};
 
-	listener.set(s, FlagRead | FlagWrite);
-	listener.unset(s, FlagRead);
+	listener.set(s, Condition::Readable | Condition::Writable);
+	listener.unset(s, Condition::Readable);
 
 	ASSERT_EQ(1U, listener.size());
 	ASSERT_TRUE(listener.backend().m_isset);
 	ASSERT_TRUE(listener.backend().m_isunset);
-	ASSERT_TRUE(listener.backend().m_flags == FlagWrite);
+	ASSERT_TRUE(listener.backend().m_flags == Condition::Writable);
 	ASSERT_FALSE(listener.backend().m_removal);
 }
 
@@ -346,14 +350,14 @@
 	Listener<TestBackendUnset> listener;
 	Handle s{0};
 
-	listener.set(s, FlagRead | FlagWrite);
-	listener.unset(s, FlagRead);
-	listener.unset(s, FlagWrite);
+	listener.set(s, Condition::Readable | Condition::Writable);
+	listener.unset(s, Condition::Readable);
+	listener.unset(s, Condition::Writable);
 
 	ASSERT_EQ(0U, listener.size());
 	ASSERT_TRUE(listener.backend().m_isset);
 	ASSERT_TRUE(listener.backend().m_isunset);
-	ASSERT_TRUE(listener.backend().m_flags == 0);
+	ASSERT_TRUE(listener.backend().m_flags == Condition::None);
 	ASSERT_TRUE(listener.backend().m_removal);
 }
 
@@ -362,13 +366,13 @@
 	Listener<TestBackendUnset> listener;
 	Handle s{0};
 
-	listener.set(s, FlagRead | FlagWrite);
+	listener.set(s, Condition::Readable | Condition::Writable);
 	listener.remove(s);
 
 	ASSERT_EQ(0U, listener.size());
 	ASSERT_TRUE(listener.backend().m_isset);
 	ASSERT_TRUE(listener.backend().m_isunset);
-	ASSERT_TRUE(listener.backend().m_flags == 0);
+	ASSERT_TRUE(listener.backend().m_flags == Condition::None);
 	ASSERT_TRUE(listener.backend().m_removal);
 }
 
@@ -377,7 +381,7 @@
 	Listener<TestBackendUnsetFail> listener;
 	Handle s{0};
 
-	listener.set(s, FlagRead | FlagWrite);
+	listener.set(s, Condition::Readable | Condition::Writable);
 
 	try {
 		listener.remove(s);
@@ -425,7 +429,7 @@
 {
 	m_tserver = std::thread([this] () {
 		try {
-			m_listener.set(m_masterTcp.handle(), FlagRead);
+			m_listener.set(m_masterTcp.handle(), Condition::Readable);
 			m_listener.wait();
 			m_masterTcp.accept(nullptr);
 			m_masterTcp.close();
@@ -445,7 +449,7 @@
 {
 	m_tserver = std::thread([this] () {
 		try {
-			m_listener.set(m_masterTcp.handle(), FlagRead);
+			m_listener.set(m_masterTcp.handle(), Condition::Readable);
 			m_listener.wait();
 
 			auto sc = m_masterTcp.accept(nullptr);
@@ -603,10 +607,7 @@
 		try {
 			auto client = m_server.accept(nullptr);
 
-			printf("state: %d\n", client.state());
-
 			ASSERT_EQ("hello", client.recv(32));
-			std::this_thread::sleep_for(5s);
 		} catch (const net::Error &ex) {
 			FAIL() << ex.function() << ": " << ex.what();
 		}
@@ -614,17 +615,14 @@
 
 	std::this_thread::sleep_for(250ms);
 
-#if 0
-
 	m_tclient = std::thread([this] () {
 		try {
 			m_client.connect(Ipv4{"127.0.0.1", 16000});
-			//m_client.send("hello");
+			m_client.send("hello");
 		} catch (const net::Error &ex) {
 			FAIL() << ex.function() << ": " << ex.what();
 		}
 	});
-#endif
 }
 
 int main(int argc, char **argv)