1498 lines
55 KiB
C
Executable File
1498 lines
55 KiB
C
Executable File
#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 */
|