#define ident "1C06" #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. ** 1B07 11-Mar-1998 DM. Allow range of msecTmo to be 0 - 999999 (it was ** 100 - 999999). ** 1C01 21-Mar-2000 MZ. Introduced idleHandler ** 1C02 30-Mar-2000 DM. Add trace and flush facilities. ** 1C06 30-Aug-2000 DM. Add AsynSrv_GetLenTerm. **============================================================================ ** The entry points included in this module are described below. Prototypes ** can be defined via: ** ** #include ** ** AsynSrv_ChanClose - Send a "CLOSE CHAN" request to RS-232-C Server. ** 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_Flush - Send a "FLUSH" request to an RS-232-C Server. ** AsynSrv_GetLenTerm - Get length and terminator of a reply. ** AsynSrv_GetReply - Get next reply from a reply buffer. ** AsynSrv_Open - Open a connection to an RS-232-C Server. ** AsynSrv_OpenNew - Same as AsynSrv_Open but forces the opening ** of a new socket. ** AsynSrv_SendCmnds - Send commands to a channel of an RS-232-C Server. ** AsynSrv_SendCmndsBig - Similar to AsynSrv_SendCmnds but with user ** defined buffer sizes. ** AsynSrv_Trace - Send a "TRACE ON" or "TRACE OFF" request to ** an RS-232-C Server. ** AsynSrv_Trace_Write - Send a "TRACE WRITE" request to RS-232-C Server. ** Other entry points which are private (i.e. not in ): ** AsynSrv_SendSpecCmnd - Send a "special" command to an RS-232-C Server. **--------------------------------------------------------------------- ** int AsynSrv_ChanClose (&asyn_info) ** ----------------- ** 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. ** Output Args: ** none ** Modified Args: ** none ** Return status: ** True if no problems detected, otherwise False and errcode (see ** AsynSrv_ErrInfo) is set to indicate the nature of the problem. ** See AsynSrv_SendSpecCmnd for possible error codes. ** Routines called: ** AsynSrv_SendSpecCmnd ** Description: ** AsynSrv_SendSpecCmnd is called to send the 4-byte "special" ** command "-006" to the server to cause it to close its serial ports. **--------------------------------------------------------------------- ** 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 --> 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 --> Unrecognised par_id or msecTmo < 0 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 0 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). ** "idleHdl" void (*hdl) (int msecTmo, int socket) MZ. ** A handler which is called in AsynSrv_SendCmds ** before receiving the response. The handler ** should contain a call to "select ()" and return ** on a read event on the socket passed as ** argument, or after the timeout specified ** has expired. **--------------------------------------------------------------------- ** 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 --> Unrecognised par_id or msecTmo < 0 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 0 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. **------------------------------------------------------------------------- ** int AsynSrv_Flush (&asyn_info) ** ------------- ** 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. ** Output Args: ** none ** Modified Args: ** none ** Return status: ** Same as AsynSrv_ChanClose ** Routines called: ** Same as AsynSrv_ChanClose ** Description: ** AsynSrv_SendSpecCmnd is called to send the 4-byte "special" ** command "-004" to the server to cause it to close its serial ports. **------------------------------------------------------------------------- ** int AsynSrv_GetLenTerm (&asyn_info, &rcve_buff, &rply, *len, &term) ** ------------------ ** Input 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. ** struct RS__RespStruct *rcve_buff - address of receive buffer used ** in last call to AsynSrv_SendCmnds. ** char *rply - address of a reply in rcve_buff as ** returned by AsynSrv_GetReply. ** Output Args: ** int *len - address of location to receive the ** length of the reply. ** char *term - address of location to receive the ** terminator of the reply. ** Modified Args: ** none ** Return status: ** True if everything seems to be OK. Otherwise, False. ** Routines called: ** none ** Description: ** AsynSrv_GetLenTerm simply converts the length of the reply as saved ** in rply[-hdr_size-1] from ASCII to binary, subtracts 2 from it (to ** allow for the terminator byte and the null termination character) and ** returns it to the caller. *term is set to the value of the character ** at location rply[-1]. **------------------------------------------------------------------------- ** 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: ** struct AsynSrv__info *asyn_info ** 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. ** asyn_info->chan - Number of RS-232-C channel to be used. ** 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 --> Call to "gethostbyname" failed to get ** network addr of host. ** ASYNSRV__BAD_SOCKET --> Call to "socket" failed. ** ASYNSRV__BAD_BIND --> Call to "bind" failed. ** ASYNSRV__BAD_CONNECT --> Call to "connect" failed. ** ASYNSRV__BAD_PAR --> Bad parameter found. Probably ** asyn_info->port or asyn_info->chan ** are out of range. ** BAD_PROT_LVL --> Server protocol level is not valid. ** ASYNSRV__NO_ROOM --> 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_OpenNew (&asyn_info) ** --------------- ** Input Args: ** struct AsynSrv__info *asyn_info ** 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. ** asyn_info->chan - Number of RS-232-C channel to be used. ** 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: ** See AsynSrv_Open ** Routines called: ** See AsynSrv_Open ** Description: ** This routine is the same as AsynSrv_Open but forces the opening ** of a new socket. The socket will be marked to ensure that no other ** connections share this connection. **------------------------------------------------------------------------- ** 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_SEND_LEN --> 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. ** ASYNSRV__BAD_CMND_LEN --> A command is too long - it's length cannot ** be encoded into the command header field ** The next 4 errors are related to network errors whilst sending the ** message buffer to the server: ** ASYNSRV__BAD_SEND --> Network problem - server has ** probably abended. ** ASYNSRV__BAD_SEND_PIPE --> Network pipe broken - probably same ** cause as ASYNSRV__BAD_SEND. ** ASYNSRV__BAD_SEND_NET --> Some other network problem. "errno" ** may be helpful. ** ASYNSRV__BAD_SEND_UNKN --> Some other network problem happened ** resulting in the message not ** getting sent completely. "errno" is ** probably not helpful in this case. ** ASYNSRV__BAD_RECV \ These are network errors whilst ** ASYNSRV__BAD_RECV_PIPE > receiving the 4-byte response header. ** ASYNSRV__BAD_RECV_NET / They are analogous to ASYNSRV__BAD_SEND ** ASYNSRV__BAD_RECV_UNKN / ... ASYNSRV__BAD_SEND_UNKN. ** ASYNSRV__BAD_NOT_BCD --> The 4-byte response header is not an ** ASCII coded decimal integer. ** ASYNSRV__BAD_RECV_LEN --> 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 --> Some network error was detected ** during flushing. This is an "or" ** of errors ASYNSRV__BAD_RECV to ** ASYNSRV__BAD_RECV_UNKN. ** ASYNSRV__FORCED_CLOSED --> The connection to the channel has been ** forcefully closed. See below. ** ASYNSRV__BAD_REPLY --> 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. ** ** ASYNSRV__BAD_RECV1 \ These are network errors whilst receiving ** ASYNSRV__BAD_RECV1_PIPE > the body of the response. They are ** ASYNSRV__BAD_RECV1_NET / equivalent to ASYNSRV__BAD_RECV, ** ASYNSRV__BAD_RECV_PIPE and ** 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_SEND_LEN and ** ASYNSRV__BAD_SEND_PIPE ASYNSRV__BAD_RECV_LEN and ** ASYNSRV__BAD_SEND_NET ASYNSRV__BAD_REPLY ** ASYNSRV__BAD_SEND_UNKN do not cause a close) ** 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. **------------------------------------------------------------------------- ** int AsynSrv_SendCmndsBig (&asyn_info, &send_buff, send_buff_size, ** -------------------- &rcve_buff, rcve_buff_size, ...) ** 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. ** int send_buff_size - The size of *send_buff in bytes. ** int rcve_buff_size - The size of *rcve_buff in bytes. ** int *c_len \ - a list of argument pairs specifying the commands ** char *cmd > to be sent. The list is terminated by ** ... / c_len == NULL. If *c_len > 0, it specifies the ** number of bytes in the command. Otherwise, *cmd ** is assumed to be a zero-terminated string. ** The *cmd string must include any terminator ** byte(s) but, if *c_len > 0, it does not need to ** be zero-terminated. ** Output Args: ** struct RS__RespStruct *rcve_buff - a buffer to receive the response ** from the server. Note that this structure must ** be extended to size rcve_buff_size by the use ** of suitable unions. ** Modified Args: ** struct RS__MsgStruct *send_buff - a buffer for holding the commands ** for sending to the server. Note that this ** structure must be extended to size ** send_buff_size by the use of suitable unions. ** Return status: ** Same as AsynSrv_SendCmnds with the addition of error code: ** ASYNSRV__BAD_SEND_PAR --> Either send_buff_size or rcve_buff_size ** is less than 64. ** Routines called: ** Socket library routines send and recv. ** Description: ** The procedure is similar to AsynSrv_SendCmnds except that the commands ** are specified by a pair of arguments (to allow for the binary ** transmission of zeros) and the send and receive structures are assumed ** to have been extended to the sizes specified by suitable declarations ** in the calling module. **------------------------------------------------------------------------- ** int AsynSrv_SendSpecCmnd (&asyn_info, &cmnd) ** ------------------- ** 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 *cmnd - the 4-byte special command to be sent. ** Output Args: ** none ** Modified Args: ** none ** 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: ** The next 4 errors are related to network errors whilst sending the ** 4-byte message buffer to the server: ** ASYNSRV__BAD_SEND --> Network problem - server has ** probably abended. ** ASYNSRV__BAD_SEND_PIPE --> Network pipe broken - probably same ** cause as ASYNSRV__BAD_SEND. ** ASYNSRV__BAD_SEND_NET --> Some other network problem. "errno" ** may be helpful. ** ASYNSRV__BAD_SEND_UNKN --> Some other network problem happened ** resulting in the message not ** getting sent completely. "errno" is ** probably not helpful in this case. ** ASYNSRV__BAD_RECV \ These are network errors whilst ** ASYNSRV__BAD_RECV_PIPE > receiving the 4-byte response. ** ASYNSRV__BAD_RECV_NET / They are analogous to ASYNSRV__BAD_SEND ** ASYNSRV__BAD_RECV_UNKN / ... ASYNSRV__BAD_SEND_UNKN. ** ASYNSRV__BAD_NOT_BCD --> The 4-byte response header is not an ** echo of the 4 bytes which were sent. ** ASYNSRV__FORCED_CLOSED --> The connection to the channel has been ** forcefully closed. See below. ** 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: ** AsynSrv_SendSpecCmnd sends the 4-byte "special" command, cmnd, to the ** server and reads the response. The response should be an echo of the ** command which was sent. ** Note: ** For any of the following errors: ** ASYNSRV__BAD_SEND ** ASYNSRV__BAD_SEND_PIPE ** 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 ** 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. **------------------------------------------------------------------------- ** int AsynSrv_Trace (&asyn_info, state) ** ------------- ** 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. ** int state - True/False to turn tracing on/off. ** Output Args: ** none ** Modified Args: ** none ** Return status: ** Same as AsynSrv_ChanClose ** Routines called: ** Same as AsynSrv_ChanClose ** Description: ** AsynSrv_SendSpecCmnd is called to send a 4-byte "special" command ** to the server. The command is "-002" to turn on tracing and "-003" ** to turn off tracing. ** Description: ** To turn on tracing, the 4-byte message "-002" is sent to the server. ** To turn off tracing, the 4-byte message "-003" is sent to the server. ** The server is expected to respond by echoing the message. ** **------------------------------------------------------------------------- ** int AsynSrv_Trace_Write (&asyn_info) ** ------------------- ** 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. ** Output Args: ** none ** Modified Args: ** none ** Return status: ** Same as AsynSrv_ChanClose ** Routines called: ** Same as AsynSrv_ChanClose ** Description: ** AsynSrv_SendSpecCmnd is called to send the 4-byte "special" ** command "-005" to the server to cause it to write its trace ** buffer to disk. **============================================================================*/ /* **--------------------------------------------------------------------------- ** Global Definitions */ #include #include #include #include #include #include #include #include #include #include #ifdef __VMS #pragma nostandard /* The "$" characters in ucx$inetdef.h give trouble! */ #include #include #else #include #endif /*-----------------------------------------------------------------*/ #include #include #include #define True 1 #define False 0 #define MAX_OPEN 64 int AsynSrv_SendSpecCmnd( /* A prototype for a local routine */ struct AsynSrv__info *asyn_info, char *cmnd); /*-------------------------------------------------------------------------- ** 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_ChanClose: Send a "CLOSE CHAN" request to ** RS232C server. */ int AsynSrv_ChanClose( /* ================= */ struct AsynSrv__info *asyn_info) { int status; char cmnd[8], rply[8]; /*---------------------------------------------- ** Pre-set the routine name (in case of error) */ if (AsynSrv_errcode == 0 && AsynSrv_call_depth < 5) { strcpy(AsynSrv_routine[AsynSrv_call_depth], "AsynSrv_ChanClose"); 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) { if ((AsynSrv_errcode == 0) && (asyn_info->skt < 0)) { AsynSrv_errcode = ASYNSRV__FORCED_CLOSED; } return False; } /*---------------------------------------------- ** Send message and get reply. */ status = AsynSrv_SendSpecCmnd(asyn_info, "-006"); if (AsynSrv_errcode == 0) AsynSrv_call_depth--; return status; } /* **--------------------------------------------------------------------------- ** 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 != 0) { 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--; } if (AsynSrv_errcode == 0) AsynSrv_call_depth--; return True; } /* **--------------------------------------------------------------------------- ** AsynSrv_Config: Configure an open connection. */ int AsynSrv_Config( /* ============== */ struct AsynSrv__info *asyn_info, ...) { char buff[16], my_eot[4]; va_list ap; /* Pointer to variable args */ char *txt_ptr; int intval; typedef void (*IdleHandler) (int, int); /* ** 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 < 0) || (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(my_eot, "\0\0\0\0", 4); switch (txt_ptr[0]) { case '3': my_eot[3] = txt_ptr[3]; case '2': my_eot[2] = txt_ptr[2]; case '1': my_eot[1] = txt_ptr[1]; case '0': my_eot[0] = txt_ptr[0]; break; default: AsynSrv_errcode = ASYNSRV__BAD_PAR; return False; } memcpy(asyn_info->eot, my_eot, 4); } else if (strcmp(txt_ptr, "idleHdl") == 0) { /* MZ. */ asyn_info->idleHandler = va_arg(ap, IdleHandler); } else { AsynSrv_errcode = ASYNSRV__BAD_PAR; return False; } txt_ptr = va_arg(ap, char *); /* Get pntr to next parameter ident */ } if (AsynSrv_errcode == 0) 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 < 0) || (intval > 999999)) { 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 */ } if (AsynSrv_errcode == 0) 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_BIND: strcpy(buff, "/ASYNSRV__BAD_BIND"); break; case ASYNSRV__BAD_CMND_LEN: strcpy(buff, "/ASYNSRV__BAD_CMND_LEN"); break; case ASYNSRV__BAD_CONNECT: strcpy(buff, "/ASYNSRV__BAD_CONNECT"); break; case ASYNSRV__BAD_FLUSH: strcpy(buff, "/ASYNSRV__BAD_FLUSH"); break; case ASYNSRV__BAD_HOST: strcpy(buff, "/ASYNSRV__BAD_HOST"); break; case ASYNSRV__BAD_NOT_BCD: strcpy(buff, "/ASYNSRV__BAD_NOT_BCD"); break; case ASYNSRV__BAD_PAR: strcpy(buff, "/ASYNSRV__BAD_PAR"); break; case ASYNSRV__BAD_PROT_LVL: strcpy(buff, "/ASYNSRV__BAD_PROT_LVL"); break; case ASYNSRV__BAD_RECV: strcpy(buff, "/ASYNSRV__BAD_RECV"); break; case ASYNSRV__BAD_RECV_LEN: strcpy(buff, "/ASYNSRV__BAD_RECV_LEN"); break; case ASYNSRV__BAD_RECV_NET: strcpy(buff, "/ASYNSRV__BAD_RECV_NET"); break; case ASYNSRV__BAD_RECV_PIPE: strcpy(buff, "/ASYNSRV__BAD_RECV_PIPE"); break; case ASYNSRV__BAD_RECV_UNKN: strcpy(buff, "/ASYNSRV__BAD_RECV_UNKN"); break; case ASYNSRV__BAD_RECV1: strcpy(buff, "/ASYNSRV__BAD_RECV1"); break; case ASYNSRV__BAD_RECV1_NET: strcpy(buff, "/ASYNSRV__BAD_RECV1_NET"); break; case ASYNSRV__BAD_RECV1_PIPE: strcpy(buff, "/ASYNSRV__BAD_RECV1_PIPE"); break; case ASYNSRV__BAD_REPLY: strcpy(buff, "/ASYNSRV__BAD_REPLY"); break; case ASYNSRV__BAD_SEND: strcpy(buff, "/ASYNSRV__BAD_SEND"); break; case ASYNSRV__BAD_SEND_LEN: strcpy(buff, "/ASYNSRV__BAD_SEND_LEN"); break; case ASYNSRV__BAD_SEND_NET: strcpy(buff, "/ASYNSRV__BAD_SEND_NET"); break; case ASYNSRV__BAD_SEND_PIPE: strcpy(buff, "/ASYNSRV__BAD_SEND_PIPE"); break; case ASYNSRV__BAD_SEND_UNKN: strcpy(buff, "/ASYNSRV__BAD_SEND_UNKN"); break; case ASYNSRV__BAD_SOCKET: strcpy(buff, "/ASYNSRV__BAD_SOCKET"); break; case ASYNSRV__FORCED_CLOSED: strcpy(buff, "/ASYNSRV__FORCED_CLOSED"); 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_Flush: Send a Flush command to RS232C server. */ int AsynSrv_Flush( /* ============= */ struct AsynSrv__info *asyn_info) { int status; char cmnd[8], rply[8]; /*---------------------------------------------- ** Pre-set the routine name (in case of error) */ if (AsynSrv_errcode == 0 && AsynSrv_call_depth < 5) { strcpy(AsynSrv_routine[AsynSrv_call_depth], "AsynSrv_Flush"); 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) { if ((AsynSrv_errcode == 0) && (asyn_info->skt < 0)) { AsynSrv_errcode = ASYNSRV__FORCED_CLOSED; } return False; } /*---------------------------------------------- ** Send message and get reply. */ status = AsynSrv_SendSpecCmnd(asyn_info, "-004"); if (AsynSrv_errcode == 0) AsynSrv_call_depth--; return status; } /* **--------------------------------------------------------------------------- ** AsynSrv_GetLenTerm: Get length and terminator of given ** reply from reply buffer. */ int AsynSrv_GetLenTerm( /* ================== */ struct AsynSrv__info *asyn_info, struct RS__RespStruct *rcve_buff, char *rply, /* In: Addr of a reply as got .. ** .. got from _GetReply */ int *len, /* Out: The returned length */ char *term) { /* Out: The returned t'nator */ int i; i = sscanf((rply - asyn_info->rply_hdr_len - 1), asyn_info->rply_fmt, len); *len = (i == 1) ? (*len - 2) : 0; *term = *(rply - 1); if (i != 1) return False; return True; } /* **--------------------------------------------------------------------------- ** 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; asyn_info->msg_id = 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].status != 0) 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 an entry? */ /* 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; asyn_info->idleHandler = NULL; AsynSrv_call_depth--; return True; } /*-------------------------------------------------------- ** There is no existing connection. Open a new one. */ status = AsynSrv_OpenNew(asyn_info); if (!status) return False; /*-------------------------------------------------------- ** Allow the entry to be shared (i.e. status = 0) */ AsynSrv_HPS_list[AsynSrv_n_cnct - 1].status = 0; /*-------------------------------------------------------- */ AsynSrv_errcode = AsynSrv_errno = AsynSrv_vaxc_errno = 0; AsynSrv_call_depth = 0; return True; } /* **--------------------------------------------------------------------------- ** AsynSrv_OpenNew: Open a new connection to an RS-232-C Server. */ int AsynSrv_OpenNew( /* =============== */ 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; asyn_info->msg_id = 0; /*-------------------------------------------------------- ** Initialise the error info stack and pre-set the ** routine name (in case of error). */ AsynSrv_errcode = AsynSrv_errno = AsynSrv_vaxc_errno = 0; if ((AsynSrv_call_depth == 1) && (strcmp(AsynSrv_routine[0], "AsynSrv_Open") == 0)) { strcpy(AsynSrv_routine[1], "AsynSrv_OpenNew"); AsynSrv_call_depth = 2; } else { strcpy(AsynSrv_routine[0], "AsynSrv_OpenNew"); 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; } /*-------------------------------------------------------- ** 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; } /*-------------------------------------------------------- ** There's room for a new connection but, before going any ** further, do some quick checks on values in asyn_info. */ if ((asyn_info->port <= 0) || (asyn_info->port > 65535) || (asyn_info->chan < 0) || (asyn_info->chan > 255)) { AsynSrv_errcode = ASYNSRV__BAD_PAR; /* Something is bad! */ return False; } /*-------------------------------------------------------- ** 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_OpenNew/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_OpenNew/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_OpenNew/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_OpenNew/connect: Failed to connect to server.\n"); perror("AsynSrv_OpenNew"); 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; asyn_info->idleHandler = NULL; /* ** 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_OpenNew: 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_OpenNew: 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_HPS_list[AsynSrv_n_cnct].status = 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--; 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 = 1, 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, '0', sizeof(*rcve_buff)); 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_SEND_LEN; /* 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; } if (asyn_info->idleHandler != NULL) { /* MZ. */ sscanf(asyn_info->tmo, "%4d", &i); /* Decode timeout from ASCII .. ** .. encoded deci-sec */ asyn_info->idleHandler(i * 150, asyn_info->skt); /* Wait for an event .. ** .. on asyn_info->skt or a .. ** .. timeout of 1.5*tmo */ } memset(rcve_buff, 0, sizeof(*rcve_buff)); size = sizeof(rcve_buff->msg_size); memset(rcve_buff->msg_size, 0, 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_RECV_LEN; 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; } } if (AsynSrv_errcode == 0) AsynSrv_call_depth--; return True; } /* **--------------------------------------------------------------------------- ** AsynSrv_SendCmndsBig: Same as AsynSrv_SendCmnds but with ** user defined buffer sizes. */ int AsynSrv_SendCmndsBig( /* ==================== */ struct AsynSrv__info *asyn_info, struct RS__MsgStruct *send_buff, int send_buff_size, struct RS__RespStruct *rcve_buff, int rcve_buff_size, ...) { /* Now we have list of commands - ** char *txt = pntr to cmnd strng ** Terminate list with *txt = NULL. */ int i, status, 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 */ int *c_len, s_len; 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_SendCmndsBig"); 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. */ if (send_buff_size < 64 || rcve_buff_size < 64) { AsynSrv_errcode = ASYNSRV__BAD_PAR; return False; } 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_size); /* Set up var arg machinery */ c_len = va_arg(ap, int *); /* Get pntr to length of next cmnd string */ ncmnds = 0; cmnd_lst_ptr = &send_buff->cmnds[0]; bytes_left = send_buff_size - OffsetOf(struct RS__MsgStruct, cmnds[0]); while (c_len != NULL) { txt_ptr = va_arg(ap, char *); s_len = *c_len; if (s_len <= 0) s_len = strlen(txt_ptr); size = asyn_info->cmnd_hdr_len + s_len; if (size > bytes_left) { AsynSrv_errcode = ASYNSRV__BAD_SEND_LEN; /* Too much to send */ fprintf(stderr, "\nAsynSrv_SendCmndsBig/send: too much to send" " - request ignored.\n"); memset(rcve_buff->msg_size, '0', sizeof(rcve_buff->msg_size)); return False; } sprintf(cmnd_lst_ptr, asyn_info->cmnd_fmt, s_len); if (cmnd_lst_ptr[asyn_info->cmnd_hdr_len] != '\0') { AsynSrv_errcode = ASYNSRV__BAD_CMND_LEN; fprintf(stderr, "\nAsynSrv_SendCmndsBig/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; memcpy(cmnd_lst_ptr, txt_ptr, s_len); cmnd_lst_ptr += s_len; ncmnds++; bytes_left = bytes_left - size; c_len = va_arg(ap, int *); } 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_SendCmndsBig/send: probable network problem"); } else if (status == -1) { if (AsynSrv_errno == EPIPE) { AsynSrv_errcode = ASYNSRV__BAD_SEND_PIPE; /* Server exited (probably) */ fprintf(stderr, "\nAsynSrv_SendCmndsBig/send: broken network pipe"); } else { AsynSrv_errcode = ASYNSRV__BAD_SEND_NET; /* It's some other net problem */ perror("AsynSrv_SendCmndsBig/send"); } } else { AsynSrv_errcode = ASYNSRV__BAD_SEND_UNKN; /* TCP/IP problems */ fprintf(stderr, "\nAsynSrv_SendCmndsBig/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_SendCmndsBig/recv: probable network problem"); } else if (status == -1) { if (AsynSrv_errno == EPIPE) { AsynSrv_errcode = ASYNSRV__BAD_RECV_PIPE; /* Server exited (probably) */ fprintf(stderr, "\nAsynSrv_SendCmndsBig/recv: broken network pipe"); } else { AsynSrv_errcode = ASYNSRV__BAD_RECV_NET; /* It's some other net problem */ perror("AsynSrv_SendCmndsBig/recv"); } } else { AsynSrv_errcode = ASYNSRV__BAD_RECV_UNKN; /* TCP/IP problems */ fprintf(stderr, "\nAsynSrv_SendCmndsBig/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_SendCmndsBig/recv: non-BCD byte count" " - link to server force-closed.\n"); return False; } max_size = rcve_buff_size - size; if (bytes_to_come > max_size) { AsynSrv_errcode = ASYNSRV__BAD_RECV_LEN; fprintf(stderr, "\nAsynSrv_SendCmndsBig/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_SendCmndsBig/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_SendCmndsBig/recv/1: probable network " "problem"); } else { if (AsynSrv_errno == EPIPE) { AsynSrv_errcode = ASYNSRV__BAD_RECV1_PIPE; /* Server exited (probably) */ fprintf(stderr, "\nAsynSrv_SendCmndsBig/recv/1: broken network pipe"); } else { AsynSrv_errcode = ASYNSRV__BAD_RECV1_NET; /* It's some other net fault */ perror("AsynSrv_SendCmndsBig/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; } } if (AsynSrv_errcode == 0) AsynSrv_call_depth--; return True; } /* **--------------------------------------------------------------------------- ** AsynSrv_SendSpecCmnd: Send a "special" command to an ** RS232C server. */ int AsynSrv_SendSpecCmnd( /* ==================== */ struct AsynSrv__info *asyn_info, char *cmnd) { int status; char rply[8]; /*---------------------------------------------- ** Pre-set the routine name (in case of error) */ if (AsynSrv_errcode == 0 && AsynSrv_call_depth < 5) { strcpy(AsynSrv_routine[AsynSrv_call_depth], "AsynSrv_SendSpecCmnd"); 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) { if ((AsynSrv_errcode == 0) && (asyn_info->skt < 0)) { AsynSrv_errcode = ASYNSRV__FORCED_CLOSED; } return False; } /*---------------------------------------------- ** Send the message to the server. */ status = send(asyn_info->skt, cmnd, 4, 0); if (status != 4) { GetErrno(&AsynSrv_errno, &AsynSrv_vaxc_errno); if (status == 0) { AsynSrv_errcode = ASYNSRV__BAD_SEND; /* Server exited (probably) */ fprintf(stderr, "\nAsynSrv_SendSpecCmnd/send: probable network problem"); } else if (status == -1) { if (AsynSrv_errno == EPIPE) { AsynSrv_errcode = ASYNSRV__BAD_SEND_PIPE; /* Server exited (probably) */ fprintf(stderr, "\nAsynSrv_SendSpecCmnd/send: broken network pipe"); } else { AsynSrv_errcode = ASYNSRV__BAD_SEND_NET; /* It's some other net problem */ perror("AsynSrv_SendSpecCmnd/send"); } } else { AsynSrv_errcode = ASYNSRV__BAD_SEND_UNKN; /* TCP/IP problems */ fprintf(stderr, "\nAsynSrv_SendSpecCmnd/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; } status = recv(asyn_info->skt, rply, 4, 0); if (status != 4) { GetErrno(&AsynSrv_errno, &AsynSrv_vaxc_errno); if (status == 0) { AsynSrv_errcode = ASYNSRV__BAD_RECV; /* Server exited (probably) */ fprintf(stderr, "\nAsynSrv_SendSpecCmnd/recv: probable network problem"); } else if (status == -1) { if (AsynSrv_errno == EPIPE) { AsynSrv_errcode = ASYNSRV__BAD_RECV_PIPE; /* Server exited (probably) */ fprintf(stderr, "\nAsynSrv_SendSpecCmnd/recv: broken network pipe"); } else { AsynSrv_errcode = ASYNSRV__BAD_RECV_NET; /* It's some other net problem */ perror("AsynSrv_SendSpecCmnd/recv"); } } else { AsynSrv_errcode = ASYNSRV__BAD_RECV_UNKN; /* TCP/IP problems */ fprintf(stderr, "\nAsynSrv_SendSpecCmnd/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 (memcmp(cmnd, rply, 4) != 0) { AsynSrv_errcode = ASYNSRV__BAD_NOT_BCD; /* Message not echoed OK */ AsynSrv_Close(asyn_info, True); /* Force close TCP/IP connection */ fprintf(stderr, "\nAsynSrv_SendSpecCmnd/recv: command not echoed correctly" " - link to server force-closed.\n"); return False; } if (AsynSrv_errcode == 0) AsynSrv_call_depth--; return True; } /* **--------------------------------------------------------------------------- ** AsynSrv_Trace: Send a "TRACE" request to RS232C server. */ int AsynSrv_Trace( /* ============= */ struct AsynSrv__info *asyn_info, int state) { int status; char cmnd[8], rply[8]; /*---------------------------------------------- ** Pre-set the routine name (in case of error) */ if (AsynSrv_errcode == 0 && AsynSrv_call_depth < 5) { strcpy(AsynSrv_routine[AsynSrv_call_depth], "AsynSrv_Trace"); 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) { if ((AsynSrv_errcode == 0) && (asyn_info->skt < 0)) { AsynSrv_errcode = ASYNSRV__FORCED_CLOSED; } return False; } /*---------------------------------------------- ** Select message for server according to value of state. */ if (state) { strcpy(cmnd, "-002"); } else { strcpy(cmnd, "-003"); } /*---------------------------------------------- ** Send message and get reply. */ status = AsynSrv_SendSpecCmnd(asyn_info, cmnd); if (AsynSrv_errcode == 0) AsynSrv_call_depth--; return status; } /* **--------------------------------------------------------------------------- ** AsynSrv_Trace_Write: Send a Trace_Write command to ** RS232C server. */ int AsynSrv_Trace_Write( /* =================== */ struct AsynSrv__info *asyn_info) { int status; char cmnd[8], rply[8]; /*---------------------------------------------- ** Pre-set the routine name (in case of error) */ if (AsynSrv_errcode == 0 && AsynSrv_call_depth < 5) { strcpy(AsynSrv_routine[AsynSrv_call_depth], "AsynSrv_Trace_Write"); 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) { if ((AsynSrv_errcode == 0) && (asyn_info->skt < 0)) { AsynSrv_errcode = ASYNSRV__FORCED_CLOSED; } return False; } /*---------------------------------------------- ** Send message and get reply. */ status = AsynSrv_SendSpecCmnd(asyn_info, "-005"); if (AsynSrv_errcode == 0) AsynSrv_call_depth--; return status; } /*-------------------------------------------- End of AsynSrv_Utility.C -----*/