📄 nettcp.c
字号:
/*****************************************************************************
* nettcp.c - Network Transport Control Protocol program file.
*
* Copyright (c) 1998 by Global Election Systems Inc. All rights reserved.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY (please don't use tabs!)
*
*(yyyy-mm-dd)
* 1998-02-02 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
* Original based on ka9q and BSD codes.
* 2001-05-18 Mads Christiansen <mads@mogi.dk>, Partner Voxtream
* Added support for running uC/IP in a single proces and on ethernet.
* Bugfix in resendTimeout, diffTime -> diffJTime!
* 2001-06-07 Robert Dickenson <odin@pnc.com.au>, Cognizant Pty Ltd.
* Quick fix to tcpInput for when OSSemCreate hadn't been called.
*
******************************************************************************
* NOTES
*
* MAXIMUM WINDOW
* We use a signed short int for the segment size adjustment (trimSeg()) to
* allow returning error codes. Thus our maximum segment size must be <=
* INT_MAX (i.e. 32767) rather than MAX_UINT. This is not a problem
* considering that we are using a PPP link over a serial link.
*
* HEADER CACHE
* The header values are all loaded in the header caches before being
* written to the outgoing segment so that a debugger can see the values
* of the header last sent.
******************************************************************************
* TO DO
*
* - Implement a SENDFIN flag in the tcb flags and use it in tcpOutput().
* - FINISH close!
*****************************************************************************/
#include "netconf.h"
#include <string.h>
#include "net.h"
#include "nettimer.h"
#include "netbuf.h"
#if MD5_SUPPORT > 0
#include "netrand.h"
#endif
#include "netmagic.h"
//#include "devio.h"
#include "netip.h"
#include "netiphdr.h"
#include "nettcp.h"
#include "nettcphd.h"
#include <stdio.h>
#include "netdebug.h"
/*#pragma warning (push)
#pragma warning (disable: 4761) // integral size mismatch in argument; conversion supplied
#pragma warning (disable: 4018) // signed/unsigned mismatch*/
/*************************/
/*** LOCAL DEFINITIONS ***/
/*************************/
/* Configuration */
#define MAXTCP 6 /* Maximum TCP connections incl listeners. */
#define TCPTTL 64 /* Default time-to-live for TCP datagrams. */
#define OPTSPACE 5*4 /* TCP options space - must be a multiple of 4. */
#define NTCB 16 /* # TCB hash table headers */
#define MAXRETRANS 12 /* Maximum retransmissions. */
#define MAXKEEPTIMES 10 /* Maximum keep alive probe timeouts. */
#define MAXLISTEN 2 /* Maximum queued cloned listen connections. */
#define MAXFINWAIT2 600L /* Max time in seconds to wait for peer FIN. */
#define WRITESLEEP TICKSPERSEC /* Sleep time write waits for buffers (jiffies). */
//#define STACK_SIZE NETSTACK /* Minimal stack. */
/*
* TCP connection control flag masks.
*/
#define FORCE 1 /* We owe the other end an ACK or window update */
#define CLONE 2 /* Server-type TCB, cloned on incoming SYN */
#define RETRAN 4 /* A retransmission has occurred */
#define ACTIVE 8 /* TCB created with an active open */
#define SYNACK 16 /* Our SYN has been acked */
#define KEEPALIVE 32 /* Send a keepalive probe */
/* Round trip timing parameters */
#define AGAIN 8 /* Average RTT gain = 1/8 */
#define DGAIN 4 /* Mean deviation gain = 1/4 */
#define MSL2 30 /* Guess at two maximum-segment lifetimes in seconds */
/* procInFlags return codes. */
#define ACKOK 0 /* OK to process segment. */
#define ACKDROP -1 /* Drop the segment. */
#define ACKRESET -2 /* Return segment as a reset. */
#define ACKCLOSE -3 /* Close the connection. */
/************************/
/*** LOCAL DATA TYPES ***/
/************************/
/*
* TCP session close reason codes.
*/
typedef enum {
NORMAL = 0, /* Normal close */
RESET = 1, /* Reset by other end */
TIMEOUT = 2, /* Excessive retransmissions */
NETWORK = 3 /* Network problem (ICMP message) */
} TCPReason;
/*
* Shorthand for common fields.
*/
#define ipVersion hdrCache.ipHdr.ip_v
#define ipHdrLen hdrCache.ipHdr.ip_hl
#define ipTOS hdrCache.ipHdr.ip_tos
#define ipLen hdrCache.ipHdr.ip_len /* Host byte order! */
#define ipIdent hdrCache.ipHdr.ip_id /* Host byte order! */
#define ipTTL hdrCache.ipHdr.ip_ttl
#define ipProto hdrCache.ipHdr.ip_p
#define ipSrcAddr hdrCache.ipHdr.ip_src.s_addr /* Network byte order! */
#define ipDstAddr hdrCache.ipHdr.ip_dst.s_addr /* Network byte order! */
#define tcpSrcPort hdrCache.tcpHdr.srcPort /* Network byte order! */
#define tcpDstPort hdrCache.tcpHdr.dstPort /* Network byte order! */
#define tcpSeq hdrCache.tcpHdr.seq /* Network byte order! */
#define tcpAck hdrCache.tcpHdr.ack /* Network byte order! */
#define tcpHdrLen hdrCache.tcpHdr.tcpOff
#define tcpFlags hdrCache.tcpHdr.flags
#define tcpWin hdrCache.tcpHdr.win /* Network byte order! */
#define tcpCkSum hdrCache.tcpHdr.ckSum
#define tcpUrgent hdrCache.tcpHdr.urgent /* Network byte order! */
#define tcpOptions hdrCache.options
/***********************************/
/*** LOCAL FUNCTION DECLARATIONS ***/
/***********************************/
#if ECHO_SUPPORT > 0
/*static void tcpEcho(void);*/
#endif
static void resendTimeout(void *arg);
static void keepTimeout(void *arg);
static void setState(TCPCB *tcb, TCPState newState);
static int procInFlags(TCPCB *tcb, TCPHdr *tcpHdr, IPHdr *ipHdr);
static void tcbInit(register TCPCB *tcb);
static void tcbUpdate(register TCPCB *tcb, register TCPHdr *tcpHdr);
static void procSyn(register TCPCB *tcb, TCPHdr *tcpHdr);
static void sendSyn(register TCPCB *tcb);
static void closeSelf(register TCPCB *tcb, int reason);
static u_int32_t newISS(void);
static void tcpOutput(TCPCB *tcb);
static u_int tcbHash(Connection *conn);
static void tcbLink(register TCPCB *tcb);
static void tcbUnlink(register TCPCB *tcb);
static TCPCB * tcbLookup(Connection *conn);
static void tcbFree(TCPCB *tcb);
static void tcpReset(
NBuf *inBuf, /* The input segment. */
IPHdr *ipHdr, /* The IP header in the segment. */
TCPHdr *tcpHdr, /* The TCP header in the segment. */
u_int16_t segLen /* The TCP segment length. */
);
static INT tcpdValid(UINT tcpd);
/*
* trimSeg - Trim segment to fit window.
* Return the new segment length, -1 if segment is unaccepable.
*/
static int trimSeg(
register TCPCB *tcb,
register TCPHdr *tcpHdr,
NBuf *nb,
u_int hdrLen,
u_int16_t segLen
);
/*
* backOff - Backoff function - the subject of much research.
*
* Use binary exponential up to retry #4, and quadratic after that
* This yields the sequence
* 1, 2, 4, 8, 16, 25, 36, 49, 64, 81, 100 ...
*/
#define backOff(n) ((n) <= 4 ? 1 << (n) : (n) * (n))
/*
* Sequence number comparisons.
*/
#define seqWithin(x, low, high) \
(((low) <= (high)) ? ((low) <= (x) && (x) <= (high)) : ((low) >= (x) && (x) >= (high)))
#define seqLT(x, y) ((long)((x) - (y)) < 0)
#define seqLE(x,y) ((long)((x) - (y)) <= 0)
#define seqGT(x,y) ((long)((x) - (y)) > 0)
#define seqGE(x,y) ((long)((x) - (y)) >= 0)
/*
* Determine if the given sequence number is in our receiver window.
* NB: must not be used when window is closed!
*/
#define inWindow(tcb, seq) \
seqWithin((seq), (tcb)->rcv.nxt, (u_int32_t)((tcb)->rcv.nxt + (tcb)->rcv.wnd - 1))
/*
* Put a data in host order into a char array in network order
* and advance the pointer.
*/
#define put32(cp, x) (*((u_int32 *)(cp))++ = ntohl(x))
#define put16(cp, x) (*((u_int16_t *)(cp))++ = ntohs(x))
/*
* Operators for the cloned listen connection queue. These should be
* used within a critical section.
*/
#define listenQLen(tcb) \
((tcb)->listenQHead > (tcb)->listenQTail \
? (tcb)->listenQHead - (tcb)->listenQTail \
: (tcb)->listenQTail - (tcb)->listenQHead)
#define listenQEmpty(tcb) ((tcb)->listenQHead == (tcb)->listenQTail)
#define listenQPush(tcb, ntcb) { \
OS_ENTER_CRITICAL(); \
if (listenQLen((tcb)) < (tcb)->listenQOpen) { \
(tcb)->listenQ[(tcb)->listenQHead] = (ntcb); \
(tcb)->listenQHead = ((tcb)->listenQHead + 1) % MAXLISTEN; \
} \
OS_EXIT_CRITICAL(); \
}
#define listenQPop(tcb, ntcbp) { \
if ((tcb)->listenQHead != (tcb)->listenQTail) { \
*(ntcbp) = (tcb)->listenQ[(tcb)->listenQTail]; \
(tcb)->listenQTail = ((tcb)->listenQTail + 1) % MAXLISTEN; \
} else \
(ntcb) = NULL; \
}
/******************************/
/*** PUBLIC DATA STRUCTURES ***/
/******************************/
#if 0
const DevDef tcpdef = {
tcpdValid,
tcpdValid,
tcpRead,
tcpWrite,
NULL,
NULL,
tcpIOCtl
};
#endif
#if STATS_SUPPORT > 0
TCPStats tcpStats;
#endif
/*****************************/
/*** LOCAL DATA STRUCTURES ***/
/*****************************/
/*
* TCP Control block free list.
*/
TCPCB tcbs[MAXTCP];
TCPCB *topTcpCB; /* Ptr to top TCB on free list. */
TCPCB *tcbTbl[NTCB]; /* Hash table for lookup. */
u_int16_t tcpFreePort = TCP_DEFPORT; /* Initial local port. */
u_int32_t newISNOffset; /* Offset for the next sequence number. */
/* TCB state labels for debugging. */
char *tcbStates[] = {
"CLOSED",
"LISTEN",
"SYN_SENT",
"SYN_RECEIVED",
"ESTABLISHED",
"FINWAIT1",
"FINWAIT2",
"CLOSE_WAIT",
"CLOSING",
"LAST_ACK",
"TIME_WAIT"
};
/* TCP Header Flag labels. */
#define TCPFLAGLABELMASK 0x1F /* We don't display URGENT. */
const char *tcpFlagLabel[] = {
"NONE", /* 0 */
"FIN", /* 1 */
"SYN", /* 2 */
"SYN+FIN", /* 3 = 2 + 1 */
"RST", /* 4 */
"RST+FIN", /* 5 = 4 + 1 */
"RST+SYN", /* 6 = 4 + 2 */
"RST+S+F", /* 7 = 4 + 2 + 1 */
"PUSH", /* 8 */
"PUSH+FIN", /* 9 = 8 + 1 */
"PUSH+SYN", /* 10 = 8 + 2 */
"PUSH+S+F", /* 11 = 8 + 2 + 1 */
"PUSH+RST", /* 12 = 8 + 4 */
"PUSH+R+F", /* 13 = 8 + 4 + 1 */
"PUSH+R+S", /* 14 = 8 + 4 + 2 */
"PUSH+R+S+F", /* 15 = 8 + 4 + 2 + 1 */
"ACK", /* 16 */
"ACK+FIN", /* 17 = 16 + 1 */
"ACK+SYN", /* 18 = 16 + 2 */
"ACK+S+F", /* 19 = 16 + 2 + 1 */
"ACK+RST", /* 20 = 16 + 4 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -