Revision 4cb40453
Added by Hamish Coleman over 16 years ago
- ID 4cb404539cbd1c232f6957db6796a8ca2d48a1a6
wconsd.c | ||
---|---|---|
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
|
||
#define VERSION "0.2.2"
|
||
#define VERSION "0.2.3"
|
||
|
||
/* Size of buffers for send and receive */
|
||
#define BUFSIZE 1024
|
||
... | ... | |
BYTE com_data=8;
|
||
BYTE com_parity=NOPARITY;
|
||
BYTE com_stop=ONESTOPBIT;
|
||
BOOL com_autoclose=TRUE;
|
||
|
||
int default_tcpport = 23;
|
||
|
||
/* TODO - these buffers are ugly and large */
|
||
char *hostname[BUFSIZE];
|
||
struct hostent *host_entry;
|
||
|
||
/* Service status: our current status, and handle on service manager */
|
||
SERVICE_STATUS wconsd_status;
|
||
SERVICE_STATUS_HANDLE wconsd_statusHandle;
|
||
... | ... | |
return 15;
|
||
}
|
||
|
||
/* FIXME - these values need much more tuning */
|
||
timeouts.ReadIntervalTimeout=20;
|
||
timeouts.ReadTotalTimeoutMultiplier=0;
|
||
timeouts.ReadTotalTimeoutConstant=2000;
|
||
/*
|
||
* Note that this means that the serial to net thread wakes
|
||
* each and ever 50 milliseconds
|
||
*/
|
||
timeouts.ReadTotalTimeoutConstant=50;
|
||
timeouts.WriteTotalTimeoutMultiplier=0;
|
||
timeouts.WriteTotalTimeoutConstant=0;
|
||
if (!SetCommTimeouts(conn->serial, &timeouts)) {
|
||
... | ... | |
*specificError=WSAGetLastError();
|
||
return 12;
|
||
}
|
||
|
||
if (gethostname((char *)hostname,sizeof(hostname))==SOCKET_ERROR) {
|
||
*specificError=WSAGetLastError();
|
||
return 1;
|
||
}
|
||
dprintf(1,"wconsd: Hostname is %s\n",hostname);
|
||
|
||
host_entry=gethostbyname((char *)hostname);
|
||
if (host_entry->h_addrtype!=AF_INET) {
|
||
host_entry=0;
|
||
return 0;
|
||
}
|
||
|
||
dprintf(1,"wconsd: IP Address is %s\n",inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list));
|
||
/* FIXME - enumerate all the IP addresses from the list */
|
||
|
||
return 0;
|
||
}
|
||
|
||
... | ... | |
case 0xf0: /* suboption end */
|
||
case 241: /* NOP */
|
||
case 242: /* Data Mark */
|
||
dprintf(1,"wconsd[%i]: option IAC %i\n",conn->id,buf[1]);
|
||
dprintf(2,"wconsd[%i]: option IAC %i\n",conn->id,buf[1]);
|
||
return 2;
|
||
case 243: /* Break */
|
||
if (conn->serialconnected) {
|
||
dprintf(1,"wconsd[%i]: send break\n",conn->id);
|
||
Sleep(1000);
|
||
SetCommBreak(conn->serial);
|
||
Sleep(1000);
|
||
... | ... | |
}
|
||
return 2;
|
||
case 244: /* Interrupt */
|
||
dprintf(1,"wconsd[%i]: option IAC Interrupt\n",conn->id,buf[1]);
|
||
conn->menuactive=1;
|
||
return 2;
|
||
case 245: /* abort output */
|
||
... | ... | |
}
|
||
return 6;
|
||
case 0xfb: /* WILL */
|
||
dprintf(1,"wconsd[%i]: option IAC WILL %i\n",conn->id,buf[2]);
|
||
dprintf(2,"wconsd[%i]: option IAC WILL %i\n",conn->id,buf[2]);
|
||
return 3;
|
||
case 0xfc: /* WONT */
|
||
dprintf(1,"wconsd[%i]: option IAC WONT %i\n",conn->id,buf[2]);
|
||
... | ... | |
case 0xfd: /* DO */
|
||
switch (buf[2]) {
|
||
case 0x01: /* ECHO */
|
||
dprintf(1,"wconsd[%i]: DO ECHO\n",conn->id);
|
||
dprintf(2,"wconsd[%i]: DO ECHO\n",conn->id);
|
||
conn->option_echo=1;
|
||
break;
|
||
case 0x03: /* suppress go ahead */
|
||
dprintf(1,"wconsd[%i]: DO suppress go ahead\n",conn->id);
|
||
dprintf(2,"wconsd[%i]: DO suppress go ahead\n",conn->id);
|
||
break;
|
||
}
|
||
return 3;
|
||
... | ... | |
conn->option_echo=0;
|
||
break;
|
||
default:
|
||
dprintf(1,"wconsd[%i]: option IAC DONT %i\n",conn->id,buf[2]);
|
||
dprintf(2,"wconsd[%i]: option IAC DONT %i\n",conn->id,buf[2]);
|
||
}
|
||
return 3;
|
||
case 0xff: /* send ff */
|
||
... | ... | |
struct timeval tv;
|
||
OVERLAPPED o={0};
|
||
|
||
dprintf(1,"wconsd[%i]: start wconsd_net_to_com\n",conn->id);
|
||
dprintf(1,"wconsd[%i]: debug: start wconsd_net_to_com\n",conn->id);
|
||
|
||
o.hEvent = writeEvent;
|
||
while (conn->netconnected && conn->serialconnected) {
|
||
... | ... | |
*/
|
||
serial_writefile(conn,&o,buf,size);
|
||
}
|
||
dprintf(1,"wconsd[%i]: finish wconsd_net_to_com\n",conn->id);
|
||
dprintf(1,"wconsd[%i]: debug: finish wconsd_net_to_com\n",conn->id);
|
||
return 0;
|
||
}
|
||
|
||
... | ... | |
|
||
o.hEvent=readEvent;
|
||
|
||
dprintf(1,"wconsd[%i]: start wconsd_com_to_net\n",conn->id);
|
||
dprintf(1,"wconsd[%i]: debug: start wconsd_com_to_net\n",conn->id);
|
||
|
||
while (conn->serialconnected && conn->netconnected) {
|
||
if (!ReadFile(conn->serial,buf,BUFSIZE,&size,&o)) {
|
||
... | ... | |
conn->net_bytes_tx+=size;
|
||
}
|
||
}
|
||
dprintf(1,"wconsd[%i]: finish wconsd_com_to_net\n",conn->id);
|
||
dprintf(1,"wconsd[%i]: debug: finish wconsd_com_to_net\n",conn->id);
|
||
return 0;
|
||
}
|
||
|
||
void send_help(struct connection *conn) {
|
||
netprintf(conn,
|
||
"NOTE: the commands will be changing in the next version\r\n"
|
||
"\r\n"
|
||
"available commands:\r\n"
|
||
"\r\n"
|
||
"NOTE: these commands will change in the next version\r\n\n"
|
||
"available commands:\r\n\n"
|
||
" port speed data parity stop\r\n"
|
||
" help status copyright\r\n"
|
||
" open close autoclose\r\n"
|
||
" show_conn_table kill_conn\r\n"
|
||
" quit\r\n");
|
||
"close - Stop serial communications\r\n"
|
||
"copyright - Print the copyright notice\r\n"
|
||
"data - Set number of data bits\r\n"
|
||
"help - This guff\r\n"
|
||
"kill_conn - Stop a given connection's serial communications\r\n"
|
||
"open - Connect or resume communications with a serial port\r\n"
|
||
"parity - Set the serial parity\r\n"
|
||
"port - Set serial port number\r\n"
|
||
"quit - exit from this session\r\n"
|
||
"show_conn_table - Show the connections table\r\n"
|
||
"speed - Set serial port speed\r\n"
|
||
"status - Show current serial port status\r\n"
|
||
"stop - Set number of stop bits\r\n"
|
||
"\r\n");
|
||
}
|
||
|
||
void show_status(struct connection* conn) {
|
||
/* print the status to the net connection */
|
||
|
||
netprintf(conn, "status:\r\n\n"
|
||
" port=%d speed=%d data=%d parity=%d stop=%d\r\n\n",
|
||
" port=%d speed=%d data=%d parity=%d stop=%d\r\n",
|
||
com_port, com_speed, com_data, com_parity, com_stop);
|
||
|
||
if(conn->serialconnected) {
|
||
netprintf(conn, " state=open autoclose=%d\r\n\n", com_autoclose);
|
||
netprintf(conn, " state=open\r\n\n");
|
||
} else {
|
||
netprintf(conn, " state=closed autoclose=%d\r\n\n", com_autoclose);
|
||
netprintf(conn, " state=closed\r\n\n");
|
||
}
|
||
netprintf(conn," connectionid=%i hostname=%s\r\n\r\n",conn->id,hostname);
|
||
}
|
||
|
||
/*
|
||
... | ... | |
} else if (!strcmp(command, "speed")) { // speed
|
||
com_speed = check_atoi(parameter1,com_port,conn,"must specify a speed\r\n");
|
||
} else if (!strcmp(command, "data")) { // data
|
||
if (!parameter1) {
|
||
netprintf(conn,"Please specify number of data bits {5,6,7,8}\r\n");
|
||
return;
|
||
}
|
||
if (!strcmp(parameter1, "5")) {
|
||
com_data=5;
|
||
} else if (!strcmp(parameter1, "6")) {
|
||
... | ... | |
}
|
||
show_status(conn);
|
||
} else if (!strcmp(command, "parity")) { // parity
|
||
if (!parameter1) {
|
||
netprintf(conn,"Please specify the parity {no,even,odd,mark,space}\r\n");
|
||
return;
|
||
}
|
||
if (!strcmp(parameter1, "no") || !strcmp(parameter1, "0")) {
|
||
com_parity=NOPARITY;
|
||
} else if (!strcmp(parameter1, "even") || !strcmp(parameter1, "2")) {
|
||
... | ... | |
}
|
||
show_status(conn);
|
||
} else if (!strcmp(command, "stop")) {
|
||
if (!parameter1) {
|
||
netprintf(conn,"Please specify the number of stop bits {1,1.5,2}\r\n");
|
||
return;
|
||
}
|
||
if (!strcmp(parameter1, "one") || !strcmp(parameter1, "1")) {
|
||
com_stop=ONESTOPBIT;
|
||
} else if (!strcmp(parameter1, "one5") || !strcmp(parameter1, "1.5")) {
|
||
... | ... | |
show_status(conn);
|
||
} else if (!strcmp(command, "open")) { // open
|
||
DWORD errcode;
|
||
int new = check_atoi(parameter1,com_port,conn,"open default port\r\n");
|
||
int new = check_atoi(parameter1,com_port,conn,"Opening default port\r\n");
|
||
|
||
if (new >= 1 && new <= 16) {
|
||
com_port=new;
|
||
... | ... | |
} else if (!strcmp(command, "close")) { // close
|
||
close_serial_connection(conn);
|
||
netprintf(conn,"info: actual com port closed\r\n\n");
|
||
} else if (!strcmp(command, "autoclose")) { // autoclose
|
||
if (!strcmp(parameter1, "true") || !strcmp(parameter1, "1") || !strcmp(parameter1, "yes")) {
|
||
com_autoclose=TRUE;
|
||
} else if (!strcmp(parameter1, "false") || !strcmp(parameter1, "0") || !strcmp(parameter1, "no")) {
|
||
com_autoclose=FALSE;
|
||
}
|
||
show_status(conn);
|
||
} else if (!strcmp(command, "quit")) {
|
||
// quit the connection
|
||
conn->menuactive=0;
|
||
... | ... | |
} else if (!strcmp(command, "show_conn_table")) {
|
||
int i;
|
||
netprintf(conn,
|
||
"slot A id M mThr N net netTh S serial serialTh E netrx nettx\r\n");
|
||
"slot state id Menu mThr Net net netTh Ser serial serialTh Echo netrx nettx\r\n");
|
||
netprintf(conn,
|
||
"---- - -- - ---- - ---- ----- - ------ -------- - ----- -----\r\n");
|
||
"---- ----- -- ---- ---- --- ---- ----- --- ------ -------- ---- ----- -----\r\n");
|
||
for (i=0;i<MAXCONNECTIONS;i++) {
|
||
netprintf(conn,
|
||
"%-4i %i %2i %i %4i %i %4i %5i %i %6i %8i %i %5i %5i\r\n",
|
||
i, connection[i].active, connection[i].id,
|
||
connection[i].menuactive, connection[i].menuThread,
|
||
connection[i].netconnected, connection[i].net, connection[i].netThread,
|
||
connection[i].serialconnected, connection[i].serial, connection[i].serialThread,
|
||
connection[i].option_echo,
|
||
"%-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,"Connection ID %i serial port closed\r\n",connid);
|
||
} else {
|
||
/* other, unknown commands */
|
||
netprintf(conn,"debug: line='%s', command='%s'\r\n\n",line,command);
|
||
netprintf(conn,"\r\nInvalid Command: '%s'\r\n\r\n",line);
|
||
}
|
||
}
|
||
|
||
void show_prompt(struct connection *conn) {
|
||
netprintf(conn,"%s> ",hostname);
|
||
}
|
||
|
||
void run_menu(struct connection * conn) {
|
||
unsigned char buf[BUFSIZE+5]; /* ensure there is room for our kludge telnet options */
|
||
unsigned char line[MAXLEN];
|
||
... | ... | |
|
||
netprintf(conn,"\r\nwconsd serial port server (version %s)\r\n\r\n",VERSION);
|
||
send_help(conn);
|
||
netprintf(conn,"> ");
|
||
show_prompt(conn);
|
||
|
||
FD_ZERO(&set_read);
|
||
while (conn->menuactive && conn->netconnected) {
|
||
... | ... | |
}
|
||
}
|
||
|
||
netprintf(conn,"> ");
|
||
show_prompt(conn);
|
||
linelen=0;
|
||
continue;
|
||
} else if (buf[i] <0x20) {
|
||
... | ... | |
struct connection * conn = (struct connection*)lpParam;
|
||
|
||
while(conn->netconnected) {
|
||
dprintf(1,"wconsd[%i]: top of menu thread running loop\n",conn->id);
|
||
dprintf(1,"wconsd[%i]: debug: start thread_new_connection loop\n",conn->id);
|
||
|
||
/* basically, if we have exited the net_to_com thread and have
|
||
* still got net connectivity, we are in the menu
|
||
... | ... | |
wait_array[1]=listenSocketEvent;
|
||
|
||
while (run) {
|
||
dprintf(1,"wconsd: top of wconsd_main run loop\n");
|
||
dprintf(1,"wconsd: debug: start wconsd_main loop\n");
|
||
|
||
o=WaitForMultipleObjects(2,wait_array,FALSE,INFINITE);
|
||
|
||
... | ... | |
break;
|
||
}
|
||
|
||
/* getnameinfo does not appear to be supported in my windows build environment */
|
||
#ifdef GETNAMEINFO
|
||
char buf[MAXLEN];
|
||
if (!getnameinfo((struct sockaddr*)&sa,salen,buf,sizeof(buf),NULL,0,0)) {
|
||
#endif
|
||
dprintf(1,"wconsd: new connection from %08x\n",
|
||
htonl(sa.sin_addr.s_addr));
|
||
#ifdef GETNAMEINFO
|
||
} else {
|
||
dprintf(1,"wconsd: new connection from %s\n",
|
||
&buf);
|
||
}
|
||
#endif
|
||
dprintf(1,"wconsd: new connection from %s\n",
|
||
inet_ntoa(sa.sin_addr));
|
||
|
||
/* search for an empty connection slot */
|
||
i=next_connection_slot%MAXCONNECTIONS;
|
||
... | ... | |
connection[i].net_bytes_rx=0;
|
||
connection[i].net_bytes_tx=0;
|
||
|
||
dprintf(1,"wconsd[%i]: accepted new connection slot=%i\n",connection[i].id,i);
|
||
dprintf(1,"wconsd[%i]: accepted new connection in slot %i\n",connection[i].id,i);
|
||
|
||
|
||
/* we successfully accepted the connection */
|
||
... | ... | |
|
||
static void usage(void)
|
||
{
|
||
printf("Usage: wconsd [-i pathname | -r | -d]\n");
|
||
printf("Usage: wconsd [-i pathname | -r | -d | -p port ]\n");
|
||
printf("Just start with no options to start server\n");
|
||
printf(" -i pathname install service 'wconsd'; pathname\n");
|
||
printf(" must be the full path to the binary\n");
|
||
printf(" -r remove service 'wconsd'\n");
|
||
printf(" -d run wconsd in debug mode (in the foreground)\n");
|
||
printf(" -d run wconsd in foreground mode\n");
|
||
printf(" -p port listen on the given port in foreground mode\n");
|
||
}
|
||
|
||
int main(int argc, char **argv)
|
||
... | ... | |
// We are running in debug mode (or any other command-line mode)
|
||
debug_mode=1;
|
||
|
||
dprintf(1,"wconsd: Serial Console server\n");
|
||
dprintf(1,"\nwconsd: Serial Console server (version %s)\n",VERSION);
|
||
dprintf(1," (see http://wob.zot.org/2/wiki/wconsd for more info)\n\n");
|
||
|
||
if (argc>1) {
|
||
if (strcmp(argv[1],"-i")==0) {
|
||
... | ... | |
}
|
||
}
|
||
|
||
dprintf(1,"wconsd: listen on port %i\n",default_tcpport);
|
||
dprintf(1,"wconsd: listening on port %i\n",default_tcpport);
|
||
|
||
// if we have decided to run as a console app..
|
||
if (console_application) {
|
||
int r;
|
||
dprintf(1,"wconsd: Console Application Mode (version %s)\n",VERSION);
|
||
dprintf(1,"wconsd: Foreground mode\n");
|
||
r=wconsd_init(argc,argv,&err);
|
||
if (r!=0) {
|
||
dprintf(1,"wconsd: wconsd_init failed, return code %d [%l]\n",r, err);
|
Also available in: Unified diff
Clean up messages and provide better help information