From 9ab6c4d1c1f9042ab5403edf1eab7258c6fda109 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 23 Jan 2014 09:31:05 -0800 Subject: [PATCH] SOCKET: Extended TMXR packet capabilities to disable the Nagle algorithm when TCP packets transports are used. --- PDP11/pdp11_dmc.c | 2 ++ PDP11/pdp11_dup.c | 1 + sim_ether.c | 2 +- sim_sock.c | 52 ++++++++++++++++++++++++++++++++++++++++++++--- sim_sock.h | 4 +++- sim_tmxr.c | 30 +++++++++++++++++++-------- sim_tmxr.h | 4 +++- 7 files changed, 80 insertions(+), 15 deletions(-) diff --git a/PDP11/pdp11_dmc.c b/PDP11/pdp11_dmc.c index d2215037..cbf162fb 100644 --- a/PDP11/pdp11_dmc.c +++ b/PDP11/pdp11_dmc.c @@ -3293,6 +3293,8 @@ uint32 i, j; sim_debug(DBG_TRC, dptr, "dmc_reset(%s)\n", dptr->name); +dmc_desc.packet = TRUE; +dmp_desc.packet = TRUE; /* Connect structures together */ for (i=0; i < DMC_NUMDEVICE; i++) { dmc_csrs[i].sel0 = &dmc_sel0[i]; diff --git a/PDP11/pdp11_dup.c b/PDP11/pdp11_dup.c index 8d63a1ee..c0b3e27c 100644 --- a/PDP11/pdp11_dup.c +++ b/PDP11/pdp11_dup.c @@ -1190,6 +1190,7 @@ int32 i, ndev; sim_debug(DBG_TRC, dptr, "dup_reset()\n"); +dup_desc.packet = TRUE; if ((UNIBUS) && (dptr == &dpv_dev)) { if (!(dptr->flags & DEV_DIS)) { printf ("Can't enable Qbus device on Unibus system\n"); diff --git a/sim_ether.c b/sim_ether.c index 4fb0f021..18b3f233 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -1897,7 +1897,7 @@ else if (sim_log) fprintf (sim_log, msg, errbuf); return SCPE_OPENERR; } - dev->fd_handle = sim_connect_sock_ex (localport, hostport, NULL, NULL, TRUE); + dev->fd_handle = sim_connect_sock_ex (localport, hostport, NULL, NULL, TRUE, FALSE); if (INVALID_SOCKET == dev->fd_handle) return SCPE_OPENERR; dev->eth_api = ETH_API_UDP; diff --git a/sim_sock.c b/sim_sock.c index 1b13ff13..9d88eb2a 100644 --- a/sim_sock.c +++ b/sim_sock.c @@ -101,7 +101,7 @@ SOCKET sim_connect_sock (const char *hostport, const char *default_host, const c return INVALID_SOCKET; } -SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, t_bool datagram) +SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, t_bool datagram, t_bool nodelay) { return INVALID_SOCKET; } @@ -797,6 +797,33 @@ return 0; #endif /* endif !Win32 && !VMS */ +static int32 sim_setnodelay (SOCKET sock) +{ +int nodelay = 1; +int sta; + +/* disable Nagle algorithm */ +sta = setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay)); +if (sta == -1) + return SOCKET_ERROR; + +#if defined(TCP_NODELAYACK) +/* disable delayed ack algorithm */ +sta = setsockopt (sock, IPPROTO_TCP, TCP_NODELAYACK, (char *)&nodelay, sizeof(nodelay)); +if (sta == -1) + return SOCKET_ERROR; +#endif + +#if defined(TCP_QUICKACK) +/* disable delayed ack algorithm */ +sta = setsockopt (sock, IPPROTO_TCP, TCP_QUICKACK, (char *)&nodelay, sizeof(nodelay)); +if (sta == -1) + return SOCKET_ERROR; +#endif + +return sta; +} + static SOCKET sim_create_sock_ex (int af, t_bool datagram) { SOCKET newsock; @@ -915,10 +942,10 @@ return newsock; /* got it! */ SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port) { -return sim_connect_sock_ex (NULL, hostport, default_host, default_port, FALSE); +return sim_connect_sock_ex (NULL, hostport, default_host, default_port, FALSE, FALSE); } -SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, t_bool datagram) +SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, t_bool datagram, t_bool nodelay) { SOCKET newsock = INVALID_SOCKET; int32 sta; @@ -986,6 +1013,13 @@ if (sta == SOCKET_ERROR) { /* fcntl error? */ p_freeaddrinfo (result); return sim_err_sock (newsock, "fcntl", 1); } +if ((!datagram) && (nodelay)) { + sta = sim_setnodelay (newsock); /* set nodelay */ + if (sta == SOCKET_ERROR) { /* setsock error? */ + p_freeaddrinfo (result); + return sim_err_sock (newsock, "setnodelay", 1); + } + } sta = connect (newsock, result->ai_addr, result->ai_addrlen); p_freeaddrinfo (result); if ((sta == SOCKET_ERROR) && @@ -998,6 +1032,11 @@ return newsock; /* got it! */ SOCKET sim_accept_conn (SOCKET master, char **connectaddr) { +return sim_accept_conn_ex (master, connectaddr, FALSE); +} + +SOCKET sim_accept_conn_ex (SOCKET master, char **connectaddr, t_bool nodelay) +{ int32 sta, err; #if defined (macintosh) || defined (__linux) || defined (__linux__) || \ defined (__APPLE__) || defined (__OpenBSD__) || \ @@ -1039,6 +1078,13 @@ if (connectaddr != NULL) { sta = sim_setnonblock (newsock); /* set nonblocking */ if (sta == SOCKET_ERROR) /* fcntl error? */ return sim_err_sock (newsock, "fcntl", 0); + +if (nodelay) { + sta = sim_setnodelay (newsock); /* set nonblocking */ + if (sta == SOCKET_ERROR) /* setsockopt error? */ + return sim_err_sock (newsock, "setnodelay", 0); + } + return newsock; } diff --git a/sim_sock.h b/sim_sock.h index f7aa14b0..e19712e4 100644 --- a/sim_sock.h +++ b/sim_sock.h @@ -78,6 +78,7 @@ #include #include #include /* for sockaddr_in */ +#include /* for TCP_NODELAY */ #include /* for inet_addr and inet_ntoa */ #include #include /* for EMX */ @@ -105,8 +106,9 @@ t_stat sim_parse_addr (const char *cptr, char *host, size_t hostlen, const char t_stat sim_parse_addr_ex (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, char *localport, size_t local_port_len, const char *default_port); SOCKET sim_master_sock (const char *hostport, t_stat *parse_status); SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port); -SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, t_bool datagram); +SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, t_bool datagram, t_bool nodelay); SOCKET sim_accept_conn (SOCKET master, char **connectaddr); +SOCKET sim_accept_conn_ex (SOCKET master, char **connectaddr, t_bool nodelay); int32 sim_check_conn (SOCKET sock, t_bool rd); int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes); int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes); diff --git a/sim_tmxr.c b/sim_tmxr.c index 42af7abd..6832c773 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -893,6 +893,8 @@ if (lp->destination || lp->port || lp->txlogname) { sprintf (growstring(&tptr, 32), ",UnBuffered"); if (lp->mp->datagram != lp->datagram) sprintf (growstring(&tptr, 8), ",%s", lp->datagram ? "UDP" : "TCP"); + if (lp->mp->packet != lp->packet) + sprintf (growstring(&tptr, 8), ",Packet"); if (lp->port) sprintf (growstring(&tptr, 12 + strlen (lp->port)), ",%s%s", lp->port, ((lp->mp->notelnet != lp->notelnet) && (!lp->datagram)) ? (lp->notelnet ? ";notelnet" : ";telnet") : ""); if (lp->destination) { @@ -996,7 +998,7 @@ mp->last_poll_time = poll_time; /* Check for a pending Telnet/tcp connection */ if (mp->master) { - newsock = sim_accept_conn (mp->master, &address); /* poll connect */ + newsock = sim_accept_conn_ex (mp->master, &address, mp->packet);/* poll connect */ if (newsock != INVALID_SOCKET) { /* got a live one? */ sprintf (msg, "tmxr_poll_conn() - Connection from %s", address); @@ -1101,7 +1103,7 @@ for (i = 0; i < mp->lines; i++) { /* check each line in se break; case 1: if (lp->master) { /* Check for a pending Telnet/tcp connection */ - while (INVALID_SOCKET != (newsock = sim_accept_conn (lp->master, &address))) {/* got a live one? */ + while (INVALID_SOCKET != (newsock = sim_accept_conn_ex (lp->master, &address, lp->packet))) {/* got a live one? */ char *sockname, *peername; sim_getnames_sock (newsock, &sockname, &peername); @@ -1167,7 +1169,7 @@ for (i = 0; i < mp->lines; i++) { /* check each line in se (!lp->modem_control || (lp->modembits & TMXR_MDM_DTR))) { sprintf (msg, "tmxr_poll_conn() - establishing outgoing connection to: %s", lp->destination); tmxr_debug_connect_line (lp, msg); - lp->connecting = sim_connect_sock_ex (lp->datagram ? lp->port : NULL, lp->destination, "localhost", NULL, lp->datagram); + lp->connecting = sim_connect_sock_ex (lp->datagram ? lp->port : NULL, lp->destination, "localhost", NULL, lp->datagram, lp->mp->packet); } } @@ -1235,7 +1237,7 @@ if ((lp->destination) && (!lp->serport)) { if ((!lp->modem_control) || (lp->modembits & TMXR_MDM_DTR)) { sprintf (msg, "tmxr_reset_ln_ex() - connecting to %s", lp->destination); tmxr_debug_connect_line (lp, msg); - lp->connecting = sim_connect_sock_ex (lp->datagram ? lp->port : NULL, lp->destination, "localhost", NULL, lp->datagram); + lp->connecting = sim_connect_sock_ex (lp->datagram ? lp->port : NULL, lp->destination, "localhost", NULL, lp->datagram, lp->mp->packet); } } tmxr_init_line (lp); /* initialize line state */ @@ -1415,7 +1417,7 @@ if (lp->mp && lp->modem_control) { /* This API ONLY works on mo sprintf (msg, "tmxr_set_get_modem_bits() - establishing outgoing connection to: %s", lp->destination); tmxr_debug_connect_line (lp, msg); - lp->connecting = sim_connect_sock_ex (lp->datagram ? lp->port : NULL, lp->destination, "localhost", NULL, lp->datagram); + lp->connecting = sim_connect_sock_ex (lp->datagram ? lp->port : NULL, lp->destination, "localhost", NULL, lp->datagram, lp->mp->packet); } } } @@ -2058,7 +2060,7 @@ char tbuf[CBUFSIZE], listen[CBUFSIZE], destination[CBUFSIZE], SOCKET sock; SERHANDLE serport; char *tptr = cptr; -t_bool nolog, notelnet, listennotelnet, unbuffered, modem_control, loopback, datagram; +t_bool nolog, notelnet, listennotelnet, unbuffered, modem_control, loopback, datagram, packet; TMLN *lp; t_stat r = SCPE_ARG; @@ -2078,6 +2080,7 @@ while (*tptr) { memset(option, '\0', sizeof(option)); nolog = notelnet = listennotelnet = unbuffered = loopback = FALSE; datagram = mp->datagram; + packet = mp->packet; if (line != -1) notelnet = listennotelnet = mp->notelnet; modem_control = mp->modem_control; @@ -2153,6 +2156,12 @@ while (*tptr) { notelnet = datagram = TRUE; continue; } + if (0 == MATCH_CMD (gbuf, "PACKET")) { + if ((NULL != cptr) && ('\0' != *cptr)) + return SCPE_2MARG; + packet = TRUE; + continue; + } if ((0 == MATCH_CMD (gbuf, "STREAM")) || (0 == MATCH_CMD (gbuf, "TCP"))) { if ((NULL != cptr) && ('\0' != *cptr)) return SCPE_2MARG; @@ -2186,7 +2195,7 @@ while (*tptr) { else return SCPE_ARG; } - sock = sim_connect_sock_ex (NULL, hostport, "localhost", NULL, datagram); + sock = sim_connect_sock_ex (NULL, hostport, "localhost", NULL, datagram, packet); if (sock != INVALID_SOCKET) sim_close_sock (sock, 0); else @@ -2315,6 +2324,7 @@ while (*tptr) { for (i = 0; i < mp->lines; i++) { /* initialize lines */ lp = mp->ldsc + i; lp->mp = mp; /* set the back pointer */ + lp->packet = mp->packet; if (lp->serport) { /* serial port attached? */ tmxr_reset_ln (lp); /* close current serial connection */ @@ -2377,7 +2387,8 @@ while (*tptr) { else return SCPE_ARG; } - sock = sim_connect_sock_ex (datagram ? listen : NULL, destination, "localhost", NULL, datagram); + lp->packet = packet; + sock = sim_connect_sock_ex (datagram ? listen : NULL, destination, "localhost", NULL, datagram, packet); if (sock != INVALID_SOCKET) { _mux_detach_line (lp, FALSE, TRUE); lp->destination = (char *)malloc(1+strlen(destination)); @@ -2489,7 +2500,8 @@ while (*tptr) { else return SCPE_ARG; } - sock = sim_connect_sock_ex (datagram ? listen : NULL, destination, "localhost", NULL, datagram); + lp->packet = packet; + sock = sim_connect_sock_ex (datagram ? listen : NULL, destination, "localhost", NULL, datagram, packet); if (sock != INVALID_SOCKET) { _mux_detach_line (lp, FALSE, TRUE); lp->destination = (char *)malloc(1+strlen(destination)); diff --git a/sim_tmxr.h b/sim_tmxr.h index b6f3a4b0..b244152d 100644 --- a/sim_tmxr.h +++ b/sim_tmxr.h @@ -152,6 +152,7 @@ struct tmln { t_bool loopback; /* Line in loopback mode */ t_bool halfduplex; /* Line in half-duplex mode */ t_bool datagram; /* Line is datagram packet oriented */ + t_bool packet; /* Line is packet oriented */ int32 lpbpr; /* loopback buf remove */ int32 lpbpi; /* loopback buf insert */ int32 lpbcnt; /* loopback buf used count */ @@ -178,7 +179,8 @@ struct tmxr { uint32 last_poll_time; /* time of last connection poll */ t_bool notelnet; /* default telnet capability for incoming connections */ t_bool modem_control; /* multiplexer supports modem control behaviors */ - t_bool datagram; /* Lines are datagram packet oriented */ + t_bool packet; /* Lines are packet oriented */ + t_bool datagram; /* Lines use datagram packet transport */ }; int32 tmxr_poll_conn (TMXR *mp);