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