void sk_addr_free(SockAddr addr);
Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
- Plug p);
+ int nodelay, Plug p);
Socket sk_newlistener(int port, Plug plug, int local_host_only);
{
char *error;
char *realhost;
+ /* nodelay is only useful if stdin is a character device (console) */
+ int nodelay = cfg.tcp_nodelay &&
+ (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR);
- error = back->init(cfg.host, cfg.port, &realhost);
+ error = back->init(cfg.host, cfg.port, &realhost, nodelay);
if (error) {
fprintf(stderr, "Unable to open connection:\n%s", error);
return 1;
pr->ready = 1;
pr->c = c;
- pr->s = *s = sk_new(addr, port, 0, 1, (Plug) pr);
+ pr->s = *s = sk_new(addr, port, 0, 1, 0, (Plug) pr);
if ((err = sk_socket_error(*s))) {
sfree(pr);
return err;
back = &ssh_backend;
- err = back->init(cfg.host, cfg.port, &realhost);
+ err = back->init(cfg.host, cfg.port, &realhost, 0);
if (err != NULL) {
fprintf(stderr, "ssh_init: %s", err);
return 1;
};
typedef struct {
- char *(*init) (char *host, int port, char **realhost);
+ char *(*init) (char *host, int port, char **realhost, int nodelay);
/* back->send() returns the current amount of buffered data. */
int (*send) (char *buf, int len);
/* back->sendbuffer() does the same thing but without attempting a send */
int close_on_exit;
int warn_on_close;
int ping_interval; /* in seconds */
+ int tcp_nodelay;
/* SSH options */
char remote_cmd[512];
char remote_cmd2[512]; /* fallback if the first fails
* Also places the canonical host name into `realhost'. It must be
* freed by the caller.
*/
-static char *raw_init(char *host, int port, char **realhost)
+static char *raw_init(char *host, int port, char **realhost, int nodelay)
{
static struct plug_function_table fn_table = {
raw_closing,
sprintf(buf, "Connecting to %.100s port %d", addrbuf, port);
logevent(buf);
}
- s = sk_new(addr, port, 0, 1, &fn_table_ptr);
+ s = sk_new(addr, port, 0, 1, nodelay, &fn_table_ptr);
if ((err = sk_socket_error(s)))
return err;
* Also places the canonical host name into `realhost'. It must be
* freed by the caller.
*/
-static char *rlogin_init(char *host, int port, char **realhost)
+static char *rlogin_init(char *host, int port, char **realhost, int nodelay)
{
static struct plug_function_table fn_table = {
rlogin_closing,
sprintf(buf, "Connecting to %.100s port %d", addrbuf, port);
logevent(buf);
}
- s = sk_new(addr, port, 1, 0, &fn_table_ptr);
+ s = sk_new(addr, port, 1, 0, nodelay, &fn_table_ptr);
if ((err = sk_socket_error(s)))
return err;
back = &ssh_backend;
- err = back->init(cfg.host, cfg.port, &realhost);
+ err = back->init(cfg.host, cfg.port, &realhost, 0);
if (err != NULL)
bump("ssh_init: %s", err);
ssh_scp_init();
write_setting_i(sesskey, "WarnOnClose", !!cfg->warn_on_close);
write_setting_i(sesskey, "PingInterval", cfg->ping_interval / 60); /* minutes */
write_setting_i(sesskey, "PingIntervalSecs", cfg->ping_interval % 60); /* seconds */
+ write_setting_i(sesskey, "TCPNoDelay", cfg->tcp_nodelay);
write_setting_s(sesskey, "TerminalType", cfg->termtype);
write_setting_s(sesskey, "TerminalSpeed", cfg->termspeed);
{
gppi(sesskey, "PingIntervalSecs", 0, &pingsec);
cfg->ping_interval = pingmin * 60 + pingsec;
}
+ gppi(sesskey, "TCPNoDelay", 1, &cfg->tcp_nodelay);
gpps(sesskey, "TerminalType", "xterm", cfg->termtype,
sizeof(cfg->termtype));
gpps(sesskey, "TerminalSpeed", "38400,38400", cfg->termspeed,
* Also places the canonical host name into `realhost'. It must be
* freed by the caller.
*/
-static char *connect_to_host(char *host, int port, char **realhost)
+static char *connect_to_host(char *host, int port, char **realhost, int nodelay)
{
static struct plug_function_table fn_table = {
ssh_closing,
sprintf(buf, "Connecting to %.100s port %d", addrbuf, port);
logevent(buf);
}
- s = sk_new(addr, port, 0, 1, &fn_table_ptr);
+ s = sk_new(addr, port, 0, 1, nodelay, &fn_table_ptr);
if ((err = sk_socket_error(s)))
return err;
*
* Returns an error message, or NULL on success.
*/
-static char *ssh_init(char *host, int port, char **realhost)
+static char *ssh_init(char *host, int port, char **realhost, int nodelay)
{
char *p;
ssh_overall_bufsize = 0;
ssh_fallback_cmd = 0;
- p = connect_to_host(host, port, realhost);
+ p = connect_to_host(host, port, realhost, nodelay);
if (p != NULL)
return p;
* Also places the canonical host name into `realhost'. It must be
* freed by the caller.
*/
-static char *telnet_init(char *host, int port, char **realhost)
+static char *telnet_init(char *host, int port, char **realhost, int nodelay)
{
static struct plug_function_table fn_table = {
telnet_closing,
sprintf(buf, "Connecting to %.100s port %d", addrbuf, port);
logevent(buf);
}
- s = sk_new(addr, port, 0, 1, &fn_table_ptr);
+ s = sk_new(addr, port, 0, 1, nodelay, &fn_table_ptr);
if ((err = sk_socket_error(s)))
return err;
IDC_TITLE_CONNECTION,
IDC_BOX_CONNECTION1,
IDC_BOX_CONNECTION2,
+ IDC_BOX_CONNECTION3,
IDC_TTSTATIC,
IDC_TTEDIT,
IDC_LOGSTATIC,
IDC_LOGEDIT,
IDC_PINGSTATIC,
IDC_PINGEDIT,
+ IDC_NODELAY,
connectionpanelend,
telnetpanelstart,
cfg.protocol ==
PROT_RLOGIN ? IDC_PROTRLOGIN : IDC_PROTRAW);
SetDlgItemInt(hwnd, IDC_PINGEDIT, cfg.ping_interval, FALSE);
+ CheckDlgButton(hwnd, IDC_NODELAY, cfg.tcp_nodelay);
CheckRadioButton(hwnd, IDC_DEL008, IDC_DEL127,
cfg.bksp_is_delete ? IDC_DEL127 : IDC_DEL008);
}
if (panel == connectionpanelstart) {
- /* The Connection panel. Accelerators used: [acgo] tuk */
+ /* The Connection panel. Accelerators used: [acgo] tukn */
struct ctlpos cp;
ctlposinit(&cp, hwnd, 80, 3, 13);
bartitle(&cp, "Options controlling the connection",
staticedit(&cp, "Seconds between &keepalives (0 to turn off)",
IDC_PINGSTATIC, IDC_PINGEDIT, 20);
endbox(&cp);
+ if (dlgtype == 0) {
+ beginbox(&cp, "Low-level TCP connection options",
+ IDC_BOX_CONNECTION3);
+ checkbox(&cp, "Disable &Nagle's algorithm (TCP_NODELAY option)",
+ IDC_NODELAY);
+ endbox(&cp);
+ }
}
if (panel == telnetpanelstart) {
MyGetDlgItemInt(hwnd, IDC_PINGEDIT,
&cfg.ping_interval);
break;
+ case IDC_NODELAY:
+ if (HIWORD(wParam) == BN_CLICKED ||
+ HIWORD(wParam) == BN_DOUBLECLICKED)
+ cfg.tcp_nodelay =
+ IsDlgButtonChecked(hwnd, IDC_NODELAY);
+ break;
case IDC_DEL008:
case IDC_DEL127:
if (HIWORD(wParam) == BN_CLICKED ||
char msg[1024], *title;
char *realhost;
- error = back->init(cfg.host, cfg.port, &realhost);
+ error = back->init(cfg.host, cfg.port, &realhost, cfg.tcp_nodelay);
if (error) {
sprintf(msg, "Unable to open connection to\n"
"%.800s\n" "%s", cfg.host, error);
}
Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
- Plug plug)
+ int nodelay, Plug plug)
{
static struct socket_function_table fn_table = {
sk_tcp_plug,
setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (void *) &b, sizeof(b));
}
+ if (nodelay) {
+ BOOL b = TRUE;
+ setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b));
+ }
+
/*
* Bind to local address.
*/
pr->throttled = pr->throttle_override = 0;
pr->c = c;
- pr->s = *s = sk_new(addr, port, 0, 1, (Plug) pr);
+ pr->s = *s = sk_new(addr, port, 0, 1, 0, (Plug) pr);
if ((err = sk_socket_error(*s))) {
sfree(pr);
return err;