KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > filesys > ftp > FTPNetworkServer


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.filesys.ftp;
18
19 import java.io.IOException JavaDoc;
20 import java.net.InetAddress JavaDoc;
21 import java.net.ServerSocket JavaDoc;
22 import java.net.Socket JavaDoc;
23 import java.net.SocketException JavaDoc;
24 import java.util.Enumeration JavaDoc;
25
26 import org.alfresco.filesys.server.ServerListener;
27 import org.alfresco.filesys.server.SrvSession;
28 import org.alfresco.filesys.server.config.ServerConfiguration;
29 import org.alfresco.filesys.server.core.SharedDeviceList;
30 import org.alfresco.filesys.server.filesys.NetworkFileServer;
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33
34 /**
35  * <p>
36  * Create an FTP server on the specified port. The default server port is 21.
37  *
38  * @author GKSpencer
39  */

40 public class FTPNetworkServer extends NetworkFileServer implements Runnable JavaDoc
41 {
42
43     // Debug logging
44

45     private static final Log logger = LogFactory.getLog("org.alfresco.ftp.protocol");
46
47     // Constants
48
//
49
// Server version
50

51     private static final String JavaDoc ServerVersion = "3.5.0";
52
53     // Listen backlog for the server socket
54

55     protected static final int LISTEN_BACKLOG = 10;
56
57     // Default FTP server port
58

59     protected static final int SERVER_PORT = 21;
60
61     // Server socket
62

63     private ServerSocket JavaDoc m_srvSock;
64
65     // Active session list
66

67     private FTPSessionList m_sessions;
68
69     // List of available shares
70

71     private SharedDeviceList m_shares;
72
73     // Next available session id
74

75     private int m_sessId;
76
77     // Root path for new sessions
78

79     private FTPPath m_rootPath;
80
81     // FTP server thread
82

83     private Thread JavaDoc m_srvThread;
84
85     // Local server address string, in FTP format (ie. n,n,n,n)
86

87     private String JavaDoc m_localFTPaddress;
88
89     /**
90      * Class constructor
91      *
92      * @param serviceResgistry ServiceRegistry
93      * @param config ServerConfiguration
94      */

95     public FTPNetworkServer(ServerConfiguration config)
96     {
97         super("FTP", config);
98
99         // Set the server version
100

101         setVersion(ServerVersion);
102
103         // Allocate the session lists
104

105         m_sessions = new FTPSessionList();
106
107         // Enable debug
108

109         if (getConfiguration().getFTPDebug() != 0)
110             setDebug(true);
111
112         // Create the root path, if configured
113

114         if (getConfiguration().hasFTPRootPath())
115         {
116
117             try
118             {
119
120                 // Create the root path
121

122                 m_rootPath = new FTPPath(getConfiguration().getFTPRootPath());
123             }
124             catch (InvalidPathException ex)
125             {
126                 logger.error(ex);
127             }
128         }
129     }
130
131     /**
132      * Add a new session to the server
133      *
134      * @param sess FTPSrvSession
135      */

136     protected final void addSession(FTPSrvSession sess)
137     {
138
139         // Add the session to the session list
140

141         m_sessions.addSession(sess);
142
143         // Propagate the debug settings to the new session
144

145         if (hasDebug())
146         {
147
148             // Enable session debugging, output to the same stream as the server
149

150             sess.setDebug(getConfiguration().getFTPDebug());
151         }
152     }
153
154     /**
155      * emove a session from the server
156      *
157      * @param sess FTPSrvSession
158      */

159     protected final void removeSession(FTPSrvSession sess)
160     {
161
162         // Remove the session from the active session list
163

164         if (m_sessions.removeSession(sess) != null)
165         {
166
167             // Inform listeners that a session has closed
168

169             fireSessionClosedEvent(sess);
170         }
171     }
172
173     /**
174      * Allocate a local port for a data session
175      *
176      * @param sess FTPSrvSession
177      * @param remAddr InetAddress
178      * @param remPort int
179      * @return FTPDataSession
180      * @exception IOException
181      */

182     protected final FTPDataSession allocateDataSession(FTPSrvSession sess, InetAddress JavaDoc remAddr, int remPort)
183             throws IOException JavaDoc
184     {
185         // Create a new FTP data session
186

187         FTPDataSession dataSess = null;
188         if (remAddr != null)
189         {
190
191             // Create a normal data session
192

193             dataSess = new FTPDataSession(sess, remAddr, remPort);
194         }
195         else
196         {
197
198             // Create a passive data session
199

200             dataSess = new FTPDataSession(sess, getBindAddress());
201         }
202
203         // Return the data session
204

205         return dataSess;
206     }
207
208     /**
209      * Release a data session
210      *
211      * @param dataSess FTPDataSession
212      */

213     protected final void releaseDataSession(FTPDataSession dataSess)
214     {
215
216         // Close the data session
217

218         dataSess.closeSession();
219     }
220
221     /**
222      * Get the shared device list
223      *
224      * @return SharedDeviceList
225      */

226     public final SharedDeviceList getShareList()
227     {
228
229         // Check if the share list has been populated
230

231         if (m_shares == null)
232             m_shares = getConfiguration().getShareMapper()
233                     .getShareList(getConfiguration().getServerName(), null, false);
234
235         // Return the share list
236

237         return m_shares;
238     }
239
240     /**
241      * Check if the FTP server is to be bound to a specific network adapter
242      *
243      * @return boolean
244      */

245     public final boolean hasBindAddress()
246     {
247         return getConfiguration().getFTPBindAddress() != null ? true : false;
248     }
249
250     /**
251      * Return the address that the FTP server should bind to
252      *
253      * @return InetAddress
254      */

255     public final InetAddress JavaDoc getBindAddress()
256     {
257         return getConfiguration().getFTPBindAddress();
258     }
259
260     /**
261      * Check if the root path is set
262      *
263      * @return boolean
264      */

265     public final boolean hasRootPath()
266     {
267         return m_rootPath != null ? true : false;
268     }
269
270     /**
271      * Check if anonymous logins are allowed
272      *
273      * @return boolean
274      */

275     public final boolean allowAnonymous()
276     {
277         return getConfiguration().allowAnonymousFTP();
278     }
279
280     /**
281      * Return the anonymous login user name
282      *
283      * @return String
284      */

285     public final String JavaDoc getAnonymousAccount()
286     {
287         return getConfiguration().getAnonymousFTPAccount();
288     }
289
290     /**
291      * Return the local FTP server address string in n,n,n,n format
292      *
293      * @return String
294      */

295     public final String JavaDoc getLocalFTPAddressString()
296     {
297         return m_localFTPaddress;
298     }
299
300     /**
301      * Return the next available session id
302      *
303      * @return int
304      */

305     protected final synchronized int getNextSessionId()
306     {
307         return m_sessId++;
308     }
309
310     /**
311      * Return the FTP server port
312      *
313      * @return int
314      */

315     public final int getPort()
316     {
317         return getConfiguration().getFTPPort();
318     }
319
320     /**
321      * Return the server socket
322      *
323      * @return ServerSocket
324      */

325     protected final ServerSocket JavaDoc getSocket()
326     {
327         return m_srvSock;
328     }
329
330     /**
331      * Return the root path for new sessions
332      *
333      * @return FTPPath
334      */

335     public final FTPPath getRootPath()
336     {
337         return m_rootPath;
338     }
339
340     /**
341      * Notify the server that a user has logged on.
342      *
343      * @param sess SrvSession
344      */

345     protected final void sessionLoggedOn(SrvSession sess)
346     {
347
348         // Notify session listeners that a user has logged on.
349

350         fireSessionLoggedOnEvent(sess);
351     }
352
353     /**
354      * Start the SMB server.
355      */

356     public void run()
357     {
358
359         // Debug
360

361         if (logger.isDebugEnabled() && hasDebug())
362         {
363             logger.debug("FTP Server starting on port " + getPort());
364             logger.debug("Version " + isVersion());
365         }
366
367         // Create a server socket to listen for incoming FTP session requests
368

369         try
370         {
371
372             // Create the server socket to listen for incoming FTP session requests
373

374             if (hasBindAddress())
375                 m_srvSock = new ServerSocket JavaDoc(getPort(), LISTEN_BACKLOG, getBindAddress());
376             else
377                 m_srvSock = new ServerSocket JavaDoc(getPort(), LISTEN_BACKLOG);
378
379             // DEBUG
380

381             if (logger.isDebugEnabled() && hasDebug())
382             {
383                 String JavaDoc ftpAddr = "ALL";
384                 
385                 if (hasBindAddress())
386                     ftpAddr = getBindAddress().getHostAddress();
387                 logger.debug("FTP Binding to local address " + ftpAddr);
388             }
389
390             // If a bind address is set then we can set the FTP local address
391

392             if (hasBindAddress())
393                 m_localFTPaddress = getBindAddress().getHostAddress().replace('.', ',');
394
395             // Indicate that the server is active
396

397             setActive(true);
398             fireServerEvent(ServerListener.ServerActive);
399
400             // Wait for incoming connection requests
401

402             while (hasShutdown() == false)
403             {
404
405                 // Wait for a connection
406

407                 Socket JavaDoc sessSock = getSocket().accept();
408
409                 // Set the local address string in FTP format (n,n,n,n), if not already set
410

411                 if (m_localFTPaddress == null)
412                 {
413                     if (sessSock.getLocalAddress() != null)
414                         m_localFTPaddress = sessSock.getLocalAddress().getHostAddress().replace('.', ',');
415                 }
416
417                 // Set socket options
418

419                 sessSock.setTcpNoDelay(true);
420
421                 // Debug
422

423                 if (logger.isDebugEnabled() && hasDebug())
424                     logger.debug("FTP session request received from "
425                             + sessSock.getInetAddress().getHostAddress());
426
427                 // Create a server session for the new request, and set the session id.
428

429                 FTPSrvSession srvSess = new FTPSrvSession(sessSock, this);
430                 srvSess.setSessionId(getNextSessionId());
431                 srvSess.setUniqueId("FTP" + srvSess.getSessionId());
432                 srvSess.setDebugPrefix("[FTP" + srvSess.getSessionId() + "] ");
433
434                 // Initialize the root path for the new session, if configured
435

436                 if (hasRootPath())
437                     srvSess.setRootPath(getRootPath());
438
439                 // Add the session to the active session list
440

441                 addSession(srvSess);
442
443                 // Inform listeners that a new session has been created
444

445                 fireSessionOpenEvent(srvSess);
446
447                 // Start the new session in a seperate thread
448

449                 Thread JavaDoc srvThread = new Thread JavaDoc(srvSess);
450                 srvThread.setDaemon(true);
451                 srvThread.setName("Sess_FTP" + srvSess.getSessionId() + "_"
452                         + sessSock.getInetAddress().getHostAddress());
453                 srvThread.start();
454
455                 // Sleep for a while
456

457                 try
458                 {
459                     Thread.sleep(1000L);
460                 }
461                 catch (InterruptedException JavaDoc ex)
462                 {
463                 }
464             }
465         }
466         catch (SocketException JavaDoc ex)
467         {
468
469             // Do not report an error if the server has shutdown, closing the server socket
470
// causes an exception to be thrown.
471

472             if (hasShutdown() == false)
473             {
474                 logger.error("FTP Socket error", ex);
475
476                 // Inform listeners of the error, store the exception
477

478                 setException(ex);
479                 fireServerEvent(ServerListener.ServerError);
480             }
481         }
482         catch (Exception JavaDoc ex)
483         {
484
485             // Do not report an error if the server has shutdown, closing the server socket
486
// causes an exception to be thrown.
487

488             if (hasShutdown() == false)
489             {
490                 logger.error("FTP Server error", ex);
491             }
492
493             // Inform listeners of the error, store the exception
494

495             setException(ex);
496             fireServerEvent(ServerListener.ServerError);
497         }
498
499         // Close the active sessions
500

501         Enumeration JavaDoc enm = m_sessions.enumerate();
502
503         while (enm.hasMoreElements())
504         {
505
506             // Get the session id and associated session
507

508             Integer JavaDoc sessId = (Integer JavaDoc) enm.nextElement();
509             FTPSrvSession sess = m_sessions.findSession(sessId);
510
511             // DEBUG
512

513             if (logger.isDebugEnabled() && hasDebug())
514                 logger.debug("FTP Close session, id = " + sess.getSessionId());
515
516             // Close the session
517

518             sess.closeSession();
519         }
520
521         // Debug
522

523         if (logger.isDebugEnabled() && hasDebug())
524             logger.debug("FTP Server shutting down ...");
525
526         // Indicate that the server has shutdown, inform listeners
527

528         setActive(false);
529         fireServerEvent(ServerListener.ServerShutdown);
530     }
531
532     /**
533      * Shutdown the FTP server
534      *
535      * @param immediate boolean
536      */

537     public void shutdownServer(boolean immediate)
538     {
539
540         // Set the shutdown flag
541

542         setShutdown(true);
543
544         // Close the FTP server listening socket to wakeup the main FTP server thread
545

546         try
547         {
548             if (getSocket() != null)
549                 getSocket().close();
550         }
551         catch (IOException JavaDoc ex)
552         {
553         }
554
555         // Wait for the main server thread to close
556

557         if (m_srvThread != null)
558         {
559
560             try
561             {
562                 m_srvThread.join(3000);
563             }
564             catch (Exception JavaDoc ex)
565             {
566             }
567         }
568
569         // Fire a shutdown notification event
570

571         fireServerEvent(ServerListener.ServerShutdown);
572     }
573
574     /**
575      * Start the FTP server in a seperate thread
576      */

577     public void startServer()
578     {
579
580         // Create a seperate thread to run the FTP server
581

582         m_srvThread = new Thread JavaDoc(this);
583         m_srvThread.setName("FTP Server");
584         m_srvThread.start();
585
586         // Fire a server startup event
587

588         fireServerEvent(ServerListener.ServerStartup);
589     }
590 }
591
Popular Tags