1 /* 2 * Created on Jul 16, 2008 3 * Created by Paul Gardner 4 * 5 * Copyright (C) Azureus Software, Inc, All Rights Reserved. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * This program 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 General Public License for more details. 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 */ 19 20 21 package com.aelitis.azureus.core.lws; 22 23 import java.io.File; 24 import java.net.InetSocketAddress; 25 import java.net.URL; 26 27 import org.gudy.azureus2.core3.disk.DiskManager; 28 import org.gudy.azureus2.core3.disk.DiskManagerReadRequest; 29 import org.gudy.azureus2.core3.disk.DiskManagerReadRequestListener; 30 import org.gudy.azureus2.core3.logging.LogEvent; 31 import org.gudy.azureus2.core3.logging.LogIDs; 32 import org.gudy.azureus2.core3.logging.LogRelation; 33 import org.gudy.azureus2.core3.logging.Logger; 34 import org.gudy.azureus2.core3.peer.PEPeer; 35 import org.gudy.azureus2.core3.peer.PEPeerManager; 36 import org.gudy.azureus2.core3.peer.PEPeerManagerFactory; 37 import org.gudy.azureus2.core3.peer.PEPeerManagerListenerAdapter; 38 import org.gudy.azureus2.core3.peer.util.PeerUtils; 39 import org.gudy.azureus2.core3.torrent.TOTorrent; 40 import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncer; 41 import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncerDataProvider; 42 import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncerException; 43 import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncerFactory; 44 import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncerListener; 45 import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncerResponse; 46 import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncerResponsePeer; 47 import org.gudy.azureus2.core3.util.AddressUtils; 48 import org.gudy.azureus2.core3.util.ByteFormatter; 49 import org.gudy.azureus2.core3.util.HashWrapper; 50 import org.gudy.azureus2.core3.util.SystemTime; 51 import org.gudy.azureus2.plugins.torrent.Torrent; 52 import org.gudy.azureus2.pluginsimpl.local.torrent.TorrentImpl; 53 54 import com.aelitis.azureus.core.networkmanager.NetworkConnection; 55 import com.aelitis.azureus.core.networkmanager.NetworkManager; 56 import com.aelitis.azureus.core.peermanager.PeerManager; 57 import com.aelitis.azureus.core.peermanager.PeerManagerRegistration; 58 import com.aelitis.azureus.core.peermanager.PeerManagerRegistrationAdapter; 59 60 61 62 public class 63 LightWeightSeed 64 extends LogRelation 65 implements PeerManagerRegistrationAdapter 66 { 67 private static final byte ACT_NONE = 0; 68 private static final byte ACT_HAS_PEERS = 2; 69 private static final byte ACT_HAS_POTENTIAL_PEERS = 3; 70 private static final byte ACT_INCOMING = 4; 71 private static final byte ACT_NO_PM = 5; 72 private static final byte ACT_TIMING_OUT = 6; 73 private static final byte ACT_TRACKER_ANNOUNCE = 7; 74 private static final byte ACT_TRACKER_SCRAPE = 8; 75 76 private static final int DEACTIVATION_TIMEOUT = 5*60*1000; 77 private static final int DEACTIVATION_WITH_POTENTIAL_TIMEOUT = 15*60*1000; 78 79 final private LightWeightSeedManager manager; 80 final private LightWeightSeedAdapter adapter; 81 final private String name; 82 final private HashWrapper hash; 83 final private URL announce_url; 84 final private File data_location; 85 final private String network; 86 87 private PeerManagerRegistration peer_manager_registration; 88 89 private volatile PEPeerManager peer_manager; 90 private volatile LWSDiskManager disk_manager; 91 private LWSDownload pseudo_download; 92 private volatile LWSTorrent torrent_facade; 93 private TRTrackerAnnouncer announcer; 94 95 private TOTorrent actual_torrent; 96 97 private boolean is_running; 98 private long last_activity_time; 99 private int activation_state = ACT_NONE; 100 101 protected LightWeightSeed( LightWeightSeedManager _manager, String _name, HashWrapper _hash, URL _announce_url, File _data_location, String _network, LightWeightSeedAdapter _adapter )102 LightWeightSeed( 103 LightWeightSeedManager _manager, 104 String _name, 105 HashWrapper _hash, 106 URL _announce_url, 107 File _data_location, 108 String _network, 109 LightWeightSeedAdapter _adapter ) 110 { 111 manager = _manager; 112 name = _name; 113 hash = _hash; 114 announce_url = _announce_url; 115 data_location = _data_location; 116 network = _network; 117 adapter = _adapter; 118 } 119 120 protected String getName()121 getName() 122 { 123 return( name + "/" + ByteFormatter.encodeString( hash.getBytes())); 124 } 125 126 protected Torrent getTorrent()127 getTorrent() 128 { 129 return( new TorrentImpl( getTOTorrent( false ))); 130 } 131 132 protected TOTorrent getTOTorrent( boolean actual )133 getTOTorrent( 134 boolean actual ) 135 { 136 if ( actual ){ 137 138 synchronized( this ){ 139 140 if ( actual_torrent == null ){ 141 142 try{ 143 144 actual_torrent = adapter.getTorrent( hash.getBytes(), announce_url, data_location ); 145 146 }catch( Throwable e ){ 147 148 log( "Failed to get torrent", e ); 149 } 150 151 if ( actual_torrent == null ){ 152 153 throw( new RuntimeException( "Torrent not available" )); 154 } 155 } 156 157 return( actual_torrent ); 158 } 159 }else{ 160 161 return( torrent_facade ); 162 } 163 } 164 165 public HashWrapper getHash()166 getHash() 167 { 168 return( hash ); 169 } 170 171 public URL getAnnounceURL()172 getAnnounceURL() 173 { 174 return( announce_url ); 175 } 176 177 public File getDataLocation()178 getDataLocation() 179 { 180 return( data_location ); 181 } 182 183 public String getNetwork()184 getNetwork() 185 { 186 return( network ); 187 } 188 189 protected long getSize()190 getSize() 191 { 192 return( data_location.length()); 193 } 194 195 public boolean isPeerSourceEnabled( String peer_source )196 isPeerSourceEnabled( 197 String peer_source ) 198 { 199 return( true ); 200 } 201 202 public boolean manualRoute( NetworkConnection connection )203 manualRoute( 204 NetworkConnection connection ) 205 { 206 return false; 207 } 208 209 public byte[][] getSecrets()210 getSecrets() 211 { 212 return( new byte[][]{ hash.getBytes()}); 213 } 214 215 public boolean activateRequest( InetSocketAddress remote_address )216 activateRequest( 217 InetSocketAddress remote_address ) 218 { 219 ensureActive( "Incoming[" + AddressUtils.getHostAddress( remote_address ) + "]", ACT_INCOMING ); 220 221 return( true ); 222 } 223 224 public void deactivateRequest( InetSocketAddress remote_address )225 deactivateRequest( 226 InetSocketAddress remote_address ) 227 { 228 229 } 230 231 public String getDescription()232 getDescription() 233 { 234 return( "LWS: " + getName()); 235 } 236 237 protected synchronized void start()238 start() 239 { 240 log( "Start" ); 241 242 if ( is_running ){ 243 244 log( "Start of '" + getString() + "' failed - already running" ); 245 246 return; 247 } 248 249 if ( peer_manager_registration != null ){ 250 251 log( "Start of '" + getString() + "' failed - router already registered" ); 252 253 return; 254 } 255 256 if ( pseudo_download != null ){ 257 258 log( "Start of '" + getString() + "' failed - pseudo download already registered" ); 259 260 return; 261 } 262 263 if ( disk_manager != null ){ 264 265 log( "Start of '" + getString() + "' failed - disk manager already started" ); 266 267 return; 268 } 269 270 if ( peer_manager != null ){ 271 272 log( "Start of '" + getString() + "' failed - peer manager already started" ); 273 274 return; 275 } 276 277 try{ 278 if ( torrent_facade == null ){ 279 280 torrent_facade = new LWSTorrent( this ); 281 } 282 283 peer_manager_registration = PeerManager.getSingleton().registerLegacyManager( hash, this ); 284 285 announcer = createAnnouncer(); 286 287 pseudo_download = new LWSDownload( this, announcer ); 288 289 manager.addToDHTTracker( pseudo_download ); 290 291 is_running = true; 292 293 last_activity_time = SystemTime.getMonotonousTime(); 294 295 }catch( Throwable e ){ 296 297 log( "Start of '" + getString() + "' failed", e ); 298 299 }finally{ 300 301 if ( is_running ){ 302 303 log( "Started " + getString()); 304 305 }else{ 306 307 stop(); 308 } 309 } 310 } 311 312 protected synchronized void stop()313 stop() 314 { 315 log( "Stop" ); 316 317 try{ 318 if ( disk_manager != null ){ 319 320 disk_manager.stop( false ); 321 322 disk_manager = null; 323 } 324 325 if ( peer_manager != null ){ 326 327 peer_manager.stopAll(); 328 329 peer_manager = null; 330 } 331 332 if ( pseudo_download != null ){ 333 334 manager.removeFromDHTTracker( pseudo_download ); 335 336 pseudo_download = null; 337 } 338 339 if ( announcer != null ){ 340 341 announcer.stop( false ); 342 343 announcer.destroy(); 344 345 announcer = null; 346 } 347 348 if ( peer_manager_registration != null ){ 349 350 peer_manager_registration.unregister(); 351 352 peer_manager_registration = null; 353 } 354 355 }finally{ 356 357 is_running = false; 358 359 activation_state = ACT_NONE; 360 361 log( "Stopped " + getString()); 362 } 363 } 364 365 protected synchronized void activate( String reason_str, byte activation_reason )366 activate( 367 String reason_str, 368 byte activation_reason ) 369 { 370 log( "Activate: " + activation_reason + "/" + reason_str ); 371 372 if ( activation_state != ACT_NONE ){ 373 374 return; 375 } 376 377 try{ 378 disk_manager = new LWSDiskManager( this, data_location ); 379 380 disk_manager.start(); 381 382 if ( disk_manager.getState() != DiskManager.READY ){ 383 384 log( "Start of '" + getString() + "' failed, disk manager failed = " + disk_manager.getErrorMessage()); 385 386 }else{ 387 388 peer_manager = 389 PEPeerManagerFactory.create( 390 announcer.getPeerId(), 391 new LWSPeerManagerAdapter( 392 this, 393 peer_manager_registration ), 394 disk_manager ); 395 396 peer_manager.addListener( 397 new PEPeerManagerListenerAdapter() 398 { 399 public void 400 peerAdded( 401 final PEPeerManager manager, 402 final PEPeer peer ) 403 { 404 last_activity_time = SystemTime.getMonotonousTime(); 405 } 406 407 408 public void 409 peerRemoved( 410 PEPeerManager manager, 411 PEPeer peer ) 412 { 413 last_activity_time = SystemTime.getMonotonousTime(); 414 } 415 }); 416 417 peer_manager.start(); 418 419 announcer.update( true ); 420 421 activation_state = activation_reason; 422 423 last_activity_time = SystemTime.getMonotonousTime(); 424 } 425 426 }catch( Throwable e ){ 427 428 log( "Activation of '" + getString() + "' failed", e ); 429 430 }finally{ 431 432 if ( activation_state != ACT_NONE ){ 433 434 435 }else{ 436 437 deactivate(); 438 } 439 } 440 } 441 442 protected synchronized void deactivate()443 deactivate() 444 { 445 log( "Deactivate" ); 446 447 try{ 448 if ( disk_manager != null ){ 449 450 disk_manager.stop( false ); 451 452 disk_manager = null; 453 } 454 455 if ( peer_manager != null ){ 456 457 peer_manager.stopAll(); 458 459 peer_manager = null; 460 } 461 }finally{ 462 463 activation_state = ACT_NONE; 464 } 465 } 466 467 protected synchronized TRTrackerAnnouncer createAnnouncer()468 createAnnouncer() 469 throws TRTrackerAnnouncerException 470 { 471 472 // use a facade here to delay loading the actual torrent until the 473 // download is activated 474 475 TRTrackerAnnouncer result = TRTrackerAnnouncerFactory.create( torrent_facade, true ); 476 477 result.addListener( 478 new TRTrackerAnnouncerListener() 479 { 480 public void 481 receivedTrackerResponse( 482 TRTrackerAnnouncerResponse response ) 483 { 484 TRTrackerAnnouncerResponsePeer[] peers = response.getPeers(); 485 486 // tracker shouldn't return seeds to seeds to we can assume 487 // that if peers returned this means we have someone to talk to 488 489 if ( peers != null && peers.length > 0 ){ 490 491 ensureActive( "Tracker[" + peers[0].getAddress()+ "]", ACT_TRACKER_ANNOUNCE ); 492 493 }else if ( response.getScrapeIncompleteCount() > 0 ){ 494 495 ensureActive( "Tracker[scrape]", ACT_TRACKER_SCRAPE ); 496 } 497 498 PEPeerManager pm = peer_manager; 499 500 if ( pm != null ){ 501 502 pm.processTrackerResponse( response ); 503 } 504 } 505 506 public void 507 urlChanged( 508 TRTrackerAnnouncer announcer, 509 URL old_url, 510 URL new_url, 511 boolean explicit ) 512 { 513 } 514 515 public void 516 urlRefresh() 517 { 518 } 519 }); 520 521 result.setAnnounceDataProvider( 522 new TRTrackerAnnouncerDataProvider() 523 { 524 public String 525 getName() 526 { 527 return( LightWeightSeed.this.getName()); 528 } 529 530 public long 531 getTotalSent() 532 { 533 return( 0 ); 534 } 535 536 public long 537 getTotalReceived() 538 { 539 return( 0 ); 540 } 541 542 public long 543 getFailedHashCheck() 544 { 545 return( 0 ); 546 } 547 548 public long 549 getRemaining() 550 { 551 return( 0 ); 552 } 553 554 public String 555 getExtensions() 556 { 557 return( null ); 558 } 559 560 public int 561 getMaxNewConnectionsAllowed( 562 String network ) 563 { 564 PEPeerManager pm = peer_manager; 565 566 if ( pm == null ){ 567 568 // got to ask for at least one to trigger activation! 569 570 return( 8 ); 571 } 572 573 return( PeerUtils.numNewConnectionsAllowed( pm.getPeerIdentityDataID(),0)); 574 } 575 576 public int 577 getPendingConnectionCount() 578 { 579 PEPeerManager pm = peer_manager; 580 581 if ( pm == null ){ 582 583 return( 0 ); 584 } 585 586 return( pm.getPendingPeerCount()); 587 } 588 589 public int 590 getConnectedConnectionCount() 591 { 592 PEPeerManager pm = peer_manager; 593 594 if ( pm == null ){ 595 596 return( 0 ); 597 } 598 599 return( pm.getNbPeers() + pm.getNbSeeds()); 600 } 601 602 public int 603 getUploadSpeedKBSec( 604 boolean estimate) 605 { 606 return 0; 607 } 608 609 public int 610 getCryptoLevel() 611 { 612 return( NetworkManager.CRYPTO_OVERRIDE_NONE ); 613 } 614 615 public boolean 616 isPeerSourceEnabled( 617 String peer_source ) 618 { 619 return( true ); 620 } 621 622 public void 623 setPeerSources( 624 String[] sources ) 625 { 626 } 627 }); 628 629 return( result ); 630 } 631 632 protected synchronized void ensureActive( String reason, byte a_reason )633 ensureActive( 634 String reason, 635 byte a_reason ) 636 { 637 if ( is_running && activation_state == ACT_NONE ){ 638 639 activate( reason, a_reason ); 640 } 641 } 642 643 protected synchronized void checkDeactivation()644 checkDeactivation() 645 { 646 if ( activation_state == ACT_NONE ){ 647 648 return; 649 } 650 651 if ( peer_manager == null ){ 652 653 activation_state = ACT_NO_PM; 654 655 return; 656 } 657 658 659 if ( peer_manager.getNbPeers() > 0 ){ 660 661 activation_state = ACT_HAS_PEERS; 662 663 return; 664 } 665 666 long now = SystemTime.getMonotonousTime(); 667 668 long millis_since_last_act = now - last_activity_time; 669 670 if ( peer_manager.hasPotentialConnections()){ 671 672 if ( millis_since_last_act < DEACTIVATION_WITH_POTENTIAL_TIMEOUT ){ 673 674 activation_state = ACT_HAS_POTENTIAL_PEERS; 675 676 return; 677 } 678 } 679 680 if ( millis_since_last_act >= DEACTIVATION_TIMEOUT ){ 681 682 deactivate(); 683 684 }else{ 685 686 activation_state = ACT_TIMING_OUT; 687 } 688 } 689 690 public void enqueueReadRequest( PEPeer peer, DiskManagerReadRequest request, DiskManagerReadRequestListener listener )691 enqueueReadRequest( 692 PEPeer peer, 693 DiskManagerReadRequest request, 694 DiskManagerReadRequestListener listener ) 695 { 696 LWSDiskManager dm = disk_manager; 697 698 if ( dm == null ){ 699 700 listener.readFailed( request, new Throwable( "download is stopped" )); 701 702 }else{ 703 704 dm.enqueueReadRequest( request, listener ); 705 } 706 } 707 708 public void remove()709 remove() 710 { 711 manager.remove( this ); 712 } 713 714 public String getRelationText()715 getRelationText() 716 { 717 return "LWS: '" + getName() + "'"; 718 } 719 720 public Object[] getQueryableInterfaces()721 getQueryableInterfaces() 722 { 723 return new Object[]{}; 724 } 725 726 public LogRelation getRelation()727 getRelation() 728 { 729 return( this ); 730 } 731 732 protected String getString()733 getString() 734 { 735 return( getName()); 736 } 737 738 protected void log( String str )739 log( 740 String str ) 741 { 742 Logger.log(new LogEvent(this, LogIDs.CORE, str )); 743 } 744 745 protected void log( String str, Throwable e )746 log( 747 String str, 748 Throwable e ) 749 { 750 Logger.log(new LogEvent(this, LogIDs.CORE, str, e )); 751 } 752 } 753