|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectcom.limegroup.gnutella.Connection
A Gnutella messaging connection. Provides handshaking functionality and routines for reading and writing of Gnutella messages. A connection is either incoming (created from a Socket) or outgoing (created from an address). This class does not provide sophisticated buffering or routing logic; use ManagedConnection for that.
You will note that the constructors don't actually involve the network and hence never throw exceptions or block. To actual initialize a connection, you must call initialize(). While this is somewhat awkward, it is intentional. It makes it easier, for example, for the GUI to show uninitialized connections.
Connection supports only 0.6 handshakes. Gnutella 0.6 connections have a list of properties read and written during the handshake sequence. Typical property/value pairs might be "Query-Routing: 0.3" or "User-Agent: LimeWire".
This class augments the basic 0.6 handshaking mechanism to allow authentication via "401" messages. Authentication interactions can take multiple rounds.
This class supports reading and writing streams using 'deflate' compression. The HandshakeResponser is what actually determines whether or not deflate will be used. This class merely looks at what the responses are in order to set up the appropriate streams. Compression is implemented by chaining the input and output streams, meaning that even if an extending class implements getInputStream() and getOutputStream(), the actual input and output stream used may not be an instance of the expected class. However, the information is still chained through the appropriate stream.
The amount of bytes written and received are maintained by this class. This is necessary because of compression and decompression are considered implementation details in this class.
Finally, Connection also handles setting the SOFT_MAX_TTL on a per-connection basis. The SOFT_MAX TTL is the limit for hops+TTL on all incoming traffic, with the exception of query hits. If an incoming message has hops+TTL greater than SOFT_MAX, we set the TTL to SOFT_MAX-hops. We do this on a per-connection basis because on newer connections that understand X-Max-TTL, we can regulate the TTLs they send us. This helps prevent malicious hosts from using headers like X-Max-TTL to simply get connections. This way, they also have to abide by the contract of the X-Max-TTL header, illustrated by sending lower TTL traffic generally.
Field Summary | |
static java.lang.String |
_200_OK
|
protected boolean |
_closed
Trigger an opening connection to close after it opens. |
protected MessagesSupportedVendorMessage |
_messagesSupported
The possibly non-null VendorMessagePayload which describes what VendorMessages the guy on the other side of this connection supports. |
static java.lang.String |
CONNECT
|
protected static java.io.IOException |
CONNECTION_CLOSED
Cache the 'connection closed' exception, so we have to allocate one for every closed connection. |
static java.lang.String |
CRLF
End of line for Gnutella 0.6 |
static java.lang.String |
GNUTELLA_06
|
static java.lang.String |
GNUTELLA_06_200
|
static java.lang.String |
GNUTELLA_OK_06
Gnutella 0.6 accept connection string. |
static int |
MAX_HANDSHAKE_ATTEMPTS
The number of times we will respond to a given challenge from the other side, or otherwise, during connection handshaking |
static int |
USER_INPUT_WAIT_TIME
Time to wait for inut from user at the remote end. |
Constructor Summary | |
Connection(java.net.Socket socket,
HandshakeResponder responseHeaders)
Creates an uninitialized incoming 0.6 Gnutella connection. |
|
Connection(java.lang.String host,
int port,
java.util.Properties requestHeaders,
HandshakeResponder responseHeaders)
Creates an uninitialized outgoing Gnutella 0.6 connection with the desired outgoing properties, possibly reverting to Gnutella 0.4 if needed. |
Method Summary | |
boolean |
allowNewPings()
Returns whether or not we should allow new pings on this connection. |
boolean |
allowNewPongs()
Returns whether or not we should allow new pongs on this connection. |
void |
close()
Closes the Connection's socket and thus the connection itself. |
void |
flush()
Flushes any buffered messages sent through the send method. |
long |
getBytesReceived()
Returns the number of bytes received on this connection. |
long |
getBytesSent()
Returns the number of bytes sent on this connection. |
long |
getConnectionTime()
Returns the time this connection was established, in milliseconds since January 1, 1970. |
java.lang.String |
getDomainsAuthenticated()
Returns the authenticated domains listed in the connection headers for this connection. |
java.net.InetAddress |
getInetAddress()
Returns the address of the foreign host this is connected to. |
protected java.io.InputStream |
getInputStream()
Returns the stream to use for reading from s. |
java.lang.String |
getIPString()
Returns the IP address of the remote host as a string. |
int |
getListeningPort()
Accessor for the port number this connection is listening on. |
int |
getNumIntraUltrapeerConnections()
Returns the number of intra-Ultrapeer connections this node maintains. |
protected java.io.OutputStream |
getOutputStream()
Returns the stream to use for writing to s. |
java.lang.String |
getPropertyWritten(java.lang.String name)
Returns the value of the given outgoing (written) connection property, or null if no such property. |
float |
getReadSavedFromCompression()
Returns the percentage saved from having the incoming data compressed. |
float |
getSentSavedFromCompression()
Returns the percentage saved through compressing the outgoing data. |
java.net.Socket |
getSocket()
Accessor for the Socket for this connection. |
byte |
getSoftMax()
Accessor for the soft max TTL to use for this connection. |
long |
getUncompressedBytesReceived()
Returns the number of uncompressed bytes read on this connection. |
long |
getUncompressedBytesSent()
Returns the number of uncompressed bytes sent on this connection. |
java.lang.String |
getUserAgent()
Returns the vendor string reported by this connection, i.e., the USER_AGENT property, or null if it wasn't set. |
java.lang.String |
getVersion()
Accessor for the LimeWire version reported in the connection headers for this node. |
protected void |
handleVendorMessage(VendorMessage vm)
Call this method when you want to handle us to handle a VM. |
HandshakeResponse |
headers()
Accessor for the HandshakeResponse instance containing all of the Gnutella connection headers passed by this node. |
void |
initialize()
Initializes this without timeout; exactly like initialize(0). |
void |
initialize(int timeout)
Initialize the connection by doing the handshake. |
boolean |
isClientSupernodeConnection()
Returns true iff the connection is an Ultrapeer and I am a leaf, i.e., if I wrote "X-Ultrapeer: false", this connection wrote "X-Ultrapeer: true" (not necessarily in that order). |
boolean |
isConnectBackCapable()
Returns true if the this connection is potentially on the 'same' network. |
boolean |
isGoodLeaf()
|
boolean |
isGoodUltrapeer()
|
boolean |
isGUESSCapable()
Returns whether or not this connection is to a client supporting GUESS. |
boolean |
isGUESSUltrapeer()
Returns whether or not this connection is to a ultrapeer supporting GUESS. |
boolean |
isHighDegreeConnection()
|
boolean |
isInitialized()
Accessor for whether or not this connection has been initialized. |
boolean |
isLeafConnection()
Returns true iff this connection wrote "Ultrapeer: false". |
protected boolean |
isLocal()
Returns whether or not this connection represents a local address. |
boolean |
isOpen()
|
boolean |
isOutgoing()
Used to determine whether the connection is incoming or outgoing. |
boolean |
isReadDeflated()
Returns true if the incoming stream is deflated. |
boolean |
isStable()
Checks whether this connection is considered a stable connection, meaning it has been up for enough time to be considered stable. |
boolean |
isStable(long millis)
Checks whether this connection is considered a stable connection, by comparing the time it was established with the millis argument. |
boolean |
isSupernodeClientConnection()
Returns true iff I am a supernode shielding the given connection, i.e., if I wrote "X-Ultrapeer: true" and this connection wrote "X-Ultrapeer: false, and both support query routing. |
boolean |
isSupernodeConnection()
Returns true iff this connection wrote "Supernode: true". |
boolean |
isSupernodeSupernodeConnection()
Returns true iff the connection is an Ultrapeer and I am a Ultrapeer, ie: if I wrote "X-Ultrapeer: true", this connection wrote "X-Ultrapeer: true" (not necessarily in that order). |
boolean |
isTempConnection()
Returns true iff this connection is a temporary connection as per the headers. |
boolean |
isUltrapeerQueryRoutingConnection()
Returns whether or not this connection is to an Ultrapeer that supports query routing between Ultrapeers at 1 hop. |
boolean |
isWriteDeflated()
Returns true if the outgoing stream is deflated. |
protected void |
postInit()
Call this method when the Connection has been initialized and accepted as 'long-lived'. |
protected Message |
receive()
Receives a message. |
Message |
receive(int timeout)
Receives a message with timeout. |
boolean |
receivedHeaders()
Accessor for whether or not this connection has received any headers. |
int |
remoteHostSupportsHopsFlow()
|
int |
remoteHostSupportsPushProxy()
|
int |
remoteHostSupportsTCPConnectBack()
|
int |
remoteHostSupportsUDPConnectBack()
|
void |
send(Message m)
Sends a message. |
boolean |
supportsGGEP()
Returns true if this supports GGEP'ed messages. |
boolean |
supportsPongCaching()
|
boolean |
supportsProbeQueries()
Returns whether or not this connections supports "probe" queries, or queries sent at TTL=1 that should not block the send path of subsequent, higher TTL queries. |
int |
supportsVendorMessage(byte[] vendorID,
int selector)
|
java.lang.String |
toString()
|
Methods inherited from class java.lang.Object |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait |
Field Detail |
protected MessagesSupportedVendorMessage _messagesSupported
protected volatile boolean _closed
public static final java.lang.String GNUTELLA_OK_06
public static final java.lang.String GNUTELLA_06
public static final java.lang.String _200_OK
public static final java.lang.String GNUTELLA_06_200
public static final java.lang.String CONNECT
public static final java.lang.String CRLF
public static final int USER_INPUT_WAIT_TIME
public static final int MAX_HANDSHAKE_ATTEMPTS
protected static final java.io.IOException CONNECTION_CLOSED
Constructor Detail |
public Connection(java.lang.String host, int port, java.util.Properties requestHeaders, HandshakeResponder responseHeaders)
host
- the name of the host to connect toport
- the port of the remote hostrequestHeaders
- the headers to be sent after "GNUTELLA CONNECT"responseHeaders
- a function returning the headers to be sent
after the server's "GNUTELLA OK". Typically this returns only
vendor-specific properties.
NullPointerException
- if any of the arguments are
null
IllegalArgumentException
- if the port is invalidpublic Connection(java.net.Socket socket, HandshakeResponder responseHeaders)
socket
- the socket accepted by a ServerSocket. The word
"GNUTELLA " and nothing else must have been read from the socket.responseHeaders
- the headers to be sent in response to the client's
"GNUTELLA CONNECT".
NullPointerException
- if any of the arguments are
nullMethod Detail |
protected void postInit()
protected void handleVendorMessage(VendorMessage vm)
public void initialize() throws java.io.IOException, NoGnutellaOkException, BadHandshakeException
java.io.IOException
NoGnutellaOkException
BadHandshakeException
initialize(int)
public void initialize(int timeout) throws java.io.IOException, NoGnutellaOkException, BadHandshakeException
timeout
- for outgoing connections, the timeout in milliseconds
to use in establishing the socket, or 0 for no timeout. If the
platform does not support native timeouts, it will be emulated with
threads.
java.io.IOException
- we were unable to connect to the host
NoGnutellaOkException
- one of the participants responded
with an error code other than 200 OK (possibly after several rounds
of 401's)
BadHandshakeException
- some other problem establishing
the connection, e.g., the server responded with HTTP, closed the
the connection during handshaking, etc.public boolean isInitialized()
protected java.io.OutputStream getOutputStream() throws java.io.IOException
java.io.IOException
protected java.io.InputStream getInputStream() throws java.io.IOException
java.io.IOException
public boolean isOutgoing()
protected Message receive() throws java.io.IOException, BadPacketException
java.io.IOException
BadPacketException
public Message receive(int timeout) throws java.io.IOException, BadPacketException, java.io.InterruptedIOException
java.io.IOException
BadPacketException
java.io.InterruptedIOException
public void send(Message m) throws java.io.IOException
java.io.IOException
public void flush() throws java.io.IOException
java.io.IOException
public long getBytesSent()
public long getUncompressedBytesSent()
public long getBytesReceived()
public long getUncompressedBytesReceived()
public float getSentSavedFromCompression()
public float getReadSavedFromCompression()
public java.lang.String getIPString()
public int getListeningPort()
public java.net.InetAddress getInetAddress() throws java.lang.IllegalStateException
java.lang.IllegalStateException
- this is not initializedpublic java.net.Socket getSocket() throws java.lang.IllegalStateException
java.lang.IllegalStateException
- if this connection is not yet
initializedpublic boolean isConnectBackCapable() throws java.lang.IllegalStateException
java.lang.IllegalStateException
public long getConnectionTime()
public byte getSoftMax()
public boolean isStable()
public boolean isStable(long millis)
public int supportsVendorMessage(byte[] vendorID, int selector)
public int remoteHostSupportsUDPConnectBack()
public int remoteHostSupportsTCPConnectBack()
public int remoteHostSupportsHopsFlow()
public int remoteHostSupportsPushProxy()
protected boolean isLocal()
public java.lang.String getPropertyWritten(java.lang.String name)
public boolean isOpen()
public void close()
public java.lang.String getUserAgent()
public boolean isWriteDeflated()
public boolean isReadDeflated()
public boolean isGoodUltrapeer()
public boolean isGoodLeaf()
public boolean supportsPongCaching()
public boolean allowNewPings()
public boolean allowNewPongs()
public int getNumIntraUltrapeerConnections()
public boolean isHighDegreeConnection()
public boolean isUltrapeerQueryRoutingConnection()
public boolean supportsProbeQueries()
public java.lang.String getDomainsAuthenticated()
public boolean receivedHeaders()
public HandshakeResponse headers()
public java.lang.String getVersion()
public boolean isLeafConnection()
public boolean isSupernodeConnection()
public boolean isClientSupernodeConnection()
public boolean isSupernodeSupernodeConnection()
public boolean isGUESSCapable()
public boolean isGUESSUltrapeer()
public boolean isTempConnection()
public boolean isSupernodeClientConnection()
public boolean supportsGGEP()
public java.lang.String toString()
|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |