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

📄 nettcp.c

📁 基于东南大学开发的SEP3203的ARM7中的所有驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
            break;

            

        case SYN_RECEIVED:

        case ESTABLISHED:

            /* 

             * Initiate a half-close on our side by sending a FIN.

             * Our FIN is indicated by setting sndcnt to the number of bytes in

             * the output queue + 1. 

             */

            tcb->sndcnt++;

            tcb->snd.nxt++;

            setState(tcb, FINWAIT1);

            tcpOutput(tcb);

            break;

            

        case CLOSE_WAIT:

            /* 

             * The peer has initiated a half-close.  We'll ACK it and complete

             * the close by sending a FIN and waiting for it to be acknowledged.

             * Our FIN is indicated by setting sndcnt to the number of bytes in

             * the output queue + 1. 

             */

            tcb->sndcnt++;

            tcb->snd.nxt++;

            setState(tcb, LAST_ACK);

            tcpOutput(tcb);

            break;

            

        case FINWAIT1:

        case FINWAIT2:

        case LAST_ACK:

        case CLOSING:

        case TIME_WAIT:

            /* Do nothing - we're already closing! */

            break;

        

        case CLOSED:

            /* Nothing to do! */

            break;

        }

    }   

    return st;

}



/*

 * Set the number of backLog connections which will be queued to be picked up

 * by calls to accept.  Without this call, no connection will be opened until

 * tcpAccept() or tcpConnect() is called.

 * Return the actual size of the queue on success, an error code on failure.

 */

int tcpListen(u_int td, int backLog)

{

    int st = 0;

    TCPCB *tcb = &tcbs[td];

    

    if (td >= MAXTCP || tcb->prev == tcb)

        st = TCPERR_PARAM;

        

    else if (tcb->tcpSrcPort == 0)

        st = TCPERR_CONFIG;

        

    else {

        switch(tcb->state){

        case CLOSED:

            tcbInit(tcb);

            tcb->conn.localIPAddr = tcb->ipSrcAddr;

            tcb->conn.localPort = tcb->tcpSrcPort;

            /* XXX Do we want 0 or left over address? */

            tcb->conn.remoteIPAddr = 0;

            tcb->conn.remotePort = 0;

            tcbLink(tcb);

            setState(tcb, LISTEN);

            /* Fall through... */

        case LISTEN:

            st = tcb->listenQOpen = MIN(backLog, MAXLISTEN);

            tcb->flags |= CLONE;

            

            TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpListen[%d]: %s:%u #%u", 

                        (int)(tcb - &tcbs[0]),

                        ip_ntoa(tcb->ipSrcAddr), tcb->tcpSrcPort,

                        tcb->listenQOpen));

            break;

        case SYN_SENT:

        case SYN_RECEIVED:

        case ESTABLISHED:

        case CLOSE_WAIT:

        case FINWAIT1:

        case FINWAIT2:

        case CLOSING:

        case LAST_ACK:

        case TIME_WAIT:

            st = TCPERR_CONNECT;

            break;

        }

    }   

    

    TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpListen[%d]: %s => %d", 

                (int)(tcb - &tcbs[0]), tcbStates[tcb->state], st));

                    

    return st;

}



/*

 * Pick up a connection opened by a remote host.  tcpBind() must be used to

 * specify the local address (possibly zero) and port number (non-zero) for

 * the connection.  Unless tcpListen() has been called, no connection will

 * be accepted until this is called.

 * Return a new TCP descriptor for the opened connection on success, an

 * error code on failure.  The peer's IP and port values are returned

 * in peerAddr.

 */



int tcpAcceptJiffy(u_int td, struct sockaddr_in *peerAddr, u_int timeout)

{

    int st = 0;

    TCPCB *ntcb = NULL;

    TCPCB *tcb = &tcbs[td];

#if ONETASK_SUPPORT == 0      

    u_long abortTime;

#endif

    long dTime = timeout;

    u_int8 err;

    

    TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpAccept[%d]: accepting %s:%u", 

                (int)(tcb - &tcbs[0]),

                ip_ntoa(tcb->ipSrcAddr), ntohs(tcb->tcpSrcPort)));

                    

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

    if (timeout)

        abortTime = jiffyTime() + timeout;

#endif

        

    if (td >= MAXTCP || tcb->prev == tcb)

        st = TCPERR_PARAM;

        

    else if (tcb->tcpSrcPort == 0)

        st = TCPERR_CONFIG;

        

    else {

        switch(tcb->state){

        case CLOSED:

            tcbInit(tcb);

            tcb->conn.localIPAddr = tcb->ipSrcAddr;

            tcb->conn.localPort = tcb->tcpSrcPort;

            /* XXX Do we want 0 or whatever's in peerAddr? */

            tcb->conn.remoteIPAddr = 0;

            tcb->conn.remotePort = 0;

            tcbLink(tcb);

            setState(tcb, LISTEN);

            /* Fall through... */

        case LISTEN:

            if (tcb->flags & CLONE) {

                OS_ENTER_CRITICAL();

                while(!ntcb && !st) {

                    if (tcb->state != LISTEN) {

                        st = TCPERR_CONNECT;

                    } else if (!listenQEmpty(tcb)) {

                        listenQPop(tcb, &ntcb);

                    } else {

                        OS_EXIT_CRITICAL();



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

                        if (!timeout || (dTime = diffJTime(abortTime)) > 0)

                            OSSemPend(tcb->connectSem, (UINT)dTime, &err);

                        else

#endif

                            st = TCPERR_TIMEOUT;        /* Abort on timeout. */

                        OS_ENTER_CRITICAL();

                    } 

                }

                OS_EXIT_CRITICAL();

            } else {

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

                while(CLOSED < tcb->state && tcb->state < ESTABLISHED) {

                    if (!timeout || (dTime = diffJTime(abortTime)) > 0)

                        OSSemPend(tcb->connectSem, (UINT)dTime, &err);

                    else {

                        closeSelf(tcb, TCPERR_TIMEOUT);

                        tcbUnlink(tcb);

                    }

                }

#endif

                if (tcb->state == ESTABLISHED)

                    ntcb = tcb;

                else if (tcb->closeReason)

                    st = tcb->closeReason;

                else

                    st = TCPERR_CONNECT;

            }

            if (!st) {

                ntcb->flags &= ~CLONE;

                peerAddr->ipAddr = ntohl(tcb->ipDstAddr);

                peerAddr->sin_port = ntohs(tcb->tcpDstPort);

                st = (int)(ntcb - &tcbs[0]);

                TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpAccept[%d]: %s:%u", 

                            (int)(tcb - &tcbs[0]),

                            ip_ntoa(tcb->ipDstAddr), ntohs(tcb->tcpDstPort)));

            } else {

                TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpAccept[%d]: at %s => %d", 

                            (int)(tcb - &tcbs[0]), tcbStates[tcb->state], st));

            }

            break;

        case SYN_SENT:

        case SYN_RECEIVED:

        case ESTABLISHED:

        case CLOSE_WAIT:

        case FINWAIT1:

        case FINWAIT2:

        case CLOSING:

        case LAST_ACK:

        case TIME_WAIT:

            st = TCPERR_CONNECT;

            break;

        }

    }   

    return st;

}



/*

 * Read from a connected TCP connection.  If a timeout is non-zero, we block 

 *  until the requested data is received or the timeout expires.  Otherwise

 *  we block only until at least one byte has been received or an error

 *  occurs.

 * Note: Ideally we would return less than len bytes only if a PUSH flag

 *  was received however this is yet to be implemented.

 * Return the number of bytes read on success, an error code on failure. 

 */

int tcpRead(u_int td, void *s, u_int len)

{

    return tcpReadJiffy(td, s, len, 0);

}

int tcpReadJiffy(u_int td, void *s1, u_int len, u_int timeout)
{
    char *s = (char*)s1;
    TCPCB *tcb = &tcbs[td];
#if ONETASK_SUPPORT == 0      
    u_long abortTime = 0;
#endif
    long dTime = timeout;
    u_int i;
    u_int8 err;
    int st = 0;

/* 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      
    if (timeout)
        abortTime = jiffyTime() + timeout;
#endif

    if (td >= MAXTCP || tcb->prev == tcb)
        st = TCPERR_PARAM;
    else if (tcb->state == CLOSED
                || tcb->ipSrcAddr == 0
                || tcb->tcpSrcPort == 0
                || tcb->ipDstAddr == 0
                || tcb->tcpDstPort == 0)
        st = TCPERR_CONNECT;
    /*
     * Loop here until either we have received something, hit a snag, or had
     *  our connection closed.
     */
    else while (len) {
        /* If there's something in the receive buffer, start with that. */
        if (tcb->rcvBuf) {
            i = nTrim(s, &tcb->rcvBuf, len);
            TCPDEBUG((tcb->traceLevel + 1, TL_TCP, "tcpRead[%d]: %u:%.*H",
                        td, i, min(60, i * 2), s));
           st += i;
//          len -= i;
            len = 0;
            s += i;
            OS_ENTER_CRITICAL();
            tcb->rcvcnt -= i;
            OS_EXIT_CRITICAL();
        /* 
         * If there's something in the receive queue, dequeue the next segment. 
         * If successful, adjust our receive window.
         */
        } else if (tcb->rcvcnt != 0) {
#if 1
            nDEQUEUE(&tcb->rcvq, tcb->rcvBuf);
#else
            OS_ENTER_CRITICAL();
            if (!(&tcb->rcvq) || !tcb->rcvq.qHead) {
                OS_EXIT_CRITICAL();
                tcb->rcvBuf = NULL;
            } else {
                tcb->rcvBuf = tcb->rcvq.qHead->nextChain;
                tcb->rcvq.qHead = tcb->rcvBuf;
                if (tcb->rcvq.qHead == NULL)
                    tcb->rcvq.qTail = NULL;
                tcb->rcvq.qLen--;
                OS_EXIT_CRITICAL();
                tcb->rcvBuf->nextChain = NULL;
            }
#endif
            if (tcb->rcvBuf) {
                OS_ENTER_CRITICAL();
                i = tcb->rcv.wnd;
                /* 
                 * Since we queue buffer chains and not characters, the receive
                 * window is adjusted by multiples of buffer lengths.
                 *
                 * XXX Here we assume that normally each buffer chain is of
                 * length 1.  If this is not the case, it may be better to
                 * adjust the buffer size rather than complicate this.  Only
                 * if you want to support greatly varying segment sizes would
                 * it be worth tracking the number of buffers in each chain.
                 */
                if ((tcb->rcv.wnd += NBUFSZ) > TCP_DEFWND)
                    tcb->rcv.wnd = TCP_DEFWND;
                /* Do a window update if it was closed. */
                if (i == 0) {
                    tcb->flags |= FORCE;
                    OS_EXIT_CRITICAL();
                    tcpOutput(tcb);
                } else {
                    OS_EXIT_CRITICAL();
                }
            }

        /*
         * We've emptied the receive queue.  If we've copied something and
         *  there's no timeout, let's return what we've got rather than 
         *  waiting for more.
         *
         * XXX We should only exit here if a PUSH segment was received.
         */

/* 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      
        } 
        else if (st && !timeout)

#else
    }
    else if (st)
#endif      
            len = 0;

        

        /*

         * If we're expecting something to come in, wait for it.  Otherwise,

         * return EOF.

         */

        else switch(tcb->state) {

        case LISTEN:

        case SYN_SENT:

        case SYN_RECEIVED:

        case ESTABLISHED:

        case FINWAIT1:

        case FINWAIT2:



/* 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 || (dTime = diffJTime(abortTime)) > 0)
                OSSemPend(tcb->readSem, (UINT)dTime, &err);
            else
#endif
                len = 0;        /* Abort on timeout. */
            break;
        case CLOSED:
        case CLOSE_WAIT:
        case CLOSING:
        case LAST_ACK:
        case TIME_WAIT:
            if (tcb->closeReason)
                st = tcb->closeReason;
            else

                st = TCPERR_EOF;

            len = 0;

            break;

        }

    }


    return st;

⌨️ 快捷键说明

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