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

📄 tcpsock.c

📁 用于嵌入式系统的TCP/IP协议栈及若干服务
💻 C
📖 第 1 页 / 共 5 页
字号:
				      if it was a blocking socket, the first connect call					  wouldn't return until either the connection was					  established or until it had failed and was back in the					  closed state. */			      err = FNS_EWOULDBLOCK; 			   }			   goto i_out;		} /* switch */	} /* First try (sv_state = CLOSED) */ if ((err = ip_inaddr(to, tolen, (so_addr *)&addr)) != 0) {    debug0(tcp_debug, "in_inaddr returned error\n");    goto i_out; } /* Can't connect TCP to a multicast address -- doesn't make sense */ {  u8  ip[4];  HostToMem32(ip, addr.a_ipa.ip_nethost);  if (is_D_class(ip)) {	  err = FNS_ENETUNREACH;      goto i_out;  } }	  svp->sv_dest = addr.a_ipa; trace1(tcp_tstate, "tcp_connect: connect %s => ", ipa2str((ipa *)&svp->sv_src, (char *)0)); trace1(tcp_tstate, "%s\n", ipa2str((ipa *)&svp->sv_dest, (char *)0)); svp->sv_flags &= ~SV_PASSIVE;   /* active open mode */ sop->so_err = 0; /* Unless this socket is already bound to a local port number, allocate an ephemeral     port automatically */ if (svp->sv_src.ip_port == 0) {     /* start at 1027 */    svp->sv_src.ip_port = htons((u16)(TCP_MIN_FREE + (tcp_port|(sop->so_index<<8))));    tcp_port++;    tcp_port &= 0xFF; } /* if */ INC_MIB_CNTR_TCP_ACTIVE_OPENSi_out: sv_detach(svp, tcp_connect_inner, true); return err;} /* tcp_connect_inner *//*******************************************************************//* Connect - Active open event in a closed state. */export  int tcp_connect (fast so_t *sop, saddr *to, int tolen){ tcpsv_t *svp; int     err; trace0(tcp_trace, "tcp_connect:\n"); /* Do all the guts of the connect processing */ err = tcp_connect_inner(sop, to, tolen, &svp); if (err == 0) {    /* Send the initial SYN for this connection */    set_state("tcp_connect", svp, SYN_SENT);#ifdef TCP_TRANSACTION_TCP    tcp_gsyn(svp, true);#else    tcp_gsyn(svp);#endif    if (can_block(sop->so_flags))        err = tcp_west(svp);/* wait for CLOSED or ESTABLISHED state */    else {        trace3(tcp_trace, "AFTER tcp_gsyn ref_cnt %x, state %x abort %x\n", svp->sv_refcnt, svp->sv_state, svp->sv_abort);        err = FNS_EINPROGRESS;	} } /* if */ return err;} /* tcp_connect *//**********************************************************************//* Functions to "get" tcp option values, invoked from tables          *//**********************************************************************/static int tcp_get_seqno_option(so_t *sop,int optname,char *optval){ u32     ulval; tcpsv_t *svp = sop->so_svp; if (svp == (tcpsv_t *)0) return FNS_ENOTCONN; ulval = MU32(svp->sv_snxt); *(u32 *)optval = ulval; return FNS_ENOERR;} /* tcp_get_seqno_option */static int tcp_get_sndbuf_option(so_t *sop,int optname,char *optval){ tcpsv_t *svp = sop->so_svp; if (svp == (tcpsv_t *)0) return FNS_ENOTCONN; *((int *)optval) = svp->sv_sq_max; return(FNS_ENOERR);} /* tcp_get_sndbuf_option */static int tcp_get_oobinline_option(so_t *sop,int optname,char *optval){ tcpsv_t *svp = sop->so_svp; if (svp == (tcpsv_t *)0) return FNS_ENOTCONN; *((int *)optval) = ( (svp->sv_urg_mode == SV_URGMODE_INLINE) ? 1 : 0); return(FNS_ENOERR);} /* tcp_get_oobinline_option *//*********************************************************************//* TCP get options */export  inttcp_getopt (so_t * sop, int level, int optname, char * optval, int * optlen){    tcpsv_t *svp = sop->so_svp;    if (level == SOL_SOCKET) {       /* process using info in the tcp socket-level option table above */       return(process_get_sockopt(sop,optname,(u8 *) optval,optlen,			                          &(tcp_sol_sockopts[0])));    } /* if */    if (level == IP_IP)        return ip_getopt(sop, optname, optval, optlen);    if (level != IP_TCP)        return FNS_EAFNOSUPPORT;              /* process using info in the tcp-level socket option table above */    return(process_get_sockopt(sop,optname,(u8 *) optval,optlen,			                          &(tcp_sockopts[0])));} /* tcp_getopt *//* glom onto the options now in the socket structure */pflocal void    tcp_glomopt (fast so_t * sop){    fast    tcpsv_t * svp;    svp = sop->so_svp;    if (!svp)        return;    svp->sv_soptions = sop->so_options; /* we now know this */    /* check for a change of delivery policy; take appropriate measures */    if (svp->sv_tos != ipsu.ipsu_tos) {        svp->sv_tos = ipsu.ipsu_tos;    /* got these too */        /* invalidate receive performance optimization */        /* give the send routine a shot at anything delayed */        tcp_sqxmit(svp);    }}/*************************************************************************//* MBM: for t/tcp, introduced the "xmit_now" parameter. It allows        *//* the SYN to be set up (initial sequence number, etc), while deferring  *//* transmission of the SYN until later (e.g., in case some data needs    *//* to be queued to the send buffer to be sent along with the SYN). If    *//* the caller calls with xmit_now false, it is up to the caller to make  *//* sure that tcp_sqxmit gets called later.                               *//* 9.4.6.3.23 Generate syn. [141..3]                                     */                                 /*************************************************************************/#ifndef TCP_TRANSACTION_TCPexport void    tcp_gsyn (tcpsv_t * svp)#elseexport void    tcp_gsyn (tcpsv_t * svp, boolean xmit_now)#endif /* TCP_TRANSACTION_TCP */{#if 0    fast    tcpsv_t * nsvp;#endif    so_t    * sop;    use_critical;    trace0(tcp_trace, "tcp_gsyn\n");    assert(svp->sv_refcnt != 0, "tcp_gsyn: state vector not bound\n");    critical;	/*********************************************************************/	/* MBM -- the following loop removed for Fusion 6.5, because is was  */ 	/* wrong for the following reasons:                                  */	/*      -- Sleeping unconditionaly, regardless of whether or not     */	/*         the socket is set up to be blocking or not                */	/*      -- The sleep could be indefinitely long, because it waits    */	/*         until the connection reaches the CLOSED or TIME_WAIT      */	/*         state, which could be very quickly or could be hours.     */	/*      -- It violates a fundamental principle of TCP, because if    */	/*         it finds a duplicate connection in the TIME_WAIT state,   */	/*         it immediately aborts it (defeating the TIME_WAIT state   */	/*         and all of its purposes). Or, if it had to sleep, kills   */	/*         it as soon as it reaches the TIME_WAIT state.             */#if 0    /* scan the tcp_q for a closed state vector that contains a matching     * source/destination port number, host id.  We can steal the sequence     * number from that guy.     */    for (nsvp = (tcpsv_t *)tcp_q.q_next; nsvp != (tcpsv_t *)&tcp_q;                 nsvp = (tcpsv_t *)nsvp->sv_q.q_next) {        if (svp == nsvp)            continue;        if ((nsvp->sv_flags & SV_SEQNO) == 0)            continue;        if ( (svp->sv_src.ip_port == nsvp->sv_src.ip_port)            && (svp->sv_dest.ip_port == nsvp->sv_dest.ip_port)            && (svp->sv_dest.ip_nethost == nsvp->sv_dest.ip_nethost) ) {            /* wait for the state vector to reach a termination             * state (CLOSED or TIME_WAIT) */            sv_bind(nsvp, tcp_gsyn, true);  /* hold onto it */            while ((nsvp->sv_state != CLOSED) && (nsvp->sv_state < TIME_WAIT)) {                fast    int     err;                if ((err = os_sleep((char *)&nsvp->sv_state)) != 0) {                    tcp_rslf(svp, err);                    sv_detach(nsvp, tcp_gsyn, true);                    normal;                    return;                }            }            stass(svp->sv_sisn, nsvp->sv_snxt);     /* steal the sequence number */            nsvp->sv_flags &= ~SV_SEQNO;    /* don't use these to generate anymore seqno's */            tcp_rslf(nsvp, nsvp->sv_err);   /* shut down the other state cold */            sv_detach(nsvp, tcp_gsyn, true);            goto gsyn;        }    }#endif				 	/* randomize the initial sequence number */    sop = sv_valid_sop(svp, sop);#ifdef CPU_IS_BIG_ENDIAN    svp->sv_sisn.m4[0] = (sop != (so_t *)0) ? (char)(sop->so_index) : (char)rnd;    svp->sv_sisn.m4[3] = (char)rnd;#else       /* little endian */    svp->sv_sisn.m4[3] = (sop != (so_t *)0) ? (u8)(sop->so_index) : (u8)rnd;    svp->sv_sisn.m4[0] = (u8)rnd;#endif    svp->sv_sisn.m4[1] = (char)rnd;    svp->sv_sisn.m4[2] = (char)rnd;#if 0gsyn:#endif	stass(svp->sv_suna, svp->sv_sisn);    stass(svp->sv_spsh, svp->sv_suna);    stass(svp->sv_surg, svp->sv_suna);    M32U(svp->sv_snxt, =, MU32(svp->sv_suna) + 1);    svp->sv_flags |= SV_TSYNFLG|SV_SEQNO;    svp->sv_swnd = 0;    normal;#ifdef TCP_TRANSACTION_TCP    if (xmit_now)#endif /* TCP_TRANSACTION_TCP */       tcp_sqxmit(svp); /* send */} /* tcp_gsyn *//**************************************************************//* Supported TCP ioctls : * *      int     pioctl(fd, SOIOCATMARK, (u32 *), sizeof(u32), 0) *      int     pioctl(fd, SOIOCURG, (u32 *), sizeof(u32), 0) *      int     pioctl(fd, SOIOCNTATTACH, (u32 *), sizeof(u32), 0) * *      SOIOCATM (SIOCATMARK) is supported for 4.2BSD compatibility *              and returns 1, if all urgent data has been read, and *              0 if there still exists urgent data to be read.  Using *              this ioctl requires that the user read byte-by-byte *              calling the ioctl each time to see if the urgent *              condition has passed. *      SOIOCURG is the right way to do the job.  SOIOCURG returns *              the number of bytes that must be read to clear the *              urgent condition.  SOIOCURG still should be checked *              after reading the indicated data, since new urgent *              data could have been received while the data was being *              processed. *      SOIOCNTATTACH connects the given socket to a network terminal. *              A single u32 value is expected, which should contain *              the type of network terminal protocol to be used *              (see <nt.h>). *      All ioctls return -1 if an error occurred, and 0 if the *              call was a success. *//*ARGSUSED; this is called from a table so flag is declared but not used *//* TCP ioctl */export  int     tcp_ioctl (so_t * sop, int cmnd, u32 * addr, int len){    fast    tcpsv_t * svp;    int     err;    u32     u1;    use_critical;    if (len < sizeof(u32))        return FNS_EINVAL;    err = 0;        /* not guilty of anything yet */    critical;    if (((svp = sop->so_svp) == (tcpsv_t *)0) ||  svp->sv_state < ESTAB) {        err = FNS_ENOTCONN; /* must have a connected state vector */        goto nout;    }    switch (cmnd) {      case SOIOCATMARK:       /* Berkeley compatability */        /* True if in urgent state and if the next byte to be read is the one beyond		   the one that arrived as an urgent byte  Stevens chapter 21*/		u1 = 0;  		if (svp->sv_urg_state != SV_URGSTATE_NONE) {	       m32 mark;		   M32M(mark, =, svp->sv_rurg);		   if (svp->sv_urg_mode == SV_URGMODE_INLINE) {		      M32U(mark, -=, 1);		   }		   u1 = MC32M(mark, ==, svp->sv_read);		}        goto poke;      case SOIOCURG:        /* return bytes 'read' past urgent pointer, or 0 if not in         * urgent mode */        u1 = (svp->sv_urg_state != SV_URGSTATE_NONE) ?                       MC32M(svp->sv_rurg, -, svp->sv_read) : (u32)0L;        /* give back the ATMARK boolean value or the urgent byte         * count via 'addr' */poke:   trace1(tcp_turgent, "tcp_ioctl: returning %d\n", (int)u1);        *addr = u1;        break;      case SOIOCNTATTACH:     /* Attach to network terminal */        /* This operation must be done on the host under INP         * implementations */      default:        /* bogus 'cmnd' */        err = FNS_EINVAL;    }nout:   normal;    return err;}/* Passive open event [104] */export  int     tcp_listen (so_t * sop, int backlog){    fast    tcpsv_t * svp;    int     err;    use_critical;    trace0(tcp_trace, "tcp_listen:\n");    trace1(tcp_tstate, "tcp_listen: backlog = %d\n", backlog);    critical;    if ((svp = sop->so_svp) == (tcpsv_t *)0) {        debug0(tcp_debug, "tcp_listen: no state vector\n");        normal;        return FNS_EINVAL;    }    sv_bind(svp, tcp_listen, true);    normal;    err = OK;    if (backlog < 0) {        err = FNS_EINVAL;        goto out;    } else if (backlog == 0) {		/* Stevens says that some TCP implementations treat a zero the same as a one,

⌨️ 快捷键说明

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