JLANServer.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  1. /*
  2. * Copyright (C) 2006-2010 Alfresco Software Limited.
  3. *
  4. * This file is part of Alfresco
  5. *
  6. * Alfresco is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Alfresco is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package org.alfresco.jlan.app;
  20. import java.io.File;
  21. import java.io.PrintStream;
  22. import java.lang.reflect.Constructor;
  23. import java.net.InetAddress;
  24. import java.net.UnknownHostException;
  25. import org.alfresco.jlan.debug.Debug;
  26. import org.alfresco.jlan.debug.DebugConfigSection;
  27. import org.alfresco.jlan.ftp.FTPConfigSection;
  28. import org.alfresco.jlan.netbios.server.NetBIOSNameServer;
  29. import org.alfresco.jlan.netbios.win32.Win32NetBIOS;
  30. import org.alfresco.jlan.oncrpc.nfs.NFSConfigSection;
  31. import org.alfresco.jlan.server.NetworkServer;
  32. import org.alfresco.jlan.server.ServerListener;
  33. import org.alfresco.jlan.server.config.ServerConfiguration;
  34. import org.alfresco.jlan.smb.SMBErrorText;
  35. import org.alfresco.jlan.smb.SMBStatus;
  36. import org.alfresco.jlan.smb.server.CIFSConfigSection;
  37. import org.alfresco.jlan.smb.server.SMBServer;
  38. import org.alfresco.jlan.smb.util.DriveMapping;
  39. import org.alfresco.jlan.smb.util.DriveMappingList;
  40. import org.alfresco.jlan.util.ConsoleIO;
  41. import org.alfresco.jlan.util.Platform;
  42. import org.alfresco.jlan.util.win32.Win32Utils;
  43. /**
  44. * JLAN File Server Application
  45. *
  46. * @author gkspencer
  47. */
  48. public class JLANServer implements ServerListener {
  49. // Constants
  50. //
  51. // Checkpoints
  52. public static final int CheckPointStarting = 0;
  53. public static final int CheckPointConfigLoading = 1;
  54. public static final int CheckPointConfigLoaded = 2;
  55. public static final int CheckPointCheckIPAddress = 3;
  56. public static final int CheckPointCreateSMBServer = 4;
  57. public static final int CheckPointCreateFTPServer = 5;
  58. public static final int CheckPointCreateNFSServer = 6;
  59. public static final int CheckPointServersStart = 7;
  60. public static final int CheckPointServersStarted = 8;
  61. public static final int CheckPointRunning = 9;
  62. public static final int CheckPointServersStop = 10;
  63. public static final int CheckPointServersStopped = 11;
  64. public static final int CheckPointFinished = 12;
  65. // Default configuration file name
  66. private static final String DEFAULT_CONFIGFILENAME = "jlanserver.xml";
  67. // Flag to enable/disable local IP address checking
  68. private static final boolean CheckLocalIPAddress = false;
  69. // Server shutdown flag
  70. protected static boolean m_shutdown = false;
  71. // Server restart flag
  72. protected static boolean m_restart = false;
  73. // Flag to enable user to shutdown the server via the console
  74. protected static boolean m_allowShutViaConsole = true;
  75. // Flag to control output of a stacktrace if an error occurs
  76. protected static boolean m_dumpStackOnError = true;
  77. // Server configuration
  78. private ServerConfiguration m_srvConfig;
  79. /**
  80. * Start the JLAN Server
  81. *
  82. * @param args an array of command-line arguments
  83. */
  84. public static void main(String[] args) {
  85. // Create the main JLAN server object
  86. JLANServer jlanServer = new JLANServer();
  87. // Loop until shutdown
  88. while (m_shutdown == false) {
  89. // Start the server
  90. jlanServer.start(args);
  91. // DEBUG
  92. if ( Debug.EnableInfo && m_restart == true) {
  93. Debug.println("Restarting server ...");
  94. Debug.println("--------------------------------------------------");
  95. }
  96. }
  97. }
  98. /**
  99. * Class constructor
  100. */
  101. protected JLANServer() {
  102. }
  103. /**
  104. * Set/clear the allow shutdown via console flag
  105. *
  106. * @param consoleShut boolean
  107. */
  108. public static final void setAllowConsoleShutdown(boolean consoleShut) {
  109. m_allowShutViaConsole = consoleShut;
  110. }
  111. /**
  112. * Enable/disable exception stack dumps
  113. *
  114. * @param ena boolean
  115. */
  116. protected final void enableExceptionStackDump(boolean ena) {
  117. m_dumpStackOnError = ena;
  118. }
  119. /**
  120. * Start the JLAN Server
  121. *
  122. * @param args String[]
  123. */
  124. protected void start(String[] args) {
  125. // Command line parameter should specify the configuration file
  126. PrintStream out = createOutputStream();
  127. // Clear the shutdown/restart flags
  128. m_shutdown = true;
  129. m_restart = false;
  130. // Checkpoint - server starting
  131. checkPoint(out, CheckPointStarting);
  132. // Load the configuration
  133. m_srvConfig = null;
  134. try {
  135. // Checkpoint - configuration loading
  136. checkPoint(out, CheckPointConfigLoading);
  137. // Load the configuration
  138. m_srvConfig = loadConfiguration(out, args);
  139. // Checkpoint - configuration loaded
  140. checkPoint(out, CheckPointConfigLoaded);
  141. }
  142. catch (Exception ex) {
  143. // Failed to load server configuration
  144. checkPointError(out, CheckPointConfigLoading, ex);
  145. return;
  146. }
  147. // Check if the local IP address returns a valid value, '127.0.0.1' indicates a mis-configuration in the hosts
  148. // file
  149. if ( CheckLocalIPAddress) {
  150. try {
  151. // Checkpoint - check IP address
  152. checkPoint(out, CheckPointCheckIPAddress);
  153. // Get the local address
  154. String localAddr = InetAddress.getLocalHost().getHostAddress();
  155. if ( localAddr.equals("127.0.0.1")) {
  156. out.println("%% Local IP address resolves to 127.0.0.1, this may be caused by a mis-configured hosts file");
  157. return;
  158. }
  159. }
  160. catch (UnknownHostException ex) {
  161. // Failed to get local host IP address details
  162. checkPointError(out, CheckPointCheckIPAddress, ex);
  163. return;
  164. }
  165. }
  166. // NetBIOS name server, SMB, FTP and NFS servers
  167. try {
  168. // Create the SMB server and NetBIOS name server, if enabled
  169. if ( m_srvConfig.hasConfigSection(CIFSConfigSection.SectionName)) {
  170. // Checkpoint - create SMB/CIFS server
  171. checkPoint(out, CheckPointCreateSMBServer);
  172. // Get the CIFS server configuration
  173. CIFSConfigSection cifsConfig = (CIFSConfigSection) m_srvConfig.getConfigSection(CIFSConfigSection.SectionName);
  174. // Load the Win32 NetBIOS library
  175. //
  176. // For some strange reason the native code loadLibrary() call hangs if done later by the SMBServer.
  177. // Forcing the Win32NetBIOS class to load here and run the static initializer fixes the problem.
  178. if ( cifsConfig.hasWin32NetBIOS())
  179. Win32NetBIOS.LanaEnumerate();
  180. // Create the NetBIOS name server if NetBIOS SMB is enabled
  181. if ( cifsConfig.hasNetBIOSSMB())
  182. m_srvConfig.addServer(createNetBIOSServer(m_srvConfig));
  183. // Create the SMB server
  184. m_srvConfig.addServer(createSMBServer(m_srvConfig));
  185. }
  186. // Create the FTP server, if enabled
  187. if ( m_srvConfig.hasConfigSection(FTPConfigSection.SectionName)) {
  188. // Checkpoint - create FTP server
  189. checkPoint(out, CheckPointCreateFTPServer);
  190. // Create the FTP server
  191. m_srvConfig.addServer(createFTPServer(m_srvConfig));
  192. }
  193. // Create the NFS server and mount server, if enabled
  194. if ( m_srvConfig.hasConfigSection(NFSConfigSection.SectionName)) {
  195. // Checkpoint - create NFS server
  196. checkPoint(out, CheckPointCreateNFSServer);
  197. // Get the NFS server configuration
  198. NFSConfigSection nfsConfig = (NFSConfigSection) m_srvConfig.getConfigSection(NFSConfigSection.SectionName);
  199. // Check if the port mapper is enabled
  200. if ( nfsConfig.hasNFSPortMapper())
  201. m_srvConfig.addServer(createNFSPortMapper(m_srvConfig));
  202. // Create the mount server
  203. m_srvConfig.addServer(createNFSMountServer(m_srvConfig));
  204. // Create the NFS server
  205. m_srvConfig.addServer(createNFSServer(m_srvConfig));
  206. }
  207. // Checkpoint - starting servers
  208. checkPoint(out, CheckPointServersStart);
  209. // Get the debug configuration
  210. DebugConfigSection dbgConfig = (DebugConfigSection) m_srvConfig.getConfigSection(DebugConfigSection.SectionName);
  211. // Start the configured servers
  212. for (int i = 0; i < m_srvConfig.numberOfServers(); i++) {
  213. // Get the current server
  214. NetworkServer server = m_srvConfig.getServer(i);
  215. // DEBUG
  216. if ( Debug.EnableInfo && dbgConfig != null && dbgConfig.hasDebug())
  217. Debug.println("Starting server " + server.getProtocolName() + " ...");
  218. // Start the server
  219. m_srvConfig.getServer(i).startServer();
  220. }
  221. // Checkpoint - servers started
  222. checkPoint(out, CheckPointServersStarted);
  223. // Check if the server is running as a service
  224. boolean service = false;
  225. if ( ConsoleIO.isValid() == false)
  226. service = true;
  227. // Checkpoint - servers running
  228. checkPoint(out, CheckPointRunning);
  229. // Wait while the server runs, user may stop or restart the server by typing a key
  230. m_shutdown = false;
  231. while (m_shutdown == false && m_restart == false) {
  232. // Check if the user has requested a shutdown, if running interactively
  233. if ( service == false && m_allowShutViaConsole) {
  234. // Wait for the user to enter the shutdown key
  235. int inChar = ConsoleIO.readCharacter();
  236. if ( inChar == 'x' || inChar == 'X')
  237. m_shutdown = true;
  238. else if ( inChar == 'r' || inChar == 'R')
  239. m_restart = true;
  240. else if ( inChar == 'g' || inChar == 'G') {
  241. Debug.println( "Running garbage collection ...");
  242. System.gc();
  243. }
  244. else if ( inChar == -1) {
  245. // Sleep for a short while
  246. try {
  247. Thread.sleep(500);
  248. }
  249. catch (InterruptedException ex) {
  250. }
  251. }
  252. }
  253. else {
  254. // Sleep for a short while
  255. try {
  256. Thread.sleep(500);
  257. }
  258. catch (InterruptedException ex) {
  259. }
  260. }
  261. }
  262. // Checkpoint - servers stopping
  263. checkPoint(out, CheckPointServersStop);
  264. // Shutdown the servers
  265. int idx = m_srvConfig.numberOfServers() - 1;
  266. while (idx >= 0) {
  267. // Get the current server
  268. NetworkServer server = m_srvConfig.getServer(idx--);
  269. // DEBUG
  270. if ( Debug.EnableInfo && dbgConfig != null && dbgConfig.hasDebug())
  271. Debug.println("Shutting server " + server.getProtocolName() + " ...");
  272. // Stop the server
  273. server.shutdownServer(false);
  274. }
  275. // Close the configuration
  276. m_srvConfig.closeConfiguration();
  277. // Checkpoint - servers stopped
  278. checkPoint(out, CheckPointServersStopped);
  279. }
  280. catch (Exception ex) {
  281. // Server error
  282. checkPointError(out, CheckPointServersStarted, ex);
  283. }
  284. finally {
  285. // Close all active servers
  286. int idx = m_srvConfig.numberOfServers() - 1;
  287. while (idx >= 0) {
  288. NetworkServer srv = m_srvConfig.getServer(idx--);
  289. if ( srv.isActive())
  290. srv.shutdownServer(true);
  291. }
  292. }
  293. // Checkpoint - finished
  294. checkPoint(out, CheckPointFinished);
  295. }
  296. /**
  297. * Shutdown the server when running as an NT service
  298. *
  299. * @param args String[]
  300. */
  301. public final static void shutdownServer(String[] args) {
  302. m_shutdown = true;
  303. }
  304. /**
  305. * Create the SMB server
  306. *
  307. * @param config ServerConfiguration
  308. * @return NetworkServer
  309. * @exception Exception
  310. */
  311. protected final NetworkServer createSMBServer(ServerConfiguration config)
  312. throws Exception {
  313. // Create an SMB server
  314. NetworkServer smbServer = new SMBServer(config);
  315. // Check if there are any drive mappings configured
  316. if ( Platform.isPlatformType() == Platform.Type.WINDOWS
  317. && config.hasConfigSection(DriveMappingsConfigSection.SectionName))
  318. smbServer.addServerListener(this);
  319. // Return the SMB server
  320. return smbServer;
  321. }
  322. /**
  323. * Create the NetBIOS name server
  324. *
  325. * @param config ServerConfiguration
  326. * @return NetworkServer
  327. * @exception Exception
  328. */
  329. protected final NetworkServer createNetBIOSServer(ServerConfiguration config)
  330. throws Exception {
  331. // Create a NetBIOS name server
  332. return new NetBIOSNameServer(config);
  333. }
  334. /**
  335. * Create the FTP server
  336. *
  337. * @param config ServerConfiguration
  338. * @return NetworkServer
  339. * @exception Exception
  340. */
  341. protected final NetworkServer createFTPServer(ServerConfiguration config)
  342. throws Exception {
  343. // Create the FTP server instance
  344. return createServer("org.alfresco.jlan.ftp.FTPServer", config);
  345. }
  346. /**
  347. * Create the NFS server
  348. *
  349. * @param config ServerConfiguration
  350. * @return NetworkServer
  351. * @exception Exception
  352. */
  353. protected final NetworkServer createNFSServer(ServerConfiguration config)
  354. throws Exception {
  355. // Create the NFS server instance
  356. return createServer("org.alfresco.jlan.oncrpc.nfs.NFSServer", config);
  357. }
  358. /**
  359. * Create the NFS mount server
  360. *
  361. * @param config ServerConfiguration
  362. * @return NetworkServer
  363. * @exception Exception
  364. */
  365. protected final NetworkServer createNFSMountServer(ServerConfiguration config)
  366. throws Exception {
  367. // Create the mount server instance
  368. return createServer("org.alfresco.jlan.oncrpc.mount.MountServer", config);
  369. }
  370. /**
  371. * Create the NFS port mapper server
  372. *
  373. * @param config ServerConfiguration
  374. * @return NetworkServer
  375. */
  376. protected final NetworkServer createNFSPortMapper(ServerConfiguration config)
  377. throws Exception {
  378. // Create the port mapper server instance
  379. return createServer("org.alfresco.jlan.oncrpc.portmap.PortMapperServer", config);
  380. }
  381. /**
  382. * Create a network server using reflection
  383. *
  384. * @param className String
  385. * @param config ServerConfiguration
  386. * @return NetworkServer
  387. * @exception Exception
  388. */
  389. protected final NetworkServer createServer(String className, ServerConfiguration config)
  390. throws Exception {
  391. // Create the server instance using reflection
  392. NetworkServer srv = null;
  393. // Find the server constructor
  394. Class<?>[] classes = new Class[1];
  395. classes[0] = ServerConfiguration.class;
  396. Constructor<?> srvConstructor = Class.forName(className).getConstructor(classes);
  397. // Create the network server
  398. Object[] args = new Object[1];
  399. args[0] = config;
  400. srv = (NetworkServer) srvConstructor.newInstance(args);
  401. // Return the network server instance
  402. return srv;
  403. }
  404. /**
  405. * Load the server configuration, default is to load using an XML configuration file.
  406. *
  407. * @param out PrintStream
  408. * @param cmdLineArgs String[]
  409. * @return ServerConfiguration
  410. * @exception Exception
  411. */
  412. protected ServerConfiguration loadConfiguration(PrintStream out, String[] cmdLineArgs)
  413. throws Exception {
  414. String fileName = null;
  415. if ( cmdLineArgs.length < 1) {
  416. // Search for a default configuration file in the users home directory
  417. fileName = System.getProperty("user.home") + File.separator + DEFAULT_CONFIGFILENAME;
  418. }
  419. else
  420. fileName = cmdLineArgs[0];
  421. // Load the configuration
  422. ServerConfiguration srvConfig = null;
  423. // Create an XML configuration
  424. srvConfig = new XMLServerConfiguration();
  425. srvConfig.loadConfiguration(fileName);
  426. // Return the server configuration
  427. return srvConfig;
  428. }
  429. /**
  430. * Create the output stream for logging
  431. *
  432. * @return PrintStream
  433. */
  434. protected PrintStream createOutputStream() {
  435. return System.out;
  436. }
  437. /**
  438. * Checkpoint method, called at various points of the server startup and shutdown
  439. *
  440. * @param out PrintStream
  441. * @param check int
  442. */
  443. protected void checkPoint(PrintStream out, int check) {
  444. }
  445. /**
  446. * Checkpoint error method, called if an error occurs during server startup/shutdown
  447. *
  448. * @param out PrintStream
  449. * @param check int
  450. * @param ex Exception
  451. */
  452. protected void checkPointError(PrintStream out, int check, Exception ex) {
  453. // Default error output goes to the console
  454. String msg = "%% Error occurred";
  455. switch (check) {
  456. // Configuration load error
  457. case CheckPointConfigLoading:
  458. msg = "%% Failed to load server configuration";
  459. break;
  460. // Checking local network address error
  461. case CheckPointCheckIPAddress:
  462. msg = "%% Failed to get local IP address details";
  463. break;
  464. //
  465. case CheckPointServersStarted:
  466. msg = "%% Server error";
  467. break;
  468. }
  469. // Output the error message and a stack trace
  470. out.println(msg);
  471. if ( m_dumpStackOnError)
  472. ex.printStackTrace(out);
  473. }
  474. /**
  475. * Handle server startup/shutdown events
  476. *
  477. * @param server NetworkServer
  478. * @param event int
  479. */
  480. public void serverStatusEvent(NetworkServer server, int event) {
  481. // Check for an SMB server event
  482. if ( server instanceof SMBServer) {
  483. // Get the drive mappings configuration
  484. DriveMappingsConfigSection mapConfig = (DriveMappingsConfigSection) m_srvConfig
  485. .getConfigSection(DriveMappingsConfigSection.SectionName);
  486. if ( mapConfig == null)
  487. return;
  488. // Check for a server startup event, add drive mappings now that the server is running
  489. if ( event == ServerListener.ServerStartup) {
  490. // Get the mapped drives list
  491. DriveMappingList mapList = mapConfig.getMappedDrives();
  492. // Add the mapped drives
  493. for (int i = 0; i < mapList.numberOfMappings(); i++) {
  494. // Get the current drive mapping
  495. DriveMapping driveMap = mapList.getMappingAt(i);
  496. // DEBUG
  497. if ( Debug.EnableInfo && mapConfig.hasDebug())
  498. Debug.println("Mapping drive " + driveMap.getLocalDrive() + " to " + driveMap.getRemotePath() + " ...");
  499. // Create a local mapped drive to the JLAN Server
  500. int sts = Win32Utils.MapNetworkDrive(driveMap.getRemotePath(), driveMap.getLocalDrive(), driveMap
  501. .getUserName(), driveMap.getPassword(), driveMap.hasInteractive(), driveMap.hasPrompt());
  502. // Check if the drive was mapped successfully
  503. if ( sts != 0)
  504. Debug.println("Failed to map drive " + driveMap.getLocalDrive() + " to " + driveMap.getRemotePath()
  505. + ", status = " + SMBErrorText.ErrorString(SMBStatus.Win32Err, sts));
  506. }
  507. }
  508. else if ( event == ServerListener.ServerShutdown) {
  509. // Get the mapped drives list
  510. DriveMappingList mapList = mapConfig.getMappedDrives();
  511. // Remove the mapped drives
  512. for (int i = 0; i < mapList.numberOfMappings(); i++) {
  513. // Get the current drive mapping
  514. DriveMapping driveMap = mapList.getMappingAt(i);
  515. // DEBUG
  516. if ( Debug.EnableInfo && mapConfig.hasDebug())
  517. Debug.println("Removing mapped drive " + driveMap.getLocalDrive() + " to " + driveMap.getRemotePath()
  518. + " ...");
  519. // Remove a mapped drive
  520. int sts = Win32Utils.DeleteNetworkDrive(driveMap.getLocalDrive(), false, true);
  521. // Check if the drive was unmapped successfully
  522. if ( sts != 0)
  523. Debug.println("Failed to delete mapped drive " + driveMap.getLocalDrive() + " from "
  524. + driveMap.getRemotePath() + ", status = " + SMBErrorText.ErrorString(SMBStatus.Win32Err, sts));
  525. }
  526. }
  527. }
  528. }
  529. }