#define ident "1B04" #ifdef __DECC #pragma module SerPortServer ident #endif /* ** Updates: ** 1A01 26-Apr-1999 DM. Initial version. ** 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. ** 1B01 21-Aug-2000 DM. Handle client requests in parallel and put ** time-out units back to 0.1 secs. ** ** +--------------------------------------------------------------+ ** | Paul Scherrer Institute | ** | SINQ Project | ** | | ** | This software may be used freely by non-profit organizations.| ** | It may be copied provided that the name of P.S.I. and of the | ** | author is included. Neither P.S.I. nor the author assume any | ** | responsibility for the use of this software outside of P.S.I.| ** +--------------------------------------------------------------+ ** ** 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=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 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:[utils]new_SerPortServer debug **!$! ** Link_options_end ** ** Building on Alpha Digital Unix: ** ** setenv TAS_BASE ~maden/tasmad ** source $TAS_BASE/tasmad.setup ** 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/new_SerPortServer.c \ ** -L$TAS_LIB -lsinq -lXm -lXt -lX11 ** ** Resources and Options File: decw$user_defaults:SinQ_rc.dat ** --------------------- or $HOME/SinQ_rc ** ** Resource Option Default Description ** -------- ------ ------- ----------- ** - -name SerPortServer Name to use when looking up the ** resources. The default is the ** image file name. ** *serPortTsName -ts none Name or IP address of Terminal ** Server. ** *serPortServPort -port 4000 TCP/IP port service number. ** *serPortTrace -trace Turn on tracing. ** *serPortTraceSize -tsize 0x40000 (= 256k) Trace buffer size. ** *serPortPeriod -period 60 Period for writing trace time-stamps ** *serPortMax -max 20 Maximum number of serial ports ** to use ** ** A value given via -name will be converted to lowercase before being used. **--------------------------------------------------------------------------- ** Module Name . . . . . . . . : [...MOTIF]SerPortServer.C ** ** Author . . . . . . . . . . : D. Maden ** Date of creation . . . . . . : Apr 1999 ** ** Purpose ** ======= ** SerPortServer is a TCP/IP server program which should accept TCP/IP ** connections from EL734, EL737 or other clients obeying the AsynSrv ** protocol and then transmit requests to an RS232C device connected to ** a Lantronix ETSnnP terminal server. It should provide the same ** functions as the SerPortServer program on the Mac. ** Use: ** === ** 1) Set up the name of the Terminal Server and the TCP/IP port number on ** which this TCP/IP server will listen for connections in the resources ** file (see above). These can also be supplied as an option on the ** command line. ** ** 2) Run the program ** ** $ spawn/nowait/out=nl: run SerPortServer ** ** or, to specify the options on the command line, use a ** DCL foreign command: ** ** $ SerPortServer :== $SerPortServer ** $ 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 #include #include #include #include #include #include #include #include #ifdef __VMS #include #include #include #include #else #include #include #ifdef FORTIFY #include #endif #endif #include #include #include /* **-------------------------------------------------------------------------- ** 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 */ static int RS__MAX_ASYNCH = 20; /* Asynch "ports" 0 - 19 will be allowed */ #define MAX_OPEN_CHANS 20 #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 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); 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, int nch); int open_RS232C_Chan ( char *server, int chan, struct RS__RespStruct *rply); 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 ( XrmDatabase *db, char *name[], int *argc, char *argv[]); 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, 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 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 */ static unsigned char *Tr_buf = NULL; /* Buffer to hold trace info. */ static int Tr_buf_len = 0; /* Length of allo trace buff */ 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 struct timeval Tr_timer; /* Trace time-stamp */ static int Tr_period = 60; /* Trace time-stamp period */ static int Debug; /* Debug mode if True */ static int Usr1_has_happened; /* Set to True when USR1 signal detected */ 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 indx) { /* The Ts_info index of channel to flush */ 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_info[indx].tp_nxt > 0)) { traceDo ('C', Ts_info[indx].chan, FLUSH, Ts_info[indx].tp_nxt, Ts_info[indx].tp_ahd); } Ts_info[indx].tp_nxt = 0; /* ** Then flush the socket */ my_rd_msk = Ts_info[indx].mask; tmo = zero_tmo; status = select (Ts_info[indx].skt+1, &my_rd_msk, NULL, NULL, &tmo); while (status > 0) { 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_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; memmove (&Ts_info[i-1].server, &Ts_info[i].server, sizeof (Ts_info[i-1].server)); memmove (&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; memmove(&Ts_info[i-1].mask,&Ts_info[i].mask,sizeof(fd_set)); memmove (&Ts_info[i-1].tp_ahd, &Ts_info[i].tp_ahd, sizeof(Ts_info[i].tp_ahd)); 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. */ void ctrlC_Handler (int sigint) { /* ============= */ 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; } } /* **--------------------------------------------------------------------------- ** getCurrentTime - get current time */ 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. */ int indx) { /* In -- Client index of pending recv */ 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; /* ** If there is currently outstanding work for this client, ** abort it with an error. */ 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"); } /* ** 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 { 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 { printf (" No buffer space available for tracing!\n"); } } if (Tr_buf != NULL) { Tr_buf_free = Tr_buf_len; Tr_buf_nxt = Tr_buf; Tr_buf_shuff = (Tr_buf_size * 25)/100; /* Shuffle buff by 25% */ Trace = True; StrJoin (buff, sizeof (buff), "Trace on at ", buff); traceAdd (strlen (buff), buff); getCurrentTime (&Tr_timer); /* Initialise trace time stamp */ } if (Trace) { strcpy (&Cl_info[indx].msge->msg_size[status], " # trace on"); traceDo ('S', Cl_info[indx].skt, IN, strlen (Cl_info[indx].msge->msg_size), Cl_info[indx].msge->msg_size); } send (Cl_info[indx].skt, "-002", 4, 0); if (Trace) traceDo ('S', Cl_info[indx].skt, OUT, 4, "-002"); }else if (Cl_info[indx].msg_len == -3) { /* Turn trace off? */ if (Trace) { /* Yes */ strcpy (&Cl_info[indx].msge->msg_size[status], " # trace off"); traceDo ('S', Cl_info[indx].skt, IN, strlen (Cl_info[indx].msge->msg_size), Cl_info[indx].msge->msg_size); } setupTime (buff, sizeof (buff)); printf ("%s: ", buff); printf ("\"Trace off\" rqst from Socket %d.\n", Cl_info[indx].skt); if (Trace) { StrJoin (buff, sizeof (buff), "Trace off at ", buff); traceAdd (strlen (buff), buff); Trace = False; } fflush (NULL); send (Cl_info[indx].skt, "-003", 4, 0); }else if (Cl_info[indx].msg_len == -4) { /* Flush output? */ if (Trace) { /* Yes */ strcpy (&Cl_info[indx].msge->msg_size[status], " # flush output"); traceDo ('S', Cl_info[indx].skt, IN, strlen (Cl_info[indx].msge->msg_size), Cl_info[indx].msge->msg_size); } setupTime (buff, sizeof (buff)); printf ("%s: ", buff); printf ("\"Flush rqst\" from Socket %d.\n", Cl_info[indx].skt); fflush (NULL); if (Trace) traceAdd (7, "Flushed"); send (Cl_info[indx].skt, "-004", 4, 0); if (Trace) traceDo ('S', Cl_info[indx].skt, OUT, 4, "-004"); }else if (Cl_info[indx].msg_len == -5) { /* Write trace? */ if (Trace) { /* Yes */ strcpy (&Cl_info[indx].msge->msg_size[status], " # write trace"); traceDo ('S', Cl_info[indx].skt, IN, strlen (Cl_info[indx].msge->msg_size), Cl_info[indx].msge->msg_size); } setupTime (buff, sizeof (buff)); printf ("%.15s: ", &buff[4]); printf ("\"Write trace\" rqst from Socket %d ...", Cl_info[indx].skt); fflush (NULL); traceWrite (); printf (" ... done.\n"); fflush (NULL); send (Cl_info[indx].skt, "-005", 4, 0); if (Trace) traceDo ('S', Cl_info[indx].skt, OUT, 4, "-005"); }else if (Cl_info[indx].msg_len == -6) { /* Close channels? */ if (Trace) { /* Yes */ strcpy (&Cl_info[indx].msge->msg_size[status], " # close channels"); traceDo ('S', Cl_info[indx].skt, IN, strlen (Cl_info[indx].msge->msg_size), Cl_info[indx].msge->msg_size); } setupTime (buff, sizeof (buff)); printf ("%s: ", buff); printf ("\"Close channels\" rqst from Socket %d ...\n", Cl_info[indx].skt); if (N_open_chans <= 0) { printf (" No RS-232-C channels are open.\n"); }else { for (i = N_open_chans; i > 0; i--) { if (Trace) traceDo ('C', Ts_info[0].chan, CLOSE, 18, " "); printf (" Closing connection to " "channel %d ...\n", Ts_info[0].chan); if (Ts_info[0].status >= 0) { /* Is the channel busy? */ /* Yes, terminate the work in ** progress */ i = Ts_info[0].status; if (Trace) traceDo ('S', Cl_info[i].skt, ERROR, 31, " - Work terminated"); j = setupErrReply (Cl_info[i].rply, Cl_info[i].msge->msg_id, "-00000000011"); status = send (Cl_info[i].skt, (char *) Cl_info[i].rply, j, 0); Cl_info[i].status = CL_SS_IDLE; Ts_info[0].status = TS_SS_IDLE; } closeTs (0); } N_open_chans = 0; } printf (" ... done.\n"); send (Cl_info[indx].skt, "-006", 4, 0); if (Trace) traceDo ('S', Cl_info[indx].skt, OUT, 4, "-006"); }else if ((Cl_info[indx].msg_len <= 0) || (Cl_info[indx].msg_len > max_msg_size)) { if (Trace) traceDo ('S', Cl_info[indx].skt, IN, status, Cl_info[indx].msge->msg_size); printf ("recv: Illegal pending message size on "); printf ("socket %d.\n", Cl_info[indx].skt); printf (" Max is: %d. Received: %d. Connection closed.\n", max_msg_size, Cl_info[indx].msg_len); close (Cl_info[indx].skt); if (Trace) traceDo ('S', Cl_info[indx].skt, ERROR, 14, " "); if (Trace) traceDo ('S', Cl_info[indx].skt, CLOSE, 9, " "); closeClient (indx); }else { bytes_to_come = Cl_info[indx].msg_len; p_nxt_byte = Cl_info[indx].msge->msg_id; while (bytes_to_come > 0) { status = recv (Cl_info[indx].skt, p_nxt_byte, bytes_to_come, 0); if (status <= 0) break; bytes_to_come -= status; p_nxt_byte += status; } if (bytes_to_come != 0) { printf ("recv: Did not get all of expected data on " "socket %d.\n", Cl_info[indx].skt); printf (" Should be: %d. Was: %d. Connection closed.\n", Cl_info[indx].msg_len, (Cl_info[indx].msg_len - bytes_to_come)); if (Trace) traceDo ('S', Cl_info[indx].skt, ERROR, 18, " "); status = send (Cl_info[indx].skt, "-001", 4, 0); if (Trace) traceDo ('S', Cl_info[indx].skt, OUT, 4, "-001"); closeClient (indx); }else { if (Trace) traceDo ('S', Cl_info[indx].skt, IN, Cl_info[indx].msg_len + 4, Cl_info[indx].msge->msg_size); startUserRequest (indx); } } } } /* **--------------------------------------------------------------------------- ** handlePendTmo - a pending client request has timed-out. ** Handle it. */ void handlePendTmo ( /* ============= */ int indx) { /* Index of timed-out client */ int j, n, status, chnx; if (Trace) traceDo ('S', Cl_info[indx].skt, ERROR, 19, " "); /* ** Send the client an error response. */ j = setupErrReply (Cl_info[indx].rply, Cl_info[indx].msge->msg_id, "-00000000010"); status = send (Cl_info[indx].skt, (char *) Cl_info[indx].rply, j, 0); if (status != j) { printf ("send: Bad byte count sent to "); printf ("socket %d.\n", Cl_info[indx].skt); printf (" Should have been: %d\n", j); printf (" Was: %d\n", status); if (Trace) traceDo ('S', Cl_info[indx].skt, ERROR, 16, " "); if (Trace) traceDo ('S', Cl_info[indx].skt, CLOSE, 9, " "); closeClient (indx); return; } /* ** The channel is now idle. */ Cl_info[indx].status = CL_SS_IDLE; /* ** Remove it from the channel's pending linked list. */ chnx = Cl_info[indx].chnx; if (Ts_info[chnx].pending == indx) { Ts_info[chnx].pending = Cl_info[indx].pending; }else { j = Ts_info[chnx].pending; for (n = 0; ((n < 10) && (Cl_info[j].pending != -1)); n++) { if (Cl_info[j].pending == indx) { Cl_info[j].pending = Cl_info[indx].pending; break; } j = Cl_info[j].pending; } } return; } /* **--------------------------------------------------------------------------- ** handleTmo - a channel has timed-out. Handle it. */ void handleTmo ( /* ========= */ int indx) { /* TS channel index of timed-out channel */ int i, j, cl_x, hdr_size, remaining, status; char *nxt, *nxt_rply_ptr0, *nxt_rply_ptr1, buff[16]; if (Trace) traceDo ('C', Ts_info[indx].chan, ERROR, 19, " "); cl_x = Ts_info[indx].status; /* Get index of associated client */ nxt_rply_ptr0 = Cl_info[cl_x].nxt_rply_ptr0; nxt_rply_ptr1 = Cl_info[cl_x].nxt_rply_ptr1; hdr_size = Cl_info[cl_x].hdr_size; remaining = Cl_info[cl_x].remaining; /* ** Close off the current cmnd by prefixing ** it with "?TMO". */ if (remaining >= 4) { /* Room for "?TMO"? */ /* Yes. */ for (nxt = nxt_rply_ptr1; nxt > nxt_rply_ptr0; nxt--) nxt[4] = nxt[0]; memcpy (&nxt_rply_ptr0[hdr_size+1], "?TMO", 4); nxt_rply_ptr1 += 4; remaining -= 4; } *nxt_rply_ptr1++ = NIL; remaining--; /* Terminate the response */ j = nxt_rply_ptr1 - nxt_rply_ptr0 - hdr_size; /* Fill in rply length ** Note that this also sets ** terminator to NIL */ sprintf (nxt_rply_ptr0, Cl_info[cl_x].fmt_out, j); nxt_rply_ptr0 = nxt_rply_ptr1; nxt_rply_ptr1 = &nxt_rply_ptr0[hdr_size+1]; remaining -= (hdr_size + 1); Cl_info[cl_x].n_cmnds--; Cl_info[cl_x].n_rplys++; /* ** Close off all remaining cmnds with "?TMO". */ for (i = 0; i < Cl_info[cl_x].n_cmnds; i++) { if (remaining > 5) { strcpy (nxt_rply_ptr1, "?TMO"); sprintf (nxt_rply_ptr0, Cl_info[cl_x].fmt_out, 6); /* Fill in rply len ** Note that this also sets ** terminator to NIL */ remaining -= (hdr_size + 6); nxt_rply_ptr0 += (hdr_size + 6); nxt_rply_ptr1 = &nxt_rply_ptr0[hdr_size+1]; Cl_info[cl_x].n_rplys++; } } /* ** Set up # of replies */ sprintf (buff, "%04.4d", Cl_info[cl_x].n_rplys); /* Set up # of replies */ memcpy (Cl_info[cl_x].rply->n_rply, buff, 4); /* ** Set up reply length */ j = nxt_rply_ptr0 - Cl_info[cl_x].rply->msg_id; j = (j + 3) & (~3); sprintf (buff, "%04.4d", j); memcpy (Cl_info[cl_x].rply->msg_size, buff, 4); /* ** Send the reply */ j += 4; status = send (Cl_info[cl_x].skt, (char *) Cl_info[cl_x].rply, j, 0); if (status != j) { printf ("send: Bad byte count sent to "); printf ("socket %d.\n", Cl_info[cl_x].skt); printf (" Should have been: %d\n", j); printf (" Was: %d\n", status); if (Trace) traceDo ('S', Cl_info[cl_x].skt, ERROR, 16, " "); if (Trace) traceDo ('S', Cl_info[cl_x].skt, CLOSE, 9, " "); closeClient (cl_x); }else { Cl_info[cl_x].status = CL_SS_IDLE; /* The client is now idle */ } /* ** The channel is now idle, see if there are any pending requests */ Ts_info[indx].status = TS_SS_IDLE; if (Ts_info[indx].pending >= 0) { /* ** There is something pending ... */ cl_x = i = Ts_info[indx].pending; /* ** ... move up the chain of pending requests ... */ Ts_info[indx].pending = Cl_info[i].pending; while (Cl_info[i].pending >= 0) { j = Cl_info[i].pending; Cl_info[i].pending = Cl_info[j].pending; i = j; } /* ** ... and start up the pending request. */ startUserRequest (cl_x); } return; } /* **---------------------------------------------------------------------------*/ void handleTsRecv ( /* ============ ** A recv from a Terminal Server channel is pending. ** Handle it. */ int indx) { /* In -- TS channel index of pending recv */ int i, j, cl_x, status, term_fnd, bytes_got, r_size; char my_term, rcve[512], buff[32], *p_rcve; /* ** If there's anything in type-ahd buff, put this ** in front of what is about to be received. */ r_size = sizeof (rcve); p_rcve = rcve; if (Ts_info[indx].tp_nxt > 0) { i = (Ts_info[indx].tp_nxt > r_size) ? r_size : Ts_info[indx].tp_nxt; memcpy (p_rcve, Ts_info[indx].tp_ahd, i); Ts_info[indx].tp_nxt -= i; if (Ts_info[indx].tp_nxt > 0) { for (j = 0; j < Ts_info[indx].tp_nxt; j++) Ts_info[indx].tp_ahd[j] = Ts_info[indx].tp_ahd[j+i]; } r_size -= i; p_rcve += i; } if (r_size > 0) { j = recv (Ts_info[indx].skt, p_rcve, r_size, 0); if (j <= 0) { /* ** An error status was returned by recv. Report the error, ** shut down any pending work on the channel and close the ** socket to the Terminal Server. */ printf ("handleTsRecv: bad recv length: %d\n", j); if (Trace) traceDo ('C', Ts_info[indx].chan, ERROR, 18, " "); closeTs (indx); /* Close the socket to the channel */ return; } j += (p_rcve - rcve); } /*-------------------------------------------------- ** We got some input. See if it's expected and, if so, put it ** in the buffer for sending to the client. If not, move it ** to the type-ahead buffer for the channel. */ i = Ts_info[indx].status; /* See if channel is "busy" */ if (i < 0) { /* If < 0, it's not. */ for (i = 0; i < j; i++) { /* Channel is not busy, so add to Tp-ahead */ addToBuffer (rcve[i], Ts_info[indx].tp_ahd, sizeof (Ts_info[0].tp_ahd), &Ts_info[indx].tp_nxt); } return; }else { term_fnd = lookForTerm (&bytes_got, &my_term, Cl_info[i].nterm, Cl_info[i].terms, rcve, j); if (bytes_got > Cl_info[i].remaining) { /* If string too long, .. */ bytes_got = Cl_info[i].remaining; /* .. force "terminator-not-fnd" status */ term_fnd = False; my_term = NIL; } if (bytes_got > 0) { memcpy (Cl_info[i].nxt_rply_ptr1, rcve, bytes_got); Cl_info[i].remaining -= bytes_got; Cl_info[i].nxt_rply_ptr1 += bytes_got; if( (j - bytes_got) > 0){ memcpy (Ts_info[indx].tp_ahd, &rcve[bytes_got], (j - bytes_got)); } Ts_info[indx].tp_nxt = j - bytes_got; } if (term_fnd) { /* Response complete? */ sprintf (Cl_info[i].nxt_rply_ptr0, Cl_info[i].fmt_out, /* Yes */ (Cl_info[i].nxt_rply_ptr1 - Cl_info[i].nxt_rply_ptr0 - Cl_info[i].hdr_size)); Cl_info[i].nxt_rply_ptr0[Cl_info[i].hdr_size] = my_term; Cl_info[i].n_rplys++; Cl_info[i].nxt_rply_ptr0 = Cl_info[i].nxt_rply_ptr1; Cl_info[i].nxt_rply_ptr1 = Cl_info[i].nxt_rply_ptr0 + Cl_info[i].hdr_size + 1; Cl_info[i].remaining -= (Cl_info[i].hdr_size + 1); /* ** Move to next cmnd */ Cl_info[i].nxt_cmnd_ptr += (Cl_info[i].hdr_size + Cl_info[i].c_len); Cl_info[i].n_cmnds--; if (Cl_info[i].n_cmnds <= 0) { /* ** No more commands, so send reply to client */ Cl_info[i].status = CL_SS_IDLE; /* The client is now idle */ Ts_info[indx].status = TS_SS_IDLE; /* The channel is now idle */ /* ** Set up # of replies */ sprintf (buff, "%04.4d", Cl_info[i].n_rplys); /* Set up # of replies */ memcpy (Cl_info[i].rply->n_rply, buff, 4); /* ** Set up reply length */ r_size = Cl_info[i].nxt_rply_ptr0 - Cl_info[i].rply->msg_id; r_size = (r_size + 3) & (~3); sprintf (buff, "%04.4d", r_size); memcpy (Cl_info[i].rply->msg_size, buff, 4); /* ** Send the reply */ r_size += 4; status = send (Cl_info[i].skt, (char *) Cl_info[i].rply, r_size, 0); if (status != r_size) { printf ("send: Bad byte count sent to "); printf ("socket %d.\n", Cl_info[i].skt); printf (" Should have been: %d\n", r_size); printf (" Was: %d\n", status); if (Trace) traceDo ('S', Cl_info[i].skt, ERROR, 16, " "); if (Trace) traceDo ('S', Cl_info[i].skt, CLOSE, 9, " "); closeClient (i); } }else { sendCmndToTs (indx, i); } } } /* ** If the channel is now idle, see if there are any pending requests */ if ((Ts_info[indx].status == TS_SS_IDLE) && (Ts_info[indx].pending >= 0)) { /* ** There is something pending ... */ cl_x = i = Ts_info[indx].pending; /* ** ... move up the chain of pending requests ... */ Ts_info[indx].pending = Cl_info[i].pending; while (Cl_info[i].pending >= 0) { j = Cl_info[i].pending; Cl_info[i].pending = Cl_info[j].pending; if(i != j){ i = j; }else { break; } } /* ** ... and start up the pending request. */ startUserRequest (cl_x); } } /* **---------------------------------------------------------------------------*/ int lookForTerm ( /* =========== ** Look for a terminator. Note that NIL is an allowed ** terminator so the normal C library routines are not ** very useful. ** ** Return value is False if no terminator found. */ int *len, /* Out -- The length of string, including ** the terminator (if any) */ char *term, /* Out -- The found terminator (if any) */ int nterm, /* In -- The number of terminators */ char *terms, /* In -- Pntr to string of valid term's */ char *buff, /* In -- Pntr to buffer to search */ int nch) { /* In -- The number of chars in buff */ int i, j, noTerm = -1, nLen = -1; if (nterm <= 0) { *len = nch; /* No terminator. So return complete string */ *term = NIL; return False; }else { /* Search string for a terminator */ for (i = 0; i < nch; i++) { for (j = 0; j < nterm; j++) { if (buff[i] == terms[j]) { /* replace terminator with NIL */ buff[i] = NIL; /* replace terminator with NIL */ noTerm = j; break; } } } *len = i; if (noTerm >= 0 ) { /* Was a terminator found? */ *term = terms[noTerm]; /* Yes. Return it */ *len += 1; /* And include the term in the length */ return True; }else { *term = NIL; /* No */ return False; } } } /* **--------------------------------------------------------------------------*/ int open_RS232C_Chan ( /* ================ ** See if a socket is already open to an RS-232-C ** channel on a Terminal Server. If so simply return its ** data structure index. ** Otherwise, open a connection to the Terminal Server ** channel, set up its data structure and return the ** index to it. ** ** If the connection fails, return -1. */ char *server, /* The name of the TS */ int chan, /* The channel to open */ struct RS__RespStruct *rply) { /* Buffer for forming reply -- ** only an error status is put ** in so we don't need to know ** its length. */ /* ** If an error is detected, this routine will set rply->u.sub_status ** as follows: ** "-00000000012" - the terminal server IP address is not known. ** "-00000000014" - socket create failed. ** "-00000000015" - socket bind failed. ** "-00000000016" - socket connect failed. ** "-00000000017" - no more indices available. **------------------------------------------------------------------ */ int i, status; char old_time_out[4], buff[80]; union { char chars[4]; int val; } time_out; unsigned int oto_status; struct sockaddr_in lcl_sockname; struct sockaddr_in rmt_sockname; struct in_addr rmt_inet_addr; struct in_addr *rmt_inet_addr_pntr; struct hostent *rmt_hostent; int rmt_sockname_len; char *ts_dot_addr; #ifdef __VMS unsigned int oto_len; int tcp_option = UCX$C_TCP_PROBE_IDLE; #else int oto_len; #ifdef LINUX int tcp_option = 0; #else int tcp_option = TCP_KEEPINIT; #endif #endif /*------------------------------------------------------------------ ** See if the channel is already open */ for (i = 0; i < N_open_chans; i++) { if ((strcmp (server, Ts_info[i].server) == 0) && (chan == Ts_info[i].chan)) { return i; /* It is, simply return the index */ } } /*------------------------------------------------------------------ ** Channel is not open. We must open it. */ setupTime (buff, sizeof (buff)); printf ("%.15s - Opening channel %d on %s ", &buff[4], chan, server); fflush (NULL); i = N_open_chans; if (i >= MAX_OPEN_CHANS) { printf ("\nFailed! --" " exceeded maximum # of open channels (%d).\n", MAX_OPEN_CHANS); memcpy (rply->u.sub_status, "-00000000017", 12); if (Trace) traceDo ('C', chan, ERROR, 16, " "); return -1; } /* ** Get the Internet address of the Terminal Server */ rmt_inet_addr.s_addr = inet_addr (server); if (rmt_inet_addr.s_addr != -1) { rmt_inet_addr_pntr = &rmt_inet_addr; }else { rmt_hostent = gethostbyname (server); if (rmt_hostent == NULL) { printf ("\nFailed! --" " Terminal server, \"%s\", is not a known " "Internet address.\n", server); memcpy (rply->u.sub_status, "-00000000012", 12); if (Trace) traceDo ('C', chan, ERROR, 16, " "); return -1; } rmt_inet_addr_pntr = (struct in_addr *) rmt_hostent->h_addr_list[0]; } ts_dot_addr = inet_ntoa (*rmt_inet_addr_pntr); printf ("(%s) ... ", ts_dot_addr); fflush (NULL); Ts_info[i].status = TS_SS_IDLE; Ts_info[i].pending = -1; StrJoin (Ts_info[i].server, sizeof (Ts_info[i].server), server, ""); StrJoin (Ts_info[i].dot_addr, sizeof (Ts_info[i].dot_addr), ts_dot_addr,""); Ts_info[i].chan = chan; Ts_info[i].tp_nxt = 0; /* Empty type-ah'd buffer */ /*--------------------------- ** Get the Internet port number of the device on the Terminal Server */ Ts_info[i].port = 3000 + chan; /*--------------------------- ** Create a TCP/IP socket for connecting to server and bind it. */ Ts_info[i].skt = socket (AF_INET, SOCK_STREAM, 0); if (Ts_info[i].skt <= 0) { printf ("failed!\n\n" " Could not create a socket.\n\n"); perror ("open_RS232C_Chan"); memcpy (rply->u.sub_status, "-00000000014", 12); if (Trace) traceDo ('C', chan, ERROR, 16, " "); return -1; } lcl_sockname.sin_family = AF_INET; lcl_sockname.sin_port = htons (0); lcl_sockname.sin_addr.s_addr = 0; status = bind (Ts_info[i].skt, (struct sockaddr *) &lcl_sockname, sizeof (lcl_sockname)); if (status == -1) { close (Ts_info[i].skt); printf ("failed!\n\n" " Could not bind the socket.\n\n"); perror ("open_RS232C_Chan"); memcpy (rply->u.sub_status, "-00000000015", 12); if (Trace) traceDo ('C', chan, ERROR, 16, " "); return -1; } /*--------------------------- ** Set short time-out */ oto_len = sizeof (old_time_out); /* Save current time-out first */ oto_status = getsockopt (Ts_info[i].skt, IPPROTO_TCP, tcp_option, old_time_out, &oto_len); if (oto_status == 0) { time_out.val = 5; /* Set new time-out */ status = setsockopt (Ts_info[i].skt, IPPROTO_TCP, tcp_option, time_out.chars, sizeof (time_out)); } /*--------------------------- ** Connect to Terminal Server */ rmt_sockname_len = sizeof (rmt_sockname); rmt_sockname.sin_family = AF_INET; rmt_sockname.sin_port = htons (Ts_info[i].port); rmt_sockname.sin_addr.s_addr = rmt_inet_addr_pntr->s_addr; status = connect (Ts_info[i].skt, (struct sockaddr *) &rmt_sockname, sizeof (rmt_sockname)); if (status != 0) { close (Ts_info[i].skt); printf ("failed!\n\n" " Could not connect to Terminal Server %s, Port %d.\n\n", server, Ts_info[i].port); perror ("open_RS232C_Chan"); memcpy (rply->u.sub_status, "-00000000016", 12); if (Trace) traceDo ('C', chan, ERROR, 16, " "); return -1; } /*--------------------------- ** Restore time-out */ if (oto_status == 0) { setsockopt (Ts_info[i].skt, IPPROTO_TCP, tcp_option, old_time_out, oto_len); } printf (" done.\n"); FD_ZERO (&Ts_info[i].mask); FD_SET (Ts_info[i].skt, &Ts_info[i].mask); FD_SET (Ts_info[i].skt, &Skt_mask); if (Ts_info[i].skt >= Max_skt) Max_skt = Ts_info[i].skt + 1; N_open_chans++; if (Trace) { sprintf (buff, " ", chan, Ts_info[i].skt, Ts_info[i].port); traceDo ('C', chan, OPEN, strlen (buff), buff); } return i; } /* **--------------------------------------------------------------------------- ** sendCmndToTs - send a command to the Terminal Server */ void sendCmndToTs ( /* ============ */ int ts_indx, /* Term srvr index */ int cl_indx) { /* Client index */ int i, c_len, status, term_fnd, bytes_got, r_size, hdr_size; char my_term, buff[32], *fmt_in, *fmt_out; char *nxt_cmnd_ptr, *nxt_rply_ptr0, *nxt_rply_ptr1; hdr_size = Cl_info[cl_indx].hdr_size; fmt_in = Cl_info[cl_indx].fmt_in; fmt_out = Cl_info[cl_indx].fmt_out; nxt_cmnd_ptr = Cl_info[cl_indx].nxt_cmnd_ptr; nxt_rply_ptr0 = Cl_info[cl_indx].nxt_rply_ptr0; nxt_rply_ptr1 = Cl_info[cl_indx].nxt_rply_ptr1; getCurrentTime (&Ts_info[ts_indx].time_stamp); sscanf (nxt_cmnd_ptr, fmt_in, &c_len); Cl_info[cl_indx].c_len = c_len; if (c_len > 0) { /* If there is a command to send, .. */ chanFlush (ts_indx); /* .. flush the input first. */ status = send (Ts_info[ts_indx].skt, &nxt_cmnd_ptr[hdr_size], c_len, 0); if (status != c_len) { if (status == -1) perror ("sendCmndToTs/send"); printf ("sendCmndToTs: bad send length on channel %d: %d %d\n", Cl_info[cl_indx].chan, c_len, status); memcpy (Cl_info[cl_indx].rply->u.sub_status, "-00000000006", 12); send (Cl_info[cl_indx].skt, (char *) Cl_info[cl_indx].rply, 28, 0); if (Trace) traceDo ('C', Cl_info[cl_indx].chan, ERROR, 34, " "); closeTs (ts_indx); if (Trace) traceDo ('C', Cl_info[cl_indx].chan, CLOSE, 9, " "); Cl_info[cl_indx].status = CL_SS_IDLE; return; } } /* ** If there is anything in the typ-ahead buf, transfer it ** to the client's buffer. */ if (Ts_info[ts_indx].tp_nxt > 0) { term_fnd = lookForTerm (&bytes_got, &my_term, Cl_info[cl_indx].nterm, Cl_info[cl_indx].terms, Ts_info[ts_indx].tp_ahd, Ts_info[ts_indx].tp_nxt); if (bytes_got > Cl_info[cl_indx].remaining) { /* If string too long, .. */ bytes_got = Cl_info[cl_indx].remaining; /* .. force "terminator-not-fnd" status */ term_fnd = False; my_term = NIL; } memcpy (nxt_rply_ptr1, Ts_info[ts_indx].tp_ahd, bytes_got); Cl_info[cl_indx].remaining -= bytes_got; nxt_rply_ptr1 += bytes_got; Ts_info[ts_indx].tp_nxt -= bytes_got; if (Ts_info[ts_indx].tp_nxt > 0) { for (i = 0; i < Ts_info[ts_indx].tp_nxt; i++) Ts_info[ts_indx].tp_ahd[i] = Ts_info[ts_indx].tp_ahd[i+bytes_got]; } if (term_fnd) { /* Response complete? */ sprintf (nxt_rply_ptr0, fmt_out, /* Yes */ (nxt_rply_ptr1 - nxt_rply_ptr0 - hdr_size)); nxt_rply_ptr0[hdr_size] = my_term; Cl_info[cl_indx].n_rplys++; nxt_rply_ptr0 = nxt_rply_ptr1; nxt_rply_ptr1 = &nxt_rply_ptr0[hdr_size+1]; Cl_info[cl_indx].remaining -= (hdr_size + 1); /* ** Move to next cmnd */ nxt_cmnd_ptr += (hdr_size + Cl_info[cl_indx].c_len); Cl_info[cl_indx].n_cmnds--; if (Cl_info[cl_indx].n_cmnds <= 0) { /* ** No more commands, so send reply to client */ Ts_info[ts_indx].status = TS_SS_IDLE; /* The channel is now idle */ Cl_info[cl_indx].status = CL_SS_IDLE; /* The client is now idle */ /* ** Set up # of replies */ sprintf (buff, "%04.4d", Cl_info[cl_indx].n_rplys); /* Set up # of replies */ memcpy (Cl_info[cl_indx].rply->n_rply, buff, 4); /* ** Set up reply length */ r_size = nxt_rply_ptr0 - Cl_info[cl_indx].rply->msg_id; r_size = (r_size + 3) & (~3); sprintf (buff, "%04.4d", r_size); memcpy (Cl_info[cl_indx].rply->msg_size, buff, 4); /* ** Send the reply */ r_size += 4; status = send (Cl_info[cl_indx].skt, (char *) Cl_info[cl_indx].rply, r_size, 0); if (status != r_size) { printf ("send: Bad byte count sent to "); printf ("socket %d.\n", Cl_info[cl_indx].skt); printf (" Should have been: %d\n", r_size); printf (" Was: %d\n", status); if (Trace) traceDo ('S', Cl_info[cl_indx].skt, ERROR, 16, " "); if (Trace) traceDo ('S', Cl_info[cl_indx].skt, CLOSE, 9, " "); closeClient (cl_indx); } Ts_info[ts_indx].status = TS_SS_IDLE; Cl_info[cl_indx].status = CL_SS_IDLE; return; }else { sendCmndToTs (ts_indx, cl_indx); } } } Cl_info[cl_indx].nxt_cmnd_ptr = nxt_cmnd_ptr; Cl_info[cl_indx].nxt_rply_ptr0 = nxt_rply_ptr0; Cl_info[cl_indx].nxt_rply_ptr1 = nxt_rply_ptr1; if (Ts_info[ts_indx].tmo < Next_tmo_secs) Next_tmo_secs = Ts_info[ts_indx].tmo; Ts_info[ts_indx].status = cl_indx; Cl_info[cl_indx].status = CL_SS_BUSY; return; } /* **--------------------------------------------------------------------------- ** setupErrReply - set up a reply with an error status */ int setupErrReply ( /* ============= */ struct RS__RespStruct *rply, char *msg_id, char *sub_status) { strcpy (rply->msg_size, "0024"); memcpy (rply->msg_id, msg_id, sizeof (rply->msg_id)); strcpy (rply->s_pcol_lvl, RS__PROTOCOL_ID_V01B); strcpy (rply->n_rply, "-001"); memcpy (rply->u.sub_status, sub_status, sizeof (rply->u.sub_status)); return 28; } /* **--------------------------------------------------------------------------- ** setupNewClient - accept a new client connection */ void setupNewClient (int skt) { /* ============== */ int rw_skt; char *rmt_host; struct hostent *rmt_host_name; int rmt_port; struct sockaddr_in rmt_sockname; char buff[120]; /*------------------------------------------------ ** Note: ** There seems to be an inconsistency between the prototype ** definitions of the accept function for VMS and Digital Unix. ** This conditional code is a hack to avoid error messages from ** the compiler. */ #ifdef __VMS unsigned int rmt_sockname_len; #else int rmt_sockname_len; #endif /*------------------------------------------------*/ rmt_sockname_len = sizeof (rmt_sockname); rw_skt = accept (Cnct_skt, (struct sockaddr *) &rmt_sockname, &rmt_sockname_len); if (rw_skt <= 0) { FailInet ("SerPortServer: accept error\n"); } rmt_host = inet_ntoa (rmt_sockname.sin_addr); rmt_port = ntohs (rmt_sockname.sin_port); rmt_host_name = gethostbyaddr ((char *) &rmt_sockname.sin_addr, sizeof (rmt_sockname.sin_addr), AF_INET); if (N_clients < RS__MAX_CLIENTS) { Cl_info[N_clients].status = CL_SS_IDLE; StrJoin (Cl_info[N_clients].host, sizeof Cl_info[N_clients].host, "", (rmt_host_name != NULL) ? rmt_host_name->h_name : rmt_host); Cl_info[N_clients].port = rmt_port; Cl_info[N_clients].skt = rw_skt; Cl_info[N_clients].pending = -1; FD_SET (rw_skt, &Skt_mask); if (rw_skt >= Max_skt) Max_skt = rw_skt + 1; setupTime (buff, sizeof (buff)); printf ("%.15s - Connected to client %s:%d via socket %d.\n", &buff[4], Cl_info[N_clients].host, rmt_port, rw_skt); if (Trace) { sprintf (buff, " ", Cl_info[N_clients].host, rmt_port); traceDo ('S', rw_skt, OPEN, strlen (buff), buff); } N_clients++; }else { printf ("accept: Connection to %s:%d rejected.\n", (rmt_host_name != NULL) ? rmt_host_name->h_name : rmt_host, rmt_port); printf (" Client slots exhausted.\n"); close (rw_skt); if (Trace) traceDo ('S', Cnct_skt, ERROR, 16, " "); } } /* **--------------------------------------------------------------------------- ** setupSocket - declare ourselves as TCP/IP server */ int setupSocket (int port) { /* =========== */ int status; int my_skt; /* listener Socket */ int one = 1; struct sockaddr_in lcl_sockname; /*=============================================================== ** Create a TCP/IP socket for receiving connection requests and ** bind it and set it to listen. */ my_skt = socket (AF_INET, SOCK_STREAM, 0); if (my_skt == -1) FailInet ("SerPortServer -- socket error\n"); /* ** Set the socket option to ease rapid re-starting of SerPortServer */ status = setsockopt (my_skt, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof (one)); lcl_sockname.sin_family = AF_INET; lcl_sockname.sin_port = htons (port); lcl_sockname.sin_addr.s_addr = 0; status = bind (my_skt, (struct sockaddr *) &lcl_sockname, sizeof (lcl_sockname)); if (status != 0) FailInet ("SerPortServer -- bind error\n"); status = listen (my_skt, 5); if (status != 0) FailInet ("SerPortServer -- listen error\n"); return my_skt; } /* **--------------------------------------------------------------------------- ** setupTime - get the current time in ASCII */ char *setupTime (char *buff, int buff_size) { /* ========== */ time_t time_now; time_now = time (NULL); /* Get the current time */ StrJoin (buff, buff_size, /* Convert to ASCII and copy to buffer */ asctime (localtime (&time_now)), ""); strtok (buff, "\n"); /* Remove the trailing "\n" character. */ return buff; } /* **--------------------------------------------------------------------------- ** setupXrmDatabase - setup Resource Manager Database */ int setupXrmDatabase ( /* ================ */ XrmDatabase *db, char *name[], int *argc, char *argv[]) { static XrmOptionDescRec opTable[] = { {"-name", ".name", XrmoptionSepArg, (XPointer) NULL}, {"-ts", ".serPortTsName", XrmoptionSepArg, (XPointer) NULL}, {"-port", ".serPortServPort", XrmoptionSepArg, (XPointer) NULL}, {"-trace", ".serPortTrace", XrmoptionNoArg, (XPointer) "1"}, {"-tsize", ".serPortTraceSize", XrmoptionSepArg, (XPointer) NULL}, {"-period", ".serPortPeriod", XrmoptionSepArg, (XPointer) NULL}, {"-debug", ".serPortDebug", XrmoptionNoArg, (XPointer) "1"}, {"-max", ".serPortMax", XrmoptionSepArg, (XPointer) NULL}, }; static char our_name[80] = "Unknown"; /* This holds the program name */ int status, i; char text[80]; char full_nm0[80]; char full_nm1[80]; char *p_fil[10]; char *my_name; char *my_name_last; char *name_type; XrmValue name_value; XrmDatabase cmnd_line_db = NULL; XrmDatabase lcl_db = NULL; /*-----------------------------------------------------*/ status = True; /* Assume success */ our_name[0] = NIL; /* ** Make a list of the databases to be merged, highest priority first. */ #ifdef __VMS p_fil[0] = "decw$user_defaults:SinQ_rc.dat"; p_fil[1] = "decw$group_defaults:SinQ_rc.dat"; p_fil[2] = "decw$system_defaults:SinQ_rc.dat"; p_fil[3] = "mad_dflt:SinQ_rc.dat"; p_fil[4] = "decw$user_defaults:decw$xdefaults.dat"; p_fil[5] = "decw$group_defaults:decw$xdefaults.dat"; p_fil[6] = "decw$system_defaults:decw$xdefaults.dat"; p_fil[7] = "mad_dflt:decw$xdefaults.dat"; p_fil[8] = NULL; if (*argc > 0) { /* Find out what we are called - parse file nm */ my_name = strstr (argv[0], "]"); /* Find end of directory, i.e. "]" */ my_name++; /* Skip over "]" */ if (my_name[0] == '[') { /* Handle possible concealed device */ my_name = strstr (my_name, "]"); my_name++; } StrJoin (our_name, sizeof (our_name), my_name, ""); /* Copy the rest */ strtok (our_name, "."); /* Close it off at "." */ } for (i = 0; our_name[i] != 0; i++) our_name[i] = tolower (our_name[i]); #else p_fil[0] = StrJoin (full_nm0, sizeof (full_nm0), getenv ("HOME"), "/SinQ_rc"); p_fil[1] = "/usr/lib/X11/app-defaults/SinQ_rc"; p_fil[2] = StrJoin (full_nm1, sizeof (full_nm1), getenv ("HOME"), "/.Xdefaults"); p_fil[3] = "/usr/lib/X11/app-defaults/Xdefaults"; p_fil[4] = NULL; if (*argc > 0) { /* Find out what we are called - parse file nm */ /* Find end of directories */ my_name = argv[0] - 1; while (my_name != NULL) { my_name_last = my_name; my_name_last++; my_name = strstr (my_name_last, "/"); } StrJoin (our_name, sizeof (our_name), my_name_last, ""); } #endif /* ** Initialise and combine all databases */ XrmInitialize (); i = 0; while (p_fil[i] != NULL) { status = XrmCombineFileDatabase (p_fil[i], &lcl_db, False); i++; } /* ** See if there's anything specified on cmnd line, incl "name". */ XrmParseCommand (&cmnd_line_db, opTable, XtNumber(opTable), our_name, argc, argv); if (cmnd_line_db != NULL) { /* ** There was at least 1 item on cmnd line. Process the line. ** If -name was specified, adopt it. */ status = XrmGetResource (cmnd_line_db, /* See if a name was specified */ StrJoin (text, sizeof (text), our_name, ".name"), "ProgramName.Values", &name_type, &name_value); if (status) { StrJoin (our_name, sizeof (our_name), name_value.addr, ""); for (i = 0; our_name[i] != 0; i++) our_name[i] = tolower (our_name[i]); printf ("Option list name is \"%s\"\n", our_name); } /* ** Loop over all items in opTable and merge them into database, ** taking care of any possible name changes. */ for (i = 0; i < XtNumber (opTable); i++) { if (strcmp (opTable[i].option, "-name") == 0) continue; status = XrmGetResource (cmnd_line_db, StrJoin (text, sizeof (text), our_name, opTable[i].specifier), "ProgramName.Values", &name_type, &name_value); if (status) { StrJoin (text, sizeof (text), our_name, opTable[i].specifier); XrmPutResource (&lcl_db, text, "String", &name_value); } } } *name = our_name; *db = lcl_db; if (lcl_db == NULL) printf ("Warning -- no resource database found.\n"); XrmDestroyDatabase (cmnd_line_db); return status; } /* **--------------------------------------------------------------------------- ** startUserRequest - respond to user */ void startUserRequest ( /* ================ ** Start the handling of a user request. */ int indx) { /* The index of the client */ /* ** Return value is CL_SS_IDLE if the request has been handled ** completely. Otherwise, the first command of the user's request ** will have been sent to the specified channel and the various ** data structures set-up so that the command will continue to be ** processed in the "select" loop. */ int status, i, rply_size, c_len, chnx; char *nxt_cmnd_ptr; char zero[] = {0, 0, 0, 0}; setupErrReply (Cl_info[indx].rply, /* Set up a null error reply */ Cl_info[indx].msge->msg_id, "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 (Cl_info[indx].msge->c_pcol_lvl, &zero, 4) == 0) { memcpy (Cl_info[indx].rply->n_rply, "0000", 4); /* Protocol level is null. ** Return "bad protocol level" err. */ memcpy (Cl_info[indx].rply->u.sub_status, "000000005001", 12); send (Cl_info[indx].skt, (char *) Cl_info[indx].rply, 28, 0); Cl_info[indx].status = CL_SS_IDLE; return; }else if (memcmp (Cl_info[indx].msge->c_pcol_lvl, RS__PROTOCOL_ID_V01B, 4) == 0) { Cl_info[indx].pcol_code = RS__PROTOCOL_CODE_V01B; strcpy (Cl_info[indx].fmt_in, "%4d"); strcpy (Cl_info[indx].fmt_out, "%4.4d"); Cl_info[indx].hdr_size = 4; }else if (memcmp (Cl_info[indx].msge->c_pcol_lvl, RS__PROTOCOL_ID, 4) == 0) { Cl_info[indx].pcol_code = RS__PROTOCOL_CODE; strcpy (Cl_info[indx].fmt_in, "%2d"); strcpy (Cl_info[indx].fmt_out, "%2.2d"); Cl_info[indx].hdr_size = 2; }else { printf ("startUserRequest -- bad protocol level: \"%.4s\"\n", Cl_info[indx].msge->c_pcol_lvl); memcpy (Cl_info[indx].rply->u.sub_status, "000000005001", 12); send (Cl_info[indx].skt, (char *) Cl_info[indx].rply, 28, 0); Cl_info[indx].status = CL_SS_IDLE; return; } nxt_cmnd_ptr = Cl_info[indx].nxt_cmnd_ptr = (char *) &Cl_info[indx].msge->cmnds; Cl_info[indx].nxt_rply_ptr0 = (char *) Cl_info[indx].rply->u.rplys; Cl_info[indx].nxt_rply_ptr1 = Cl_info[indx].nxt_rply_ptr0 + Cl_info[indx].hdr_size + 1; Cl_info[indx].remaining = Cl_info[indx].rply_size - (Cl_info[indx].nxt_rply_ptr1 - &Cl_info[indx].rply->msg_size[0]); Cl_info[indx].n_rplys = 0; /*---------------------------------------------- ** Protocol level seems OK. Continue decyphering the message */ status = sscanf (Cl_info[indx].msge->serial_port, "%4d", &Cl_info[indx].chan); if ((status != 1) || (Cl_info[indx].chan < 0) || (Cl_info[indx].chan >= RS__MAX_ASYNCH)) { printf ("startUserRequest: Bad Cl_info[indx].msge->serial_port.\n"); if (Trace) traceDo ('S', Cl_info[indx].skt, ERROR, 16, " "); memcpy (Cl_info[indx].rply->u.sub_status, "-00000000008", 12); send (Cl_info[indx].skt, (char *) Cl_info[indx].rply, 28, 0); Cl_info[indx].status = CL_SS_IDLE; return; } if (sscanf (Cl_info[indx].msge->tmo, "%4d", &i) != 1) i = 50; if (i < 0) i = 0; Cl_info[indx].tmo = ((float) i)/10.0; switch (Cl_info[indx].msge->terms[0]) { case '0': Cl_info[indx].nterm = 0; break; case '1': Cl_info[indx].nterm = 1; break; case '2': Cl_info[indx].nterm = 2; break; case '3': Cl_info[indx].nterm = 3; break; default: Cl_info[indx].nterm = 0; } if (Cl_info[indx].nterm > 0) memcpy (Cl_info[indx].terms, &Cl_info[indx].msge->terms[1], Cl_info[indx].nterm); Cl_info[indx].terms[Cl_info[indx].nterm] = NIL; if (sscanf (Cl_info[indx].msge->n_cmnds, "%4d", &Cl_info[indx].n_cmnds) != 1) { printf ("startUserRequest: Non-decimal ASCII " "Cl_info[indx].msge->n_cmnds.\n"); memcpy (Cl_info[indx].rply->u.sub_status, "-00000000001", 12); send (Cl_info[indx].skt, (char *) Cl_info[indx].rply, 28, 0); if (Trace) traceDo ('S', Cl_info[indx].skt, ERROR, 14, " "); Cl_info[indx].status = CL_SS_IDLE; return; }else if (Cl_info[indx].n_cmnds == 0) { memcpy (Cl_info[indx].rply->n_rply, "0000", 4); /* Nothing to do!! */ send (Cl_info[indx].skt, (char *) Cl_info[indx].rply, 28, 0); Cl_info[indx].status = CL_SS_IDLE; return; }else if (Cl_info[indx].n_cmnds < 0) { printf ("startUserRequest: Illegal Cl_info[indx].msge->n_cmnds: %d\n", Cl_info[indx].n_cmnds); memcpy (Cl_info[indx].rply->u.sub_status, "-00000000002", 12); send (Cl_info[indx].skt, (char *) Cl_info[indx].rply, 28, 0); if (Trace) traceDo ('S', Cl_info[indx].skt, ERROR, 14, " "); Cl_info[indx].status = CL_SS_IDLE; return; } /* ** Check the structure of the command list */ for (i = 0; i < Cl_info[indx].n_cmnds; i++) { if ((nxt_cmnd_ptr - Cl_info[indx].msge->msg_id) >= Cl_info[indx].msg_len) { printf ("startUserRequest: runaway command list.\n"); memcpy (Cl_info[indx].rply->u.sub_status, "-00000000003", 12); send (Cl_info[indx].skt, (char *) Cl_info[indx].rply, 28, 0); if (Trace) traceDo ('S', Cl_info[indx].skt, ERROR, 20, " "); Cl_info[indx].status = CL_SS_IDLE; return; } if (sscanf (nxt_cmnd_ptr, Cl_info[indx].fmt_in, &c_len) != 1) { printf ("startUserRequest: Non-decimal ASCII command length.\n"); memcpy (Cl_info[indx].rply->u.sub_status, "-00000000004", 12); send (Cl_info[indx].skt, (char *) Cl_info[indx].rply, 28, 0); if (Trace) traceDo ('S', Cl_info[indx].skt, ERROR, 15, " "); Cl_info[indx].status = CL_SS_IDLE; return; } if ((c_len < 0) || (c_len >= Cl_info[indx].msg_len)) { printf ("startUserRequest: illegal command length: %d\n", c_len); memcpy (Cl_info[indx].rply->u.sub_status, "-00000000005", 12); send (Cl_info[indx].skt, (char *) Cl_info[indx].rply, 28, 0); if (Trace) traceDo ('S', Cl_info[indx].skt, ERROR, 16, " "); Cl_info[indx].status = CL_SS_IDLE; return; } nxt_cmnd_ptr += (Cl_info[indx].hdr_size + c_len); /* Move to next cmnd */ } /* ** The list of commands seems to be OK. Start processing them. ** Find the index of the data structure for the channel. If ** necessary, a socket will be opened. */ chnx = open_RS232C_Chan (Ts_name, Cl_info[indx].chan, Cl_info[indx].rply); if (chnx < 0) { send (Cl_info[indx].skt, (char *) Cl_info[indx].rply, 28, 0); if (Trace) traceDo ('S', Cl_info[indx].skt, ERROR, 23, " "); Cl_info[indx].status = CL_SS_IDLE; return; } Cl_info[indx].chnx = chnx; if (Ts_info[chnx].status == TS_SS_IDLE) { /* If channel is idle ... */ Ts_info[chnx].tmo = Cl_info[indx].tmo; /* .. start processing the .. */ sendCmndToTs (chnx, indx); /* .. commands. */ }else { addToPendList (chnx, indx); /* Otherwise, pend the request */ } } /* **--------------------------------------------------------------------------- ** subtractTimes - subtract two times. Return value ** is time difference in seconds. */ float subtractTimes ( /* ============= */ struct timeval time0, /* The first time */ struct timeval time1) { /* The time to be subtracted */ /* ** Under UNIX, time0 & time1 contain the time of day in secs/microsecs ** since 1970. */ int diff_secs, diff_usec; float val; #ifdef __VMS int my_time0[2], my_time1[2], deltaTime[2]; my_time0[0] = time0.tv_sec; my_time0[1] = time0.tv_usec; my_time1[0] = time1.tv_sec; my_time1[1] = time1.tv_usec; lib$sub_times (my_time0, my_time1, deltaTime); lib$cvtf_from_internal_time (&LIB$K_DELTA_SECONDS_F, &val, deltaTime); #else if (time0.tv_sec > time1.tv_sec) { /* Is delta-Time positive? */ diff_secs = time0.tv_sec - time1.tv_sec; /* Yes */ diff_usec = time0.tv_usec - time1.tv_usec; if (diff_usec < 0) {diff_secs -= 1; diff_usec += 1000000;} }else if (time0.tv_sec == time1.tv_sec) { /* Maybe - anyway, it's < 1sec */ diff_secs = 0; diff_usec = time0.tv_usec - time1.tv_usec; if (diff_usec < 0) {diff_secs = -1; diff_usec += 1000000;} }else { /* delta-Time is negative */ diff_secs = time0.tv_sec - time1.tv_sec; diff_usec = time0.tv_usec - time1.tv_usec; if (diff_usec < 0) {diff_secs -= 1; diff_usec += 1000000;} } val = (float) diff_usec; val /= 1000000; val += (float) diff_secs; #endif return val; } /* **--------------------------------------------------------------------------- ** Add a trace message to the trace buffer */ void traceAdd ( /* ======== */ int n_chars, /* # chars in buffer */ char *buf) { /* The buffer of chars */ int i = n_chars, j; unsigned char *nxt; if (Tr_buf == NULL) return; if (i > 252) i = 252; /* Ensure length fits in 1 byte */ if (i >= (Tr_buf_free - 2)) { /* Must we shuffle the buffer? */ nxt = Tr_buf; /* Yes */ j = 0; while ((*nxt != 0)&&(j < Tr_buf_shuff)) {j += *nxt + 1; nxt += *nxt + 1;} memmove (Tr_buf, nxt, (Tr_buf_len - j)); Tr_buf_free += j; Tr_buf_nxt -= j; if (i >= Tr_buf_free) { /* Double check, in case trace buf is small! */ printf ("Trace buffer shuffle problems, trace turned off!\n"); Trace = False; fflush (NULL); return; } } memcpy (&Tr_buf_nxt[1], buf, i); *Tr_buf_nxt = i; if (i != n_chars) { Tr_buf_nxt[i+1] = '.'; Tr_buf_nxt[i+2] = '.'; Tr_buf_nxt[i+3] = '.'; *Tr_buf_nxt += 3; } Tr_buf_free -= *Tr_buf_nxt; Tr_buf_free--; Tr_buf_nxt += *Tr_buf_nxt; Tr_buf_nxt++; *Tr_buf_nxt = 0; } /* **--------------------------------------------------------------------------- ** Add a message to the trace */ void traceDo ( /* ======= */ char prefix, /* 'C' or 'S' for Chan or Socket */ int indx, /* The channel or socket # */ enum ACTION in_or_out, /* The 'action' to be traced */ int n_txt, /* The # chars in the text */ char *txt) { /* The text */ int i; char *my_buf, *nxt; my_buf = malloc (2 * n_txt + 10); if (my_buf == NULL) return; my_buf[0] = prefix; if ((indx < 0) || (indx > 99)) indx = 99; sprintf (&my_buf[1], "%02d", indx); switch (in_or_out) { case IN: my_buf[3] = '<'; break; case OUT: my_buf[3] = '>'; break; case ERROR: my_buf[3] = 'E'; break; case OPEN: my_buf[3] = 'O'; break; case CLOSE: my_buf[3] = 'C'; break; case TMO: my_buf[3] = 'T'; break; case FLUSH: my_buf[3] = 'F'; break; default: my_buf[3] = '?'; } nxt = &my_buf[4]; for (i = 0; i < n_txt; i++) { *nxt = txt[i]; if (*nxt == '^') {nxt++; *nxt = '^';} if (!isprint (*nxt)) {*nxt++ = '^'; *nxt = txt[i] + '@';} nxt++; } *nxt = NIL; traceAdd (strlen (my_buf), my_buf); free (my_buf); } /* **---------------------------------------------------------------------------*/ void traceWrite () { /* ========== ** Write trace to disk */ FILE *fd; int i; unsigned char *nxt; char buff[40]; if (Tr_buf == NULL) return; #ifdef __VMS fd = fopen ("mad_log:SerPortServer.trace", "wb"); printf (" Writing trace to mad_log:SerPortServer.trace ..."); #else fd = fopen ("/tmp/SerPortServer.trace", "wb"); printf (" Writing trace to /tmp/SerPortServer.trace ..."); #endif fflush (NULL); if (fd != NULL) { nxt = Tr_buf; while (*nxt != 0) { fwrite (&nxt[1], 1, *nxt, fd); fwrite ("\n", 1, 1, fd); nxt += *nxt + 1; } setupTime (buff, sizeof (buff)); fprintf (fd, "%s\n", buff); fprintf (fd, "The listener socket is %d, Port %d\n", Cnct_skt, Inet_port); if (N_clients > 0) { fprintf (fd, "The following client connections are open:\n"); for (i = 0; i < N_clients; i++) fprintf (fd, " Skt %2d --> %s:%d\n", Cl_info[i].skt, Cl_info[i].host, Cl_info[i].port); }else { fprintf (fd, "There are no open client connections.\n"); } if (N_open_chans > 0) { fprintf (fd, "The following channels are open:\n"); for (i = 0; i < N_open_chans; i++) fprintf (fd, " Chan %2d via Skt %2d and Port %4d\n", Ts_info[i].chan, Ts_info[i].skt, Ts_info[i].port); }else { fprintf (fd, "There are no open channels.\n"); } fclose (fd); printf (" done.\n"); }else { printf (" failed to open file!\n"); } } /* **-------------------------------------------------------------------------- ** USR1_Handler: Signal handler to detect USR1 (31) signals. */ void USR1_Handler (int sigint) { /* ============ */ Usr1_has_happened = True; } /* **========================================================================== ** Main line program ** ------------------ */ int main (int argc, char **argv) { /* ============================ */ Widget main_window; /* MainWindow */ char buff[120], *p_nxt_byte; int buff_len; int status, i, j, indx, fds_bits_last = 0; fd_set my_rd_mask; int r_size, bytes_to_come; struct timeval tmo, time_now; pid_t my_pid; int my_errno, my_vaxc_errno; int max_msg_size; char *appName; XrmDatabase my_db; char *type; XrmValue value; /*-----------------------------------------------------------------------*/ setupTime (buff, sizeof (buff)); my_pid = getpid (); printf ("%s - SerPortServer, Ident %s, started. PID = %d/0x%x\n", &buff[4], ident, my_pid, my_pid); /*-------------------------------------------------------------- ** Setup the resource database and look up the resources. */ setupXrmDatabase (&my_db, &appName, &argc, argv); /* - - - - - - - - - - - - - - - - - - - - - - - - -ts */ status = XrmGetResource (my_db, StrJoin (buff, sizeof (buff), appName, ".serPortTsName"), "ProgramName.Values", &type, &value); if (!status) { printf (" Terminal server name not defined via the\n"); printf (" \"serPortTsName\" resource or the\n"); printf (" \"-ts\" option.\n"); printf (" There is no default!\n"); exit (EXIT_FAILURE); } StrJoin (Ts_name, sizeof (Ts_name), value.addr, ""); printf (" Terminal Server to use is %s\n", Ts_name); /* - - - - - - - - - - - - - - - - - - - - - - - - -port */ status = XrmGetResource (my_db, StrJoin (buff, sizeof (buff), appName, ".serPortServPort"), "ProgramName.Values", &type, &value); if (!status || (sscanf (value.addr, "%d", &Inet_port) != 1)) { Inet_port = 4000; printf (" TCP/IP server port number defaulting to %d\n", Inet_port); }else { printf (" TCP/IP server port number = %d\n", Inet_port); } /* - - - - - - - - - - - - - - - - - - - - - - - - -tsize */ status = XrmGetResource (my_db, StrJoin (buff, sizeof (buff), appName, ".serPortTraceSize"), "ProgramName.Values", &type, &value); if (!status || (sscanf (value.addr, "%d", &Tr_buf_size) != 1)) { Tr_buf_size = 0x40000; } /* - - - - - - - - - - - - - - - - - - - - - - - - -trace */ status = XrmGetResource (my_db, StrJoin (buff, sizeof (buff), appName, ".serPortTrace"), "ProgramName.Values", &type, &value); Trace = (status) ? True : False; if (Trace) { Tr_buf = malloc (Tr_buf_size); /* Allocate buffer for tracing */ if (Tr_buf != NULL) { printf (" Tracing is on.\n"); Tr_buf_len = Tr_buf_free = Tr_buf_size; Tr_buf_nxt = Tr_buf; Tr_buf_shuff = (Tr_buf_size * 25)/100; /* Shuffle buff by 25% */ getCurrentTime (&Tr_timer); /* Initialise trace time stamp */ setupTime (buff, sizeof (buff)); traceAdd (strlen (buff), buff); }else { Trace = False; printf (" No buffer space available for tracing!\n"); } } /* - - - - - - - - - - - - - - - - - - - - - - - - -period */ status = XrmGetResource (my_db, StrJoin (buff, sizeof (buff), appName, ".serPortPeriod"), "ProgramName.Values", &type, &value); if (!status || (sscanf (value.addr, "%d", &i) != 1)) { i = 60; } Tr_period = (float) i; /* - - - - - - - - - - - - - - - - - - - - - - - - -debug */ status = XrmGetResource (my_db, StrJoin (buff, sizeof (buff), appName, ".serPortDebug"), "ProgramName.Values", &type, &value); Debug = (status) ? True : False; /* - - - - - - - - - - - - - - - - - - - - - - - - -max */ status = XrmGetResource (my_db, StrJoin (buff, sizeof (buff), appName, ".serPortMax"), "ProgramName.Values", &type, &value); if (!status || (sscanf (value.addr, "%d", &RS__MAX_ASYNCH) != 1)) { RS__MAX_ASYNCH = 20; printf (" Max Serial Lines defaulting to %d\n", RS__MAX_ASYNCH); }else { printf (" Max Serial Lines Taken = %d\n", RS__MAX_ASYNCH); } /*-----------------------------------------------------------------------*/ N_clients = N_open_chans = 0; Cl_info = calloc (RS__MAX_CLIENTS, sizeof (Cl_info[0])); if (Cl_info == NULL) { printf (" Unable to allocate space for Cl_info\n"); exit (EXIT_FAILURE); } for (i = 0; i < RS__MAX_CLIENTS; i++) { Cl_info[i].status = CL_SS_IDLE; Cl_info[i].msge_size = MAX_PKT_SIZE; Cl_info[i].rply_size = MAX_PKT_SIZE; Cl_info[i].msge = calloc (MAX_PKT_SIZE, sizeof (char)); Cl_info[i].rply = calloc (MAX_PKT_SIZE, sizeof (char)); if ((Cl_info[i].msge == NULL) || (Cl_info[i].rply == NULL)) { printf (" Unable to allocate space for Cl_info[%d].msge or" " Cl_info[%d].rply\n", i, i); freeAll (); exit (EXIT_FAILURE); } } Ts_info = calloc (RS__MAX_ASYNCH, sizeof (Ts_info[0])); if (Ts_info == NULL) { printf (" Unable to allocate space for Ts_info\n"); freeAll (); exit (EXIT_FAILURE); } for (i = 0; i < RS__MAX_ASYNCH; i++) Ts_info[i].status = TS_SS_IDLE; /*-----------------------------------------------------------------------*/ printf (" Creating RS-232-C Server Socket ...\n"); Cnct_skt = setupSocket (Inet_port); /*-----------------------------------------------------------------------*/ printf (" RS-232-C Server ready. Waiting for work ...\n"); FD_ZERO (&Skt_mask); FD_SET (Cnct_skt, &Skt_mask); Max_skt = Cnct_skt + 1; /* ** Declare a signal handler to catch so that we ** can exit cleanly. */ Ctrl_C_has_happened = False; Ctrl_C_pending = False; signal (SIGINT, ctrlC_Handler); /* SIGINT is signal #2 */ signal (SIGTERM, ctrlC_Handler); /* SIGTERM is signal #15 */ /* ** Declare a signal handler to catch USR1 signals. These ** cause the trace to be written to disk. */ Usr1_has_happened = False; signal (SIGUSR1, USR1_Handler); /* SIGUSR1 is signal #31 */ /*-------------------------------------------------------- ** Poll looking for work: accepts, reads or exceptions. ** Each time, check for signals (= SIGINT/SIGTERM) ** and USR1 signals too and handle them. */ Next_tmo_secs = 1.0; /* Time-out is 1 sec by default. It can be ** shorter if client requests need it to be. */ for (;;) { fflush (NULL); #ifdef LINUX #define fds_bits __fds_bits #endif /* Linux */ if (Debug && (Skt_mask.fds_bits[0] != fds_bits_last)) { printf ("Skt_mask.fds_bits[0] is now 0x%04x\n", Skt_mask.fds_bits[0]); fds_bits_last = Skt_mask.fds_bits[0]; } tmo.tv_sec = (int) Next_tmo_secs; /* Set up the time-out */ tmo.tv_usec = (int) ((Next_tmo_secs - (float) tmo.tv_sec) * 1000000.0); my_rd_mask = Skt_mask; status = select (Max_skt, &my_rd_mask, NULL, NULL, &tmo); Next_tmo_secs = 1.0; if (status < 0) { /* Select error? */ if (errno != EINTR) { /* Yes. Ignore signal ** interrupts of select */ FailInet ("SerPortServer: select error.\n"); } }else if (status > 0) { /* Look for pending new client */ if (FD_ISSET (Cnct_skt, &my_rd_mask)) { status--; setupNewClient (Cnct_skt); } /* Look for pending recv's from TS */ for (i = 0; (i < N_open_chans) && (status > 0); i++) { if (FD_ISSET (Ts_info[i].skt, &my_rd_mask) != 0) { handleTsRecv (i); status--; } } /* Look for pending recv's from Clients */ for (i = 0; (i < N_clients) && (status > 0); i++) { if (FD_ISSET (Cl_info[i].skt, &my_rd_mask) != 0) { handleClientRecv (i); status--; } } } /* ** Check all active channels for time-out */ getCurrentTime (&time_now); for (i = 0; i < N_open_chans; i++) { if (Ts_info[i].status != TS_SS_IDLE) { if (subtractTimes (time_now, Ts_info[i].time_stamp) >= Ts_info[i].tmo) { subtractTimes(time_now, Ts_info[i].time_stamp); printf("TMO: Difference: %f, allowed %f\n", subtractTimes(time_now, Ts_info[i].time_stamp), Ts_info[i].tmo); handleTmo (i); /* This channel has timed-out! */ } } } /* ** Check all pending clients for time-out */ for (i = 0; i < N_clients; i++) { if (Cl_info[i].status == CL_SS_PENDING) { if (subtractTimes (time_now, Cl_info[i].pend_time) >= Cl_info[i].tmo) { handlePendTmo (i); /* This pending client request has timed-out! */ } } } if ((Trace) && (subtractTimes (time_now, Tr_timer) > Tr_period)) { setupTime (buff, sizeof (buff)); memcpy (&buff[5], "===== ", 6); traceAdd (14, &buff[5]); Tr_timer = time_now; } if (Ctrl_C_has_happened) { /* Check for (= SIGINT/SIGTERM) */ /* detected. ** If any RS-232-C channels are open, close them and ** start a timer. ** If no RS-232-C channels are open, see if a timer is ** active. Exit if it's less than 5 secs since ** previous . */ Ctrl_C_has_happened = False; setupTime (buff, sizeof (buff)); printf ("%.15s - detected ...\n", &buff[4]); if (N_open_chans <= 0) { printf (" No RS-232-C channels were open.\n"); if (Ctrl_C_pending) { if (subtractTimes (time_now, Ctrl_C_time) < 5.0) { printf (" SerPortServer closing down ...\n"); if (N_clients <= 0) { printf (" No client connections were open.\n"); }else { for (i = N_clients; i > 0; i--) { printf (" Closing client socket %d --> %s:%d ...\n", Cl_info[0].skt, Cl_info[0].host, Cl_info[0].port); closeClient (0); } printf (" All client sockets closed.\n"); } printf (" Closing listener socket %d ...\n", Cnct_skt); if (Trace) { setupTime (buff, sizeof (buff)); StrJoin (buff, sizeof(buff), buff, ": SerPortServer terminating"); traceAdd (strlen (buff), buff); traceWrite (); } close (Cnct_skt); Cnct_skt = 0; freeAll (); printf (" SerPortServer exiting.\n"); exit (EXIT_SUCCESS); } } }else { while (N_open_chans > 0) { if (Trace) traceDo ('C', Ts_info[0].chan, CLOSE, 18, " detected"); printf (" Closing connection to channel %d ...\n", Ts_info[0].chan); if (Ts_info[0].status >= 0) { /* Is the channel busy? */ /* Yes, terminate the work in ** progress */ indx = Ts_info[0].status; if (Trace) traceDo ('S', Cl_info[indx].skt, ERROR, 27, " - Work terminated"); j = setupErrReply (Cl_info[indx].rply, Cl_info[indx].msge->msg_id, "-00000000011"); status = send (Cl_info[indx].skt, (char *) Cl_info[indx].rply, j, 0); Cl_info[indx].status = CL_SS_IDLE; Ts_info[0].status = TS_SS_IDLE; } closeTs (0); } N_open_chans = 0; printf (" All RS-232-C channels closed.\n"); } if (Trace) traceWrite (); Ctrl_C_pending = True; Ctrl_C_time = time_now; printf (" Hit again fairly soon to quit program.\n"); signal (SIGINT, ctrlC_Handler); /* Re-enable signal */ signal (SIGTERM, ctrlC_Handler); /* Re-enable signal */ }else { if (Ctrl_C_pending) { /* No detected. If a was ** detected recently, see if the time-out ** has elapsed. */ if (subtractTimes (time_now, Ctrl_C_time) >= 5.0) { Ctrl_C_pending = False; /* The time-out has elapsed. */ printf (" time has expired.\n"); } } } if (Usr1_has_happened) { Usr1_has_happened = False; setupTime (buff, sizeof (buff)); if (Tr_buf != NULL) { printf ("%.15s - USR1 signal detected. Write trace to disk.\n", &buff[4]); traceWrite (); }else { printf ("%.15s - USR1 signal detected. There is no trace buffer.\n", &buff[4]); } fflush (NULL); signal (SIGUSR1, USR1_Handler); /* Re-enable USR1 signal */ } } } /*------------------------------------------------- End of SerPortServer.C */