📄 tcpsock.c
字号:
/** Copyright (c) 1998-2001 by NETsilicon Inc.** This software is copyrighted by and is the sole property of* NETsilicon. All rights, title, ownership, or other interests* in the software remain the property of NETsilicon. This* software may only be used in accordance with the corresponding* license agreement. Any unauthorized use, duplication, transmission,* distribution, or disclosure of this software is expressly forbidden.** This Copyright notice may not be removed or modified without prior* written consent of NETsilicon.** NETsilicon, reserves the right to modify this software* without notice.** NETsilicon* 411 Waverley Oaks Road USA 781.647.1234* Suite 227 http://www.netsilicon.com* Waltham, MA 02452 AmericaSales@netsilicon.com*************************************************************************** $Name: Fusion 6.52 $* $Date: 2002/04/10 15:57:21 $* $Source: M:/psisrc/stack/tcp/rcs/tcpsock.c $* $Revision: 1.59 $*************************************************************************** - Revision Log - ** Who When Why** FND 01/05/01 Rename t_start/t_delete to fns_t_start/fns_t_delete* to fix conflict with pSOS.** FND 01/05/02 Change variable 'oval' in tcp_setopt_ackdly to i32* because comparisons are made against negative values.**************************************************************************** File Description: TCP - Transmission Control Protocol* This file contains routines related to the ULP/TCP interface**************************************************************************/#include "std.h"#include "flags.h"#include "ip.h"#include "m.h"#include "netioc.h"#include "pr.h"#include "q.h"#include "select.h" /* so_notify(), so_clr_notify() */#include "so.h"#include "timer.h"#include "fnsproto.h"#include "in.h"#include "tcp.h"#include "fnsmib.h"#include "nerrno.h"#include "debug.h"#include "fns_heap.h"#define t_start fns_t_start#define t_delete fns_t_deletepflocal so_t * get_accept_sop(so_t * sop);pflocal void tcp_glomopt(so_t * sop);#ifndef TCP_TRANSACTION_TCPpflocal void tcp_sfin(tcpsv_t * svp);#elseexport void tcp_sfin(tcpsv_t * svp, boolean xmit_now);#endif /* TCP_TRANSACTION_TCP */import int tcp_port;import pr_t * tcp_prp;import q tcp_q;import tcb * tcp_quiet;import u32 max_backlog, tcp_sq_max, tcp_rq_max;#ifdef DEBUGimport boolean tcp_debug;#endif#ifdef TRACEimport boolean tcp_taccept, tcp_tbind, tcp_tclose, tcp_tlinger;import boolean tcp_trace, tcp_trcv, tcp_tstate, tcp_tsend, tcp_tsfin;import boolean tcp_tud, tcp_turgent;#endifimport int tcp_seed;#ifdef MSD_DEBUGimport boolean msd_debug;#endif#define rnd (tcp_seed = ((tcp_seed >> 1) + (int)t_time + 13) * 317, tcp_seed & 0xFF)/******************************************************************************//* Table for storing information about the TCP-level socket options we *//* support. Enables the software to be table-driven rather than case statement*//* for each option *//******************************************************************************/static int tcp_get_seqno_option(so_t *sop,int optname,char *optval);static int tcp_get_sndbuf_option(so_t *sop,int optname,char *optval);static int tcp_get_oobinline_option(so_t *sop,int optname,char *optval);static int tcp_setopt_sndbuf(so_t *sop,int optname,char *optval);static int tcp_setopt_oobinline(so_t *sop,int optname,char *optval);static int tcp_setopt_rcvbuf(so_t *sop,int optname,char *optval);static int tcp_getopt_int(so_t *sop,int optname,char *optval);static int tcp_setopt_retr(so_t *sop,int optname,char *optval);static int tcp_setopt_bitflag2(so_t *sop,int optname,char *optval);static int tcp_getopt_bitflag2(so_t *sop,int optname,char *optval);static int tcp_get_maxseg_option(so_t *sop,int optname,char *optval);static int tcp_set_maxseg_option(so_t *sop,int optname,char *optval);static int tcp_set_rcvmss_option(so_t *sop,int optname,char *optval);static int tcp_setopt_ackdly(so_t *sop,int optname,char *optval);#ifdef TCP_TRANSACTION_TCPstatic int tcp_setopt_trans(so_t *sop,int optname,char *optval);#endif /* TCP_TRANSACTION_TCP */static sockopt_entry_ tcp_sockopts[] = { {TCP_O_SEQNO, sizeof(u32), tcp_get_seqno_option, 0 }, {TCP_MAXSEG, sizeof(int), tcp_get_maxseg_option, tcp_set_maxseg_option }, {TCP_USE_PEER_MSS_OPTION, sizeof(int), 0, tcp_setopt_bitflag2 }, {TCP_SET_RCV_MSS, sizeof(int), 0, tcp_set_rcvmss_option },#ifdef TCP_WND_SCALE {TCP_WINDOW_SCALE, sizeof(int), tcp_getopt_bitflag2,tcp_setopt_bitflag2 },#endif /* TCP_WND_SCALE */#ifdef TCP_RTTM {TCP_RTT_ALGORITHM, sizeof(int), tcp_getopt_bitflag2,tcp_setopt_bitflag2 },#endif /* TCP_RTTM */#ifdef TCP_TIMESTAMPS {TCP_PROVIDE_TIMESTAMPS, sizeof(int), tcp_getopt_bitflag2,tcp_setopt_bitflag2},#endif /* TCP_TIMESTAMPS */#ifdef TCP_PAWS {TCP_ENABLE_PAWS, sizeof(int), tcp_getopt_bitflag2,tcp_setopt_bitflag2},#endif /* TCP_PAWS */ {TCP_REX_MAX, sizeof(int), tcp_getopt_int, tcp_setopt_retr}, {TCP_REX_MIN, sizeof(int), tcp_getopt_int, tcp_setopt_retr}, {TCP_REX_INIT, sizeof(int), tcp_getopt_int, tcp_setopt_retr}, {TCP_ACKDELAYTIME, sizeof(int), tcp_getopt_int, tcp_setopt_ackdly}, {TCP_ACKNSEG, sizeof(int), tcp_getopt_int, tcp_setopt_ackdly},#ifdef TCP_SELACK_ENHANCEMENTS {TCP_PERMIT_SACKS, sizeof(int), tcp_getopt_bitflag2,tcp_setopt_bitflag2}, {TCP_SEND_SACKS, sizeof(int), tcp_getopt_bitflag2,tcp_setopt_bitflag2},#endif /* TCP_SELACK_ENHANCEMENTS */#ifdef TCP_SS_CA_FRETR_FREC {TCP_FAST_RETR_RECOV, sizeof(int), tcp_getopt_bitflag2, tcp_setopt_bitflag2}, {TCP_SLOW_START_CA, sizeof(int), tcp_getopt_bitflag2, tcp_setopt_bitflag2},#endif /* TCP_SS_CA_FRETR_FREC */ {TCP_NODELAY, sizeof(int), tcp_getopt_bitflag2, tcp_setopt_bitflag2},#ifdef TCP_TRANSACTION_TCP {TCP_ENABLE_TRANSACTION_TCP, sizeof(int), 0, tcp_setopt_trans},#endif /* TCP_TRANSACTION_TCP */ {0,-1, 0, 0} /* sentinel entry, marks end of table */};static sockopt_entry_ tcp_sol_sockopts[] = {#ifndef SOCKET_USE_OLD_SOCKOPT_FUNCTIONS {SO_SNDBUF, sizeof(int), tcp_get_sndbuf_option, tcp_setopt_sndbuf }, {SO_OOBINLINE, sizeof(int), tcp_get_oobinline_option, tcp_setopt_oobinline }, {SO_RCVBUF, sizeof(int), 0, tcp_setopt_rcvbuf},#endif {0,-1, 0, 0} /* sentinel entry, marks end of table */}; /*******************************************************************//* Hang on an insert into the listener's connection queue by 'tcp_passive'. * Make up a clone of the listener's socket. The clone will retain the same * local host port number, a requirement of the TCP way of doing things. */export int tcp_accept (so_t * sop, int * nfdp, int flags, saddr * addrname, int * addrlenp){ fast tcpsv_t * svp; fast so_t * nsop; int err; struct in_sockaddr *inaddr = (struct in_sockaddr *)addrname; use_critical; /* A lot of this is common code with other protocol families and * should be moved into 'so_accept'. */ trace0(tcp_trace, "tcp_accept:\n");/* Let the user know that caccept is not supported anymore */ if (flags & MSG_PEEK) { return FNS_EOPNOTSUPP; /* caccept not supported anymore */ } /* Validate params */ if( addrlenp ) { if( *addrlenp < sizeof(struct sockaddr_in)) { return FNS_EFAULT; } } if( !addrname ) { /* We want a NULL length too then? */ if( addrlenp ) { return FNS_EFAULT; } } err = 0; critical; if ((svp = sop->so_svp) == (tcpsv_t *)0) { /* no state vector (CLOSED) */ debug0(tcp_debug, "tcp_accept: no listen state vector\n"); normal; return FNS_ENOTCONN; } if( svp->sv_state != LISTEN ) { normal; return FNS_EINVAL; }/* We need to stay critical here UNTIL we do not touch nsop. So that nsop * does not disappear from under us (in tcp_rslf) */ nsop = (so_t *)0; trace1(tcp_taccept, "tcp_accept listen socket %d\n", sop->so_index); while ( (nsop = get_accept_sop(sop)) == (so_t *)0 ) { if (can_block(flags)) { os_sleep((char *)sop); /* Check whether user closed the listening socket */ svp = sop->so_svp; if ( !svp || svp->sv_state != LISTEN ) { err = sop->so_err; if (err == 0) err = FNS_ECONNABORTED; normal; return err; } } else { normal; return FNS_EWOULDBLOCK; } } trace1(tcp_taccept, "tcp_accept accept socket %d\n", nsop->so_index); *nfdp = nsop->so_index; if ((svp = nsop->so_svp) == (tcpsv_t *)0) { /* no state vector (CLOSED) */ debug0(tcp_debug, "tcp_accept: no accept state vector\n"); /* socket freed in tcp_rsfl */ normal; return FNS_ENOTCONN; } sv_bind(svp, tcp_accept, true); /* copy peer's address */ /* sv_dest set in tcp_rsyn (after we have received the first SYN) */ if (addrname != (saddr *)0 && addrlenp != (int *)0) { /* Make sure they passed us a sockaddr_in */ if( *addrlenp < sizeof(struct in_sockaddr) ) { debug0(tcp_debug, "tcp_accept: incorrect size of saddr structure\n"); *addrlenp = 0; /* Let them know we didn't fill it in */ }else { *addrlenp = sizeof(struct in_sockaddr); inaddr->sin_addr.s_addr = svp->sv_dest.ip_nethost; inaddr->sin_family = AF_INET; inaddr->sin_port = svp->sv_dest.ip_port; } } err = 0; q_out(&nsop->so_q); /* user is now responsible for closing the socket */ nsop->so_flags &= ~F_SO_TEMP; if (q_empty(&sop->so_q)) so_clr_notify(sop, READ_NOTIFY|ACCEPT_NOTIFY); /* no more connection requests */ normal; sv_detach(svp, tcp_accept, true); /* detach the state vector */ return err;} /* tcp_accept *//*******************************************************************/export int tcpattach (so_t * sop){ fast tcpsv_t * svp; auto int err; use_critical; trace0(tcp_trace, "tcpattach:\n"); critical; assert(sop->so_svp == (tcpsv_t *)0, "tcpattach: sv already bound\n"); normal; /* Allocate a zeroed state-vector */ if ((svp = (tcpsv_t *)h_calloc((i32)(sizeof(tcpsv_t)), (int *)&err, (boolean)can_block(sop->so_flags))) == (tcpsv_t *)0) return err; /* Allocate timers for the state vector */ critical; /* bind svp <==> tcb */ if ((svp->sv_acktcb = t_new((tcb *)0, tcp_acktimer, svp, (u32)0L, (u16)(give_bs(sop->so_flags)|F_T_STOPPED))) == (tcb *)0) {abort:; if (svp->sv_acktcb) t_delete(svp->sv_acktcb); if (svp->sv_rextcb) t_delete(svp->sv_rextcb); normal; h_free((i32 *)svp); return FNS_EWOULDBLOCK; /* can't block and can't allocate tcb */ } if ((svp->sv_rextcb = t_new((tcb *)0, tcp_rextimer, svp, (u32)0L, (u16)(give_bs(sop->so_flags)|F_T_STOPPED))) == (tcb *)0) goto abort; if ((svp->sv_perftcb = t_new((tcb *)0, tcp_perftimer, svp, (u32)0L, (u16)(give_bs(sop->so_flags)|F_T_STOPPED))) == (tcb *)0) goto abort; /* Bind the state vector and timers together */ sv_bind(svp, svp->sv_acktcb, false); sv_bind(svp, svp->sv_rextcb, false); sv_bind(svp, svp->sv_perftcb, false); normal; q_init(&svp->sv_q, 0); sv_bind(svp, tcpattach, true); sv_so_bind(svp, sop); /* Bind the socket and state vector together */ q_init(&sop->so_rq.gq_q, F_Q_HEADER|F_Q_BYTE_QUEUE); q_init(&sop->so_sq.gq_q, F_Q_HEADER|F_Q_BYTE_QUEUE); sop->so_err = 0; /* note: don't offer an initial receive window UNTIL we know what * the MSS will become */ svp->sv_sq_max = tcp_sq_max; /* default value until/unless over-ridden by the SO_SNDBUF option */ svp->sv_rq_max = tcp_rq_max; /* default value until/unless over-ridden by the SO_RCVBUF option */ ip_at_comm(sop, svp->sv_sq_max, (u32)0L); svp->sv_num_mss_sized_msgs = 0; svp->sv_num_ack_sized_msgs = 0;#ifdef IP_RFC_1191 svp->sv_peer_mss = 0;#endif /* IP_RFC_1191 *//* for backward compatibility with pre-Fusion 5.5 */#ifdef TCP_URGENT_DATA_INBAND_DEFAULT svp->sv_urg_mode = SV_URGMODE_INLINE;#else svp->sv_urg_mode = SV_URGMODE_OOB;#endif#ifdef TCP_WND_SCALE svp->sv_flags2 |= SV_WSCALE_PERMITTED; /* by default we try to negotiate window scaling */ svp->sv_flags2 &= ~SV_WSCALE_ENABLED; /* Assume its not negotiated until proven otherwise */ svp->sv_rwndscale = svp->sv_swndscale = 0;#endif svp->sv_rcv_mss = 0;#ifdef TCP_RTTM svp->sv_flags2 &= ~SV_RTTM_RFC_1323; /* Assume using standard RTTM until/unless socket option says otherwise */#endif /* retransmission timer value limits unless overridden by socket option */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -