Project

General

Profile

« Previous | Next » 

Revision 3fa88c6f

Added by Hamish Coleman about 16 years ago

  • ID 3fa88c6f9db7e4300a304ebba051ae652e76c8be

Handle WSAECONNRESET, add Telnet keepalives, rework the show_conn_table.
During long-term connection testing, I found that at least one of my
connections would have some kind of disconnect - perhaps an idle timeout,
so I have added support for sending IAC NOP packets on each net loop
timeout. Additionally, if the TCP connection does go away, we need to
detect that in the net loops and stop processing them.
Finally, since the show_conn_table was getting crowded, I put all the flags
into one column and made them smaller. This freed up enough space to show
the IP peer for the connection

View differences:

wconsd.c
#include <stdio.h>
#include <stdlib.h>
#define VERSION "0.2.4"
#define VERSION "0.2.5"
/* Size of buffers for send and receive */
#define BUFSIZE 1024
......
struct connection {
int active; /* an active entry cannot be reused */
int id; /* connection identifier */
int menuactive; /* dont run the serial pump on a menu */
HANDLE menuThread;
int netconnected;
SOCKET net;
......
int serialconnected;
HANDLE serial;
HANDLE serialThread;
int option_runmenu; /* are we at the menu? */
int option_echo; /* will we echo chars recieved? */
int option_keepalive; /* will we send IAC NOPs all the time? */
int net_bytes_rx;
int net_bytes_tx;
struct sockaddr *sa;
};
struct connection connection[MAXCONNECTIONS];
......
dprintf(1,"wconsd: closing closed connection %i\n",conn->id);
return;
}
conn->menuactive=1;
conn->option_runmenu=1;
close_com_port(conn);
WaitForSingleObject(conn->serialThread,INFINITE);
CloseHandle(conn->serialThread);
......
}
return 2;
case 244: /* Interrupt */
conn->menuactive=1;
conn->option_runmenu=1;
return 2;
case 245: /* abort output */
dprintf(1,"wconsd[%i]: option IAC %i\n",conn->id,buf[1]);
......
switch (err) {
case WSAEWOULDBLOCK:
/* ignore */
if (conn->option_keepalive) {
netprintf(conn,"\xff\xf1");
}
continue;
case WSAECONNRESET:
closesocket(conn->net);
conn->net=INVALID_SOCKET;
conn->netconnected=0;
return;
default:
dprintf(1,"wconsd[%i]: net_to_com socket error (%i)\n",conn->id,err);
/* General paranoia about blocking sockets */
......
/* TODO - emulate ciscos ctrl-^,x sequence for exit to menu */
if (conn->menuactive) {
if (conn->option_runmenu) {
/* TODO - if we are in menu mode, hook into the menu here */
// dprintf(1,"wconsd[%i]: unexpected menuactive\n",conn->id);
// dprintf(1,"wconsd[%i]: unexpected option_runmenu\n",conn->id);
return 0;
}
......
} else {
netprintf(conn, " state=closed\r\n\n");
}
netprintf(conn," connectionid=%i hostname=%s\r\n\r\n",conn->id,hostname);
netprintf(conn," connectionid=%i hostname=%s\r\n",conn->id,hostname);
netprintf(conn," echo=%i keepalive=%i\r\n",conn->option_echo,conn->option_keepalive);
netprintf(conn,"\r\n");
}
/*
......
/* port ist still open */
netprintf(conn,"\r\n\n");
/* signal to quit the menu */
conn->menuactive=0;
conn->option_runmenu=0;
return;
}
if (!open_com_port(conn,&errcode)) {
netprintf(conn,"\r\n\n");
// signal to quit the menu
conn->menuactive=0;
conn->option_runmenu=0;
return;
} else {
netprintf(conn,"error: cannot open port\r\n\n");
......
netprintf(conn,"info: actual com port closed\r\n\n");
} else if (!strcmp(command, "quit")) {
// quit the connection
conn->menuactive=0;
conn->option_runmenu=0;
closesocket(conn->net);
conn->net=INVALID_SOCKET;
conn->netconnected=0;
return;
} else if (!strcmp(command, "keepalive")) {
conn->option_keepalive=!conn->option_keepalive;
return;
} else if (!strcmp(command, "show_conn_table")) {
int i;
netprintf(conn,
"slot state id Menu mThr Net net netTh Ser serial serialTh Echo netrx nettx\r\n");
"Flags: A - Active Slot, N - Network active, S - Serial active,\r\n"
" M - Run Menu, E - Echo enabled, K - Telnet Keepalives,\r\n"
" * - This connection\r\n"
"\r\n");
netprintf(conn,
"---- ----- -- ---- ---- --- ---- ----- --- ------ -------- ---- ----- -----\r\n");
"s flags id mThr net netTh serial serialTh netrx nettx peer address\r\n");
netprintf(conn,
"- ------ -- ---- ---- ----- ------ -------- ----- ----- ------------\r\n");
for (i=0;i<MAXCONNECTIONS;i++) {
netprintf(conn,
"%-4i %s %2i %s %4i %s %4i %5i %s %6i %8i %s %5i %5i\r\n",
i, connection[i].active?"ACTIV":" ", connection[i].id,
connection[i].menuactive?"YES ":" ",
connection[i].menuThread,
connection[i].netconnected?"OK ":" ",
connection[i].net, connection[i].netThread,
connection[i].serialconnected?"OK ":" ",
connection[i].serial, connection[i].serialThread,
connection[i].option_echo?"YES ":"NO ",
connection[i].net_bytes_rx, connection[i].net_bytes_tx
);
netprintf(conn,"%i%c%c%c%c%c%c%c %2i %4i ",
i,
&connection[i]==conn?'*':' ',
connection[i].active?'A':' ',
connection[i].netconnected?'N':' ',
connection[i].serialconnected?'S':' ',
connection[i].option_runmenu?'M':' ',
connection[i].option_echo?'E':' ',
connection[i].option_keepalive?'K':' ',
connection[i].id,
connection[i].menuThread);
if (connection[i].netconnected) {
netprintf(conn,"%4i %5i ",
connection[i].net,
connection[i].netThread);
} else {
netprintf(conn," ");
}
if (connection[i].serialconnected) {
netprintf(conn,"%6i %8i ",
connection[i].serial,
connection[i].serialThread);
} else {
netprintf(conn," ");
}
netprintf(conn, "%5i %5i ",
connection[i].net_bytes_rx,
connection[i].net_bytes_tx);
if (connection[i].sa) {
/* FIXME - IPv4 Specific */
netprintf(conn,"%s:%i",
inet_ntoa(((struct sockaddr_in*)connection[i].sa)->sin_addr),
htons(((struct sockaddr_in*)connection[i].sa)->sin_port));
}
netprintf(conn, "\r\n");
}
} else if (!strcmp(command, "kill_conn")) {
int connid = check_atoi(parameter1,0,conn,"must specify a connection id\r\n");
......
show_prompt(conn);
FD_ZERO(&set_read);
while (conn->menuactive && conn->netconnected) {
while (conn->option_runmenu && conn->netconnected) {
FD_SET(conn->net,&set_read);
tv.tv_sec = 2;
tv.tv_usec = 0;
......
switch (err) {
case WSAEWOULDBLOCK:
/* ignore */
if (conn->option_keepalive) {
netprintf(conn,"\xff\xf1");
}
continue;
case WSAECONNRESET:
closesocket(conn->net);
conn->net=INVALID_SOCKET;
conn->netconnected=0;
return;
default:
dprintf(1,"wconsd[%i]: run_menu socket error (%i)\n",conn->id,WSAGetLastError());
/* General paranoia about blocking sockets */
......
line[linelen]=0; // ensure string is terminated
process_menu_line(conn,(char*)line);
if (!conn->menuactive) {
if (!conn->option_runmenu) {
/* exiting the menu.. */
return;
}
......
/* basically, if we have exited the net_to_com thread and have
* still got net connectivity, we are in the menu
*/
conn->menuactive=1;
conn->option_runmenu=1;
if ((conn->menuactive && conn->netconnected) || !conn->serialconnected) {
if ((conn->option_runmenu && conn->netconnected) || !conn->serialconnected) {
/* run the menu to ask the user questions */
run_menu(conn);
}
if (!conn->menuactive && conn->netconnected && conn->serialconnected) {
if (!conn->option_runmenu && conn->netconnected && conn->serialconnected) {
/* they must have opened the com port, so start the threads */
PurgeComm(conn->serial,PURGE_RXCLEAR|PURGE_RXABORT);
conn->netThread=CreateThread(NULL,0,wconsd_net_to_com,conn,0,NULL);
......
next_connection_slot = (next_connection_slot+1)%MAXCONNECTIONS;
connection[i].active=1; /* mark this entry busy */
connection[i].id = next_connection_id++;
connection[i].menuactive=1; /* start in the menu */
connection[i].menuThread=NULL;
connection[i].netconnected=1;
connection[i].net=as;
......
connection[i].serialconnected=0;
connection[i].serial=INVALID_HANDLE_VALUE;
connection[i].serialThread=NULL;
connection[i].option_runmenu=1; /* start in the menu */
connection[i].option_echo=0;
connection[i].option_keepalive=0;
connection[i].net_bytes_rx=0;
connection[i].net_bytes_tx=0;
if (connection[i].sa) {
/* Do lazy de-allocation so that the info is
* still visible to show conn table */
free(connection[i].sa);
}
if ((connection[i].sa=malloc(salen))==NULL) {
dprintf(1,"wconsd[%i]: malloc failed\n",
connection[i].id);
} else {
memcpy(connection[i].sa,&sa,salen);
}
dprintf(1,"wconsd[%i]: accepted new connection in slot %i\n",connection[i].id,i);

Also available in: Unified diff