package com.limegroup.gnutella.handshaking; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Properties; import org.limewire.util.StringUtils; import com.limegroup.gnutella.http.WriteHeadersIOState; /** Superclass for HandshakeStates that are written out. */ public abstract class WriteHandshakeState extends WriteHeadersIOState { /** The handshake support. */ protected final HandshakeSupport support; protected WriteHandshakeState(HandshakeSupport support) { super(null); this.support = support; } /** The second state in an incoming handshake, or the third state in an outgoing handshake. */ static class WriteResponseState extends WriteHandshakeState { private HandshakeResponder responder; private HandshakeResponse response; private boolean outgoing; /** * Constructs a new WriteResponseState using the given support, responder, * and whether or not we're responding to an outgoing or incoming request. * * @param support * @param responder * @param outgoing */ WriteResponseState(HandshakeSupport support, HandshakeResponder responder, boolean outgoing) { super(support); this.responder = responder; this.outgoing = outgoing; } /** * Creates a response using the responder and wraps it into a ByteBuffer. */ @Override protected ByteBuffer createOutgoingData() throws IOException { // The distinction between requests is not necessary for correctness, // but is useful. The getReadHandshakeRemoteResponse() method will // contain the correct response status code & msg, whereas // the getReadHandshakeResponse() method assumes '200 OK'. HandshakeResponse theirResponse; if(outgoing) theirResponse = support.getReadHandshakeRemoteResponse(); else theirResponse = support.getReadHandshakeResponse(); response = responder.respond(theirResponse, outgoing); StringBuilder sb = new StringBuilder(); support.appendResponse(response, sb); return ByteBuffer.wrap(StringUtils.toAsciiBytes(sb.toString())); } /** * Throws an IOException if we wrote a code other than 'OK'. * Increments the appropriate statistics also. */ @Override protected void processWrittenHeaders() throws IOException { if(outgoing) { switch(response.getStatusCode()) { case HandshakeResponse.OK: break; case HandshakeResponse.SLOTS_FULL: 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: throw NoGnutellaOkException.createClientUnknown(response.getStatusCode()); } } else { switch(response.getStatusCode()) { case HandshakeResponse.OK: case HandshakeResponse.CRAWLER_CODE: // let the crawler IOX in ReadResponse break; case HandshakeResponse.SLOTS_FULL: throw NoGnutellaOkException.CLIENT_REJECT; default: throw NoGnutellaOkException.createClientUnknown(response.getStatusCode()); } } } } /** The first state in an outgoing handshake. */ static class WriteRequestState extends WriteHandshakeState { private Properties request; /** Creates a new WriteRequestState using the given support & initial set of properties. */ WriteRequestState(HandshakeSupport support, Properties request) { super(support); this.request = request; } /** Returns a ByteBuffer of the initial connect request & headers. */ @Override protected ByteBuffer createOutgoingData() { StringBuilder sb = new StringBuilder(); support.appendConnectLine(sb); support.appendHeaders(request, sb); return ByteBuffer.wrap(StringUtils.toAsciiBytes(sb.toString())); } /** Does nothing. */ @Override protected void processWrittenHeaders() {} } }