SOCKET: Extended TMXR packet capabilities to disable the Nagle algorithm when TCP packets transports are used.

This commit is contained in:
Mark Pizzolato 2014-01-23 09:31:05 -08:00
parent bebb787325
commit 9ab6c4d1c1
7 changed files with 80 additions and 15 deletions

View file

@ -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];

View file

@ -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");

View file

@ -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;

View file

@ -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;
}

View file

@ -78,6 +78,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <netinet/in.h> /* for sockaddr_in */
#include <netinet/tcp.h> /* for TCP_NODELAY */
#include <arpa/inet.h> /* for inet_addr and inet_ntoa */
#include <netdb.h>
#include <sys/time.h> /* 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);

View file

@ -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));

View file

@ -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);