package com.limegroup.gnutella.handshaking; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.util.Properties; import com.limegroup.gnutella.Constants; import com.limegroup.gnutella.statistics.HandshakingStat; /** * An outgoing handshaker that blocks while handshaking. */ public class BlockingOutgoingHandshaker implements Handshaker { private BlockingHandshakeSupport support; private Properties ourRequestHeaders; private HandshakeResponder ourResponder; /** * Constructs a new BlockingOutgoingHandshaker using the given * requestHeaders for the initial request, responsder to handle our response, * and Socket/InputStream/OutputStream for I/O. */ public BlockingOutgoingHandshaker(Properties requestHeaders, HandshakeResponder responder, Socket socket, InputStream in, OutputStream out) { this.support = new BlockingHandshakeSupport(socket, in, out); this.ourRequestHeaders = requestHeaders; this.ourResponder = responder; } /** Returns a HandshakeResponse containing all the headers we read while handshaking. */ public HandshakeResponse getReadHeaders() { return support.getReadHandshakeResponse(); } /** Returns a HandshakeResponse containing all the headers we wrote while handshaking. */ public HandshakeResponse getWrittenHeaders() { return support.getWrittenHandshakeResponse(); } /** Performs the handshake.*/ public void shake() throws IOException, BadHandshakeException, NoGnutellaOkException { initializeOutgoing(); concludeOutgoingHandshake(); } /** * Sends and receives handshake strings for outgoing connections, * throwing exception if any problems. * * @exception NoGnutellaOkException one of the participants responded * with an error code other than 200 OK (possibly after several rounds * of 401's) * @exception IOException any other error. */ private void initializeOutgoing() throws IOException { support.writeConnectLine(); support.sendHeaders(ourRequestHeaders); } /** * Responds to the responses/challenges 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 concludeOutgoingHandshake() throws IOException { String connectLine = support.readLine(); if (!support.isConnectLineValid(connectLine)) { HandshakingStat.OUTGOING_BAD_CONNECT.incrementStat(); throw new IOException("Bad connect string"); } support.readHeaders(Constants.TIMEOUT); //Terminate abnormally if we read something other than 200 or 401. HandshakeResponse theirResponse = support.createRemoteResponse(connectLine); switch(theirResponse.getStatusCode()) { case HandshakeResponse.OK: break; case HandshakeResponse.SLOTS_FULL: handleSlotsFullStats(theirResponse); throw NoGnutellaOkException.SERVER_REJECT; default: HandshakingStat.OUTGOING_SERVER_UNKNOWN.incrementStat(); throw NoGnutellaOkException.createServerUnknown(theirResponse.getStatusCode()); } HandshakeResponse ourResponse = ourResponder.respond(theirResponse, true); support.writeResponse(ourResponse); switch(ourResponse.getStatusCode()) { case HandshakeResponse.OK: HandshakingStat.SUCCESSFUL_OUTGOING.incrementStat(); break; case HandshakeResponse.SLOTS_FULL: HandshakingStat.OUTGOING_CLIENT_REJECT.incrementStat(); throw NoGnutellaOkException.CLIENT_REJECT; case HandshakeResponse.LOCALE_NO_MATCH: //if responder's locale preferencing was set //and didn't match the locale this code is used. //(currently in use by the dedicated connectionfetcher) throw NoGnutellaOkException.CLIENT_REJECT_LOCALE; default: HandshakingStat.OUTGOING_CLIENT_UNKNOWN.incrementStat(); throw NoGnutellaOkException.createClientUnknown(ourResponse.getStatusCode()); } } /** Increments various HandshakingStats because of a slots full response. */ private void handleSlotsFullStats(HandshakeResponse theirResponse) { if (theirResponse.isLimeWire()) { if (theirResponse.isUltrapeer()) HandshakingStat.OUTGOING_LIMEWIRE_ULTRAPEER_REJECT.incrementStat(); else HandshakingStat.OUTGOING_LIMEWIRE_LEAF_REJECT.incrementStat(); } else { if (theirResponse.isUltrapeer()) HandshakingStat.OUTGOING_OTHER_ULTRAPEER_REJECT.incrementStat(); else HandshakingStat.OUTGOING_OTHER_LEAF_REJECT.incrementStat(); } } }