1 /*
2 DSFML - The Simple and Fast Multimedia Library for D
3 
4 Copyright (c) 2013 - 2015 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 use of this software.
8 
9 Permission is granted to anyone to use this software for any purpose, including commercial applications,
10 and to alter it and redistribute it freely, subject to the following restrictions:
11 
12 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
13 If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
14 
15 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
16 
17 3. This notice may not be removed or altered from any source distribution
18 */
19 
20 ///A module containing the TcpListener class.
21 module dsfml.network.tcplistener;
22 
23 
24 import dsfml.network.socket;
25 import dsfml.network.tcpsocket;
26 
27 import dsfml.system.err;
28 
29 /**
30  *Socket that listens to new TCP connections.
31  *
32  *A listener socket is a special type of socket that listens to a given port and waits for connections on that port.
33  *
34  *This is all it can do.
35  *
36  *When a new connection is received, you must call accept and the listener returns a new instance of sf::TcpSocket that is properly initialized and can be used to communicate with the new client.
37  *
38  *Listener sockets are specific to the TCP protocol, UDP sockets are connectionless and can therefore communicate directly. As a consequence, a listener socket will always return the new connections as sf::TcpSocket instances.
39  *
40  *A listener is automatically closed on destruction, like all other types of socket. However if you want to stop listening before the socket is destroyed, you can call its close() function.
41  */
42 class TcpListener:Socket
43 {
44 	package sfTcpListener* sfPtr;
45 
46 	///Default constructor
47 	this()
48 	{
49 		sfPtr = sfTcpListener_create();
50 	}
51 	
52 	///Destructor
53 	~this()
54 	{
55 		import dsfml.system.config;
56 		mixin(destructorOutput);
57 		sfTcpListener_destroy(sfPtr);
58 	}
59 
60 	///Get the port to which the socket is bound locally.
61 	///
62 	///If the socket is not listening to a port, this function returns 0.
63 	///
64 	///Returns: Port to which the socket is bound.
65 	ushort getLocalPort()
66 	{
67 		return sfTcpListener_getLocalPort(sfPtr);
68 	}
69 
70 	///Tell whether the socket is in blocking or non-blocking mode. 
71 	///
72 	///In blocking mode, calls will not return until they have completed their task. For example, a call to Receive in blocking mode won't return until some data was actually received. In non-blocking mode, calls will always return immediately, using the return code to signal whether there was data available or not. By default, all sockets are blocking.
73 	///
74 	///Params:
75     ///		blocking = True to set the socket as blocking, false for non-blocking.
76 	void setBlocking(bool blocking)
77 	{
78 		sfTcpListener_setBlocking(sfPtr, blocking);
79 	}
80 
81 	///Accept a new connection.
82 	//
83 	///If the socket is in blocking mode, this function will not return until a connection is actually received.
84 	///
85 	///Params:
86     ///		socket = Socket that will hold the new connection.
87     ///
88     ///Returns: Status code.
89 	Status accept(TcpSocket socket)
90 	{
91 		import dsfml.system..string;
92 
93 		Status toReturn = sfTcpListener_accept(sfPtr, socket.sfPtr); 
94 		err.write(dsfml.system..string.toString(sfErr_getOutput()));
95 		return toReturn; 
96 	}
97 
98 	///Start listening for connections.
99 	///
100 	///This functions makes the socket listen to the specified port, waiting for new connections. If the socket was previously listening to another port, it will be stopped first and bound to the new port.
101 	///
102 	///Params:
103     ///		port = Port to listen for new connections.
104     ///
105 	///Returns: Status code.
106 	Status listen(ushort port)
107 	{
108 		import dsfml.system..string;
109 
110 		Status toReturn = sfTcpListener_listen(sfPtr, port);
111 		err.write(dsfml.system..string.toString(sfErr_getOutput()));
112 		return toReturn;
113 	}
114 
115 	///Set the blocking state of the socket.
116 	///
117 	///In blocking mode, calls will not return until they have completed their task. For example, a call to Receive in blocking mode won't return until some data was actually received. In non-blocking mode, calls will always return immediately, using the return code to signal whether there was data available or not. By default, all sockets are blocking.
118 	///
119 	///Returns: True if the socket is blocking, false otherwise.
120 	bool isBlocking()
121 	{
122 		return (sfTcpListener_isBlocking(sfPtr));
123 	}
124 
125 }
126 
127 unittest
128 {
129 	version(DSFML_Unittest_Network)
130 	{
131 		import std.stdio;
132 		import dsfml.network.ipaddress;
133 
134 		writeln("Unittest for Listener");
135 		//socket connecting to server
136 		auto clientSocket = new TcpSocket();
137 		
138 		//listener looking for new sockets
139 		auto listener = new TcpListener();
140 		listener.listen(55002);
141 
142 		writeln("The listener is listening to port ", listener.getLocalPort());
143 
144 		//get our client socket to connect to the server
145 		clientSocket.connect(IpAddress.LocalHost, 55002);
146 
147 
148 		//socket on the server side connected to the client's socket
149 		auto serverSocket = new TcpSocket();
150 		
151 		//accepts a new connection and binds it to the socket in the parameter
152 		listener.accept(serverSocket);
153 
154 		
155 		clientSocket.disconnect();
156 		writeln();
157 	}
158 }
159 
160 package extern(C):
161 
162 struct sfTcpListener;
163 
164 sfTcpListener* sfTcpListener_create();
165 
166 
167 //Destroy a TCP listener
168 void sfTcpListener_destroy(sfTcpListener* listener);
169 
170 
171 //Set the blocking state of a TCP listener
172 void sfTcpListener_setBlocking(sfTcpListener* listener, bool blocking);
173 
174 
175 //Tell whether a TCP listener is in blocking or non-blocking mode
176 bool sfTcpListener_isBlocking(const sfTcpListener* listener);
177 
178 
179 //Get the port to which a TCP listener is bound locally
180 ushort sfTcpListener_getLocalPort(const(sfTcpListener)* listener);
181 
182 
183 //Start listening for connections
184 Socket.Status sfTcpListener_listen(sfTcpListener* listener, ushort port);
185 
186 
187 //Accept a new connection
188 Socket.Status sfTcpListener_accept(sfTcpListener* listener, sfTcpSocket* connected);
189 
190 const(char)* sfErr_getOutput();