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

📄 nettcp.c

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



/*

 * Write to a connected TCP connection.  This blocks until either all bytes

 *  are queued, the timeout is reached, or an error occurs.

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

 */

int tcpWrite(u_int td, const void *s, u_int len)

{

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

}

int tcpWriteJiffy(u_int td, const void *s1, u_int len, u_int timeout)

{

    const char *s = (char*)s1;

    TCPCB *tcb = &tcbs[td];

    NBuf *outBuf = NULL;

#if ONETASK_SUPPORT == 0      

    u_long abortTime;

#endif

    long dTime = timeout;

    u_int segSize;

    int sendSize;

    int st = 0;

    u_int8 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)

        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 queued our data, hit a snag, had

     * our connection closed, or timed out.

     */

    else while (len) {

        /* 

         * Wait for space in the queue to queue up what we've got up to

         * a full length segment. 

         */

        OS_ENTER_CRITICAL();

        sendSize = tcb->snd.wnd - tcb->sndcnt;

        OS_EXIT_CRITICAL();

        sendSize = MIN((unsigned)sendSize, len);

        sendSize = MIN(sendSize, tcb->mss);

        

        /*

         * Block if we can't send anything or if we've got our quota of 

         * outstanding segments already in the queue.  It's up to the

         * input side to wake us up when things open up.

         */

        if (sendSize <= 0 || tcb->sndq.qLen >= TCP_MAXQUEUE) {



/* 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->writeSem, (UINT)dTime, &err);

            else

#endif

                len = 0;        /* Abort on timeout. */

            

        /* 

         * Get a network buffer to fill.  Ensure that enough buffers remain

         * on the free list to enable receiving an acknowledgement on a full

         * length segment.

         * If we fail, poll for free buffers until we get one or we time out.

         */

        } else if (!outBuf) {

            if (nBUFSFREE() < (unsigned long)(tcb->minFreeBufs + (sendSize / NBUFSZ) * 2)) {



/* 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->writeSem, MIN((UINT)dTime, WRITESLEEP), &err);

                else

#endif

                    len = 0;        /* Abort on timeout. */

                    

            } else {

                nGET(outBuf);

            }

            /* Loop again and update the open size. */

        

        /*

         * Prepare and queue whatever we can.

         */

        } else {

            nAPPEND(outBuf, s, (unsigned)sendSize, segSize);

            if (segSize > 0) {

                TCPDEBUG((tcb->traceLevel + 1, TL_TCP, "tcpWrite[%d]: %u:%.*H",

                            td, segSize, min(60, segSize * 2), s));

                len -= segSize;

                s += segSize;

                switch(tcb->state) {

                case SYN_SENT:

                case SYN_RECEIVED:

                case ESTABLISHED:

                case CLOSE_WAIT:

                    OSSemPend(tcb->mutex, 0, &err);

                    nENQUEUE(&tcb->sndq, outBuf);

                    OSSemPost(tcb->mutex);

                    outBuf = NULL;

                    st += segSize;

                    

                    OS_ENTER_CRITICAL();

                    tcb->sndcnt += segSize;

                    OS_EXIT_CRITICAL();

                    

                    tcpOutput(tcb);

                    break;

                case LISTEN:

                case FINWAIT1:

                case FINWAIT2:

                case CLOSING:

                case LAST_ACK:

                case TIME_WAIT:

                case CLOSED:

                    nFreeChain(outBuf);

                    len = 0;

                    if (tcb->closeReason)

                        st = tcb->closeReason;

                    else

                        st = TCPERR_EOF;

                    break;

                }

            }

        }

    }

    

    return st;

}





/*

 * tcpWait - Wait for the connection to be closed.  Normally this will be

 * done after a disconnect before trying to reuse the TCB.  This will fail

 * if the connection is not closing.

 * Returns 0 on success or an error code if the connection is not

 * closing.

 */

int tcpWait(u_int td)

{

    TCPCB *tcb = &tcbs[td];

    int st = 0;

    u_int8 err;



    /* Here we allow the TCB to be on the free list. */

    if (td >= MAXTCP)

        st = TCPERR_PARAM;

        

    else if (tcb->state != CLOSED && tcb->state < FINWAIT1)

        st = TCPERR_CONNECT;

    



/* We don't support blocking when running in a single task! */

#if ONETASK_SUPPORT == 0      

    else while (tcb->state != CLOSED)

        OSSemPend(tcb->connectSem, 0, &err);

#else

  else st = TCPERR_TIMEOUT; 

#endif

    

    return st;

}





/* 

 * Receive an incoming datagram.  This is called from IP with the IP and

 * TCP headers intact at the head of the buffer chain.

 */

void tcpInput(NBuf *inBuf, u_int ipHeadLen)

{

    

    TCPCB *tcb;

    Connection conn;

    u_int tcpHeadLen;           /* Length of TCP header. */

    int segLen;                 /* TCP segment length exclusive of flags. */

    IPHdr *ipHdr;               /* Ptr to IP header in output buffer. */

    TCPHdr *tcpHdr;             /* Ptr to TCP header in output buffer. */

    

    u_int chkSum;

    static chkFail = 0;

    

    if (inBuf == NULL) {

        TCPDEBUG((LOG_ERR, TL_TCP, "tcpInput: Null input dropped"));

        return;

    }



    /*

     * Strip off the IP options.  The TCP checksum includes fields from the

     * IP header but without the options.

     */

    if (ipHeadLen > sizeof(IPHdr)) {

        inBuf = ipOptStrip(inBuf, ipHeadLen);

        ipHeadLen = sizeof(IPHdr);

    }

    

    /*

     * Get IP and TCP header together in first nBuf.

     */

    if (inBuf->len < sizeof(TCPHdr) + sizeof(IPHdr)) {

        if ((inBuf = nPullup(inBuf, sizeof(TCPHdr) + ipHeadLen)) == 0) {

            STATS(tcpStats.runt.val++;)

            TCPDEBUG((LOG_ERR, TL_TCP, "tcpInput: Runt packet dropped"));

#if DEBUG_SUPPORT > 0

            nDumpChain(inBuf);

#endif

            return;

        }

    }

    ipHdr = nBUFTOPTR(inBuf, IPHdr *);

    /*

     * Note: We use ipHeadLen below just in case we kept an option with

     *  the IP header.

     */

    tcpHdr = (TCPHdr *)((char *)ipHdr + ipHeadLen);



    /*

     * Prepare the header for the TCP checksum.  The TCP checksum is

     * computed on a pseudo IP header as well as the TCP header and

     * the data segment.  The pseudo IP header includes the length

     * (not including the length of the IP header), protocol, source

     * address and destination address fields.  We prepare this by

     * clearing the TTL field and loading the length in the IP checksum

     * field.

     */

    ipHdr->ip_ttl = 0;

    ipHdr->ip_sum = htons((unsigned short)(ipHdr->ip_len - sizeof(IPHdr)));

    

    /* Validate the TCP checksum including fields from IP TTL. */

    if ((chkSum = inChkSum(inBuf, (unsigned short)(ipHdr->ip_len - 8), 8)) != 0) {

        /* Checksum failed, ignore segment completely */

        STATS(tcpStats.checksum.val++;)

        TCPDEBUG((LOG_ERR, TL_TCP, "tcpInput: Bad checksum %X", chkSum));

#if DEBUG_SUPPORT > 0

        nDumpChain(inBuf);

#endif

        if (++chkFail > 3) {

            /* Break point. */

            TCPDEBUG((LOG_ERR, TL_TCP, "tcpInput: Serious checksum issue here."));

        }

        nFreeChain(inBuf);

        return;

    }



    /* Convert needed TCP fields to host byte order. */

    if ((tcpHeadLen = tcpHdr->tcpOff * 4) < sizeof(TCPHdr)) {

        /* TCP header is too small */

        STATS(tcpStats.runt.val++;)

        TCPDEBUG((LOG_ERR, TL_TCP, "tcpInput: Bad TCP header len %u", tcpHeadLen));

#if DEBUG_SUPPORT > 0

        nDumpChain(inBuf);

#endif

        nFreeChain(inBuf);

        return;

    }

    NTOHL(tcpHdr->seq);

    NTOHL(tcpHdr->ack);

    NTOHS(tcpHdr->win);

    NTOHS(tcpHdr->urgent);



    segLen = ipHdr->ip_len - sizeof(IPHdr) - tcpHeadLen;



    /* Find the connection if any. */   

    conn.localIPAddr = ipHdr->ip_dst.s_addr;

    conn.localPort = tcpHdr->dstPort;

    conn.remoteIPAddr = ipHdr->ip_src.s_addr;

    conn.remotePort = tcpHdr->srcPort;

    if((tcb = tcbLookup(&conn)) == NULL) {

        TCPCB *ntcb;

        

        if(!(tcpHdr->flags & TH_SYN)) {

            /* No open TCB for this connection so reject */

            tcpReset(inBuf, ipHdr, tcpHdr, (unsigned short)segLen);

            return;

        }

        

        /*

         * Check for a LISTEN on this connection request.

         */

        conn.remoteIPAddr = 0;

        conn.remotePort = 0;

        if((tcb = tcbLookup(&conn)) == NULL) {

            /*

             * Could be a LISTEN with a null local address.

             */

            conn.localIPAddr = 0;

            if((tcb = tcbLookup(&conn)) == NULL) {

                /* No unspecified LISTEN so reject */

                tcpReset(inBuf, ipHdr, tcpHdr, (unsigned short)segLen);

                return;

            }

        }

        /* We've found a server listen socket, so clone the TCB */

        if(tcb->flags & CLONE) {

//            OS_EVENT *connectSem;   /* Semaphore for connections. */
//            OS_EVENT *readSem;      /* Semaphore for read function. */
//            OS_EVENT *writeSem;     /* Semaphore for write function. */
//            OS_EVENT *mutex;        /* Semaphore for mutex. */
            u_long connectSem;   /* Semaphore for connections. */
            u_long readSem;      /* Semaphore for read function. */
            u_long writeSem;     /* Semaphore for write function. */
            u_long mutex;        /* Semaphore for mutex. */

            

            /*

             * If no room in the listen queue, we have to reject the connection. 

             */

            if (tcb->listenQOpen < listenQLen(tcb)) {

                tcpReset(inBuf, ipHdr, tcpHdr, (unsigned short)segLen);

                return;

            }

        

            /* Get a free TCB. */

            OS_ENTER_CRITICAL();

⌨️ 快捷键说明

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