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

📄 tcpsock.c

📁 用于嵌入式系统的TCP/IP协议栈及若干服务
💻 C
📖 第 1 页 / 共 5 页
字号:
		   while others don't allow connections. We choose to treat it as a one rather		   than return an error. */		backlog = 1;	}    if (svp->sv_state != CLOSED) {        err = FNS_EISCONN;        goto out;    }    gq_max_set(&sop->so_cq, (int)min(backlog, (int)max_backlog));    q_init((q *)&sop->so_q, F_Q_HEADER); /* accept sockets */    tcp_no_more_data_in(svp);    set_state("tcp_listen", svp, LISTEN);    svp->sv_flags |= SV_PASSIVE;    SET_SOCKET_OPTION_ON(sop,SO_ACCEPTCONN);out:    sv_detach(svp, tcp_listen, true);    return err;} /* tcp_listen *//* Function called by tcp_recv to determine whether a window update should be sent, and   if so, whether it should be delayed or immediate *//* returns one of the following values */#define TCP_SEND_NO_WIND_UPDATE        0#define TCP_SEND_DELAYED_WIND_UPDATE   1#define TCP_SEND_IMMEDIATE_WIND_UPDATE 2static int tcp_decide_window_update(fast so_t * sop, fast tcpsv_t * svp, int length){ u32 rwind, whalf;    /* Acknowledgements under full-speed conditions come out of the     * following logic.  Simply, a delayed window update (acknowledgement)     * was requested when the data was received and placed in the receive     * queue.  If things are operating at high speed though that     * delayed ACK will be superceded by a forced window update     * generated here, thus piggy-backing ACK's with window openings.     * These window updates are offered at half-open conditions, or     * when enough data has been 'recv'ed to constitute two maximum-sized     * segments since the last window update (this is how we implement the	 * "ack every other segment" requirement of RFC 1122). One additional 	 * consideration is, if the window is opening back up from having been 	 * advertised as zero, an updated window is advertised once space is 	 * available in the receive buffer for a single maximum-sized segment.     */    rwind = rwnd(sop);    whalf = (int)(sop->so_rq.gq_max >> 1);    /* if the remote does better with fully-open window ACK's being     * sent immediately (e.g. Nagle send policy), do it now */    if (rwind == sop->so_rq.gq_max  &&  (svp->sv_flags & SV_EMPTYACK)) {        return(TCP_SEND_IMMEDIATE_WIND_UPDATE);    /* if we are rising back from a zero-window advertisement and we have        not yet reached the "silly window" threshold (i.e., we would be 		advertising a very small window), don't send an ack now. But if we        have risen back above the "silly window" threshold, do send one        now */    } else if (svp->sv_flags & SV_RECOVZWIN) {        u32 silly_thresh = ((svp->sv_mssd < whalf) ? svp->sv_mssd : whalf);        return( (rwind < silly_thresh) ? TCP_SEND_NO_WIND_UPDATE : 		                                 TCP_SEND_IMMEDIATE_WIND_UPDATE);    /* if we've read N maximum-sized segements since the last window update	   (N being a generalization of the "ack every second segment" where N	   is a configurable parameter), offer a window update now (this is 	   the "ack every other segment" strategy described by Stevens */    } else if (svp->sv_rcvsncwupd >= (svp->sv_ackEveryN * svp->sv_mssd) ) {        return(TCP_SEND_IMMEDIATE_WIND_UPDATE);    /* if the read just done has caused the amount of available space in the       receive buffer to exceed half of the receive buffer size,        offer a window now */    } else if (whalf >= svp->sv_mssd &&  rwind >= whalf  &&  rwind-length < whalf) {        return(TCP_SEND_IMMEDIATE_WIND_UPDATE);    /* No need to offer an immediate update, one will be sent after a delay period, or,       if additional data is read from the socket prior to that, we'll go thru this       decision process again. */    } else {        return(TCP_SEND_DELAYED_WIND_UPDATE);    }} /* tcp_decide_window_update *//* ULP receive event */export  inttcp_recv (fast so_t * sop, char * buf, int * buf_lenp, int flags){    fast    tcpsv_t * svp = sop->so_svp;    int     err;    auto    int     length;    use_critical;    trace0(tcp_trace, "tcp_recv:\n");    /***********************************************************************/    /* Code to deal with out-of-band reads */    /* Is this an attempt to read "out-of-band" data, i.e., an urgent byte? */    if (flags & MSG_OOB) {        /* Possibly we don't have a state vector -- if thats the case, its           probably because the TCP connection was closed even though the           application is still reading data out of the socket. In that case           we've lost the urgent byte (possibly thats an argument for keeping           it with the socket structure rather than the TCP state vector) */        if (svp == (tcpsv_t *) 0) return(FNS_ENOTCONN);        /* not allowed if the OOBINLINE socket option is in effect */        if (svp->sv_urg_mode != SV_URGMODE_OOB) return(FNS_EINVAL);        /* Well, we are in out-of-band mode -- lets see what state we           are in right now with respect to urgent data */        switch (svp->sv_urg_state) {           case SV_URGSTATE_NONE: /* MSG_OOB not allowed in this state */               return(FNS_EINVAL);           case SV_URGSTATE_NODATA: /* tell user urgent byte not here yet */               return(FNS_EWOULDBLOCK);           case SV_URGSTATE_DATA:   /* return the urgent byte to the user and                                       return to non-urgent state */                so_clr_notify(sop, URGENT_NOTIFY);                svp->sv_urg_state = SV_URGSTATE_NONE;                /* assuming that buf_lenp is at least one, not checking */                *buf = svp->sv_urg_buf;                *buf_lenp = 1;                return(FNS_ENOERR);        } /* switch */    } /* end if out-of-band read */    /***********************************************************************/   err = so_rbcomm(sop, buf, buf_lenp, flags);    /* if 'so_rbcomm' wasn't PEEKing, receive queue     * will be locked upon return; 'gq_out' will unlock it     */    debug2(tcp_debug  &&  err, "tcp_recv: [%d] so_rbcomm returns err = %d\n", sop->so_index, err);    if ((flags & MSG_PEEK)  ||  err) {        goto out;	}    /* If there is urgent data and we are receiving urgent data inline, a read 	   operation must (if it reaches the urgent byte) stop at the byte before	   (Stevens Unix Network Programming page 574) so that the application can	   check atmark. But if they are reading at the mark right now, let them	   read it */	if ( (svp->sv_urg_state == SV_URGSTATE_DATA) && 		(svp->sv_urg_mode == SV_URGMODE_INLINE) ) {        u32 read_seqno = MU32(svp->sv_read);	   u32 urg_off = (M32U(svp->sv_rurg, -, read_seqno) - 1);       if ( (urg_off > 0) && (*buf_lenp > (int) urg_off) ) {		   *buf_lenp = (int)urg_off;	   }	}    length = *buf_lenp;    trace1(tcp_trcv, "tcp_recv: accepted %d. bytes\n", length);    gq_out(&sop->so_rq, length);    /* check it out */    if ( length == 0 )        /* We called gq_out to unlock the receive queue, so now         * we can return. */        goto out;    /* The connection and the state vector could be long gone even though     * we are still reading data out of the socket, so we don't assume     * here that there has to still be a state vector. */    if ( svp == (tcpsv_t *)0 )        goto out;    critical;    sv_bind(svp, tcp_recv, true);    /* keeping track of how many bytes read from socket since last time we       sent an ACK */    svp->sv_rcvsncwupd += length;    /* Determine whether or not we need to send a window update now, later, or 	   not at all, and do it. */    switch (tcp_decide_window_update(sop,svp,length)) {        case TCP_SEND_NO_WIND_UPDATE:        break;        case TCP_SEND_DELAYED_WIND_UPDATE:   tcp_schedule_delayed_ack(svp,0); break;        case TCP_SEND_IMMEDIATE_WIND_UPDATE: tcp_sndack((m *) 0, svp); break;    }    /* If we are in an urgent state (inline) and with this read we are reading       past the the urgent data, clear the urgent state */    M32U(svp->sv_read, +=, length);   if ( (svp->sv_urg_mode == SV_URGMODE_INLINE)   &&         (svp->sv_urg_state != SV_URGSTATE_NONE)  &&           MC32M(svp->sv_read, >=, svp->sv_rurg)) {        /* Read past urgent pointer in URGENT mode */        so_clr_notify(sop, URGENT_NOTIFY);        svp->sv_urg_state = SV_URGSTATE_NONE;    /* Clear the URGENT condition */#if 0        os_printf("\ntcp_recv: reading past urgent data, clearing urgent state \n");#endif    }#ifdef  MSD_DEBUG   {   extern boolean msd_debug;   if (msd_debug  &&  length)     os_printf("tcp_recv: length ==%d RFIN==%c rqcnt==%d\n", length,                                      (svp->sv_flags & SV_RFINFLG)?'y':'n',sop->so_rq.gq_cnt);   }#endif    /* The application needs to be told when FIN arrives and     * no data is waiting to be read.     */    if ((svp->sv_flags & SV_RFINFLG) && sop->so_rq.gq_cnt == 0 && length)    {        normal;        /* FIN seen and is now next to be read. */        so_notify(sop, RSHUTDOWN_NOTIFY);    } else        normal;    sv_detach(svp, tcp_recv, true);out:    return err;}/* reject a connection request */export  int     tcp_reject (fast so_t * sop, boolean can_wait){    fast so_t * nsop;    use_critical;    critical;    if ( (nsop = get_accept_sop(sop)) == (so_t *)0 )    {        normal;        return FNS_EINVAL;    }    q_out(&nsop->so_q);    nsop->so_flags &= ~F_SO_TEMP; /* don't let tcp_rslf() close the socket*/    tcp_cabort(nsop);    so_smoke(nsop);    so_ditchsop(nsop);    if (q_empty(&sop->so_q))        so_clr_notify(sop, READ_NOTIFY|ACCEPT_NOTIFY);  /* no more connection requests */    normal;    return 0;} /* tcp_reject *//*********************************************************************************//* ULP transmit event */export  int tcp_send (so_t *sop, char *buf, int *buf_lenp, int flags){    fast    tcpsv_t *svp;    auto    int     err;    use_critical;    trace0(tcp_trace, "tcp_send:\n");    critical;    if ((svp = sop->so_svp) == (tcpsv_t *)0) {        debug0(tcp_debug, "tcp_send: no state vector\n");        normal;        return FNS_ENOTCONN;    }    sv_bind(svp, tcp_send, true);    normal;    trace1(tcp_tsend, "tcp_send: state = %s\n", tcp_st(svp->sv_state));    switch (svp->sv_state) {      case CLOSED:#ifdef TCP_TRANSACTION_TCP		  if (svp->sv_t_tcp_flags & SV_TRANSACTION) {		      err = tcp_do_implied_connect(sop,svp,buf,buf_lenp,flags);			  goto out;		  }#endif /* TCP_TRANSACTION_TCP */          err = FNS_ENOTCONN;          goto out;      case ESTAB:      case SYN_RECVD:      case SYN_SENT:      case CLOSE_WAIT:		  break;      default:                /* no sends allowed otherwise */        debug1(tcp_debug, "tcp_send: incorrect state: %d\n", svp->sv_state);        err = svp->sv_err ? svp->sv_err : FNS_ENOTCONN;        goto out;    }    err = 0;    /* put data on send queue and send it.  New version of so_sbcomm now       takes care of calling tcp_sqxmit() so no need to do it here.    */    so_sbcomm(sop, buf, buf_lenp, flags, (int *)&err);out:#ifdef TCP_TRANSACTION_TCP    /* If we avoided sending a FIN before due to having reverted to       non-transaction mode (in sob.c), do it now */    if ( (err == FNS_ENOERR) || (err == FNS_EINPROGRESS) ) {       if ( (!svp->sv_t_tcp_flags & SV_TRANSACTION) && (flags & MSG_EOF) ) { 	       tcp_sfin(svp, false); 	   } 	}#endif /* TCP_TRANSACTION_TCP */    sv_detach(svp, tcp_send, true);   return err;} /* tcp_send *//*************************************************************************************//* Processing for the SOL_SOCKET OOBINLINE option */static int tcp_setopt_oobinline (fast so_t *sop, int optname, char *optval){ tcpsv_t *svp; svp = sop->so_svp; if (!svp) return(FNS_ENOERR); /* maybe we should return an error here? */                           /* But tcp_glomopt below doesn't even return an                              error if it can't transltate the sop into                              a svp, so if I want to worry about it here I                              should worry about it there too */ svp->sv_urg_mode = ( ((*((int *)optval)) != 0) ? SV_URGMODE_INLINE : SV_URGMODE_OOB ); return(FNS_ENOERR);} /* tcp_setopt_oobinline *//*************************************************************************************//* Processing for the SOL_SOCKET SNDBUF option */static int tcp_setopt_sndbuf (fast so_t *sop, int optname, char *optval){ tcpsv_t *svp; int sbs = *((int *)optval); svp = sop->so_svp; if (!svp) return(FNS_ENOTCONN); #ifndef TCP_WND_SCALE /* If window scaling is compile-time disabled, then don't allow values above    65535 (max rcv window size we can receive) */ if (sbs > TCP_MAX_WINDOW_FIELD_VALUE) return(FNS_EINVAL);#endif /* Store the new maximum senbuf value in TCP's control block */ svp->sv_sq_max = sbs; /* Don't store it in the send queue control block right now if to do so    would interfere with protocol operations, i.e. recovery from a source    quench where we have lowered the receive queue size and are gradually    adjusting it back upward to its max. */ if ( (svp->sv_sqcntdwn != 0) && (svp->sv_sq_max >= sop->so_sq.gq_max) )    return (FNS_ENOERR); /* Either we are not in source quench recovery mode, or the specified new max    is less than the current value of the receive queue, in which case we should    abort the recovery operation anyway and make the new queue size operative */ svp->sv_sqcntdwn = 0; gq_max_set(&sop->so_sq, svp->sv_sq_max); return(FNS_ENOERR);} /* tcp_setopt_sndbuf *//*************************************************************************************//* Processing for the SOL_SOCKET RCV option */static int tcp_setopt_rcvbuf (fast so_t *sop, int optname, char *optval){ tcpsv_t *svp; int rbs = *((int *)optval); svp = sop->so_svp; if (!svp) return(FNS_ENOTCONN);  /* Reject values above the maximum allowed. */

⌨️ 快捷键说明

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