java.lang.Object
org.klomp.snark.Peer
- All Implemented Interfaces:
Comparable<Peer>, BandwidthListener
- Direct Known Subclasses:
WebPeer
Represents a peer in the BitTorrent network, managing all public information and communication with that peer.
This class handles:
- Peer identification and handshaking
- BitTorrent protocol communication
- Upload/download statistics tracking
- Connection state management
- Bandwidth monitoring and limiting
Peers can be either incoming (they connected to us) or outgoing (we connected to them) connections.
Field Summary
FieldsModifier and TypeFieldDescriptionprivate static final AtomicLongCounter numbering the peer objects.private final AtomicBooleanTrue once the peer has been disconnected.private final DontHaveMemoPieces the peer told us it does not have.private final longThis peer's id, for the logs.private final booleanTrue if we accepted the connection.protected final LogLogger for this peer instance.private intMaximum pipelined requests for the peer.private intComments sent to the peer so far.private booleanTrue if the peer only receives uploads.(package private) static final longHow often to recompute upload slots and UI download speeds.private longWhen the peer connected.private booleanTrue to deregister the peer when it disconnects.private DataInputStreamStream reading the data from the peer.private DataOutputStreamStream writing the data to the peer.private final AtomicLongRunning counters.private final long[]Download totals at the rate stat boundaries.private static final byte[]Protocol name sent in the handshake.private static final longBound on the socket read timeout while reading the handshake, to avoid hanging a thread on a stalled peer.The handshake map received from the peer.protected final byte[]SHA-1 of this torrent's info dictionary, sent in the handshake and checked against the remote copy.(package private) MagnetStateShared across all peers on this torrent.protected MetaInfoWill start out null in magnet mode.private final byte[]Our 20-byte peer id.private static final longExtension protocol option bit.private static final longFast extension option bit.private longOptions negotiated with the peer.private final PeerIDThe remote peer's id.private longWhen PEX was last sent to the peer.(package private) static final intNumber of samples in the upload/download rate windows.private I2PSocketThe socket connected to the peer.(package private) PeerState` Keeps state for in/out connections.private final AtomicLongBytes uploaded to this peer.private final long[]Upload totals at the rate stat boundaries.Constructor Summary
ConstructorsConstructorDescriptionPeer(I2PSocket sock, InputStream in, OutputStream out, byte[] myId, byte[] infohash, MetaInfo metainfo) Incoming connection.Outgoing connection.Method Summary
Modifier and TypeMethodDescriptionvoidaddDontHave(int piece) Remember that this peer said it no longer has the piece (BEP 54 dont_have), so it is not re-requested from this peer until the remembered state expires, even if it re-announces HAVE.(package private) voidcancel(int piece) Tell the other side that we are no longer interested in any of the outstanding requests (if any) for this piece.intCompares this peer to another byPeerID, then by internal ID.intReturn how much the peer has.(package private) voidDisconnects this peer, closing the socket and cleaning up state.voiddisconnect(boolean deregister) Disconnects this peer if it was connected.booleandontHave(int piece) Whether this peer recently said it does not have the piece (BEP 54 dont_have).voiddownloaded(int size) BandwidthListener interface - increments the download counter for this peer.booleanTwo Peers are equal when they have the same PeerID.Returns the I2P destination of the connected peer.longCurrent limit in Bps.longReturns the number of bytes that have been downloaded.longReturns the average rate in Bps.Returns the extension handshake data from the peer.(package private) I2PSocketThe I2PSocket of this connection, or null if never connected.longReturns the time in milliseconds since the last activity on either the incoming or outgoing connection.Returns the shared magnet state across all peers on this torrent.longThe max inactive time.intReturns the maximum request pipeline depth negotiated with the peer.This peer's ID, assigned when it was created.longReturns the timestamp when PEX peers were last sent to this peer.Socket debug string, for debug printing.(package private) intReturns the total number of UT comments sent to this peer.longCurrent limit in Bps.longReturns the number of bytes that have been uploaded.longReturns the average rate in Bps.longReturns the timestamp when the handshake completed.private byte[]handshake(InputStream in, OutputStream out) Perform the handshake over the data streams and return the ID reported by the other side.inthashCode()The hash code of a Peer is the hash code of the peerID.voidhave(int piece) Notifies the peer that we have a new piece.booleanisChoked()Whether or not the peer choked us.booleanWhether or not we are choking the peer.booleanReturn if a peer is a seeder.booleanReturns whether the peer is in active communication.booleanReturns whether this is an incoming connection (initiated by the remote peer).booleanWhether or not the peer is interested in pieces we have.booleanWhether or not the peer has pieces we want from it.booleanWhether or not the peer is snubbing us (unchoked but not requesting).booleanWhether the peer declared itself a partial seed (BEP 21 upload_only).booleanReturns whether this is a web peer.voidSend keepalive.booleanAre we currently over the limit?booleanIs snark as a whole over its limit?(package private) voidrequest()Update the request queue.voidRetransmit outstanding requests if necessary Does nothing ifsupportsFast().voidrunConnection(I2PSnarkUtil util, PeerListener listener, BandwidthListener bwl, BitField bitfield, MagnetState mState, boolean uploadOnly) Runs the connection to the other peer.voidsendExtension(int type, byte[] payload) Sends a protocol extension message to the peer.voidsetChoking(boolean choke) Whether we are choking the peer.voidsetHandshakeMap(Map<String, BEValue> map) Store the extension handshake data and update the request pipeline limit.voidsetMetaInfo(MetaInfo meta) Switches from magnet mode to normal mode with metainfo.voidsetPexLastSent(long now) Store the timestamp when PEX peers were last sent to this peer.(package private) voidPush the total uploaded/downloaded onto a RATE_DEPTH deep stack.(package private) voidsetTotalCommentsSent(int count) Store the total number of UT comments sent to this peer.voidsetUploadOnly(boolean uploadOnly) The peer declared itself a partial seed (BEP 21 upload_only).booleanshouldRequest(int size) Should we request this many bytes?booleanshouldRequest(Peer peer, int size) Should we request this many bytes? Only true for this peer, which is how a callback that was handed one peer is prevented from answering for another.booleanshouldSend(int size) Should we send this many bytes? Do NOT calluploadedafter this.booleanReturns whether the peer supports the FAST protocol extension (BEP 6).toString()Returns the String representation of the peerID.voiduploaded(int size) Increments the upload counter for this peer.
Field Details
_log
Logger for this peer instance.peerID
The remote peer's id.my_id
private final byte[] my_idOur 20-byte peer id.infohash
protected final byte[] infohashSHA-1 of this torrent's info dictionary, sent in the handshake and checked against the remote copy.metainfo
Will start out null in magnet mode.handshakeMap
din
Stream reading the data from the peer.dout
Stream writing the data to the peer.downloaded
Running counters.uploaded
Bytes uploaded to this peer.state
` Keeps state for in/out connections. Non-null when the handshake was successful, the connection setup and runs. Do not access directly. All actions should be through Peer methods.magnetState
MagnetState magnetStateShared across all peers on this torrent.sock
The socket connected to the peer.deregister
private boolean deregisterTrue to deregister the peer when it disconnects.__id
Counter numbering the peer objects._id
private final long _idThis peer's id, for the logs._disconnected
True once the peer has been disconnected.CHECK_PERIOD
static final long CHECK_PERIODHow often to recompute upload slots and UI download speeds.- See Also:
RATE_DEPTH
static final int RATE_DEPTHNumber of samples in the upload/download rate windows.- See Also:
uploaded_old
private final long[] uploaded_oldUpload totals at the rate stat boundaries.downloaded_old
private final long[] downloaded_oldDownload totals at the rate stat boundaries.HANDSHAKE
private static final byte[] HANDSHAKEProtocol name sent in the handshake.OPTION_EXTENSION
private static final long OPTION_EXTENSIONExtension protocol option bit.- See Also:
OPTION_FAST
options
private long optionsOptions negotiated with the peer._isIncoming
private final boolean _isIncomingTrue if we accepted the connection._uploadOnly
private volatile boolean _uploadOnlyTrue if the peer only receives uploads._dontHave
Pieces the peer told us it does not have._totalCommentsSent
private int _totalCommentsSentComments sent to the peer so far._maxPipeline
private int _maxPipelineMaximum pipelined requests for the peer.connected
private long connectedWhen the peer connected.pexLastSent
private long pexLastSentWhen PEX was last sent to the peer.HANDSHAKE_READ_TIMEOUT
private static final long HANDSHAKE_READ_TIMEOUTBound on the socket read timeout while reading the handshake, to avoid hanging a thread on a stalled peer.- See Also:
Constructor Details
Peer
Outgoing connection. Creates a disconnected peer given a PeerID, your own id and the relevant MetaInfo.- Parameters:
peerID- the remote peer's IDmyId- our own peer ID, sent during the handshakeinfohash- the info hash of the torrentmetainfo- null if in magnet mode
Peer
public Peer(I2PSocket sock, InputStream in, OutputStream out, byte[] myId, byte[] infohash, MetaInfo metainfo) throws IOException Incoming connection. Creates a unconnected peer from the input and output stream got from the socket. Note that the complete handshake (which can take some time or block indefinitely) is done in the calling Thread to get the remote peer id. To completely start the connection call the connect() method.- Parameters:
sock- the connected socket the handshake runs overin- the stream the handshake is read fromout- the stream the handshake is written tomyId- our own peer ID, sent during the handshakeinfohash- the info hash of the torrentmetainfo- null if in magnet mode- Throws:
IOException- when an error occurred during the handshake.
Method Details
isIncoming
public boolean isIncoming()Returns whether this is an incoming connection (initiated by the remote peer).- Returns:
- true if incoming, false if outgoing
setUploadOnly
public void setUploadOnly(boolean uploadOnly) The peer declared itself a partial seed (BEP 21 upload_only).A partial seed has some files but does not want to download anything more.
- Parameters:
uploadOnly- whether the peer is a partial seed
isUploadOnly
public boolean isUploadOnly()Whether the peer declared itself a partial seed (BEP 21 upload_only).A partial seed has some files but does not want to download anything more.
- Returns:
- true if the peer is a partial seed
addDontHave
public void addDontHave(int piece) Remember that this peer said it no longer has the piece (BEP 54 dont_have), so it is not re-requested from this peer until the remembered state expires, even if it re-announces HAVE.- Parameters:
piece- the piece index
dontHave
public boolean dontHave(int piece) Whether this peer recently said it does not have the piece (BEP 54 dont_have).- Parameters:
piece- the piece index- Returns:
- true if within the retention window
getPeerID
This peer's ID, assigned when it was created.- Returns:
- the peer ID this peer was created with
toString
getSocket
Socket debug string, for debug printing.- Returns:
- socket debug string (for debug printing)
getI2PSocket
I2PSocket getI2PSocket()The I2PSocket of this connection, or null if never connected.- Returns:
- the socket backing this connection, or null if never connected
hashCode
equals
compareTo
Compares this peer to another byPeerID, then by internal ID.- Specified by:
compareToin interfaceComparable<Peer>- Parameters:
p- the peer to compare to- Returns:
- a negative, zero, or positive integer
runConnection
public void runConnection(I2PSnarkUtil util, PeerListener listener, BandwidthListener bwl, BitField bitfield, MagnetState mState, boolean uploadOnly) Runs the connection to the other peer. This method does not return until the connection is terminated.When the connection is correctly started the connected() method of the given PeerListener is called. If the connection ends or the connection could not be setup correctly the disconnected() method is called.
If the given BitField is non-null it is send to the peer as first message.
- Parameters:
util- the utility holding this client's connection settingslistener- notified when the connection is established or endsbwl- the bandwidth limiter this peer's traffic is accounted againstbitfield- the bitfield sent as the first message, or null to send nonemState- the magnet state recording this peer's piece availabilityuploadOnly- if we are complete with skipped files, i.e. a partial seed
handshake
Perform the handshake over the data streams and return the ID reported by the other side.- Parameters:
in- the socket input stream to read the peer's handshake fromout- the socket output stream to write our handshake to- Returns:
- the 20-byte peer ID reported by the other side
- Throws:
IOException- if the peer's handshake is malformed or its metainfo hash does not match ours
supportsFast
public boolean supportsFast()Returns whether the peer supports the FAST protocol extension (BEP 6).- Returns:
- true if FAST extension is supported
getDestination
Returns the I2P destination of the connected peer.- Returns:
- the peer's Destination, or null if not connected
getMagnetState
Returns the shared magnet state across all peers on this torrent. Callers must synchronize on the returned object.- Returns:
- the magnet state (non-null)
getHandshakeMap
setHandshakeMap
getMaxPipeline
public int getMaxPipeline()Returns the maximum request pipeline depth negotiated with the peer.- Returns:
- the max pipeline depth, bounded by MIN_PIPELINE and MAX_PIPELINE
sendExtension
public void sendExtension(int type, byte[] payload) Sends a protocol extension message to the peer.- Parameters:
type- the extension message typepayload- the extension message payload
setMetaInfo
Switches from magnet mode to normal mode with metainfo.- Parameters:
meta- the metainfo to set
isConnected
public boolean isConnected()Returns whether the peer is in active communication.- Returns:
- true if the peer has an active PeerState
disconnect
public void disconnect(boolean deregister) Disconnects this peer if it was connected.PeerListener.disconnected(Peer)will be called when the connection is completely terminated. If deregister is true, partial pieces will be returned.- Parameters:
deregister- true if partial pieces should be returned
disconnect
void disconnect()Disconnects this peer, closing the socket and cleaning up state. Partial pieces are returned if deregister is true.have
public void have(int piece) Notifies the peer that we have a new piece.- Parameters:
piece- the piece index
cancel
void cancel(int piece) Tell the other side that we are no longer interested in any of the outstanding requests (if any) for this piece.- Parameters:
piece- the piece index
request
void request()Update the request queue. Call after adding wanted pieces.isInterested
public boolean isInterested()Whether or not the peer is interested in pieces we have.- Returns:
- true if interested, false if not connected
isInteresting
public boolean isInteresting()Whether or not the peer has pieces we want from it.- Returns:
- true if interesting, false if not connected
setChoking
public void setChoking(boolean choke) Whether we are choking the peer. Defaults to true. When choke is false and the peer requests some pieces we upload them, otherwise requests of this peer are ignored.- Parameters:
choke- true to choke (stop uploading), false to unchoke (allow uploads)
isChoking
public boolean isChoking()Whether or not we are choking the peer.- Returns:
- true when choking or not connected
isChoked
public boolean isChoked()Whether or not the peer choked us.- Returns:
- true when choked or not connected
isSnubbing
public boolean isSnubbing()Whether or not the peer is snubbing us (unchoked but not requesting).- Returns:
- true if snubbing, false if not connected
downloaded
public void downloaded(int size) BandwidthListener interface - increments the download counter for this peer.- Specified by:
downloadedin interfaceBandwidthListener- Parameters:
size- the number of bytes downloaded
uploaded
public void uploaded(int size) Increments the upload counter for this peer.- Specified by:
uploadedin interfaceBandwidthListener- Parameters:
size- the number of bytes uploaded
getDownloaded
public long getDownloaded()Returns the number of bytes that have been downloaded. Can be reset to zero withresetCounters()which is called every CHECK_PERIOD byPeerCheckerTask.- Returns:
- the downloaded byte count since the last counter reset
getUploaded
public long getUploaded()Returns the number of bytes that have been uploaded. Can be reset to zero withresetCounters()which is called every CHECK_PERIOD by PeerCheckerTask.- Returns:
- the uploaded byte count since the last counter reset
getUploadRate
public long getUploadRate()Returns the average rate in Bps.- Specified by:
getUploadRatein interfaceBandwidthListener- Returns:
- average upload rate in bytes per second
getDownloadRate
public long getDownloadRate()Returns the average rate in Bps.- Specified by:
getDownloadRatein interfaceBandwidthListener- Returns:
- average download rate in bytes per second
shouldSend
public boolean shouldSend(int size) Should we send this many bytes? Do NOT calluploadedafter this.- Specified by:
shouldSendin interfaceBandwidthListener- Parameters:
size- the number of bytes to send- Returns:
- true if the bandwidth listener allows the send, which is then counted
shouldRequest
public boolean shouldRequest(int size) Should we request this many bytes?- Parameters:
size- the number of bytes about to be requested- Returns:
- true if the bandwidth listener allows this peer to request them
shouldRequest
Should we request this many bytes? Only true for this peer, which is how a callback that was handed one peer is prevented from answering for another.- Specified by:
shouldRequestin interfaceBandwidthListener- Parameters:
peer- the peer the callback was invoked forsize- the requested size in bytes- Returns:
- true only if peer is this peer and the listener allows the request
getUpBWLimit
public long getUpBWLimit()Current limit in Bps.- Specified by:
getUpBWLimitin interfaceBandwidthListener- Returns:
- the up b w limit
overUpBWLimit
public boolean overUpBWLimit()Is snark as a whole over its limit?- Specified by:
overUpBWLimitin interfaceBandwidthListener- Returns:
- true if over the upload limit, false otherwise
getDownBWLimit
public long getDownBWLimit()Current limit in Bps.- Specified by:
getDownBWLimitin interfaceBandwidthListener- Returns:
- the down b w limit
overDownBWLimit
public boolean overDownBWLimit()Are we currently over the limit?- Specified by:
overDownBWLimitin interfaceBandwidthListener- Returns:
- true if over the download limit, false otherwise
setRateHistory
void setRateHistory()Push the total uploaded/downloaded onto a RATE_DEPTH deep stack. Resets the downloaded and uploaded counters to zero.getInactiveTime
public long getInactiveTime()Returns the time in milliseconds since the last activity on either the incoming or outgoing connection.- Returns:
- inactive time in ms, or -1 if not connected
getMaxInactiveTime
public long getMaxInactiveTime()The max inactive time.- Returns:
- inactivity limit in ms before the peer is disconnected
keepAlive
public void keepAlive()Send keepalive.retransmitRequests
public void retransmitRequests()Retransmit outstanding requests if necessary Does nothing ifsupportsFast().completed
public int completed()Return how much the peer has.- Returns:
- number of completed pieces (not bytes)
isCompleted
public boolean isCompleted()Return if a peer is a seeder.- Returns:
- true if the peer has all pieces
getTotalCommentsSent
int getTotalCommentsSent()Returns the total number of UT comments sent to this peer.- Returns:
- the comment count
setTotalCommentsSent
void setTotalCommentsSent(int count) Store the total number of UT comments sent to this peer.- Parameters:
count- the count to set
isWebPeer
public boolean isWebPeer()Returns whether this is a web peer.- Returns:
- false (base Peer is never a web peer)
getWhenConnected
public long getWhenConnected()Returns the timestamp when the handshake completed.- Returns:
- the connection timestamp in milliseconds
getPexLastSent
public long getPexLastSent()Returns the timestamp when PEX peers were last sent to this peer.- Returns:
- the last PEX timestamp in milliseconds
setPexLastSent
public void setPexLastSent(long now) Store the timestamp when PEX peers were last sent to this peer.- Parameters:
now- the current timestamp in milliseconds