Skip to content

Commit

Permalink
Optimize ACK and window updates
Browse files Browse the repository at this point in the history
  • Loading branch information
jwt27 committed Jan 18, 2024
1 parent 5363dff commit 80530a2
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 83 deletions.
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
79 changes: 43 additions & 36 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 @@ -1844,13 +1831,30 @@ static int tcp_read (_tcp_Socket *s, BYTE *buf, int maxlen)
to_move += s->missed_seq[1] - s->recv_next;

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

TCP_SENDSOON (s); /* delayed ACK */
/* Delay ACK until we can advertise maximum window size.
*/
if (s->max_rx_data - s->rx_datalen >= s->max_rx_data / 2)
{
/* Update window if it becomes too small.
*/
if (s->recv_win <= (int)s->max_seg * 2)
TCP_SEND (s);
else if (s->locflags & LF_NEED_ACK)
{
/* Normal "fast" ACK condition, except we do it slower.
* Try to ACK every second segment, or when PUSH received.
* Otherwise, delay further to avoid empty packets.
*/
if ((s->locflags & LF_GOT_PUSH) ||
s->adv_win - s->recv_win >= 2 * s->max_seg)
TCP_SEND (s);
else
TCP_SENDSOON (s);
}
s->locflags &= ~LF_GOT_PUSH;
}
else
tcp_upd_win (s, __LINE__);
}
else if (s->state == tcp_StateCLOSWT)
_tcp_close (s);
Expand Down Expand Up @@ -1981,7 +1985,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_NEED_ACK | LF_KEEPALIVE | LF_GOT_FIN | LF_GOT_ICMP);

s->datatimer = 0UL;
s->inactive_to = 0;
Expand Down Expand Up @@ -2145,20 +2149,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 +2354,27 @@ 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)
{
new_window = min (new_window, s->max_rx_data / 2);
if (new_window > (int)s->max_seg)
{
new_window -= new_window % s->max_seg;
if (s->recv_win < new_window - (int)s->max_seg)
s->recv_win = new_window;
}
else s->recv_win = new_window;
}
else s->recv_win = new_window;

s->adv_win = s->recv_win;

#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 Expand Up @@ -2524,6 +2530,7 @@ int _tcp_send (_tcp_Socket *s, const char *file, unsigned line)
}

s->send_una = start_data; /* relative start of tx_data[] buffer */
s->locflags &= ~LF_NEED_ACK;

TRACE_CONSOLE (2, "tcp_send (called from %s/%u): sent %u bytes in %u "
"packets with (%ld) unacked. SND.NXT %lu\n",
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
65 changes: 21 additions & 44 deletions src/tcp_fsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,6 @@ 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;

/* handle lost SYN
*/
Expand Down Expand Up @@ -364,14 +363,13 @@ 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 */
return (1);
}

did_tx = FALSE;

if (s->state != tcp_StateCLOSWT &&
(flags & tcp_FlagFIN) &&
SEQ_GEQ(s->recv_next,seqnum) &&
Expand All @@ -385,7 +383,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 +391,41 @@ 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>
*/
len -= (tcp->offset << 2);

/* 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;
}
BOOL do_tx = !(s->locflags & LF_NEED_ACK);
s->locflags |= LF_NEED_ACK;
if (do_tx)
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,6 +841,7 @@ 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;
}

/*
Expand Down Expand Up @@ -907,6 +883,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 Down Expand Up @@ -1117,7 +1094,7 @@ static int tcp_process_data (_tcp_Socket *s, const tcp_Header *tcp,
{
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
3 changes: 2 additions & 1 deletion 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_NEED_ACK 0x00001 /**< need to send ACK for received data */
#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 Down

0 comments on commit 80530a2

Please sign in to comment.