tcpcontrolblock.java
来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 751 行 · 第 1/2 页
JAVA
751 行
log.error("Error in timeout of " + this, ex);
}
}
// ------------------------------------------
// Utility methods
// ------------------------------------------
/**
* Notify a segment drop to the debug log
*/
private void drop(IPv4Header ipHdr, TCPHeader hdr, String reason) {
log.debug("Dropping segment due to: " + reason);
}
/**
* Send a ACK segment
*/
protected final void sendACK(int extraFlags, int ackNr) throws SocketException {
log.debug("sendACK(0x" + NumberUtils.hex(extraFlags, 4) + ", " + (ackNr & 0xFFFFFFFFL) + ")");
// Create the FIN TCP reply
final TCPHeader replyHdr = createOutgoingTCPHeader(extraFlags | TCPF_ACK, ackNr);
// ACK takes 0 seq-nrs, so don't increment snd_next
// Create the IP reply header
final IPv4Header replyIp = createOutgoingIPv4Header();
// Send the reply
outChannel.send(replyIp, replyHdr);
}
/**
* Send a FIN segment
*/
private final void sendFIN() throws SocketException {
log.debug("sendFIN");
// Create the FIN TCP reply
final TCPHeader replyHdr = createOutgoingTCPHeader(TCPF_FIN | TCPF_ACK, inChannel.getRcvNext());
// Create the IP reply header
final IPv4Header replyIp = createOutgoingIPv4Header();
// Send the reply
outChannel.send(replyIp, replyHdr);
}
/**
* Send a RST segment
*/
private final void sendRST() throws SocketException {
log.debug("sendRST");
// Create the RST TCP reply
final TCPHeader replyHdr = createOutgoingTCPHeader(TCPF_RST, 0);
// RST takes 0 seg-nrs TODO is this correct????
// Create the IP reply header
final IPv4Header replyIp = createOutgoingIPv4Header();
// Send the reply
outChannel.send(replyIp, replyHdr);
}
/**
* Send a SYN segment
*/
private final void sendSYN() throws SocketException {
log.debug("sendSYN");
// Create the SYN TCP
final TCPHeader hdr = createOutgoingTCPHeader(TCPF_SYN, 0);
// Create the IP reply header
final IPv4Header ipHdr = createOutgoingIPv4Header();
// Send the reply
outChannel.send(ipHdr, hdr);
}
/**
* Notify this listening parent that one of my children have established a connection.
*
* @param child
*/
private synchronized void notifyChildEstablished(TCPControlBlock child) throws SocketException {
if (isState(TCPS_LISTEN)) {
// Put on the waiting list for accept to handle and notify blocked threads.
readyToAcceptList.add(child);
notifyAll();
} else {
// I'm not listening anymore, close the connection.
child.appClose();
}
}
/**
* Notify a connection reset
*/
private synchronized void notifyConnectionReset() {
this.reset = true;
inChannel.notifyConnectionReset();
outChannel.notifyConnectionReset();
notifyAll();
}
/**
* Notify a connection refused
*/
private void notifyConnectionRefused() {
this.refused = true;
notifyAll();
}
/**
* Is the current state equal to the given state?
*
* @param state
* @return
*/
private boolean isState(int state) {
return (this.curState == state);
}
/**
* Update the state and notify any waiting threads
*
* @param state
*/
private synchronized void setState(int state) throws SocketException {
if (this.curState != state) {
this.curState = state;
if (state == TCPS_CLOSED) {
super.removeFromList();
}
notifyAll();
}
}
/**
* Wait until the state is equal to the given state or the connection is reset or refused.
*/
private synchronized void waitUntilState(int state, long timeout) throws TimeoutException {
final long start = System.currentTimeMillis();
while (!isState(state) && !isReset() && !isRefused()) {
final long now = System.currentTimeMillis();
if ((start + timeout <= now) && (timeout > 0)) {
// We have a timeout
throw new TimeoutException();
}
try {
wait(timeout - (now - start));
} catch (InterruptedException ex) {
// Ignore
}
}
}
/**
* Create a TCP header for outgoing trafic
*
* @param options
* @return The created TCP header
*/
protected TCPHeader createOutgoingTCPHeader(int options, int ackNr) {
final TCPHeader hdr = new TCPHeader(getLocalPort(), getForeignPort(), 0, 0, ackNr, outWindowSize, 0);
hdr.setFlags(options);
return hdr;
}
// ------------------------------------------
// Application methods
// ------------------------------------------
/**
* Wait for incoming requests
*
* @throws SocketException
*/
public synchronized void appListen() throws SocketException {
if (!isState(TCPS_CLOSED)) {
throw new SocketException("Invalid connection state " + getStateName());
}
setState(TCPS_LISTEN);
}
/**
* Active connect to a foreign address. This method blocks until the connection has been
* established.
*
* @throws SocketException
*/
public synchronized void appConnect(IPv4Address fAddr, int fPort) throws SocketException {
if (!isState(TCPS_CLOSED)) {
throw new SocketException("Invalid connection state " + getStateName());
}
super.connect(getLocalAddress(), fAddr, fPort);
for (int attempt = 0; attempt < TCP_MAXCONNECT; attempt++) {
try {
// Send the SYN
sendSYN();
// Update the state
setState(TCPS_SYN_SENT);
// Wait for an ESTABLISHED state
waitUntilState(TCPS_ESTABLISHED, timeout);
// Check for reset condition
if (isRefused()) {
throw new ConnectException("Connection refused");
}
log.debug("Connected to " + fAddr + ":" + fPort);
return;
} catch (TimeoutException ex) {
// Ignore and just try again
}
}
// Not succeeded to connect
throw new ConnectException("Connection request timeout");
}
/**
* Wait for an established connection.
*
* @return The accepted connection
*/
public synchronized TCPControlBlock appAccept() {
while (true) {
if (!readyToAcceptList.isEmpty()) {
final TCPControlBlock child = (TCPControlBlock) readyToAcceptList.getFirst();
readyToAcceptList.remove(child);
return child;
} else {
try {
wait();
} catch (InterruptedException ex) {
// Ignore
}
}
}
}
/**
* Active close the connection by the application.
*/
public synchronized void appClose() throws SocketException {
if (log.isDebugEnabled()) {
log.debug("active close state=" + getStateName());
}
try {
switch (curState) {
case TCPS_SYN_RECV :
case TCPS_ESTABLISHED :
{
sendFIN();
setState(TCPS_FIN_WAIT_1);
waitUntilState(TCPS_CLOSED, 0);
}
break;
case TCPS_SYN_SENT :
case TCPS_LISTEN :
{
setState(TCPS_CLOSED);
}
break;
case TCPS_CLOSE_WAIT :
{
sendFIN();
setState(TCPS_LAST_ACK);
waitUntilState(TCPS_CLOSED, 0);
}
break;
default :
throw new SocketException("Illegal state in close (" + getStateName() + ")");
}
} catch (TimeoutException ex) {
throw (SocketException) new SocketException("Timeout").initCause(ex);
}
if (isReset()) {
throw new SocketException("Connection reset");
}
}
/**
* Send data to the foreign side. This method can split-up the data in chunks and blocks until
* there is space in the send buffer to hold the data.
*
* @param data
* @param offset
* @param length
* @throws SocketException
*/
public void appSendData(byte[] data, int offset, int length) throws SocketException {
log.debug("appSendData(data, " + offset + ", " + length + ")");
if (!isState(TCPS_ESTABLISHED) && !isState(TCPS_CLOSE_WAIT)) {
throw new SocketException("Illegal state to send data: " + getStateName());
}
if (offset < 0) {
throw new IllegalArgumentException("offset " + offset);
}
if (length < 0) {
throw new IllegalArgumentException("length " + length);
}
final int mss = outChannel.getMss();
while (length > 0) {
final int chunk = Math.min(length, mss);
// Create the TCP header
final TCPHeader hdr = createOutgoingTCPHeader(TCPF_ACK, inChannel.getRcvNext());
// Create the IP header
final IPv4Header ipHdr = createOutgoingIPv4Header();
// Send the chunk of data
outChannel.send(ipHdr, hdr, data, offset, chunk);
// Update length & offset
offset += chunk;
length -= chunk;
}
}
/**
* Return the number of available bytes in the input buffer.
*/
public int appAvailable() {
return inChannel.available();
}
/**
* Read data from the input buffer up to len bytes long. Block until there is data available.
*
* @param dst
* @param off
* @param len
* @return The number of bytes read
*/
public int appRead(byte[] dst, int off, int len) throws SocketException {
return inChannel.read(dst, off, len);
}
/**
* @return Returns the state.
*/
public final int getState() {
return this.curState;
}
/**
* @return Returns the name of the current state.
*/
public final String getStateName() {
return TCP_STATE_NAMES[this.curState];
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return super.toString() + ", state " + TCP_STATE_NAMES[curState];
}
/**
* Has this connection been reset
*
* @return Returns the reset.
*/
public final boolean isReset() {
return this.reset;
}
/**
* @return Returns the refused.
*/
public final boolean isRefused() {
return this.refused;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?