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

📄 nettcp.c

📁 uC/IP Release Notes These release notes for uC/IP are divided into the following sections
💻 C
📖 第 1 页 / 共 5 页
字号:

/******************************/
/*** 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 */
    "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 */
    "ACK+P+R",                  /* 28 = 16 + 8 + 4 */
    "A+P+R+F",                  /* 29 = 16 + 8 + 4 + 1 */
    "A+P+R+S",                  /* 30 = 16 + 8 + 4 + 2 */
    "A+P+R+S+F"                 /* 31 = 16 + 8 + 4 + 2 + 1 */
};

#if ECHO_SUPPORT > 0
char tcpEchoStack[STACK_SIZE];          /* The TCP echo task stack. */
#endif

/***********************************/
/*** PUBLIC FUNCTION DEFINITIONS ***/
/***********************************/
/*
 * Initialize the TCP subsystem.
 */
void tcpInit(void)
{
    int i;
    
    /* The TCB free list. */
    memset(tcbs, 0, sizeof(tcbs));
    topTcpCB = &tcbs[0];
    for (i = 0; i < MAXTCP; i++) {
        tcbs[i].next = &tcbs[i + 1];
        /* Prev referencing self indicates that it's on the free list. */
        tcbs[i].prev = &tcbs[i];
        timerCreate(&tcbs[i].resendTimer);
        timerCreate(&tcbs[i].keepTimer);
        tcbs[i].state = CLOSED;
    }
    tcbs[MAXTCP - 1].next = NULL;

    /* The TCB hash table. */
    memset(&tcbTbl, 0, sizeof(tcbTbl));
    
    /* The TCP stats. */
#if STATS_SUPPORT > 0
    memset(&tcpStats, 0, sizeof(tcpStats));
    tcpStats.headLine.fmtStr    = "\t\tTCP STATISTICS\r\n";
    tcpStats.curFree.fmtStr     = "\tCURRENT FREE: %5lu\r\n";
    tcpStats.curFree.val        = MAXTCP;
    tcpStats.minFree.fmtStr     = "\tMINIMUM FREE: %5lu\r\n";
    tcpStats.minFree.val        = MAXTCP;
    tcpStats.runt.fmtStr        = "\tRUNT HEADERS: %5lu\r\n";
    tcpStats.checksum.fmtStr    = "\tBAD CHECKSUM: %5lu\r\n";
    tcpStats.conout.fmtStr      = "\tOUT CONNECTS: %5lu\r\n";
    tcpStats.conin.fmtStr       = "\tIN CONNECTS : %5lu\r\n";
    tcpStats.resetOut.fmtStr    = "\tRESETS SENT : %5lu\r\n";
    tcpStats.resetIn.fmtStr     = "\tRESETS REC'D: %5lu\r\n";
#endif
    
    /* The new sequence number offset. */
    newISNOffset = magic();
    
#if ECHO_SUPPORT > 0
    /* Start the TCP echo server. */
    OSTaskCreate(tcpEcho, NULL, tcpEchoStack + STACK_SIZE, PRI_ECHO);
#endif
}

/* 
 * Return a new TCP descriptor on success or an error code (negative) on 
 *  failure. 
 */
#if ONETASK_SUPPORT > 0
  int tcpOpen(
    void (*receiveEvent)(int, u_long),               
    void (*transmitEvent)(int, u_long),              
    void (*stateEvent)(int, TCPState, TCPState)      
  )
#else
int tcpOpen(void)
#endif
{
    int st;
    TCPCB *tcb;
    
    OS_ENTER_CRITICAL();
    if ((tcb = topTcpCB) != NULL) {
        topTcpCB = topTcpCB->next;
        STATS(if (--tcpStats.curFree.val < tcpStats.minFree.val)
                tcpStats.minFree.val = tcpStats.curFree.val;)
    }
    OS_EXIT_CRITICAL();
    
    if (!tcb)
        st = TCPERR_ALLOC;
    else {
        st = (int)(tcb - &tcbs[0]);
        tcb->next = tcb;        /* Self ref => unlinked. */
        tcb->prev = NULL;       /* Always NULL when neither free nor linked. */
        

#if ONETASK_SUPPORT > 0
    // Setup event functions
    tcb->receiveEvent = receiveEvent;
    tcb->transmitEvent = transmitEvent;
    tcb->stateEvent = stateEvent;
#endif

    
        tcb->freeOnClose = 0;
#if DEBUG_SUPPORT == 0               
    tcb->traceLevel = 0;
#else
        tcb->traceLevel = LOG_INFO;
#endif
        tcb->keepAlive = 0;
        tcb->keepProbes = 0;
        
        /* Grab semaphores. */
        if (!tcb->connectSem)
            if ((tcb->connectSem = OSSemCreate(0)) == NULL)
                st = TCPERR_ALLOC;
        if (!tcb->readSem)
            if ((tcb->readSem = OSSemCreate(0)) == NULL)
                st = TCPERR_ALLOC;
        if (!tcb->writeSem)
            if ((tcb->writeSem = OSSemCreate(0)) == NULL)
                st = TCPERR_ALLOC;
        if (!tcb->mutex)
            if ((tcb->mutex = OSSemCreate(1)) == NULL)
                st = TCPERR_ALLOC;
        TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpOpen[%d]: Opened", st));
    }
    
    return st;
}

/* 
 * Close a TCP connection and release the descriptor.
 * Any outstanding packets in the queues are dropped.
 * Return 0 on success when the peer acknowledges our message
 * or an error code on failure. 
 */
int tcpClose(u_int td)
{
    int st = 0;
    TCPCB *tcb = &tcbs[td];

    /* Protect from race on tcb->state. */
    OS_ENTER_CRITICAL();    
    if (td >= MAXTCP || tcb->prev == tcb) {
        OS_EXIT_CRITICAL();
        st = TCPERR_PARAM;

    } else if (tcb->state == CLOSED) {
        OS_EXIT_CRITICAL();
        TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpClose[%d]: Freeing closed", td));
        tcbFree(tcb);
        
    } else {
        /* 
         * Initiate a half-close on our side by sending a FIN.  The
         * freeOnClose flag is set so the TCB will be freed when the
         * state reaches CLOSED.  Note that a timer will limit the
         * time that we wait in FINWAIT2.
         */
        tcb->freeOnClose = !0;
        OS_EXIT_CRITICAL();
        
        st = tcpDisconnect(td);
        TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpClose[%d]: Closed", td));
    }   
    return st;
}

/*
 * Bind an IP address and port number in the sockaddr structure as our
 * address on a TCP connection.
 * Note: The IP address must be zero (wild) or equal to localHost since that
 * is all that ipDispatch() will recognize.  You can only bind a CLOSED
 * connection.
 * Return 0 on success, an error code on failure.
 */
int tcpBind(u_int td, struct sockaddr_in *myAddr)
{
    int st = 0;
    TCPCB *tcb = &tcbs[td];
    
    if (td >= MAXTCP || tcb->prev == tcb || !myAddr)
        st = TCPERR_PARAM;
    else if (myAddr->ipAddr != 0 && myAddr->ipAddr != localHost)
        st = TCPERR_INVADDR;
    else if (tcb->state != CLOSED)
        st = TCPERR_CONNECT;    /* Can't bind an active connection. */
    else {
        tcb->ipSrcAddr = htonl(myAddr->ipAddr);
        tcb->tcpSrcPort = htons(myAddr->sin_port);

        TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpBind[%d]: to %s:%u mss %d", 
                    (int)(tcb - &tcbs[0]),
                    ip_ntoa(tcb->ipSrcAddr), ntohs(tcb->tcpSrcPort),
                    tcb->mss));
    }
    
    return st;
}

/*
 * Establish a connection with a remote host.  Unless tcpBind() has been called,
 * the local IP address and port number are generated automatically.
 * Return 0 on success, an error code on failure.
 */
int tcpConnectJiffy(u_int td, const struct sockaddr_in *remoteAddr, u_char tos, u_int timeout)
{
    int st = 0;
    TCPCB *tcb = &tcbs[td];
#if ONETASK_SUPPORT == 0      
    u_long abortTime;
#endif
    long dTime = timeout;
    UBYTE err;
    
/* We don't use the timeout argument when running in a single task! 
   We also don't want to be able to block.
   And we want to be able to do a quick poll, without having to make a timeout of at least 1 jiffy. */
#if ONETASK_SUPPORT == 0      
    if (timeout)
        abortTime = jiffyTime() + timeout;
#endif
        
    if (td >= MAXTCP || tcb->prev == tcb || !remoteAddr)
        st = TCPERR_PARAM;
    else if (remoteAddr->ipAddr == 0 || remoteAddr->sin_port == 0)
        st = TCPERR_INVADDR;
    else if (tcb->ipSrcAddr == 0 && localHost == 0)
        st = TCPERR_CONFIG;
    else if (tcb->state != CLOSED)
        st = TCPERR_CONNECT;    /* Already connected! */
    else {
        tcbInit(tcb);
        tcb->ipTOS = tos;
        if (tcb->ipSrcAddr == 0)
            tcb->ipSrcAddr = htonl(localHost);
        if (tcb->tcpSrcPort == 0) {
            OS_ENTER_CRITICAL();
            tcb->tcpSrcPort = htons(tcpFreePort++);
            OS_EXIT_CRITICAL();
        }
        tcb->ipDstAddr = htonl(remoteAddr->ipAddr);
        tcb->tcpDstPort = htons(remoteAddr->sin_port);

        /* Initialize connection parameters. */     
        tcb->rcv.wnd = TCP_DEFWND;
        tcb->mss = ipMTU(tcb->ipDstAddr) - sizeof(IPHdr) - sizeof(TCPHdr);
        tcb->mss = MAX(tcb->mss, TCP_MINMSS);
        tcb->minFreeBufs = ((tcb->mss + NBUFSZ) / NBUFSZ);

        /* 
         * Load the connection structure and link the TCB into the connection
         * table so that tcpInput can find it.
         */
        tcb->conn.remoteIPAddr = tcb->ipDstAddr;
        tcb->conn.remotePort = tcb->tcpDstPort;
        tcb->conn.localIPAddr = tcb->ipSrcAddr;
        tcb->conn.localPort = tcb->tcpSrcPort;
        tcbLink(tcb);
        
        TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpConnect[%d]: to %s:%u mss %d", 
                    (int)(tcb - &tcbs[0]),
                    ip_ntoa(tcb->ipDstAddr), ntohs(tcb->tcpDstPort),
                    tcb->mss));
        
        /* Send SYN, go into SYN_SENT state */
        tcb->flags |= ACTIVE;
        sendSyn(tcb);
        setState(tcb, SYN_SENT);
        tcpOutput(tcb);
        STATS(tcpStats.conout.val++;)
        
/* We don't use the timeout argument when running in a single task! 
   We also don't want to be able to block.
   And want to be able to do a quick poll, without having to make a timeout of at least 1 jiffy. */
#if ONETASK_SUPPORT == 0      
      

⌨️ 快捷键说明

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