KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > filesys > smb > server > SMBServer


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.smb.server;
18
19 import java.io.FileNotFoundException JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.net.InetAddress JavaDoc;
22 import java.net.NetworkInterface JavaDoc;
23 import java.util.Enumeration JavaDoc;
24 import java.util.Vector JavaDoc;
25
26 import org.alfresco.filesys.netbios.NetworkSettings;
27 import org.alfresco.filesys.server.ServerListener;
28 import org.alfresco.filesys.server.SrvSessionList;
29 import org.alfresco.filesys.server.auth.SrvAuthenticator;
30 import org.alfresco.filesys.server.auth.UserAccountList;
31 import org.alfresco.filesys.server.config.ServerConfiguration;
32 import org.alfresco.filesys.server.core.InvalidDeviceInterfaceException;
33 import org.alfresco.filesys.server.core.ShareType;
34 import org.alfresco.filesys.server.core.SharedDevice;
35 import org.alfresco.filesys.server.filesys.DiskInterface;
36 import org.alfresco.filesys.server.filesys.NetworkFileServer;
37 import org.alfresco.filesys.smb.DialectSelector;
38 import org.alfresco.filesys.smb.SMBException;
39 import org.alfresco.filesys.smb.ServerType;
40 import org.alfresco.filesys.smb.mailslot.HostAnnouncer;
41 import org.alfresco.filesys.smb.server.win32.Win32NetBIOSLanaMonitor;
42 import org.alfresco.filesys.smb.server.win32.Win32NetBIOSSessionSocketHandler;
43 import org.apache.commons.logging.Log;
44 import org.apache.commons.logging.LogFactory;
45
46 /**
47  * <p>
48  * Creates an SMB server with the specified host name.
49  * <p>
50  * The server can optionally announce itself so that it will appear under the Network Neighborhood,
51  * by enabling the host announcer in the server configuration or using the enableAnnouncer() method.
52  */

53 public class SMBServer extends NetworkFileServer implements Runnable JavaDoc
54 {
55
56     // Debug logging
57

58     private static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol");
59
60     // Server version
61

62     private static final String JavaDoc ServerVersion = "3.5.1";
63
64     // Server thread
65

66     private Thread JavaDoc m_srvThread;
67
68     // Session socket handlers (NetBIOS over TCP/IP, native SMB and/or Win32 NetBIOS)
69

70     private Vector JavaDoc<SessionSocketHandler> m_sessionHandlers;
71
72     // Host announcers, server will appear under Network Neighborhood
73

74     private Vector JavaDoc<HostAnnouncer> m_hostAnnouncers;
75
76     // Active session list
77

78     private SrvSessionList m_sessions;
79
80     // Server type flags, used when announcing the host
81

82     private int m_srvType = ServerType.WorkStation + ServerType.Server;
83
84     // Next available session id
85

86     private int m_sessId;
87
88     // Server shutdown flag and server active flag
89

90     private boolean m_shutdown = false;
91     private boolean m_active = false;
92
93     /**
94      * Create an SMB server using the specified configuration.
95      *
96      * @param serviceRegistry repository connection
97      * @param cfg ServerConfiguration
98      */

99     public SMBServer(ServerConfiguration cfg) throws IOException JavaDoc
100     {
101         super("SMB", cfg);
102
103         // Call the common constructor
104
CommonConstructor();
105     }
106
107     /**
108      * Add a shared device to the server.
109      *
110      * @param shr Shared device to be added to the server.
111      * @return True if the share was added successfully, else false.
112      */

113     public final synchronized boolean addShare(SharedDevice shr)
114     {
115
116         // For disk devices check if the shared device is read-only, this should also check if the
117
// shared device
118
// path actully exists.
119

120         if (shr.getType() == ShareType.DISK)
121         {
122
123             // Check if the disk device is read-only
124

125             checkReadOnly(shr);
126         }
127
128         // Add the share to the shared device list
129

130         boolean sts = getConfiguration().getShares().addShare(shr);
131
132         // Debug
133

134         if (logger.isInfoEnabled())
135             logger.info("[SMB] Add Share " + shr.toString() + " : " + sts);
136
137         // Return the add share status
138

139         return sts;
140     }
141
142     /**
143      * Add a session handler
144      *
145      * @param sessHandler SessionSocketHandler
146      */

147     public final void addSessionHandler(SessionSocketHandler handler)
148     {
149
150         // Check if the session handler list has been allocated
151

152         if (m_sessionHandlers == null)
153             m_sessionHandlers = new Vector JavaDoc<SessionSocketHandler>();
154
155         // Add the session handler
156

157         m_sessionHandlers.addElement(handler);
158     }
159
160     /**
161      * Add a host announcer
162      *
163      * @param announcer HostAnnouncer
164      */

165     public final void addHostAnnouncer(HostAnnouncer announcer)
166     {
167
168         // Check if the host announcer list has been allocated
169

170         if (m_hostAnnouncers == null)
171             m_hostAnnouncers = new Vector JavaDoc<HostAnnouncer>();
172
173         // Add the host announcer
174

175         m_hostAnnouncers.addElement(announcer);
176     }
177
178     /**
179      * Add a new session to the server
180      *
181      * @param sess SMBSrvSession
182      */

183     public final void addSession(SMBSrvSession sess)
184     {
185
186         // Add the session to the session list
187

188         m_sessions.addSession(sess);
189
190         // Propagate the debug settings to the new session
191

192         sess.setDebug(getConfiguration().getSessionDebugFlags());
193     }
194
195     /**
196      * Check if the disk share is read-only.
197      *
198      * @param shr SharedDevice
199      */

200     protected final void checkReadOnly(SharedDevice shr)
201     {
202
203         // For disk devices check if the shared device is read-only, this should also check if the
204
// shared device
205
// path actully exists.
206

207         if (shr.getType() == ShareType.DISK)
208         {
209
210             // Check if the disk device is read-only
211

212             try
213             {
214
215                 // Get the device interface for the shared device
216

217                 DiskInterface disk = (DiskInterface) shr.getInterface();
218                 if (disk.isReadOnly(null, shr.getContext()))
219                 {
220
221                     // The disk is read-only, mark the share as read-only
222

223                     int attr = shr.getAttributes();
224                     if ((attr & SharedDevice.ReadOnly) == 0)
225                         attr += SharedDevice.ReadOnly;
226                     shr.setAttributes(attr);
227
228                     // Debug
229

230                     if (logger.isInfoEnabled())
231                         logger.info("[SMB] Add Share " + shr.toString() + " : isReadOnly");
232                 }
233             }
234             catch (InvalidDeviceInterfaceException ex)
235             {
236
237                 // Shared device interface error
238

239                 if (logger.isInfoEnabled())
240                     logger.info("[SMB] Add Share " + shr.toString() + " : " + ex.toString());
241                 return;
242             }
243             catch (FileNotFoundException JavaDoc ex)
244             {
245
246                 // Shared disk device local path does not exist
247

248                 if (logger.isInfoEnabled())
249                     logger.info("[SMB] Add Share " + shr.toString() + " : " + ex.toString());
250                 return;
251             }
252             catch (IOException JavaDoc ex)
253             {
254
255                 // Shared disk device access error
256

257                 if (logger.isInfoEnabled())
258                     logger.info("[SMB] Add Share " + shr.toString() + " : " + ex.toString());
259                 return;
260             }
261         }
262     }
263
264     /**
265      * Common constructor code.
266      */

267     private void CommonConstructor() throws IOException JavaDoc
268     {
269
270         // Set the server version
271

272         setVersion(ServerVersion);
273
274         // Create the session socket handler list
275

276         m_sessionHandlers = new Vector JavaDoc<SessionSocketHandler>();
277
278         // Create the active session list
279

280         m_sessions = new SrvSessionList();
281
282         // Set the global domain name
283

284         NetworkSettings.setDomain(getConfiguration().getDomainName());
285         NetworkSettings.setBroadcastMask(getConfiguration().getBroadcastMask());
286     }
287
288     /**
289      * Close the host announcer, if enabled
290      */

291     protected void closeHostAnnouncers()
292     {
293
294         // Check if there are active host announcers
295

296         if (m_hostAnnouncers != null)
297         {
298
299             // Shutdown the host announcers
300

301             for (int i = 0; i < m_hostAnnouncers.size(); i++)
302             {
303
304                 // Get the current host announcer from the active list
305

306                 HostAnnouncer announcer = (HostAnnouncer) m_hostAnnouncers.elementAt(i);
307
308                 // Shutdown the host announcer
309

310                 announcer.shutdownAnnouncer();
311             }
312         }
313     }
314
315     /**
316      * Close the session handlers
317      */

318     protected void closeSessionHandlers()
319     {
320
321         // Close the session handlers
322

323         for (SessionSocketHandler handler : m_sessionHandlers)
324         {
325
326             // Request the handler to shutdown
327

328             handler.shutdownRequest();
329         }
330
331         // Clear the session handler list
332

333         m_sessionHandlers.removeAllElements();
334     }
335
336     /**
337      * Delete the specified shared device from the server.
338      *
339      * @param name String Name of the shared resource to remove from the server.
340      * @return SharedDevice that has been removed from the server, else null.
341      */

342     public final synchronized SharedDevice deleteShare(String JavaDoc name)
343     {
344         return getConfiguration().getShares().deleteShare(name);
345     }
346
347     /**
348      * Delete temporary shares created by the share mapper for the specified session
349      *
350      * @param sess SMBSrvSession
351      */

352     public final void deleteTemporaryShares(SMBSrvSession sess)
353     {
354
355         // Delete temporary shares via the share mapper
356

357         getConfiguration().getShareMapper().deleteShares(sess);
358     }
359
360     /**
361      * Return an enumeration to allow the shared devices to be listed.
362      *
363      * @return java.util.Enumeration
364      */

365     public final Enumeration JavaDoc enumerateShares()
366     {
367         return getConfiguration().getShares().enumerateShares();
368     }
369
370     /**
371      * Return the server comment.
372      *
373      * @return java.lang.String
374      */

375     public final String JavaDoc getComment()
376     {
377         return getConfiguration().getComment();
378     }
379
380     /**
381      * Return the server type flags.
382      *
383      * @return int
384      */

385     public final int getServerType()
386     {
387         return m_srvType;
388     }
389
390     /**
391      * Return the per session debug flag settings.
392      */

393     public final int getSessionDebug()
394     {
395         return getConfiguration().getSessionDebugFlags();
396     }
397
398     /**
399      * Return the list of SMB dialects that this server supports.
400      *
401      * @return DialectSelector
402      */

403     public final DialectSelector getSMBDialects()
404     {
405         return getConfiguration().getEnabledDialects();
406     }
407
408     /**
409      * Return the list of user accounts.
410      *
411      * @return UserAccountList
412      */

413     public final UserAccountList getUserAccountList()
414     {
415         return getConfiguration().getUserAccounts();
416     }
417
418     /**
419      * Return the active session list
420      *
421      * @return SrvSessionList
422      */

423     public final SrvSessionList getSessions()
424     {
425         return m_sessions;
426     }
427
428     /**
429      * Start the SMB server.
430      */

431     public void run()
432     {
433
434         // Indicate that the server is active
435

436         setActive(true);
437
438         // Check if we are running under Windows
439

440         boolean isWindows = isWindowsNTOnwards();
441
442         // Debug
443

444         if (logger.isInfoEnabled())
445         {
446
447             // Dump the server name/version and Java runtime details
448

449             logger.info("[SMB] SMB Server " + getServerName() + " starting");
450             logger.info("[SMB] Version " + isVersion());
451             logger.info("[SMB] Java VM " + System.getProperty("java.vm.version"));
452             logger.info("[SMB] OS " + System.getProperty("os.name") + ", version " + System.getProperty("os.version"));
453
454             // Output the authenticator details
455

456             if (getAuthenticator() != null)
457             {
458                 String JavaDoc mode = getAuthenticator().getAccessMode() == SrvAuthenticator.SHARE_MODE ? "SHARE" : "USER";
459                 logger.info("[SMB] Using authenticator " + getAuthenticator().getClass().getName() + ", mode=" + mode);
460
461                 // Display the count of user accounts
462

463                 if (getUserAccountList() != null)
464                     logger.info("[SMB] " + getUserAccountList().numberOfUsers() + " user accounts defined");
465                 else
466                     logger.info("[SMB] No user accounts defined");
467             }
468
469             // Display the timezone offset/name
470

471             if (getConfiguration().getTimeZone() != null)
472                 logger.info("[SMB] Server timezone " + getConfiguration().getTimeZone() + ", offset from UTC = "
473                         + getConfiguration().getTimeZoneOffset() / 60 + "hrs");
474             else
475                 logger.info("[SMB] Server timezone offset = " + getConfiguration().getTimeZoneOffset() / 60 + "hrs");
476
477             // Dump the share list
478

479             logger.info("[SMB] Shares:");
480             Enumeration JavaDoc<SharedDevice> enm = getFullShareList(getServerName(), null).enumerateShares();
481
482             while (enm.hasMoreElements())
483             {
484                 SharedDevice share = enm.nextElement();
485                 logger.info("[SMB] " + share.toString() + " " + share.getContext().toString());
486             }
487         }
488
489         // Create a server socket to listen for incoming session requests
490

491         try
492         {
493
494             // Add the IPC$ named pipe shared device
495

496             AdminSharedDevice admShare = new AdminSharedDevice();
497             addShare(admShare);
498
499             // Clear the server shutdown flag
500

501             m_shutdown = false;
502
503             // Get the list of IP addresses the server is bound to
504

505             getServerIPAddresses();
506
507             // Check if the socket connection debug flag is enabled
508

509             boolean sockDbg = false;
510
511             if ((getSessionDebug() & SMBSrvSession.DBG_SOCKET) != 0)
512                 sockDbg = true;
513
514             // Create the NetBIOS session socket handler, if enabled
515

516             if (getConfiguration().hasNetBIOSSMB())
517             {
518
519                 // Create the TCP/IP NetBIOS SMB/CIFS session handler(s), and host announcer(s) if
520
// enabled
521

522                 NetBIOSSessionSocketHandler.createSessionHandlers(this, sockDbg);
523             }
524
525             // Create the TCP/IP SMB session socket handler, if enabled
526

527             if (getConfiguration().hasTcpipSMB())
528             {
529
530                 // Create the TCP/IP native SMB session handler(s)
531

532                 TcpipSMBSessionSocketHandler.createSessionHandlers(this, sockDbg);
533             }
534
535             // Create the Win32 NetBIOS session handler, if enabled
536

537             if (getConfiguration().hasWin32NetBIOS())
538             {
539
540                 // Only enable if running under Windows
541

542                 if (isWindows == true)
543                 {
544
545                     // Create the Win32 NetBIOS SMB handler(s), and host announcer(s) if enabled
546

547                     Win32NetBIOSSessionSocketHandler.createSessionHandlers(this, sockDbg);
548                 }
549             }
550
551             // Check if there are any session handlers installed, if not then close the server
552

553             if (m_sessionHandlers.size() > 0 || getConfiguration().hasWin32NetBIOS())
554             {
555
556                 // Wait for incoming connection requests
557

558                 while (m_shutdown == false)
559                 {
560
561                     // Sleep for a while
562

563                     try
564                     {
565                         Thread.sleep(1000L);
566                     }
567                     catch (InterruptedException JavaDoc ex)
568                     {
569                     }
570                 }
571             }
572             else if (logger.isInfoEnabled())
573             {
574
575                 // DEBUG
576

577                 logger.info("[SMB] No valid session handlers, server closing");
578             }
579         }
580         catch (SMBException ex)
581         {
582
583             // Output the exception
584

585             logger.error("SMB server error", ex);
586
587             // Store the error, fire a server error event
588

589             setException(ex);
590             fireServerEvent(ServerListener.ServerError);
591         }
592         catch (Exception JavaDoc ex)
593         {
594
595             // Do not report an error if the server has shutdown, closing the server socket
596
// causes an exception to be thrown.
597

598             if (m_shutdown == false)
599             {
600                 logger.error("[SMB] Server error : ", ex);
601
602                 // Store the error, fire a server error event
603

604                 setException(ex);
605                 fireServerEvent(ServerListener.ServerError);
606             }
607         }
608
609         // Debug
610

611         if (logger.isInfoEnabled())
612             logger.info("[SMB] SMB Server shutting down ...");
613
614         // Close the host announcer and session handlers
615

616         closeHostAnnouncers();
617         closeSessionHandlers();
618
619         // Shutdown the Win32 NetBIOS LANA monitor, if enabled
620

621         if (isWindows && Win32NetBIOSLanaMonitor.getLanaMonitor() != null)
622             Win32NetBIOSLanaMonitor.getLanaMonitor().shutdownRequest();
623
624         // Indicate that the server is not active
625

626         setActive(false);
627         fireServerEvent(ServerListener.ServerShutdown);
628     }
629
630     /**
631      * Notify the server that a session has been closed.
632      *
633      * @param sess SMBSrvSession
634      */

635     protected final void sessionClosed(SMBSrvSession sess)
636     {
637
638         // Remove the session from the active session list
639

640         m_sessions.removeSession(sess);
641
642         // Notify session listeners that a session has been closed
643

644         fireSessionClosedEvent(sess);
645     }
646
647     /**
648      * Notify the server that a user has logged on.
649      *
650      * @param sess SMBSrvSession
651      */

652     protected final void sessionLoggedOn(SMBSrvSession sess)
653     {
654
655         // Notify session listeners that a user has logged on.
656

657         fireSessionLoggedOnEvent(sess);
658     }
659
660     /**
661      * Notify the server that a session has been closed.
662      *
663      * @param sess SMBSrvSession
664      */

665     protected final void sessionOpened(SMBSrvSession sess)
666     {
667
668         // Notify session listeners that a session has been closed
669

670         fireSessionOpenEvent(sess);
671     }
672
673     /**
674      * Shutdown the SMB server
675      *
676      * @param immediate boolean
677      */

678     public final void shutdownServer(boolean immediate)
679     {
680
681         // Indicate that the server is closing
682

683         m_shutdown = true;
684
685         try
686         {
687
688             // Close the session handlers
689

690             closeSessionHandlers();
691         }
692         catch (Exception JavaDoc ex)
693         {
694         }
695
696         // Close the active sessions
697

698         Enumeration JavaDoc<Integer JavaDoc> enm = m_sessions.enumerate();
699
700         while (enm.hasMoreElements())
701         {
702
703             // Get the session id and associated session
704

705             Integer JavaDoc sessId = enm.nextElement();
706             SMBSrvSession sess = (SMBSrvSession) m_sessions.findSession(sessId);
707
708             // Inform listeners that the session has been closed
709

710             fireSessionClosedEvent(sess);
711
712             // Close the session
713

714             sess.closeSession();
715         }
716
717         // Wait for the main server thread to close
718

719         if (m_srvThread != null)
720         {
721
722             try
723             {
724                 m_srvThread.join(3000);
725             }
726             catch (Exception JavaDoc ex)
727             {
728             }
729         }
730
731         // Fire a shutdown notification event
732

733         fireServerEvent(ServerListener.ServerShutdown);
734     }
735
736     /**
737      * Start the SMB server in a seperate thread
738      */

739     public void startServer()
740     {
741
742         // Create a seperate thread to run the SMB server
743

744         m_srvThread = new Thread JavaDoc(this);
745         m_srvThread.setName("SMB Server");
746         m_srvThread.setDaemon(true);
747
748         m_srvThread.start();
749
750         // Fire a server startup event
751

752         fireServerEvent(ServerListener.ServerStartup);
753     }
754
755     /**
756      * Determine if we are running under Windows NT onwards
757      *
758      * @return boolean
759      */

760     private final boolean isWindowsNTOnwards()
761     {
762
763         // Get the operating system name property
764

765         String JavaDoc osName = System.getProperty("os.name");
766
767         if (osName.startsWith("Windows"))
768         {
769             if (osName.endsWith("95") || osName.endsWith("98") || osName.endsWith("ME"))
770             {
771
772                 // Windows 95-ME
773

774                 return false;
775             }
776
777             // Looks like Windows NT onwards
778

779             return true;
780         }
781
782         // Not Windows
783

784         return false;
785     }
786
787     /**
788      * Get the list of local IP addresses
789      */

790     private final void getServerIPAddresses()
791     {
792
793         try
794         {
795
796             // Get the local IP address list
797

798             Enumeration JavaDoc<NetworkInterface JavaDoc> enm = NetworkInterface.getNetworkInterfaces();
799             Vector JavaDoc<InetAddress JavaDoc> addrList = new Vector JavaDoc<InetAddress JavaDoc>();
800
801             while (enm.hasMoreElements())
802             {
803
804                 // Get the current network interface
805

806                 NetworkInterface JavaDoc ni = enm.nextElement();
807
808                 // Get the address list for the current interface
809

810                 Enumeration JavaDoc<InetAddress JavaDoc> addrs = ni.getInetAddresses();
811
812                 while (addrs.hasMoreElements())
813                     addrList.add(addrs.nextElement());
814             }
815
816             // Convert the vector of addresses to an array
817

818             if (addrList.size() > 0)
819             {
820
821                 // Convert the address vector to an array
822

823                 InetAddress JavaDoc[] inetAddrs = new InetAddress JavaDoc[addrList.size()];
824
825                 // Copy the address details to the array
826

827                 for (int i = 0; i < addrList.size(); i++)
828                     inetAddrs[i] = (InetAddress JavaDoc) addrList.elementAt(i);
829
830                 // Set the server IP address list
831

832                 setServerAddresses(inetAddrs);
833             }
834         }
835         catch (Exception JavaDoc ex)
836         {
837
838             // DEBUG
839

840             logger.error("[SMB] Error getting local IP addresses", ex);
841         }
842     }
843 }
Popular Tags