comparison C++/modules/Socket/SocketListener.h @ 334:0b576ee64d45

* Create brand new hierarchy * Rename DynLib to Dynlib * Remove some warnings
author David Demelier <markand@malikania.fr>
date Sun, 08 Mar 2015 14:26:33 +0100
parents C++/SocketListener.h@cba77da58496
children d235553e47a9
comparison
equal deleted inserted replaced
333:412ca7a5e1ea 334:0b576ee64d45
1 /*
2 * SocketListener.h -- portable select() wrapper
3 *
4 * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #ifndef _SOCKET_LISTENER_NG_H_
20 #define _SOCKET_LISTENER_NG_H_
21
22 #include <chrono>
23 #include <functional>
24 #include <initializer_list>
25 #include <map>
26 #include <memory>
27 #include <utility>
28 #include <vector>
29
30 #include "Socket.h"
31
32 #if defined(_WIN32)
33 # if _WIN32_WINNT >= 0x0600
34 # define SOCKET_HAVE_POLL
35 # endif
36 #else
37 # define SOCKET_HAVE_POLL
38 #endif
39
40 /**
41 * @enum SocketMethod
42 * @brief The SocketMethod enum
43 *
44 * Select the method of polling. It is only a preferred method, for example if you
45 * request for poll but it is not available, select will be used.
46 */
47 enum class SocketMethod {
48 Select, //!< select(2) method, fallback
49 Poll //!< poll(2), everywhere possible
50 };
51
52 /**
53 * @struct SocketStatus
54 * @brief The SocketStatus struct
55 *
56 * Result of a select call, returns the first ready socket found with its
57 * direction.
58 */
59 class SocketStatus {
60 public:
61 Socket &socket; //!< which socket is ready
62 int direction; //!< the direction
63 };
64
65 /**
66 * @class SocketListenerInterface
67 * @brief Implement the polling method
68 */
69 class SocketListenerInterface {
70 public:
71 /**
72 * Default destructor.
73 */
74 virtual ~SocketListenerInterface() = default;
75
76 /**
77 * Add a socket with a specified direction.
78 *
79 * @param s the socket
80 * @param direction the direction
81 */
82 virtual void set(Socket &sc, int direction) = 0;
83
84 /**
85 * Remove a socket with a specified direction.
86 *
87 * @param s the socket
88 * @param direction the direction
89 */
90 virtual void unset(Socket &sc, int direction) = 0;
91
92 /**
93 * Remove completely a socket.
94 *
95 * @param sc the socket to remove
96 */
97 virtual void remove(Socket &sc) = 0;
98
99 /**
100 * Remove all sockets.
101 */
102 virtual void clear() = 0;
103
104 /**
105 * Select one socket.
106 *
107 * @param ms the number of milliseconds to wait, -1 means forever
108 * @return the socket status
109 * @throw error::Failure on failure
110 * @throw error::Timeout on timeout
111 */
112 virtual SocketStatus select(int ms) = 0;
113
114 /**
115 * Select many sockets.
116 *
117 * @param ms the number of milliseconds to wait, -1 means forever
118 * @return a vector of ready sockets
119 * @throw error::Failure on failure
120 * @throw error::Timeout on timeout
121 */
122 virtual std::vector<SocketStatus> selectMultiple(int ms) = 0;
123 };
124
125 /**
126 * @class SocketListener
127 * @brief Synchronous multiplexing
128 *
129 * Convenient wrapper around the select() system call.
130 *
131 * This class is implemented using a bridge pattern to allow different uses
132 * of listener implementation.
133 *
134 * Currently, poll and select() are available.
135 *
136 * This wrappers takes abstract sockets as non-const reference but it does not
137 * own them so you must take care that sockets are still alive until the
138 * SocketListener is destroyed.
139 */
140 class SocketListener final {
141 public:
142 #if defined(SOCKET_HAVE_POLL)
143 static constexpr const SocketMethod PreferredMethod = SocketMethod::Poll;
144 #else
145 static constexpr const SocketMethod PreferredMethod = SocketMethod::Select;
146 #endif
147
148 static const int Read;
149 static const int Write;
150
151 using Map = std::map<std::reference_wrapper<Socket>, int>;
152 using Iface = std::unique_ptr<SocketListenerInterface>;
153
154 private:
155 Map m_map;
156 Iface m_interface;
157
158 public:
159 /**
160 * Move constructor.
161 *
162 * @param other the other object
163 */
164 SocketListener(SocketListener &&other) = default;
165
166 /**
167 * Move operator.
168 *
169 * @param other the other object
170 * @return this
171 */
172 SocketListener &operator=(SocketListener &&other) = default;
173
174 /**
175 * Create a socket listener.
176 *
177 * @param method the preferred method
178 */
179 SocketListener(SocketMethod method = PreferredMethod);
180
181 /**
182 * Create a listener from a list of sockets.
183 *
184 * @param list the list
185 */
186 SocketListener(std::initializer_list<std::pair<std::reference_wrapper<Socket>, int>> list);
187
188 /**
189 * Return an iterator to the beginning.
190 *
191 * @return the iterator
192 */
193 inline auto begin() noexcept
194 {
195 return m_map.begin();
196 }
197
198 /**
199 * Overloaded function.
200 *
201 * @return the iterator
202 */
203 inline auto begin() const noexcept
204 {
205 return m_map.begin();
206 }
207
208 /**
209 * Overloaded function.
210 *
211 * @return the iterator
212 */
213 inline auto cbegin() const noexcept
214 {
215 return m_map.cbegin();
216 }
217
218 /**
219 * Return an iterator to the end.
220 *
221 * @return the iterator
222 */
223 inline auto end() noexcept
224 {
225 return m_map.end();
226 }
227
228 /**
229 * Overloaded function.
230 *
231 * @return the iterator
232 */
233 inline auto end() const noexcept
234 {
235 return m_map.end();
236 }
237
238 /**
239 * Overloaded function.
240 *
241 * @return the iterator
242 */
243 inline auto cend() const noexcept
244 {
245 return m_map.cend();
246 }
247
248 /**
249 * Add a socket to the listener.
250 *
251 * @param sc the socket
252 * @param direction (may be OR'ed)
253 */
254 void set(Socket &sc, int direction);
255
256 /**
257 * Unset a socket from the listener, only the direction is removed
258 * unless the two directions are requested.
259 *
260 * For example, if you added a socket for both reading and writing,
261 * unsetting the write direction will keep the socket for reading.
262 *
263 * @param sc the socket
264 * @param direction the direction (may be OR'ed)
265 * @see remove
266 */
267 void unset(Socket &sc, int direction) noexcept;
268
269 /**
270 * Remove completely the socket from the listener.
271 *
272 * @param sc the socket
273 */
274 inline void remove(Socket &sc) noexcept
275 {
276 m_map.erase(sc);
277 m_interface->remove(sc);
278 }
279
280 /**
281 * Remove all sockets.
282 */
283 inline void clear() noexcept
284 {
285 m_map.clear();
286 m_interface->clear();
287 }
288
289 /**
290 * Get the number of sockets in the listener.
291 */
292 unsigned size() const noexcept
293 {
294 return m_map.size();
295 }
296
297 /**
298 * Select a socket. Waits for a specific amount of time specified as the duration.
299 *
300 * @param duration the duration
301 * @return the socket ready
302 */
303 template <typename Rep, typename Ratio>
304 inline SocketStatus select(const std::chrono::duration<Rep, Ratio> &duration)
305 {
306 auto cvt = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
307
308 return m_interface->select(cvt.count());
309 }
310
311 /**
312 * Overload with milliseconds.
313 *
314 * @param timeout the optional timeout in milliseconds
315 * @return the socket ready
316 */
317 inline SocketStatus select(int timeout = -1)
318 {
319 return m_interface->select(timeout);
320 }
321
322 /**
323 * Select multiple sockets.
324 *
325 * @param duration the duration
326 * @return the socket ready
327 */
328 template <typename Rep, typename Ratio>
329 inline std::vector<SocketStatus> selectMultiple(const std::chrono::duration<Rep, Ratio> &duration)
330 {
331 auto cvt = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
332
333 return m_interface->selectMultiple(cvt.count());
334 }
335
336 /**
337 * Overload with milliseconds.
338 *
339 * @return the socket ready
340 */
341 inline std::vector<SocketStatus> selectMultiple(int timeout = -1)
342 {
343 return m_interface->selectMultiple(timeout);
344 }
345 };
346
347 #endif // !_SOCKET_LISTENER_NG_H_