Files
sicspsi/utils/SerPortServer.c
koennecke 9e5781718a - Added tabledrive: table driven path for MARS
- Initial MARS development
- Upgraded Manager Manual
2005-07-22 14:56:19 +00:00

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