tcpcontrolblock.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 751 行 · 第 1/2 页

JAVA
751
字号
/*
 * $Id: TCPControlBlock.java,v 1.1 2003/11/25 11:52:23 epr Exp $
 */
package org.jnode.net.ipv4.tcp;

import java.net.ConnectException;
import java.net.SocketException;
import java.util.LinkedList;

import org.apache.log4j.Logger;
import org.jnode.net.SocketBuffer;
import org.jnode.net.ipv4.IPv4Address;
import org.jnode.net.ipv4.IPv4Constants;
import org.jnode.net.ipv4.IPv4ControlBlock;
import org.jnode.net.ipv4.IPv4Header;
import org.jnode.util.NumberUtils;
import org.jnode.util.TimeoutException;

/**
 * @author Ewout Prangsma (epr@users.sourceforge.net)
 */
public class TCPControlBlock extends IPv4ControlBlock implements TCPConstants {

	/** My logger */
	private final Logger log = Logger.getLogger(getClass());
	/** The outgoing channel */
	private final TCPOutChannel outChannel;
	/** The incoming channel */
	private final TCPInChannel inChannel;
	/** Last incoming sequence number */
	//private int lastInSeqNr;
	/** Window size of the outgoing connection */
	private int outWindowSize;
	/** The current state */
	private int curState;
	/** My listening parent */
	private final TCPControlBlock parent;
	/** List of connections that are established, but have not been "accepted" */
	private LinkedList readyToAcceptList = new LinkedList();
	/** Has this connection be reset? */
	private boolean reset;
	/** Has this connection been refused? */
	private boolean refused;
	/** Timeout for blocking operations */
	private int timeout = TCP_DEFAULT_TIMEOUT;

	/**
	 * Create a new instance
	 * 
	 * @param list
	 * @param parent
	 * @param tcp
	 * @param isn
	 *            The initial outgoing sequence number
	 */
	public TCPControlBlock(TCPControlBlockList list, TCPControlBlock parent, TCPProtocol tcp, int isn) {
		super(list, IPv4Constants.IPPROTO_TCP, TCP_DEFAULT_TTL);
		this.parent = parent;
		this.outChannel = new TCPOutChannel(tcp, this, isn);
		this.inChannel = new TCPInChannel(this);
		//this.tcp = tcp;
		this.curState = TCPS_CLOSED;
		this.outWindowSize = TCP_MAXWIN;
		this.reset = false;
		this.refused = false;
	}

	// ------------------------------------------
	// Receive (input) methods
	// ------------------------------------------

	/**
	 * Handle a received segment for this connection
	 * 
	 * @param hdr
	 * @param skbuf
	 */
	public synchronized void receive(TCPHeader hdr, SocketBuffer skbuf) throws SocketException {
		if (log.isDebugEnabled()) {
			log.debug("receive: me=[" + this +"], hdr=[" + hdr + "]");
		}

		final IPv4Header ipHdr = (IPv4Header) skbuf.getNetworkLayerHeader();
		final boolean ack = hdr.isFlagAcknowledgeSet();
		final boolean rst = hdr.isFlagResetSet();

		if (rst) {
			receiveProcessReset(ipHdr, hdr, skbuf);
			return;
		}

		if (ack) {
			outChannel.processAck(hdr.getAckNr());
		}

		switch (curState) {
			case TCPS_LISTEN :
				receiveListen(ipHdr, hdr, skbuf);
				break;
			case TCPS_SYN_RECV :
				receiveSynRecv(ipHdr, hdr, skbuf);
				break;
			case TCPS_SYN_SENT :
				receiveSynSend(ipHdr, hdr, skbuf);
				break;
			case TCPS_ESTABLISHED :
				receiveEstablished(ipHdr, hdr, skbuf);
				break;
			case TCPS_FIN_WAIT_1 :
				receiveFinWait1(ipHdr, hdr, skbuf);
				break;
			case TCPS_FIN_WAIT_2 :
				receiveFinWait2(ipHdr, hdr, skbuf);
				break;
			case TCPS_LAST_ACK :
				receiveLastAck(ipHdr, hdr, skbuf);
				break;
			case TCPS_CLOSING :
				receiveClosing(ipHdr, hdr, skbuf);
				break;
			case TCPS_TIME_WAIT :
				receiveTimeWait(ipHdr, hdr, skbuf);
				break;
			default :
				log.debug("Unhandled state in receive (" + getStateName() + ")");
				break;
		}
	}

	/**
	 * Process a reset segment
	 * 
	 * @param ipHdr
	 * @param hdr
	 * @param skbuf
	 */
	private final void receiveProcessReset(IPv4Header ipHdr, TCPHeader hdr, SocketBuffer skbuf) throws SocketException {
		final boolean ack = hdr.isFlagAcknowledgeSet();
		final boolean syn = hdr.isFlagSynchronizeSet();

		switch (curState) {
			case TCPS_SYN_RECV :
			case TCPS_SYN_SENT :
				notifyConnectionRefused();
				setState(TCPS_CLOSED);
				drop(ipHdr, hdr, "connection refused");
				break;

			case TCPS_ESTABLISHED :
			case TCPS_FIN_WAIT_1 :
			case TCPS_FIN_WAIT_2 :
			case TCPS_CLOSE_WAIT :
				notifyConnectionReset();
				setState(TCPS_CLOSED);
				drop(ipHdr, hdr, "connection reset");
				break;

			case TCPS_CLOSING :
			case TCPS_LAST_ACK :
			case TCPS_TIME_WAIT :
				setState(TCPS_CLOSED);
				drop(ipHdr, hdr, "connection reset");
				break;
		}

		if (syn) {
			notifyConnectionReset();
			sendRST();
			drop(ipHdr, hdr, "connection reset");
		}

		if (!ack) {
			drop(ipHdr, hdr, "ACK expected together with RST");
		}
	}

	/**
	 * Current state is LISTEN. If a SYN segment is received, send a SYN&ACK, and set the state to
	 * SYN_RECV
	 * 
	 * @param hdr
	 * @param skbuf
	 */
	private final void receiveListen(IPv4Header ipHdr, TCPHeader hdr, SocketBuffer skbuf) throws SocketException {
		log.debug("receiveListen");

		final boolean ack = hdr.isFlagAcknowledgeSet();
		final boolean syn = hdr.isFlagSynchronizeSet();

		if (ack) {
			// Drop this segment with a RST reply
			sendRST();
			drop(ipHdr, hdr, "unexpected ACK segment");
		} else if (syn) {
			// Drop if broadcast or multicast
			final IPv4Address dst = ipHdr.getDestination();
			if (dst.isBroadcast() || dst.isMulticast()) {
				// Drop this segment
				drop(ipHdr, hdr, "broadcast or multicast destination");
			} else {
				// Process the SYN request
				final TCPControlBlock copy = (TCPControlBlock) copyAndConnect(dst, ipHdr.getSource(), hdr.getSrcPort());
				copy.listenSynReceivedOnCopy(hdr, skbuf);
			}
		} else {
			// Invalid segment
			drop(ipHdr, hdr, "unexpected segment; SYN expected");
		}
	}

	/**
	 * Current state is 0, SYN segment received. This method is called on a copy of the listening
	 * control block. Send a SYN&ACK, and set the state to SYN_RECV
	 * 
	 * @param hdr
	 * @param skbuf
	 */
	private final void listenSynReceivedOnCopy(TCPHeader hdr, SocketBuffer skbuf) throws SocketException {
		log.debug("listenSynReceivedOnCopy");

		// Save the foreign seq nr
		inChannel.initISN(hdr);

		// Send the SYN&ACK TCP reply
		sendACK(TCPF_SYN, hdr.getSequenceNr() + 1);

		// Update the state
		setState(TCPS_SYN_RECV);
	}

	/**
	 * Current state is SYN_RECV.
	 */
	private final void receiveSynRecv(IPv4Header ipHdr, TCPHeader hdr, SocketBuffer skbuf) throws SocketException {
		final boolean ack = hdr.isFlagAcknowledgeSet();

		if (ack) {
			setState(TCPS_ESTABLISHED);
			parent.notifyChildEstablished(this);
		} else {
			// Invalid segment
			drop(ipHdr, hdr, "ACK expected");
		}
	}

	/**
	 * Current state is SYN_SEND.
	 */
	private final void receiveSynSend(IPv4Header ipHdr, TCPHeader hdr, SocketBuffer skbuf) throws SocketException {
		final boolean syn = hdr.isFlagSynchronizeSet();

		if (!syn) {
			// Invalid segment
			drop(ipHdr, hdr, "SYN expected");
		} else {
			// Active open , go to ESTABLISHED
			inChannel.initISN(hdr);
			sendACK(0, hdr.getSequenceNr() + 1);
			setState(TCPS_ESTABLISHED);
			//Syslog.debug("go to ESTABLISHED not implemented yet");
		}
	}

	/**
	 * Current state is ESTABLISHED, FIN segment received. Send a ACK, and set the state to
	 * CLOSE_WAIT
	 * 
	 * @param hdr
	 * @param skbuf
	 */
	private final void receiveEstablished(IPv4Header ipHdr, TCPHeader hdr, SocketBuffer skbuf) throws SocketException {
		final boolean fin = hdr.isFlagFinishedSet();
		// Process the data
		inChannel.processData(ipHdr, hdr, skbuf);
		// FIN received, then change state
		if (fin) {
			setState(TCPS_CLOSE_WAIT);
		}
	}

	/**
	 * State is FIN_WAIT_1, any segment received
	 * 
	 * @param hdr
	 * @param skbuf
	 */
	private final void receiveFinWait1(IPv4Header ipHdr, TCPHeader hdr, SocketBuffer skbuf) throws SocketException {
		final boolean fin = hdr.isFlagFinishedSet();
		final boolean ack = hdr.isFlagAcknowledgeSet();
		// Process the data
		inChannel.processData(ipHdr, hdr, skbuf);
		// Update state (if required)
		if (fin && ack) {
			setState(TCPS_TIME_WAIT);
		} else if (fin) {
			setState(TCPS_CLOSING);
		} else if (ack) {
			setState(TCPS_FIN_WAIT_2);
		} else {
			// Invalid segment
			drop(ipHdr, hdr, "FIN and/or ACK expected");
		}
	}

	/**
	 * State is FIN_WAIT_2, any segment received
	 * 
	 * @param hdr
	 * @param skbuf
	 */
	private final void receiveFinWait2(IPv4Header ipHdr, TCPHeader hdr, SocketBuffer skbuf) throws SocketException {
		final boolean fin = hdr.isFlagFinishedSet();
		// Process the data
		inChannel.processData(ipHdr, hdr, skbuf);
		// Update state
		if (fin) {
			setState(TCPS_TIME_WAIT);
		} else {
			// Invalid segment
			drop(ipHdr, hdr, "FIN expected");
		}
	}

	/**
	 * State is LAST_ACK, any segment received
	 * 
	 * @param hdr
	 * @param skbuf
	 */
	private final void receiveLastAck(IPv4Header ipHdr, TCPHeader hdr, SocketBuffer skbuf) throws SocketException {
		final boolean ack = hdr.isFlagAcknowledgeSet();
		if (ack) {
			setState(TCPS_CLOSED);
		} else {
			// Invalid segment
			drop(ipHdr, hdr, "ACK expected");
		}
	}

	/**
	 * State is CLOSING, any segment received
	 * 
	 * @param hdr
	 * @param skbuf
	 */
	private final void receiveClosing(IPv4Header ipHdr, TCPHeader hdr, SocketBuffer skbuf) throws SocketException {
		final boolean ack = hdr.isFlagAcknowledgeSet();
		if (ack) {
			setState(TCPS_TIME_WAIT);
		} else {
			// Invalid segment
			drop(ipHdr, hdr, "ACK expected");
		}
	}

	/**
	 * State is TIME_WAIT, discard any segments
	 * 
	 * @param hdr
	 * @param skbuf
	 */
	private final void receiveTimeWait(IPv4Header ipHdr, TCPHeader hdr, SocketBuffer skbuf) throws SocketException {
		drop(ipHdr, hdr, "discard all in TIME_WAIT state");
	}

	// ------------------------------------------
	// Timeout methods
	// ------------------------------------------

	/**
	 * Process timeout handling
	 */
	public void timeout() {
		try {
			outChannel.timeout();
		} catch (SocketException ex) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?