From dbcfea115d50cfb0efce97e0150b62167dfe17e9 Mon Sep 17 00:00:00 2001 From: cvs Date: Fri, 20 Oct 2000 07:00:56 +0000 Subject: [PATCH] New multi-threaded version --- utils/SerPortServer.c | 2557 +++++++++++++++++++++++++++++------------ 1 file changed, 1811 insertions(+), 746 deletions(-) diff --git a/utils/SerPortServer.c b/utils/SerPortServer.c index c9c2fbb3..9cd655c5 100755 --- a/utils/SerPortServer.c +++ b/utils/SerPortServer.c @@ -1,4 +1,4 @@ -#define ident "1A13" +#define ident "1B03" #ifdef __DECC #pragma module SerPortServer ident @@ -9,8 +9,8 @@ ** 1A04 14-Jan-2000 DM. Increase # RS-232-C ports to 20. ** 1A08 3-Apr-2000 DM. Add fortify.h ** 1A10 7-Apr-2000 DM. Change time-out units to 0.2 secs. -** 1A13 13-Sep-2000 DM. Set up time-out each time select is called to be -** Linux compatible. +** 1B01 21-Aug-2000 DM. Handle client requests in parallel and put +** time-out units back to 0.1 secs. ** ** +--------------------------------------------------------------+ ** | Paul Scherrer Institute | @@ -25,22 +25,22 @@ ** Link_options - Here is the Linker Option File **!$ if p1 .eqs. "DEBUG" then dbg1 := /debug **!$ if p1 .eqs. "DEBUG" then dbg2 := _dbg -**!$ link 'dbg1'/exe=SerPortServer'dbg2'.exe sys$input/options -**! SerPortServer +**!$ link 'dbg1'/exe=new_SerPortServer'dbg2'.exe sys$input/options +**! new_SerPortServer **! mad_lib:sinq_dbg/lib **! sys$share:decw$xmlibshr12/share **! sys$share:decw$xtlibshrr5/share **! sys$share:decw$xlibshr/share -**!$ purge/nolog SerPortServer'dbg2'.exe -**!$ set prot=w:re SerPortServer'dbg2'.exe -**!$ write sys$output "Exec file is ''f$environment ("default")'SerPortServer''DBG2'.EXE +**!$ purge/nolog new_SerPortServer'dbg2'.exe +**!$ set prot=w:re new_SerPortServer'dbg2'.exe +**!$ write sys$output "Exec file is ''f$environment ("default")'new_SerPortServer''DBG2'.EXE **!$ exit **!$! **!$! To build on LNSA09 ... **!$! $ import tasmad dev **!$! $ build_cc_select :== decc **!$! $ define/job deltat_c_tlb sinq_c_tlb -**!$! $ bui tas_src:[tests]SerPortServer debug +**!$! $ bui tas_src:[utils]new_SerPortServer debug **!$! ** Link_options_end ** @@ -48,11 +48,11 @@ ** ** setenv TAS_BASE ~maden/tasmad ** source $TAS_BASE/tasmad.setup -** rcp -p "lnsa09:tas_src:[utils]SerPortServer.c" \ -** $TAS_SRC/utils/SerPortServer.c -** cc -std -g -o $TAS_BIN/SerPortServer \ +** rcp -p "lnsa09:tas_src:[utils]new_SerPortServer.c" \ +** $TAS_SRC/utils/new_SerPortServer.c +** cc -std -g -o $TAS_BIN/new_SerPortServer \ ** -I$TAS_INC \ -** $TAS_SRC/utils/SerPortServer.c \ +** $TAS_SRC/utils/new_SerPortServer.c \ ** -L$TAS_LIB -lsinq -lXm -lXt -lX11 ** ** Resources and Options File: decw$user_defaults:SinQ_rc.dat @@ -102,6 +102,36 @@ ** $ SerPortServer -ts -port ** **==================================================================== +** Clients send packets of commands to SerPortServer. These packets consist +** of zero or more commands to a serial port. The commands are sent and +** the responses are read. The responses are packed up ito a response packet +** which is sent to the client when complete. See rs232c_def.h for a description +** of the packet structure. +** +** If an error is detected, the field n_rply in the response packet is set +** to "-001" and the field u.sub_status may take one of the values: +** "-00000000001" if field n_cmnds is a non-decimal ASCII string. +** "-00000000002" if field n_cmnds is illegal. +** "-00000000003" if runaway command list. +** "-00000000004" if non-decimal ASCII command length. +** "-00000000005" if illegal command length. +** "-00000000006" if bad status from send. +** "-00000000007" if request aborted while in pending list. +** "-00000000008" if field serial_port is illegal. +** "-00000000009" if command list execution terminated because another request +** has been received from this client before this one +** was completed. +** "-00000000010" if the request timed out whilst still on the pending queue +** for the specified channel. +** "-00000000011" if command list execution terminated via . +** "-00000000012" if the terminal server IP address is not known. +** "-00000000014" if TS socket create failed. +** "-00000000015" if TS socket bind failed. +** "-00000000016" if TS socket connect failed. +** "-00000000017" if no more TS indices available. +** "-00000000018" if runaway pending list. +** "000000005001" if protocol level mismatch. +**==================================================================== */ #include #include @@ -112,12 +142,16 @@ #include #include +#include #ifdef __VMS #include - #include + #include + #include + #include #else #include + #include #ifdef FORTIFY #include #endif @@ -134,79 +168,176 @@ ** Define global structures and constants. */ #include +#ifdef __VMS + int sys$gettim (int *time, ...); +#endif #define RS__MAX_CLIENTS 8 /* Up to 8 clients will be supported */ #define RS__MAX_ASYNCH 20 /* Asynch "ports" 0 - 19 will be allowed */ +#define MAX_OPEN_CHANS RS__MAX_ASYNCH -#define IN 1 -#define OUT 2 -#define ERROR 3 -#define OPEN 4 -#define CLOSE 5 -#define TMO 6 -#define FLUSH 7 - +#define MAX_PKT_SIZE 10000 /* The SerPortServer packet protocol has a + ** 4 char ASCII header giving the packet length. + ** The max packet size is therefore 9999. + */ #define NIL '\0' + + enum ACTION { + IN, + OUT, + ERROR, + OPEN, + CLOSE, + TMO, + FLUSH}; + + enum CL_SKT_STATUS { + CL_SS_IDLE, + CL_SS_BUSY, + CL_SS_PENDING}; + + enum TS_SKT_STATUS { + TS_SS_IDLE = -1}; /*------------------------------------------------------------- ** Prototypes of Routines in this File */ - void chanFlush ( - int chan); - void ctrlC_Handler ( + void abortPending ( + int indx); + void addToBuffer ( + char byte, + char *buff, + int b_size, + int *nxt); + void addToPendList ( + int ts_indx, + int cl_indx); + void chanFlush ( + int indx); + void closeClient ( + int indx); + void closeTs ( + int indx); + void ctrlC_Handler ( int sigint); - int handleUserRequest ( - struct RS__MsgStruct *msg, - int msg_size, - struct RS__RespStruct *rply, - int rply_len); - int lookForTerm ( + void freeAll (); + void getCurrentTime ( + struct timeval *time_now); + void handleClientRecv ( + int indx); + void handlePendTmo ( + int indx); + void handleTmo ( + int indx); + void handleTsRecv ( + int indx); + int lookForTerm ( int *len, char *term, int nterm, char *terms, char *buff, - char *buff_end); - int open_RS232C_Chan ( - int chan, + int nch); + int open_RS232C_Chan ( + char *server, + int chan, struct RS__RespStruct *rply); - int setupSocket ( - int port); - char *setupTime ( + void sendCmndToTs ( + int ts_indx, + int cl_indx); + int setupErrReply ( + struct RS__RespStruct *rply, + char *msg_id, + char *sub_status); + void setupNewClient ( + int skt); + int setupSocket ( + int port); + char *setupTime ( char *buff, int buff_size); - int setupXrmDatabase ( + int setupXrmDatabase ( XrmDatabase *db, char *name[], int *argc, char *argv[]); - void traceAdd ( + void startUserRequest ( + int indx); + float subtractTimes ( + struct timeval time0, + struct timeval time1); + void traceAdd ( int n_txt, char *txt); - void traceDo ( - char prefix, - int indx, - int in_or_out, - int n_txt, - char *txt); - void traceWrite (); + void traceDo ( + char prefix, + int indx, + enum ACTION in_or_out, + int n_txt, + char *txt); + void traceWrite (); + void USR1_Handler ( + int sigint); /*------------------------------------------------------------- ** Global Variables */ static int Inet_port; /* TCP/IP Port number for listening */ - static int Cnct_skt; /* Base socket for "accept" */ - static int Client_skts[RS__MAX_CLIENTS]; /* Client sockets */ - static int Client_port[RS__MAX_CLIENTS]; /* Client ports */ - static char Client_host[RS__MAX_CLIENTS][32]; /* Client hosts */ - static int Skt_mask = 0; /* Mask for "select" */ - static int Max_skt = 0; /* Max socket to check by "select" */ - static char Ts_name[32]; /* Name of Terminal Server */ - static int Ts_skts[RS__MAX_ASYNCH]; /* Sockets for the TS channels */ - static int Ts_ports[RS__MAX_ASYNCH]; /* Ports of the TS channels */ - static int Ts_mask[RS__MAX_ASYNCH]; /* Masks for "select" */ - static char Ts_buff[RS__MAX_ASYNCH][512]; /* Buffers for each channel */ - static char *Ts_nxt[RS__MAX_ASYNCH]; /* Pointer to next char in buff */ - static char *Ts_last[RS__MAX_ASYNCH]; /* Pointer to last char in buff */ - static int Max_ts_skt = 0; /* Max TS socket to check by "select" */ + static int Cnct_skt; /* Base socket for "accept" */ + static fd_set Skt_mask; /* Mask for "select" */ + static int Max_skt = 0; /* Max socket to check by "select" */ + static float Next_tmo_secs; /* Number of secs till next time-out */ + + static char Ts_name[32]; /* Name of Terminal Server */ + + static int N_clients; /* The number of connected clients */ + static int N_open_chans; /* The number of open RS-232-C chans */ + + static struct cl_recd { /* Data structures for the open clients */ + struct RS__MsgStruct *msge; /* Pntr to bufr for msge from client */ + struct RS__RespStruct *rply; /* Pntr to bufr for reply to client */ + enum CL_SKT_STATUS status; /* Status of the connection */ + char host[64]; /* Name of client host */ + int port; /* Client's TCP/IP port number */ + int skt; /* The socket number */ + int pending; /* Index of a pending request */ + struct timeval pend_time; /* Time-stamp if rqst pending */ + int msg_len; /* The length of the data in *msge */ + int pcol_code; /* The Protocol level of *msge */ + char fmt_in[8]; /* The format for decoding */ + char fmt_out[8]; /* The format for encoding */ + int hdr_size; /* The size of header fields (2 or 4) */ + int chan; /* The channel # from *msge */ + int chnx; /* The channel index */ + float tmo; /* Time-out in secs from *msge */ + int nterm; /* # terminators from *msge */ + char terms[4]; /* The terminators from *msge */ + int n_cmnds; /* # cmnds from *msge */ + int n_rplys; /* # replies in from *rply */ + int c_len; /* Len of current cmnd from *msge */ + int msge_size; /* The size of the *msge buffer */ + int rply_size; /* The size of the *rply buffer */ + int remaining; /* # bytes available in *rply */ + char *nxt_cmnd_ptr; /* Pntr to next cmnd in *msge */ + char *nxt_rply_ptr0;/* Pntr to hdr of nxt rply in *rply */ + char *nxt_rply_ptr1;/* Pntr to next byte to fill in *rply */ + } *Cl_info; + + static struct ts_recd { /* Data structures for the open chans */ + enum TS_SKT_STATUS status; /* Status of the connection + ** >= 0 ==> in use by a client. The + ** value is the client's index. + */ + char server[64]; /* Name of terminal server */ + char dot_addr[20]; /* Internet addr of TS in dot format */ + int chan; /* The channel number */ + int port; /* Remote TCP/IP port number */ + int skt; /* The socket number */ + fd_set mask; /* A select mask for the socket */ + char tp_ahd[2048]; /* Type-ahead buffer */ + int tp_nxt; /* Index of next free byte in tp_ahd */ + float tmo; /* Time-out for current cmnd in secs */ + struct timeval time_stamp; /* Time-stamp for current cmnd */ + int pending; /* Index of a pending request */ + } *Ts_info; static int Trace; /* Trace transactions if True */ static int Tr_buf_size = 0x40000; /* Size of trace buffer */ @@ -215,50 +346,288 @@ static unsigned char *Tr_buf_nxt; /* Next free byte in trace bf */ static int Tr_buf_free; /* # free bytes in trace buff */ static int Tr_buf_shuff; /* Trace buffer shuffle value */ - static time_t Tr_timer; /* Trace time-stamp */ + static struct timeval Tr_timer; /* Trace time-stamp */ static int Tr_period = 60; /* Trace time-stamp period */ - static int Ctrl_C_has_happened; /* Set to True when hit */ - static int Ctrl_C_number; /* counter to decide when to exit */ + static int Debug; /* Debug mode if True */ + static int Usr1_has_happened; /* Set to True when USR1 signal detected */ - extern int C_gbl_status; /* Return status from C_... routines */ + static int Ctrl_C_has_happened; /* Set to True when hit */ + static int Ctrl_C_pending; /* True if exit is + ** pending */ + static struct timeval Ctrl_C_time; /* Time-stamp of detection + ** of */ +/* +**--------------------------------------------------------------------------- +** abortPending: Abort any pending requests on a channel. +*/ + void abortPending ( +/* ============ +*/ int indx) { /* The index of the channel */ + + int i, j, status; + + if (Ts_info[indx].pending >= 0) { + i = Ts_info[indx].pending; + Ts_info[indx].pending = -1; + while (i != -1) { + j = setupErrReply (Cl_info[i].rply, + Cl_info[i].msge->msg_id, "-00000000007"); + status = send (Cl_info[i].skt, (char *) Cl_info[i].rply, j, 0); + if (Trace) traceDo ('S', Cl_info[i].skt, ERROR, 16, " sub_status = -7"); + j = Cl_info[i].pending; + Cl_info[i].status = CL_SS_IDLE; + Cl_info[i].pending = -1; + j = i; + } + } + return; + } +/* +**--------------------------------------------------------------------------- +** addToBuffer: Add a byte to the end of a type-ahead buffer. +*/ + void addToBuffer ( +/* =========== +*/ char byte, /* The byte to be added */ + char *buff, /* The buffer start address */ + int b_size, /* The size of the buffer */ + int *nxt) { /* Index of first free byte in buffer */ + + int i; + + if (*nxt >= b_size) { /* Must the buffer be shuffled down? */ + for (i = 1; i < b_size; i++) buff[i-1] = buff[i]; /* Yes */ + *nxt = b_size - 1; + } + buff[*nxt] = byte; + *nxt += 1; + } +/* +**--------------------------------------------------------------------------- +** addToPendList - add a request to pending list +*/ + void addToPendList ( +/* ============= +*/ int ts_indx, /* Term srvr index */ + int cl_indx) { /* Client index of pending request */ + + int i, j, run_away = 0; + + Cl_info[cl_indx].status = CL_SS_PENDING; + Cl_info[cl_indx].pending = -1; + getCurrentTime (&Cl_info[cl_indx].pend_time); + + if (Ts_info[ts_indx].pending == -1) { + Ts_info[ts_indx].pending = cl_indx; + }else { + i = Ts_info[ts_indx].pending; + while ((Cl_info[i].pending != -1) && (run_away < 10)) { + i = Cl_info[i].pending; run_away++; + } + if (Cl_info[i].pending != -1) { + if (Trace) traceDo ('C', Ts_info[ts_indx].chan, ERROR, + 23, " "); + if (Trace) traceDo ('S', Cl_info[cl_indx].skt, ERROR, + 23, " "); + printf (" C:%d S:%d\n", + Ts_info[ts_indx].chan, Cl_info[cl_indx].skt); + j = setupErrReply (Cl_info[cl_indx].rply, + Cl_info[cl_indx].msge->msg_id, "-00000000018"); + send (Cl_info[cl_indx].skt, + (char *) Cl_info[cl_indx].rply, j, 0); + Cl_info[cl_indx].status = CL_SS_IDLE; + return; + } + Cl_info[i].pending = cl_indx; + } + } /* **---------------------------------------------------------------------------*/ void chanFlush ( /* ========= ** Flush out any pending input */ - int chan) { /* The channel to flush */ + int indx) { /* The Ts_info index of channel to flush */ - int i, my_rd_msk, status; + int i, status; + fd_set my_rd_msk; char buff[80]; struct timeval tmo, zero_tmo = {0, 0}; /* ** First flush the type-ahead buffer */ - if ((Trace) && (Ts_nxt[chan] != Ts_last[chan])) { - traceDo ('C', chan, FLUSH, (Ts_last[chan] - Ts_nxt[chan]), Ts_nxt[chan]); + if ((Trace) && (Ts_info[indx].tp_nxt > 0)) { + traceDo ('C', Ts_info[indx].chan, FLUSH, + Ts_info[indx].tp_nxt, Ts_info[indx].tp_ahd); } - Ts_nxt[chan] = Ts_last[chan] = Ts_buff[chan]; + Ts_info[indx].tp_nxt = 0; /* ** Then flush the socket */ - my_rd_msk = Ts_mask[chan]; + my_rd_msk = Ts_info[indx].mask; tmo = zero_tmo; - status = select (Ts_skts[chan]+1, - (fd_set *) &my_rd_msk, NULL, NULL, &tmo); + status = select (Ts_info[indx].skt+1, + &my_rd_msk, NULL, NULL, &tmo); while (status > 0) { - status = recv (Ts_skts[chan], buff, sizeof (buff), 0); - if ((Trace) && (status > 0)) traceDo ('C', chan, FLUSH, status, buff); - - - my_rd_msk = Ts_mask[chan]; + status = recv (Ts_info[indx].skt, buff, sizeof (buff), 0); + if ((Trace) && (status > 0)) traceDo ('C', Ts_info[indx].chan, FLUSH, + status, buff); + my_rd_msk = Ts_info[indx].mask; tmo = zero_tmo; - status = select (Ts_skts[chan]+1, + status = select (Ts_info[indx].skt+1, (fd_set *) &my_rd_msk, NULL, NULL, &tmo); } } /* +**--------------------------------------------------------------------------*/ + void closeClient ( +/* =========== +** Close a client socket and remove the item from the +** Cl_info array and compress the rest. +*/ + int indx) { /* The index of the client to be closed */ + + int i, j; + + if ((indx < 0) || (indx >= N_clients)) return; + /* + ** Ensure that the client is not in any active or pending + ** list and remove it, if so. + */ + for (i = 0; i < N_open_chans; i++) { + if (Ts_info[i].status != TS_SS_IDLE) { + if (Ts_info[i].status == indx) { + Ts_info[i].status = TS_SS_IDLE; + if (Ts_info[i].pending >= 0) { + j = Ts_info[i].pending; + startUserRequest (j); + Ts_info[i].pending = Cl_info[j].pending; /* Move up pending chain */ + while (Cl_info[j].pending >= 0) { + Cl_info[j].pending = Cl_info[Cl_info[j].pending].pending; + j = Cl_info[j].pending; + } + } + } + if (Ts_info[i].pending == indx) { + j = Ts_info[i].pending; + Ts_info[i].pending = Cl_info[j].pending; + } + } + } + for (i = 0; i < N_clients; i++) { + if ((i != indx) && (Cl_info[i].status != CL_SS_IDLE)) { + if (Cl_info[i].pending == indx) { + Cl_info[i].pending = Cl_info[indx].pending; + } + } + } + /*---------------------------------------------*/ + close (Cl_info[indx].skt); + for (i = (indx + 1); i < N_clients; i++) { + memcpy (Cl_info[i-1].msge, Cl_info[i].msge, MAX_PKT_SIZE); + memcpy (Cl_info[i-1].rply, Cl_info[i].rply, MAX_PKT_SIZE); + Cl_info[i-1].status = Cl_info[i].status; + memcpy (Cl_info[i-1].host, Cl_info[i].host, sizeof (Cl_info[i].host)); + Cl_info[i-1].port = Cl_info[i].port; + Cl_info[i-1].skt = Cl_info[i].skt; + Cl_info[i-1].pending = Cl_info[i].pending; + if (Cl_info[i-1].pending > indx) Cl_info[i-1].pending -= 1; + Cl_info[i-1].pend_time = Cl_info[i].pend_time; + Cl_info[i-1].msg_len = Cl_info[i].msg_len; + Cl_info[i-1].pcol_code = Cl_info[i].pcol_code; + strcpy (Cl_info[i-1].fmt_in, Cl_info[i].fmt_in); + strcpy (Cl_info[i-1].fmt_out, Cl_info[i].fmt_out); + Cl_info[i-1].hdr_size = Cl_info[i].hdr_size; + Cl_info[i-1].chan = Cl_info[i].chan; + Cl_info[i-1].chnx = Cl_info[i].chnx; + Cl_info[i-1].tmo = Cl_info[i].tmo; + Cl_info[i-1].nterm = Cl_info[i].nterm; + memcpy (Cl_info[i-1].terms, Cl_info[i].terms, sizeof (Cl_info[i].terms)); + Cl_info[i-1].n_cmnds = Cl_info[i].n_cmnds; + Cl_info[i-1].n_rplys = Cl_info[i].n_rplys; + Cl_info[i-1].c_len = Cl_info[i].c_len; + Cl_info[i-1].msge_size = Cl_info[i].msge_size; + Cl_info[i-1].rply_size = Cl_info[i].rply_size; + Cl_info[i-1].remaining = Cl_info[i].remaining; + Cl_info[i-1].nxt_cmnd_ptr = Cl_info[i].nxt_cmnd_ptr - + ((char *) Cl_info[i].msge - (char *) Cl_info[i-1].msge); + Cl_info[i-1].nxt_rply_ptr0 = Cl_info[i].nxt_rply_ptr0 - + ((char *) Cl_info[i].rply - (char *) Cl_info[i-1].rply); + Cl_info[i-1].nxt_rply_ptr1 = Cl_info[i].nxt_rply_ptr1 - + ((char *) Cl_info[i].rply - (char *) Cl_info[i-1].rply); + } + N_clients--; + + for (i = 0; i < N_open_chans; i++) { + if (Ts_info[i].pending > indx) Ts_info[i].pending -= 1; + } + /* + ** Ensure Max_skt and Skt_mask are up to date + */ + FD_ZERO (&Skt_mask); FD_SET (Cnct_skt, &Skt_mask); + Max_skt = Cnct_skt + 1; + for (i = 0; i < N_open_chans; i++) { + FD_SET (Ts_info[i].skt, &Skt_mask); + if (Ts_info[i].skt >= Max_skt) Max_skt = Ts_info[i].skt + 1; + } + for (i = 0; i < N_clients; i++) { + FD_SET (Cl_info[i].skt, &Skt_mask); + if (Cl_info[i].skt >= Max_skt) Max_skt = Cl_info[i].skt + 1; + } + } +/* +**--------------------------------------------------------------------------*/ + void closeTs ( +/* ======= +** Close a socket and remove the item from the +** Ts_info array and compress the rest. +*/ + int indx) { /* The index of the channel to be closed */ + + int i; + + if ((indx < 0) || (indx >= N_open_chans)) return; + + abortPending (indx); + close (Ts_info[indx].skt); + + for (i = (indx + 1); i < N_open_chans; i++) { + Ts_info[i-1].status = Ts_info[i].status; + memcpy (Ts_info[i-1].server, Ts_info[i].server, + sizeof (Ts_info[i-1].server)); + memcpy (Ts_info[i-1].dot_addr, Ts_info[i].dot_addr, + sizeof (Ts_info[i-1].dot_addr)); + Ts_info[i-1].chan = Ts_info[i].chan; + Ts_info[i-1].port = Ts_info[i].port; + Ts_info[i-1].skt = Ts_info[i].skt; + Ts_info[i-1].mask = Ts_info[i].mask; + memcpy (Ts_info[i-1].tp_ahd, Ts_info[i].tp_ahd, Ts_info[i].tp_nxt); + Ts_info[i-1].tp_nxt = Ts_info[i].tp_nxt; + Ts_info[i-1].tmo = Ts_info[i].tmo; + Ts_info[i-1].time_stamp = Ts_info[i].time_stamp; + Ts_info[i-1].pending = Ts_info[i].pending; + } + N_open_chans--; + + for (i = 0; i < N_clients; i++) { + if (Cl_info[i].chnx > indx) Cl_info[i].chnx -= 1; + } + /* + ** Ensure Max_skt and Skt_mask are up to date + */ + FD_ZERO (&Skt_mask); FD_SET (Cnct_skt, &Skt_mask); + Max_skt = Cnct_skt + 1; + for (i = 0; i < N_open_chans; i++) { + FD_SET (Ts_info[i].skt, &Skt_mask); + if (Ts_info[i].skt >= Max_skt) Max_skt = Ts_info[i].skt + 1; + } + for (i = 0; i < N_clients; i++) { + FD_SET (Cl_info[i].skt, &Skt_mask); + if (Cl_info[i].skt >= Max_skt) Max_skt = Cl_info[i].skt + 1; + } + } +/* **-------------------------------------------------------------------------- ** ctrlC_Handler: Signal handler to detect on keyboard. */ @@ -268,281 +637,610 @@ Ctrl_C_has_happened = True; } /* +**-------------------------------------------------------------------------- +** freeAll: Free all allocated space. +*/ + void freeAll () { +/* ======= +*/ + int i; + + if (Cl_info != NULL) { + for (i = 0; i < RS__MAX_CLIENTS; i++) { + if (Cl_info[i].msge != NULL) free (Cl_info[i].msge); + if (Cl_info[i].rply != NULL) free (Cl_info[i].rply); + Cl_info[i].msge = NULL; Cl_info[i].rply = NULL; + } + free (Cl_info); + Cl_info = NULL; + } + if (Ts_info != NULL) { + free (Ts_info); + Ts_info = NULL; + } + } +/* **--------------------------------------------------------------------------- -** handleUserRequest - respond to user +** getCurrentTime - get current time */ - int handleUserRequest ( -/* ================= -** Handle a user request. + void getCurrentTime ( +/* ============== +*/ struct timeval *time_now) { /* Return value */ + +#ifdef __VMS + int my_time_now[2]; + + sys$gettim (my_time_now); + time_now->tv_sec = my_time_now[0]; + time_now->tv_usec = my_time_now[1]; +#else + gettimeofday (time_now, NULL); +#endif + } +/* +**---------------------------------------------------------------------------*/ + void handleClientRecv ( +/* ================ +** A recv from a client is pending. Handle it. */ - struct RS__MsgStruct *msg, /* The user's request */ - int msg_size, /* The request size */ - struct RS__RespStruct *rply, /* Buffer for forming reply */ - int rply_len) { /* Size of reply buffer in - ** (to allow for variable - ** length buffers in - ** RS__RespStruct. - */ - /* Return value is number of bytes which have been stored in rply, - ** including the 4 header bytes which give the length of the remainder - ** of rply, rounded up to a multiple of 4. The 4 header bytes in - ** rply will have been set to the ASCII coded value of (return_val - 4). - ** - ** If an error is detected, rply->n_rply is "-001" and - ** rply->u.sub_status may take the values: - ** "-00000000001" if Non-decimal ASCII msg->n_cmnds. - ** "-00000000002" if Illegal msg->n_cmnds. - ** "-00000000003" if runaway command list. - ** "-00000000004" if Non-decimal ASCII command length. - ** "-00000000005" if illegal command length. - ** "-00000000006" if bad status from send. - ** "-00000000007" if bad recv length. - ** "-00000000008" if Bad msg->serial_port. - ** "-00000000009" if Error opening connection to serial port - the - ** appropriate environment variable is not defined. - ** "-00000000010" if Error opening connection to serial port - the - ** environment variable is badly defined. - ** "000000005001" if Protocol Level mismatch. - */ - int status, i, j, chan, io_chan, hdr_size, pcol_code; - int ncmnds, nterm, rply_size, remaining, bytes_got; - int my_rd_msk, c_len, term_fnd, max_bytes, tmo_detected; - int zero = 0; - char terms[4], my_term, *fmt_in, *fmt_out, *nxt_pntr; - struct timeval tmo, tmo_set; - char *nxt_cmnd_ptr; - char *nxt_rply_ptr; - char buff[16]; + int indx) { /* In -- Client index of pending recv */ - /* Set up a null error reply */ - strcpy (rply->msg_size, "0024"); - strcpy (rply->msg_id, msg->msg_id); - strcpy (rply->s_pcol_lvl, RS__PROTOCOL_ID_V01B); - strcpy (rply->n_rply, "-001"); - strcpy (rply->u.sub_status, "000000000000"); - /*---------------------------------------------- - ** Check protocol level of request. If all zero, give error - ** response silently (AsynSrv_Open is probably trying to - ** establish our level). Otherwise, it must be recognised. - */ - if (memcmp (msg->c_pcol_lvl, &zero, 4) == 0) { - memcpy (rply->n_rply, "0000", 4); /* Protocol level is null. Return - ** "bad protocol level" error. - */ - memcpy (rply->u.sub_status, "000000005001", 12); - return 28; - }else if (memcmp (msg->c_pcol_lvl, RS__PROTOCOL_ID_V01B, 4) == 0) { - pcol_code = RS__PROTOCOL_CODE_V01B; - fmt_in = "%4d"; - fmt_out = "%4.4d"; - hdr_size = 4; - }else if (memcmp (msg->c_pcol_lvl, RS__PROTOCOL_ID, 4) == 0) { - pcol_code = RS__PROTOCOL_CODE; - fmt_in = "%2d"; - fmt_out = "%2.2d"; - hdr_size = 2; - }else { - printf ("handleUserRequest -- bad protocol level: \"%.4s\"\n", - msg->c_pcol_lvl); - memcpy (rply->u.sub_status, "000000005001", 12); - return 28; - } - nxt_cmnd_ptr = (char *) &msg->cmnds; - nxt_rply_ptr = (char *) &rply->u.rplys; - remaining = rply_len; - /*---------------------------------------------- - ** Protocol level seems OK. Continue decyphering the message - */ - if ((sscanf (msg->serial_port, "%4d", &chan) != 1) || - (chan < 0) || - (chan >= RS__MAX_ASYNCH)) { - printf ("handleUserRequest: Bad msg->serial_port.\n"); - memcpy (rply->u.sub_status, "-00000000008", 12); - return 28; - } - - if (sscanf (msg->tmo, "%4d", &tmo_set.tv_usec) != 1) tmo_set.tv_usec = 50; - if (tmo_set.tv_usec < 0) tmo_set.tv_usec = 0; - tmo_set.tv_sec = tmo_set.tv_usec/5; /* Cvt to secs and microsecs from .. */ - tmo_set.tv_usec = (tmo_set.tv_usec - /* .. 0.2 secs */ - 5 * tmo_set.tv_sec) * 100000; - - switch (msg->terms[0]) { - case '0': nterm = 0; break; - case '1': nterm = 1; break; - case '2': nterm = 2; break; - case '3': nterm = 3; break; - default: nterm = 0; - } - if (nterm > 0) memcpy (terms, &msg->terms[1], nterm); - terms[nterm] = '\0'; - - if (sscanf (msg->n_cmnds, "%4d", &ncmnds) != 1) { - printf ("handleUserRequest: Non-decimal ASCII msg->n_cmnds.\n"); - memcpy (rply->u.sub_status, "-00000000001", 12); - return 28; - }else if (ncmnds == 0) { - memcpy (rply->n_rply, "0000", 4); /* Nothing to do!! */ - return 28; - }else if (ncmnds < 0) { - printf ("handleUserRequest: Illegal msg->n_cmnds: %d\n", ncmnds); - memcpy (rply->u.sub_status, "-00000000002", 12); - return 28; - } - - if (Ts_skts[chan] == 0) { + int i, j, status, max_msg_size; + int r_size, bytes_to_come; + int my_errno, my_vaxc_errno; + char buff[120], *p_nxt_byte; /* - ** A connection to the RS-232-C device needs to be opened. - ** Open it. On error, assume reply buffer is all ready to - ** be returned with its error status set up. + ** If there is currently outstanding work for this client, + ** abort it with an error. */ - if (!open_RS232C_Chan (chan, rply)) return 28; - Ts_nxt[chan] = Ts_last[chan] = Ts_buff[chan]; /* Empty type-ah'd buffer */ + if (Cl_info[indx].status != CL_SS_IDLE) { + i = setupErrReply (Cl_info[indx].rply, Cl_info[indx].msge->msg_id, + "-00000000009"); + status = send (Cl_info[indx].skt, (char *) Cl_info[indx].rply, i, 0); + Cl_info[indx].status = CL_SS_IDLE; + if (Trace) traceDo ('S', Cl_info[indx].skt, ERROR, + 16, " sub_status = -9"); } - - tmo_detected = False; - for (i = 0; i < ncmnds; i++) { - if (remaining < (hdr_size + 8)) break; - if ((nxt_cmnd_ptr - msg->serial_port) >= msg_size) { - printf ("handleUserRequest: runaway command list.\n"); - memcpy (rply->u.sub_status, "-00000000003", 12); - return 28; - } - if (sscanf (nxt_cmnd_ptr, fmt_in, &c_len) != 1) { - printf ("handleUserRequest: Non-decimal ASCII command length.\n"); - memcpy (rply->u.sub_status, "-00000000004", 12); - return 28; - } - if ((c_len < 0) || (c_len >= msg_size)) { - printf ("handleUserRequest: illegal command length: %d\n", c_len); - memcpy (rply->u.sub_status, "-00000000005", 12); - return 28; - } - nxt_pntr = &nxt_rply_ptr[hdr_size+1]; /* Get ready for the response */ - remaining -= (hdr_size + 1); - if (tmo_detected) { - /*--------------------- - ** If a time-out has already been detected for this - ** packet of commands, then give ?TMO for the rest. - */ - sprintf (nxt_rply_ptr, fmt_out, 6); - strcpy (nxt_pntr, "?TMO"); - nxt_pntr += 5; - remaining -= 5; - nxt_rply_ptr = nxt_pntr; + /* + ** Call recv to get the client's message. First get the + ** first 4 bytes to see how much more must be read. + */ + max_msg_size = Cl_info[indx].msge_size - + sizeof (Cl_info[indx].msge->msg_size); + status = recv (Cl_info[indx].skt, + Cl_info[indx].msge->msg_size, + sizeof (Cl_info[indx].msge->msg_size), 0); + if (status != sizeof (Cl_info[indx].msge->msg_size)) { + GetErrno (&my_errno, &my_vaxc_errno); + setupTime (buff, sizeof (buff)); + printf ("%s: ", buff); + if (((status == -1) && (errno == EPIPE)) || + (status == 0)) { + printf ("Socket %d --> %s:%d closed.\n", + Cl_info[indx].skt, Cl_info[indx].host, Cl_info[indx].port); + if (Trace) traceDo ('S', Cl_info[indx].skt, CLOSE, 9, " "); + }else if ((status == -1) && (errno == ECONNRESET)) { + printf ("Socket %d --> %s:%d. Connection reset by peer.\n", + Cl_info[indx].skt, Cl_info[indx].host, Cl_info[indx].port); + if (Trace) traceDo ('S', Cl_info[indx].skt, CLOSE, + 26, " "); + }else if (status == -1) { + printf ("Socket %d --> %s:%d. recv error.\n", + Cl_info[indx].skt, Cl_info[indx].host, Cl_info[indx].port); + perror ("handleClientRecv: "); + if (Trace) traceDo ('S', Cl_info[indx].skt, CLOSE, + 24, " "); }else { - /*--------------------- - ** If there is a command to send, flush the input - ** first and then send the command. - */ - if (c_len > 0) { - chanFlush (chan); /* Flush any pending input from device */ - status = send (Ts_skts[chan], &nxt_cmnd_ptr[hdr_size], c_len, 0); - if (status != c_len) { - printf ("handleUserRequest: bad send length: %d %d\n", - c_len, status); - memcpy (rply->u.sub_status, "-00000000006", 12); - if (Trace) traceDo ('C', chan, ERROR, 18, " "); - return 28; + printf ("recv: Did not get full message header on "); + printf ("socket %d.\n", Cl_info[indx].skt); + printf (" Should be: %d. Was: %d. Connection closed.\n", + sizeof (Cl_info[indx].msge->msg_size), status); + if (Trace) traceDo ('S', Cl_info[indx].skt, ERROR, + 30, " "); + } + closeClient (indx); + }else { + Cl_info[indx].msge->msg_size[status] = NIL; /* Terminate msg_size */ + if (sscanf (Cl_info[indx].msge->msg_size, "%d", + &Cl_info[indx].msg_len) != 1) { + printf ("recv: Non-decimal ASCII message size on "); + printf ("socket %d.\n", Cl_info[indx].skt); + printf (" Value received = \"%s\". Connection closed.\n", + Cl_info[indx].msge->msg_size); + closeClient (indx); + }else if (Cl_info[indx].msg_len == -1) { /* Close connection? */ + if (Trace) traceDo ('S', Cl_info[indx].skt, IN, + status, Cl_info[indx].msge->msg_size); + send (Cl_info[indx].skt, "-001", 4, 0); /* Yes */ + if (Trace) { + strcpy (&Cl_info[indx].msge->msg_size[status], " # close connection"); + traceDo ('S', Cl_info[indx].skt, IN, + strlen (Cl_info[indx].msge->msg_size), + Cl_info[indx].msge->msg_size); + } + setupTime (buff, sizeof (buff)); /* Yes */ + printf ("%.15s - Closing socket %d to client %s:%d ...", &buff[4], + Cl_info[indx].skt, Cl_info[indx].host, Cl_info[indx].port); + fflush (NULL); + closeClient (indx); + printf (" done.\n"); + }else if (Cl_info[indx].msg_len == -2) { /* Turn trace on? */ + setupTime (buff, sizeof (buff)); /* Yes */ + printf ("%s: ", buff); + printf ("\"Trace on\" rqst from Socket %d.\n", Cl_info[indx].skt); + if (Tr_buf == NULL) { + Tr_buf = malloc (Tr_buf_size); /* Allocate buf for trace */ + if (Tr_buf != NULL) { + Tr_buf_len = Tr_buf_size; }else { - if (Trace) traceDo ('C', chan, OUT, c_len, &nxt_cmnd_ptr[hdr_size]); + printf (" No buffer space available for tracing!\n"); } } - /*--------------------- - ** Before reading anything more from the terminal - ** server, use anything which might be in the type- - ** ahead buffer. - */ - while (True) { /* Break out via "break" on time-out or - ** terminator found. - */ - term_fnd = lookForTerm (&bytes_got, &my_term, - nterm, terms, Ts_nxt[chan], Ts_last[chan]); - if (bytes_got > remaining) { /* If string too long, .. */ - bytes_got = remaining; /* .. force "terminator-not-fnd" status */ - term_fnd = False; - my_term = NIL; - } - - if (bytes_got > 0) { - memcpy (nxt_pntr, Ts_nxt[chan], bytes_got); - remaining -= bytes_got; - nxt_pntr += bytes_got; - Ts_nxt[chan] += bytes_got; - } - - if (Ts_nxt[chan] == Ts_last[chan]) { /* If T-ahead buffer now empty, */ - Ts_nxt[chan] = Ts_last[chan] = Ts_buff[chan]; /* .. reset it */ - } - - if (term_fnd) { /* Response complete? */ - nxt_rply_ptr[hdr_size] = my_term; /* Yes. finish it off */ - sprintf (buff, fmt_out, (nxt_pntr - nxt_rply_ptr - hdr_size)); - memcpy (nxt_rply_ptr, buff, hdr_size); - nxt_rply_ptr = nxt_pntr; - break; /* And break out of loop */ - }else { /* Response not complete. Try to read some more */ - my_rd_msk = Ts_mask[chan]; - tmo = tmo_set; - status = select (Ts_skts[chan]+1, - (fd_set *) &my_rd_msk, NULL, NULL, &tmo); - if (status <= 0) { /* Time-out or error? */ - if (status < 0) { - perror ("handleUserRequest/select"); - if (Trace) traceDo ('C', chan, ERROR, 31, - "