package com.limegroup.gnutella.handshaking;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import com.limegroup.gnutella.statistics.HandshakingStat;
/**
* An incoming handshaker that blocks while handshaking.
*/
public class BlockingIncomingHandshaker implements Handshaker {
private HandshakeResponder responder;
private BlockingHandshakeSupport support;
/**
* Constructs a new BlockingIncomingHandshaker using the given responder
* to calculate our response, and the Socket/InputStream/OutputStream for i/o.
*
* @param responder
* @param socket
* @param in
* @param out
*/
public BlockingIncomingHandshaker(HandshakeResponder responder, Socket socket, InputStream in, OutputStream out) {
this.responder = responder;
this.support = new BlockingHandshakeSupport(socket, in, out);
}
/** Performs an incoming handshake. */
public void shake() throws IOException, BadHandshakeException, NoGnutellaOkException {
initializeIncoming();
concludeIncomingHandshake();
}
/** Returns all headers we read while connecting. */
public HandshakeResponse getReadHeaders() {
return support.getReadHandshakeResponse();
}
/** Returns all headers we wrote while connecting. */
public HandshakeResponse getWrittenHeaders() {
return support.getWrittenHandshakeResponse();
}
/**
* Sends and receives handshake strings for incoming connections,
* throwing exception if any problems.
*
* @exception NoGnutellaOkException one of the participants responded
* with an error code other than 200 OK
* @exception IOException if there's an unexpected connect string or
* any other problem
*/
private void initializeIncoming() throws IOException {
String connectString = support.readLine();
if (support.notLessThan06(connectString))
support.readHeaders();
else
throw new IOException("Unexpected connect string: "+connectString);
}
/**
* Responds to the handshake from the host on the other
* end of the connection, till a conclusion reaches. Handshaking may
* involve multiple steps.
*
* @exception NoGnutellaOkException one of the participants responded
* with an error code other than 200 OK
* @exception IOException any other error.
*/
private void concludeIncomingHandshake() throws IOException {
HandshakeResponse theirRequest = support.getReadHandshakeResponse();
HandshakeResponse ourResponse = responder.respond(theirRequest, false);
support.writeResponse(ourResponse);
// if it was the crawler, leave early.
if(theirRequest.isCrawler()) {
// read one response, just to make sure they got ours.
support.readLine();
throw new IOException("crawler");
}
switch(ourResponse.getStatusCode()) {
case HandshakeResponse.OK:
break;
case HandshakeResponse.SLOTS_FULL:
HandshakingStat.INCOMING_CLIENT_REJECT.incrementStat();
throw NoGnutellaOkException.CLIENT_REJECT;
default:
HandshakingStat.INCOMING_CLIENT_UNKNOWN.incrementStat();
throw NoGnutellaOkException.createClientUnknown(ourResponse.getStatusCode());
}
String connectLine = support.readLine();
if (!support.isConnectLineValid(connectLine)) {
HandshakingStat.INCOMING_BAD_CONNECT.incrementStat();
throw new IOException("Bad connect string");
}
support.readHeaders();
HandshakeResponse theirResponse = support.createRemoteResponse(connectLine);
switch(theirResponse.getStatusCode()) {
case HandshakeResponse.OK:
HandshakingStat.SUCCESSFUL_INCOMING.incrementStat();
break;
default:
HandshakingStat.INCOMING_SERVER_UNKNOWN.incrementStat();
throw NoGnutellaOkException.createServerUnknown(theirResponse.getStatusCode());
}
}
}