Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize window update logic #108

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/pcbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ size_t W32_CALL sock_setbuf (sock_type *s, BYTE *rx_buf, size_t rx_len)
}
else
{
size_t len = min (rx_len, USHRT_MAX-1) - 8;
size_t len = min (rx_len, 2 * USHRT_MAX) - 8;

*(DWORD*)rx_buf = SAFETY_TCP;
*(DWORD*)(rx_buf+4+len) = SAFETY_TCP;
Expand Down
84 changes: 45 additions & 39 deletions src/pctcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ W32_CLANG_PACK_WARN_DEF()

static void tcp_no_arp (_tcp_Socket *s);
static void tcp_rtt_win (_tcp_Socket *s);
static void tcp_upd_win (_tcp_Socket *s, unsigned line);
static BOOL tcp_checksum (const in_Header *ip, const tcp_Header *tcp, int len);
#endif

Expand Down Expand Up @@ -826,8 +825,7 @@ _tcp_Socket *_tcp_handler (const in_Header *ip, BOOL broadcast)
}

if (flags & tcp_FlagPUSH) /* EE 2002.2.28 */
s->locflags |= LF_GOT_PUSH;
else s->locflags &= ~LF_GOT_PUSH;
s->locflags |= LF_GOT_PUSH;

tcp_rtt_win (s); /* update retrans timer, windows etc. */

Expand Down Expand Up @@ -1273,17 +1271,6 @@ void tcp_Retransmitter (BOOL force)
continue;
}

/* Need to send a window update? Because we advertised a 0 window
* in a previous _tcp_send() (but only in ESTAB state).
*/
if ((s->locflags & LF_WINUPDATE) && sock_rbleft((sock_type*)s) > 0)
{
STAT (tcpstats.tcps_sndwinup++);
s->locflags &= ~LF_WINUPDATE;
s->flags |= tcp_FlagACK;
TCP_SEND (s);
}

else if (s->tx_datalen > 0 || s->unhappy || s->karn_count == 1)
{
if (chk_timeout(s->rtt_time)) /* retransmission timeout */
Expand Down Expand Up @@ -1835,22 +1822,37 @@ static int tcp_read (_tcp_Socket *s, BYTE *buf, int maxlen)
{
int to_move;

s->rx_datalen -= len;

if (s->recv_win < (long)s->adv_win)
{
/* ACK every second segment, or when PUSH received.
*/
if (s->adv_win - s->recv_win > s->max_seg ||
(s->locflags & LF_GOT_PUSH))
TCP_SEND (s);
else
TCP_SENDSOON (s);
}
else if (s->rx_datalen == 0 &&
s->recv_win <= 2 * s->max_seg)
{
/* Update window now if it was (nearly) closed.
*/
TCP_SEND (s);
}

s->locflags &= ~LF_GOT_PUSH;

if (buf)
memcpy (buf, s->rx_data, len);
s->rx_datalen -= len;

to_move = s->rx_datalen;
if (s->missed_seq[0] != s->missed_seq[1])
to_move += s->missed_seq[1] - s->recv_next;

if (to_move > 0)
{
memmove (s->rx_data, s->rx_data + len, to_move);

TCP_SENDSOON (s); /* delayed ACK */
}
else
tcp_upd_win (s, __LINE__);
memmove (s->rx_data, s->rx_data + len, to_move);
}
else if (s->state == tcp_StateCLOSWT)
_tcp_close (s);
Expand Down Expand Up @@ -1981,7 +1983,7 @@ static void tcp_sockreset (_tcp_Socket *s, BOOL proxy)
s->unhappy = FALSE;
s->hisport = 0;
s->hisaddr = 0UL;
s->locflags &= ~(LF_WINUPDATE | LF_KEEPALIVE | LF_GOT_FIN | LF_GOT_ICMP);
s->locflags &= ~(LF_KEEPALIVE | LF_GOT_FIN | LF_GOT_ICMP);

s->datatimer = 0UL;
s->inactive_to = 0;
Expand Down Expand Up @@ -2145,20 +2147,6 @@ static void tcp_rtt_win (_tcp_Socket *s)
s->datatimer = 0UL; /* resetting tx-timer, EE 99.08.23 */
}

/**
* Check if receive window needs an update.
*/
static void tcp_upd_win (_tcp_Socket *s, unsigned line)
{
UINT winfree = s->max_rx_data - (UINT)s->rx_datalen;

if (winfree < s->max_seg/2)
{
_tcp_send (s, __FILE__, line); /* update window now */
TRACE_CONSOLE (2, "tcp_upd_win(%d): win-free %u\n", line, winfree);
}
}

/**
* TCP option routines.
* \note Each of these \b MUST add multiple of 4 bytes of options.
Expand Down Expand Up @@ -2364,10 +2352,29 @@ int _tcp_send (_tcp_Socket *s, const char *file, unsigned line)
int opt_len; /* total length of TCP options */
int pkt_num; /* 0 .. s->cwindow-1 */
int rtt;
int new_window;

s->recent = 0;
dst = (_pktserial ? NULL : &s->his_ethaddr);

new_window = s->max_rx_data - s->rx_datalen;
if (s->max_rx_data >= s->max_seg * 4)
{
/* For large buffers, use half the buffer size, and round to a
* multiple of MSS. Only update if the difference is at least
* one segment (recommended by RFC 1122).
*/
new_window = min (new_window, s->max_rx_data / 2);
if (new_window > s->max_seg)
{
if (new_window - s->recv_win >= s->max_seg)
new_window -= new_window % s->max_seg;
else
new_window = s->recv_win;
}
}
s->adv_win = s->recv_win = new_window;

#if defined(USE_IPV6)
if (s->is_ip6)
{
Expand Down Expand Up @@ -2425,7 +2432,6 @@ int _tcp_send (_tcp_Socket *s, const char *file, unsigned line)
tcp->seqnum = intel (s->send_next + start_data); /* unacked - no longer send_tot_len */
tcp->acknum = intel (s->recv_next);

s->adv_win = s->max_rx_data - s->rx_datalen; /* Our new advertised recv window */
tcp->window = intel16 ((WORD)s->adv_win);
tcp->flags = (BYTE) (s->flags & ~tcp_FlagPUSH);
tcp->unused = 0;
Expand Down Expand Up @@ -2461,7 +2467,7 @@ int _tcp_send (_tcp_Socket *s, const char *file, unsigned line)
memcpy (data, s->tx_queue+start_data, send_data_len);
else memcpy (data, s->tx_data +start_data, send_data_len);

if (send_data_len == send_tot_data &&
if ((unsigned)start_data + send_data_len == s->tx_datalen &&
(s->flags & tcp_FlagPUSH))
{
/* Set PUSH bit on last segment.
Expand Down
2 changes: 1 addition & 1 deletion src/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ BOOL _sock_dos_fd (int s)
*/
int _sock_set_rcv_buf (sock_type *s, size_t len)
{
len = min (len+8,USHRT_MAX); /* add room for head/tail markers */
len = 2 * min (len, USHRT_MAX) + 8; /* add room for head/tail markers */
return sock_setbuf (s, (BYTE*)malloc(len), len);

/* Note: the ret-val from above malloc() is freed below.
Expand Down
90 changes: 45 additions & 45 deletions src/tcp_fsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ static int tcp_estab_state (_tcp_Socket **sp, const in_Header *ip,
_tcp_Socket *s = *sp;
int len;
long ldiff; /* how much still ACK'ed */
BOOL did_tx;
BOOL ack_scheduled = s->recv_win < (int)s->adv_win;

/* handle lost SYN
*/
Expand Down Expand Up @@ -364,13 +364,21 @@ static int tcp_estab_state (_tcp_Socket **sp, const in_Header *ip,
len = intel16 (ip->length) - in_GetHdrLen (ip);
else len = intel16 (ip6->len);

if (tcp_process_data (s, tcp, len, &flags) < 0)
len = tcp_process_data (s, tcp, len, &flags);
if (len < 0)
{
TCP_SEND (s); /* An out-of-order or missing segment; do fast ACK */
/* An out-of-order or missing segment; do fast ACK.
* Three should be enough. If those get dropped,
* retransmitter will send more eventually.
*/
if (s->dup_acks < 3)
{
TCP_SEND (s);
++s->dup_acks;
}
return (1);
}

did_tx = FALSE;
s->dup_acks = 0;

if (s->state != tcp_StateCLOSWT &&
(flags & tcp_FlagFIN) &&
Expand All @@ -385,7 +393,6 @@ static int tcp_estab_state (_tcp_Socket **sp, const in_Header *ip,
/* Implied CLOSE-WAIT -> LAST-ACK transition here
*/
TCP_SEND (s);
did_tx = TRUE;

TRACE_CONSOLE (2, "tcp_estab_state(): got FIN\n");

Expand All @@ -394,63 +401,47 @@ static int tcp_estab_state (_tcp_Socket **sp, const in_Header *ip,
s->unhappy = TRUE;
s->timeout = set_timeout (tcp_LASTACK_TIME); /* Added AGW 6 Jan 2001 */
s->state = tcp_StateLASTACK;

return (0);
}
else
{
s->unhappy = TRUE;
TCP_SEND (s); /* force a retransmit, no state change */
did_tx = TRUE;
return (0);
}
}

/*
* Eliminate the spurious ACK messages bug.
* For the window update, the length should be the
* data length only, so exclude the TCP header size
* -- Joe <jdhagen@itis.com>
/* Send fast-ACK after retransmission.
*/
len -= (tcp->offset << 2);
if (len > 0 && s->missed_seq[0] != s->missed_seq[1])
{
TCP_SEND (s);
return (0);
}

/* Peer ACKed some of our data, continue sending more.
*/
if (ldiff > 0 && s->tx_datalen > (unsigned long)s->send_una)
goto send_now;
{
s->karn_count = 0;
TCP_SEND (s);
return (0);
}

/* Send ACK for received data.
/* Schedule delayed-ACK for received data, in case
* tcp_read() doesn't get to it in time.
*/
if (len > 0)
{
/* Need to ACK and update window, but how urgent ??
* We need a better criteria for doing Fast-ACK.
*/
if (s->adv_win < s->max_seg)
{
send_now:
TRACE_FILE ("tcp_estab_state (%u): FastACK: ldiff %ld, "
"UNA %ld, MS-right %ld\n",
__LINE__, ldiff, s->send_una,
s->missed_seq[0] != s->missed_seq[1] ?
(u_long)(s->missed_seq[0] - s->recv_next) : 0);
s->karn_count = 0;
TCP_SEND (s);
did_tx = TRUE;

if (s->adv_win == 0) /* need to open closed window in retransmitter */
{
s->locflags |= LF_WINUPDATE;
s->unhappy = TRUE;
}
}
else
{
TCP_SENDSOON (s); /* delayed ACK */
did_tx = TRUE;
}
if (!ack_scheduled)
TCP_SENDSOON (s);
return (0);
}

/* Check if we need to reply to keep-alive segment
*/
if (!did_tx && (len == 0) && (seqnum == s->recv_next-1) &&
if ((seqnum == s->recv_next-1) &&
((flags & tcp_FlagACK) == tcp_FlagACK) && /* ACK only */
(s->state == tcp_StateESTAB))
{
Expand Down Expand Up @@ -866,13 +857,14 @@ copy_in_order (_tcp_Socket *s, const BYTE *data, unsigned len)
memcpy (s->rx_data + s->rx_datalen, data, len);
s->recv_next += len;
s->rx_datalen += len;
s->recv_win -= len;
}

/*
* Handle any new data that increments the 'recv_next' index.
* 'ldiff >= 0'.
*/
static void
static int
data_in_order (_tcp_Socket *s, const BYTE *data, unsigned len, unsigned diff)
{
/* Skip data before recv_next. We must be left with some data or
Expand Down Expand Up @@ -907,6 +899,7 @@ data_in_order (_tcp_Socket *s, const BYTE *data, unsigned len, unsigned diff)
TRACE_FILE ("data_in_order (%u): Use %lu out-of-order bytes\n",
__LINE__, (u_long)(s->missed_seq[1] - s->missed_seq[0]));
s->rx_datalen += (s->missed_seq[1] - s->missed_seq[0]);
s->recv_win -= (s->missed_seq[1] - s->missed_seq[0]);
s->recv_next = s->missed_seq[1];
s->missed_seq[0] = s->missed_seq[1] = 0;

Expand All @@ -916,6 +909,11 @@ data_in_order (_tcp_Socket *s, const BYTE *data, unsigned len, unsigned diff)
*/
copy_in_order (s, data + ms_end, len - ms_end);
}

/* Send fast-ACK to notify peer that we caught up.
*/
s->dup_acks = 0;
len = -1;
}

TRACE_FILE ("data_in_order (%u): edges %lu/%lu, recv.next %lu\n",
Expand All @@ -924,6 +922,8 @@ data_in_order (_tcp_Socket *s, const BYTE *data, unsigned len, unsigned diff)

TRACE_FILE ("data_in_order (%u): new data now ends at %u\n",
__LINE__, s->rx_datalen);

return (len);
}

/*
Expand Down Expand Up @@ -1115,9 +1115,9 @@ static int tcp_process_data (_tcp_Socket *s, const tcp_Header *tcp,

if (ldiff >= 0)
{
data_in_order (s, data, len, ldiff);
len = data_in_order (s, data, len, ldiff);
s->unhappy = (s->tx_datalen > 0);
return (0);
return (len);
}

STAT (tcpstats.tcps_rcvduppack++); /* increment dup-ACK count */
Expand Down
7 changes: 5 additions & 2 deletions src/wattcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ struct ulong_long {
* UDP/TCP socket local flags (locflags) bits.
* Mostly used to support the BSD-socket API.
*/
#define LF_WINUPDATE 0x00001 /**< need to send a window-update */
#define LF_WINUPDATE 0x00001 /**< no longer used */
#define LF_NOPUSH 0x00002 /**< don't push on write */
#define LF_NOOPT 0x00004 /**< don't use tcp options */
#define LF_REUSEADDR 0x00008 /**< \todo Reuse address not supported */
Expand Down Expand Up @@ -607,6 +607,7 @@ typedef struct tcp_Socket {

UINT window; /**< other guy's window */
UINT adv_win; /**< our last advertised window */
long recv_win; /**< our current remaining window */

BYTE cwindow; /**< Congestion window */
BYTE wwindow; /**< Van Jacobson's algorithm */
Expand All @@ -618,7 +619,9 @@ typedef struct tcp_Socket {
UINT rto; /**< retransmission timeout */
BYTE karn_count; /**< count of packets */
BYTE tos; /**< TOS from IP-header */
WORD fill_5;

BYTE dup_acks; /**< number of dup-ACKs we sent recently */
BYTE fill_5;

DWORD rtt_time; /**< Round Trip Time value */
DWORD rtt_lasttran; /**< RTT at last transmission */
Expand Down