📄 tcp_send.c
字号:
tmp_pack->acc_next= bf_cut(tcp_conn->tc_send_data, (unsigned)(seg_lo_data-queue_lo_data), (unsigned) (seg_hi_data-seg_lo_data)); } seg_flags |= THF_ACK; }after_data: if (!(seg_flags & THF_ACK)) { if (pack2write) bf_afree(pack2write); return NULL; } tcp_hdr->th_seq_nr= htonl(seg_seq); tcp_hdr->th_ack_nr= htonl(tcp_conn->tc_RCV_NXT); tcp_hdr->th_flags= seg_flags; tcp_hdr->th_window= htons(tcp_conn->tc_RCV_HI - tcp_conn->tc_RCV_NXT); tcp_hdr->th_urgptr= htons(seg_up); pack_size= bf_bufsize(pack2write); ip_hdr->ih_length= htons(pack_size); pack2write->acc_linkC++; ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2; tcp_pack= bf_delhead(pack2write, ip_hdr_len); tcp_hdr->th_chksum= ~tcp_pack_oneCsum(ip_hdr, tcp_pack); bf_afree(tcp_pack); new_dis= curr_time + 2*HZ*tcp_conn->tc_ttl; if (new_dis > tcp_conn->tc_senddis) tcp_conn->tc_senddis= new_dis; return pack2write; default: DBLOCK(1, tcp_print_conn(tcp_conn); printf("\n")); ip_panic(( "Illegal state" )); } assert(0); return NULL;}/*tcp_release_retrans*/PUBLIC void tcp_release_retrans(tcp_conn, seg_ack, new_win)tcp_conn_t *tcp_conn;u32_t seg_ack;u16_t new_win;{ tcp_fd_t *tcp_fd; size_t size, offset; acc_t *pack; clock_t retrans_time, curr_time, rtt, artt, drtt, srtt; u32_t queue_lo, queue_hi; u16_t mss, cthresh; unsigned window; DBLOCK(0x10, printf("tcp_release_retrans, conn[%d]: ack %lu, win %u\n", tcp_conn-tcp_conn_table, (unsigned long)seg_ack, new_win);); assert(tcp_conn->tc_busy); assert (tcp_GEmod4G(seg_ack, tcp_conn->tc_SND_UNA)); assert (tcp_LEmod4G(seg_ack, tcp_conn->tc_SND_NXT)); tcp_conn->tc_snd_dack= 0; mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE; curr_time= get_time(); if (tcp_conn->tc_rt_seq != 0 && tcp_Gmod4G(seg_ack, tcp_conn->tc_rt_seq)) { assert(curr_time >= tcp_conn->tc_rt_time); retrans_time= curr_time-tcp_conn->tc_rt_time; rtt= tcp_conn->tc_rtt; tcp_conn->tc_rt_seq= 0; if (rtt == TCP_RTT_GRAN*CLOCK_GRAN && retrans_time <= TCP_RTT_GRAN*CLOCK_GRAN) { /* Common in fast networks. Nothing to do. */ } else { srtt= retrans_time * TCP_RTT_SCALE; artt= tcp_conn->tc_artt; artt= ((TCP_RTT_SMOOTH-1)*artt+srtt)/TCP_RTT_SMOOTH; srtt -= artt; if (srtt < 0) srtt= -srtt; drtt= tcp_conn->tc_drtt; drtt= ((TCP_RTT_SMOOTH-1)*drtt+srtt)/TCP_RTT_SMOOTH; rtt= (artt+TCP_DRTT_MULT*drtt-1)/TCP_RTT_SCALE+1; if (rtt < TCP_RTT_GRAN*CLOCK_GRAN) { rtt= TCP_RTT_GRAN*CLOCK_GRAN; } else if (rtt > TCP_RTT_MAX) {#if DEBUG static int warned /* = 0 */; if (!warned) { printf("tcp_release_retrans: warning retransmission time is limited to %d ms\n", TCP_RTT_MAX*1000/HZ); warned= 1; }#endif rtt= TCP_RTT_MAX; } DBLOCK(0x10, printf( "tcp_release_retrans, conn[%d]: retrans_time= %ld ms, rtt = %ld ms\n", tcp_conn-tcp_conn_table, retrans_time*1000/HZ, rtt*1000/HZ)); DBLOCK(0x10, printf( "tcp_release_retrans: artt= %ld -> %ld, drtt= %ld -> %ld\n", tcp_conn->tc_artt, artt, tcp_conn->tc_drtt, drtt)); tcp_conn->tc_artt= artt; tcp_conn->tc_drtt= drtt; tcp_conn->tc_rtt= rtt; } if (tcp_conn->tc_mtu != tcp_conn->tc_max_mtu && curr_time > tcp_conn->tc_mtutim+TCP_PMTU_INCR_IV) { tcp_mtu_incr(tcp_conn); } } /* Update the current window. */ window= tcp_conn->tc_snd_cwnd-tcp_conn->tc_SND_UNA; assert(seg_ack != tcp_conn->tc_SND_UNA); /* For every real ACK we try to increase the current window * with 1 mss. */ window += mss; /* If the window becomes larger than the current threshold, * increment the threshold by a small amount and set the * window to the threshold. */ cthresh= tcp_conn->tc_snd_cthresh; if (window > cthresh) { cthresh += tcp_conn->tc_snd_cinc; tcp_conn->tc_snd_cthresh= cthresh; window= cthresh; } /* If the window is larger than the window advertised by the * receiver, set the window size to the advertisement. */ if (window > new_win) window= new_win; tcp_conn->tc_snd_cwnd= seg_ack+window; /* Release data queued for retransmissions. */ queue_lo= tcp_conn->tc_SND_UNA; queue_hi= tcp_conn->tc_SND_NXT; tcp_conn->tc_SND_UNA= seg_ack; if (tcp_Lmod4G(tcp_conn->tc_SND_TRM, seg_ack)) { tcp_conn->tc_SND_TRM= seg_ack; } assert(tcp_GEmod4G(tcp_conn->tc_snd_cwnd, seg_ack)); /* Advance ISS every 0.5GB to avoid problem with wrap around */ if (tcp_conn->tc_SND_UNA - tcp_conn->tc_ISS > 0x40000000) { tcp_conn->tc_ISS += 0x20000000; DBLOCK(1, printf( "tcp_release_retrans: updating ISS to 0x%lx\n", (unsigned long)tcp_conn->tc_ISS);); if (tcp_Lmod4G(tcp_conn->tc_SND_UP, tcp_conn->tc_ISS)) { tcp_conn->tc_SND_UP= tcp_conn->tc_ISS; DBLOCK(1, printf( "tcp_release_retrans: updating SND_UP to 0x%lx\n", (unsigned long)tcp_conn->tc_SND_UP);); } } if (queue_lo == tcp_conn->tc_ISS) queue_lo++; if (tcp_conn->tc_flags & TCF_FIN_SENT) { if (seg_ack == queue_hi) seg_ack--; if (queue_lo == queue_hi) queue_lo--; queue_hi--; } offset= seg_ack - queue_lo; size= queue_hi - seg_ack; pack= tcp_conn->tc_send_data; tcp_conn->tc_send_data= 0; if (!size) { bf_afree(pack); } else { pack= bf_delhead(pack, offset); tcp_conn->tc_send_data= pack; } if (tcp_Gmod4G(tcp_conn->tc_SND_TRM, tcp_conn->tc_snd_cwnd)) tcp_conn->tc_SND_TRM= tcp_conn->tc_snd_cwnd; /* Copy in new data if an ioctl is pending or if a write request is * pending and either the write can be completed or at least one * mss buffer space is available. */ tcp_fd= tcp_conn->tc_fd; if (tcp_fd) { if (tcp_fd->tf_flags & TFF_IOCTL_IP) { tcp_fd_write(tcp_conn); } if ((tcp_fd->tf_flags & TFF_WRITE_IP) && (size+tcp_fd->tf_write_count <= TCP_MAX_SND_WND_SIZE || size <= TCP_MAX_SND_WND_SIZE-mss)) { tcp_fd_write(tcp_conn); } if (tcp_fd->tf_flags & TFF_SEL_WRITE) tcp_rsel_write(tcp_conn); } else { if (tcp_conn->tc_SND_UNA == tcp_conn->tc_SND_NXT) { assert(tcp_conn->tc_state == TCS_CLOSING); DBLOCK(0x10, printf("all data sent in abondoned connection\n")); tcp_close_connection(tcp_conn, ENOTCONN); return; } } if (!size && !tcp_conn->tc_send_data) { /* Reset window if a write is completed */ tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_UNA + mss; } DIFBLOCK(2, (tcp_conn->tc_snd_cwnd == tcp_conn->tc_SND_TRM), printf("not sending: zero window\n")); if (tcp_conn->tc_snd_cwnd != tcp_conn->tc_SND_TRM && tcp_conn->tc_SND_NXT != tcp_conn->tc_SND_TRM) { tcp_conn_write(tcp_conn, 1); }}/*tcp_fast_retrans*/PUBLIC void tcp_fast_retrans(tcp_conn)tcp_conn_t *tcp_conn;{ u16_t mss, mss2; /* Update threshold sequence number for retransmission calculation. */ if (tcp_Gmod4G(tcp_conn->tc_SND_TRM, tcp_conn->tc_rt_threshold)) tcp_conn->tc_rt_threshold= tcp_conn->tc_SND_TRM; tcp_conn->tc_SND_TRM= tcp_conn->tc_SND_UNA; mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE; mss2= 2*mss; if (tcp_conn->tc_snd_cwnd == tcp_conn->tc_SND_UNA) tcp_conn->tc_snd_cwnd++; if (tcp_Gmod4G(tcp_conn->tc_snd_cwnd, tcp_conn->tc_SND_UNA + mss2)) { tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_UNA + mss2; if (tcp_Gmod4G(tcp_conn->tc_SND_TRM, tcp_conn->tc_snd_cwnd)) tcp_conn->tc_SND_TRM= tcp_conn->tc_snd_cwnd; tcp_conn->tc_snd_cthresh /= 2; if (tcp_conn->tc_snd_cthresh < mss2) tcp_conn->tc_snd_cthresh= mss2; } tcp_conn_write(tcp_conn, 1);}#if 0PUBLIC void do_tcp_timeout(tcp_conn)tcp_conn_t *tcp_conn;{ tcp_send_timeout(tcp_conn-tcp_conn_table, &tcp_conn->tc_transmit_timer);}#endif/*tcp_send_timeout*/PRIVATE void tcp_send_timeout(conn, timer)int conn;struct timer *timer;{ tcp_conn_t *tcp_conn; u16_t mss, mss2; u32_t snd_una, snd_nxt; clock_t curr_time, rtt, stt, timeout; acc_t *pkt; int new_ttl, no_push; DBLOCK(0x20, printf("tcp_send_timeout: conn[%d]\n", conn)); curr_time= get_time(); tcp_conn= &tcp_conn_table[conn]; assert(tcp_conn->tc_flags & TCF_INUSE); assert(tcp_conn->tc_state != TCS_CLOSED); assert(tcp_conn->tc_state != TCS_LISTEN); snd_una= tcp_conn->tc_SND_UNA; snd_nxt= tcp_conn->tc_SND_NXT; no_push= (tcp_conn->tc_flags & TCF_NO_PUSH); if (snd_nxt == snd_una || no_push) { /* Nothing more to send */ assert(tcp_conn->tc_SND_TRM == snd_una || no_push); /* A new write sets the timer if tc_transmit_seq == SND_UNA */ tcp_conn->tc_transmit_seq= tcp_conn->tc_SND_UNA; tcp_conn->tc_stt= 0; tcp_conn->tc_0wnd_to= 0; assert(!tcp_conn->tc_fd || !(tcp_conn->tc_fd->tf_flags & TFF_WRITE_IP) || (tcp_print_conn(tcp_conn), printf("\n"), 0)); if (snd_nxt != snd_una) { assert(no_push); DBLOCK(1, printf("not setting keepalive timer\n");); /* No point in setting the keepalive timer if we * still have to send more data. */ return; } assert(tcp_conn->tc_send_data == NULL); DBLOCK(0x20, printf("keep alive timer\n")); if (tcp_conn->tc_ka_snd != tcp_conn->tc_SND_NXT || tcp_conn->tc_ka_rcv != tcp_conn->tc_RCV_NXT) { tcp_conn->tc_ka_snd= tcp_conn->tc_SND_NXT; tcp_conn->tc_ka_rcv= tcp_conn->tc_RCV_NXT; DBLOCK(0x20, printf("tcp_send_timeout: conn[%d] setting keepalive timer (+%ld ms)\n", tcp_conn-tcp_conn_table, tcp_conn->tc_ka_time*1000/HZ)); clck_timer(&tcp_conn->tc_transmit_timer, curr_time+tcp_conn->tc_ka_time, tcp_send_timeout, tcp_conn-tcp_conn_table); return; } DBLOCK(0x10, printf( "tcp_send_timeout, conn[%d]: triggering keep alive probe\n", tcp_conn-tcp_conn_table)); tcp_conn->tc_ka_snd--; if (!(tcp_conn->tc_flags & TCF_FIN_SENT)) { pkt= bf_memreq(1); *ptr2acc_data(pkt)= '\xff'; /* a random char */ tcp_conn->tc_send_data= pkt; pkt= NULL; } tcp_conn->tc_SND_UNA--; if (tcp_conn->tc_SND_UNA == tcp_conn->tc_ISS) { /* We didn't send anything so far. Retrying the * SYN is too hard. Decrement ISS and hope * that the other side doesn't care. */ tcp_conn->tc_ISS--; } /* Set tc_transmit_seq and tc_stt to trigger packet */ tcp_conn->tc_transmit_seq= tcp_conn->tc_SND_UNA; tcp_conn->tc_stt= curr_time; /* Set tc_rt_seq for round trip measurements */ tcp_conn->tc_rt_time= curr_time; tcp_conn->tc_rt_seq= tcp_conn->tc_SND_UNA; /* Set PSH to make sure that data gets sent */ tcp_conn->tc_SND_PSH= tcp_conn->tc_SND_NXT; assert(tcp_check_conn(tcp_conn)); /* Fall through */ } rtt= tcp_conn->tc_rtt; if (tcp_conn->tc_transmit_seq != tcp_conn->tc_SND_UNA) { /* Some data has been acknowledged since the last time the * timer was set, set the timer again. */ tcp_conn->tc_transmit_seq= tcp_conn->tc_SND_UNA; tcp_conn->tc_stt= 0; tcp_conn->tc_0wnd_to= 0; DBLOCK(0x20, printf( "tcp_send_timeout: conn[%d] setting timer to %ld ms (+%ld ms)\n", tcp_conn-tcp_conn_table, (curr_time+rtt)*1000/HZ, rtt*1000/HZ)); clck_timer(&tcp_conn->tc_transmit_timer, curr_time+rtt, tcp_send_timeout, tcp_conn-tcp_conn_table); return; } stt= tcp_conn->tc_stt; if (stt == 0) { /* Some packet arrived but did not acknowledge any data. * Apparently, the other side is still alive and has a * reason to transmit. We can asume a zero window. */ DBLOCK(0x10, printf("conn[%d] setting zero window timer\n", tcp_conn-tcp_conn_table)); if (tcp_conn->tc_0wnd_to < TCP_0WND_MIN) tcp_conn->tc_0wnd_to= TCP_0WND_MIN; else if (tcp_conn->tc_0wnd_to < rtt) tcp_conn->tc_0wnd_to= rtt; else { tcp_conn->tc_0wnd_to *= 2; if (tcp_conn->tc_0wnd_to > TCP_0WND_MAX) tcp_conn->tc_0wnd_to= TCP_0WND_MAX; } tcp_conn->tc_stt= curr_time; tcp_conn->tc_rt_seq= 0; DBLOCK(0x10, printf( "tcp_send_timeout: conn[%d] setting timer to %ld ms (+%ld ms)\n", tcp_conn-tcp_conn_table, (curr_time+tcp_conn->tc_0wnd_to)*1000/HZ, tcp_conn->tc_0wnd_to*1000/HZ)); clck_timer(&tcp_conn->tc_transmit_timer, curr_time+tcp_conn->tc_0wnd_to, tcp_send_timeout, tcp_conn-tcp_conn_table); return; } assert(stt <= curr_time);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -