Mercurial > code
annotate C++/SocketListener.h @ 278:adcae2bde2f0
Socket: listener now have initializer list constructor
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 23 Oct 2014 18:15:38 +0200 |
parents | b544a599e08e |
children | 836903141476 24085fae3162 |
rev | line source |
---|---|
170 | 1 /* |
2 * SocketListener.h -- portable select() wrapper | |
3 * | |
4 * Copyright (c) 2013, 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_H_ | |
20 #define _SOCKET_LISTENER_H_ | |
21 | |
258 | 22 #include <chrono> |
23 #include <functional> | |
278
adcae2bde2f0
Socket: listener now have initializer list constructor
David Demelier <markand@malikania.fr>
parents:
277
diff
changeset
|
24 #include <initializer_list> |
adcae2bde2f0
Socket: listener now have initializer list constructor
David Demelier <markand@malikania.fr>
parents:
277
diff
changeset
|
25 #include <utility> |
270 | 26 #include <vector> |
170 | 27 |
28 #include "Socket.h" | |
29 | |
270 | 30 #if defined(_WIN32) |
31 # if _WIN32_WINNT >= 0x0600 | |
32 # define SOCKET_LISTENER_HAVE_POLL | |
33 # endif | |
34 #else | |
35 # define SOCKET_LISTENER_HAVE_POLL | |
36 #endif | |
37 | |
170 | 38 /** |
258 | 39 * @enum SocketDirection |
40 * @brief The SocketDirection enum | |
41 * | |
42 * Bitmask that can be set to both reading and writing. | |
170 | 43 */ |
277
b544a599e08e
Socket: remove enum class
David Demelier <markand@malikania.fr>
parents:
271
diff
changeset
|
44 enum SocketDirection { |
258 | 45 Read = (1 << 0), //!< only for receive |
46 Write = (1 << 1) //!< only for sending | |
47 }; | |
48 | |
49 /** | |
50 * @enum SocketMethod | |
51 * @brief The SocketMethod enum | |
52 * | |
53 * Select the method of polling. It is only a preferred method, for example if you | |
54 * request for poll but it is not available, select will be used. | |
55 */ | |
277
b544a599e08e
Socket: remove enum class
David Demelier <markand@malikania.fr>
parents:
271
diff
changeset
|
56 enum SocketMethod { |
258 | 57 Select, //!< select(2) method, fallback |
58 Poll //!< poll(2), everywhere possible | |
59 }; | |
60 | |
61 /** | |
62 * @struct SocketStatus | |
63 * @brief The SocketStatus struct | |
64 * | |
65 * Result of a select call, returns the first ready socket found with its | |
66 * direction. | |
67 */ | |
68 struct SocketStatus { | |
277
b544a599e08e
Socket: remove enum class
David Demelier <markand@malikania.fr>
parents:
271
diff
changeset
|
69 Socket socket; //!< which socket is ready |
b544a599e08e
Socket: remove enum class
David Demelier <markand@malikania.fr>
parents:
271
diff
changeset
|
70 int direction; //!< the direction |
170 | 71 }; |
72 | |
188
ce3e1c3d6fed
Update sockets to style and using instead of typedef
David Demelier <markand@malikania.fr>
parents:
170
diff
changeset
|
73 /** |
ce3e1c3d6fed
Update sockets to style and using instead of typedef
David Demelier <markand@malikania.fr>
parents:
170
diff
changeset
|
74 * @class SocketListener |
ce3e1c3d6fed
Update sockets to style and using instead of typedef
David Demelier <markand@malikania.fr>
parents:
170
diff
changeset
|
75 * @brief Synchronous multiplexing |
ce3e1c3d6fed
Update sockets to style and using instead of typedef
David Demelier <markand@malikania.fr>
parents:
170
diff
changeset
|
76 * |
ce3e1c3d6fed
Update sockets to style and using instead of typedef
David Demelier <markand@malikania.fr>
parents:
170
diff
changeset
|
77 * Convenient wrapper around the select() system call. |
ce3e1c3d6fed
Update sockets to style and using instead of typedef
David Demelier <markand@malikania.fr>
parents:
170
diff
changeset
|
78 */ |
245
3c12f0e8bbb9
Converter: add cstring missing
David Demelier <markand@malikania.fr>
parents:
194
diff
changeset
|
79 class SocketListener final { |
258 | 80 public: |
81 /** | |
82 * @brief Function for listing all sockets | |
83 */ | |
277
b544a599e08e
Socket: remove enum class
David Demelier <markand@malikania.fr>
parents:
271
diff
changeset
|
84 using MapFunc = std::function<void (Socket &, int)>; |
258 | 85 |
270 | 86 #if defined(SOCKET_LISTENER_HAVE_POLL) |
87 static constexpr const SocketMethod PreferredMethod = SocketMethod::Poll; | |
88 #else | |
89 static constexpr const SocketMethod PreferredMethod = SocketMethod::Select; | |
90 #endif | |
91 | |
258 | 92 /** |
93 * @class Interface | |
94 * @brief Implement the polling method | |
95 */ | |
96 class Interface { | |
97 public: | |
98 /** | |
99 * Default destructor. | |
100 */ | |
101 virtual ~Interface() = default; | |
102 | |
103 /** | |
104 * List all sockets in the interface. | |
105 * | |
106 * @param func the function | |
107 */ | |
108 virtual void list(const MapFunc &func) = 0; | |
109 | |
110 /** | |
111 * Add a socket with a specified direction. | |
112 * | |
113 * @param s the socket | |
114 * @param direction the direction | |
115 */ | |
277
b544a599e08e
Socket: remove enum class
David Demelier <markand@malikania.fr>
parents:
271
diff
changeset
|
116 virtual void add(Socket s, int direction) = 0; |
258 | 117 |
118 /** | |
119 * Remove a socket with a specified direction. | |
120 * | |
121 * @param s the socket | |
122 * @param direction the direction | |
123 */ | |
277
b544a599e08e
Socket: remove enum class
David Demelier <markand@malikania.fr>
parents:
271
diff
changeset
|
124 virtual void remove(const Socket &s, int direction) = 0; |
258 | 125 |
126 /** | |
127 * Remove all sockets. | |
128 */ | |
129 virtual void clear() = 0; | |
130 | |
131 /** | |
132 * Get the total number of sockets in the listener. | |
133 */ | |
134 virtual unsigned size() const = 0; | |
135 | |
136 /** | |
270 | 137 * Select one socket. |
258 | 138 * |
139 * @param ms the number of milliseconds to wait, -1 means forever | |
140 * @return the socket status | |
141 * @throw error::Failure on failure | |
142 * @throw error::Timeout on timeout | |
143 */ | |
144 virtual SocketStatus select(int ms) = 0; | |
270 | 145 |
146 /** | |
147 * Select many sockets. | |
148 * | |
149 * @param ms the number of milliseconds to wait, -1 means forever | |
150 * @return a vector of ready sockets | |
151 * @throw error::Failure on failure | |
152 * @throw error::Timeout on timeout | |
153 */ | |
154 virtual std::vector<SocketStatus> selectMultiple(int ms) = 0; | |
258 | 155 }; |
156 | |
157 std::unique_ptr<Interface> m_interface; | |
158 | |
170 | 159 public: |
160 /** | |
271
f7000cc599d0
Socket: make listener movable
David Demelier <markand@malikania.fr>
parents:
270
diff
changeset
|
161 * Move constructor. |
f7000cc599d0
Socket: make listener movable
David Demelier <markand@malikania.fr>
parents:
270
diff
changeset
|
162 * |
f7000cc599d0
Socket: make listener movable
David Demelier <markand@malikania.fr>
parents:
270
diff
changeset
|
163 * @param other the other object |
f7000cc599d0
Socket: make listener movable
David Demelier <markand@malikania.fr>
parents:
270
diff
changeset
|
164 */ |
f7000cc599d0
Socket: make listener movable
David Demelier <markand@malikania.fr>
parents:
270
diff
changeset
|
165 SocketListener(SocketListener &&other) = default; |
f7000cc599d0
Socket: make listener movable
David Demelier <markand@malikania.fr>
parents:
270
diff
changeset
|
166 |
f7000cc599d0
Socket: make listener movable
David Demelier <markand@malikania.fr>
parents:
270
diff
changeset
|
167 /** |
f7000cc599d0
Socket: make listener movable
David Demelier <markand@malikania.fr>
parents:
270
diff
changeset
|
168 * Move operator. |
f7000cc599d0
Socket: make listener movable
David Demelier <markand@malikania.fr>
parents:
270
diff
changeset
|
169 * |
f7000cc599d0
Socket: make listener movable
David Demelier <markand@malikania.fr>
parents:
270
diff
changeset
|
170 * @param other the other object |
f7000cc599d0
Socket: make listener movable
David Demelier <markand@malikania.fr>
parents:
270
diff
changeset
|
171 * @return this |
f7000cc599d0
Socket: make listener movable
David Demelier <markand@malikania.fr>
parents:
270
diff
changeset
|
172 */ |
f7000cc599d0
Socket: make listener movable
David Demelier <markand@malikania.fr>
parents:
270
diff
changeset
|
173 SocketListener &operator=(SocketListener &&other) = default; |
f7000cc599d0
Socket: make listener movable
David Demelier <markand@malikania.fr>
parents:
270
diff
changeset
|
174 |
f7000cc599d0
Socket: make listener movable
David Demelier <markand@malikania.fr>
parents:
270
diff
changeset
|
175 /** |
258 | 176 * Create a socket listener. |
245
3c12f0e8bbb9
Converter: add cstring missing
David Demelier <markand@malikania.fr>
parents:
194
diff
changeset
|
177 * |
258 | 178 * @param method the preferred method |
245
3c12f0e8bbb9
Converter: add cstring missing
David Demelier <markand@malikania.fr>
parents:
194
diff
changeset
|
179 */ |
278
adcae2bde2f0
Socket: listener now have initializer list constructor
David Demelier <markand@malikania.fr>
parents:
277
diff
changeset
|
180 SocketListener(int method = PreferredMethod); |
adcae2bde2f0
Socket: listener now have initializer list constructor
David Demelier <markand@malikania.fr>
parents:
277
diff
changeset
|
181 |
adcae2bde2f0
Socket: listener now have initializer list constructor
David Demelier <markand@malikania.fr>
parents:
277
diff
changeset
|
182 /** |
adcae2bde2f0
Socket: listener now have initializer list constructor
David Demelier <markand@malikania.fr>
parents:
277
diff
changeset
|
183 * Createa listener with some sockets. |
adcae2bde2f0
Socket: listener now have initializer list constructor
David Demelier <markand@malikania.fr>
parents:
277
diff
changeset
|
184 * |
adcae2bde2f0
Socket: listener now have initializer list constructor
David Demelier <markand@malikania.fr>
parents:
277
diff
changeset
|
185 * @param list the initializer list |
adcae2bde2f0
Socket: listener now have initializer list constructor
David Demelier <markand@malikania.fr>
parents:
277
diff
changeset
|
186 * @param method the preferred method |
adcae2bde2f0
Socket: listener now have initializer list constructor
David Demelier <markand@malikania.fr>
parents:
277
diff
changeset
|
187 */ |
adcae2bde2f0
Socket: listener now have initializer list constructor
David Demelier <markand@malikania.fr>
parents:
277
diff
changeset
|
188 SocketListener(std::initializer_list<std::pair<Socket, int>> list, int method = PreferredMethod); |
245
3c12f0e8bbb9
Converter: add cstring missing
David Demelier <markand@malikania.fr>
parents:
194
diff
changeset
|
189 |
3c12f0e8bbb9
Converter: add cstring missing
David Demelier <markand@malikania.fr>
parents:
194
diff
changeset
|
190 /** |
170 | 191 * Add a socket to listen to. |
192 * | |
193 * @param s the socket | |
258 | 194 * @param direction the direction |
170 | 195 */ |
277
b544a599e08e
Socket: remove enum class
David Demelier <markand@malikania.fr>
parents:
271
diff
changeset
|
196 inline void add(Socket s, int direction) |
258 | 197 { |
198 m_interface->add(std::move(s), direction); | |
199 } | |
170 | 200 |
201 /** | |
202 * Remove a socket from the list. | |
203 * | |
204 * @param s the socket | |
258 | 205 * @param direction the direction |
170 | 206 */ |
277
b544a599e08e
Socket: remove enum class
David Demelier <markand@malikania.fr>
parents:
271
diff
changeset
|
207 inline void remove(const Socket &s, int direction) |
258 | 208 { |
209 m_interface->remove(s, direction); | |
210 } | |
170 | 211 |
212 /** | |
213 * Remove every sockets in the listener. | |
214 */ | |
258 | 215 inline void clear() |
216 { | |
217 m_interface->clear(); | |
218 } | |
170 | 219 |
220 /** | |
194
9fc5f917872b
Update Luae bits and LuaSocket
David Demelier <markand@malikania.fr>
parents:
188
diff
changeset
|
221 * Get the number of clients in listener. |
9fc5f917872b
Update Luae bits and LuaSocket
David Demelier <markand@malikania.fr>
parents:
188
diff
changeset
|
222 * |
258 | 223 * @return the total number of sockets in the listener |
194
9fc5f917872b
Update Luae bits and LuaSocket
David Demelier <markand@malikania.fr>
parents:
188
diff
changeset
|
224 */ |
258 | 225 inline unsigned size() const |
226 { | |
227 return m_interface->size(); | |
228 } | |
194
9fc5f917872b
Update Luae bits and LuaSocket
David Demelier <markand@malikania.fr>
parents:
188
diff
changeset
|
229 |
9fc5f917872b
Update Luae bits and LuaSocket
David Demelier <markand@malikania.fr>
parents:
188
diff
changeset
|
230 /** |
258 | 231 * Select a socket. Waits for a specific amount of time specified as the duration. |
170 | 232 * |
270 | 233 * @param duration the duration |
247 | 234 * @return the socket ready |
170 | 235 * @throw SocketError on error |
236 * @throw SocketTimeout on timeout | |
237 */ | |
258 | 238 template <typename Rep, typename Ratio> |
239 inline SocketStatus select(const std::chrono::duration<Rep, Ratio> &duration) | |
240 { | |
241 auto cvt = std::chrono::duration_cast<std::chrono::milliseconds>(duration); | |
242 | |
243 return m_interface->select(cvt.count()); | |
244 } | |
245 | |
246 /** | |
247 * Overload that waits indefinitely. | |
248 * | |
249 * @return the socket ready | |
250 * @throw SocketError on error | |
251 * @throw SocketTimeout on timeout | |
252 */ | |
253 inline SocketStatus select() | |
254 { | |
255 return m_interface->select(-1); | |
256 } | |
257 | |
258 /** | |
270 | 259 * Select multiple sockets. |
260 * | |
261 * @param duration the duration | |
262 * @return the socket ready | |
263 * @throw SocketError on error | |
264 * @throw SocketTimeout on timeout | |
265 */ | |
266 template <typename Rep, typename Ratio> | |
267 inline std::vector<SocketStatus> selectMultiple(const std::chrono::duration<Rep, Ratio> &duration) | |
268 { | |
269 auto cvt = std::chrono::duration_cast<std::chrono::milliseconds>(duration); | |
270 | |
271 return m_interface->selectMultiple(cvt.count()); | |
272 } | |
273 | |
274 /** | |
275 * Overload that waits indefinitely. | |
276 * | |
277 * @return the socket ready | |
278 * @throw SocketError on error | |
279 * @throw SocketTimeout on timeout | |
280 */ | |
281 inline std::vector<SocketStatus> selectMultiple() | |
282 { | |
283 return m_interface->selectMultiple(-1); | |
284 } | |
285 | |
286 /** | |
258 | 287 * List every socket in the listener. |
288 * | |
289 * @param func the function to call | |
290 */ | |
291 template <typename Func> | |
292 inline void list(Func func) | |
293 { | |
294 m_interface->list(func); | |
295 } | |
170 | 296 }; |
297 | |
298 #endif // !_SOCKET_LISTENER_H_ |