1 18 package net.sf.drftpd.master; 19 20 import java.io.FileInputStream ; 21 import java.io.FileNotFoundException ; 22 import java.io.FileReader ; 23 import java.io.IOException ; 24 import java.io.PrintWriter ; 25 import java.lang.reflect.Constructor ; 26 import java.net.ServerSocket ; 27 import java.net.Socket ; 28 import java.util.ArrayList ; 29 import java.util.Collections ; 30 import java.util.Iterator ; 31 import java.util.List ; 32 import java.util.Properties ; 33 import java.util.Timer ; 34 import java.util.TimerTask ; 35 36 import net.sf.drftpd.FatalException; 37 import net.sf.drftpd.ObjectNotFoundException; 38 import net.sf.drftpd.event.Event; 39 import net.sf.drftpd.event.FtpListener; 40 import net.sf.drftpd.event.MessageEvent; 41 import net.sf.drftpd.event.listeners.RaceStatistics; 42 import net.sf.drftpd.master.command.CommandManagerFactory; 43 import net.sf.drftpd.master.config.FtpConfig; 44 import net.sf.drftpd.master.usermanager.NoSuchUserException; 45 import net.sf.drftpd.master.usermanager.User; 46 import net.sf.drftpd.master.usermanager.UserFileException; 47 import net.sf.drftpd.master.usermanager.UserManager; 48 import net.sf.drftpd.mirroring.JobManager; 49 import net.sf.drftpd.permission.GlobRMIServerSocketFactory; 50 import net.sf.drftpd.remotefile.LinkedRemoteFile; 51 import net.sf.drftpd.remotefile.MLSTSerialize; 52 import net.sf.drftpd.slave.SlaveImpl; 53 import net.sf.drftpd.util.SafeFileWriter; 54 55 import org.apache.log4j.Level; 56 import org.apache.log4j.Logger; 57 import org.drftpd.sections.SectionManagerInterface; 58 import org.drftpd.slave.socket.SocketSlaveManager; 59 60 63 public class ConnectionManager { 64 65 public static final int idleTimeout = 300; 66 67 private static final Logger logger = 68 Logger.getLogger(ConnectionManager.class.getName()); 69 70 public static LinkedRemoteFile loadMLSTFileDatabase( 71 List rslaves, 72 ConnectionManager cm) 73 throws IOException { 74 return MLSTSerialize.unserialize( 75 cm != null ? cm.getConfig() : null, 76 new FileReader ("files.mlst"), 77 rslaves); 78 } 79 80 public static void main(String args[]) { 81 System.out.println(SlaveImpl.VERSION + " master server starting."); 82 System.out.println("http://drftpd.org/"); 83 try { 84 String cfgFileName; 85 if (args.length >= 1) { 86 cfgFileName = args[0]; 87 } else { 88 cfgFileName = "drftpd.conf"; 89 } 90 String slaveCfgFileName; 91 if (args.length >= 2) { 92 slaveCfgFileName = args[1]; 93 } else { 94 slaveCfgFileName = "slave.conf"; 95 } 96 97 98 Properties cfg = new Properties (); 99 cfg.load(new FileInputStream (cfgFileName)); 100 101 102 Properties slaveCfg; if (cfg 104 .getProperty("master.localslave", "false") 105 .equalsIgnoreCase("true")) { 106 slaveCfg = new Properties (); 107 slaveCfg.load(new FileInputStream (slaveCfgFileName)); 108 } else { 109 slaveCfg = null; 110 } 111 112 logger.info("Starting ConnectionManager"); 113 ConnectionManager mgr = 114 new ConnectionManager( 115 cfg, 116 slaveCfg, 117 cfgFileName, 118 slaveCfgFileName); 119 120 ServerSocket server = 121 new ServerSocket ( 122 Integer.parseInt( 123 FtpConfig.getProperty(cfg, "master.port"))); 124 logger.info("Listening on port " + server.getLocalPort()); 125 while (true) { 126 mgr.start(server.accept()); 127 } 128 } catch (Throwable th) { 130 logger.error("", th); 131 System.exit(0); 132 return; 133 } 134 } 135 136 private static String [] scrubArgs(String [] args) { 137 String ret[] = new String [args.length - 1]; 138 System.arraycopy(args, 1, ret, 0, ret.length); 139 return ret; 140 } 141 private CommandManagerFactory _commandManagerFactory; 142 private FtpConfig _config; 143 private List _conns = Collections.synchronizedList(new ArrayList ()); 144 145 private ArrayList _ftpListeners = new ArrayList (); 146 protected JobManager _jm; 147 148 protected LinkedRemoteFile _root; 149 private SectionManagerInterface _sections; 150 private String _shutdownMessage = null; 151 private SlaveManagerImpl _slaveManager; 153 private Timer _timer; 154 private UserManager _usermanager; 155 156 protected ConnectionManager() { 157 } 158 159 public ConnectionManager( 160 Properties cfg, 161 Properties slaveCfg, 162 String cfgFileName, 163 String slaveCfgFileName) { 164 try { 165 _config = new FtpConfig(cfg, cfgFileName, this); 166 } catch (Throwable ex) { 167 throw new FatalException(ex); 168 } 169 _timer = new Timer (); 170 171 loadSlaveManager(cfg, cfgFileName); 172 173 loadRSlaves(); 174 175 if (!cfg.getProperty("master.socketport", "").equals("")) { 177 new SocketSlaveManager(this, cfg); 178 } 179 180 if (slaveCfg != null) { 181 try { 182 new SlaveImpl(slaveCfg); 183 } catch (IOException ex) { throw new FatalException(ex); 185 } 186 } 187 188 loadUserManager(cfg, cfgFileName); 189 190 _commandManagerFactory = new CommandManagerFactory(this); 191 192 addFtpListener(new RaceStatistics()); 193 194 loadSectionManager(cfg); 195 196 loadPlugins(cfg); 197 198 loadTimer(); 199 getSlaveManager().addShutdownHook(); 200 } 201 202 private void loadRSlaves() { 203 try { 204 List rslaves1 = _slaveManager.getSlaveList(); 205 _root = ConnectionManager.loadMLSTFileDatabase(rslaves1, this); 206 } catch (FileNotFoundException e) { 207 logger.info("files.mlst not found, creating a new filelist", e); 208 _root = new LinkedRemoteFile(getConfig()); 209 } catch (IOException e) { 211 throw new FatalException(e); 212 } 213 } 214 215 218 private void loadSlaveManager(Properties cfg, String cfgFileName) { 219 220 try { 221 String smclass = null; 222 try { 223 smclass = FtpConfig.getProperty(cfg, "master.slavemanager"); 224 } catch (Exception ex) { 225 } 226 if (smclass == null) 227 smclass = "net.sf.drftpd.master.SlaveManagerImpl"; 228 _slaveManager = 229 (SlaveManagerImpl) Class.forName(smclass).newInstance(); 230 List rslaves = _slaveManager.loadSlaves(); 231 GlobRMIServerSocketFactory ssf = 232 new GlobRMIServerSocketFactory(rslaves); 233 _slaveManager.init(cfg, rslaves, ssf, this); 234 } catch (Exception e) { 235 logger.log(Level.WARN, "Exception instancing SlaveManager", e); 236 throw new FatalException( 237 "Cannot create instance of slavemanager, check master.slavemanager in " 238 + cfgFileName, 239 e); 240 } 241 } 242 243 246 public void addFtpListener(FtpListener listener) { 247 listener.init(this); 248 _ftpListeners.add(listener); 249 } 250 251 public FtpReply canLogin(BaseFtpConnection baseconn, User user) { 252 int count = getConfig().getMaxUsersTotal(); 253 if (user.isExempt()) 255 count = Math.max(count, count + getConfig().getMaxUsersExempt()); 256 int userCount = 0; 257 int ipCount = 0; 258 259 if (_conns.size() > count) 261 return new FtpReply(550, "The site is full, try again later."); 262 synchronized (_conns) { 263 for (Iterator iter = _conns.iterator(); iter.hasNext();) { 264 BaseFtpConnection tempConnection = 265 (BaseFtpConnection) iter.next(); 266 try { 267 User tempUser = tempConnection.getUser(); 268 if (tempUser.getUsername().equals(user.getUsername())) { 269 userCount++; 270 if (tempConnection 271 .getClientAddress() 272 .equals(baseconn.getClientAddress())) { 273 ipCount++; 274 } 275 } 276 } catch (NoSuchUserException ex) { 277 } 279 } 280 } 281 if (user.getMaxLoginsPerIP() > 0 && ipCount > user.getMaxLoginsPerIP()) 282 return new FtpReply( 283 530, 284 "Sorry, your maximum number of connections from this IP (" 285 + user.getMaxLoginsPerIP() 286 + ") has been reached."); 287 if (user.getMaxLogins() > 0 && userCount > user.getMaxLogins()) 288 return new FtpReply( 289 530, 290 "Sorry, your account is restricted to " 291 + user.getMaxLogins() 292 + " simultaneous logins."); 293 if (!baseconn.isSecure() 294 && getConfig().checkUserRejectInsecure(user)) { 295 return new FtpReply(530, "USE SECURE CONNECTION"); 296 } else if ( 297 baseconn.isSecure() && getConfig().checkUserRejectSecure(user)) { 298 return new FtpReply(530, "USE INSECURE CONNECTION"); 299 } 300 return null; } 302 303 public void dispatchFtpEvent(Event event) { 304 logger.debug("Dispatching " + event+" to "+getFtpListeners()); 305 for (Iterator iter = getFtpListeners().iterator(); iter.hasNext();) { 306 try { 307 FtpListener handler = (FtpListener) iter.next(); 308 handler.actionPerformed(event); 309 } catch (RuntimeException e) { 310 logger.warn("RuntimeException dispatching event", e); 311 } 312 } 313 } 314 315 public CommandManagerFactory getCommandManagerFactory() { 316 return _commandManagerFactory; 317 } 318 319 public FtpConfig getConfig() { 320 return _config; 321 } 322 323 326 public List getConnections() { 327 return _conns; 328 } 329 public FtpListener getFtpListener(Class clazz) 330 throws ObjectNotFoundException { 331 for (Iterator iter = getFtpListeners().iterator(); iter.hasNext();) { 332 FtpListener listener = (FtpListener) iter.next(); 333 if (clazz.isInstance(listener)) 334 return listener; 335 } 336 throw new ObjectNotFoundException(); 337 } 338 339 public List getFtpListeners() { 340 return _ftpListeners; 341 } 342 343 public JobManager getJobManager() { 344 if (_jm == null) 345 throw new IllegalStateException ("JobManager not loaded"); 346 return _jm; 347 } 348 349 public LinkedRemoteFile getRoot() { 350 return _root; 351 } 352 353 public SectionManagerInterface getSectionManager() { 354 return _sections; 355 } 356 public String getShutdownMessage() { 357 return _shutdownMessage; 358 } 359 360 public SlaveManagerImpl getSlaveManager() { 361 return _slaveManager; 362 } 363 364 public Timer getTimer() { 365 return _timer; 366 } 367 368 public UserManager getUserManager() { 369 return _usermanager; 370 } 371 372 public boolean isJobManagerLoaded() { 373 return (_jm != null); 374 } 375 public boolean isShutdown() { 376 return _shutdownMessage != null; 377 } 378 379 public void loadJobManager() { 380 if (_jm != null) 381 return; try { 383 _jm = new JobManager(this); 384 getSlaveManager().getSlaveSelectionManager().reload(); 385 _jm.startJobs(); 386 } catch (IOException e) { 387 throw new FatalException("Error loading JobManager", e); 388 } 389 } 390 391 protected void loadPlugins(Properties cfg) { 392 for (int i = 1;; i++) { 393 String classname = cfg.getProperty("plugins." + i); 394 if (classname == null) 395 break; 396 try { 397 FtpListener ftpListener = 398 (FtpListener) Class.forName(classname).newInstance(); 399 addFtpListener(ftpListener); 400 } catch (Exception e) { 401 throw new FatalException("Error loading plugins", e); 402 } 403 } 404 } 405 406 private void loadSectionManager(Properties cfg) { 407 try { 408 Class cl = 409 Class.forName( 410 cfg.getProperty( 411 "sectionmanager", 412 "org.drftpd.sections.def.SectionManager")); 413 Constructor c = 414 cl.getConstructor(new Class [] { ConnectionManager.class }); 415 _sections = 416 (SectionManagerInterface) c.newInstance(new Object [] { this }); 417 } catch (Exception e) { 418 throw new FatalException(e); 419 } 420 } 421 422 private void loadTimer() { 423 TimerTask timerLogoutIdle = new TimerTask () { 424 public void run() { 425 timerLogoutIdle(); 426 } 427 }; 428 _timer.schedule(timerLogoutIdle, 10 * 1000, 10 * 1000); 430 431 TimerTask timerSave = new TimerTask () { 432 public void run() { 433 getSlaveManager().saveFilelist(); 434 try { 435 getUserManager().saveAll(); 436 } catch (UserFileException e) { 437 logger.log(Level.FATAL, "Error saving all users", e); 438 } 439 } 440 }; 441 _timer.schedule(timerSave, 60 * 60 * 1000, 60 * 60 * 1000); 443 } 444 445 449 protected void loadUserManager(Properties cfg, String cfgFileName) { 450 try { 451 _usermanager = 452 (UserManager) Class 453 .forName(FtpConfig.getProperty(cfg, "master.usermanager")) 454 .newInstance(); 455 _usermanager.init(this); 457 } catch (Exception e) { 458 throw new FatalException( 459 "Cannot create instance of usermanager, check master.usermanager in " 460 + cfgFileName, 461 e); 462 } 463 } 464 465 public void reload() { 466 getSectionManager().reload(); 472 } 473 474 public void remove(BaseFtpConnection conn) { 475 if (!_conns.remove(conn)) { 476 throw new RuntimeException ("connections.remove() returned false."); 477 } 478 if (isShutdown() && _conns.isEmpty()) { 479 logger.info("Shutdown complete, exiting"); 486 System.exit(0); 487 } 488 } 489 public void saveFilelist() { 490 try { 491 SafeFileWriter out = new SafeFileWriter("files.mlst"); 492 try { 493 MLSTSerialize.serialize(getRoot(), out); 494 } finally { 495 out.close(); 496 } 497 } catch (IOException e) { 498 logger.warn("Error saving files.mlst", e); 499 } 500 } 501 public void shutdown(String message) { 502 _shutdownMessage = message; 503 ArrayList conns = new ArrayList (getConnections()); 504 for (Iterator iter = conns.iterator(); iter.hasNext();) { 505 ((BaseFtpConnection) iter.next()).stop(message); 506 } 507 dispatchFtpEvent(new MessageEvent("SHUTDOWN", message)); 508 } 509 public void start(Socket sock) throws IOException { 510 if (isShutdown()) { 511 new PrintWriter (sock.getOutputStream()).println( 512 "421 " + getShutdownMessage()); 513 sock.close(); 514 return; 515 } 516 BaseFtpConnection conn = new BaseFtpConnection(this, sock); 517 _conns.add(conn); 518 conn.start(); 519 } 520 521 public void timerLogoutIdle() { 522 long currTime = System.currentTimeMillis(); 523 ArrayList conns = new ArrayList (_conns); 524 for (Iterator i = conns.iterator(); i.hasNext();) { 525 BaseFtpConnection conn = (BaseFtpConnection) i.next(); 526 527 int idle = (int) ((currTime - conn.getLastActive()) / 1000); 528 int maxIdleTime; 529 try { 530 maxIdleTime = conn.getUser().getIdleTime(); 531 if (maxIdleTime == 0) 532 maxIdleTime = idleTimeout; 533 } catch (NoSuchUserException e) { 534 maxIdleTime = idleTimeout; 535 } 536 537 if (!conn.isExecuting() && idle >= maxIdleTime) { 538 conn.stop("Idle time expired: " + maxIdleTime + "s"); 540 } 541 } 542 } 543 } 544 | Popular Tags |