📄 tcp_recv.c
字号:
/*tcp_recv.cCopyright 1995 Philip Homburg*/#include "inet.h"#include "buf.h"#include "clock.h"#include "event.h"#include "type.h"#include "sr.h"#include "io.h"#include "tcp_int.h"#include "tcp.h"#include "assert.h"THIS_FILEFORWARD void create_RST ARGS(( tcp_conn_t *tcp_conn, ip_hdr_t *ip_hdr, tcp_hdr_t *tcp_hdr, int data_len ));FORWARD void process_data ARGS(( tcp_conn_t *tcp_conn, tcp_hdr_t *tcp_hdr, acc_t *tcp_data, int data_len ));FORWARD void process_advanced_data ARGS(( tcp_conn_t *tcp_conn, tcp_hdr_t *tcp_hdr, acc_t *tcp_data, int data_len ));PUBLIC void tcp_frag2conn(tcp_conn, ip_hdr, tcp_hdr, tcp_data, data_len)tcp_conn_t *tcp_conn;ip_hdr_t *ip_hdr;tcp_hdr_t *tcp_hdr;acc_t *tcp_data;size_t data_len;{ tcp_fd_t *connuser; int tcp_hdr_flags; int ip_hdr_len, tcp_hdr_len; u32_t seg_ack, seg_seq, rcv_hi, snd_una, snd_nxt; u16_t seg_wnd, mtu; size_t mss; int acceptable_ACK, segm_acceptable, send_rst, close_connection; ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2; tcp_hdr_len= (tcp_hdr->th_data_off & TH_DO_MASK) >> 2; tcp_hdr_flags= tcp_hdr->th_flags & TH_FLAGS_MASK; seg_ack= ntohl(tcp_hdr->th_ack_nr); seg_seq= ntohl(tcp_hdr->th_seq_nr); seg_wnd= ntohs(tcp_hdr->th_window);#if 0 { where(); tcp_print_conn(tcp_conn); printf("\n"); tcp_print_pack(ip_hdr, tcp_hdr); printf("\n"); }#endif switch (tcp_conn->tc_state) { case TCS_CLOSED:/*CLOSED: discard all data. !RST ? ACK ? <SEQ=SEG.ACK><CTL=RST> exit : <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK> exit : discard packet exit*/ if (!(tcp_hdr_flags & THF_RST)) { create_RST(tcp_conn, ip_hdr, tcp_hdr, data_len); tcp_conn_write(tcp_conn, 1); } break; case TCS_LISTEN:/*LISTEN: RST ? discard packet exit ACK ? <SEQ=SEG.ACK><CTL=RST> exit SYN ? BUG: no security check RCV.NXT= SEG.SEQ+1 IRS= SEG.SEQ ISS should already be selected <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK> SND.NXT=ISS+1 SND.UNA=ISS state= SYN-RECEIVED exit : shouldnot occur discard packet exit*/ if (tcp_hdr_flags & THF_RST) break; if (tcp_hdr_flags & THF_ACK) { create_RST (tcp_conn, ip_hdr, tcp_hdr, data_len); tcp_conn_write(tcp_conn, 1); break; } if (tcp_hdr_flags & THF_SYN) { tcp_extract_ipopt(tcp_conn, ip_hdr); tcp_extract_tcpopt(tcp_conn, tcp_hdr, &mss); mtu= mss+IP_TCP_MIN_HDR_SIZE; if (mtu < IP_MIN_MTU) { /* No or unrealistic mss, use default MTU */ mtu= IP_DEF_MTU; } if (mtu < tcp_conn->tc_max_mtu) { tcp_conn->tc_max_mtu= mtu; tcp_conn->tc_mtu= mtu; DBLOCK(1, printf( "tcp[%d]: conn[%d]: mtu = %d\n", tcp_conn->tc_port-tcp_port_table, tcp_conn-tcp_conn_table, mtu);); } tcp_conn->tc_RCV_LO= seg_seq+1; tcp_conn->tc_RCV_NXT= seg_seq+1; tcp_conn->tc_RCV_HI= tcp_conn->tc_RCV_LO+ tcp_conn->tc_rcv_wnd; tcp_conn->tc_RCV_UP= seg_seq; tcp_conn->tc_IRS= seg_seq; 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+1; tcp_conn->tc_SND_UP= tcp_conn->tc_ISS-1; tcp_conn->tc_SND_PSH= tcp_conn->tc_ISS-1; tcp_conn->tc_state= TCS_SYN_RECEIVED; tcp_conn->tc_stt= 0; assert (tcp_check_conn(tcp_conn)); tcp_conn->tc_locaddr= ip_hdr->ih_dst; tcp_conn->tc_locport= tcp_hdr->th_dstport; tcp_conn->tc_remaddr= ip_hdr->ih_src; tcp_conn->tc_remport= tcp_hdr->th_srcport; tcp_conn_write(tcp_conn, 1); DIFBLOCK(0x10, seg_seq == 0, printf("warning got 0 IRS from "); writeIpAddr(tcp_conn->tc_remaddr); printf("\n")); /* Start the timer (if necessary) */ tcp_set_send_timer(tcp_conn); break; } /* do nothing */ break; case TCS_SYN_SENT:/*SYN-SENT: ACK ? SEG.ACK <= ISS || SEG.ACK > SND.NXT ? RST ? discard packet exit : <SEQ=SEG.ACK><CTL=RST> exit SND.UNA <= SEG.ACK && SEG.ACK <= SND.NXT ? ACK is acceptable : ACK is !acceptable : ACK is !acceptable RST ? ACK acceptable ? discard segment state= CLOSED error "connection refused" exit : discard packet exit BUG: no security check SYN ? IRS= SEG.SEQ RCV.NXT= IRS+1 ACK ? SND.UNA= SEG.ACK SND.UNA > ISS ? state= ESTABLISHED <SEQ=SND.NXT><ACK= RCV.NXT><CTL=ACK> process ev. URG and text exit : state= SYN-RECEIVED SND.WND= SEG.WND SND.WL1= SEG.SEQ SND.WL2= SEG.ACK <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK> exit : discard segment exit*/ if (tcp_hdr_flags & THF_ACK) { if (tcp_LEmod4G(seg_ack, tcp_conn->tc_ISS) || tcp_Gmod4G(seg_ack, tcp_conn->tc_SND_NXT)) if (tcp_hdr_flags & THF_RST) break; else { /* HACK: force sending a RST, * normally, RSTs are not send * if the segment is an ACK. */ create_RST (tcp_conn, ip_hdr, tcp_hdr, data_len+1); tcp_conn_write(tcp_conn, 1); break; } acceptable_ACK= (tcp_LEmod4G(tcp_conn->tc_SND_UNA, seg_ack) && tcp_LEmod4G(seg_ack, tcp_conn->tc_SND_NXT)); } else acceptable_ACK= FALSE; if (tcp_hdr_flags & THF_RST) { if (acceptable_ACK) { DBLOCK(1, printf( "calling tcp_close_connection\n")); tcp_close_connection(tcp_conn, ECONNREFUSED); } break; } if (tcp_hdr_flags & THF_SYN) { tcp_extract_ipopt(tcp_conn, ip_hdr); tcp_extract_tcpopt(tcp_conn, tcp_hdr, &mss); mtu= mss+IP_TCP_MIN_HDR_SIZE; if (mtu < IP_MIN_MTU) { /* No or unrealistic mss, use default MTU */ mtu= IP_DEF_MTU; } if (mtu < tcp_conn->tc_max_mtu) { tcp_conn->tc_max_mtu= mtu; tcp_conn->tc_mtu= mtu; DBLOCK(1, printf( "tcp[%d]: conn[%d]: mtu = %d\n", tcp_conn->tc_port-tcp_port_table, tcp_conn-tcp_conn_table, mtu);); } tcp_conn->tc_RCV_LO= seg_seq+1; tcp_conn->tc_RCV_NXT= seg_seq+1; tcp_conn->tc_RCV_HI= tcp_conn->tc_RCV_LO + tcp_conn->tc_rcv_wnd; tcp_conn->tc_RCV_UP= seg_seq; tcp_conn->tc_IRS= seg_seq; if (tcp_hdr_flags & THF_ACK) tcp_conn->tc_SND_UNA= seg_ack; if (tcp_Gmod4G(tcp_conn->tc_SND_UNA, tcp_conn->tc_ISS)) { tcp_conn->tc_state= TCS_ESTABLISHED; tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD; assert (tcp_check_conn(tcp_conn)); assert(tcp_conn->tc_connInprogress); tcp_restart_connect(tcp_conn); tcp_conn->tc_flags |= TCF_SEND_ACK; tcp_conn_write(tcp_conn, 1); if (data_len != 0) { tcp_frag2conn(tcp_conn, ip_hdr, tcp_hdr, tcp_data, data_len); /* tcp_data is already freed */ return; } break; } tcp_conn->tc_state= TCS_SYN_RECEIVED; assert (tcp_check_conn(tcp_conn)); tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS; tcp_conn_write(tcp_conn, 1); } break; case TCS_SYN_RECEIVED:/*SYN-RECEIVED: test if segment is acceptable: Segment Receive Test Length Window 0 0 SEG.SEQ == RCV.NXT 0 >0 RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND >0 0 not acceptable >0 >0 (RCV.NXT <= SEG.SEQ && SEG.SEQ < RCV.NXT+RCV.WND) || (RCV.NXT <= SEG.SEQ+SEG.LEN-1 && SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND) for urgent data: use RCV.WND+1 for RCV.WND Special: Send RST if SEG.SEQ < IRS or SEG.SEQ > RCV.NXT+64K (and the packet is not a RST packet itself).*/ rcv_hi= tcp_conn->tc_RCV_HI; if (tcp_hdr_flags & THF_URG) rcv_hi++; send_rst= tcp_Lmod4G(seg_seq, tcp_conn->tc_IRS) || tcp_Gmod4G(seg_seq, tcp_conn->tc_RCV_NXT+0x10000); close_connection= 0; if (!data_len) { if (rcv_hi == tcp_conn->tc_RCV_NXT) segm_acceptable= (seg_seq == rcv_hi); else { assert (tcp_Gmod4G(rcv_hi, tcp_conn->tc_RCV_NXT)); segm_acceptable= (tcp_LEmod4G(tcp_conn-> tc_RCV_NXT, seg_seq) && tcp_Lmod4G(seg_seq, rcv_hi)); } } else { if (tcp_Gmod4G(rcv_hi, tcp_conn->tc_RCV_NXT)) { segm_acceptable= (tcp_LEmod4G(tcp_conn-> tc_RCV_NXT, seg_seq) && tcp_Lmod4G(seg_seq, rcv_hi)) || (tcp_LEmod4G(tcp_conn->tc_RCV_NXT, seg_seq+data_len-1) && tcp_Lmod4G(seg_seq+data_len-1, rcv_hi)); } else { segm_acceptable= FALSE; } }/* !segment acceptable ? RST ? discard packet exit : <SEG=SND.NXT><ACK=RCV.NXT><CTL=ACK> exit*/ if (!segm_acceptable) { if (tcp_hdr_flags & THF_RST) ; /* do nothing */ else if (send_rst) { create_RST(tcp_conn, ip_hdr, tcp_hdr, data_len); tcp_conn_write(tcp_conn, 1); } else { tcp_conn->tc_flags |= TCF_SEND_ACK; tcp_conn_write(tcp_conn, 1); } break; }/* RST ? initiated by a LISTEN ? state= LISTEN exit : state= CLOSED error "connection refused" exit*/ if (tcp_hdr_flags & THF_RST) close_connection= 1;/* SYN in window ? initiated by a LISTEN ? state= LISTEN exit : state= CLOSED error "connection reset" exit*/ if ((tcp_hdr_flags & THF_SYN) && tcp_GEmod4G(seg_seq, tcp_conn->tc_RCV_NXT)) { close_connection= 1; } if (close_connection) { if (!tcp_conn->tc_orglisten) { tcp_close_connection(tcp_conn, ECONNREFUSED); break; } connuser= tcp_conn->tc_fd; assert(connuser); if (connuser->tf_flags & TFF_LISTENQ) { tcp_close_connection (tcp_conn, ECONNREFUSED); } else { tcp_conn->tc_connInprogress= 0; tcp_conn->tc_fd= NULL; tcp_close_connection (tcp_conn, ECONNREFUSED); /* Pick a new ISS next time */ tcp_conn->tc_ISS= 0; (void)tcp_su4listen(connuser, tcp_conn, 0 /* !do_listenq */); } break; }/* !ACK ? discard packet exit*/ if (!(tcp_hdr_flags & THF_ACK)) break;/* SND.UNA < SEG.ACK <= SND.NXT ? state= ESTABLISHED : <SEG=SEG.ACK><CTL=RST> exit*/ if (tcp_Lmod4G(tcp_conn->tc_SND_UNA, seg_ack) && tcp_LEmod4G(seg_ack, tcp_conn->tc_SND_NXT)) { tcp_conn->tc_state= TCS_ESTABLISHED; tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD; tcp_release_retrans(tcp_conn, seg_ack, seg_wnd); assert (tcp_check_conn(tcp_conn)); assert(tcp_conn->tc_connInprogress); tcp_restart_connect(tcp_conn); tcp_frag2conn(tcp_conn, ip_hdr, tcp_hdr, tcp_data, data_len); /* tcp_data is already freed */ return; } else { create_RST (tcp_conn, ip_hdr, tcp_hdr, data_len); tcp_conn_write(tcp_conn, 1); break; } break; case TCS_ESTABLISHED: case TCS_CLOSING:/*ESTABLISHED:FIN-WAIT-1:FIN-WAIT-2:CLOSE-WAIT:CLOSING:LAST-ACK:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -