Servent.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
xnap.plugin.gnutella.net |
![]() |
![]() |
XNap 2 |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
| Metric | Description | |
|---|---|---|
/*
* 03/31/2001
*
* GnutellaConnectionHandler.java
* Copyright (C) 2001 Frederik Zimmer
* tristian@users.sourceforge.net
* http://sourceforge.net/projects/ziga/
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package xnap.plugin.gnutella.net;
import xnap.net.*;
import xnap.util.*;
import xnap.plugin.gnutella.util.*;
import xnap.plugin.gnutella.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.net.InetAddress;
import java.io.IOException;
import java.io.EOFException;
import java.io.InterruptedIOException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.util.*;
public class Servent extends AbstractCommunication implements Runnable
{
//--- Constant(s) ---
public static final int STATUS_NOT_CONNECTED = 0;
public static final int STATUS_CONNECTING = 1;
public static final int STATUS_CONNECTED = 2;
public static final int STATUS_DISCONNECTED = 3;
public static final int STATUS_NEW_STATS = 4;
public static final String[] STATUS_MSGS = {
"", "connecting...", "connected", "disconnected", "error"
};
public static final int PRIORITY_BROADCAST = 0;
public static final int PRIORITY_ROUTE = 1;
public static final int PRIORITY_NORMAL = 2;
protected static final long ALIVE_PING_INTERVAL = 30 * 1000;
protected static final int CONNECT_SOCKET_TIMEOUT = 5 * 1000;
protected static final int DEFAULT_SOCKET_TIMEOUT = 30 * 1000;
protected static final String CONNECT = " CONNECT/";
protected static final String LOGINMSG_04 = " CONNECT/0.4";
protected static final String LOGIN_OK_04 = " OK";
protected static final String NETWORK_NAME = "GNUTELLA";
protected static final String LOGIN_FORBIDDEN = " FORBIDDEN\n\n";
protected static final String USER_AGENT = "User-Agent";
protected static final String VENDORCODE = "XNAP";
protected static final String X_TRY = "X-Try";
protected static final String X_YOU_ARE = "X-YouAre";
protected static final String VERSION = "0.6";
//--- Data field(s) ---
private GnuPreferences gnuPrefs = GnuPreferences.getInstance();
protected RoutingTable routingTable = RoutingTable.getInstance();
protected Socket socket;
protected DataInputStream in;
protected DataOutputStream out;
protected Thread thread;
protected WriterThread writerThread;
protected boolean alive;
protected boolean incomingConnection = false;
protected String ip;
protected int port;
protected String hostString;
protected String firstLine;
protected long startTime;
protected long connectTime;
protected long lastAlivePing;
protected int badMessageCount;
private int messagesReceived;
private int numOfKBs;
private int numOfFiles;
private SendQueue sendQueue;
/**
* Constructs a new servent to accept the connection coming in from socket.
*/
public Servent(String request, Socket sock)
{
sendQueue = new SendQueue();
writerThread = new WriterThread(this);
socket = sock;
firstLine = request;
ip = socket.getInetAddress().getHostAddress();
port = socket.getPort();
hostString = ip + ":" + port;
incomingConnection = true;
}
/**
* Creates a new Servent with given ip and port.
*/
public Servent(String ip, int port)
{
sendQueue = new SendQueue();
writerThread = new WriterThread(this);
this.ip = ip;
this.port = port;
hostString = ip + ":" + port;
}
/**
* Called from run when connection is an accepting one, handles
* handshaking.
*/
public boolean accept()
{
try {
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
writerThread.setOutputStream(out);
}
catch (IOException ie) {
Debug.log(ie);
setStatus(STATUS_DISCONNECTED, ie.getMessage());
return false;
}
StringTokenizer t = new StringTokenizer(firstLine, "/");
if (t.countTokens() < 2) {
sendInvalidLogin(out, "Wrong number of args");
return false;
}
/* skip "GNUTELLA CONNECT/" */
t.nextToken();
setStatus(STATUS_CONNECTING, "Handshake");
String version = t.nextToken();
// checking for '1' as a return value is not a good idea
if (VersionParser.compare(version, "0.4") == 1) {
try {
out.write(NETWORK_NAME.getBytes());
out.write(LOGIN_OK_04.getBytes());
out.write(10);
out.write(10);
out.flush();
}
catch (IOException ie) {
return false;
}
return true;
}
else if (VersionParser.compare(version, "0.4") > 0) {
StringBuffer loginOk = new StringBuffer();
loginOk.append(NETWORK_NAME);
loginOk.append('/');
loginOk.append(VERSION);
loginOk.append(" 200 OK");
try {
out.write(loginOk.toString().getBytes());
out.write(13);
out.write(10);
/* send some cached servers */
sendServerHeaders(out);
out.flush();
}
catch (IOException ie) {
return false;
}
ReadLineReader rlr = new ReadLineReader(in);
String response = rlr.readLine();
if (response != null && response.indexOf("200") != -1)
sendInvalidLogin(out, "Wrong response" + response);
else {
sendInvalidLogin(out, "Wrong response");
return false;
}
}
return true;
}
/**
* Called from <code>run()</code> when connection is initiated from us,
* handles handshaking.
*/
public boolean connect()
{
ReadLineReader rlr;
try {
socket = new Socket(ip, port);
socket.setSoTimeout(CONNECT_SOCKET_TIMEOUT);
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
writerThread.setOutputStream(out);
}
catch (SocketException se) {
Debug.log("gnutella: timeout reached");
setStatus(STATUS_DISCONNECTED, se.getMessage());
return false;
}
catch (IOException ie) {
Debug.log(ie.getMessage() + " " + ip + ":" + port);
setStatus(STATUS_DISCONNECTED, ie.getMessage());
return false;
}
rlr = new ReadLineReader(in);
try {
out.write(NETWORK_NAME.getBytes());
out.write(LOGINMSG_04.getBytes());
out.write(10);
out.write(10);
out.flush();
}
catch (IOException ie) {
Debug.log("gnutella: Could not handshake");
setStatus(STATUS_DISCONNECTED);
return false;
}
String response = rlr.readLine();
if (response == null
|| !response.equalsIgnoreCase(NETWORK_NAME + LOGIN_OK_04)) {
Debug.log("gnutella: " + response);
return false;
}
return true;
}
/**
* Closes socket if open.
*/
public void close() {
if (socket != null) {
try {
socket.close();
}
catch(IOException e) {
}
socket = null;
writerThread.close();
if (in != null) {
try {
in.close();
}
catch(IOException e) {}
}
}
setStatus(STATUS_DISCONNECTED);
}
/**
* Checks for equity.
*/
public boolean equals(Object o)
{
if (o == null) {
return false;
}
else {
try {
Servent handler = (Servent) o;
return handler.ip.equals(ip) && handler.port == port;
}
catch(ClassCastException e) {
return false;
}
}
}
/**
* Returns ip address of remote host.
*/
public String getAddress()
{
return ip;
}
public long getConnectTime()
{
return System.currentTimeMillis() - connectTime;
}
/**
* Returns string of local ip address this socket is bound to. Returns
* <code>null</code> if socket is <code>null</code>.
*/
public String getLocalAddress()
{
if (socket != null) {
return socket.getLocalAddress().getHostAddress();
}
else {
return null;
}
}
/**
* Returns number of messages this servent has already received.
*/
public int getMessagesReceived()
{
return messagesReceived;
}
/**
* Returns number of messages this servent has already sent.
*/
public int getMessagesSent()
{
return writerThread.getMessagesSent();
}
/**
* Returns number of files the direct remote host shares.
*/
public int getNumberOfFiles()
{
return numOfFiles;
}
/**
* Returns number of kilo bytes the direct remote host shares.
*/
public int getNumberOfKBs()
{
return numOfKBs;
}
/**
* Returns port of remote host.
*/
public int getPort()
{
return port;
}
/**
* Returns sendQueue.
*/
public SendQueue getSendQueue()
{
return sendQueue;
}
/**
* Returns uptime of connection in seconds.
*/
public long getUpTime()
{
if (startTime != 0)
return (System.currentTimeMillis() - startTime) / 1000;
return startTime;
}
protected String getStatusMsg(int index)
{
return STATUS_MSGS[index];
}
private void handleStats(PongMessage msg)
{
if (msg.getHops() == 0) {
numOfFiles = msg.getNumberOfFiles();
numOfKBs = msg.getNumberOfKBs();
}
}
public boolean isConnected()
{
return (status == STATUS_CONNECTED);
}
/**
* Returns type of connection.
*/
public boolean isIncoming()
{
return incomingConnection;
}
/**
* Sends a ping to the remote host after timeout
* <code>ALIVE_PING_INTERVAL</code> if <code>sendQueue</code> has no
* messages queued.
* @see ALIVE_PING_INTERVAL
*/
public void keepAlivePing()
{
if ((System.currentTimeMillis() - lastAlivePing) > ALIVE_PING_INTERVAL
&& sendQueue.size() == 0)
sendAlivePing();
}
/**
* Main loop reads in new messages and calls respective functions in
* <code>routingTable</code>.
* @see RoutingTable
*/
public void run()
{
boolean success = false;
setStatus(STATUS_CONNECTING);
connectTime = System.currentTimeMillis();
if (incomingConnection) {
success = accept();
}
else {
success = connect();
}
if (!success) {
setStatus(STATUS_DISCONNECTED);
return;
}
setStatus(STATUS_CONNECTED);
startTime = System.currentTimeMillis();
try {
socket.setSoTimeout(DEFAULT_SOCKET_TIMEOUT);
}
catch (SocketException se) {
Debug.log(se);
}
sendPing();
writerThread.start();
while (alive) {
try {
boolean isUnknownMessage = false;
DescriptorHeader header = new DescriptorHeader(in);
messagesReceived++;
switch (header.payloadDescriptor) {
case DescriptorHeader.PING:
PingMessage pingMsg = new PingMessage(header);
routingTable.route(pingMsg, this);
break;
case DescriptorHeader.PONG:
PongMessage pongMsg = new PongMessage(header, in);
handleStats(pongMsg);
routingTable.route(pongMsg, this);
break;
case DescriptorHeader.QUERY:
QueryMessage queryMsg = new QueryMessage(header, in);
routingTable.route(queryMsg, this);
break;
case DescriptorHeader.QUERY_HIT:
QueryHitMessage queryHitMsg = new QueryHitMessage(header,
in);
routingTable.route(queryHitMsg, this);
break;
case DescriptorHeader.PUSH:
PushMessage pushMsg = new PushMessage(header, in);
routingTable.route(pushMsg, this);
break;
case DescriptorHeader.BYE:
ByeMessage byeMsg = new ByeMessage(header, in);
Debug.log("bye: " + byeMsg.getErrorCode() + " "
+ byeMsg.getErrorDescription());
break;
default:
UnknownMessage unknownMessage = new UnknownMessage(header,
in);
Debug.log("Unknown message received");
isUnknownMessage = true;
}
if (isUnknownMessage) {
badMessageCount++;
}
else if (badMessageCount > 0) {
badMessageCount--;
}
if (badMessageCount > 2) {
throw new InvalidMessageException("Too many unknown messages");
}
if (sendQueue.size() == 0) {
keepAlivePing();
}
}
catch(InterruptedIOException e) {
if (alive) {
sendAlivePing();
}
}
catch(IOException e) {
Debug.log("Peer disconnected");
break;
}
catch(InvalidMessageException e) {
Debug.log(e);
break;
}
}
writerThread.stop();
close();
if (incomingConnection) {
try {
thread.sleep(5000);
}
catch(InterruptedException e) {
}
}
setStatus(STATUS_DISCONNECTED);
}
/**
* Sends message to remote host. Message is queued in
* <code>sendQueue</code> and sent by <code>writerThread</code>.
* @see SendQueue
* @see Writerthread
*/
public void send(Message msg, int priority)
{
if (getStatus() == STATUS_CONNECTED) {
sendQueue.add(msg, priority);
}
}
private void sendAlivePing()
{
Debug.log("gnutella: sending alive ping");
lastAlivePing = System.currentTimeMillis();
PingMessage msg = new PingMessage();
msg.setTTL((byte) 1);
routingTable.send(msg, this);
}
private void sendInvalidLogin(DataOutputStream out, String reason)
{
try {
out.write(NETWORK_NAME.getBytes());
out.write(LOGIN_FORBIDDEN.getBytes());
out.flush();
Debug.log(reason);
}
catch (IOException ie) {
}
close();
}
/**
* Sends a ping message through this servent.
*/
public void sendPing()
{
routingTable.send(new PingMessage(), this);
}
/**
* Behave as host cache and send some cached hosts.
*/
private void sendServerHeaders(DataOutputStream os)
throws IOException
{
Debug.log("Sending some server entries");
LineWriter out = new LineWriter(os);
out.println(USER_AGENT + ": " + VENDORCODE);
out.println(X_YOU_ARE + ": " + ip);
StringBuffer cachedHosts = new StringBuffer();
Connections connections = Connections.getInstance();
int j = 0;
synchronized (connections) {
for (Iterator i = connections.iterator(); i.hasNext() && j < 10;
j++) {
Servent s = (Servent) i.next();
cachedHosts.append(s.getAddress());
cachedHosts.append(':');
cachedHosts.append(s.getPort());
cachedHosts.append(", ");
}
}
/* remove last comma again */
if (j > 0) {
cachedHosts.deleteCharAt(cachedHosts.length() - 1);
}
out.println(X_TRY + ": " + cachedHosts.toString());
out.println();
}
/**
* Start connection to remote host.
*/
public synchronized void start()
{
if (!alive) {
alive = true;
thread = new Thread(this);
thread.start();
}
}
/**
* Stop connection to remote host.
*/
public synchronized void stop()
{
if (alive) {
alive = false;
writerThread.stop();
setStatus(STATUS_DISCONNECTED, "User disconnect");
close();
}
}
/**
* Returns the host string containing both, the remote host's ip and port
* as string separated by a column.
*/
public String toString()
{
return hostString;
}
}
The table below shows all metrics for Servent.java.
| Metric | Value | Description | |
|---|---|---|---|



