📄 tcp_recv.c
字号:
TIME-WAIT: 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*/ rcv_hi= tcp_conn->tc_RCV_HI; if (tcp_hdr_flags & THF_URG) rcv_hi++; 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)) { DBLOCK(0x20, printf("segment is not acceptable\n"); printf("\t"); tcp_print_pack(ip_hdr, tcp_hdr); printf("\n\t"); tcp_print_conn(tcp_conn); printf("\n")); tcp_conn->tc_flags |= TCF_SEND_ACK; tcp_conn_write(tcp_conn, 1); /* Sometimes, a retransmission sets the PSH * flag (Solaris 2.4) */ if (tcp_conn->tc_rcvd_data != NULL && (tcp_hdr_flags & THF_PSH)) { tcp_conn->tc_flags |= TCF_RCV_PUSH; if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_READ_IP)) { tcp_fd_read(tcp_conn, 1); } if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_SEL_READ)) { tcp_rsel_read(tcp_conn); } } } break; }/* RST ? state == CLOSING || state == LAST-ACK || state == TIME-WAIT ? state= CLOSED exit : state= CLOSED error "connection reset" exit*/ if (tcp_hdr_flags & THF_RST) { if ((tcp_conn->tc_flags & (TCF_FIN_SENT|TCF_FIN_RECV)) == (TCF_FIN_SENT|TCF_FIN_RECV) && tcp_conn->tc_send_data == NULL) { /* Clean shutdown, but the other side * doesn't want to ACK our FIN. */ tcp_close_connection (tcp_conn, 0); } else tcp_close_connection(tcp_conn, ECONNRESET); break; }/* SYN in window ? state= CLOSED error "connection reset" exit*/ if ((tcp_hdr_flags & THF_SYN) && tcp_GEmod4G(seg_seq, tcp_conn->tc_RCV_NXT)) { tcp_close_connection(tcp_conn, ECONNRESET); break; }/* !ACK ? discard packet exit*/ if (!(tcp_hdr_flags & THF_ACK)) break;/* SND.UNA < SEG.ACK <= SND.NXT ? SND.UNA= SEG.ACK reply "send ok" SND.WL1 < SEG.SEQ || (SND.WL1 == SEG.SEQ && SND.WL2 <= SEG.ACK ? SND.WND= SEG.WND SND.Wl1= SEG.SEQ SND.WL2= SEG.ACK SEG.ACK <= SND.UNA ? ignore ACK SEG.ACK > SND.NXT ? <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK> discard packet exit*/ /* Always reset the send timer after a valid ack is * received. The assumption is that either the ack really * acknowledges some data (normal case), contains a zero * window, or the remote host has another reason not * to accept any data. In all cases, the remote host is * alive, so the connection should stay alive too. * Do not reset stt if the state is CLOSING, i.e. if * the user closed the connection and we still have * some data to deliver. We don't want a zero window * to keep us from closing the connection. */ if (tcp_conn->tc_state != TCS_CLOSING) tcp_conn->tc_stt= 0; snd_una= tcp_conn->tc_SND_UNA; snd_nxt= tcp_conn->tc_SND_NXT; if (seg_ack == snd_una) { if (tcp_Gmod4G(snd_nxt, snd_una)) { /* Duplicate ACK */ if (++tcp_conn->tc_snd_dack == TCP_DACK_RETRANS) { tcp_fast_retrans(tcp_conn); } } /* This ACK doesn't acknowledge any new data, this * is a likely situation if we are only receiving * data. We only update the window if we are * actually sending or if we currently have a * zero window. */ if (tcp_conn->tc_snd_cwnd == snd_una && seg_wnd != 0) { DBLOCK(2, printf("zero window opened\n")); /* The other side opened up its receive * window. */ mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE; if (seg_wnd > 2*mss) seg_wnd= 2*mss; tcp_conn->tc_snd_cwnd= snd_una+seg_wnd; tcp_conn_write(tcp_conn, 1); } if (seg_wnd == 0) { tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_TRM= snd_una; } } else if (tcp_Lmod4G(snd_una, seg_ack) && tcp_LEmod4G(seg_ack, snd_nxt)) { tcp_release_retrans(tcp_conn, seg_ack, seg_wnd); if (tcp_conn->tc_state == TCS_CLOSED) break; } else if (tcp_Gmod4G(seg_ack, snd_nxt)) { tcp_conn->tc_flags |= TCF_SEND_ACK; tcp_conn_write(tcp_conn, 1); DBLOCK(1, printf( "got an ack of something I haven't send\n"); printf( "seg_ack= %lu, SND_NXT= %lu\n", seg_ack, snd_nxt)); break; }/* process data...*/ tcp_extract_ipopt(tcp_conn, ip_hdr); tcp_extract_tcpopt(tcp_conn, tcp_hdr, &mss); if (data_len) { if (tcp_LEmod4G(seg_seq, tcp_conn->tc_RCV_NXT)) { process_data (tcp_conn, tcp_hdr, tcp_data, data_len); } else { process_advanced_data (tcp_conn, tcp_hdr, tcp_data, data_len); } tcp_conn->tc_flags |= TCF_SEND_ACK; tcp_conn_write(tcp_conn, 1); /* Don't process a FIN if we got new data */ break; }/* FIN ? reply pending receives advace RCV.NXT over the FIN <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK> state == ESTABLISHED ? state= CLOSE-WAIT state == FIN-WAIT-1 ? state= CLOSING state == FIN-WAIT-2 ? state= TIME-WAIT state == TIME-WAIT ? restart the TIME-WAIT timer exit*/ if ((tcp_hdr_flags & THF_FIN) && tcp_LEmod4G(seg_seq, tcp_conn->tc_RCV_NXT)) { if (!(tcp_conn->tc_flags & TCF_FIN_RECV) && tcp_Lmod4G(tcp_conn->tc_RCV_NXT, tcp_conn->tc_RCV_HI)) { tcp_conn->tc_RCV_NXT++; tcp_conn->tc_flags |= TCF_FIN_RECV; } tcp_conn->tc_flags |= TCF_SEND_ACK; tcp_conn_write(tcp_conn, 1); if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_READ_IP)) { tcp_fd_read(tcp_conn, 1); } if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_SEL_READ)) { tcp_rsel_read(tcp_conn); } } break; default: printf("tcp_frag2conn: unknown state "); tcp_print_state(tcp_conn); break; } if (tcp_data != NULL) bf_afree(tcp_data);}PRIVATE voidprocess_data(tcp_conn, tcp_hdr, tcp_data, data_len)tcp_conn_t *tcp_conn;tcp_hdr_t *tcp_hdr;acc_t *tcp_data;int data_len;{ u32_t lo_seq, hi_seq, urg_seq, seq_nr, adv_seq, nxt; u32_t urgptr; int tcp_hdr_flags; unsigned int offset; acc_t *tmp_data, *rcvd_data, *adv_data; int len_diff; assert(tcp_conn->tc_busy); /* Note, tcp_data will be freed by the caller. */ assert (!(tcp_hdr->th_flags & THF_SYN)); seq_nr= ntohl(tcp_hdr->th_seq_nr); urgptr= ntohs(tcp_hdr->th_urgptr); tcp_data->acc_linkC++; lo_seq= seq_nr; tcp_hdr_flags= tcp_hdr->th_flags & TH_FLAGS_MASK; if (tcp_Lmod4G(lo_seq, tcp_conn->tc_RCV_NXT)) { DBLOCK(0x10, printf("segment is a retransmission\n")); offset= tcp_conn->tc_RCV_NXT-lo_seq; tcp_data= bf_delhead(tcp_data, offset); lo_seq += offset; data_len -= offset; if (tcp_hdr_flags & THF_URG) { printf("process_data: updating urgent pointer\n"); if (urgptr >= offset) urgptr -= offset; else tcp_hdr_flags &= ~THF_URG; } } assert (lo_seq == tcp_conn->tc_RCV_NXT); if (tcp_hdr_flags & THF_URG) { if (!(tcp_conn->tc_flags & TCF_BSD_URG)) { /* Update urgent pointer to point past the urgent * data */ urgptr++; } if (urgptr == 0) tcp_hdr_flags &= ~THF_URG; } if (tcp_hdr_flags & THF_URG) { if (urgptr > data_len) urgptr= data_len; urg_seq= lo_seq+urgptr; if (tcp_GEmod4G(urg_seq, tcp_conn->tc_RCV_HI)) urg_seq= tcp_conn->tc_RCV_HI; if (tcp_conn->tc_flags & TCF_BSD_URG) { if (tcp_Gmod4G(tcp_conn->tc_RCV_NXT, tcp_conn->tc_RCV_LO)) { DBLOCK(1, printf( "ignoring urgent data\n")); bf_afree(tcp_data); /* Should set advertised window to * zero */ /* Flush */ tcp_conn->tc_flags |= TCF_RCV_PUSH; if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_READ_IP)) { tcp_fd_read(tcp_conn, 1); } if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_SEL_READ)) { tcp_rsel_read(tcp_conn); } return; } } if (tcp_Gmod4G(urg_seq, tcp_conn->tc_RCV_UP)) tcp_conn->tc_RCV_UP= urg_seq;#if 0 if (urgptr < data_len) { data_len= urgptr; tmp_data= bf_cut(tcp_data, 0, data_len); bf_afree(tcp_data); tcp_data= tmp_data; tcp_hdr_flags &= ~THF_FIN; }#endif tcp_conn->tc_flags |= TCF_RCV_PUSH; } else { /* Normal data. */ } if (tcp_hdr_flags & THF_PSH) { tcp_conn->tc_flags |= TCF_RCV_PUSH; } hi_seq= lo_seq+data_len; if (tcp_Gmod4G(hi_seq, tcp_conn->tc_RCV_HI)) { data_len= tcp_conn->tc_RCV_HI-lo_seq; tmp_data= bf_cut(tcp_data, 0, data_len); bf_afree(tcp_data); tcp_data= tmp_data; hi_seq= lo_seq+data_len; tcp_hdr_flags &= ~THF_FIN; } assert (tcp_LEmod4G (hi_seq, tcp_conn->tc_RCV_HI)); rcvd_data= tcp_conn->tc_rcvd_data; tcp_conn->tc_rcvd_data= 0; tmp_data= bf_append(rcvd_data, tcp_data); tcp_conn->tc_rcvd_data= tmp_data; tcp_conn->tc_RCV_NXT= hi_seq; if ((tcp_hdr_flags & THF_FIN) && tcp_Lmod4G(tcp_conn->tc_RCV_NXT, tcp_conn->tc_RCV_HI) && !(tcp_conn->tc_flags & TCF_FIN_RECV)) { tcp_conn->tc_RCV_NXT++; tcp_conn->tc_flags |= TCF_FIN_RECV; } if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_READ_IP)) tcp_fd_read(tcp_conn, 1); if (tcp_conn->tc_fd && (tcp_conn->tc_fd->tf_flags & TFF_SEL_READ)) tcp_rsel_read(tcp_conn); DIFBLOCK(2, (tcp_conn->tc_RCV_NXT == tcp_conn->tc_RCV_HI), printf("conn[[%d] full receive buffer\n", tcp_conn-tcp_conn_table)); if (tcp_conn->tc_adv_data == NULL) return; if (tcp_hdr_flags & THF_FIN) { printf("conn[%d]: advanced data after FIN\n", tcp_conn-tcp_conn_table); tcp_data= tcp_conn->tc_adv_data; tcp_conn->tc_adv_data= NULL; bf_afree(tcp_data); return; } lo_seq= tcp_conn->tc_adv_seq; if (tcp_Gmod4G(lo_seq, tcp_conn->tc_RCV_NXT)) return; /* Not yet */ tcp_data= tcp_conn->tc_adv_data; tcp_conn->tc_adv_data= NULL; data_len= bf_bufsize(tcp_data); if (tcp_Lmod4G(lo_seq, tcp_conn->tc_RCV_NXT)) { offset= tcp_conn->tc_RCV_NXT-lo_seq; if (offset >= data_len) { bf_afree(tcp_data); return; } tcp_data= bf_delhead(tcp_data, offset); lo_seq += offset; data_len -= offset; } assert (lo_seq == tcp_conn->tc_RCV_NXT); hi_seq= lo_seq+data_len; assert (tcp_LEmod4G (hi_seq, tcp_conn->tc_RCV_HI)); rcvd_data= tcp_conn->tc_rcvd_data; tcp_conn->tc_rcvd_data= 0; tmp_data= bf_append(rcvd_data, tcp_data);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -