Files
sicspsi/hardsup/asynsrv_mark.c
2009-02-13 09:01:24 +00:00

1559 lines
57 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#define ident "1B06"
#ifdef VAXC
#module AsynSrv_Utility ident
#endif
#ifdef __DECC
#pragma module AsynSrv_Utility ident
#endif
/*
** +--------------------------------------------------------------+
** | Paul Scherrer Institute |
** | Department ASQ |
** | |
** | 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.|
** +--------------------------------------------------------------+
**
** Module Name . . . . . . . . : [...LIB.SINQ]AsynSrv_Utility.C
**
** Author . . . . . . . . . . : D. Maden
** Date of creation . . . . . . : Mar 1996
**
** To compile this module, use:
$ define/group sinq_c_tlb mad_lib:sinq_c.tlb
$ cc /debug /noopt /obj=[]AsynSrv_Utility -
lnsa01::tasmad_disk:[mad.psi.lib.sinq]AsynSrv_Utility +
sinq_c_tlb/lib
** To include this module in SINQ.OLB, use:
$ define/group sinq_c_tlb mad_lib:sinq_c.tlb
$
$ define/group sinq_olb mad_lib:sinq_dbg.olb
$ @lnsa01::tasmad_disk:[mad.psi.lib.sinq]sinq_olb AsynSrv_Utility debug
$
$ define/group sinq_olb mad_lib:sinq.olb
$ @lnsa01::tasmad_disk:[mad.psi.lib.sinq]sinq_olb AsynSrv_Utility
**
** Updates:
** 1A01 21-Mar-1996 DM. Initial version.
** 1B01 12-Sep-1996 DM. Allow host name to be in dot format too.
** 1B02 5-May-1997 DM. Set 5 sec time-out on "connect" on VMS systems.
**============================================================================
** The entry points included in this module are described below. Prototypes
** can be defined via:
**
** #include <sinq_prototypes.h>
**
** AsynSrv_Close - Close a connection to an RS-232-C Server.
** AsynSrv_Config - Configure an open AsynSrv_Utility connection.
** AsynSrv_ConfigDflt - Set defaults for AsynSrv_Open.
** AsynSrv_ErrInfo - Return detailed status from last operation.
** AsynSrv_GetReply - Get next reply from a reply buffer.
** AsynSrv_Open - Open a connection to an RS-232-C Server.
** AsynSrv_SendCmnds - Send commands to a channel of an RS-232-C Server.
**---------------------------------------------------------------------
** int AsynSrv_Close (&asyn_info, force_flag)
** -------------
** Input Args:
** int force_flag - if non-zero, all connections using the same socket
** will also be marked as force-closed (socket number
** set to -1) and the connection will really be
** closed. This is needed for error recovery operations.
** Output Args:
** none
** Modified Args:
** struct AsynSrv__info *asyn_info - a structure holding skt, host and
** port of the connection. On return
* skt = 0.
** Return status:
** True if no problems detected, otherwise False and AsynSrv_errcode
** is set to indicate the nature of the problem as follows:
** AsynSrv__BAD_PAR = -29 --> skt does not match with host/port.
** Routines called:
** Socket library, "close".
** Description:
** The routine decrements the usage count on the connection to host/port.
** If the counter is still >0, the routine simply returns.
** If the counter is now 0, the routine sends a "-001" message to the
** server to inform it that we are about to close the link, waits for a
** possible 4 bytes of response and then closes the TCP/IP connection.
**---------------------------------------------------------------------
** int AsynSrv_Config (&asyn_info, &par_id, par_val, ...)
** --------------
** Input Args:
** char* par_id - Text string identifying the next argument (see below).
** NULL indicates the end of the argument list.
** <??> par_val - The value to set for the argument. The type of the
** argument can depend on par_id.
** Output Args:
** none
** Modified Args:
** struct AsynSrv__info *asyn_info - the structure used in the call to
** AsynSrv_Open. It is used to hold the config
** info for the connection.
** Return status:
** True if no problems detected, otherwise False and AsynSrv_errcode
** is set to indicate the nature of the problem as follows:
** AsynSrv__BAD_PAR = -29 --> Unrecognised par_id or msecTmo < 100 or
** msecTmo > 999'999 or bad eot or ..
** Routines called:
** None
** Description:
** AsynSrv_Config may be used for setting values of parameters for
** use in subsequent calls to AsynSrv_SendCmnds. Defaults for these
** parameters are set via a call to AsynSrv_ConfigDflt, prior to
** calling AsynSrv_Open. Values which may be taken by par_id (warning --
** par_id is case-sensitive) and the corresponding variable type of
** par_val are:
**
** "msecTmo" int The time-out response for commands sent
** to a serial channel on the server. The
** valid range is 100 to 999'999.
** "eot" char* The expected terminators in responses to
** commands sent to a serial channel on the
** server. The first character specifies the
** number of terminators (max=3).
**---------------------------------------------------------------------
** int AsynSrv_ConfigDflt (&par_id, par_val, ...)
** ------------------
** Input Args:
** char* par_id - Text string identifying the next argument (see below).
** NULL indicates the end of the argument list.
** <??> par_val - The value to set for the argument. The type of the
** argument can depend on par_id.
** Output Args:
** none
** Modified Args:
** none
** Return status:
** True if no problems detected, otherwise False and AsynSrv_errcode
** is set to indicate the nature of the problem as follows:
** AsynSrv__BAD_PAR = -29 --> Unrecognised par_id or msecTmo < 100 or
** msecTmo > 999'999 or bad eot or ..
** Routines called:
** None
** Description:
** AsynSrv_ConfigDflt may be used for setting default values of parameters
** for use in subsequent calls to AsynSrv_Open. Values which may be taken
** by par_id (warning -- par_id is case-sensitive) and the corresponding
** variable type of par_val are:
**
** "TmoC" int The time-out in seconds to be used when
** opening a connection to a server. This
** value is only effective on VMS systems. For
** UNIX systems, the systemwide default (usually
** 75 secs) cannot be changed. The initial
** setting for "TmoC" is 5 secs.
** "msecTmo" int The time-out response for commands sent
** to a serial channel on the server. The
** valid range is 100 to 999'999. The initial
** setting for "msecTmo" is 10'000 msec.
** "eot" char* The expected terminators in responses to
** commands sent to a serial channel on the
** server. The first character specifies the
** number of terminators (max=3). The initial
** setting for "eot" is "1\r".
**-------------------------------------------------------------------------
** void AsynSrv_ErrInfo (&entry_txt_ptr, &errcode, &my_errno, &vaxc_errno)
** ---------------
** Input Args:
** None
** Output Args:
** char **entry_txt_ptr - Pointer to a text string giving the call stack
** at the time that the error was detected.
** int *errcode - An internal error code indicating the detected error.
** int *my_errno - Saved value of errno.
** int *vaxc_errno - Saved value of vaxc$errno (OpenVMS only).
** Modified Args:
** none
** Return status:
** none
** Routines called:
** none
** Description:
** Returns detailed status of the last operation. Once an error has been
** detected, the error status is frozen until this routine has been called.
**-------------------------------------------------------------------------
** char *AsynSrv_GetReply (&asyn_info, &rcve_buff, &last_rply)
** ----------------
** Input Args:
** struct RS__RespStruct *rcve_buff - address of receive buffer used
** in last call to AsynSrv_SendCmnds.
** char *last_rply - Address of last reply processed
** or NULL.
** Output Args:
** none
** Modified Args:
** struct AsynSrv__info *asyn_info - the structure used in the call to
** AsynSrv_Open. It is used to hold status info
** between calls to this routine.
** Return status:
** Address of next reply in the buffer or NULL if no more. Note that this
** is a pointer to the reply and not to the head of the reply structure.
** The terminator byte found is therefore at index [-1] from this address.
** Routines called:
** none
** Description:
** AsynSrv_GetReply unpacks the replies in the response packet from the
** RS232C server which is an argument in the call to AsynSrv_SendCmnds.
** If the routine is called with last_rply = NULL, a pointer to the
** first reply is returned. On calling AsynSrv_GetReply again with
** last_rply set to this address, one receives the address of the second
** reply and so on, until NULL is returned, indicating that all responses
** have been exhausted.
** Warning:
** AsynSrv_GetReply keeps count of the number of responses it returns.
** Responses must therefore be processed in order.
**-------------------------------------------------------------------------
** int AsynSrv_Open (&asyn_info)
** ------------
** Input Args:
** asyn_info->host - Name of host offering the RS-232-C service. The name
** can be either symbolic or numeric, e.g.
** "lnsw02.psi.ch" or "129.129.90.18".
** asyn_info->port - Number of TCP/IP port of TCP/IP server.
** Output Args:
** none
** Modified Args:
** struct AsynSrv__info *asyn_info - a structure holding skt, host and
** port of the connection. On return
** skt = socket number of connection.
** Set to 0 if error.
** Return status:
** If non-zero, no problems detected and asyn_info->skt is the socket to
** use for communicating with the server. Otherwise, a problem
** was detected and AsynSrv_errcode may be set as follows
** to indicate the nature of the problem:
** AsynSrv__BAD_HOST = -6 --> Call to "gethostbyname" failed to get
** network addr of host.
** AsynSrv__BAD_SOCKET = -7 --> Call to "socket" failed.
** AsynSrv__BAD_BIND = -8 --> Call to "bind" failed.
** AsynSrv__BAD_CONNECT = -9 --> Call to "connect" failed.
** AsynSrv__BAD_PAR = -29 --> Bad parameter found. Probably
** asyn_info->port or asyn_info->chan
** are out of range.
** AsynSrv__NO_ROOM = -40 --> Host/port table full or Active-link
** table full.
** Routines called:
** Socket library routine "open".
** Description:
** The routine maintains a list of hosts/ports to which it has open
** sockets. If an entry is found in the list, the socket is returned
** and the usage count of this connection is incremented. If no entry
** is found in the list, a connection to the host is established and
** entered into the list.
** The routine also maintains a table of active links so that the
** "force-close" function can be performed. The link is added to this
** table too.
**-------------------------------------------------------------------------
** int AsynSrv_SendCmnds (&asyn_info, &send_buff, &rcve_buff, ...)
** -----------------
** Input Args:
** struct AsynSrv__info *asyn_info - the structure used in the call to
** AsynSrv_Open. It contains settings required
** for setting up and sending send_buff.
** char * ... - A list of commands, terminated by NULL, for
** sending to the channel on the server. The commands
** must have any necessary \r characters included.
** Output Args:
** struct RS__RespStruct *rcve_buff - a buffer to receive the response
** from the server.
** Modified Args:
** struct RS__MsgStruct *send_buff - a buffer for holding the commands
** for sending to the server.
** Return status:
** True if no problems detected, otherwise False and errcode (see
** AsynSrv_ErrInfo) is set to indicate the nature of the problem.
** AsynSrv_errcode may be set as follows:
** AsynSrv__BAD_SENDLEN = -12 --> Too much to send; either too many
** commands or too long. The buffer
** is 232 bytes long and each command
** has a 2-byte header.
** Errors -13 to -16 are related to network errors whilst sending the
** message buffer to the server:
** AsynSrv__BAD_SEND = -13 --> Network problem - server has
** probably abended.
** AsynSrv__BAD_SEND_PIPE = -14 --> Network pipe broken - probably same
** cause as AsynSrv__BAD_SEND.
** AsynSrv__BAD_SEND_NET = -15 --> Some other network problem. "errno"
** may be helpful.
** AsynSrv__BAD_SEND_UNKN = -16 --> Some other network problem happened
** resulting in the message not
** getting sent completely. "errno" is
** probably not helpful in this case.
** Errors AsynSrv__BAD_RECV, AsynSrv__BAD_RECV_PIPE, AsynSrv__BAD_RECV_NET
** and AsynSrv__BAD_RECV_UNKN (-17 to -20) are related to network
** errors whilst receiving the 4-byte response header. They are
** analogous to AsynSrv__BAD_SEND to AsynSrv__BAD_SEND_UNKN.
** AsynSrv__BAD_NOT_BCD = -21 --> The 4-byte response header is not an
** ASCII coded decimal integer.
** AsynSrv__BAD_RECVLEN = -22 --> The body of the response would be too
** big to fit in the input buffer. The
** buffer is ??? bytes long and each
** response has a 5-byte header and a
** trailing zero-byte. The response
** is flushed.
** AsynSrv__BAD_FLUSH = -23 --> Some network error was detected
** during flushing. This is an "or"
** of errors AsynSrv__BAD_RECV to
** AsynSrv__BAD_RECV_UNKN.
** AsynSrv__FORCED_CLOSED = -32 --> The connection to the motor has been
** forcefully closed. See below.
** AsynSrv__BAD_REPLY = -34 --> The n_rply field of the response was
** either non-numeric or <0, indicating
** that the Terminal Server detected an
** error. The reply is added to the
** routine call stack for debug purposes.
**
** Errors AsynSrv__BAD_RECV1, AsynSrv__BAD_RECV1_PIPE and
** AsynSrv__BAD_RECV1_NET (-24 to -26) are related to network
** errors whilst receiving the body of the response. They are
** equivalent to errors AsynSrv__BAD_RECV, to AsynSrv__BAD_RECV_NET.
**
** AsynSrv__FORCED_CLOSED occurs if AsynSrv_Close has been called
** for another device on the same server and the 'force_flag'
** was set (see AsynSrv_Close). The caller should call
** AsynSrv_Close and then AsynSrv_Open to re-establish a
** connection to the server.
** Routines called:
** Socket library routines send and recv.
** Description:
** The list of commands is assembled into a message buffer with appropriate
** header information and sent off to the server. The response is then
** awaited and read in when it arrives.
**
** For any of the following errors:
** AsynSrv__BAD_SEND (Note: AsynSrv__BAD_SENDLEN and
** AsynSrv__BAD_SEND_PIPE AsynSrv__BAD_RECVLEN do not cause a close
** AsynSrv__BAD_SEND_NET
** AsynSrv__BAD_SEND_UNKN
** AsynSrv__BAD_RECV
** AsynSrv__BAD_RECV_PIPE
** AsynSrv__BAD_RECV_NET
** AsynSrv__BAD_RECV_UNKN
** AsynSrv__BAD_NOT_BCD
** AsynSrv__BAD_FLUSH
** AsynSrv__BAD_RECV1
** AsynSrv__BAD_RECV1_PIPE
** AsynSrv__BAD_RECV1_NET
** the network link to the server is force-closed via a call to AsynSrv_Close.
** Once the error has been corrected, the link can be re-opened via a
** call to AsynSrv_Open. As a result of the force-close, other active handles
** will need to be released via a call to AsynSrv_Close before AsynSrv_Open is
** called.
**
** Note: neither of the errors AsynSrv__BAD_SENDLEN, AsynSrv__BAD_RECVLEN
** nor AsynSrv__BAD_REPLY cause the link to be closed.
**============================================================================*/
/*
**---------------------------------------------------------------------------
** Global Definitions
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <signal.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "fortify.h"
#include <string.h>
#ifdef __VMS
#include <ucx$inetdef.h>
#include <unixio.h>
#else
#include <unistd.h>
#endif
/*-----------------------------------------------------------------*/
#include <asynsrv_def.h>
#include <rs232c_def.h>
#include <sinq_prototypes.h>
#define True 1
#define False 0
#define MAX_OPEN 64
/*--------------------------------------------------------------------------
** Global Variables
*/
static int AsynSrv_call_depth = 0;
static char AsynSrv_routine[5][64];
static int AsynSrv_errcode = 0;
static int AsynSrv_errno, AsynSrv_vaxc_errno;
static int AsynSrv_connect_tmo = 5; /* Time-out on "connect" */
static int AsynSrv_msec_tmo = 10000; /* Time-out for responses */
static char AsynSrv_eot[] = { '1', '\r', '\0', '\0' }; /* Terminators */
/*
** The following is the list of open connections (= number of
** active sockets).
*/
static int AsynSrv_n_cnct = 0;
static struct AsynSrv_HostPortSkt AsynSrv_HPS_list[AsynSrv_MAX_LINK];
/*
** The following is the list of active calls to AsynSrv_Open.
*/
static int AsynSrv_n_active = 0;
static struct AsynSrv__info *AsynSrv_active[MAX_OPEN];
/*
**---------------------------------------------------------------------------
** AsynSrv_Close: Close a connection to an RS-232-C server.
*/
int AsynSrv_Close(
/* =============
*/ struct AsynSrv__info *asyn_info,
int force_flag)
{
int i, j, k, my_skt;
char buff[4];
/*-----------------------------------------------
*/
if (asyn_info == NULL)
return True; /* Just return if nothing to do! */
my_skt = asyn_info->skt;
if (my_skt <= 0)
return True; /* Just return if nothing to do! */
/*-----------------------------------------------
** Pre-set the routinename (in case of error)
*/
if (AsynSrv_errcode == 0 && AsynSrv_call_depth < 5) {
strcpy(AsynSrv_routine[AsynSrv_call_depth], "AsynSrv_Close");
AsynSrv_call_depth++;
}
/*------------------------------------------------------
** Start by finding the table entry for this connection
*/
for (i = 0; i < AsynSrv_n_cnct; i++) {
if (AsynSrv_HPS_list[i].skt != my_skt)
continue;
if (AsynSrv_HPS_list[i].port != asyn_info->port)
continue;
if (strcmp(AsynSrv_HPS_list[i].host, asyn_info->host) == 0)
break;
}
if (i >= AsynSrv_n_cnct) { /* Did we find the entry? */
AsynSrv_errcode = AsynSrv__BAD_PAR; /* No! */
return False;
}
/*------------------------------------------------------
** Now find the table entry for the AsynSrvOpen call.
*/
for (j = 0; j < AsynSrv_n_active; j++) {
if ((AsynSrv_active[j] == asyn_info) &&
(AsynSrv_active[j]->skt == my_skt)) {
break;
}
}
if (j >= AsynSrv_n_active) { /* Did we find the entry? */
AsynSrv_errcode = AsynSrv__BAD_PAR; /* No! */
return False;
}
/*------------------------------------------------------
** i is the index for the connection table entry.
** j is the index for the caller's AsynSrvOpen call entry.
*/
if (AsynSrv_HPS_list[i].usage_cnt <= 0) { /* Is the connection active? */
AsynSrv_errcode = AsynSrv__BAD_PAR; /* No */
return False;
}
/*------------------------------------------------------
** For the caller, simply set his socket number to zero,
** mark the AsynSrvOpen entry as free and decrease the
** usage count (the entries will be compressed later).
*/
AsynSrv_active[j]->skt = 0; /* Mark the close .. */
AsynSrv_active[j] = NULL; /* .. and flag entry to be removed. */
AsynSrv_HPS_list[i].usage_cnt--; /* Decrease usage count */
/*------------------------------------------------------
** If this is a force-close, go through all AsynSrv_Open
** entries looking for a socket match, mark them as
** free and decrease usage count.
*/
if (force_flag) {
for (k = 0; k < AsynSrv_n_active; k++) {
if (AsynSrv_active[k] != NULL) {
if (AsynSrv_active[k]->skt == my_skt) {
AsynSrv_active[k]->skt = -1; /* Mark the force-close */
AsynSrv_active[k] = NULL; /* Mark entry to be removed */
AsynSrv_HPS_list[i].usage_cnt--; /* Decrease usage count */
}
}
}
if (AsynSrv_HPS_list[i].usage_cnt != 0) { /* Use count should now be .. */
AsynSrv_errcode = AsynSrv__BAD_PAR; /* .. zero or there's a bug. */
return False;
}
}
/*------------------------------------------------------
** Compress the list of AsynSrv_Open entries
*/
j = 0;
for (k = 0; k < AsynSrv_n_active; k++) {
if (AsynSrv_active[k] != NULL) {
AsynSrv_active[j] = AsynSrv_active[k];
j++;
}
}
for (k = j; k < AsynSrv_n_active; k++)
AsynSrv_active[k] = NULL;
AsynSrv_n_active = j;
/*------------------------------------------------------
** If the link is now idle, really close it and compress
** the connection table entry out of the list.
*/
if (AsynSrv_HPS_list[i].usage_cnt == 0) {
send(my_skt, "-001", 4, 0); /* Tell the TCP/IP server that ..
** .. we are about to quit.
*/
recv(my_skt, buff, sizeof(buff), 0); /* And wait for his ack */
close(my_skt);
for (j = i; j < AsynSrv_n_cnct; j++) {
memcpy((char *) &AsynSrv_HPS_list[j],
(char *) &AsynSrv_HPS_list[j + 1],
sizeof(AsynSrv_HPS_list[0]));
}
AsynSrv_HPS_list[AsynSrv_n_cnct].skt = 0; /* Invalidate the free entry */
AsynSrv_n_cnct--;
}
AsynSrv_call_depth--;
return True;
}
/*
**---------------------------------------------------------------------------
** AsynSrv_Config: Configure an open connection.
*/
int AsynSrv_Config(
/* ==============
*/ struct AsynSrv__info *asyn_info,
...)
{
char buff[16];
va_list ap; /* Pointer to variable args */
char *txt_ptr;
int intval;
/*
** Pre-set the routinename (in case of error)
*/
if (AsynSrv_errcode == 0 && AsynSrv_call_depth < 5) {
strcpy(AsynSrv_routine[AsynSrv_call_depth], "AsynSrv_Config");
AsynSrv_call_depth++;
}
va_start(ap, asyn_info); /* Set up var arg machinery */
txt_ptr = va_arg(ap, char *); /* Get pntr to first parameter ident */
while (txt_ptr != NULL) {
if (strcmp(txt_ptr, "msecTmo") == 0) {
intval = va_arg(ap, int);
if ((intval < 100) || (intval > 999999)) {
AsynSrv_errcode = AsynSrv__BAD_PAR;
return False;
}
sprintf(buff, "%04d", intval / 100); /* Convert to ASCII as ..
** .. deci-secs */
memcpy(asyn_info->tmo, buff, 4);
} else if (strcmp(txt_ptr, "eot") == 0) {
txt_ptr = va_arg(ap, char *);
if (txt_ptr == NULL) {
AsynSrv_errcode = AsynSrv__BAD_PAR;
return False;
}
memcpy(asyn_info->eot, "\0\0\0\0", 4);
switch (txt_ptr[0]) {
case '3':
asyn_info->eot[3] = txt_ptr[3];
case '2':
asyn_info->eot[2] = txt_ptr[2];
case '1':
asyn_info->eot[1] = txt_ptr[1];
case '0':
asyn_info->eot[0] = txt_ptr[0];
break;
default:
AsynSrv_errcode = AsynSrv__BAD_PAR;
return False;
}
} else {
AsynSrv_errcode = AsynSrv__BAD_PAR;
return False;
}
txt_ptr = va_arg(ap, char *); /* Get pntr to next parameter ident */
}
AsynSrv_call_depth--;
return True;
}
/*
**---------------------------------------------------------------------------
** AsynSrv_ConfigDflt: Set default values in AsynSrv_Utility
** which will be used to initialise
** structures in AsynSrv_Open.
*/
int AsynSrv_ConfigDflt(
/* ==================
*/ char *par_id,
...)
{
int i;
char buff[4];
va_list ap; /* Pointer to variable args */
char *txt_ptr;
int intval;
/*
** Pre-set the routinename (in case of error)
*/
if (AsynSrv_errcode == 0 && AsynSrv_call_depth < 5) {
strcpy(AsynSrv_routine[AsynSrv_call_depth], "AsynSrv_ConfigDflt");
AsynSrv_call_depth++;
}
va_start(ap, par_id); /* Set up var arg machinery */
txt_ptr = par_id; /* Point to first arg */
while (txt_ptr != NULL) {
if (strcmp(txt_ptr, "tmoC") == 0) {
intval = va_arg(ap, int);
if ((intval < 1) || (intval > 3600)) {
AsynSrv_errcode = AsynSrv__BAD_PAR;
return False;
}
AsynSrv_connect_tmo = intval;
} else if (strcmp(txt_ptr, "msecTmo") == 0) {
intval = va_arg(ap, int);
if ((intval < 100) || (intval > 999900)) {
AsynSrv_errcode = AsynSrv__BAD_PAR;
return False;
}
AsynSrv_msec_tmo = intval;
} else if (strcmp(txt_ptr, "eot") == 0) {
txt_ptr = va_arg(ap, char *);
if (txt_ptr == NULL) {
AsynSrv_errcode = AsynSrv__BAD_PAR;
return False;
}
switch (txt_ptr[0]) {
case '3':
AsynSrv_eot[3] = txt_ptr[3];
case '2':
AsynSrv_eot[2] = txt_ptr[2];
case '1':
AsynSrv_eot[1] = txt_ptr[1];
case '0':
AsynSrv_eot[0] = txt_ptr[0];
break;
default:
AsynSrv_errcode = AsynSrv__BAD_PAR;
return False;
}
switch (txt_ptr[0]) {
case '0':
AsynSrv_eot[1] = '\0';
case '1':
AsynSrv_eot[2] = '\0';
case '2':
AsynSrv_eot[3] = '\0';
}
} else {
AsynSrv_errcode = AsynSrv__BAD_PAR;
return False;
}
txt_ptr = va_arg(ap, char *); /* Get pntr to next parameter ident */
}
AsynSrv_call_depth--;
return True;
}
/*
**---------------------------------------------------------------------------
** AsynSrv_ErrInfo: Return detailed status from last operation.
*/
void AsynSrv_ErrInfo(
/* ===============
*/ char **entry_txt,
int *errcode, int *my_errno, int *vaxc_errno)
{
int i, j, k;
char buff[80];
if (AsynSrv_call_depth <= 0) {
strcpy(AsynSrv_routine[0], "AsynSrv_no_error_detected");
*errcode = 0;
*my_errno = 0;
*vaxc_errno = 0;
} else {
if (AsynSrv_call_depth > 1) { /* Concatenate the names */
for (i = 1; i < AsynSrv_call_depth; i++) {
strcat(AsynSrv_routine[0], "/");
StrJoin(AsynSrv_routine[0], sizeof(AsynSrv_routine),
AsynSrv_routine[0], AsynSrv_routine[i]);
}
}
*errcode = AsynSrv_errcode;
*my_errno = AsynSrv_errno;
*vaxc_errno = AsynSrv_vaxc_errno;
switch (AsynSrv_errcode) {
case AsynSrv__BAD_HOST:
strcpy(buff, "/AsynSrv__BAD_HOST");
break;
case AsynSrv__BAD_SOCKET:
strcpy(buff, "/AsynSrv__BAD_SOCKET");
break;
case AsynSrv__BAD_BIND:
strcpy(buff, "/AsynSrv__BAD_BIND");
break;
case AsynSrv__BAD_CONNECT:
strcpy(buff, "/AsynSrv__BAD_CONNECT");
break;
case AsynSrv__BAD_SENDLEN:
strcpy(buff, "/AsynSrv__BAD_SENDLEN");
break;
case AsynSrv__BAD_SEND:
strcpy(buff, "/AsynSrv__BAD_SEND");
break;
case AsynSrv__BAD_SEND_PIPE:
strcpy(buff, "/AsynSrv__BAD_SEND_PIPE");
break;
case AsynSrv__BAD_SEND_NET:
strcpy(buff, "/AsynSrv__BAD_SEND_NET");
break;
case AsynSrv__BAD_SEND_UNKN:
strcpy(buff, "/AsynSrv__BAD_SEND_UNKN");
break;
case AsynSrv__BAD_RECV:
strcpy(buff, "/AsynSrv__BAD_RECV");
break;
case AsynSrv__BAD_RECV_PIPE:
strcpy(buff, "/AsynSrv__BAD_RECV_PIPE");
break;
case AsynSrv__BAD_RECV_NET:
strcpy(buff, "/AsynSrv__BAD_RECV_NET");
break;
case AsynSrv__BAD_RECV_UNKN:
strcpy(buff, "/AsynSrv__BAD_RECV_UNKN");
break;
case AsynSrv__BAD_NOT_BCD:
strcpy(buff, "/AsynSrv__BAD_NOT_BCD");
break;
case AsynSrv__BAD_RECVLEN:
strcpy(buff, "/AsynSrv__BAD_RECVLEN");
break;
case AsynSrv__BAD_FLUSH:
strcpy(buff, "/AsynSrv__BAD_FLUSH");
break;
case AsynSrv__BAD_RECV1:
strcpy(buff, "/AsynSrv__BAD_RECV1");
break;
case AsynSrv__BAD_RECV1_PIPE:
strcpy(buff, "/AsynSrv__BAD_RECV1_PIPE");
break;
case AsynSrv__BAD_RECV1_NET:
strcpy(buff, "/AsynSrv__BAD_RECV1_NET");
break;
case AsynSrv__BAD_PAR:
strcpy(buff, "/AsynSrv__BAD_PAR");
break;
case AsynSrv__FORCED_CLOSED:
strcpy(buff, "/AsynSrv__FORCED_CLOSED");
break;
case AsynSrv__BAD_REPLY:
strcpy(buff, "/AsynSrv__BAD_REPLY");
break;
case AsynSrv__BAD_CMND_LEN:
strcpy(buff, "/AsynSrv__BAD_CMND_LEN");
break;
case AsynSrv__BAD_PROT_LVL:
strcpy(buff, "/AsynSrv__BAD_PROT_LVL");
break;
case AsynSrv__NO_ROOM:
strcpy(buff, "/AsynSrv__NO_ROOM");
break;
default:
sprintf(buff, "/AsynSrv__unkn_err_code: %d", AsynSrv_errcode);
}
StrJoin(AsynSrv_routine[0], sizeof(AsynSrv_routine),
AsynSrv_routine[0], buff);
}
*entry_txt = AsynSrv_routine[0];
AsynSrv_call_depth = 0;
AsynSrv_errcode = 0;
}
/*
**---------------------------------------------------------------------------
** AsynSrv_GetReply: Get next reply from a reply buffer.
*/
char *AsynSrv_GetReply(
/* ================
*/ struct AsynSrv__info *asyn_info,
struct RS__RespStruct *rcve_buff, char *last_rply)
{
char *pntr = NULL;
int i, rply_len;
if (last_rply == NULL) { /* Start with first reply? */
/* Yes */
asyn_info->n_replies = 1;
if (asyn_info->max_replies > 0) {
pntr = rcve_buff->u.rplys;
pntr = pntr + 1 + asyn_info->rply_hdr_len;
}
} else { /* No - get next reply */
if (asyn_info->n_replies < asyn_info->max_replies) { /* If there is one */
i = sscanf((last_rply - asyn_info->rply_hdr_len - 1),
asyn_info->rply_fmt, &rply_len);
if ((i == 1) && (rply_len >= 0)) {
pntr = last_rply + rply_len + asyn_info->rply_hdr_len;
}
}
}
return pntr;
}
/*
**---------------------------------------------------------------------------
** AsynSrv_Open: Open a connection to an RS-232-C Server.
*/
int AsynSrv_Open(
/* ============
*/ struct AsynSrv__info *asyn_info)
{
int i, status;
int my_skt;
char old_time_out[4];
union {
char chars[4];
int val;
} time_out;
char buff[128];
struct RS__MsgStruct s_buff;
struct RS__RespStruct r_buff;
unsigned int oto_len, oto_status;
struct hostent *rmt_hostent;
struct in_addr *rmt_inet_addr_pntr;
struct in_addr rmt_inet_addr;
int rmt_sockname_len;
struct sockaddr_in lcl_sockname;
struct sockaddr_in rmt_sockname;
char *errtxt_ptr;
int errcode, my_errno, my_vaxc_errno;
/*--------------------------------------------------------
*/
asyn_info->skt = 0;
/*--------------------------------------------------------
** Initialise the error info stack and pre-set the
** routine name (in case of error).
*/
AsynSrv_errcode = AsynSrv_errno = AsynSrv_vaxc_errno = 0;
strcpy(AsynSrv_routine[0], "AsynSrv_Open");
AsynSrv_call_depth = 1;
/*--------------------------------------------------------
** Is there room for a new AsynSrv_Open table entry?
*/
if (AsynSrv_n_active >= MAX_OPEN) {
AsynSrv_errcode = AsynSrv__NO_ROOM; /* There isn't! */
return False;
}
/*--------------------------------------------------------
** See if a table entry for this connection already exists.
*/
for (i = 0; i < AsynSrv_n_cnct; i++) {
if (AsynSrv_HPS_list[i].port != asyn_info->port)
continue;
if (strcmp(AsynSrv_HPS_list[i].host, asyn_info->host) == 0)
break;
}
if (i < AsynSrv_n_cnct) { /* Did we find an entry? */
AsynSrv_call_depth--; /* Yes */
AsynSrv_HPS_list[i].usage_cnt++; /* Up the usage count and .. */
AsynSrv_active[AsynSrv_n_active] = /* .. remember the open and .. */
asyn_info;
AsynSrv_n_active++;
asyn_info->skt = /* .. return the socket. */
AsynSrv_HPS_list[i].skt;
if (asyn_info->chan < 0)
asyn_info->chan = 0;
if (asyn_info->chan > 255)
asyn_info->chan = 0;
sprintf(buff, "%04d", asyn_info->chan); /* Convert channel # to ASCII */
memcpy(asyn_info->chan_char, buff, sizeof(asyn_info->chan_char));
asyn_info->protocol_code = AsynSrv_HPS_list[i].protocol_code;
memcpy(asyn_info->protocol_id,
AsynSrv_HPS_list[i].protocol_id,
sizeof(asyn_info->protocol_id));
asyn_info->cmnd_hdr_len = AsynSrv_HPS_list[i].cmnd_hdr_len;
sprintf(asyn_info->cmnd_fmt, "%%0%dd", asyn_info->cmnd_hdr_len);
asyn_info->rply_hdr_len = AsynSrv_HPS_list[i].rply_hdr_len;
sprintf(asyn_info->rply_fmt, "%%%dd", asyn_info->rply_hdr_len);
sprintf(buff, "%04d", AsynSrv_msec_tmo / 100); /* Set dflt time-out ..
** ..(deci-secs) */
memcpy(asyn_info->tmo, buff, sizeof(asyn_info->tmo));
memcpy(asyn_info->eot, /* Set dflt terminator(s) */
AsynSrv_eot, sizeof(asyn_info->eot));
asyn_info->max_replies = asyn_info->n_replies = 0;
return True;
}
/*--------------------------------------------------------
** There is no existing connection. Is there room for
** a new connection entry?
*/
if (AsynSrv_n_cnct >= AsynSrv_MAX_LINK) {
AsynSrv_errcode = AsynSrv__NO_ROOM; /* There isn't! */
return False;
}
/*--------------------------------------------------------
** But, before going any further, do some quick checks on
** values in asyn_info.
*/
if ((asyn_info->port <= 0) || (asyn_info->port > 65535)) {
AsynSrv_errcode = AsynSrv__BAD_PAR; /* Something is bad! */
return False;
}
if (asyn_info->chan < 0)
asyn_info->chan = 0;
if (asyn_info->chan > 255)
asyn_info->chan = 0;
/*--------------------------------------------------------
** Set up a new connection.
*/
StrJoin(AsynSrv_HPS_list[AsynSrv_n_cnct].host,
sizeof(AsynSrv_HPS_list[AsynSrv_n_cnct].host),
asyn_info->host, "");
AsynSrv_HPS_list[AsynSrv_n_cnct].port = asyn_info->port;
/*---------------------------
** Get the Internet address of the server.
*/
rmt_inet_addr.s_addr = inet_addr(asyn_info->host);
if (rmt_inet_addr.s_addr != -1) {
rmt_inet_addr_pntr = &rmt_inet_addr;
} else {
rmt_hostent = gethostbyname(asyn_info->host);
if (rmt_hostent == NULL) {
AsynSrv_errcode = AsynSrv__BAD_HOST;
GetErrno(&AsynSrv_errno, &AsynSrv_vaxc_errno); /* Save errno info */
fprintf(stderr,
"\nAsynSrv_Open/gethostbyname: Failed to get Internet "
"address of \"%s\".\n", asyn_info->host);
return False;
}
rmt_inet_addr_pntr = (struct in_addr *) rmt_hostent->h_addr_list[0];
}
/*---------------------------
** Create a TCP/IP socket for connecting to server and bind it.
*/
my_skt = socket(AF_INET, SOCK_STREAM, 0);
if (my_skt <= 0) {
AsynSrv_errcode = AsynSrv__BAD_SOCKET;
GetErrno(&AsynSrv_errno, &AsynSrv_vaxc_errno); /* Save the errno info */
fprintf(stderr, "\nAsynSrv_Open/socket: Failed to create a socket.\n");
return False;
}
lcl_sockname.sin_family = AF_INET;
lcl_sockname.sin_port = htons(0);
lcl_sockname.sin_addr.s_addr = 0;
status = bind(my_skt, (struct sockaddr *) &lcl_sockname,
sizeof(lcl_sockname));
if (status == -1) {
close(my_skt);
AsynSrv_errcode = AsynSrv__BAD_BIND;
GetErrno(&AsynSrv_errno, &AsynSrv_vaxc_errno); /* Save the errno info */
fprintf(stderr, "\nAsynSrv_Open/bind: Failed to bind socket.\n");
return False;
}
/*---------------------------
** Set short time-out (VMS systems only)
*/
#ifdef __VMS
oto_len = sizeof(old_time_out); /* Save current time-out first */
oto_status = getsockopt(my_skt, IPPROTO_TCP, UCX$C_TCP_PROBE_IDLE,
old_time_out, &oto_len);
if (oto_status == 0) {
time_out.val = AsynSrv_connect_tmo; /* Set new time-out */
status = setsockopt(my_skt, IPPROTO_TCP, UCX$C_TCP_PROBE_IDLE,
time_out.chars, sizeof(time_out));
}
#endif
/*---------------------------
** Connect to RS-232-C Server.
*/
rmt_sockname_len = sizeof(rmt_sockname);
rmt_sockname.sin_family = AF_INET;
rmt_sockname.sin_port = htons(asyn_info->port);
rmt_sockname.sin_addr.s_addr = rmt_inet_addr_pntr->s_addr;
status = connect(my_skt, (struct sockaddr *) &rmt_sockname,
sizeof(rmt_sockname));
if (status != 0) {
close(my_skt);
AsynSrv_errcode = AsynSrv__BAD_CONNECT;
GetErrno(&AsynSrv_errno, &AsynSrv_vaxc_errno); /* Save the errno info */
fprintf(stderr,
"\nAsynSrv_Open/connect: Failed to connect to server.\n");
perror("AsynSrv_Open");
return False;
}
/*---------------------------
** Restore time-out (VMS only)
*/
#ifdef __VMS
if (oto_status == 0) {
setsockopt(my_skt, IPPROTO_TCP, UCX$C_TCP_PROBE_IDLE,
old_time_out, oto_len);
}
#endif
/*---------------------------------------------------
** Setup the defaults in the AsynSrv__info data structure.
*/
asyn_info->skt = my_skt; /* Return socket number to caller */
asyn_info->protocol_code = 0; /* Ensure protocol_code set to "unknown" */
memcpy(asyn_info->protocol_id, "\0\0\0\0",
sizeof(asyn_info->protocol_id));
asyn_info->cmnd_hdr_len = 4;
strcpy(asyn_info->cmnd_fmt, "%04d");
asyn_info->rply_hdr_len = 4;
strcpy(asyn_info->rply_fmt, "%4d");
sprintf(buff, "%04d", asyn_info->chan); /* Convert channel # to ASCII */
memcpy(asyn_info->chan_char, buff, sizeof(asyn_info->chan_char));
sprintf(buff, "%04d", AsynSrv_msec_tmo / 100); /* Set dflt time-out ..
** .. (deci-secs) */
memcpy(asyn_info->tmo, buff, sizeof(asyn_info->tmo));
memcpy(asyn_info->eot, AsynSrv_eot, sizeof(asyn_info->eot)); /* Set ..
** .. dflt terminator(s) */
asyn_info->max_replies = 0;
asyn_info->n_replies = 0;
/*
** Send a null command buffer to the server. This should give
** a "protocol mismatch" error response and from this we can get
** the actual protocol level supported by the server.
*/
status = AsynSrv_SendCmnds(asyn_info, &s_buff, &r_buff, NULL);
if (!status && (AsynSrv_errcode == AsynSrv__BAD_PROT_LVL)) {
/*
** As expected, we got a "protocol mismatch" error.
** Save the server's protocol level for future use.
*/
memcpy(asyn_info->protocol_id, r_buff.s_pcol_lvl,
sizeof(r_buff.s_pcol_lvl));
if (strncmp(r_buff.s_pcol_lvl, RS__PROTOCOL_ID_V01B,
strlen(RS__PROTOCOL_ID_V01B)) == 0) {
asyn_info->protocol_code = RS__PROTOCOL_CODE_V01B;
asyn_info->cmnd_hdr_len = 4;
strcpy(asyn_info->cmnd_fmt, "%04d");
asyn_info->rply_hdr_len = 4;
strcpy(asyn_info->rply_fmt, "%4d");
} else if (strncmp(r_buff.s_pcol_lvl, RS__PROTOCOL_ID,
strlen(RS__PROTOCOL_ID)) == 0) {
asyn_info->protocol_code = RS__PROTOCOL_CODE;
asyn_info->cmnd_hdr_len = 2;
strcpy(asyn_info->cmnd_fmt, "%02d");
asyn_info->rply_hdr_len = 2;
strcpy(asyn_info->rply_fmt, "%2d");
} else {
close(my_skt);
asyn_info->skt = 0;
fprintf(stderr,
"\nAsynSrv_Open: Server protocol level is unrecognised.\n"
" Server level is \"%4s\"\n", r_buff.s_pcol_lvl);
return False;
}
} else {
close(my_skt);
asyn_info->skt = 0;
AsynSrv_errcode = AsynSrv__BAD_PROT_LVL;
fprintf(stderr,
"\nAsynSrv_Open: Problem getting protocol level of Server!\n");
return False;
}
/*---------------------------------------------------
** Complete the setup of the connection table entry
*/
AsynSrv_HPS_list[AsynSrv_n_cnct].skt = my_skt;
AsynSrv_HPS_list[AsynSrv_n_cnct].protocol_code =
asyn_info->protocol_code;
memcpy(AsynSrv_HPS_list[AsynSrv_n_cnct].protocol_id,
asyn_info->protocol_id, sizeof(asyn_info->protocol_id));
AsynSrv_HPS_list[AsynSrv_n_cnct].cmnd_hdr_len = asyn_info->cmnd_hdr_len;
AsynSrv_HPS_list[AsynSrv_n_cnct].rply_hdr_len = asyn_info->rply_hdr_len;
AsynSrv_HPS_list[AsynSrv_n_cnct].usage_cnt = 1;
AsynSrv_n_cnct++;
AsynSrv_active[AsynSrv_n_active] = /* Remember the open in case .. */
asyn_info; /* .. there's a force-exit */
AsynSrv_n_active++;
AsynSrv_errcode = AsynSrv_errno = AsynSrv_vaxc_errno = 0;
AsynSrv_call_depth = 0;
return True;
}
/*
**---------------------------------------------------------------------------
** AsynSrv_Force: Open a connection to an RS-232-C Server.
** Thereby insisting on an own socket.
*/
int AsynSrv_Force(
/* ============
*/ struct AsynSrv__info *asyn_info)
{
int i, status;
int my_skt;
char old_time_out[4];
union {
char chars[4];
int val;
} time_out;
char buff[128];
struct RS__MsgStruct s_buff;
struct RS__RespStruct r_buff;
unsigned int oto_len, oto_status;
struct hostent *rmt_hostent;
struct in_addr *rmt_inet_addr_pntr;
struct in_addr rmt_inet_addr;
int rmt_sockname_len;
struct sockaddr_in lcl_sockname;
struct sockaddr_in rmt_sockname;
char *errtxt_ptr;
int errcode, my_errno, my_vaxc_errno;
/*--------------------------------------------------------
*/
asyn_info->skt = 0;
/*--------------------------------------------------------
** Initialise the error info stack and pre-set the
** routine name (in case of error).
*/
AsynSrv_errcode = AsynSrv_errno = AsynSrv_vaxc_errno = 0;
strcpy(AsynSrv_routine[0], "AsynSrv_Open");
AsynSrv_call_depth = 1;
/*--------------------------------------------------------
** But, before going any further, do some quick checks on
** values in asyn_info.
*/
if ((asyn_info->port <= 0) || (asyn_info->port > 65535)) {
AsynSrv_errcode = AsynSrv__BAD_PAR; /* Something is bad! */
return False;
}
if (asyn_info->chan < 0)
asyn_info->chan = 0;
if (asyn_info->chan > 255)
asyn_info->chan = 0;
/*--------------------------------------------------------
** Set up a new connection.
*/
/*---------------------------
** Get the Internet address of the server.
*/
rmt_inet_addr.s_addr = inet_addr(asyn_info->host);
if (rmt_inet_addr.s_addr != -1) {
rmt_inet_addr_pntr = &rmt_inet_addr;
} else {
rmt_hostent = gethostbyname(asyn_info->host);
if (rmt_hostent == NULL) {
AsynSrv_errcode = AsynSrv__BAD_HOST;
GetErrno(&AsynSrv_errno, &AsynSrv_vaxc_errno); /* Save errno info */
fprintf(stderr,
"\nAsynSrv_Open/gethostbyname: Failed to get Internet "
"address of \"%s\".\n", asyn_info->host);
return False;
}
rmt_inet_addr_pntr = (struct in_addr *) rmt_hostent->h_addr_list[0];
}
/*---------------------------
** Create a TCP/IP socket for connecting to server and bind it.
*/
my_skt = socket(AF_INET, SOCK_STREAM, 0);
if (my_skt <= 0) {
AsynSrv_errcode = AsynSrv__BAD_SOCKET;
GetErrno(&AsynSrv_errno, &AsynSrv_vaxc_errno); /* Save the errno info */
fprintf(stderr, "\nAsynSrv_Open/socket: Failed to create a socket.\n");
return False;
}
lcl_sockname.sin_family = AF_INET;
lcl_sockname.sin_port = htons(0);
lcl_sockname.sin_addr.s_addr = 0;
status = bind(my_skt, (struct sockaddr *) &lcl_sockname,
sizeof(lcl_sockname));
if (status == -1) {
close(my_skt);
AsynSrv_errcode = AsynSrv__BAD_BIND;
GetErrno(&AsynSrv_errno, &AsynSrv_vaxc_errno); /* Save the errno info */
fprintf(stderr, "\nAsynSrv_Open/bind: Failed to bind socket.\n");
return False;
}
/*---------------------------
** Set short time-out (VMS systems only)
*/
#ifdef __VMS
oto_len = sizeof(old_time_out); /* Save current time-out first */
oto_status = getsockopt(my_skt, IPPROTO_TCP, UCX$C_TCP_PROBE_IDLE,
old_time_out, &oto_len);
if (oto_status == 0) {
time_out.val = AsynSrv_connect_tmo; /* Set new time-out */
status = setsockopt(my_skt, IPPROTO_TCP, UCX$C_TCP_PROBE_IDLE,
time_out.chars, sizeof(time_out));
}
#endif
/*---------------------------
** Connect to RS-232-C Server.
*/
rmt_sockname_len = sizeof(rmt_sockname);
rmt_sockname.sin_family = AF_INET;
rmt_sockname.sin_port = htons(asyn_info->port);
rmt_sockname.sin_addr.s_addr = rmt_inet_addr_pntr->s_addr;
status = connect(my_skt, (struct sockaddr *) &rmt_sockname,
sizeof(rmt_sockname));
if (status != 0) {
close(my_skt);
AsynSrv_errcode = AsynSrv__BAD_CONNECT;
GetErrno(&AsynSrv_errno, &AsynSrv_vaxc_errno); /* Save the errno info */
fprintf(stderr,
"\nAsynSrv_Open/connect: Failed to connect to server.\n");
perror("AsynSrv_Open");
return False;
}
/*---------------------------
** Restore time-out (VMS only)
*/
#ifdef __VMS
if (oto_status == 0) {
setsockopt(my_skt, IPPROTO_TCP, UCX$C_TCP_PROBE_IDLE,
old_time_out, oto_len);
}
#endif
/*---------------------------------------------------
** Setup the defaults in the AsynSrv__info data structure.
*/
asyn_info->skt = my_skt; /* Return socket number to caller */
asyn_info->protocol_code = 0; /* Ensure protocol_code set to "unknown" */
memcpy(asyn_info->protocol_id, "\0\0\0\0",
sizeof(asyn_info->protocol_id));
asyn_info->cmnd_hdr_len = 4;
strcpy(asyn_info->cmnd_fmt, "%04d");
asyn_info->rply_hdr_len = 4;
strcpy(asyn_info->rply_fmt, "%4d");
sprintf(buff, "%04d", asyn_info->chan); /* Convert channel # to ASCII */
memcpy(asyn_info->chan_char, buff, sizeof(asyn_info->chan_char));
sprintf(buff, "%04d", AsynSrv_msec_tmo / 100); /* Set dflt time-out ..
** .. (deci-secs) */
memcpy(asyn_info->tmo, buff, sizeof(asyn_info->tmo));
memcpy(asyn_info->eot, AsynSrv_eot, sizeof(asyn_info->eot)); /* Set ..
** .. dflt terminator(s) */
asyn_info->max_replies = 0;
asyn_info->n_replies = 0;
/*
** Send a null command buffer to the server. This should give
** a "protocol mismatch" error response and from this we can get
** the actual protocol level supported by the server.
*/
status = AsynSrv_SendCmnds(asyn_info, &s_buff, &r_buff, NULL);
if (!status && (AsynSrv_errcode == AsynSrv__BAD_PROT_LVL)) {
/*
** As expected, we got a "protocol mismatch" error.
** Save the server's protocol level for future use.
*/
memcpy(asyn_info->protocol_id, r_buff.s_pcol_lvl,
sizeof(r_buff.s_pcol_lvl));
if (strncmp(r_buff.s_pcol_lvl, RS__PROTOCOL_ID_V01B,
strlen(RS__PROTOCOL_ID_V01B)) == 0) {
asyn_info->protocol_code = RS__PROTOCOL_CODE_V01B;
asyn_info->cmnd_hdr_len = 4;
strcpy(asyn_info->cmnd_fmt, "%04d");
asyn_info->rply_hdr_len = 4;
strcpy(asyn_info->rply_fmt, "%4d");
} else if (strncmp(r_buff.s_pcol_lvl, RS__PROTOCOL_ID,
strlen(RS__PROTOCOL_ID)) == 0) {
asyn_info->protocol_code = RS__PROTOCOL_CODE;
asyn_info->cmnd_hdr_len = 2;
strcpy(asyn_info->cmnd_fmt, "%02d");
asyn_info->rply_hdr_len = 2;
strcpy(asyn_info->rply_fmt, "%2d");
} else {
close(my_skt);
asyn_info->skt = 0;
fprintf(stderr,
"\nAsynSrv_Open: Server protocol level is unrecognised.\n"
" Server level is \"%4s\"\n", r_buff.s_pcol_lvl);
return False;
}
} else {
close(my_skt);
asyn_info->skt = 0;
AsynSrv_errcode = AsynSrv__BAD_PROT_LVL;
fprintf(stderr,
"\nAsynSrv_Open: Problem getting protocol level of Server!\n");
return False;
}
AsynSrv_errcode = AsynSrv_errno = AsynSrv_vaxc_errno = 0;
AsynSrv_call_depth = 0;
return True;
}
/*
**---------------------------------------------------------------------------
** AsynSrv_SendCmnds: Send commands to RS232C server.
*/
int AsynSrv_SendCmnds(
/* =================
*/ struct AsynSrv__info *asyn_info,
struct RS__MsgStruct *send_buff,
struct RS__RespStruct *rcve_buff, ...)
{ /* Now we have list of commands -
** char *txt = pntr to cmnd strng
** Terminate list with *txt = NULL.
*/
int i, status, c_len, size, max_size, ncmnds;
int bytes_to_come, bytes_left;
char *nxt_byte_ptr;
char err_text[80];
char text[20];
va_list ap; /* Pointer to variable args */
char *txt_ptr;
char *cmnd_lst_ptr;
/*----------------------------------------------
** Pre-set the routine name (in case of error)
*/
if (AsynSrv_errcode == 0 && AsynSrv_call_depth < 5) {
strcpy(AsynSrv_routine[AsynSrv_call_depth], "AsynSrv_SendCmnds");
AsynSrv_call_depth++;
}
/*----------------------------------------------
** Do nothing if no connection - the connection gets
** closed if an error is detected. The connection may
** also be marked to have been forcefully closed.
*/
if (asyn_info->skt <= 0) {
memset(rcve_buff->msg_size, '0', sizeof(rcve_buff->msg_size));
if ((AsynSrv_errcode == 0) && (asyn_info->skt < 0)) {
AsynSrv_errcode = AsynSrv__FORCED_CLOSED;
}
return False;
}
/*----------------------------------------------
** Build message for server from the list of commands.
*/
asyn_info->max_replies = asyn_info->n_replies = 0;
asyn_info->msg_id++; /* Set up an incrementing message id */
if (asyn_info->msg_id > 9999)
asyn_info->msg_id = 1;
sprintf(send_buff->msg_id, "%04d", asyn_info->msg_id);
memcpy(send_buff->c_pcol_lvl, asyn_info->protocol_id,
sizeof(send_buff->c_pcol_lvl));
memcpy(send_buff->serial_port, asyn_info->chan_char,
sizeof(send_buff->serial_port));
memcpy(send_buff->tmo, asyn_info->tmo, sizeof(send_buff->tmo));
memcpy(send_buff->terms, asyn_info->eot, sizeof(send_buff->terms));
memcpy(send_buff->n_cmnds, "0000", sizeof(send_buff->n_cmnds));
va_start(ap, rcve_buff); /* Set up var arg machinery */
txt_ptr = va_arg(ap, char *); /* Get pntr to next cmnd string */
ncmnds = 0;
cmnd_lst_ptr = &send_buff->cmnds[0];
bytes_left = sizeof(*send_buff) -
OffsetOf(struct RS__MsgStruct, cmnds[0]);
while (txt_ptr != NULL) {
c_len = strlen(txt_ptr);
size = asyn_info->cmnd_hdr_len + c_len;
if (size > bytes_left) {
AsynSrv_errcode = AsynSrv__BAD_SENDLEN; /* Too much to send */
fprintf(stderr, "\nAsynSrv_SendCmnds/send: too much to send"
" - request ignored.\n");
memset(rcve_buff->msg_size, '0', sizeof(rcve_buff->msg_size));
return False;
} else {
sprintf(cmnd_lst_ptr, asyn_info->cmnd_fmt, c_len);
if (cmnd_lst_ptr[asyn_info->cmnd_hdr_len] != '\0') {
AsynSrv_errcode = AsynSrv__BAD_CMND_LEN;
fprintf(stderr, "\nAsynSrv_SendCmnds/send: command too long -"
" - request ignored.\n");
memset(rcve_buff->msg_size, '0', sizeof(rcve_buff->msg_size));
return False;
}
cmnd_lst_ptr += asyn_info->cmnd_hdr_len;
strcpy(cmnd_lst_ptr, txt_ptr);
cmnd_lst_ptr += c_len;
ncmnds++;
bytes_left = bytes_left - size;
txt_ptr = va_arg(ap, char *);
}
}
sprintf(text, "%04d", ncmnds);
memcpy(send_buff->n_cmnds, text, sizeof(send_buff->n_cmnds));
size = cmnd_lst_ptr - send_buff->msg_id;
size = (size + 3) & (~3); /* Round up to multiple of 4 */
sprintf(text, "%04d", size);
memcpy(send_buff->msg_size, text, sizeof(send_buff->msg_size));
size += sizeof(send_buff->msg_size);
status = send(asyn_info->skt, (char *) send_buff, size, 0);
if (status != size) {
GetErrno(&AsynSrv_errno, &AsynSrv_vaxc_errno);
if (status == 0) {
AsynSrv_errcode = AsynSrv__BAD_SEND; /* Server exited (probably) */
fprintf(stderr,
"\nAsynSrv_SendCmnds/send: probable network problem");
} else if (status == -1) {
if (AsynSrv_errno == EPIPE) {
AsynSrv_errcode = AsynSrv__BAD_SEND_PIPE; /* Server exited (probably) */
fprintf(stderr, "\nAsynSrv_SendCmnds/send: broken network pipe");
} else {
AsynSrv_errcode = AsynSrv__BAD_SEND_NET; /* It's some other net problem */
perror("AsynSrv_SendCmnds/send");
}
} else {
AsynSrv_errcode = AsynSrv__BAD_SEND_UNKN; /* TCP/IP problems */
fprintf(stderr, "\nAsynSrv_SendCmnds/send: probable TCP/IP problem");
}
AsynSrv_Close(asyn_info, True); /* Force close TCP/IP connection */
fprintf(stderr, " - link to server force-closed.\n");
return False;
}
size = sizeof(rcve_buff->msg_size);
status = recv(asyn_info->skt, rcve_buff->msg_size, size, 0);
if (status != size) {
GetErrno(&AsynSrv_errno, &AsynSrv_vaxc_errno);
if (status == 0) {
AsynSrv_errcode = AsynSrv__BAD_RECV; /* Server exited (probably) */
fprintf(stderr,
"\nAsynSrv_SendCmnds/recv: probable network problem");
} else if (status == -1) {
if (AsynSrv_errno == EPIPE) {
AsynSrv_errcode = AsynSrv__BAD_RECV_PIPE; /* Server exited (probably) */
fprintf(stderr, "\nAsynSrv_SendCmnds/recv: broken network pipe");
} else {
AsynSrv_errcode = AsynSrv__BAD_RECV_NET; /* It's some other net problem */
perror("AsynSrv_SendCmnds/recv");
}
} else {
AsynSrv_errcode = AsynSrv__BAD_RECV_UNKN; /* TCP/IP problems */
fprintf(stderr, "\nAsynSrv_SendCmnds/recv: probable TCP/IP problem");
}
AsynSrv_Close(asyn_info, True); /* Force close TCP/IP connection */
fprintf(stderr, " - link to server force-closed.\n");
return False;
}
if (sscanf(rcve_buff->msg_size, "%4d", &bytes_to_come) != 1) {
AsynSrv_errcode = AsynSrv__BAD_NOT_BCD; /* Header not an ASCII BCD integer */
AsynSrv_Close(asyn_info, True); /* Force close TCP/IP connection */
fprintf(stderr, "\nAsynSrv_SendCmnds/recv: non-BCD byte count"
" - link to server force-closed.\n");
return False;
}
max_size = sizeof(*rcve_buff) - size;
if (bytes_to_come > max_size) {
AsynSrv_errcode = AsynSrv__BAD_RECVLEN;
fprintf(stderr,
"\nAsynSrv_SendCmnds/recv: pending message length too big"
" - flushing ...\n");
nxt_byte_ptr = &rcve_buff->msg_size[size];
while (bytes_to_come > 0) { /* Flush out the incoming message */
bytes_left = bytes_to_come;
if (bytes_left > max_size)
bytes_left = max_size;
status = recv(asyn_info->skt, nxt_byte_ptr, bytes_left, 0);
if (status <= 0) {
AsynSrv_errcode = AsynSrv__BAD_FLUSH; /* TCP/IP problem during flush */
GetErrno(&AsynSrv_errno, &AsynSrv_vaxc_errno);
AsynSrv_Close(asyn_info, True); /* Force close TCP/IP connection */
fprintf(stderr, "\nAsynSrv_SendCmnds/recv: network problem during"
" flush.\nLink to server force-closed.\n");
return False;
}
bytes_to_come = bytes_to_come - status;
}
fprintf(stderr, "\n flushed OK.\n");
memset(rcve_buff->msg_size, '0', sizeof(rcve_buff->msg_size));
return False;
} else {
nxt_byte_ptr = &rcve_buff->msg_size[size];
bytes_left = bytes_to_come;
while (bytes_left > 0) { /* Read the rest of the response */
status = recv(asyn_info->skt, nxt_byte_ptr, bytes_left, 0);
if (status <= 0) {
GetErrno(&AsynSrv_errno, &AsynSrv_vaxc_errno);
if (status == 0) {
AsynSrv_errcode = AsynSrv__BAD_RECV1; /* Server exited (probably) */
fprintf(stderr, "\nAsynSrv_SendCmnds/recv/1: probable network "
"problem");
} else {
if (AsynSrv_errno == EPIPE) {
AsynSrv_errcode = AsynSrv__BAD_RECV1_PIPE; /* Server exited (probably) */
fprintf(stderr,
"\nAsynSrv_SendCmnds/recv/1: broken network pipe");
} else {
AsynSrv_errcode = AsynSrv__BAD_RECV1_NET; /* It's some other net fault */
perror("AsynSrv_SendCmnds/recv/1");
}
}
AsynSrv_Close(asyn_info, True); /* Force close TCP/IP connection */
fprintf(stderr, " - link to server force-closed.\n");
return False;
}
bytes_left = bytes_left - status;
nxt_byte_ptr = nxt_byte_ptr + status;
}
if (strncmp(asyn_info->protocol_id, rcve_buff->s_pcol_lvl,
sizeof(rcve_buff->s_pcol_lvl)) != 0) {
AsynSrv_errcode = AsynSrv__BAD_PROT_LVL; /* Protocol level is bad */
return False;
}
if ((sscanf(rcve_buff->n_rply, "%4d", &asyn_info->max_replies) != 1) ||
(asyn_info->max_replies < 0)) {
AsynSrv_errcode = AsynSrv__BAD_REPLY; /* Reply is bad */
if (AsynSrv_call_depth < 5) { /* Add reply to routine stack */
bytes_to_come = bytes_to_come + 4;
if (bytes_to_come >= sizeof(AsynSrv_routine[0]))
bytes_to_come = sizeof(AsynSrv_routine[0]) - 1;
for (i = 0; i < bytes_to_come; i++) {
if (rcve_buff->msg_size[i] == '\0')
rcve_buff->msg_size[i] = '.';
}
rcve_buff->msg_size[bytes_to_come] = '\0';
strcpy(AsynSrv_routine[AsynSrv_call_depth], rcve_buff->msg_size);
AsynSrv_call_depth++;
}
return False;
}
}
AsynSrv_call_depth--;
return True;
}
/*-------------------------------------------- End of AsynSrv_Utility.C -----*/