📄 tcpsock.c
字号:
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 + -