JLANCifsServer.java 16 KB

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