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 * A listener socket is a special type of socket that listens to a given port 27 * and waits for connections on that port. This is all it can do. 28 * 29 * When a new connection is received, you must call `accept` and the listener 30 * returns a new instance of $(TCPSOCKET_LINK) that is properly initialized and 31 * can be used to communicate with the new client. 32 * 33 * Listener sockets are specific to the TCP protocol, UDP sockets are 34 * connectionless and can therefore communicate directly. As a consequence, a 35 * listener socket will always return the new connections as $(TCPSOCKET_LINK) 36 * instances. 37 * 38 * A listener is automatically closed on destruction, like all other types of 39 * socket. However if you want to stop listening before the socket is destroyed, 40 * you can call its `close()` function. 41 * 42 * Example: 43 * --- 44 * // Create a listener socket and make it wait for new 45 * // connections on port 55001 46 * auto listener = new TcpListener(); 47 * listener.listen(55001); 48 * 49 * // Endless loop that waits for new connections 50 * while (running) 51 * { 52 * auto client = new TcpSocket(); 53 * if (listener.accept(client) == Socket.Status.Done) 54 * { 55 * // A new client just connected! 56 * writeln("New connection received from ", client.getRemoteAddress()); 57 * doSomethingWith(client); 58 * } 59 * } 60 * --- 61 * 62 * See_Also: 63 * $(TCPSOCKET_LINK), $(SOCKET_LINK) 64 */ 65 module dsfml.network.tcplistener; 66 67 68 import dsfml.network.ipaddress; 69 import dsfml.network.socket; 70 import dsfml.network.tcpsocket; 71 import dsfml.system.err; 72 73 /** 74 * Socket that listens to new TCP connections. 75 */ 76 class TcpListener:Socket 77 { 78 package sfTcpListener* sfPtr; 79 80 /// Default constructor. 81 this() 82 { 83 sfPtr = sfTcpListener_create(); 84 } 85 86 /// Destructor. 87 ~this() 88 { 89 import dsfml.system.config; 90 mixin(destructorOutput); 91 sfTcpListener_destroy(sfPtr); 92 } 93 94 /** 95 * Get the port to which the socket is bound locally. 96 * 97 * If the socket is not listening to a port, this function returns 0. 98 * 99 * Returns: Port to which the socket is bound. 100 */ 101 ushort getLocalPort() 102 { 103 return sfTcpListener_getLocalPort(sfPtr); 104 } 105 106 /** 107 * Tell whether the socket is in blocking or non-blocking mode. 108 * 109 * In blocking mode, calls will not return until they have completed their 110 * task. For example, a call to `receive` in blocking mode won't return 111 * until some data was actually received. 112 * 113 * In non-blocking mode, calls will 114 * always return immediately, using the return code to signal whether there 115 * was data available or not. By default, all sockets are blocking. 116 * 117 * Params: 118 * blocking = true to set the socket as blocking, false for non-blocking 119 */ 120 void setBlocking(bool blocking) 121 { 122 sfTcpListener_setBlocking(sfPtr, blocking); 123 } 124 125 /** 126 * Accept a new connection. 127 * 128 * If the socket is in blocking mode, this function will not return until a 129 * connection is actually received. 130 * 131 * Params: 132 * socket = Socket that will hold the new connection 133 * 134 * Returns: Status code. 135 */ 136 Status accept(TcpSocket socket) 137 { 138 import dsfml.system..string; 139 140 Status toReturn = sfTcpListener_accept(sfPtr, socket.sfPtr); 141 err.write(dsfml.system..string.toString(sfErr_getOutput())); 142 return toReturn; 143 } 144 145 /** 146 * Start listening for connections. 147 * 148 * This functions makes the socket listen to the specified port, waiting for 149 * new connections. If the socket was previously listening to another port, 150 * it will be stopped first and bound to the new port. 151 * 152 * Params: 153 * port = Port to listen for new connections 154 * 155 * Returns: Status code. 156 */ 157 Status listen(ushort port, IpAddress address = IpAddress.Any) 158 { 159 import dsfml.system..string; 160 161 Status toReturn = sfTcpListener_listen(sfPtr, port, &address); 162 err.write(dsfml.system..string.toString(sfErr_getOutput())); 163 return toReturn; 164 } 165 166 /** 167 * Tell whether the socket is in blocking or non-blocking mode. 168 * 169 * Returns: true if the socket is blocking, false otherwise. 170 */ 171 bool isBlocking() const 172 { 173 return (sfTcpListener_isBlocking(sfPtr)); 174 } 175 176 } 177 178 unittest 179 { 180 version(DSFML_Unittest_Network) 181 { 182 import std.stdio; 183 import dsfml.network.ipaddress; 184 185 writeln("Unittest for Listener"); 186 //socket connecting to server 187 auto clientSocket = new TcpSocket(); 188 189 //listener looking for new sockets 190 auto listener = new TcpListener(); 191 listener.listen(55002); 192 193 writeln("The listener is listening to port ", listener.getLocalPort()); 194 195 //get our client socket to connect to the server 196 clientSocket.connect(IpAddress.LocalHost, 55002); 197 198 199 //socket on the server side connected to the client's socket 200 auto serverSocket = new TcpSocket(); 201 202 //accepts a new connection and binds it to the socket in the parameter 203 listener.accept(serverSocket); 204 205 clientSocket.disconnect(); 206 writeln(); 207 } 208 } 209 210 package extern(C): 211 212 struct sfTcpListener; 213 214 sfTcpListener* sfTcpListener_create(); 215 216 217 //Destroy a TCP listener 218 void sfTcpListener_destroy(sfTcpListener* listener); 219 220 221 //Set the blocking state of a TCP listener 222 void sfTcpListener_setBlocking(sfTcpListener* listener, bool blocking); 223 224 225 //Tell whether a TCP listener is in blocking or non-blocking mode 226 bool sfTcpListener_isBlocking(const sfTcpListener* listener); 227 228 229 //Get the port to which a TCP listener is bound locally 230 ushort sfTcpListener_getLocalPort(const(sfTcpListener)* listener); 231 232 233 //Start listening for connections 234 Socket.Status sfTcpListener_listen(sfTcpListener* listener, ushort port, IpAddress* address); 235 236 237 //Accept a new connection 238 Socket.Status sfTcpListener_accept(sfTcpListener* listener, sfTcpSocket* connected); 239 240 const(char)* sfErr_getOutput();