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