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