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

📄 nettcp.c

📁 uC/IP Release Notes These release notes for uC/IP are divided into the following sections
💻 C
📖 第 1 页 / 共 5 页
字号:
        /* Wait for connection or failure. */
        while(tcb->state != ESTABLISHED && !st) {
            if (tcb->state == CLOSED) {
                /* 
                 * Post the connect semaphore in case another task was also
                 * waiting on it.  Unlikely for connect but a single extra
                 * post costs little and improves robustness.
                 */
                OSSemPost(tcb->connectSem);
                if (tcb->closeReason)
                    st = tcb->closeReason;
                else
                    st = TCPERR_EOF;
            } else if (!timeout || (dTime = diffJTime(abortTime)) > 0) {
                OSSemPend(tcb->connectSem, (UINT)dTime, &err);
            } else {                    /* Abort on timeout. */
                closeSelf(tcb, TCPERR_TIMEOUT);
                tcbUnlink(tcb);
            }
        }
#endif

    }
            
    TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpConnect[%d]: %s", 
                (int)(tcb - &tcbs[0]), tcbStates[tcb->state]));
    
    return st;
}

/*
 * tcpDisconnect - Tell the peer that we will not be sending any more data
 * (i.e. perform a half close on a connection).  tcpRead() will then
 * wait until the connection closes.
 * Return 0 when the peer acknowledges our message or an error code on
 * failure.
 */
int tcpDisconnect(u_int td)
{
    int st = 0;
    TCPCB *tcb = &tcbs[td];
    
    TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpDisconnect[%d]: state %s", 
                (int)(tcb - &tcbs[0]), tcbStates[tcb->state]));
                    
    if (td >= MAXTCP || tcb->prev == tcb)
        st = TCPERR_PARAM;
        
    else {
        switch(tcb->state){
        case LISTEN:
        case SYN_SENT:
            /*
             * We haven't established a connection yet so we can just
             * close this.
             */
            closeSelf(tcb, 0);
            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;
    UBYTE 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;
#endif
    long dTime = timeout;
    u_int i;
    UBYTE 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;
            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 0
            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)

⌨️ 快捷键说明

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