Mercurial > code
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_ |