Files
sics/utils/SerPortServer.c
2000-09-13 14:30:14 +00:00

1498 lines
55 KiB
C
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#define ident "1A13"
#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.
** 1A13 13-Sep-2000 DM. Set up time-out each time select is called to be
** Linux compatible.
**
** +--------------------------------------------------------------+
** | 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=SerPortServer'dbg2'.exe sys$input/options
**! 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
**!$ 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
**!$!
** Link_options_end
**
** Building on Alpha Digital Unix:
**
** 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 \
** -I$TAS_INC \
** $TAS_SRC/utils/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
**
** 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 <directory>SerPortServer
**
** or, to specify the options on the command line, use a
** DCL foreign command:
**
** $ SerPortServer :== $<directory>SerPortServer
** $ SerPortServer -ts <TS-name> -port <port-number>
**
**====================================================================
*/
#include <stdlib.h>
#include <stdio.h>
#include <netdb.h>
#include <signal.h>
#include <ctype.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/time.h>
#ifdef __VMS
#include <ucx$inetdef.h>
#include <sys/unixio.h>
#else
#include <unistd.h>
#ifdef FORTIFY
#include <fortify/fortify.h>
#endif
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <X11/Intrinsic.h>
/*
**--------------------------------------------------------------------------
** Define global structures and constants.
*/
#include <sinq_prototypes.h>
#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 IN 1
#define OUT 2
#define ERROR 3
#define OPEN 4
#define CLOSE 5
#define TMO 6
#define FLUSH 7
#define NIL '\0'
/*-------------------------------------------------------------
** Prototypes of Routines in this File
*/
void chanFlush (
int chan);
void ctrlC_Handler (
int sigint);
int handleUserRequest (
struct RS__MsgStruct *msg,
int msg_size,
struct RS__RespStruct *rply,
int rply_len);
int lookForTerm (
int *len,
char *term,
int nterm,
char *terms,
char *buff,
char *buff_end);
int open_RS232C_Chan (
int chan,
struct RS__RespStruct *rply);
int setupSocket (
int port);
char *setupTime (
char *buff,
int buff_size);
int setupXrmDatabase (
XrmDatabase *db,
char *name[],
int *argc,
char *argv[]);
void traceAdd (
int n_txt,
char *txt);
void traceDo (
char prefix,
int indx,
int in_or_out,
int n_txt,
char *txt);
void traceWrite ();
/*-------------------------------------------------------------
** 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 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 time_t Tr_timer; /* Trace time-stamp */
static int Tr_period = 60; /* Trace time-stamp period */
static int Ctrl_C_has_happened; /* Set to True when <Ctrl-C> hit */
static int Ctrl_C_number; /* <Ctrl-C> counter to decide when to exit */
extern int C_gbl_status; /* Return status from C_... routines */
/*
**---------------------------------------------------------------------------*/
void chanFlush (
/* =========
** Flush out any pending input
*/
int chan) { /* The channel to flush */
int i, my_rd_msk, status;
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]);
}
Ts_nxt[chan] = Ts_last[chan] = Ts_buff[chan];
/*
** Then flush the socket
*/
my_rd_msk = Ts_mask[chan];
tmo = zero_tmo;
status = select (Ts_skts[chan]+1,
(fd_set *) &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];
tmo = zero_tmo;
status = select (Ts_skts[chan]+1,
(fd_set *) &my_rd_msk, NULL, NULL, &tmo);
}
}
/*
**--------------------------------------------------------------------------
** ctrlC_Handler: Signal handler to detect <Ctrl-C> on keyboard.
*/
void ctrlC_Handler (int sigint) {
/* =============
*/
Ctrl_C_has_happened = True;
}
/*
**---------------------------------------------------------------------------
** handleUserRequest - respond to user
*/
int handleUserRequest (
/* =================
** Handle a user request.
*/
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
** <rply> (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];
/* 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) {
/*
** 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 (!open_RS232C_Chan (chan, rply)) return 28;
Ts_nxt[chan] = Ts_last[chan] = Ts_buff[chan]; /* Empty type-ah'd buffer */
}
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;
}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, " <bad send length>");
return 28;
}else {
if (Trace) traceDo ('C', chan, OUT, c_len, &nxt_cmnd_ptr[hdr_size]);
}
}
/*---------------------
** 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,
" <select error - generate ?TMO>");
}else {
if (Trace) traceDo ('C', chan, TMO, 6, " <TMO>");
}
tmo_detected = True;
nxt_rply_ptr[hdr_size] = NIL; /* Put in a NIL terminator */
if (remaining > 4) { /* Is there room for "?TMO" */
nxt_pntr[0] = NIL; /* Yes */
StrJoin (&nxt_rply_ptr[hdr_size+1], 1000,
"?TMO", &nxt_rply_ptr[hdr_size+1]);
nxt_pntr += 5;
remaining -= 5;
}
sprintf (buff, fmt_out, (nxt_pntr - nxt_rply_ptr - hdr_size));
memcpy (nxt_rply_ptr, buff, hdr_size);
nxt_rply_ptr = nxt_pntr;
break;
}else {
max_bytes = sizeof (Ts_buff[chan]) - (Ts_last[chan] - Ts_nxt[chan]);
status = recv (Ts_skts[chan], Ts_last[chan], max_bytes, 0);
if (status <= 0) {
printf ("handleUserRequest: bad recv length: %d\n", status);
memcpy (rply->u.sub_status, "-00000000007", 12);
return 28;
}
if (Trace) traceDo ('C', chan, IN, status, Ts_last[chan]);
Ts_last[chan] += status;
}
}
}
}
nxt_cmnd_ptr += (hdr_size + c_len); /* Move to next command */
}
/*
** Set up number of replies
*/
sprintf (buff, "%04.4d", i); /* Set up number of replies */
memcpy (rply->n_rply, buff, sizeof (rply->n_rply));
/*
** Calculate and set up reply size.
*/
rply_size = nxt_rply_ptr - ((char *) rply) - 4;
rply_size = (rply_size + 3) & (~3);
sprintf (buff, "%04.4d", rply_size);
memcpy (rply->msg_size, buff, sizeof (rply->msg_size));
return (rply_size + 4);
}
/*
**---------------------------------------------------------------------------*/
int lookForTerm (
/* ===========
** Look for a terminator. Note that '\0' 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 */
char *buff_end) { /* In -- Pntr to end of search buffer + 1 */
int i, term_found;
char *nxt;
if (nterm <= 0) {
*len = buff_end - buff; /* No terminator. So return complete string */
*term = NIL;
return False;
}else { /* Search string for a terminator */
nxt = buff;
term_found = False;
while ((nxt != buff_end) && (!term_found)) {
for (i = 0; i < nterm; i++) if (*nxt == terms[i]) term_found = True;
if (!term_found) nxt++;
}
*len = nxt - buff;
if (term_found) { /* Was a terminator found? */
*term = *nxt; /* Yes. Return it */
*nxt = NIL; /* Replace the terminator with a NIL */
*len += 1; /* And include the term in the length */
return True;
}else {
*term = NIL; /* No */
return False;
}
}
}
/*
**--------------------------------------------------------------------------*/
int open_RS232C_Chan (
/* ================
** Open a connection to Terminal Server Port
*/
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.
**------------------------------------------------------------------
*/
int my_skt, my_port, status;
char old_time_out[4];
union {
char chars[4];
int val;
} time_out;
unsigned int oto_len, 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;
/*------------------------------------------------------------------*/
printf ("Opening RS-232-C channel %d on %s ", chan, Ts_name);
fflush (NULL);
/*
** Get the Internet address of the Terminal Server
*/
rmt_inet_addr.s_addr = inet_addr (Ts_name);
if (rmt_inet_addr.s_addr != -1) {
rmt_inet_addr_pntr = &rmt_inet_addr;
}else {
rmt_hostent = gethostbyname (Ts_name);
if (rmt_hostent == NULL) {
printf ("\nFailed! --"
" Terminal server, \"%s\", is not a known "
"Internet address.\n", Ts_name);
memcpy (rply->u.sub_status, "-00000000012", 12);
return False;
}
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);
/*---------------------------
** Get the Internet port number of the device on the Terminal Server
*/
my_port = 3000 + chan;
/*---------------------------
** Create a TCP/IP socket for connecting to server and bind it.
*/
my_skt = socket (AF_INET, SOCK_STREAM, 0);
if (my_skt <= 0) {
printf ("failed!\n\n"
" Could not create a socket.\n\n");
perror ("open_RS232C_Chan");
memcpy (rply->u.sub_status, "-00000000014", 12);
return False;
}
lcl_sockname.sin_family = AF_INET;
lcl_sockname.sin_port = htons (0);
lcl_sockname.sin_addr.s_addr = 0;
status = bind (my_skt, (struct sockaddr *) &lcl_sockname,
sizeof (lcl_sockname));
if (status == -1) {
close (my_skt);
printf ("failed!\n\n"
" Could not bind the socket.\n\n");
perror ("open_RS232C_Chan");
memcpy (rply->u.sub_status, "-00000000015", 12);
return False;
}
/*---------------------------
** Set short time-out (VMS systems only)
*/
#ifdef __VMS
oto_len = sizeof (old_time_out); /* Save current time-out first */
oto_status = getsockopt (my_skt, IPPROTO_TCP, UCX$C_TCP_PROBE_IDLE,
old_time_out, &oto_len);
if (oto_status == 0) {
time_out.val = 5; /* Set new time-out */
status = setsockopt (my_skt, IPPROTO_TCP, UCX$C_TCP_PROBE_IDLE,
time_out.chars, sizeof (time_out));
}
#endif
/*---------------------------
** Connect to Terminal Server
*/
rmt_sockname_len = sizeof (rmt_sockname);
rmt_sockname.sin_family = AF_INET;
rmt_sockname.sin_port = htons (my_port);
rmt_sockname.sin_addr.s_addr = rmt_inet_addr_pntr->s_addr;
status = connect (my_skt, (struct sockaddr *) &rmt_sockname,
sizeof (rmt_sockname));
if (status != 0) {
close (my_skt);
printf ("failed!\n\n"
" Could not connect to Terminal Server %s, Port %d.\n\n",
Ts_name, my_port);
perror ("open_RS232C_Chan");
memcpy (rply->u.sub_status, "-00000000016", 12);
return False;
}
/*---------------------------
** Restore time-out (VMS only)
*/
#ifdef __VMS
if (oto_status == 0) {
setsockopt (my_skt, IPPROTO_TCP, UCX$C_TCP_PROBE_IDLE,
old_time_out, oto_len);
}
#endif
printf (" done.\n");
Ts_skts[chan] = my_skt;
Ts_ports[chan] = my_port;
Ts_mask[chan] = (1 << my_skt);
if (my_skt >= Max_ts_skt) Max_ts_skt = my_skt + 1;
}
/*
**---------------------------------------------------------------------------
** 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},
};
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] = '\0';
/*
** 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;
}
/*
**---------------------------------------------------------------------------
** 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 # */
int in_or_out, /* IN or OUT or ... */
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);
fprintf (fd, "The client select mask is 0x%x\n", Skt_mask);
fprintf (fd, "The following client connections are open:\n");
for (i = 0; i < RS__MAX_CLIENTS; i++) {
if (Client_skts[i] != 0) {
fprintf (fd, " Skt %2d --> %s:%d\n",
Client_skts[i], Client_host[i], Client_port[i]);
}
}
fprintf (fd, "The following channels are open:\n");
for (i = 0; i < RS__MAX_ASYNCH; i++) {
if (Ts_skts[i] != 0) {
fprintf (fd, " Chan %2d via Skt %2d and Port %4d (Mask = %d)\n",
i, Ts_skts[i], Ts_ports[i], Ts_mask[i]);
}
}
fclose (fd);
printf (" done.\n");
}else {
printf (" failed to open file!\n");
}
}
/*
**==========================================================================
** 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;
int open_channel;
int my_accept_mask, my_rd_mask;
struct timeval tmo, one_sec = {1, 0};
int msgSize, r_size, bytes_to_come;
time_t time_now;
int my_errno, my_vaxc_errno;
int rw_skt;
struct sockaddr_in rmt_sockname;
char *rmt_host;
int rmt_port;
struct hostent *rmt_host_name;
/*------------------------------------------------
** 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
/*------------------------------------------------*/
int max_msg_size;
struct RS__MsgStruct msg_buff;
char *appName;
struct RS__RespStruct respon_buff;
int responSize;
XrmDatabase my_db;
char *type;
XrmValue value;
/*-----------------------------------------------------------------------*/
setupTime (buff, sizeof (buff));
printf ("%s: Server for RS-232-C Devices, Ident %s, started.\n",
buff, ident);
/*--------------------------------------------------------------
** 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 (0);
}
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% */
Tr_timer = time (NULL); /* 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", &Tr_period) != 1)) {
Tr_period = 60;
}
/*--------------------------------------------------------------*/
printf (" Creating RS-232-C Server Socket ...\n");
Cnct_skt = setupSocket (Inet_port);
printf (" RS-232-C Server ready. Waiting for connections ...\n");
for (i = 0; i < RS__MAX_CLIENTS; i++) Client_skts[i] = 0;
Skt_mask = my_accept_mask = (1 << Cnct_skt);
Max_skt = Cnct_skt + 1;
/*
** Declare a signal handler to catch <Ctrl-C> so that we
** can exit cleanly.
*/
Ctrl_C_has_happened = False;
Ctrl_C_number = 0;
signal (SIGINT, ctrlC_Handler); /* SIGINT is signal #2 */
signal (SIGTERM, ctrlC_Handler); /* SIGTERM is signal #15 */
/*
** Poll looking for work: accepts, reads or exceptions.
*/
for (;;) {
fflush (NULL);
if (Ctrl_C_has_happened) {
Ctrl_C_has_happened = False;
setupTime (buff, sizeof (buff));
printf ("%s: <Ctrl-C> detected ...\n", buff);
open_channel = False;
for (i = 0; i < RS__MAX_ASYNCH; i++) {
if (Ts_skts[i] != 0) {
printf (" Closing connection to RS-232-C channel %d ...\n", i);
if (Trace) traceDo ('C', i, CLOSE, 18, " <Ctrl-C> detected");
close (Ts_skts[i]);
Ts_skts[i] = 0;
open_channel = True;
}
}
if (open_channel) {
printf (" All RS-232-C channels closed.\n");
printf (" Hit <Ctrl-C> again fairly soon to quit program.\n");
Ctrl_C_number = 5;
}else {
if (Ctrl_C_number <= 1) {
printf (" No RS-232-C channels were open.\n");
printf (" Hit <Ctrl-C> again fairly soon to quit program.\n");
Ctrl_C_number = 5;
}else {
open_channel = False;
for (i = 0; i < RS__MAX_CLIENTS; i++) {
if (Client_skts[i] != 0) {
printf (" Closing TCP/IP socket %d --> %s:%d ...\n",
Client_skts[i], Client_host[i], Client_port[i]);
close (Client_skts[i]);
Skt_mask = Skt_mask & ~(1 << Client_skts[i]);
Client_skts[i] = 0;
open_channel = True;
}
}
if (open_channel) printf (" All client sockets closed.\n");
printf (" Closing listener TCP/IP socket ...\n");
close (Cnct_skt);
Cnct_skt = 0;
if (Trace) {
traceAdd (25, "SerPortServer terminating");
traceWrite ();
}
printf (" Done.\n");
exit (True);
}
}
signal (SIGINT, ctrlC_Handler); /* Re-enable <Ctrl-C> signal */
signal (SIGTERM, ctrlC_Handler); /* Re-enable <Ctrl-C> signal */
}
if (Ctrl_C_number > 0) Ctrl_C_number--;
my_rd_mask = Skt_mask;
tmo = one_sec;
status = select (Max_skt, (fd_set *) &my_rd_mask, NULL, NULL, &tmo);
if (Trace) {
time_now = time (NULL);
if (difftime (time_now, Tr_timer) > Tr_period) {
Tr_timer = time_now;
setupTime (buff, sizeof (buff)); memcpy (&buff[5], "===== ", 6);
traceAdd (14, &buff[5]);
}
}
switch (status) {
case -1:
if (errno != EINTR) {
FailInet ("SerPortServer: select error.\n");
}
break;
case 0:
break;
default:
if ((my_rd_mask & my_accept_mask) != 0) { /* New accept? .. */
rmt_sockname_len = sizeof (rmt_sockname); /* .. Yes */
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);
for (i = 0; i < RS__MAX_CLIENTS; i++) {
if (Client_skts[i] != 0) continue;
Client_skts[i] = rw_skt;
Client_port[i] = rmt_port;
StrJoin (Client_host[i], sizeof Client_host[0], "",
(rmt_host_name != NULL) ? rmt_host_name->h_name : rmt_host);
Skt_mask = Skt_mask | (1 << rw_skt);
if (rw_skt >= Max_skt) Max_skt = rw_skt + 1;
setupTime (buff, sizeof (buff));
printf ("%s: Socket %d connected to %s:%d.\n",
buff, rw_skt, Client_host[i], rmt_port);
sprintf (buff, " <Connected to %s:%d>", Client_host[i], rmt_port);
if (Trace) traceDo ('S', Client_skts[i], OPEN,
strlen (buff), buff);
break;
}
if (i == RS__MAX_CLIENTS) {
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, " <No more slots>");
}
}
for (i = 0; i < RS__MAX_CLIENTS; i++) { /* Look for pending recv's */
if (Client_skts[i] == 0) continue;
if (((1 << Client_skts[i]) & my_rd_mask) != 0) {
max_msg_size = sizeof (msg_buff) - sizeof (msg_buff.msg_size);
status = recv (Client_skts[i],
msg_buff.msg_size,
sizeof (msg_buff.msg_size), 0);
if (status != sizeof (msg_buff.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",
Client_skts[i], Client_host[i], Client_port[i]);
if (Trace) traceDo ('S', Client_skts[i], CLOSE, 9, " <Closed>");
}else {
printf ("recv: Did not get full message header on ");
printf ("socket %d.\n", Client_skts[i]);
printf (" Should be: %d. Was: %d. Connection closed.\n",
sizeof (msg_buff.msg_size), status);
if (Trace) traceDo ('S', Client_skts[i], ERROR,
30, " <Only partial message header>");
}
close (Client_skts[i]);
Skt_mask = Skt_mask & ~(1 << Client_skts[i]);
Client_skts[i] = 0;
}else {
msg_buff.msg_size[status] = '\0'; /* Zero terminate msg_size */
if (sscanf (msg_buff.msg_size, "%d", &msgSize) != 1) {
printf ("recv: Non-decimal ASCII message size on ");
printf ("socket %d.\n", Client_skts[i]);
printf (" Value received = \"%s\". Connection closed.\n",
msg_buff.msg_size);
close (Client_skts[i]);
Skt_mask = Skt_mask & ~(1 << Client_skts[i]);
Client_skts[i] = 0;
}else if (msgSize == -1) { /* Close connection? */
if (Trace) traceDo ('S', Client_skts[i], IN,
status, msg_buff.msg_size);
send (Client_skts[i], "-001", 4, 0); /* Yes */
if (Trace) traceDo ('S', Client_skts[i], OUT, 4, "-001");
close (Client_skts[i]);
setupTime (buff, sizeof (buff));
printf ("%s: Socket %d closed.\n", buff, Client_skts[i]);
if (Trace) traceDo ('S', Client_skts[i], CLOSE, 9, " <Closed>");
Skt_mask = Skt_mask & ~(1 << Client_skts[i]);
Client_skts[i] = 0;
}else if (msgSize == -2) { /* Turn trace on? */
if (Trace) traceDo ('S', Client_skts[i], IN, /* Yes */
status, msg_buff.msg_size);
send (Client_skts[i], "-002", 4, 0);
if (Trace) traceDo ('S', Client_skts[i], OUT, 4, "-002");
setupTime (buff, sizeof (buff));
printf ("%s: ", buff);
printf ("\"Trace on\" rqst from Socket %d.\n", Client_skts[i]);
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);
Tr_timer = time (NULL); /* Initialise trace time stamp */
}
}else if (msgSize == -3) { /* Turn trace off? */
if (Trace) traceDo ('S', Client_skts[i], IN, /* Yes */
status, msg_buff.msg_size);
send (Client_skts[i], "-003", 4, 0);
if (Trace) traceDo ('S', Client_skts[i], OUT, 4, "-003");
setupTime (buff, sizeof (buff));
printf ("%s: ", buff);
printf ("\"Trace off\" rqst from Socket %d.\n",
Client_skts[i]);
if (Trace) {
StrJoin (buff, sizeof (buff), "Trace off at ", buff);
traceAdd (strlen (buff), buff);
Trace = False;
}
fflush (NULL);
}else if (msgSize == -4) { /* Flush output? */
if (Trace) traceDo ('S', Client_skts[i], IN, /* Yes */
status, msg_buff.msg_size);
setupTime (buff, sizeof (buff));
printf ("%s: ", buff);
printf ("\"Flush rqst\" from Socket %d.\n", Client_skts[i]);
fflush (NULL);
if (Trace) traceAdd (7, "Flushed");
send (Client_skts[i], "-004", 4, 0);
if (Trace) traceDo ('S', Client_skts[i], OUT, 4, "-004");
}else if (msgSize == -5) { /* Write trace? */
if (Trace) traceDo ('S', Client_skts[i], IN, /* Yes */
status, msg_buff.msg_size);
send (Client_skts[i], "-005", 4, 0);
if (Trace) traceDo ('S', Client_skts[i], OUT, 4, "-005");
setupTime (buff, sizeof (buff));
printf ("%s: ", buff);
printf ("\"Write trace\" rqst from Socket %d ...\n",
Client_skts[i]);
traceWrite ();
printf (" ... done.\n");
fflush (NULL);
}else if (msgSize == -6) { /* Close channels? */
if (Trace) traceDo ('S', Client_skts[i], IN, /* Yes */
status, msg_buff.msg_size);
send (Client_skts[i], "-006", 4, 0);
if (Trace) traceDo ('S', Client_skts[i], OUT, 4, "-006");
setupTime (buff, sizeof (buff));
printf ("%s: ", buff);
printf ("\"Close channels\" rqst from Socket %d ...\n",
Client_skts[i]);
open_channel = False;
for (i = 0; i < RS__MAX_ASYNCH; i++) {
if (Ts_skts[i] != 0) {
printf (" Closing connection to RS-232-C "
"channel %d ...\n", i);
if (Trace) traceDo ('C', i, CLOSE, 18, " <Close-chan rqst>");
close (Ts_skts[i]);
Ts_skts[i] = 0;
open_channel = True;
}
}
if (!open_channel) printf (" No RS-232-C channels were open.\n");
printf (" ... done.\n");
}else if ((msgSize <= 0) ||
(msgSize > max_msg_size)) {
if (Trace) traceDo ('S', Client_skts[i], IN,
status, msg_buff.msg_size);
printf ("recv: Illegal pending message size on ");
printf ("socket %d.\n", Client_skts[i]);
printf (" Max is: %d. Received: %d. Connection closed.\n",
max_msg_size, msgSize);
close (Client_skts[i]);
if (Trace) traceDo ('S', Client_skts[i], ERROR,
14, " <Bad msg hdr>");
if (Trace) traceDo ('S', Client_skts[i], CLOSE, 9, " <Closed>");
Skt_mask = Skt_mask & ~(1 << Client_skts[i]);
Client_skts[i] = 0;
}else {
bytes_to_come = msgSize;
p_nxt_byte = msg_buff.msg_id;
while (bytes_to_come > 0) {
status = recv (Client_skts[i], 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", Client_skts[i]);
printf (" Should be: %d. Was: %d. Connection closed.\n",
msgSize, (msgSize - bytes_to_come));
if (Trace) traceDo ('S', Client_skts[i], ERROR,
18, " <bad recv length>");
status = send (Client_skts[i], "-001", 4, 0);
if (Trace) traceDo ('S', Client_skts[i], OUT, 4, "-001");
close (Client_skts[i]);
Skt_mask = Skt_mask & ~(1 << Client_skts[i]);
Client_skts[i] = 0;
}else {
if (Trace) traceDo ('S', Client_skts[i], IN,
msgSize + 4, (char *) &msg_buff);
responSize = sizeof (respon_buff.u.rplys);
r_size = handleUserRequest (&msg_buff, msgSize,
&respon_buff, responSize);
status = send (Client_skts[i],
(char *) &respon_buff, r_size, 0);
if (status != r_size) {
printf ("send: Bad byte count sent to ");
printf ("socket %d.\n", Client_skts[i]);
printf (" Should have been: %d\n", r_size);
printf (" Was: %d\n", status);
if (Trace) traceDo ('S', Client_skts[i], ERROR,
16, " <bad send size>");
close (Client_skts[i]);
if (Trace) traceDo ('S', Client_skts[i], CLOSE,
9, " <Closed>");
Skt_mask = Skt_mask & ~(1 << Client_skts[i]);
Client_skts[i] = 0;
}else {
if (Trace) traceDo ('S', Client_skts[i], OUT,
r_size, (char *) &respon_buff);
}
}
}
}
}
}
}
}
}
/*------------------------------------------------- End of SerPortServer.C */