📄 tcpconnection.java
字号:
} /* package */ void openSuccess() { _listener.opened(this); return; } /* package */ void openFailed(String reason) { _listener.openFailed(reason, this); return; } /* package */ void closeSocket() { _async_socket.closeDatagramSocket(); _async_socket = null; _address = null; _port = -1; return; } /* package */ void halfClosed() { if (_listener != null) { _listener.halfClosed(this); } return; } /* package */ void closed(String reason) { if (_listener != null) { _listener.closed(reason, this); _listener = null; } return; } /* package */ void clearListener() { _listener = null; return; } /* package */ void transmitted() { if (_listener != null) { _listener.transmitted(this); } return; } /* package */ void transmitFailed(String reason) { if (_listener != null) { _listener.transmitFailed(reason, this); } 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 accepted() { TcpServer server = _server; TcpConnectionListener listener = _listener; // Tell the server listener that a new connection has // been accepted. Then clear the server listener because // this socket is now truly a client socket. Clear the // listener member data now because the callback method // will be resetting it and the reset will fail if we // don't do it. _server = null; _listener = null; listener.accepted((TcpClient) this, server); return; } // Send the SYN/ACK reply to the client's SYN. /* package */ void sendAcceptSynAck(TcpSegment segment) { int client_port; byte[] port_bytes = new byte[2]; // Tell the far-side client with what port it should now // communicate. client_port = _async_socket.getDatagramSocket().getLocalPort(); port_bytes[0] = (byte) ((client_port & 0x0000ff00) >> 8); port_bytes[1] = (byte) (client_port & 0x000000ff); send(TcpSegment.SYN_ACK, port_bytes, 0, 2, null, -1, segment); return; } /* 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 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; } /* package */ void startTimer(String name, long time) { AsyncTimer.startTimer(name, time, this); return; } /* package */ void stopTimer(String name) { AsyncTimer.stopTimer(name); 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; } 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); } /* * REFLECTION * Uncomment the following method to output transitions. * private void _outputTransitions() { if (_fsm.getDebugFlag() == true) { java.io.PrintStream str = _fsm.getDebugStream(); TcpConnectionContext.TcpConnectionState state = _fsm.getState(); java.util.Iterator it; String sep; str.print("State "); str.print(state.getName()); str.print(" has transitions "); for (it = state.getTransitions().iterator(), sep = "{"; it.hasNext(); sep = ", ") { str.print(sep); str.print(it.next()); } str.println("}"); } return; } * *///---------------------------------------------------------------// Member data.// protected TcpConnectionListener _listener; private TcpConnectionContext _fsm; protected AsyncDatagramSocket _async_socket; private int _sequence_number; // The port to which a client socket is connected. protected InetAddress _address; protected int _port; // The server which accepted this connection. protected TcpServer _server; private String _errorMessage; // The Initial Sequence Number. private static final int ISN = 1415531521; // Wait only so long for an ACK (in milliseconds). /* package */ static final long ACK_TIMEOUT = 2000; // Wait a while before reusing this port (in milliseconds). /* package */ static final long CLOSE_TIMEOUT = 10000; /* package */ static final long MIN_TIMEOUT = 1; // Use this table to translate received segment flags into // state map transitions. private static Method[] _transition_table; static { try { Class context = TcpConnectionContext.class; Class[] parameters = new Class[1]; Method undefined; int i; // All "TCP flag" transitions take a DatagramPacket as // a parameter. parameters[0] = TcpSegment.class; _transition_table = new Method[TcpSegment.FLAG_MASK + 1]; // First, set all transitions to undefined. undefined = context.getDeclaredMethod("UNDEF", parameters); for (i = 0; i < _transition_table.length; ++i) { _transition_table[i] = undefined; } // Now go back and set the known transitions. _transition_table[TcpSegment.FIN] = context.getDeclaredMethod("FIN", parameters); _transition_table[TcpSegment.SYN] = context.getDeclaredMethod("SYN", parameters); _transition_table[TcpSegment.RST] = context.getDeclaredMethod("RST", parameters); _transition_table[TcpSegment.PSH] = context.getDeclaredMethod("PSH", parameters); _transition_table[TcpSegment.ACK] = context.getDeclaredMethod("ACK", parameters); _transition_table[TcpSegment.URG] = context.getDeclaredMethod("URG", parameters); _transition_table[TcpSegment.FIN_ACK] = context.getDeclaredMethod("FIN_ACK", parameters); _transition_table[TcpSegment.SYN_ACK] = context.getDeclaredMethod("SYN_ACK", parameters); _transition_table[TcpSegment.PSH_ACK] = context.getDeclaredMethod("PSH_ACK", parameters); } catch (Exception jex) {} }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -