1 /***
2 * Jetrix TetriNET Server
3 * Copyright (C) 2001-2005 Emmanuel Bourg
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 package net.jetrix.listeners;
21
22 import java.io.*;
23 import java.net.*;
24 import java.util.*;
25 import java.util.logging.*;
26
27 import net.jetrix.*;
28 import net.jetrix.clients.*;
29 import net.jetrix.config.*;
30 import net.jetrix.listeners.interceptor.*;
31 import net.jetrix.messages.*;
32 import net.jetrix.services.*;
33
34 /***
35 * Abstract Listener waiting for incoming clients.
36 *
37 * @author Emmanuel Bourg
38 * @version $Revision: 867 $, $Date: 2010-08-26 14:32:10 +0200 (jeu., 26 août 2010) $
39 */
40 public abstract class ClientListener extends AbstractService implements Listener
41 {
42 private ServerSocket serverSocket;
43 private Socket socket;
44 protected int port;
45 private Logger log;
46 private boolean running;
47
48 /***
49 * Initialize a client from a socket.
50 */
51 public abstract Client getClient(Socket socket) throws Exception;
52
53 /***
54 * Main loop waiting for clients and checking basic rules (nickname
55 * unicity, ban list, room left on the server). Newly created clients
56 * are then forwarded to the main server queue for channel assignation.
57 */
58 public final void run()
59 {
60 log = Logger.getLogger("net.jetrix");
61 ServerConfig serverConfig = Server.getInstance().getConfig();
62
63 try
64 {
65
66 serverSocket = new ServerSocket(getPort(), 50, serverConfig.getHost());
67 running = true;
68 log.info("Listening at " + getName() + " port " + getPort()
69 + ((serverConfig.getHost() != null) ? ", bound to " + serverConfig.getHost() : ""));
70 }
71 catch (BindException e)
72 {
73 log.severe("Unable to bind " + getName() + " listener at port " + getPort());
74 }
75 catch (IOException e)
76 {
77 log.log(Level.SEVERE, "Cannot open ServerSocket on port " + getPort(), e);
78 }
79
80 while (serverConfig.isRunning() && running)
81 {
82 try
83 {
84
85 socket = serverSocket.accept();
86 socket.setSoTimeout(10000);
87 socket.setTcpNoDelay(true);
88 socket.setTrafficClass(0x10);
89
90 InetAddress address = socket.getInetAddress();
91
92
93 log.info("Incoming " + getName() + " client " + address.getHostAddress() + ":" + socket.getPort());
94
95
96 if (Banlist.getInstance().isBanned(address))
97 {
98 socket.close();
99 log.info("Banned host, client rejected (" + address + ")");
100 continue;
101 }
102
103
104 new ClientVerifier(socket).start();
105 }
106 catch (Exception e)
107 {
108 try
109 {
110 if (socket != null)
111 {
112 socket.close();
113 }
114 }
115 catch (IOException ioe)
116 {
117 ioe.printStackTrace();
118 }
119
120 if (Server.getInstance().getConfig().isRunning())
121 {
122 e.printStackTrace();
123 }
124 }
125 }
126 }
127
128 public int getPort()
129 {
130 return port;
131 }
132
133 public void setPort(int port)
134 {
135 this.port = port;
136 }
137
138 /***
139 * Start the listener.
140 */
141 public void start()
142 {
143 (new Thread(this, "listener: " + getName())).start();
144 }
145
146 /***
147 * Stop the listener.
148 */
149 public void stop()
150 {
151 try
152 {
153 log.info("Stopping listener " + getName());
154 running = false;
155 serverSocket.close();
156 }
157 catch (IOException e)
158 {
159 e.printStackTrace();
160 }
161 }
162
163 public boolean isRunning()
164 {
165 return running;
166 }
167
168 public String toString()
169 {
170 return "[Listener name='" + getName() + "' port=" + getPort() + "]";
171 }
172
173 /***
174 * Thread checking incoming connections and spawning a new client
175 * if everything is ok.
176 *
177 * @since 0.2
178 */
179 private class ClientVerifier extends Thread
180 {
181 private Socket socket;
182
183 public ClientVerifier(Socket socket)
184 {
185 super("client-verifier:" + socket.getInetAddress().getHostAddress());
186 this.socket = socket;
187 }
188
189 public void run()
190 {
191 ServerConfig serverConfig = Server.getInstance().getConfig();
192 InetAddress address = socket.getInetAddress();
193
194 try
195 {
196 Client client = getClient(socket);
197
198 if (client != null)
199 {
200 User user = client.getUser();
201 user.setLocale(serverConfig.getLocale());
202
203
204 Collection<ClientInterceptor> validators = new ArrayList<ClientInterceptor>();
205 validators.add(new AccessInterceptor());
206 validators.add(new NameCheckInterceptor());
207 validators.add(new SpeedCheckInterceptor());
208
209
210 for (ClientInterceptor interceptor : validators)
211 {
212 interceptor.process(client);
213 }
214
215 log.fine("Client accepted (" + address + ")");
216 socket.setSoTimeout(serverConfig.getTimeout() * 1000);
217
218 if (!(client instanceof QueryClient))
219 {
220
221 ClientRepository repository = ClientRepository.getInstance();
222 repository.addClient(client);
223
224 Collection<ClientInterceptor> interceptors = new ArrayList<ClientInterceptor>();
225 interceptors.add(new MotdInterceptor());
226 interceptors.add(new OnlineUsersInterceptor());
227 interceptors.add(new ServerStatsInterceptor());
228
229
230 for (ClientInterceptor interceptor : interceptors)
231 {
232 interceptor.process(client);
233 }
234
235
236 if (client.supportsAutoJoin())
237 {
238 AddPlayerMessage m = new AddPlayerMessage();
239 m.setClient(client);
240 Server.getInstance().send(m);
241 }
242 }
243
244
245 (new Thread(client, "client: " + client.getUser().getName())).start();
246 }
247 }
248 catch (Exception e)
249 {
250 try
251 {
252 if (socket != null)
253 {
254 socket.close();
255 }
256 }
257 catch (IOException ioe)
258 {
259 ioe.printStackTrace();
260 }
261
262 if (!(e instanceof ClientValidationException))
263 {
264 e.printStackTrace();
265 }
266 }
267
268 }
269 }
270
271 }