package com.limegroup.gnutella.messages.vendor; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import com.limegroup.gnutella.ByteOrder; import com.limegroup.gnutella.ErrorService; import com.limegroup.gnutella.messages.BadPacketException; import com.limegroup.gnutella.statistics.SentMessageStatHandler; import com.limegroup.gnutella.util.NetworkUtils; /** In Vendor Message parlance, the "message type" of this VMP is "BEAR/7". * Used to ask a host you connect to do a TCP ConnectBack. */ public final class TCPConnectBackVendorMessage extends VendorMessage { public static final int VERSION = 1; /** The payload has a 16-bit unsigned value - the port - at which one should * connect back. */ private final int _port; /** * Constructs a new TCPConnectBackVendorMessage with data from the network. */ TCPConnectBackVendorMessage(byte[] guid, byte ttl, byte hops, int version, byte[] payload) throws BadPacketException { super(guid, ttl, hops, F_BEAR_VENDOR_ID, F_TCP_CONNECT_BACK, version, payload); if (getVersion() > VERSION) throw new BadPacketException("UNSUPPORTED VERSION"); if (getPayload().length != 2) throw new BadPacketException("UNSUPPORTED PAYLOAD LENGTH: " + payload.length); // get the port from the payload.... _port = ByteOrder.ushort2int(ByteOrder.leb2short(getPayload(), 0)); if( !NetworkUtils.isValidPort(_port) ) throw new BadPacketException("invalid port"); } /** * Constructs a new TCPConnectBackVendorMessage to be sent out. * @param port The port you want people to connect back to. If you give a * bad port I don't check so check yourself! */ public TCPConnectBackVendorMessage(int port) { super(F_BEAR_VENDOR_ID, F_TCP_CONNECT_BACK, VERSION, derivePayload(port)); _port = port; } public int getConnectBackPort() { return _port; } /** * Constructs the payload given the desired port. */ private static byte[] derivePayload(int port) { try { // i do it during construction.... ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteOrder.short2leb((short)port,baos); // write _port return baos.toByteArray(); } catch (IOException ioe) { ErrorService.error(ioe); // impossible. return null; } } /** Overridden purely for stats handling. */ protected void writePayload(OutputStream out) throws IOException { super.writePayload(out); SentMessageStatHandler.TCP_TCP_CONNECTBACK.addMessage(this); } /** Overridden purely for stats handling. */ public void recordDrop() { super.recordDrop(); } }