1559 lines
57 KiB
C
1559 lines
57 KiB
C
#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 -----*/
|