📄 tcp.c
字号:
/*tcp.cCopyright 1995 Philip Homburg*/#include "inet.h"#include "buf.h"#include "clock.h"#include "event.h"#include "type.h"#include "io.h"#include "ip.h"#include "sr.h"#include "assert.h"#include "rand256.h"#include "tcp.h"#include "tcp_int.h"THIS_FILE#define NOT_IMPLEMENTED 0PUBLIC tcp_port_t *tcp_port_table;PUBLIC tcp_fd_t tcp_fd_table[TCP_FD_NR];PUBLIC tcp_conn_t tcp_conn_table[TCP_CONN_NR];PUBLIC sr_cancel_t tcp_cancel_f;FORWARD void tcp_main ARGS(( tcp_port_t *port ));FORWARD int tcp_select ARGS(( int fd, unsigned operations ));FORWARD acc_t *tcp_get_data ARGS(( int fd, size_t offset, size_t count, int for_ioctl ));FORWARD int tcp_put_data ARGS(( int fd, size_t offset, acc_t *data, int for_ioctl ));FORWARD void tcp_put_pkt ARGS(( int fd, acc_t *data, size_t datalen ));FORWARD void read_ip_packets ARGS(( tcp_port_t *port ));FORWARD int tcp_setconf ARGS(( tcp_fd_t *tcp_fd ));FORWARD int tcp_setopt ARGS(( tcp_fd_t *tcp_fd ));FORWARD int tcp_connect ARGS(( tcp_fd_t *tcp_fd ));FORWARD int tcp_listen ARGS(( tcp_fd_t *tcp_fd, int do_listenq ));FORWARD int tcp_acceptto ARGS(( tcp_fd_t *tcp_fd ));FORWARD tcpport_t find_unused_port ARGS(( int fd ));FORWARD int is_unused_port ARGS(( Tcpport_t port ));FORWARD int reply_thr_put ARGS(( tcp_fd_t *tcp_fd, int reply, int for_ioctl ));FORWARD void reply_thr_get ARGS(( tcp_fd_t *tcp_fd, int reply, int for_ioctl ));FORWARD tcp_conn_t *find_conn_entry ARGS(( Tcpport_t locport, ipaddr_t locaddr, Tcpport_t remport, ipaddr_t readaddr ));FORWARD tcp_conn_t *find_empty_conn ARGS(( void ));FORWARD tcp_conn_t *find_best_conn ARGS(( ip_hdr_t *ip_hdr, tcp_hdr_t *tcp_hdr ));FORWARD tcp_conn_t *new_conn_for_queue ARGS(( tcp_fd_t *tcp_fd ));FORWARD int maybe_listen ARGS(( ipaddr_t locaddr, Tcpport_t locport, ipaddr_t remaddr, Tcpport_t remport ));FORWARD int tcp_su4connect ARGS(( tcp_fd_t *tcp_fd ));FORWARD void tcp_buffree ARGS(( int priority ));#ifdef BUF_CONSISTENCY_CHECKFORWARD void tcp_bufcheck ARGS(( void ));#endifFORWARD void tcp_setup_conn ARGS(( tcp_port_t *tcp_port, tcp_conn_t *tcp_conn ));FORWARD u32_t tcp_rand32 ARGS(( void ));PUBLIC void tcp_prep(){ tcp_port_table= alloc(tcp_conf_nr * sizeof(tcp_port_table[0]));}PUBLIC void tcp_init(){ int i, j, k, ifno; tcp_fd_t *tcp_fd; tcp_port_t *tcp_port; tcp_conn_t *tcp_conn; assert (BUF_S >= sizeof(struct nwio_ipopt)); assert (BUF_S >= sizeof(struct nwio_ipconf)); assert (BUF_S >= sizeof(struct nwio_tcpconf)); assert (BUF_S >= IP_MAX_HDR_SIZE + TCP_MAX_HDR_SIZE); for (i=0, tcp_fd= tcp_fd_table; i<TCP_FD_NR; i++, tcp_fd++) { tcp_fd->tf_flags= TFF_EMPTY; } for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++, tcp_fd++) { tcp_conn->tc_flags= TCF_EMPTY; tcp_conn->tc_busy= 0; }#ifndef BUF_CONSISTENCY_CHECK bf_logon(tcp_buffree);#else bf_logon(tcp_buffree, tcp_bufcheck);#endif for (i=0, tcp_port= tcp_port_table; i<tcp_conf_nr; i++, tcp_port++) { tcp_port->tp_ipdev= tcp_conf[i].tc_port; tcp_port->tp_flags= TPF_EMPTY; tcp_port->tp_state= TPS_EMPTY; tcp_port->tp_snd_head= NULL; tcp_port->tp_snd_tail= NULL; ev_init(&tcp_port->tp_snd_event); for (j= 0; j<TCP_CONN_HASH_NR; j++) { for (k= 0; k<4; k++) { tcp_port->tp_conn_hash[j][k]= &tcp_conn_table[0]; } } ifno= ip_conf[tcp_port->tp_ipdev].ic_ifno; sr_add_minor(if2minor(ifno, TCP_DEV_OFF), i, tcp_open, tcp_close, tcp_read, tcp_write, tcp_ioctl, tcp_cancel, tcp_select); tcp_main(tcp_port); } tcp_cancel_f= tcp_cancel;}PRIVATE void tcp_main(tcp_port)tcp_port_t *tcp_port;{ int result, i; tcp_conn_t *tcp_conn; tcp_fd_t *tcp_fd; switch (tcp_port->tp_state) { case TPS_EMPTY: tcp_port->tp_state= TPS_SETPROTO; tcp_port->tp_ipfd= ip_open(tcp_port->tp_ipdev, tcp_port->tp_ipdev, tcp_get_data, tcp_put_data, tcp_put_pkt, 0 /* no select_res */); if (tcp_port->tp_ipfd < 0) { tcp_port->tp_state= TPS_ERROR; DBLOCK(1, printf("%s, %d: unable to open ip port\n", __FILE__, __LINE__)); return; } result= ip_ioctl(tcp_port->tp_ipfd, NWIOSIPOPT); if (result == NW_SUSPEND) tcp_port->tp_flags |= TPF_SUSPEND; if (result < 0) { return; } if (tcp_port->tp_state != TPS_GETCONF) return; /* drops through */ case TPS_GETCONF: tcp_port->tp_flags &= ~TPF_SUSPEND; result= ip_ioctl(tcp_port->tp_ipfd, NWIOGIPCONF); if (result == NW_SUSPEND) tcp_port->tp_flags |= TPF_SUSPEND; if (result < 0) { return; } if (tcp_port->tp_state != TPS_MAIN) return; /* drops through */ case TPS_MAIN: tcp_port->tp_flags &= ~TPF_SUSPEND; tcp_port->tp_pack= 0; tcp_conn= &tcp_conn_table[tcp_port->tp_ipdev]; tcp_conn->tc_flags= TCF_INUSE; assert(!tcp_conn->tc_busy); tcp_conn->tc_locport= 0; tcp_conn->tc_locaddr= tcp_port->tp_ipaddr; tcp_conn->tc_remport= 0; tcp_conn->tc_remaddr= 0; tcp_conn->tc_state= TCS_CLOSED; tcp_conn->tc_fd= 0; tcp_conn->tc_connInprogress= 0; tcp_conn->tc_orglisten= FALSE; tcp_conn->tc_senddis= 0; tcp_conn->tc_ISS= 0; tcp_conn->tc_SND_UNA= tcp_conn->tc_ISS; tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS; tcp_conn->tc_SND_NXT= tcp_conn->tc_ISS; tcp_conn->tc_SND_UP= tcp_conn->tc_ISS; tcp_conn->tc_IRS= 0; tcp_conn->tc_RCV_LO= tcp_conn->tc_IRS; tcp_conn->tc_RCV_NXT= tcp_conn->tc_IRS; tcp_conn->tc_RCV_HI= tcp_conn->tc_IRS; tcp_conn->tc_RCV_UP= tcp_conn->tc_IRS; tcp_conn->tc_port= tcp_port; tcp_conn->tc_rcvd_data= NULL; tcp_conn->tc_adv_data= NULL; tcp_conn->tc_send_data= 0; tcp_conn->tc_remipopt= NULL; tcp_conn->tc_tcpopt= NULL; tcp_conn->tc_frag2send= 0; tcp_conn->tc_tos= TCP_DEF_TOS; tcp_conn->tc_ttl= IP_MAX_TTL; tcp_conn->tc_rcv_wnd= TCP_MAX_RCV_WND_SIZE; tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD; tcp_conn->tc_stt= 0; tcp_conn->tc_0wnd_to= 0; tcp_conn->tc_artt= TCP_DEF_RTT*TCP_RTT_SCALE; tcp_conn->tc_drtt= 0; tcp_conn->tc_rtt= TCP_DEF_RTT; tcp_conn->tc_max_mtu= tcp_port->tp_mtu; tcp_conn->tc_mtu= tcp_conn->tc_max_mtu; tcp_conn->tc_mtutim= 0; tcp_conn->tc_error= NW_OK; tcp_conn->tc_snd_wnd= TCP_MAX_SND_WND_SIZE; tcp_conn->tc_snd_cinc= (long)TCP_DEF_MSS*TCP_DEF_MSS/TCP_MAX_SND_WND_SIZE+1; tcp_conn->tc_rt_time= 0; tcp_conn->tc_rt_seq= 0; tcp_conn->tc_rt_threshold= tcp_conn->tc_ISS; for (i=0, tcp_fd= tcp_fd_table; i<TCP_FD_NR; i++, tcp_fd++) { if (!(tcp_fd->tf_flags & TFF_INUSE)) continue; if (tcp_fd->tf_port != tcp_port) continue; if (tcp_fd->tf_flags & TFF_IOC_INIT_SP) { tcp_fd->tf_flags &= ~TFF_IOC_INIT_SP; tcp_ioctl(i, tcp_fd->tf_ioreq); } } read_ip_packets(tcp_port); return; default: ip_panic(( "unknown state" )); break; }}PRIVATE int tcp_select(fd, operations)int fd;unsigned operations;{ int i; unsigned resops; tcp_fd_t *tcp_fd; tcp_conn_t *tcp_conn; tcp_fd= &tcp_fd_table[fd]; assert (tcp_fd->tf_flags & TFF_INUSE); resops= 0; if (tcp_fd->tf_flags & TFF_LISTENQ) { /* Special case for LISTENQ */ if (operations & SR_SELECT_READ) { for (i= 0; i<TFL_LISTEN_MAX; i++) { if (tcp_fd->tf_listenq[i] == NULL) continue; if (tcp_fd->tf_listenq[i]->tc_connInprogress == 0) { break; } } if (i >= TFL_LISTEN_MAX) tcp_fd->tf_flags |= TFF_SEL_READ; else resops |= SR_SELECT_READ; } if (operations & SR_SELECT_WRITE) return ENOTCONN; /* Is this right? */ return resops; } if (tcp_fd->tf_flags & TFF_CONNECTING) { /* Special case for CONNECTING */ if (operations & SR_SELECT_WRITE) tcp_fd->tf_flags |= TFF_SEL_WRITE; return 0; } if (operations & SR_SELECT_READ) { if (!(tcp_fd->tf_flags & TFF_CONNECTEDx)) return ENOTCONN; /* Is this right? */ tcp_conn= tcp_fd->tf_conn; if (tcp_conn->tc_state == TCS_CLOSED || tcp_sel_read(tcp_conn)) resops |= SR_SELECT_READ; else if (!(operations & SR_SELECT_POLL)) tcp_fd->tf_flags |= TFF_SEL_READ; } if (operations & SR_SELECT_WRITE) { if (!(tcp_fd->tf_flags & TFF_CONNECTEDx)) return ENOTCONN; /* Is this right? */ tcp_conn= tcp_fd->tf_conn; if (tcp_conn->tc_state == TCS_CLOSED || tcp_conn->tc_flags & TCF_FIN_SENT || tcp_sel_write(tcp_conn)) { resops |= SR_SELECT_WRITE; } else if (!(operations & SR_SELECT_POLL)) tcp_fd->tf_flags |= TFF_SEL_WRITE; } if (operations & SR_SELECT_EXCEPTION) { printf("tcp_select: not implemented for exceptions\n"); } return resops;}PRIVATE acc_t *tcp_get_data (port, offset, count, for_ioctl)int port;size_t offset;size_t count;int for_ioctl;{ tcp_port_t *tcp_port; int result; tcp_port= &tcp_port_table[port]; switch (tcp_port->tp_state) { case TPS_SETPROTO: if (!count) { result= (int)offset; if (result<0) { tcp_port->tp_state= TPS_ERROR; break; } tcp_port->tp_state= TPS_GETCONF; if (tcp_port->tp_flags & TPF_SUSPEND) tcp_main(tcp_port); return NW_OK; }assert (!offset);assert (count == sizeof(struct nwio_ipopt)); { struct nwio_ipopt *ipopt; acc_t *acc; acc= bf_memreq(sizeof(*ipopt)); ipopt= (struct nwio_ipopt *)ptr2acc_data(acc); ipopt->nwio_flags= NWIO_COPY | NWIO_EN_LOC | NWIO_DI_BROAD | NWIO_REMANY | NWIO_PROTOSPEC | NWIO_HDR_O_ANY | NWIO_RWDATALL; ipopt->nwio_proto= IPPROTO_TCP; return acc; } case TPS_MAIN: assert(tcp_port->tp_flags & TPF_WRITE_IP); if (!count) { result= (int)offset; if (result<0) { if (result == EDSTNOTRCH) { if (tcp_port->tp_snd_head) { tcp_notreach(tcp_port-> tp_snd_head); } } else { ip_warning(( "ip_write failed with error: %d\n", result )); } } assert (tcp_port->tp_pack); bf_afree (tcp_port->tp_pack); tcp_port->tp_pack= 0; if (tcp_port->tp_flags & TPF_WRITE_SP) { tcp_port->tp_flags &= ~(TPF_WRITE_SP| TPF_WRITE_IP); if (tcp_port->tp_snd_head) tcp_port_write(tcp_port); } else tcp_port->tp_flags &= ~TPF_WRITE_IP; } else { return bf_cut (tcp_port->tp_pack, offset, count); } break; default: printf("tcp_get_data(%d, 0x%x, 0x%x) called but tp_state= 0x%x\n", port, offset, count, tcp_port->tp_state); break; } return NW_OK;}PRIVATE int tcp_put_data (fd, offset, data, for_ioctl)int fd;size_t offset;acc_t *data;int for_ioctl;{ tcp_port_t *tcp_port; int result; tcp_port= &tcp_port_table[fd]; switch (tcp_port->tp_state) { case TPS_GETCONF: if (!data) { result= (int)offset; if (result<0) { tcp_port->tp_state= TPS_ERROR; return NW_OK; } tcp_port->tp_state= TPS_MAIN; if (tcp_port->tp_flags & TPF_SUSPEND) tcp_main(tcp_port); } else { struct nwio_ipconf *ipconf; data= bf_packIffLess(data, sizeof(*ipconf)); ipconf= (struct nwio_ipconf *)ptr2acc_data(data);assert (ipconf->nwic_flags & NWIC_IPADDR_SET); tcp_port->tp_ipaddr= ipconf->nwic_ipaddr; tcp_port->tp_subnetmask= ipconf->nwic_netmask; tcp_port->tp_mtu= ipconf->nwic_mtu; bf_afree(data); } break; case TPS_MAIN: assert(tcp_port->tp_flags & TPF_READ_IP); if (!data) { result= (int)offset; if (result<0) ip_panic(( "ip_read() failed" )); if (tcp_port->tp_flags & TPF_READ_SP) { tcp_port->tp_flags &= ~(TPF_READ_SP| TPF_READ_IP); read_ip_packets(tcp_port); } else tcp_port->tp_flags &= ~TPF_READ_IP; } else { assert(!offset); /* this is an invalid assertion but ip sends * only whole datagrams up */ tcp_put_pkt(fd, data, bf_bufsize(data)); } break; default: printf( "tcp_put_data(%d, 0x%x, %p) called but tp_state= 0x%x\n", fd, offset, data, tcp_port->tp_state); break; } return NW_OK;}/*tcp_put_pkt*/PRIVATE void tcp_put_pkt(fd, data, datalen)int fd;acc_t *data;size_t datalen;{ tcp_port_t *tcp_port; tcp_conn_t *tcp_conn, **conn_p; ip_hdr_t *ip_hdr; tcp_hdr_t *tcp_hdr; acc_t *ip_pack, *tcp_pack; size_t ip_datalen, tcp_datalen, ip_hdr_len, tcp_hdr_len; u16_t sum, mtu; u32_t bits; int i, hash; ipaddr_t srcaddr, dstaddr, ipaddr, mask; tcpport_t srcport, dstport; tcp_port= &tcp_port_table[fd]; /* Extract the IP header. */ ip_hdr= (ip_hdr_t *)ptr2acc_data(data); ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2; ip_datalen= datalen - ip_hdr_len; if (ip_datalen == 0) { if (ip_hdr->ih_proto == 0) { /* IP layer reports new IP address */ ipaddr= ip_hdr->ih_src; mask= ip_hdr->ih_dst; mtu= ntohs(ip_hdr->ih_length); tcp_port->tp_ipaddr= ipaddr; tcp_port->tp_subnetmask= mask; tcp_port->tp_mtu= mtu; DBLOCK(1, printf("tcp_put_pkt: using address "); writeIpAddr(ipaddr); printf(", netmask "); writeIpAddr(mask); printf(", mtu %u\n", mtu)); for (i= 0, tcp_conn= tcp_conn_table+i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -