mirror of
https://github.com/brazilofmux/tinymux
synced 2026-08-13 00:23:11 -04:00
fix(tf): set TCP_NODELAY on the session socket (#2196)
client/tf never set TCP_NODELAY, so the client side of every session ran with Nagle enabled. Client companion to #2194, which was the same gap in the server's POSIX engines. A single typed command is immune either way: send_line() assembles command + CRLF into one buffer and issues one write(). But anything that sends several lines in one event-loop pass -- a trigger firing off a match, a macro or keybinding bound to multiple commands, a scripted burst, a speedwalk -- produces back-to-back small writes, and Nagle makes each one after the first wait for the ACK of its predecessor, which the peer's delayed-ACK timer can hold for up to ~40ms. Against a remote server the burst then leaves the client at ACK cadence instead of departing together. Invisible on loopback, which is why local testing never showed it. Set after the connect loop rather than at either `break`, so both paths (immediate connect and EINPROGRESS + poll) are covered by one call. Non-fatal: a latency hint failing is no reason to refuse a connection that otherwise works. Verified by strace'ing tf under a pty against a scratch netmux: setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0 Catch-verified: with the change reverted, tf makes no setsockopt call at all on the connect path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
40cbfe33ac
commit
2f1399c80d
1 changed files with 24 additions and 0 deletions
|
|
@ -1,6 +1,8 @@
|
|||
#include "connection.h"
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h> // TCP_NODELAY (#2196)
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -143,6 +145,28 @@ bool Connection::connect() {
|
|||
|
||||
if (fd_ < 0) return false;
|
||||
|
||||
// #2196: disable Nagle on the session socket.
|
||||
//
|
||||
// A single typed command is immune either way -- send_line() assembles
|
||||
// command + CRLF into one buffer and issues one write(). But anything
|
||||
// that sends several lines in one event-loop pass (a trigger firing off a
|
||||
// match, a macro or keybinding bound to multiple commands, a scripted
|
||||
// burst, a speedwalk) produces back-to-back small writes, and with Nagle
|
||||
// each one after the first waits for the ACK of its predecessor -- which
|
||||
// the peer's delayed-ACK timer can hold for up to ~40ms. The burst then
|
||||
// leaves the client at ACK cadence instead of departing together.
|
||||
//
|
||||
// Invisible on loopback, which is why local testing never shows it.
|
||||
//
|
||||
// Set here rather than at either `break` so both connect paths (immediate
|
||||
// and EINPROGRESS + poll) are covered by one call. Non-fatal: a latency
|
||||
// hint failing is no reason to refuse a working connection.
|
||||
//
|
||||
{
|
||||
int one = 1;
|
||||
(void)setsockopt(fd_, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
|
||||
}
|
||||
|
||||
if (use_ssl_) {
|
||||
if (!ssl_connect()) {
|
||||
close(fd_);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue