1 /* 2 * DSFML - The Simple and Fast Multimedia Library for D 3 * 4 * Copyright (c) 2013 - 2017 Jeremy DeHaan (dehaan.jeremiah@gmail.com) 5 * 6 * This software is provided 'as-is', without any express or implied warranty. 7 * In no event will the authors be held liable for any damages arising from the 8 * use of this software. 9 * 10 * Permission is granted to anyone to use this software for any purpose, 11 * including commercial applications, and to alter it and redistribute it 12 * freely, subject to the following restrictions: 13 * 14 * 1. The origin of this software must not be misrepresented; you must not claim 15 * that you wrote the original software. If you use this software in a product, 16 * an acknowledgment in the product documentation would be appreciated but is 17 * not required. 18 * 19 * 2. Altered source versions must be plainly marked as such, and must not be 20 * misrepresented as being the original software. 21 * 22 * 3. This notice may not be removed or altered from any source distribution 23 */ 24 25 /** 26 * Socket selectors provide a way to wait until some data is available on a set 27 * of sockets, instead of just one. This is convenient when you have multiple 28 * sockets that may possibly receive data, but you don't know which one will be 29 * ready first. In particular, it avoids to use a thread for each socket; with 30 * selectors, a single thread can handle all the sockets. 31 * 32 * All types of sockets can be used in a selector: 33 * $(UL 34 * $(LI $(TCPLISTENER_LINK)) 35 * $(LI $(TCPSOCKET_LINK)) 36 * $(LI $(UDPSOCKET_LINK))) 37 * 38 * $(PARA 39 * A selector doesn't store its own copies of the sockets, it simply keeps a 40 * reference to the original sockets that you pass to the "add" function. 41 * Therefore, you can't use the selector as a socket container, you must store 42 * them outside and make sure that they are alive as long as they are used in 43 * the selector (i.e., they cannot be collected by the GC). 44 * 45 * Using a selector is simple:) 46 * $(UL 47 * $(LI populate the selector with all the sockets that you want to observe) 48 * $(LI make it wait until there is data available on any of the sockets) 49 * $(LI test each socket to find out which ones are ready)) 50 * 51 * Example: 52 * --- 53 * // Create a socket to listen to new connections 54 * auto listener = new TcpListener(); 55 * listener.listen(55001); 56 * 57 * // Create a list to store the future clients 58 * TcpSocket[] clients; 59 * 60 * // Create a selector 61 * auto selector = new SocketSelector(); 62 * 63 * // Add the listener to the selector 64 * selector.add(listener); 65 * 66 * // Endless loop that waits for new connections 67 * while (running) 68 * { 69 * // Make the selector wait for data on any socket 70 * if (selector.wait()) 71 * { 72 * // Test the listener 73 * if (selector.isReady(listener)) 74 * { 75 * // The listener is ready: there is a pending connection 76 * auto client = new TcpSocket(); 77 * if (listener.accept(client) == Socket.Status.Done) 78 * { 79 * // Add the new client to the clients list 80 * clients~=client; 81 * 82 * // Add the new client to the selector so that we will 83 * // be notified when he sends something 84 * selector.add(client); 85 * } 86 * else 87 * { 88 * // Error, we won't get a new connection 89 * } 90 * } 91 * else 92 * { 93 * // The listener socket is not ready, test all other sockets (the clients) 94 * foreach(client; clients) 95 * { 96 * if (selector.isReady(client)) 97 * { 98 * // The client has sent some data, we can receive it 99 * auto packet = new Packet(); 100 * if (client.receive(packet) == Socket.Status.Done) 101 * { 102 * ... 103 * } 104 * } 105 * } 106 * } 107 * } 108 * } 109 * --- 110 * 111 * See_Also: 112 * $(SOCKET_LINK) 113 */ 114 module dsfml.network.socketselector; 115 116 import dsfml.network.tcplistener; 117 import dsfml.network.tcpsocket; 118 import dsfml.network.udpsocket; 119 120 import core.time; 121 122 /** 123 * Multiplexer that allows to read from multiple sockets. 124 */ 125 class SocketSelector 126 { 127 package sfSocketSelector* sfPtr; 128 129 /// Default constructor. 130 this() 131 { 132 sfPtr = sfSocketSelector_create(); 133 } 134 135 /// Destructor. 136 ~this() 137 { 138 import dsfml.system.config; 139 mixin(destructorOutput); 140 sfSocketSelector_destroy(sfPtr); 141 } 142 143 /** 144 * Add a new TcpListener to the selector. 145 * 146 * This function keeps a weak reference to the socket, so you have to make 147 * sure that the socket is not destroyed while it is stored in the selector. 148 * This function does nothing if the socket is not valid. 149 * 150 * Params: 151 * listener = Reference to the listener to add 152 */ 153 void add(TcpListener listener) 154 { 155 sfSocketSelector_addTcpListener(sfPtr, listener.sfPtr); 156 } 157 158 /** 159 * Add a new TcpSocket to the selector. 160 * 161 * This function keeps a weak reference to the socket, so you have to make 162 * sure that the socket is not destroyed while it is stored in the selector. 163 * This function does nothing if the socket is not valid. 164 * 165 * Params: 166 * socket = Reference to the socket to add 167 */ 168 void add(TcpSocket socket) 169 { 170 sfSocketSelector_addTcpSocket(sfPtr, socket.sfPtr); 171 } 172 173 /** 174 * Add a new UdpSocket to the selector. 175 * 176 * This function keeps a weak reference to the socket, so you have to make 177 * sure that the socket is not destroyed while it is stored in the selector. 178 * This function does nothing if the socket is not valid. 179 * 180 * Params: 181 * socket = Reference to the socket to add 182 */ 183 void add(UdpSocket socket) 184 { 185 sfSocketSelector_addUdpSocket(sfPtr, socket.sfPtr); 186 } 187 188 /** 189 * Remove all the sockets stored in the selector. 190 * 191 * This function doesn't destroy any instance, it simply removes all the 192 * references that the selector has to external sockets. 193 */ 194 void clear() 195 { 196 sfSocketSelector_clear(sfPtr); 197 } 198 199 /** 200 * Test a socket to know if it is ready to receive data. 201 * 202 * This function must be used after a call to Wait, to know which sockets 203 * are ready to receive data. If a socket is ready, a call to receive will 204 * never block because we know that there is data available to read. Note 205 * that if this function returns true for a TcpListener, this means that it 206 * is ready to accept a new connection. 207 */ 208 bool isReady(TcpListener listener) 209 { 210 return (sfSocketSelector_isTcpListenerReady(sfPtr, listener.sfPtr)); 211 } 212 213 /// ditto 214 bool isReady(TcpSocket socket) 215 { 216 return (sfSocketSelector_isTcpSocketReady(sfPtr, socket.sfPtr)); 217 } 218 219 /// ditto 220 bool isReady(UdpSocket socket) 221 { 222 return (sfSocketSelector_isUdpSocketReady(sfPtr, socket.sfPtr)); 223 } 224 225 /** 226 * Remove a socket from the selector. 227 * 228 * This function doesn't destroy the socket, it simply removes the reference 229 * that the selector has to it. 230 * 231 * Params: 232 * socket = Reference to the socket to remove 233 */ 234 void remove(TcpListener socket) 235 { 236 sfSocketSelector_removeTcpListener(sfPtr, socket.sfPtr); 237 } 238 239 /** 240 * Remove a socket from the selector. 241 * 242 * This function doesn't destroy the socket, it simply removes the reference 243 * that the selector has to it. 244 * 245 * Params: 246 * socket = Reference to the socket to remove 247 */ 248 void remove(TcpSocket socket) 249 { 250 sfSocketSelector_removeTcpSocket(sfPtr, socket.sfPtr); 251 } 252 253 /** 254 * Remove a socket from the selector. 255 * 256 * This function doesn't destroy the socket, it simply removes the reference 257 * that the selector has to it. 258 * 259 * Params: 260 * socket = Reference to the socket to remove 261 */ 262 void remove(UdpSocket socket) 263 { 264 sfSocketSelector_removeUdpSocket(sfPtr, socket.sfPtr); 265 } 266 267 /** 268 * Wait until one or more sockets are ready to receive. 269 * 270 * This function returns as soon as at least one socket has some data 271 * available to be received. To know which sockets are ready, use the 272 * isReady function. If you use a timeout and no socket is ready before the 273 * timeout is over, the function returns false. 274 * 275 * Parameters 276 * timeout = Maximum time to wait, (use Time::Zero for infinity) 277 * 278 * Returns: true if there are sockets ready, false otherwise. 279 */ 280 bool wait(Duration timeout = Duration.zero()) 281 { 282 return (sfSocketSelector_wait(sfPtr, timeout.total!"usecs")); 283 } 284 } 285 286 unittest 287 { 288 version(DSFML_Unittest_Network) 289 { 290 import std.stdio; 291 import dsfml.network.ipaddress; 292 293 294 writeln("Unittest for SocketSelector"); 295 296 auto selector = new SocketSelector(); 297 298 //get a listener and start listening to a new port 299 auto listener = new TcpListener(); 300 listener.listen(55004); 301 302 //add the listener to the selector 303 selector.add(listener); 304 305 //The client tries to connect to the server 306 auto clientSocket = new TcpSocket(); 307 clientSocket.connect(IpAddress.LocalHost, 55004); 308 309 310 //wait for the selector to be informed of new things! 311 selector.wait(); 312 313 auto serverSocket = new TcpSocket(); 314 //the listener is ready! New connections are available 315 if(selector.isReady(listener)) 316 { 317 writeln("Accepted the connection."); 318 listener.accept(serverSocket); 319 } 320 321 writeln(); 322 } 323 } 324 325 private extern(C): 326 327 struct sfSocketSelector; 328 329 //Create a new selector 330 sfSocketSelector* sfSocketSelector_create(); 331 332 //Create a new socket selector by copying an existing one 333 sfSocketSelector* sfSocketSelector_copy(const sfSocketSelector* selector); 334 335 336 //Destroy a socket selector 337 void sfSocketSelector_destroy(sfSocketSelector* selector); 338 339 340 //Add a new socket to a socket selector 341 void sfSocketSelector_addTcpListener(sfSocketSelector* selector, sfTcpListener* socket); 342 void sfSocketSelector_addTcpSocket(sfSocketSelector* selector, sfTcpSocket* socket); 343 void sfSocketSelector_addUdpSocket(sfSocketSelector* selector, sfUdpSocket* socket); 344 345 346 //Remove a socket from a socket selector 347 void sfSocketSelector_removeTcpListener(sfSocketSelector* selector, sfTcpListener* socket); 348 void sfSocketSelector_removeTcpSocket(sfSocketSelector* selector, sfTcpSocket* socket); 349 void sfSocketSelector_removeUdpSocket(sfSocketSelector* selector, sfUdpSocket* socket); 350 351 352 //Remove all the sockets stored in a selector 353 void sfSocketSelector_clear(sfSocketSelector* selector); 354 355 356 //Wait until one or more sockets are ready to receive 357 bool sfSocketSelector_wait(sfSocketSelector* selector, long timeout); 358 359 360 //Test a socket to know if it is ready to receive data 361 bool sfSocketSelector_isTcpListenerReady(const(sfSocketSelector)* selector, sfTcpListener* socket); 362 bool sfSocketSelector_isTcpSocketReady(const(sfSocketSelector)* selector, sfTcpSocket* socket); 363 bool sfSocketSelector_isUdpSocketReady(const(sfSocketSelector)* selector, sfUdpSocket* socket);