📄 tcp_recv.c
字号:
tcp_conn->tc_rcvd_data= tmp_data; tcp_conn->tc_RCV_NXT= hi_seq; assert (tcp_conn->tc_RCV_LO + bf_bufsize(tcp_conn->tc_rcvd_data) == tcp_conn->tc_RCV_NXT || (tcp_print_conn(tcp_conn), printf("\n"), 0)); 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); adv_data= tcp_conn->tc_adv_data; if (adv_data != NULL) { /* Try to use advanced data. */ adv_seq= tcp_conn->tc_adv_seq; nxt= tcp_conn->tc_RCV_NXT; if (tcp_Gmod4G(adv_seq, nxt)) return; /* not yet */ tcp_conn->tc_adv_data= NULL; data_len= bf_bufsize(adv_data); if (tcp_Lmod4G(adv_seq, nxt)) { if (tcp_LEmod4G(adv_seq+data_len, nxt)) { /* Data is not needed anymore. */ bf_afree(adv_data); return; } len_diff= nxt-adv_seq; adv_data= bf_delhead(adv_data, len_diff); data_len -= len_diff; } DBLOCK(1, printf("using advanced data\n")); /* Append data to the input buffer */ if (tcp_conn->tc_rcvd_data == NULL) { tcp_conn->tc_rcvd_data= adv_data; } else { tcp_conn->tc_rcvd_data= bf_append(tcp_conn->tc_rcvd_data, adv_data); } tcp_conn->tc_SND_NXT += data_len; assert(tcp_check_conn(tcp_conn)); 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); } }}PRIVATE void process_advanced_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 seq, adv_seq; acc_t *adv_data; assert(tcp_conn->tc_busy); /* Note, tcp_data will be freed by the caller. */ /* Always send an ACK, this allows the sender to do a fast * retransmit. */ tcp_conn->tc_flags |= TCF_SEND_ACK; tcp_conn_write(tcp_conn, 1); if (tcp_hdr->th_flags & THF_URG) return; /* Urgent data is to complicated */ if (tcp_hdr->th_flags & THF_PSH) tcp_conn->tc_flags |= TCF_RCV_PUSH; seq= ntohl(tcp_hdr->th_seq_nr); /* Make sure that the packet doesn't fall outside of the window * we offered. */ if (tcp_Gmod4G(seq+data_len, tcp_conn->tc_RCV_HI)) return; adv_data= tcp_conn->tc_adv_data; adv_seq= tcp_conn->tc_adv_seq; tcp_conn->tc_adv_data= NULL; tcp_data->acc_linkC++; if (adv_data == NULL) { adv_seq= seq; adv_data= tcp_data; } else if (seq + data_len == adv_seq) { /* New data fits right before exiting data. */ adv_data= bf_append(tcp_data, adv_data); adv_seq= seq; } else if (adv_seq + bf_bufsize(adv_data) == seq) { /* New data fits right after exiting data. */ adv_data= bf_append(adv_data, tcp_data); } else { /* New data doesn't fit. */ bf_afree(tcp_data); } tcp_conn->tc_adv_data= adv_data; tcp_conn->tc_adv_seq= adv_seq;} PRIVATE void create_RST(tcp_conn, ip_hdr, tcp_hdr, data_len)tcp_conn_t *tcp_conn;ip_hdr_t *ip_hdr;tcp_hdr_t *tcp_hdr;int data_len;{ acc_t *tmp_ipopt, *tmp_tcpopt, *tcp_pack; acc_t *RST_acc; ip_hdr_t *RST_ip_hdr; tcp_hdr_t *RST_tcp_hdr; size_t pack_size, ip_hdr_len, mss; DBLOCK(0x10, printf("in create_RST, bad pack is:\n"); tcp_print_pack(ip_hdr, tcp_hdr); tcp_print_state(tcp_conn); printf("\n")); assert(tcp_conn->tc_busy); /* Only send RST packets in reponse to actual data (or SYN, FIN) * this solves a problem during connection shutdown. The problem * is the follow senario: a senders closes the connection instead * of doing a shutdown and waiting for the receiver to shutdown. * The receiver is slow in processing the last data. After the * sender has completely closed the connection, the receiver * sends a window update which triggers the sender to send a * RST. The receiver closes the connection in reponse to the RST. */ if ((tcp_hdr->th_flags & (THF_FIN|THF_SYN)) == 0 && data_len == 0) {#if DEBUG { printf("tcp_recv`create_RST: no data, no RST\n"); }#endif return; } tmp_ipopt= tcp_conn->tc_remipopt; if (tmp_ipopt) tmp_ipopt->acc_linkC++; tmp_tcpopt= tcp_conn->tc_tcpopt; if (tmp_tcpopt) tmp_tcpopt->acc_linkC++; tcp_extract_ipopt (tcp_conn, ip_hdr); tcp_extract_tcpopt (tcp_conn, tcp_hdr, &mss); RST_acc= tcp_make_header (tcp_conn, &RST_ip_hdr, &RST_tcp_hdr, (acc_t *)0); if (tcp_conn->tc_remipopt) bf_afree(tcp_conn->tc_remipopt); tcp_conn->tc_remipopt= tmp_ipopt; if (tcp_conn->tc_tcpopt) bf_afree(tcp_conn->tc_tcpopt); tcp_conn->tc_tcpopt= tmp_tcpopt; RST_ip_hdr->ih_src= ip_hdr->ih_dst; RST_ip_hdr->ih_dst= ip_hdr->ih_src; RST_tcp_hdr->th_srcport= tcp_hdr->th_dstport; RST_tcp_hdr->th_dstport= tcp_hdr->th_srcport; if (tcp_hdr->th_flags & THF_ACK) { RST_tcp_hdr->th_seq_nr= tcp_hdr->th_ack_nr; RST_tcp_hdr->th_flags= THF_RST; } else { RST_tcp_hdr->th_seq_nr= 0; RST_tcp_hdr->th_ack_nr= htonl( ntohl(tcp_hdr->th_seq_nr)+ data_len + (tcp_hdr->th_flags & THF_SYN ? 1 : 0) + (tcp_hdr->th_flags & THF_FIN ? 1 : 0)); RST_tcp_hdr->th_flags= THF_RST|THF_ACK; } pack_size= bf_bufsize(RST_acc); RST_ip_hdr->ih_length= htons(pack_size); RST_tcp_hdr->th_window= htons(tcp_conn->tc_rcv_wnd); RST_tcp_hdr->th_chksum= 0; RST_acc->acc_linkC++; ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2; tcp_pack= bf_delhead(RST_acc, ip_hdr_len); RST_tcp_hdr->th_chksum= ~tcp_pack_oneCsum (RST_ip_hdr, tcp_pack); bf_afree(tcp_pack); DBLOCK(2, tcp_print_pack(ip_hdr, tcp_hdr); printf("\n"); tcp_print_pack(RST_ip_hdr, RST_tcp_hdr); printf("\n")); if (tcp_conn->tc_frag2send) bf_afree(tcp_conn->tc_frag2send); tcp_conn->tc_frag2send= RST_acc; tcp_conn_write(tcp_conn, 1);}PUBLIC voidtcp_fd_read(tcp_conn, enq)tcp_conn_t *tcp_conn;int enq; /* Enqueue writes. */{ tcp_fd_t *tcp_fd; size_t data_size, read_size; acc_t *data; int fin_recv, urg, push, result; i32_t old_window, new_window; u16_t mss; assert(tcp_conn->tc_busy); tcp_fd= tcp_conn->tc_fd; assert (tcp_fd->tf_flags & TFF_READ_IP); if (tcp_conn->tc_state == TCS_CLOSED) { if (tcp_fd->tf_read_offset) tcp_reply_read (tcp_fd, tcp_fd->tf_read_offset); else tcp_reply_read (tcp_fd, tcp_conn->tc_error); return; } urg= tcp_Gmod4G(tcp_conn->tc_RCV_UP, tcp_conn->tc_RCV_LO); push= (tcp_conn->tc_flags & TCF_RCV_PUSH); fin_recv= (tcp_conn->tc_flags & TCF_FIN_RECV); data_size= tcp_conn->tc_RCV_NXT-tcp_conn->tc_RCV_LO; if (fin_recv) data_size--; if (urg) {#if DEBUG printf("tcp_fd_read: RCV_UP = 0x%x, RCV_LO = 0x%x\n", tcp_conn->tc_RCV_UP, tcp_conn->tc_RCV_LO);#endif read_size= tcp_conn->tc_RCV_UP-tcp_conn->tc_RCV_LO; } else read_size= data_size; if (read_size >= tcp_fd->tf_read_count) read_size= tcp_fd->tf_read_count; else if (!push && !fin_recv && !urg && data_size < TCP_MIN_RCV_WND_SIZE) { /* Defer the copy out until later. */ return; } else if (data_size == 0 && !fin_recv) { /* No data, and no end of file. */ return; } if (read_size) { if (urg && !(tcp_fd->tf_flags & TFF_RECV_URG)) { if (tcp_fd->tf_read_offset) { tcp_reply_read (tcp_fd, tcp_fd->tf_read_offset); } else { tcp_reply_read (tcp_fd, EURG); } return; } else if (!urg && (tcp_fd->tf_flags & TFF_RECV_URG)) { if (tcp_fd->tf_read_offset) { tcp_reply_read (tcp_fd, tcp_fd->tf_read_offset); } else { tcp_reply_read(tcp_fd, ENOURG); } return; } if (read_size == data_size) { data= tcp_conn->tc_rcvd_data; data->acc_linkC++; } else { data= bf_cut(tcp_conn->tc_rcvd_data, 0, read_size); } result= (*tcp_fd->tf_put_userdata) (tcp_fd->tf_srfd, tcp_fd->tf_read_offset, data, FALSE); if (result<0) { if (tcp_fd->tf_read_offset) tcp_reply_read(tcp_fd, tcp_fd-> tf_read_offset); else tcp_reply_read(tcp_fd, result); return; } tcp_fd->tf_read_offset += read_size; tcp_fd->tf_read_count -= read_size; if (data_size == read_size) { bf_afree(tcp_conn->tc_rcvd_data); tcp_conn->tc_rcvd_data= 0; } else { tcp_conn->tc_rcvd_data= bf_delhead(tcp_conn->tc_rcvd_data, read_size); } tcp_conn->tc_RCV_LO += read_size; data_size -= read_size; } /* Update IRS and often RCV_UP every 0.5GB */ if (tcp_conn->tc_RCV_LO - tcp_conn->tc_IRS > 0x40000000) { tcp_conn->tc_IRS += 0x20000000; DBLOCK(1, printf("tcp_fd_read: updating IRS to 0x%lx\n", (unsigned long)tcp_conn->tc_IRS);); if (tcp_Lmod4G(tcp_conn->tc_RCV_UP, tcp_conn->tc_IRS)) { tcp_conn->tc_RCV_UP= tcp_conn->tc_IRS; DBLOCK(1, printf( "tcp_fd_read: updating RCV_UP to 0x%lx\n", (unsigned long)tcp_conn->tc_RCV_UP);); } DBLOCK(1, printf("tcp_fd_read: RCP_LO = 0x%lx\n", (unsigned long)tcp_conn->tc_RCV_LO);); } mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE; if (tcp_conn->tc_RCV_HI-tcp_conn->tc_RCV_LO <= tcp_conn->tc_rcv_wnd-mss) { old_window= tcp_conn->tc_RCV_HI-tcp_conn->tc_RCV_NXT; tcp_conn->tc_RCV_HI= tcp_conn->tc_RCV_LO + tcp_conn->tc_rcv_wnd; new_window= tcp_conn->tc_RCV_HI-tcp_conn->tc_RCV_NXT; assert(old_window >=0 && new_window >= old_window); if (old_window < mss && new_window >= mss) { tcp_conn->tc_flags |= TCF_SEND_ACK; DBLOCK(2, printf("opening window\n")); tcp_conn_write(tcp_conn, 1); } } if (tcp_conn->tc_rcvd_data == NULL && tcp_conn->tc_adv_data == NULL) { /* Out of data, clear PUSH flag and reply to a read. */ tcp_conn->tc_flags &= ~TCF_RCV_PUSH; } if (fin_recv || urg || tcp_fd->tf_read_offset || !tcp_fd->tf_read_count) { tcp_reply_read (tcp_fd, tcp_fd->tf_read_offset); return; }}PUBLIC unsignedtcp_sel_read(tcp_conn)tcp_conn_t *tcp_conn;{ tcp_fd_t *tcp_fd; size_t data_size; int fin_recv, urg, push; tcp_fd= tcp_conn->tc_fd; if (tcp_conn->tc_state == TCS_CLOSED) return 1; fin_recv= (tcp_conn->tc_flags & TCF_FIN_RECV); if (fin_recv) return 1; data_size= tcp_conn->tc_RCV_NXT-tcp_conn->tc_RCV_LO; if (data_size == 0) { /* No data, and no end of file. */ return 0; } urg= tcp_Gmod4G(tcp_conn->tc_RCV_UP, tcp_conn->tc_RCV_LO); push= (tcp_conn->tc_flags & TCF_RCV_PUSH); if (!push && !urg && data_size < TCP_MIN_RCV_WND_SIZE) { /* Defer until later. */ return 0; } return 1;}PUBLIC voidtcp_rsel_read(tcp_conn)tcp_conn_t *tcp_conn;{ tcp_fd_t *tcp_fd; if (tcp_sel_read(tcp_conn) == 0) return; tcp_fd= tcp_conn->tc_fd; tcp_fd->tf_flags &= ~TFF_SEL_READ; if (tcp_fd->tf_select_res) tcp_fd->tf_select_res(tcp_fd->tf_srfd, SR_SELECT_READ); else printf("tcp_rsel_read: no select_res\n");}PUBLIC void tcp_bytesavailable(tcp_fd, bytesp)tcp_fd_t *tcp_fd;int *bytesp;{ tcp_conn_t *tcp_conn; size_t data_size, read_size; acc_t *data; int fin_recv, urg, push, result; i32_t old_window, new_window; u16_t mss; *bytesp= 0; /* The default is that nothing is available */ if (!(tcp_fd->tf_flags & TFF_CONNECTEDx)) return; tcp_conn= tcp_fd->tf_conn; if (tcp_conn->tc_state == TCS_CLOSED) return; urg= tcp_Gmod4G(tcp_conn->tc_RCV_UP, tcp_conn->tc_RCV_LO); push= (tcp_conn->tc_flags & TCF_RCV_PUSH); fin_recv= (tcp_conn->tc_flags & TCF_FIN_RECV); data_size= tcp_conn->tc_RCV_NXT-tcp_conn->tc_RCV_LO; if (fin_recv) data_size--; if (urg) data_size= tcp_conn->tc_RCV_UP-tcp_conn->tc_RCV_LO; if (urg && !(tcp_fd->tf_flags & TFF_RECV_URG)) return; else if (!urg && (tcp_fd->tf_flags & TFF_RECV_URG)) return; *bytesp= data_size;}/* * $PchId: tcp_recv.c,v 1.30 2005/06/28 14:21:35 philip Exp $ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -