tcpoutchannel.java

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

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

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

import org.apache.log4j.Logger;
import org.jnode.net.ipv4.IPv4Header;

/**
 * @author Ewout Prangsma (epr@users.sourceforge.net)
 */
public class TCPOutChannel {
	
	/** My logger */
	private final Logger log = Logger.getLogger(getClass());
	/** The protocol */
	private final TCPProtocol tcp;
	/** All unacked segments */
	private final LinkedList unackedSegments = new LinkedList();
	/** The outgoing databuffer */
	private final TCPDataBuffer dataBuffer;
	/** Send unacknowledged */
	private int snd_unack;
	/** Send next seq-nr */
	private int snd_next;
	/** Highest seq-nr sent; used to recognize retransmits */
	private int snd_max;
	/** Maximum segment size (determined by the foreign part of the connection */
	private int mss;
	/** The control block I belong to */
	private final TCPControlBlock controlBlock;
	/** Number of ticks before a retransmit timeout */
	private int timeoutTicks = 6;
	
	/**
	 * Create a new instance
	 */
	public TCPOutChannel(TCPProtocol tcp, TCPControlBlock controlBlock, int isn) {
		this.tcp = tcp;
		this.controlBlock = controlBlock;
		this.dataBuffer = new TCPDataBuffer(TCPConstants.TCP_BUFFER_SIZE);
		this.snd_unack = isn;
		this.snd_next = isn;
		this.snd_max = isn;
		this.mss = TCPConstants.TCP_DEFAULT_MSS;
	}
	
	/**
	 * Process an ack-nr.
	 * Remove all segments that have been acknowledged and remove
	 * the occupied data from the databuffer.
	 * @param ackNr
	 */
	public synchronized void processAck(int ackNr) {
		// Is the ack valid?
		if (snd_unack == ackNr) {
			// Not a new ack, ignore it
			return;
		} else if (!TCPUtils.SEQ_LT(snd_unack, ackNr)) {
			// snd_unack < ackNr violated
			log.debug("snd_unack < ackNr violated");
			return;
		}
		if (!TCPUtils.SEQ_LE(ackNr, snd_max)) {
			// ackNr <= snd_max violated
			log.debug("ackNr <= snd_max violated");
			return;
		}
		
		// The ackNr is valid
		final int diff = ackNr - snd_unack;
		snd_unack = ackNr;
		// Remove data from the databuffer
		dataBuffer.pull(diff);
		for (Iterator i = unackedSegments.iterator(); i.hasNext(); ) {
			final TCPOutSegment seg = (TCPOutSegment)i.next();
			final int seqNr = seg.getSeqNr();
			if (TCPUtils.SEQ_LT(seqNr, ackNr)) {
				// Remove the segment
				i.remove();
			} else {
				// Adjust the dataOffset
				seg.adjustDataOffset(diff);
			}
		}
		// Notify any blocked threads
		notifyAll();
	}
	
	/**
	 * Process timeout handling
	 */
	public void timeout() 
	throws SocketException {
		for (Iterator i = unackedSegments.iterator(); i.hasNext(); ) {
			final TCPOutSegment seg = (TCPOutSegment)i.next();
			seg.timeout(tcp);
		}
	}
	
	/**
	 * Send a TCP segment containing no data
	 * @param ipHdr
	 * @param hdr
	 */
	public void send(IPv4Header ipHdr, TCPHeader hdr)
	throws SocketException {
		// Check the datalength
		if (hdr.getDataLength() != 0) {
			throw new IllegalArgumentException("dataLength must be 0");
		}
		// Do the actual send
		sendHelper(ipHdr, hdr, 0);
	}

	/**
	 * Send a TCP segment containing the given data.
	 * This method blocks until there is enough space in the output buffer
	 * to hold the data.
	 * @param ipHdr
	 * @param hdr
	 * @param data
	 * @param offset
	 * @param length Must be smaller or equal to mss. 
	 */
	public synchronized void send(IPv4Header ipHdr, TCPHeader hdr, byte[] data, int offset, int length)
	throws SocketException {
		log.debug("outChannel.send(ipHdr,hdr,data," + offset + ", " + length + ")");
		// Check for maximum datalength
		if (length > mss) {
			throw new IllegalArgumentException("dataLength must be <= mss");
		}
		// Wait until there is space in the output buffer
		while ((length > dataBuffer.getFreeSize()) && !controlBlock.isReset()) {
			try {
				wait();
			} catch (InterruptedException ex) {
				// Ignore
			}
		}
		if (controlBlock.isReset()) {
			throw new SocketException("Connection reset");
		}
		// Add to databuffer
		final int bufOfs = dataBuffer.add(data, offset, length);
		// Update tcp header
		hdr.setDataLength(length);
		// Do the actual send
		sendHelper(ipHdr, hdr, bufOfs);
	}

	/**
	 * Do the actual sending and adjusting of sequence number.
	 * @param ipHdr
	 * @param hdr
	 * @param dataOffset
	 */
	private final void sendHelper(IPv4Header ipHdr, TCPHeader hdr, int dataOffset) 
	throws SocketException {
		// Adjust the sequence numbers
		hdr.setSequenceNr(snd_next);
		if (hdr.isFlagSynchronizeSet() || hdr.isFlagFinishedSet()) {
			snd_next++;
			//snd_unack++;
		} else {
			snd_next += hdr.getDataLength();
		}
		snd_max = snd_next;
		// Create & send the segment
		final TCPOutSegment seg = new TCPOutSegment(ipHdr, hdr, dataBuffer, 0, timeoutTicks);
		seg.send(tcp);
		if (!seg.isAckOnly() && !hdr.isFlagSynchronizeSet()) {
			log.debug("Adding segment " + seg.getSeqNr() + " to unacklist");
			unackedSegments.add(seg);
		}		
	}

	/**
	 * Notify a connection reset
	 */
	public synchronized void notifyConnectionReset() {
		notifyAll();
	}
	
	/**
	 * @return Returns the mss.
	 */
	public final int getMss() {
		return this.mss;
	}

	/**
	 * @param mss The mss to set.
	 */
	public final void setMss(int mss) {
		this.mss = mss;
	}

}

⌨️ 快捷键说明

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