diff --git a/tecs/asynsrv_utility.c b/tecs/asynsrv_utility.c new file mode 100644 index 00000000..d0256c80 --- /dev/null +++ b/tecs/asynsrv_utility.c @@ -0,0 +1,1569 @@ +#define ident "1B12" +#ifdef VAXC +#module AsynSrv_Utility ident +#endif +#ifdef __DECC +#pragma module AsynSrv_Utility ident +#pragma nostandard +#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). +** 22-Feb-2000 MZ. Introduced idleHandler +**============================================================================ +** The entry points included in this module are described below. Prototypes +** can be defined via: +** +** #include +** +** 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. +** AsynSrv_SendCmndsBig - Similar to AsynSrv_SendCmnds but with user +** defined buffer sizes. +**--------------------------------------------------------------------- +** 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 select() command 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. +**------------------------------------------------------------------------- +** 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 --> 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_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. +**============================================================================*/ +/* +**--------------------------------------------------------------------------- +** Global Definitions +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef __VMS +#include +#include +#else +#include +#endif +/*-----------------------------------------------------------------*/ +#include +#include +#include + +#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 != 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; + /* + ** 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 = (void (*)(int,int)) va_arg (ap, void *); + }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_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? */ + /* 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; /* MZ. */ + AsynSrv_call_depth--; + 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_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_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. */ + /* decode timeout from ascii encoded deci-sec */ + sscanf(asyn_info->tmo, "%4d", &i); + /* wait for an event on asyn_info->skt or a timeout of 1.5*tmo */ + asyn_info->idleHandler(i*150, asyn_info->skt); + } + + 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_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; imsg_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; imsg_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; + } +/*-------------------------------------------- End of AsynSrv_Utility.C -----*/ diff --git a/tecs/buf.c b/tecs/buf.c index 074636db..664268d2 100644 --- a/tecs/buf.c +++ b/tecs/buf.c @@ -77,7 +77,7 @@ void buf_put_int(buf_type *buf, int val) return; } -void buf_put_str(buf_type *buf, char *str) +void buf_put_str(buf_type *buf, const char *str) { char *b; int l; diff --git a/tecs/client.c b/tecs/client.c index d1cc2a1e..c4bdc0a3 100644 --- a/tecs/client.c +++ b/tecs/client.c @@ -4,61 +4,63 @@ /*-------------------------------------------------------------------------*/ +int CocConnect(CocConn *conn, int allowConnRefused) { + int i; + struct sockaddr_in sadr; + + ERR_I(CocCreateSockAdr(&sadr, conn->host, conn->port)); + ERR_SI(conn->fd=socket(AF_INET, SOCK_STREAM, 0)); + i = 1; + ERR_SI(setsockopt(conn->fd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int))); /* allow quick port reuse */ + i=connect(conn->fd, (struct sockaddr *)&sadr, sizeof(sadr)); + if (i<0) { + if (allowConnRefused && errno==ECONNREFUSED) return(1); + ERR_COD(errno); + } + return(0); + OnError: return(-1); +} + int CocOpen(CocConn *conn) { - int i, cnt, try, port, tryConn, tmo; - struct sockaddr_in sadr; - char *p, *q; + int i, try, tmo; - try=2; - tryConn=1; - tmo=0; + ERR_I(i=CocConnect(conn, conn->startcmd[0]!='\0')); + if (i==0) return(0); + + printf("%s\n", conn->startcmd); + ERR_I(system(conn->startcmd)); + + try=15; + tmo=100; /* wait total ca. 10 sec. for 15 tries */ while (try>0) { try--; - while (tryConn>0) { - port=CocPORT; - cnt=CocPORTS; - tryConn--; - while (cnt>0) { - ERR_SI(conn->fd=socket(AF_INET, SOCK_STREAM, 0)); - ERR_I(CocCreateSockAdr(&sadr, conn->host, port)); - i=connect(conn->fd, (struct sockaddr *)&sadr, sizeof(sadr)); - if (i>=0) return(0); - if (errno!=ECONNREFUSED) { ERR_COD(errno); } - port++; cnt--; - } - util_delay(tmo); tmo+=100; - } - if (conn->startcmd[0]=='\0' || try<=0) { ERR_COD(ECONNREFUSED); } - p=conn->startcmd; - q=strchr(p,' '); - while (q!=NULL) { - p=q+1; - q=strchr(p,' '); - }; - printf("start server %s\n", p); - ERR_I(system(conn->startcmd)); - util_delay(100); tmo=200; - tryConn=5; + util_delay(tmo); tmo=tmo*5/4; + ERR_I(i=CocConnect(conn, try>0)); + if (i==0) return(0); } - ERR_COD(ECONNREFUSED); + ERR_MSG("error in CocConnect"); OnError: return(-1); } /*-------------------------------------------------------------------------*/ -void CocInitClient(CocConn *conn, char *host, char *magic, int bufsize, char *startcmd) -{ void *e; - +int CocInitClient(CocConn *conn, char *host, int port, char *magic, int bufsize, char *startcmd) { + assert(conn!=NULL); if (bufsize==0) bufsize=1024; conn->cmdbuf=buf_create(bufsize); conn->resbuf=buf_create(bufsize); + conn->port=port; str_copy(conn->host, host); str_copy(conn->magic, magic); str_copy(conn->startcmd, startcmd); conn->fd=-1; conn->varList=NULL; CocVarList(&conn->varList); + ERR_I(CocOpen(conn)); + ERR_I(CocSendMagic(conn, conn->magic)); + return(0); + OnError: return(-1); } /*-------------------------------------------------------------------------*/ @@ -102,6 +104,7 @@ int CocCmd(CocConn *conn, const char *rwList) char nam[32]; CocVar *var; + assert(conn!=NULL); buf_put_start(conn->cmdbuf); s=rwList; setmode=0; @@ -117,7 +120,7 @@ int CocCmd(CocConn *conn, const char *rwList) assert(i<32); str_ncpy(nam, s, i+1); if (setmode) { - if (nam[i-1]==']') { nam[i-1]='\0'; setmode=0; } + if (nam[i-1]==']') { i--; nam[i]='\0'; setmode=0; } buf_put_str(conn->cmdbuf, nam); ERR_I(CocPutVar(conn->varList, conn->cmdbuf, nam)); if (!setmode) buf_put_str(conn->cmdbuf, "]"); @@ -159,9 +162,10 @@ int CocCmd(CocConn *conn, const char *rwList) setmode=1; } i=t-s; - if (!setmode) { + if (setmode) { + if (*(t-1)==']') setmode=0; + } else { str_ncpy(nam, s, i+1); - if (nam[i-1]==']') { nam[i-1]='\0'; setmode=0; } ERR_I(CocGetVar(conn->varList, conn->resbuf, nam)); } s=t+1; @@ -173,6 +177,7 @@ int CocCmd(CocConn *conn, const char *rwList) } void CocCloseClient(CocConn *conn) { + assert(conn!=NULL); close(conn->fd); buf_free(conn->cmdbuf); buf_free(conn->resbuf); diff --git a/tecs/coc.c b/tecs/coc.c index b5914907..3f52a428 100644 --- a/tecs/coc.c +++ b/tecs/coc.c @@ -19,7 +19,7 @@ int CocCreateSockAdr( (void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in)); sockaddrPtr->sin_family = AF_INET; sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF)); - if (host == NULL) { + if (host == NULL || host[0]=='\0') { addr.s_addr = INADDR_ANY; } else { hostent = gethostbyname(host); @@ -113,7 +113,7 @@ int CocGetVar(CocVar *varList, buf_type *buf, const char *name) { ERR_MSG("unknown type"); } if (varList==serverVarList) { /* we are the server */ - if (var->flag!=NULL) (*var->flag)++; + (*var->flag)++; } return(0); OnError: return(-1); @@ -125,7 +125,7 @@ int CocPutVar(CocVar *varList, buf_type *buf, const char *name) { var=CocFindVar(varList, name); if (var==NULL) ERR_MSG("undefined variable"); - if (varList!=serverVarList) { /* we are a client */ + if (varList!=serverVarList) { /* we are the client */ if (var->flag==&CocRD) ERR_MSG("variable is read only"); } if (var->type==-1) { diff --git a/tecs/dlog.c b/tecs/dlog.c new file mode 100644 index 00000000..3de0fe0d --- /dev/null +++ b/tecs/dlog.c @@ -0,0 +1,242 @@ +/* switch off ANSI_C_SOURCE (allows compiling all sources with cc/stand=ansi) */ +#ifdef __VMS +#ifdef __HIDE_FORBIDDEN_NAMES +#undef __HIDE_FORBIDDEN_NAMES +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "errhdl.h" +#include "util.h" +#include "dlog.h" + +#define VERSION 1.1 + +#define DEFINED(F) (abs((F)-dset->undef)>1.0e-5*(F)) + +int DlogWrite(DlogSet *dset, int idx, void *data) { + int p; + + p = dset->headsize + (idx % dset->nlen) * dset->fsize; + if (p!=dset->pos) { + ERR_SI(lseek(dset->fd, p, SEEK_SET)); + } + ERR_SI(write(dset->fd, data, dset->fsize)); + dset->pos = p + dset->fsize; + return(0); + OnError: + return(-1); +} + +int DlogRead(DlogSet *dset, int idx, void *data) { + int p; + + p = dset->headsize + (idx % dset->nlen) * dset->fsize; + if (p!=dset->pos) { + ERR_SI(lseek(dset->fd, p, SEEK_SET)); + } + ERR_SI(read(dset->fd, data, dset->fsize)); + dset->pos = p + dset->fsize; + return(0); + OnError: + return(-1); +} + +int DlogOpen(DlogSet *dset, char *name, int write) { + int i, p, np, fd; + + fd=0; + str_copy(dset->name, name); + if (write) { +#ifdef __VMS + ERR_SI(fd=open(name, O_RDWR | O_SYNC, 0, "SHR=UPD")); +#else + ERR_SI(fd=open(name, O_RDWR | O_SYNC, 0)); +#endif + } else { +#ifdef __VMS + ERR_SI(fd=open(name, O_RDONLY | O_SYNC, 0, "SHR=UPD")); +#else + ERR_SI(fd=open(name, O_RDONLY | O_SYNC, 0)); +#endif + } + dset->fd=fd; + + p=(char *)&dset->fd - (char *)dset; + ERR_SI(read(dset->fd, dset, p)); + dset->pos=p; + if ((int)(dset->version*1000+0.5) != (int)(VERSION*1000+0.5)) ERR_MSG("version mismatch"); + if (dset->headsize != p) ERR_MSG("illegal dlog file"); + return(0); + OnError: + if (fd!=0) close(fd); + return(-1); +} + +int DlogCreate(DlogSet *dset, char *name, time_t start, int nset, int nlen, int period, float undef) { + int fd, i, j, p; + va_list ap; + float f[DLOG_MAX_SET]; + + fd=0; + if (nset>DLOG_MAX_SET) ERR_MSG("nset too large"); + dset->nset=nset; + dset->nlen=nlen; + dset->start=start; + dset->last=start-period; + dset->period=period; + dset->undef=undef; + dset->version=VERSION; + str_copy(dset->name, name); + + for (i=0; iundef; + } + ERR_SI(fd=open(name, O_RDWR | O_CREAT | O_SYNC | O_TRUNC, 0666)); + dset->fd=fd; + p=(char *)&dset->fd - (char *)dset; + dset->headsize = p; + dset->fsize = nset * sizeof(float); + ERR_SI(write(dset->fd, dset, p)); + dset->pos=p; + return(0); + OnError: + if (fd!=0) close(fd); + return(-1); +} + +int DlogPut(DlogSet *dset, time_t time, int nset, float val[]) { + int i, i0, j; + float f[DLOG_MAX_SET], f0[DLOG_MAX_SET]; + + if (nset > dset->nset) nset = dset->nset; + + for (j=0; j < nset; j++) { f[j]=val[j]; } + for (j=nset; j < dset->nset; j++) { f[j]=dset->undef; } + + i = ( time - dset->start ) / dset->period; + i0 = ( dset->last - dset->start ) / dset->period; + + if (i0==i) { + ERR_I(DlogRead(dset, i, f0)); + for (j=0; jf[j] || /* take maximum (for odd i) */ + !i%2 && f0[j]nset; j++) { f0[j]=dset->undef; } + i0++; + while (i0last=time; + return(0); + OnError: + return(-1); +} + +int DlogGet(DlogSet *dset, int iset, int nmax, double *starttime, float x[], float y[]) { + int i0, i, n, undef; + float f[DLOG_MAX_SET]; + + if (iset<0) ERR_MSG("illegal iset"); + if (iset>=dset->nset) return(0); + + i = ( dset->last - dset->start ) / dset->period; + i0=0; + if (i0 <= i - dset->nlen) { + i0 = i - dset->nlen + 1; + } + + *starttime = dset->start + i0 * dset->period; + n=0; + undef=2; + while (i0<=i) { + if (n>=nmax) return(n); + ERR_I(DlogRead(dset, i0, f)); + i0++; + if (DEFINED(f[iset])) { + x[n]=(float)i0*dset->period; + y[n]=f[iset]; + n++; + undef=0; + } else if (undef==0) { + undef=1; + } else if (undef==1) { + undef=2; + x[n]=0; + y[n]=0; + n++; + } + } + return(n); + OnError: + return(-1); +} + +int DlogGetMany(DlogSet *dset, int nset, int nmax, double *starttime, float x[], float y[], int index[]) { + int n, k, nmx, ntot; + + ntot=0; + for (k=0; kfd, 0, SEEK_SET)); + ERR_SI(write(dset->fd, &dset->last, sizeof(int))); + dset->pos=sizeof(int); +#ifdef __VMS + close(dset->fd); + DlogOpen(dset, dset->name, 1); +#endif + return(0); + OnError: + return(-1); +} + +int DlogClose(DlogSet *dset) { + ERR_I(DlogUpd(dset)); + close(dset->fd); + return(0); + OnError: + return(-1); +} diff --git a/tecs/geterrno.c b/tecs/geterrno.c new file mode 100644 index 00000000..3f80860c --- /dev/null +++ b/tecs/geterrno.c @@ -0,0 +1,97 @@ +#define ident "1B01" +#ifdef VAXC +#module GetErrno ident +#endif +#ifdef __DECC +#pragma module GetErrno ident +#pragma nostandard +#endif +/* +** +--------------------------------------------------------------+ +** | Paul Scherrer Institute | +** | Computing Section | +** | | +** | 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]GETERRNO.C +** +** Author . . . . . . . . . . : D. Maden +** Date of creation . . . . . . : Nov 1995 +** +** To compile this module, use: + + $ import tasmad + $ define/group sinq_c_tlb mad_lib:sinq_c.tlb + $ cc /debug /noopt /obj=[]GetErrno - + tasmad_disk:[mad.lib.sinq]GetErrno + + sinq_c_tlb/lib + +** To include this module in SINQ.OLB, use: + + $ import tasmad + $ define/group sinq_c_tlb mad_lib:sinq_c.tlb + $ + $ define/group sinq_olb mad_lib:sinq_dbg.olb + $ @tasmad_disk:[mad.lib.sinq]sinq_olb GetErrno debug + $ + $ define/group sinq_olb mad_lib:sinq.olb + $ @tasmad_disk:[mad.lib.sinq]sinq_olb GetErrno +** +** Updates: +** 1A01 2-Nov-1995 DM. Initial version. +** 1B01 21-Mar-1996 DM. Move from DELTAT.OLB to SINQ.OLB. +**============================================================================ +** The following entry points are included: +** + #include + + void GetErrno (int *his_errno, int *his_vaxc_errno) +** -------- +** Input Args: +** none +** Output Args: +** his_errno - value of "errno". +** his_vaxc_errno - on VMS systems only, value of "vaxc$errno". Otherwise +** set to 1. +** Modified Args: +** none +** Return status: +** none +** Global variables modified: +** none +** Description: +** GetErrno returns a copy of the universal error variable "errno" (and, +** on VMS systems, vaxc$errno) to a local variable supplied by the user. +** This can occasionally be useful when debugging since the debugger on +** VMS can't easily examine them. +**============================================================================ +** Global Definitions +*/ +#ifdef VAXC +#include errno +#else +#include +#endif +/*-------------------------------------------------------------------------- +** Global Variables +*/ + +/*-------------------------------------------------------------------------- +** GetErrno: Make copies of errno and vaxc$errno for debug. +*/ + void GetErrno (int *his_errno, int *his_vaxc_errno) { +/* ======== +*/ + *his_errno = errno; /* Make copy of errno */ +#ifdef __VMS + *his_vaxc_errno = vaxc$errno; /* Make copy of vaxc$errno */ +#else + *his_vaxc_errno = 1; +#endif + return; + } +/*------------------------------------------------- End of GETERRNO.C =======*/ diff --git a/tecs/logfile.c b/tecs/logfile.c new file mode 100644 index 00000000..aaa4e38b --- /dev/null +++ b/tecs/logfile.c @@ -0,0 +1,191 @@ +/* switch off ANSI_C_SOURCE (allows compiling all sources with cc/stand=ansi) */ +#ifdef __VMS +#ifdef __HIDE_FORBIDDEN_NAMES +#undef __HIDE_FORBIDDEN_NAMES +#endif +#endif + +#include +#include +#include +#include +#include +#include "logfile.h" +#include "errhdl.h" +#include "util.h" + +static FILE *fil=NULL; +static char lnam[256]="", filnam[256]=""; +static char ebuf[20000]=""; +static char *eptr=&ebuf[0]; +static int lastStamp=0; +static int notDated=0; + +int logfileStd=0; +int dirty=0; + +void logfileOpen(int first) { + struct tm *tim; + struct timeb btim; + + dirty=1; + if (logfileStd) { + fil=stdout; + return; + } + assert(fil==NULL); + if (first) { + ftime(&btim); + tim=localtime(&btim.time); + if (notDated) { + if (lnam[0]=='\0') { + str_copy(filnam, "test.log"); + } else { + str_copy(filnam, lnam); + str_append(filnam, ".log"); + } + } else { + sprintf(filnam, "%s%04d-%02d-%02d.log", lnam, tim->tm_year+1900, tim->tm_mon+1, tim->tm_mday); + } + } +#ifdef __VMS + if (first && notDated) { + fil=fopen(filnam, "w", "SHR=UPD"); /* new version at restart */ + } else { + fil=fopen(filnam, "a", "SHR=UPD"); + } +#else + if (first && notDated) { + fil=fopen(filnam, "w"); /* overwrite at restart */ + } else { + fil=fopen(filnam, "a"); + } +#endif +} + +void logfileInit(char *path, int nodate) { + str_copy(lnam, path); + lastStamp=-1; + notDated=nodate; + logfileOpen(1); +} + +void logfileStamp(char *text) +{ struct tm *tim; + struct timeb btim; + int stamp; + + ftime(&btim); + tim=localtime(&btim.time); + stamp=tim->tm_hour*60+tim->tm_min; + if (stamp!=lastStamp) { + if (stamp new day -> new logfile */ + if (fil!=NULL) { fclose(fil); fil=NULL; } + logfileOpen(0); + } else { + if (!dirty) return; +#ifdef __VMS + if (fil==NULL) logfileOpen(0); +#endif + } + lastStamp=stamp; + fprintf(fil, "%02d:%02d %s\n",tim->tm_hour,tim->tm_min,text); + dirty=0; + } +#ifdef __VMS + if (!logfileStd) { fclose(fil); fil=NULL; } +#endif +} + +void logfileUpd() +{ +#ifdef __VMS + if (!logfileStd) { fclose(fil); fil=NULL; } +#else + fflush(fil); +#endif +} + +void logfileOutTmp(char *fmt, ...) +{ va_list ap; + + va_start(ap, fmt); + if (eptr!=NULL) { + if (eptr-ebuf > sizeof(ebuf)-512) { + sprintf(eptr, "... buffer full ... \n"); + eptr=NULL; + } else { + vsprintf(eptr, fmt, ap); + eptr+=strlen(eptr); + } + } + va_end(ap); +} + +void logfileOut(char *fmt, ...) +{ va_list ap; + + if (!dirty) { dirty=1; logfileStamp(""); } + dirty=1; + +#ifdef __VMS + if (fil==NULL) logfileOpen(0); +#endif + va_start(ap, fmt); + vfprintf(fil, fmt, ap); + va_end(ap); +} + +void logfilePurge() { + ebuf[0]='\0'; + eptr=&ebuf[0]; +} + +void logfileWriteTmp() { + + if (!dirty) { dirty=1; logfileStamp(""); } + dirty=1; + +#ifdef __VMS + if (fil==NULL) logfileOpen(0); +#endif + if (ebuf[0]!='\0') fprintf(fil, "%s", ebuf); + ebuf[0]='\0'; + eptr=&ebuf[0]; +} + +void logfileShowErr(char *text) +{ + logfileWriteTmp(); + ErrWrite(fil, text); +} + +void logfileClose() +{ if (fil!=NULL) { fclose(fil); fil=NULL; } +} + +void logfileOutBuf(buf_type *buf) +{ char *obuf, *str; + int osiz; + + obuf=buf->buf; + osiz=buf->size; + while (buf->size>0) { + if (buf->buf==NULL) { + logfileOutTmp(" ?"); break; + } else if (buf->buf[0]==1) { + logfileOutTmp(" %d", buf_get_int(buf)); + } else if (buf->buf[0]==2) { + logfileOutTmp(" %f", buf_get_float(buf)); + } else { + str=buf_get_str(buf); + if (*str=='\0') { + logfileOutTmp(" ."); + } else { + logfileOutTmp(" %s", str); + } + } + } + buf->size=osiz; + buf->buf=obuf; +} diff --git a/tecs/lsc.c b/tecs/lsc.c new file mode 100644 index 00000000..dfcebf6f --- /dev/null +++ b/tecs/lsc.c @@ -0,0 +1,103 @@ +#include + +#include +#include +#include +#include "errhdl.h" +#include "logfile.h" +#include "lsc.h" +#include "util.h" + +#define MC LSC_MAX_CMDS +#define MAX_PAR 16 +#define MAX_ARG 9 +/* when changing FBUF_LEN, change also the constant in the fscanf call in subroutine LscExeCmd */ +#define FBUF_LEN 132 + +int LscEqPar(char *par, char *res) { + char pbuf[SER_BUF_LEN], rbuf[SER_BUF_LEN]; + char *plist[MAX_PAR], *rlist[MAX_PAR]; + int i,n,i1,i2; + float f1, f2; + char ch1, ch2; + + strcpy(pbuf, par); + strcpy(rbuf, res); + n=MAX_PAR; + str_split(pbuf, ',', plist, &n); + str_split(rbuf, ',', rlist, &n); + for (i=0; i1e-4+abs(f1)*5e-6) { + logfileOut("%s#%s\n", plist[i], rlist[i]); + return(0); + } + } + } + return(1); +} + +int LscCmdChkC(SerChannel *ser, const char *cmds) { + char buf[128]; + assert(strlen(cmds)<128); + strcpy(buf, cmds); + return(LscCmdChk(ser, buf)); +} + +int LscCmdChk(SerChannel *ser, char *cmds) { + char *b, *o, *cn, *c, *d, *r, *res; + char *clist[MC], *plist[MC], *rlist[MC], *olist[MC]; + char obuf[SER_BUF_LEN], r1[SER_BUF_LEN]; + int i,n,m,j,cnt,l; + + if (NULL!=strchr(cmds, '?')) ERR_COD(EINVAL); + cn=cmds; + o=&obuf[0]; + m=MC; + do { + n=m; + cn=str_split(cn, ';', clist, &n); + for (i=0; id) { + *d=' '; b=d; + } else { + *d=','; + } + plist[i]=d+1; + l=strlen(c); + if ((o-&obuf[0])+l+(d-c)+2>SER_BUF_LEN) ERR_COD(ENOBUFS); + olist[i]=o; + strcpy(o, c); o+=l; + *o=';'; o++; + strncpy(o, c, d-c); + o[b-c]='?'; o+=d-c; + if (b==d) o++; + *o=';'; o++; + }; + o--; *o='\0'; + cnt=0; + do { + cnt++; + if (cnt>3) ERR_MSG("can not set parameter"); + ERR_P(res=SerCmd(ser, obuf)); + if (cnt>0) { + if (0==strcmp(r1, res)) break; /* got two times the same result */ + } + strcpy(r1, res); + j=n; + r=str_split(res, ';', rlist, &n); + if (r==NULL || n!=j) continue; + for (i=0; i + +#include +#include "rs232c_def.h" +#include "asynsrv_def.h" +#include "sinq_prototypes.h" +#include "errhdl.h" +#include "serutil.h" +#include "logfile.h" +#include "util.h" + +#define A_CHK(R) if (1!=(R)) { SerA_error(); ErrTxt(#R,0); goto OnError; } + +void (*idleHandler)(int,int); + +struct SerChan { + struct AsynSrv__info asyn_info; /* Contains skt, host, port & chan */ + struct RS__MsgStruct to_host; + struct RS__RespStruct from_host; + int logIt; + char cmd[SER_BUF_LEN]; +}; + +void SerA_error() { + char *a_txt; + int a_cod, a_my, a_vms; + + AsynSrv_ErrInfo(&a_txt, &a_cod, &a_my, &a_vms); + ErrMsg("asynsrv error"); ErrTxt(a_txt,0); +} + +SerChannel *SerOpen(const char *host, int logIt, int msecTmo, void (*idleHdl)(int,int)) { + struct SerChan *ser; + char hbuf[64]; + char *p, *c; + int port, chan; + + idleHandler=idleHdl; + ser=calloc(1, sizeof(*ser)); + str_copy(hbuf, host); + p=str_split1(hbuf, ':'); + str_copy(ser->asyn_info.host, hbuf); + port=4000; + chan=0; + if (p!=NULL) { + c=str_split1(p, '/'); + if (c!=NULL) chan=atoi(c); + port=atoi(p); + } + ser->asyn_info.port=port; + ser->asyn_info.chan=chan; + ser->logIt=logIt; + A_CHK(AsynSrv_Open(&ser->asyn_info)); + if (msecTmo==0) msecTmo=5000; + A_CHK(AsynSrv_Config(&ser->asyn_info, "msecTmo", msecTmo, "idleHdl", idleHdl, NULL)); + return((SerChannel *)ser); + OnError: return(NULL); +} + +int SerClose(SerChannel *serch) { + struct SerChan *ser; + + ser=(struct SerChan *)serch; + A_CHK(AsynSrv_Close(&ser->asyn_info, 0)); + return(0); + OnError: return(-1); +} + +char *SerCmdC(SerChannel *serch, const char *cmnd) { + char cmd[SER_BUF_LEN]; + int l; + + l=strlen(cmnd); + if (l>=SER_BUF_LEN-1) ERR_COD(ENOBUFS); + strcpy(cmd, cmnd); + return(SerCmd(serch, cmd)); + OnError: return(NULL); +} + +char *SerCmd(SerChannel *serch, char *cmnd) { + int l; + struct SerChan *ser; + char *result; + + l=strlen(cmnd); + if (l>=SER_BUF_LEN-1) ERR_COD(ENOBUFS); + + ser=(struct SerChan *)serch; + if (ser->logIt) logfileOutTmp(">%s\n", cmnd); + cmnd[l]=ser->asyn_info.eot[1]; + cmnd[l+1]='\0'; + A_CHK(AsynSrv_SendCmnds(&ser->asyn_info, &ser->to_host, &ser->from_host, cmnd, NULL)); + result=AsynSrv_GetReply(&ser->asyn_info, &ser->from_host, NULL); + if (result==NULL) ERR_MSG("empty result"); + /* if (idleHandler!=NULL) idleHandler(50,0); */ + if (ser->logIt) logfileOutTmp("<%s\n", result); + return(result); + OnError: return(NULL); +} diff --git a/tecs/strjoin.c b/tecs/strjoin.c new file mode 100644 index 00000000..88a8b721 --- /dev/null +++ b/tecs/strjoin.c @@ -0,0 +1,142 @@ +#define ident "1B03" +#ifdef VAXC +#module StrJoin ident +#endif +#ifdef __DECC +#pragma module StrJoin 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]STRJOIN.C +** +** Author . . . . . . . . . . : D. Maden +** Date of creation . . . . . . : Nov 1995 +** +** To compile this module, use: + + $ import tasmad + $ define/group sinq_c_tlb mad_lib:sinq_c.tlb + $ cc /debug /noopt /obj=[]StrEdit - + tasmad_disk:[mad.lib.sinq]StrEdit + + sinq_c_tlb/lib + +** To include this module in SINQ.OLB, use: + + $ import tasmad + $ define/group sinq_c_tlb mad_lib:sinq_c.tlb + $ + $ define/group sinq_olb mad_lib:sinq_dbg.olb + $ @tasmad_disk:[mad.lib.sinq]sinq_olb StrEdit debug + $ + $ define/group sinq_olb mad_lib:sinq.olb + $ @tasmad_disk:[mad.lib.sinq]sinq_olb StrEdit +** +** Updates: +** 1A01 2-Nov-1995 DM. Initial version. +** 1B01 21-Mar-1996 DM. Move from DELTAT.OLB to SINQ.OLB. +** 1B03 28-May-1997 DM. Allow result string to be either of source +** strings. +**============================================================================ +** The following entry points are included in this module: +** +**------------------------------------------------------------------------- +** #include +** +** char *StrJoin (&result, result_size, &str_a, &str_b) +** ------- +** Input Args: +** int result_size - max size of "result". The resultant string will +** have a max length of (result_size - 1) to allow +** for the zero terminator +** char *str_a - Pointer to first string to be joined. +** char *str_b - Pointer to second string to be joined. +** Output Args: +** char *result - Pointer to resulting string. +** Modified Args: +** none +** Return value: +** Pointer to resulting string. +** Global variables modified: +** none +** Routines called: +** None +** Description: +** The routine joins 2 strings, checking for total string length and +** ensuring the result will be zero terminated. The "result" arg may be +** the same as "str_a" or "str_b". +**------------------------------------------------------------------------- +** Global Definitions +*/ +#include + +#define NIL '\0' +/* +**==================================================================== +*/ +/* +**==================================================================== +** StrJoin - join 2 strings. +** Note: strncat is used exclusively rather than +** strncpy to be sure result is always +** null terminated. +*/ + char *StrJoin ( +/* ======= +*/ char *result, + int result_size, + char *str_a, + char *str_b) { + + int i, size, size_a, size_b; + + size = result_size - 1; + + if (size < 0) return result; + + if (result == str_a) { /* Are the result and str_a the same? */ + size_a = strlen (str_a); /* Yes */ + if (size_a > size) { /* Check sizes anyway. */ + result[size] = NIL; /* Truncate str_a. No room for str_b! */ + }else { + size = size - strlen (result); /* And append str_b */ + if (size > 0) { + strncat (result, str_b, size); + } + } + }else if (result == str_b) { /* Are the result and str_b the same? */ + size_a = strlen (str_a); /* Yes, this is a bit complicated! */ + size_b = strlen (str_b); + if (size_a >= size) { /* If str_a completely fills result, .. */ + result[0] = NIL; /* .. then just copy in str_a */ + strncat (result, str_a, size); + }else { + /* + ** Otherwise, str_b must first be moved to + ** make room for str_a and then str_a must + ** be put at the front of the result. + */ + if ((size_a + size_b) > size) size_b = size - size_a; + result[size_a+size_b] = NIL; + for (i = (size_b-1); i >= 0; i--) { + result[size_a+i] = str_b[i]; + } + memcpy (result, str_a, size_a); + } + }else { /* Result is neither str_a nor str_b so .. */ + result[0] = NIL; /* .. str_a needs to be copied */ + strncat (result, str_a, size); + size = size - strlen (result); /* And str_a appended */ + if (size > 0) strncat (result, str_b, size); + } + return result; + } +/*-------------------------------------------------- End of STRJOIN.C =======*/ diff --git a/tecs/tecc.c b/tecs/tecc.c index 15de3b21..68d2149d 100644 --- a/tecs/tecc.c +++ b/tecs/tecc.c @@ -1,27 +1,22 @@ #include "errhdl.h" -#include "client.h" #include "tecc.h" -char command[80], response[80], device[80]; -float tempX, tempP, tempC; +static char device[80], command[80]; +static int quit; +static float tempX, tempP, tempC; -pTecsClient TeccInit(char *server) { +pTecsClient TeccInit(char *startcmd, int port) { CocConn *conn; - char buf[80]; ERR_SP(conn=(CocConn *)malloc(sizeof(*conn))); -#ifdef __VMS - sprintf(buf, "@start_tecs %s", server); -#else - sprintf(buf, "start_tecs %s", server); -#endif - CocInitClient(conn, "", "#rwacs", 0, buf); + ERR_I(CocInitClient(conn, "", port, "#rwacs", 0, startcmd)); CocDefFlt(tempX, CocRD); CocDefFlt(tempP, CocRD); CocDefFlt(tempC, CocWR); CocDefStr(device, CocWR); - CocDefStr(command, CocWR); - CocDefStr(response, CocWR); + CocDefInt(quit, CocWR); + CocDefCmd(command); + return((pTecsClient)conn); OnError: return(NULL); } @@ -39,13 +34,6 @@ char *TeccGetDev(pTecsClient conn) { OnError: return(NULL); } -int TeccGet(pTecsClient conn, float *temp) { - ERR_I(CocCmd((CocConn *)conn, "tempP")); - *temp=tempP; - return(0); - OnError: return(-1); -} - int TeccGet3(pTecsClient conn, float temp[3]) { ERR_I(CocCmd((CocConn *)conn, "tempC,tempX,tempP")); temp[0]=tempC; @@ -55,6 +43,14 @@ int TeccGet3(pTecsClient conn, float temp[3]) { OnError: return(-1); } +int TeccGet(pTecsClient conn, float *temp) { + float t[3]; + ERR_I(TeccGet3(conn, t)); + *temp=t[2]; + return(0); + OnError: return(-1); +} + int TeccSet(pTecsClient conn, float temp) { tempC=temp; ERR_I(CocCmd((CocConn *)conn, "[tempC]")); @@ -63,17 +59,30 @@ int TeccSet(pTecsClient conn, float temp) { } int TeccSend(pTecsClient conn, char *cmd, char *reply, int replyLen) { - command[0]='\0'; - while (0!=strcmp(command, cmd)) { - str_copy(command, cmd); - strcpy(response,""); - ERR_I(CocCmd((CocConn *)conn, "[command,response]")); - while (0==strcmp(response,"") && 0==strcmp(command, cmd)) { - util_delay(250); - ERR_I(CocCmd((CocConn *)conn, "command,response")); + char *res; + int cnt; + + str_copy(command, cmd); + ERR_I(CocCmd((CocConn *)conn, "[$]")); + cnt=40; + util_delay(100); + while (cnt>0) { + ERR_I(CocCmd((CocConn *)conn, "$")); + if (command[0]!='\0') { + str_ncpy(reply, command, replyLen); + return(0); } + util_delay(250); + cnt--; } - str_ncpy(reply, response, replyLen); + str_ncpy(reply, "", replyLen); + return(0); + OnError: return(-1); +} + +int TeccQuitServer(pTecsClient conn) { + quit=1; + ERR_I(CocCmd((CocConn *)conn, "quit")); return(0); OnError: return(-1); } @@ -119,7 +128,7 @@ int TeccSendVms(pTecsClient conn, char **cmd, char **reply) { strncpy(cbuf, cmd[1], l); while (l>0 && cbuf[l-1]==' ') l--; /* trim */ cbuf[l]='\0'; - TeccSend(conn, cbuf, rbuf, sizeof(rbuf)); + ERR_I(TeccSend(conn, cbuf, rbuf, sizeof(rbuf))); lr=strlen(rbuf); l=*(short *)reply; if (lr>=l) lr=l; diff --git a/tecs/util.c b/tecs/util.c index 7e901e12..2c1d5bfa 100644 --- a/tecs/util.c +++ b/tecs/util.c @@ -163,10 +163,20 @@ int str_cmp(const char *str1, const char *str2) { return(0); } -int str_ncpy(char *dst, const char *src, int n) { - strncpy(dst, src, n); - if (dst[n-1]!='\0') { - dst[n-1]='\0'; +int str_ncpy(char *dst, const char *src, int maxdest) { + strncpy(dst, src, maxdest); + if (dst[maxdest-1]!='\0') { + dst[maxdest-1]='\0'; + ERR_MSG("destination string too short"); + } + return(0); + OnError: return(-1); +} + +int str_ncat(char *dst, const char *src, int maxdest) { + strncat(dst, src, maxdest-strlen(dst)-1); + if (dst[maxdest-1]!='\0') { + dst[maxdest-1]='\0'; ERR_MSG("destination string too short"); } return(0); diff --git a/tecsdriv.c b/tecsdriv.c index f5306c5c..87c71fff 100644 --- a/tecsdriv.c +++ b/tecsdriv.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include "fortify.h" #include "conman.h" @@ -57,11 +58,10 @@ #include "servlog.h" #include "sicsvar.h" #include "tecs/tecc.h" +#include "tecs/util.h" #include "tecs/errhdl.h" extern pServer pServ; - typedef struct __EVDriver *pEVDriver; - #include "evdriver.i" /*------------------------- The Driver ------------------------------------*/ @@ -72,10 +72,13 @@ /*-----------------------------------------------------------------------*/ typedef struct { void *pData; - char server[64]; - int iLastError; char *lastError; - } TecsDriv, *pTecsDriv; + int iLastError, port; + char server[256]; + } TecsDriv, *pTecsDriv; + + + static time_t lastGet=0; /*-------------------------------------------------------------------------*/ int TecsWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, @@ -151,11 +154,19 @@ { pTecsDriv pMe = NULL; int iRet; + time_t now; assert(self); pMe = (pTecsDriv)self->pPrivate; - assert(pMe); - + assert(pMe); + + time(&now); + if (now>lastGet) { + lastGet=now; + } else { + SicsWait(1); /* avoid extensive network traffic */ + } + /* get temperature */ iRet = TeccGet(pMe->pData, fPos); if(iRet < 0 ) @@ -178,8 +189,7 @@ /* set temperature */ iRet = TeccSet(pMe->pData, fVal); - if(iRet != 1) - { + if(iRet < 0) { pMe->iLastError=1; /* severe */ pMe->lastError = ErrMessage; return 0; @@ -196,7 +206,7 @@ assert(pMe); *iCode = pMe->iLastError; - error=pMe->lastError; + str_ncpy(error, pMe->lastError, iErrLen); return 1; } /*---------------------------------------------------------------------------*/ @@ -243,7 +253,7 @@ pMe = (pTecsDriv )self->pPrivate; assert(pMe); - pMe->pData = TeccInit(pMe->server); + pMe->pData = TeccInit(pMe->server, pMe->port); if(pMe->pData==NULL) { pMe->iLastError = 1; /* severe */ @@ -262,7 +272,7 @@ pMe = (pTecsDriv )self->pPrivate; assert(pMe); - TeccClose(&pMe->pData); + TeccClose(pMe->pData); pMe->pData=NULL; return 1; } @@ -288,7 +298,8 @@ pEVDriver pNew = NULL; pTecsDriv pMe = NULL; pSicsVariable pInst = NULL; - + char *pStart = NULL, *pBin=NULL, *pLog=NULL, *pPort=NULL; + pNew = CreateEVDriver(argc,argv); pMe = (pTecsDriv)malloc(sizeof(TecsDriv)); memset(pMe,0,sizeof(TecsDriv)); @@ -302,12 +313,45 @@ /* initalise pTecsDriver */ pMe->lastError = NULL; + /* get the start server option */ + pStart = IFindOption(pSICSOptions, "TecsStartCmd"); + if (pStart==NULL) return(NULL); + str_copy(pMe->server, pStart); + + /* get the port number for tecs */ + pMe->port=0; + pPort = IFindOption(pSICSOptions, "TecsPort"); + if (pPort!=NULL) { + pMe->port=atoi(pPort); + } + if (pMe->port==0) { + pPort="9750"; + pMe->port=atoi(pPort); + } + str_append(pMe->server, " -p "); + str_append(pMe->server, pPort); + /* get the instrument name */ pInst = FindVariable(pServ->pSics,"instrument"); if (pInst==NULL || pInst->text==NULL || strlen(pInst->text)>sizeof(pMe->server)-6) return NULL; - sprintf(pMe->server,"tecs_%s", pInst->text); + str_append(pMe->server, " -n tecs_"); + str_append(pMe->server, pInst->text); + + /* add binDir option if present */ + pBin = IFindOption(pSICSOptions, "TecsBinDir"); + if (pBin!=NULL) { + str_append(pMe->server, " -b "); + str_append(pMe->server, pBin); + } + /* add logDir option if present */ + pLog = IFindOption(pSICSOptions, "TecsLogDir"); + if (pLog!=NULL) { + str_append(pMe->server, " -d "); + str_append(pMe->server, pLog); + } + str_append(pMe->server, " &"); /* initialise function pointers */ pNew->SetValue = TecsRun;