📄 pepeercontrolimpl.java
字号:
public int getPieceLength(int pieceNumber) {
if (pieceNumber ==_nbPieces -1)
return disk_mgr.getLastPieceLength();
return disk_mgr.getPieceLength();
}
public int
getNbPeers()
{
return _peers;
}
public int getNbSeeds()
{
return _seeds;
}
public int getNbRemoteConnections()
{
return _remotes;
}
public long getLastRemoteConnectionTime()
{
return( last_remote_time );
}
public PEPeerManagerStats getStats() {
return _stats;
}
public int
getNbPeersStalledPendingLoad()
{
int res = 0;
Iterator it = peer_transports_cow.iterator();
while( it.hasNext()){
PEPeerTransport transport = (PEPeerTransport)it.next();
if ( transport.isStalledPendingLoad()){
res ++;
}
}
return( res );
}
/**
* Returns the ETA time in seconds.
* If the returned time is 0, the download is complete.
* If the returned time is negative, the download
* is complete and it took -xxx time to complete.
*/
public long
getETA()
{
final long now = SystemTime.getCurrentTime();
if ( now < last_eta_calculation || now - last_eta_calculation > 900 ){
long dataRemaining = disk_mgr.getRemainingExcludingDND();
if ( dataRemaining > 0 ){
int writtenNotChecked = 0;
for (int i = 0; i < _nbPieces; i++)
{
if (dm_pieces[i].isInteresting()){
writtenNotChecked +=dm_pieces[i].getNbWritten() *DiskManager.BLOCK_SIZE;
}
}
dataRemaining = dataRemaining - writtenNotChecked;
if (dataRemaining < 0 ){
dataRemaining = 0;
}
}
long result;
if (dataRemaining == 0) {
final long timeElapsed = (_timeFinished - _timeStarted)/1000;
//if time was spent downloading....return the time as negative
if(timeElapsed > 1){
result = timeElapsed * -1;
}else{
result = 0;
}
}else{
final long averageSpeed = _averageReceptionSpeed.getAverage();
long lETA = (averageSpeed == 0) ? Constants.INFINITY_AS_INT : dataRemaining / averageSpeed;
// stop the flickering of ETA from "Finished" to "x seconds" when we are
// just about complete, but the data rate is jumpy.
if (lETA == 0)
lETA = 1;
result = lETA;
}
last_eta = result;
last_eta_calculation = now;
}
return( last_eta );
}
private void
addToPeerTransports(
PEPeerTransport peer )
{
boolean added = false;
try{
peer_transports_mon.enter();
// if it is already disconnected (synchronous failure during connect
// for example) don't add it
if ( peer.getPeerState() == PEPeer.DISCONNECTED ){
return;
}
if( peer_transports_cow.contains( peer ) ){
Debug.out( "Transport added twice" );
return; //we do not want to close it
}
if( is_running ) {
//copy-on-write semantics
final ArrayList new_peer_transports = new ArrayList(peer_transports_cow.size() +1);
new_peer_transports.addAll( peer_transports_cow );
new_peer_transports.add( peer );
peer_transports_cow = new_peer_transports;
added = true;
}
}
finally{
peer_transports_mon.exit();
}
if( added ) {
if ( peer.isIncoming()){
long connect_time = SystemTime.getCurrentTime();
if ( connect_time > last_remote_time ){
last_remote_time = connect_time;
}
}
peerAdded( peer );
}
else {
peer.closeConnection( "PeerTransport added when manager not running" );
}
}
// the peer calls this method itself in closeConnection() to notify this manager
public void peerConnectionClosed( PEPeerTransport peer, boolean connect_failed ) {
boolean connection_found = false;
try{
peer_transports_mon.enter();
int udp_port = peer.getUDPListenPort();
if ( is_running && connect_failed && peer.isTCP() && UDPNetworkManager.UDP_OUTGOING_ENABLED && udp_port > 0 ){
PeerItem peer_item = peer.getPeerItemIdentity();
PeerItem self_item = peer_database.getSelfPeer();
if ( self_item == null || !self_item.equals( peer_item )){
// candidate for a fallback UDP connection attempt
String ip = peer.getIp();
String key = ip + ":" + udp_port;
udp_fallbacks.put( key, peer_item );
}
}
if( peer_transports_cow.contains( peer )) {
final ArrayList new_peer_transports = new ArrayList( peer_transports_cow );
new_peer_transports.remove(peer);
peer_transports_cow = new_peer_transports;
connection_found = true;
}
}
finally{
peer_transports_mon.exit();
}
if ( connection_found ){
if( peer.getPeerState() != PEPeer.DISCONNECTED ) {
System.out.println( "peer.getPeerState() != PEPeer.DISCONNECTED: " +peer.getPeerState() );
}
peerRemoved( peer ); //notify listeners
}
}
public void
peerAdded(
PEPeer pc)
{
adapter.addPeer(pc); //async downloadmanager notification
//sync peermanager notification
final ArrayList peer_manager_listeners = peer_manager_listeners_cow;
for( int i=0; i < peer_manager_listeners.size(); i++ ) {
((PEPeerManagerListener)peer_manager_listeners.get(i)).peerAdded( this, pc );
}
}
public void
peerRemoved(
PEPeer pc)
{
final int piece = pc.getUniqueAnnounce();
if(piece != -1 && superSeedMode ) {
superSeedModeNumberOfAnnounces--;
superSeedPieces[piece].peerLeft();
}
int reserved_piece = pc.getReservedPieceNumber();
if ( reserved_piece >= 0 ){
PEPiece pe_piece = pePieces[reserved_piece];
if ( pe_piece != null ){
String reserved_by = pe_piece.getReservedBy();
if ( reserved_by != null && reserved_by.equals( pc.getIp())){
pe_piece.setReservedBy( null );
}
}
}
adapter.removePeer(pc); //async downloadmanager notification
//sync peermanager notification
final ArrayList peer_manager_listeners = peer_manager_listeners_cow;
for( int i=0; i < peer_manager_listeners.size(); i++ ) {
((PEPeerManagerListener)peer_manager_listeners.get(i)).peerRemoved( this, pc );
}
}
/** Don't pass a null to this method. All activations of pieces must go through here.
* @param piece PEPiece invoked; notifications of it's invocation need to be done
* @param pieceNumber of the PEPiece
*/
public void addPiece(final PEPiece piece, final int pieceNumber)
{
addPiece( piece, pieceNumber, false );
}
protected void addPiece(final PEPiece piece, final int pieceNumber, final boolean force_add )
{
pePieces[pieceNumber] =(PEPieceImpl)piece;
nbPiecesActive++;
if ( is_running || force_add ){
// deal with possible piece addition by scheduler loop after closdown started
adapter.addPiece(piece);
}
}
/** Sends messages to listeners that the piece is no longer active. All closing
* out (deactivation) of pieces must go through here. The piece will be null upon return.
* @param pePiece PEPiece to remove
* @param pieceNumber int
*/
public void removePiece(PEPiece pePiece, int pieceNumber) {
adapter.removePiece(pePiece);
pePieces[pieceNumber] =null;
nbPiecesActive--;
}
public int getNbActivePieces()
{
return nbPiecesActive;
}
public String getElapsedTime() {
return TimeFormatter.format((SystemTime.getCurrentTime() - _timeStarted) / 1000);
}
// Returns time started in ms
public long getTimeStarted() {
return _timeStarted;
}
public long getTimeStartedSeeding() {
return _timeStartedSeeding;
}
private byte[] computeMd5Hash(DirectByteBuffer buffer)
{
BrokenMd5Hasher md5 =new BrokenMd5Hasher();
md5.reset();
final int position =buffer.position(DirectByteBuffer.SS_DW);
md5.update(buffer.getBuffer(DirectByteBuffer.SS_DW));
buffer.position(DirectByteBuffer.SS_DW, position);
ByteBuffer md5Result =ByteBuffer.allocate(16);
md5Result.position(0);
md5.finalDigest(md5Result);
final byte[] result =new byte[16];
md5Result.position(0);
for (int i =0; i <result.length; i++ )
{
result[i] =md5Result.get();
}
return result;
}
private void MD5CheckPiece(PEPiece piece, boolean correct)
{
final String[] writers =piece.getWriters();
int offset =0;
for (int i =0; i <writers.length; i++ )
{
final int length =piece.getBlockSize(i);
final String peer =writers[i];
if (peer !=null)
{
DirectByteBuffer buffer =disk_mgr.readBlock(piece.getPieceNumber(), offset, length);
if (buffer !=null)
{
final byte[] hash =computeMd5Hash(buffer);
buffer.returnToPool();
buffer =null;
piece.addWrite(i, peer, hash, correct);
}
}
offset +=length;
}
}
public void checkCompleted(DiskManagerCheckRequest request, boolean passed)
{
try
{
piece_check_result_list_mon.enter();
piece_check_result_list.add(new Object[]{request, new Integer(passed ?1 :0)});
} finally
{
piece_check_result_list_mon.exit();
}
}
public void checkCancelled(DiskManagerCheckRequest request)
{
try
{
piece_check_result_list_mon.enter();
piece_check_result_list.add(new Object[]{request, new Integer(2)});
} finally
{
piece_check_result_list_mon.exit();
}
}
public void checkFailed(DiskManagerCheckRequest request, Throwable cause)
{
try
{
piece_check_result_list_mon.enter();
piece_check_result_list.add(new Object[]{request, new Integer(0)});
} finally
{
piece_check_result_list_mon.exit();
}
}
public boolean needsMD5CheckOnCompletion(int pieceNumber)
{
final PEPieceImpl piece = pePieces[pieceNumber];
if (piece == null)
{
return false;
}
return piece.getPieceWrites().size() > 0;
}
private void processPieceCheckResult(DiskManagerCheckRequest request, int outcome)
{
final int check_type =((Integer) request.getUserData()).intValue();
try
{
final int pieceNumber =request.getPieceNumber();
// System.out.println( "processPieceCheckResult(" + _finished + "/" + recheck_on_completion + "):" + pieceNumber +
// "/" + piece + " - " + result );
// passed = 1, failed = 0, cancelled = 2
if (check_type ==CHECK_REASON_COMPLETE){
// this is a recheck, so don't send HAVE msgs
if (outcome ==0)
{
// piece failed; restart the download afresh
Debug.out(getDisplayName() + ": Piece #" +pieceNumber +" failed final re-check. Re-downloading...");
if (!restart_initiated)
{
restart_initiated =true;
adapter.restartDownload();
}
}
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -