View Javadoc

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              // bind the listener to the host & port
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                  // waiting for connexions
85                  socket = serverSocket.accept();
86                  socket.setSoTimeout(10000);
87                  socket.setTcpNoDelay(true);
88                  socket.setTrafficClass(0x10); // low delay
89                  
90                  InetAddress address = socket.getInetAddress();
91  
92                  // log the connection
93                  log.info("Incoming " + getName() + " client " + address.getHostAddress() + ":" + socket.getPort());
94  
95                  // test the ban list
96                  if (Banlist.getInstance().isBanned(address))
97                  {
98                      socket.close();
99                      log.info("Banned host, client rejected (" + address + ")");
100                     continue;
101                 }
102 
103                 // spawn the client verifier processing the interceptors
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                     // todo move the declaration of the interceptors in the server configuration
204                     Collection<ClientInterceptor> validators = new ArrayList<ClientInterceptor>();
205                     validators.add(new AccessInterceptor());
206                     validators.add(new NameCheckInterceptor());
207                     validators.add(new SpeedCheckInterceptor());
208                     
209                     // run the validators
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                         // add the client to the repository
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                         // run the interceptors
230                         for (ClientInterceptor interceptor : interceptors)
231                         {
232                             interceptor.process(client);
233                         }
234 
235                         // forward the client to the server for channel assignation
236                         if (client.supportsAutoJoin())
237                         {
238                             AddPlayerMessage m = new AddPlayerMessage();
239                             m.setClient(client);
240                             Server.getInstance().send(m);
241                         }
242                     }
243 
244                     // start the client
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 }