public final void handleReceive(DatagramPacket packet, AsyncDatagramSocket dgram_socket) { synchronized (this) { try { TcpSegment segment = new TcpSegment(packet); Object[] args = new Object[1]; // Generate the appropriate transition based on // the header flags. args[0] = segment; // DEBUG // System.out.println( // "Receive event from " + // packet.getAddress() + // ":" + // Integer.toString(packet.getPort()) + // ":\n" + // segment); // REFLECTION // Uncomment the following line to output // transitions. // _outputTransitions(); _transition_table[segment.getFlags()].invoke(_fsm, args); } catch (Exception jex) { System.err.println(jex); jex.printStackTrace(); } finally { this.notify(); } } return; }
private int getAck(TcpSegment segment) { int retval; // The ack # depends on the segment's flags. switch (segment.getFlags()) { case TcpSegment.FIN: case TcpSegment.SYN: case TcpSegment.FIN_ACK: case TcpSegment.SYN_ACK: retval = segment.getSequenceNumber() + 1; break; case TcpSegment.PSH: case TcpSegment.PSH_ACK: retval = segment.getSequenceNumber() + segment.getDataSize(); break; case TcpSegment.ACK: default: retval = segment.getSequenceNumber(); break; } return (retval); }
/* package */ void send(int flags, byte[] data, int offset, int size, TcpSegment recv_segment) { send( flags, data, offset, size, recv_segment.getSourceAddress(), recv_segment.getSourcePort(), recv_segment); return; }
/* package */ void setDestinationPort(TcpSegment segment) { byte[] data; // The server socket is telling us the accepted client's // port number. Reset the destination port to that. data = segment.getData(); _port = ((((int) data[0]) & 0x000000ff) << 8) | (((int) data[1]) & 0x000000ff); // Modify the segment's source port so that the ack will // go to the correct destination. segment.setSourcePort(_port); return; }
/* package */ void receive(TcpSegment segment) { // Send the TCP segment's data to the socket listener. if (_listener != null) { _listener.receive(segment.getData(), this); } return; }
// Create a client socket to handle a new connection. /* package */ void accept(TcpSegment segment) { TcpClient accept_client; DatagramSocket dgram_socket; try { _address = segment.getSourceAddress(); _port = segment.getSourcePort(); // Create a new client socket to handle this side of // the socket pair. dgram_socket = new DatagramSocket(); accept_client = new TcpClient( _address, _port, dgram_socket, _sequence_number, (TcpServer) this, _listener); ((TcpConnection) accept_client).acceptOpen(segment); } catch (Exception jex) { // If the open fails, send a reset to the peer. send(TcpSegment.RST, null, 0, 0, segment); } return; }
/* package */ void send( int flags, byte[] data, int offset, int size, InetAddress address, int port, TcpSegment recv_segment) { DatagramSocket socket; // Quietly quit if there is no socket. if (_async_socket != null && (socket = _async_socket.getDatagramSocket()) != null) { int local_port; int ack_number; TcpSegment send_segment; DatagramPacket packet = null; // If the address and port were not specified, then // send this segment to whatever client socket we are // currently speaking. if (address == null) { address = _address; port = _port; } // If there is a recv_segment, then use its // destination port as the local port. Otherwise, use // the local datagram socket's local port. if (recv_segment != null) { local_port = recv_segment.getDestinationPort(); } else { local_port = _async_socket.getDatagramSocket().getLocalPort(); } // Send the ack number only if the ack flag is set. if ((flags & TcpSegment.ACK) == 0) { ack_number = 0; } else { // Figure out the ack number based on the // received segment's sequence number and data // size. ack_number = getAck(recv_segment); } send_segment = new TcpSegment( local_port, address, port, _sequence_number, ack_number, flags, data, offset, size); // Advance the sequence number depending on the // message sent. Don't do this if message came from // an interloper. if (address.equals(_address) && port == _port) { _sequence_number = getAck(send_segment); } // Now send the data. try { packet = send_segment.packetize(); // DEBUG // System.out.println( // "Sending packet to " + // packet.getAddress() + // ":" + // Integer.toString(packet.getPort()) + // ":\n" + // send_segment); _async_socket.getDatagramSocket().send(packet); } catch (IOException io_exception) { // Ignore - the ack timer will figure out this // packet was never sent. // DEBUG // System.out.println( // "Send to " + // packet.getAddress() + // ": " + // io_exception.getMessage()); } } return; }