⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nettcp.c

📁 UCOS-ii对于网络的支持代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*****************************************************************************
* 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
*
* 98-02-02 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.
*	Original based on ka9q and BSD codes.
******************************************************************************
* 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 "typedefs.h"
#include "avconfig.h"
#include <string.h>
#include "stdio.h"			// Required for debug.h
#include "timer.h"
#include "avos.h"
#include "netbuf.h"
#include "devio.h"

#include "net.h"
#include "netmagic.h"
#include "netip.h"
#include "netiphdr.h"
#include "nettcp.h"
#include "nettcphd.h"

#include "debug.h"


/*************************/
/*** 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 ***/
/************************/
/*
 * Combined TCP/IP headers with no options.  Used to cached the headers.
 */
typedef	struct TcpIPHdr_s {
	IPHdr  ipHdr;		/* IP header - no options. */
	TCPHdr tcpHdr;		/* TCP header.  tcpSeq, ack, off, & win
						 * are in host byte order.
						 */
	char options[OPTSPACE];	/* Cache for TCP options. */
} TCPIPHdr;

/*
 * TCP connection states.
 */
typedef enum {
	CLOSED = 0,		/* Must be 0 */
	LISTEN = 1,
	SYN_SENT= 2,
	SYN_RECEIVED = 3,
	ESTABLISHED = 4,
	FINWAIT1 = 5,
	FINWAIT2 = 6,
	CLOSE_WAIT = 7,
	CLOSING	= 8,
	LAST_ACK = 9,
	TIME_WAIT = 10
} TCPState;


/*
 * 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;



/*
 * TCP connection control block.
 */
typedef struct TCPCB_s {
	struct TCPCB_s *prev;	/* Linked list pointers for hash table */
	struct TCPCB_s *next;
	Connection conn;		/* Connection struct for hash lookup. */	

	TCPState state;			/* Connection state */

	int freeOnClose;		/* Flag set to free TCB on close. */
	int closeReason;		/* Reason for closing - TCPERR_ or 0 */
	int traceLevel;			/* Trace level this connection. */

	/*
	 * Send sequence variables.
	 */
	struct {
		int32 una;	/* First unacknowledged sequence number */
		int32 nxt;	/* Next sequence num to be sent for the first time */
		int32 ptr;	/* Working transmission pointer */
		int16 wnd;	/* Other end's offered receive window */
		int32 wl1;	/* Sequence number used for last window update */
		int32 wl2;	/* Ack number used for last window update */
	} snd;
	int32 iss;			/* Initial send sequence number */
	int16 cwind;		/* Congestion window */
	int16 ssthresh;		/* Slow-start threshold */
	int32 resent;		/* Count of bytes retransmitted */

	/* Receive sequence variables */
	struct {
		int32 nxt;		/* Incoming sequence number expected next */
		int16 wnd;		/* Our offered receive window */
		int16 up;		/* Receive urgent pointer */
	} rcv;
	int32 irs;			/* Initial receive sequence number */
	int16 mss;			/* Maximum segment size */
	int32 rerecv;		/* Count of duplicate bytes received */
	
	int minFreeBufs;	/* Minimum free buffers before we'll queue something. */

	char backoff;		/* Backoff interval */
	char flags;			/* Control flags */

	int listenQOpen;	/* Max queued listen connections. */
	int listenQHead;	/* Head of cloned TCB queue. */
	int listenQTail;	/* Tail of cloned TCB queue. */
	struct TCPCB_s 
		*listenQ[MAXLISTEN + 1];	/* Circular queue of clones. */
	
	NBufQHdr rcvq;		/* Receive queue */
	int16 rcvcnt;		/* Bytes on receive queue. */
	NBuf *rcvBuf;		/* Hold one buffer while we trim it. */

	NBufQHdr sndq;		/* Send queue */
	int16 sndcnt;		/* Number of unacknowledged sequence numbers on
						 * send queue. NB: includes SYN and FIN, which don't
						 * actually appear on sndq!
						 */

	NBufQHdr *reseq;		/* Out-of-order segment queue */
	Timer resendTimer;			/* Timeout timer */
	u_int32 retransTime;	/* Retransmission time - 0 for none. */
	u_int retransCnt;		/* Retransmission count at current wl2. */
	u_int32 rttStart;		/* Start time for round trip measurement. */
	int32 rttseq;			/* Sequence number being timed */
	int32 srtt;				/* Smoothed round trip time, milliseconds */
	int32 mdev;				/* Mean deviation, milliseconds */
	
	u_long keepAlive;		/* Keepalive in Jiffys - 0 for none. */
	int keepProbes;			/* Number of keepalive probe timeouts. */
	u_long keepTime;		/* Jiffy time of keepalive timeout. */
	Timer keepTimer;		/* Keep alive timer */
	    
    OS_EVENT *connectSem;	/* Semaphore for connect requests. */
	OS_EVENT *readSem;		/* Semaphore for read function. */
	OS_EVENT *writeSem;		/* Semaphore for write function. */
	OS_EVENT *mutex;		/* Mutex for tcpOutput TCB variables. */
	
	TCPIPHdr hdrCache;		/* Cached TCP/IP header. */
	char *optionsPtr;		/* Ptr into TCP options area. */
} TCPCB;

/* 
 * 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 ***/
/***********************************/
static void tcpEcho(void *arg);
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 int32 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. */
	int16 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,
	int16 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, (int32)((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 *)(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 ***/
/******************************/
const DevDef tcpdef = {
	tcpdValid,
	tcpdValid,
	tcpRead,
	tcpWrite,
	
	NULL,
	NULL,
	
	tcpIOCtl
};

#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 tcpFreePort = TCP_DEFPORT;	/* Initial local port. */

int32 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 */
	"ACK+R+F",					/* 21 = 16 + 4 + 1 */
	"ACK+R+S",					/* 22 = 16 + 4 + 2 */
	"ACK+R+S+F",				/* 23 = 16 + 4 + 2 + 1 */
	"ACK+PUSH",					/* 24 = 16 + 8 */
	"ACK+P+F",					/* 25 = 16 + 8 + 1 */
	"ACK+P+S",					/* 26 = 16 + 8 + 2 */
	"ACK+P+S+F",				/* 27 = 16 + 8 + 2 + 1 */

⌨️ 快捷键说明

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