📄 tcp_send.c
字号:
/*
tcp_send.c
*/
#include "inet.h"
#include "buf.h"
#include "clock.h"
#include "type.h"
#include "assert.h"
#include "ip.h"
#include "tcp.h"
#include "tcp_int.h"
INIT_PANIC();
#if DEBUG
#include "tcp_delay.h"
int tcp_delay_on;
u32_t tcp_delay;
#endif
#if DEBUG & 2
#define d_bufcut 1
#endif
FORWARD void write2port ARGS(( tcp_port_t *tcp_port,
acc_t *data ));
FORWARD void major_to ARGS(( int conn, struct timer *timer ));
FORWARD void minor_to ARGS(( int conn, struct timer *timer ));
FORWARD void ack_to ARGS(( int conn, struct timer *timer ));
FORWARD void time_wait_to ARGS(( int conn,
struct timer *timer ));
FORWARD acc_t *make_pack ARGS(( tcp_conn_t *tcp_conn ));
FORWARD void fd_write ARGS(( tcp_fd_t *tcp_fd ));
FORWARD void switch_write_fd ARGS(( tcp_conn_t *tcp_conn,
tcp_fd_t *new_fd, tcp_fd_t **ref_urgent_fd,
tcp_fd_t **ref_normal_fd, tcp_fd_t **ref_shutdown_fd ));
FORWARD void tcp_restart_write_conn ARGS (( tcp_conn_t *tcp_conn ));
#if DEBUG
FORWARD void tcp_delay_to ARGS(( int ref, timer_t *timer ));
#endif
PUBLIC void tcp_restart_write (tcp_conn)
tcp_conn_t *tcp_conn;
{
tcp_port_t *tcp_port;
#if DEBUG & 256
{ where(); printf("in tcp_restart_write\n"); }
#endif
assert (tcp_conn->tc_flags & TCF_INUSE);
tcp_conn->tc_flags |= TCF_MORE2WRITE;
#if DEBUG & 256
{ where(); printf("tcp_conn_table[%d].tc_flags= 0x%x\n",
tcp_conn-tcp_conn_table, tcp_conn->tc_flags); }
#endif
tcp_port= tcp_conn->tc_port;
tcp_port->tp_flags |= TPF_MORE2WRITE;
if (tcp_port->tp_flags & TPF_WRITE_IP)
return;
tcp_restart_write_port (tcp_port);
}
PUBLIC void tcp_restart_write_port (tcp_port)
tcp_port_t *tcp_port;
{
tcp_conn_t *tcp_conn, *hi_conn;
#if DEBUG & 256
{ where(); printf("in tcp_restart_write_port\n"); }
#endif
assert (tcp_port->tp_flags & TPF_MORE2WRITE);
assert (!(tcp_port->tp_flags & TPF_WRITE_IP));
while(tcp_port->tp_flags & TPF_MORE2WRITE)
{
tcp_port->tp_flags &= ~TPF_MORE2WRITE;
for (tcp_conn= tcp_conn_table, hi_conn=
&tcp_conn_table[TCP_CONN_NR]; tcp_conn<hi_conn;
tcp_conn++)
{
if ((tcp_conn->tc_flags & (TCF_INUSE|
TCF_MORE2WRITE)) != (TCF_INUSE|
TCF_MORE2WRITE))
continue;
if (tcp_conn->tc_port != tcp_port)
continue;
tcp_conn->tc_flags &= ~TCF_MORE2WRITE;
#if DEBUG & 256
{ where(); printf("tcp_conn_table[%d].tc_flags= 0x%x\n",
tcp_conn-tcp_conn_table, tcp_conn->tc_flags); }
#endif
#if DEBUG & 256
{ where(); printf("calling tcp_restart_write_conn(&tcp_conn_table[%d])\n",
tcp_conn - tcp_conn_table); }
#endif
tcp_restart_write_conn (tcp_conn);
if (tcp_port->tp_flags & TPF_WRITE_IP)
{
#if DEBUG & 256
{ where(); printf("setting TCF_MORE2WRITE because of TPF_WRITE_IP\n"); }
#endif
tcp_port->tp_flags |= TPF_MORE2WRITE;
return;
}
tcp_port->tp_flags |= TPF_MORE2WRITE;
}
}
}
PRIVATE void tcp_restart_write_conn (tcp_conn)
tcp_conn_t *tcp_conn;
{
ip_hdr_t *ip_hdr;
tcp_hdr_t *tcp_hdr;
acc_t *pack2write;
#if DEBUG & 256
{ where(); printf("in tcp_restart_write_conn\n"); }
#endif
assert (tcp_conn->tc_flags & TCF_INUSE);
if (tcp_conn->tc_port->tp_flags & TPF_WRITE_IP)
{
tcp_conn->tc_flags |= TCF_MORE2WRITE;
#if DEBUG & 16
{ where(); printf("tcp_conn_table[%d].tc_flags= 0x%x\n",
tcp_conn-tcp_conn_table, tcp_conn->tc_flags); }
#endif
tcp_conn->tc_port->tp_flags |= TPF_MORE2WRITE;
return;
}
if (tcp_conn->tc_frag2send)
{
pack2write= tcp_conn->tc_frag2send;
tcp_conn->tc_frag2send= 0;
#if DEBUG & 256
{ where(); printf("calling write2port\n"); }
#endif
write2port(tcp_conn->tc_port, pack2write);
if (tcp_conn->tc_port->tp_flags & TPF_WRITE_IP)
{
tcp_conn->tc_flags |= TCF_MORE2WRITE;
#if DEBUG & 16
{ where(); printf("tcp_conn_table[%d].tc_flags= 0x%x\n",
tcp_conn-tcp_conn_table, tcp_conn->tc_flags); }
#endif
tcp_conn->tc_port->tp_flags |= TPF_MORE2WRITE;
return;
}
}
if (tcp_conn->tc_state == TCS_CLOSED || tcp_conn->tc_state ==
TCS_LISTEN)
return;
if (tcp_conn->tc_no_retrans >
tcp_conn->tc_max_no_retrans)
{
#if DEBUG
{ where(); printf("calling tcp_close_connection\n"); }
#endif
tcp_close_connection(tcp_conn, ETIMEDOUT);
return;
}
while (pack2write= make_pack(tcp_conn))
{
/* if (tcp_conn->tc_state == TCS_CLOSED)
return; */ /* XXX Why is this? */
if (tcp_conn->tc_port->tp_flags & TPF_WRITE_IP)
{
tcp_conn->tc_frag2send= pack2write;
tcp_conn->tc_flags |= TCF_MORE2WRITE;
#if DEBUG & 16
{ where(); printf("tcp_conn_table[%d].tc_flags= 0x%x\n",
tcp_conn-tcp_conn_table, tcp_conn->tc_flags); }
#endif
tcp_conn->tc_port->tp_flags |= TPF_MORE2WRITE;
return;
}
write2port(tcp_conn->tc_port, pack2write);
if (tcp_conn->tc_port->tp_flags & TPF_WRITE_IP)
{
tcp_conn->tc_flags |= TCF_MORE2WRITE;
#if DEBUG & 16
{ where(); printf("tcp_conn_table[%d].tc_flags= 0x%x\n",
tcp_conn-tcp_conn_table, tcp_conn->tc_flags); }
#endif
tcp_conn->tc_port->tp_flags |= TPF_MORE2WRITE;
return;
}
}
}
PRIVATE acc_t *make_pack(tcp_conn)
tcp_conn_t *tcp_conn;
{
acc_t *pack2write, *tmp_pack;
tcp_hdr_t *tcp_hdr;
ip_hdr_t *ip_hdr;
int tot_hdr_size;
u32_t seg_seq, seg_lo_data, queue_lo_data, seg_hi, seg_hi_data;
u16_t seg_up;
u8_t seg_flags;
time_t new_dis;
size_t pack_size;
time_t major_timeout, minor_timeout;
#if DEBUG & 256
{ where(); printf("make_pack called\n"); }
#endif
switch (tcp_conn->tc_state)
{
case TCS_CLOSED:
return 0;
case TCS_SYN_RECEIVED:
case TCS_SYN_SENT:
if (tcp_conn->tc_SND_TRM == tcp_conn->tc_SND_NXT &&
!(tcp_conn->tc_flags & TCF_SEND_ACK))
{
#if DEBUG & 256
{ where(); printf("make_pack returned\n"); }
#endif
return 0;
}
major_timeout= 0;
tcp_conn->tc_flags &= ~TCF_SEND_ACK;
#if DEBUG & 256
{ where(); printf("tcp_conn_table[%d].tc_flags= 0x%x\n",
tcp_conn-tcp_conn_table, tcp_conn->tc_flags); }
#endif
pack2write= tcp_make_header(tcp_conn, &ip_hdr, &tcp_hdr,
(acc_t *)0);
if (!pack2write)
{
{ where(); printf("connection closed while inuse\n"); }
#if DEBUG
{ where(); printf("make_pack returned\n"); }
#endif
return 0;
}
tot_hdr_size= bf_bufsize(pack2write);
seg_seq= tcp_conn->tc_SND_TRM;
if (tcp_conn->tc_state == TCS_SYN_SENT)
seg_flags= 0;
else
seg_flags= THF_ACK; /* except for TCS_SYN_SENT
* ack is always present */
if (seg_seq == tcp_conn->tc_ISS)
{
seg_flags |= THF_SYN;
tcp_conn->tc_SND_TRM++;
if (!tcp_conn->tc_ett)
tcp_conn->tc_ett= get_time();
/* fill in estimated transmition time field */
major_timeout= get_time() + (tcp_conn->tc_rtt *
(tcp_conn->tc_no_retrans + 2));
}
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_mss);
/* Initially we allow one segment */
ip_hdr->ih_length= htons(tot_hdr_size);
tcp_hdr->th_chksum= ~tcp_pack_oneCsum(pack2write, tot_hdr_size);
new_dis= get_time() + 2*HZ*tcp_conn->tc_ttl;
if (new_dis > tcp_conn->tc_senddis)
tcp_conn->tc_senddis= new_dis;
if (major_timeout)
{
tcp_conn->tc_no_retrans++;
#if DEBUG & 256
{ where(); printf("setting major_to\n"); }
#endif
clck_timer(&tcp_conn->tc_major_timer,
major_timeout, major_to,
tcp_conn-tcp_conn_table);
}
if (tcp_conn->tc_flags & TCF_ACK_TIMER_SET)
{
tcp_conn->tc_flags &= ~TCF_ACK_TIMER_SET;
#if DEBUG & 16
{ where(); printf("tcp_conn_table[%d].tc_flags= 0x%x\n",
tcp_conn-tcp_conn_table, tcp_conn->tc_flags); }
#endif
clck_untimer(&tcp_conn->tc_ack_timer);
}
#if DEBUG & 256
{ where(); printf("make_pack returned\n"); }
#endif
return pack2write;
break;
case TCS_ESTABLISHED:
case TCS_FIN_WAIT_1:
case TCS_FIN_WAIT_2:
case TCS_CLOSE_WAIT:
case TCS_CLOSING:
case TCS_LAST_ACK:
case TCS_TIME_WAIT:
#if DEBUG & 256
{ where(); printf("SND_TRM= 0x%x, snd_cwnd= 0x%x\n", tcp_conn->tc_SND_TRM,
tcp_conn->tc_snd_cwnd); }
#endif
assert (tcp_LEmod4G(tcp_conn->tc_SND_TRM, tcp_conn->tc_snd_cwnd));
assert (tcp_LEmod4G(tcp_conn->tc_SND_TRM, tcp_conn->tc_SND_NXT));
if ((tcp_conn->tc_SND_TRM == tcp_conn->tc_snd_cwnd ||
tcp_conn->tc_SND_TRM == tcp_conn->tc_SND_NXT) &&
!(tcp_conn->tc_flags & TCF_SEND_ACK))
{
#if DEBUG & 256
{ where(); printf("nothing to do\n"); }
#endif
#if DEBUG & 256
{ where(); printf("make_pack returned\n"); }
#endif
return 0;
}
major_timeout= 0;
tcp_conn->tc_flags &= ~TCF_SEND_ACK;
#if DEBUG & 256
{ where(); printf("tcp_conn_table[%d].tc_flags= 0x%x\n",
tcp_conn-tcp_conn_table, tcp_conn->tc_flags); }
#endif
pack2write= tcp_make_header (tcp_conn, &ip_hdr,
&tcp_hdr, (acc_t *)0);
if (!pack2write)
{
{ where(); printf("connection closed while inuse\n"); }
#if DEBUG
{ where(); printf("make_pack returned\n"); }
#endif
return 0;
}
bf_chkbuf(pack2write);
tot_hdr_size= bf_bufsize(pack2write);
seg_seq= tcp_conn->tc_SND_TRM;
seg_flags= THF_ACK;
assert(tcp_Gmod4G(seg_seq, tcp_conn->tc_ISS));
seg_lo_data= seg_seq;
queue_lo_data= tcp_conn->tc_SND_UNA;
assert(tcp_Gmod4G(queue_lo_data, tcp_conn->tc_ISS));
assert (tcp_check_conn(tcp_conn));
seg_hi= tcp_conn->tc_SND_NXT;
seg_hi_data= seg_hi;
if (tcp_conn->tc_flags & TCF_FIN_SENT)
{
#if DEBUG & 256
{ where(); printf("Setting FIN flags\n"); }
#endif
if (seg_seq != seg_hi)
seg_flags |= THF_FIN;
if (queue_lo_data == seg_hi_data)
queue_lo_data--;
if (seg_lo_data == seg_hi_data)
seg_lo_data--;
seg_hi_data--;
}
if (seg_hi_data - seg_lo_data > tcp_conn->tc_mss -
tot_hdr_size)
{
seg_hi_data= seg_lo_data + tcp_conn->tc_mss -
tot_hdr_size;
seg_hi= seg_hi_data;
#if DEBUG & 256
{ where(); printf("Clearing FIN flags\n"); }
#endif
seg_flags &= ~THF_FIN;
}
if (tcp_Gmod4G(seg_hi_data, tcp_conn->tc_snd_cwnd))
{
seg_hi_data= tcp_conn->tc_snd_cwnd;
seg_hi= seg_hi_data;
#if DEBUG & 256
{ where(); printf("Clearing FIN flags\n"); }
#endif
seg_flags &= ~THF_FIN;
}
if (tcp_Gmod4G(tcp_conn->tc_SND_UP, seg_lo_data) &&
tcp_LEmod4G(tcp_conn->tc_SND_UP, seg_hi_data))
{
seg_up= tcp_conn->tc_SND_UP-seg_seq;
seg_flags |= THF_URG;
#if DEBUG
{ where(); printf("seg_up= %d\n", seg_up); }
#endif
}
if (tcp_Gmod4G(tcp_conn->tc_SND_PSH, seg_lo_data) &&
tcp_LEmod4G(tcp_conn->tc_SND_PSH, seg_hi_data))
{
seg_flags |= THF_PSH;
}
tcp_conn->tc_SND_TRM= seg_hi;
if (seg_hi-seg_seq)
{
if (!tcp_conn->tc_ett)
tcp_conn->tc_ett= get_time();
if (seg_seq == tcp_conn->tc_SND_UNA)
major_timeout= get_time() + (tcp_conn->tc_rtt *
(tcp_conn->tc_no_retrans + 1));
}
if (seg_hi_data-seg_lo_data)
{
tmp_pack= pack2write;
while (tmp_pack->acc_next)
tmp_pack= tmp_pack->acc_next;
assert (tcp_check_conn(tcp_conn));
bf_chkbuf(pack2write);
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));
bf_chkbuf(pack2write);
}
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);
bf_chkbuf(pack2write);
tcp_hdr->th_chksum= ~tcp_pack_oneCsum(pack2write,
pack_size);
bf_chkbuf(pack2write);
new_dis= get_time() + 2*HZ*tcp_conn->tc_ttl;
if (new_dis > tcp_conn->tc_senddis)
tcp_conn->tc_senddis= new_dis;
bf_chkbuf(pack2write);
if (major_timeout)
{
tcp_conn->tc_no_retrans++;
#if DEBUG & 256
{ where(); printf("setting major_to\n"); }
#endif
clck_timer(&tcp_conn->tc_major_timer,
major_timeout,
major_to, tcp_conn-tcp_conn_table);
}
if (tcp_conn->tc_flags & TCF_ACK_TIMER_SET)
{
tcp_conn->tc_flags &= ~TCF_ACK_TIMER_SET;
#if DEBUG & 256
{ where(); printf("tcp_conn_table[%d].tc_flags= 0x%x\n",
tcp_conn-tcp_conn_table, tcp_conn->tc_flags); }
#endif
clck_untimer(&tcp_conn->tc_ack_timer);
}
#if DEBUG & 256
{ where(); printf("make_pack returned\n"); }
#endif
return pack2write;
default:
#if DEBUG
{ where(); printf("tcp_conn_table[%d].tc_state= %d\n", tcp_conn-tcp_conn_table,
tcp_conn->tc_state); }
#endif
ip_panic(( "Illegal state" ));
}
#if DEBUG
{ where(); printf("make_pack returned\n"); }
#endif
}
PRIVATE void write2port(tcp_port, data)
tcp_port_t *tcp_port;
acc_t *data;
{
int result;
#if DEBUG & 256
{ where(); printf("in write2port\n"); }
#endif
assert (!(tcp_port->tp_flags & TPF_WRITE_IP));
tcp_port->tp_flags |= TPF_WRITE_IP;
tcp_port->tp_pack= data;
bf_chkbuf(data);
#if DEBUG
if (tcp_delay_on)
{
if (tcp_port->tp_flags & TPF_DELAY_TCP)
tcp_port->tp_flags &= ~TPF_DELAY_TCP;
else
{
tcp_port->tp_flags |= TPF_WRITE_SP;
clck_timer(&tcp_port->tp_delay_tim,
get_time() + tcp_delay,
tcp_delay_to, tcp_port-
tcp_port_table);
return;
}
}
#endif
result= ip_write (tcp_port->tp_ipfd, bf_bufsize(data));
if (result == NW_SUSPEND)
{
tcp_port->tp_flags |= TPF_WRITE_SP;
return;
}
assert(result == NW_OK);
tcp_port->tp_flags &= ~TPF_WRITE_IP;
assert(!(tcp_port->tp_flags & (TPF_WRITE_IP|TPF_WRITE_SP)));
}
PRIVATE void major_to(conn, timer)
int conn;
struct timer *timer;
{
tcp_conn_t *tcp_conn;
u16_t mss, mss2;
#if DEBUG & 256
{ where(); printf("in major_to\n"); }
#endif
tcp_conn= &tcp_conn_table[conn];
#if DEBUG & 256
{ where(); printf("major_to: snd_cwnd-SND_UNA= %lu, no_retrans: %d snd_cthresh= %d\n",
tcp_conn->tc_snd_cwnd-tcp_conn->tc_SND_UNA, tcp_conn->tc_no_retrans,
tcp_conn->tc_snd_cthresh); }
#endif
assert(tcp_conn->tc_flags & TCF_INUSE);
assert(tcp_conn->tc_state != TCS_CLOSED &&
tcp_conn->tc_state != TCS_LISTEN);
clck_untimer(&tcp_conn->tc_minor_timer);
tcp_conn->tc_SND_TRM= tcp_conn->tc_SND_UNA;
mss= tcp_conn->tc_mss;
mss2= 2*mss;
tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_TRM + mss2;
#if DEBUG & 256
{ where(); printf("snd_cwnd is now %d\n", tcp_conn->tc_snd_cwnd); }
#endif
tcp_conn->tc_snd_cthresh /= 2;
if (tcp_conn->tc_snd_cthresh < mss2)
tcp_conn->tc_snd_cthresh= mss2;
tcp_conn->tc_snd_cinc= ((unsigned long)mss*mss)/tcp_conn->
tc_snd_cthresh;
tcp_restart_write(tcp_conn);
}
PRIVATE void minor_to(conn, timer)
int conn;
struct timer *timer;
{
tcp_conn_t *tcp_conn;
#if DEBUG
{ where(); printf("in minor_to\n"); }
#endif
tcp_conn= &tcp_conn_table[conn];
assert(tcp_conn->tc_flags & TCF_INUSE);
assert(tcp_conn->tc_state != TCS_CLOSED &&
tcp_conn->tc_state != TCS_LISTEN);
tcp_restart_write(tcp_conn);
}
PUBLIC void tcp_release_retrans(tcp_conn, seg_ack, new_win)
tcp_conn_t *tcp_conn;
u32_t seg_ack;
u16_t new_win;
{
size_t size, offset;
acc_t *old_pack, *new_pack;
time_t retrans_time, curr_time;
u32_t queue_lo, queue_hi;
u16_t cwnd, incr, mss, mss2, cthresh;
#if DEBUG & 256
{ where(); printf("in release_retrans(&tcp_conn_table[%d], 0x%x, %d)\n",
tcp_conn-tcp_conn_table, seg_ack, new_win); }
#endif
assert (tcp_GEmod4G(seg_ack, tcp_conn->tc_SND_UNA));
assert (tcp_LEmod4G(seg_ack, tcp_conn->tc_SND_NXT));
if (tcp_Gmod4G(seg_ack, tcp_conn->tc_SND_UNA))
{
tcp_conn->tc_no_retrans= 0;
curr_time= get_time();
if (curr_time < tcp_conn->tc_ett)
retrans_time= 0;
else
retrans_time= curr_time-tcp_conn->tc_ett;
if (tcp_conn->tc_rtt*2 < retrans_time)
{
tcp_conn->tc_rtt *= 2;
assert (tcp_conn->tc_rtt);
}
else if (tcp_conn->tc_rtt > retrans_time*2)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -