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

📄 nettcp.c

📁 一个tcp/ip协议栈,带有PPP、IP、TCP、UDP等协议
💻 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 (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"
#include "netos.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 12           /* 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 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 {
        u_int32_t una;  /* First unacknowledged sequence number */
        u_int32_t nxt;  /* Next sequence num to be sent for the first time */
        u_int32_t ptr;  /* Working transmission pointer */
        u_int16_t wnd;  /* Other end's offered receive window */
        u_int32_t wl1;  /* Sequence number used for last window update */
        u_int32_t wl2;  /* Ack number used for last window update */
    } snd;
    u_int32_t iss;          /* Initial send sequence number */
    u_int16_t cwind;        /* Congestion window */
    u_int16_t ssthresh;     /* Slow-start threshold */
    u_int32_t resent;       /* Count of bytes retransmitted */

    /* Receive sequence variables */
    struct {
        u_int32_t nxt;      /* Incoming sequence number expected next */
//        u_int16_t wnd;      /* Our offered receive window */
        short wnd;          /* Our offered receive window */
        u_int16_t up;       /* Receive urgent pointer */
    } rcv;
    u_int32_t irs;          /* Initial receive sequence number */
    u_int16_t mss;          /* Maximum segment size */
    u_int32_t 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 */
    u_int16_t rcvcnt;       /* Bytes on receive queue. */
    NBuf *rcvBuf;       /* Hold one buffer while we trim it. */

    NBufQHdr sndq;      /* Send queue */
    u_int16_t 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. */
    u_int32_t rttseq;           /* Sequence number being timed */
    u_int32_t srtt;             /* Smoothed round trip time, milliseconds */
    u_int32_t 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. */

#if ONETASK_SUPPORT > 0
  // When running in a single task, we want to use callback functions...
  void (*receiveEvent)(int td, u_long cnt);               /* Called when new data has arrived */
  void (*transmitEvent)(int td, u_long cnt);              /* Called when ready to transmit more data */
  void (*stateEvent)(int td, TCPState oldState, TCPState newState); /* Called when connection state changes */
#endif

} 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 ***/
/***********************************/
#if ECHO_SUPPORT > 0
static void tcpEcho(void *arg);
#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; \
}

⌨️ 快捷键说明

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