1 18 package net.sf.drftpd.slave; 19 20 import java.io.BufferedReader ; 21 import java.io.EOFException ; 22 import java.io.FileInputStream ; 23 import java.io.FileNotFoundException ; 24 import java.io.FileReader ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.net.InetSocketAddress ; 28 import java.rmi.ConnectIOException ; 29 import java.rmi.Naming ; 30 import java.rmi.NotBoundException ; 31 import java.rmi.RemoteException ; 32 import java.rmi.server.RMISocketFactory ; 33 import java.rmi.server.UnicastRemoteObject ; 34 import java.rmi.server.Unreferenced ; 35 import java.util.ArrayList ; 36 import java.util.Collection ; 37 import java.util.Iterator ; 38 import java.util.Properties ; 39 import java.util.Vector ; 40 import java.util.zip.CRC32 ; 41 import java.util.zip.CheckedInputStream ; 42 43 import javax.net.ssl.SSLContext; 44 45 import net.sf.drftpd.Bytes; 46 import net.sf.drftpd.FatalException; 47 import net.sf.drftpd.FileExistsException; 48 import net.sf.drftpd.PermissionDeniedException; 49 import net.sf.drftpd.SFVFile; 50 import net.sf.drftpd.master.SlaveManager; 51 import net.sf.drftpd.master.config.FtpConfig; 52 import net.sf.drftpd.remotefile.FileRemoteFile; 53 import net.sf.drftpd.remotefile.LinkedRemoteFile; 54 import net.sf.drftpd.util.PortRange; 55 import net.sf.drftpd.util.SSLGetContext; 56 57 import org.apache.log4j.BasicConfigurator; 58 import org.apache.log4j.Level; 59 import org.apache.log4j.Logger; 60 61 import se.mog.io.File; 62 63 67 public class SlaveImpl 68 extends UnicastRemoteObject 69 implements Slave, Unreferenced { 70 private int _bufferSize; 71 static final boolean isWin32 = 72 System.getProperty("os.name").startsWith("Windows"); 73 private static final Logger logger = 74 Logger.getLogger(SlaveImpl.class.getName()); 75 76 public static final String VERSION = "DrFTPD 1.1.4"; 77 78 82 public static LinkedRemoteFile getDefaultRoot(RootBasket rootBasket) 83 throws IOException { 84 85 LinkedRemoteFile linkedroot = 86 new LinkedRemoteFile(new FileRemoteFile(rootBasket), null); 87 88 return linkedroot; 89 } 90 91 public static RootBasket getDefaultRootBasket(Properties cfg) throws IOException { 92 RootBasket roots; 93 long defaultMinSpaceFree = 95 Bytes.parseBytes(cfg.getProperty("slave.minspacefree", "50mb")); 96 ArrayList rootStrings = new ArrayList (); 97 for (int i = 1; true; i++) { 98 String rootString = cfg.getProperty("slave.root." + i); 99 if (rootString == null) 100 break; 101 System.out.println("slave.root." + i + ": " + rootString); 102 103 long minSpaceFree; 104 try { 105 minSpaceFree = 106 Long.parseLong( 107 cfg.getProperty("slave.root." + i + ".minspacefree")); 108 } catch (NumberFormatException ex) { 109 minSpaceFree = defaultMinSpaceFree; 110 } 111 112 int priority; 113 try { 114 priority = 115 Integer.parseInt( 116 cfg.getProperty("slave.root." + i + ".priority")); 117 } catch (NumberFormatException ex) { 118 priority = 0; 119 } 120 121 rootStrings.add(new Root(rootString, minSpaceFree, priority)); 122 } 123 124 try { 125 roots = new RootBasket(rootStrings); 126 } catch (IOException e) { 127 throw new FatalException(e); 128 } 129 return roots; 131 } 132 133 public static void main(String args[]) { 134 BasicConfigurator.configure(); 135 System.out.println(SlaveImpl.VERSION + " slave server starting"); 136 String slaveconf; 137 if (args.length >= 1) { 138 slaveconf = args[0]; 139 } else { 140 slaveconf = "slave.conf"; 141 } 142 try { 143 144 Properties cfg = new Properties (); 145 try { 146 cfg.load(new FileInputStream (slaveconf)); 147 } catch (Throwable ex) { 148 ex.printStackTrace(); 149 System.err.println( 150 "Could not open " + slaveconf + ", exiting."); 151 System.exit(0); 152 return; 153 } 154 if (cfg.getProperty("slave.portfrom") != null) { 155 RMISocketFactory.setSocketFactory( 156 new PortRangeServerSocketFactory( 157 Integer.parseInt(cfg.getProperty("slave.portfrom")), 158 Integer.parseInt( 159 FtpConfig.getProperty(cfg, "slave.portto")))); 160 } 161 162 new SlaveImpl(cfg); 163 164 } catch (Throwable e) { 165 logger.warn("Error registering", e); 166 System.exit(0); 167 return; 168 } 169 } 170 private SSLContext _ctx; 171 private boolean _downloadChecksums; 172 private String _name; 173 private PortRange _portRange = new PortRange(); 174 private long _receivedBytes = 0; 175 private RootBasket _roots; 177 private long _sentBytes = 0; 178 179 private Vector _transfers = new Vector (); 180 private boolean _uploadChecksums; 181 182 public LinkedRemoteFile getSlaveRoot() throws IOException { 183 return SlaveImpl.getDefaultRoot(_roots); 184 } 185 186 public SlaveImpl(Properties cfg) throws RemoteException , IOException { 187 super(0); 188 try { 189 _ctx = SSLGetContext.getSSLContext(); 190 } catch (Exception e) { 191 logger.warn("Error loading SSLContext", e); 192 } 193 _uploadChecksums = cfg.getProperty("enableuploadchecksums", "true").equals("true"); 194 _downloadChecksums = cfg.getProperty("enabledownloadchecksums", "true").equals("true"); 195 _bufferSize = Integer.parseInt(cfg.getProperty("bufferSize","0")); 196 197 String slavemanagerurl; 198 slavemanagerurl = 199 "//" 200 + FtpConfig.getProperty(cfg, "master.host") 201 + ":" 202 + cfg.getProperty("master.bindport", "1099") 203 + "/" 204 + cfg.getProperty("master.bindname", "slavemanager"); 205 _name = FtpConfig.getProperty(cfg, "slave.name"); 206 207 _roots = getDefaultRootBasket(cfg); 208 try { 209 SlaveManager manager; 210 logger.log(Level.INFO, "Getting master reference"); 211 manager = (SlaveManager) Naming.lookup(slavemanagerurl); 212 213 logger.log( 214 Level.INFO, 215 "Registering with master and sending filelist"); 216 217 manager.addSlave(_name, this, getSlaveStatus(), _roots.getMaxPath()); 218 219 logger.log( 220 Level.INFO, 221 "Finished registered with master, awaiting commands."); 222 } catch (RuntimeException t) { 223 logger.warn("Error registering with slave", t); 224 System.exit(0); 225 } catch (IOException e) { 226 if (e instanceof ConnectIOException 227 && e.getCause() instanceof EOFException ) { 228 logger.info( 229 "Check slaves.xml on the master that you are allowed to connect."); 230 } 231 logger.info("", e); 232 System.exit(0); 233 } catch (NotBoundException e) { 234 logger.warn("", e); 235 } 236 System.gc(); 237 } 238 239 public void addTransfer(TransferImpl transfer) { 240 synchronized (_transfers) { 241 _transfers.add(transfer); 242 } 243 } 244 245 248 public long checkSum(String path) throws IOException { 249 logger.debug("Checksumming: " + path); 250 CRC32 crc32 = new CRC32 (); 251 FileInputStream fis = new FileInputStream (_roots.getFile(path)); 252 try { 253 InputStream in = new CheckedInputStream (fis, crc32); 254 byte buf[] = new byte[4096]; 255 while (in.read(buf) != -1); 256 } finally { 257 fis.close(); 258 } 259 return crc32.getValue(); 260 } 261 262 public Transfer connect(InetSocketAddress addr, boolean encrypted) 263 throws RemoteException { 264 return new TransferImpl( 266 new ActiveConnection(encrypted ? _ctx : null, addr), 267 this); 268 } 269 270 public void delete(String path) throws IOException { 271 Collection files = _roots.getMultipleRootsForFile(path); 272 for (Iterator iter = files.iterator(); iter.hasNext();) { 273 Root root = (Root) iter.next(); 274 File file = root.getFile(path); 275 if (!file.exists()) { 276 throw new FileNotFoundException ( 277 file.getAbsolutePath() + " does not exist."); 278 } 279 if (!file.delete()) 280 throw new PermissionDeniedException("delete failed on " + path); 281 File dir = new File(file.getParentFile()); 282 283 logger.debug("DELETE: "+path); 285 while (dir.list().length == 0) { 286 file.delete(); 287 logger.debug("DELETEFS: "+file.getPath()); 288 java.io.File tmpFile = dir.getParentFile(); 289 if (tmpFile == null) 290 break; 291 if (tmpFile.getPath().length() < root.getPath().length()) { 292 throw new SecurityException ("Attempt to break out of root"); 293 } 294 dir = new File(tmpFile); 295 } 296 } 297 } 298 299 public boolean getDownloadChecksums() { 300 return _downloadChecksums; 301 } 302 303 public RootBasket getRoots() { 304 return _roots; 305 } 306 307 public SFVFile getSFVFile(String path) throws IOException { 308 return new SFVFile( 309 new BufferedReader (new FileReader (_roots.getFile(path)))); 310 } 311 312 public SlaveStatus getSlaveStatus() { 313 int throughputUp = 0, throughputDown = 0; 314 int transfersUp = 0, transfersDown = 0; 315 long bytesReceived, bytesSent; 316 synchronized (_transfers) { 317 bytesReceived = _receivedBytes; 318 bytesSent = _sentBytes; 319 for (Iterator i = _transfers.iterator(); i.hasNext();) { 320 TransferImpl transfer = (TransferImpl) i.next(); 321 switch (transfer.getDirection()) { 322 case Transfer.TRANSFER_RECEIVING_UPLOAD : 323 throughputUp += transfer.getXferSpeed(); 324 transfersUp += 1; 325 bytesReceived += transfer.getTransfered(); 326 break; 327 case Transfer.TRANSFER_SENDING_DOWNLOAD : 328 throughputDown += transfer.getXferSpeed(); 329 transfersDown += 1; 330 bytesSent += transfer.getTransfered(); 331 break; 332 default : 333 throw new FatalException("unrecognized direction"); 334 } 335 } 336 } 337 try { 338 return new SlaveStatus( 339 _roots.getTotalDiskSpaceAvailable(), 340 _roots.getTotalDiskSpaceCapacity(), 341 bytesSent, 342 bytesReceived, 343 throughputUp, 344 transfersUp, 345 throughputDown, 346 transfersDown); 347 } catch (Exception ex) { 348 ex.printStackTrace(); 349 throw new RuntimeException (ex.toString()); 350 } 351 } 352 353 public boolean getUploadChecksums() { 354 return _uploadChecksums; 355 } 356 357 public Transfer listen(boolean encrypted) 358 throws RemoteException , IOException { 359 return new TransferImpl( 360 new PassiveConnection( 361 encrypted ? _ctx : null, 362 _portRange, 363 new InetSocketAddress (0)), 364 this); 365 } 366 367 public void ping() { 368 } 369 370 public void removeTransfer(TransferImpl transfer) { 371 synchronized (_transfers) { 372 switch (transfer.getDirection()) { 373 case Transfer.TRANSFER_RECEIVING_UPLOAD : 374 _receivedBytes += transfer.getTransfered(); 375 break; 376 case Transfer.TRANSFER_SENDING_DOWNLOAD : 377 _sentBytes += transfer.getTransfered(); 378 break; 379 default : 380 throw new IllegalArgumentException (); 381 } 382 if (!_transfers.remove(transfer)) 383 throw new IllegalStateException (); 384 } 385 } 386 387 public void rename(String from, String toDirPath, String toName) 388 throws IOException { 389 for (Iterator iter = _roots.iterator(); iter.hasNext();) { 390 Root root = (Root) iter.next(); 391 392 File fromfile = root.getFile(from); 393 if (!fromfile.exists()) 394 continue; 395 396 File toDir = root.getFile(toDirPath); 397 toDir.mkdirs(); 398 File tofile = new File(toDir.getPath() + File.separator + toName); 399 if (tofile.exists() 402 && !(isWin32 && fromfile.getName().equalsIgnoreCase(toName))) { 403 throw new FileExistsException( 404 "cannot rename from " 405 + fromfile 406 + " to " 407 + tofile 408 + ", destination exists"); 409 } 410 411 if (!fromfile.renameTo(tofile)) { 412 throw new IOException ( 413 "renameTo(" + fromfile + ", " + tofile + ") failed"); 414 } 415 } 416 } 417 418 public void unreferenced() { 419 logger.info("unreferenced"); 420 System.exit(0); 421 } 422 423 426 public int getBufferSize() { 427 return _bufferSize; 428 } 429 430 } 431 | Popular Tags |