/* ***************************************************************************** * * Copyright 1989, Xylogics, Inc. ALL RIGHTS RESERVED. * * ALL RIGHTS RESERVED. Licensed Material - Property of Xylogics, Inc. * This software is made available solely pursuant to the terms of a * software license agreement which governs its use. * Unauthorized duplication, distribution or sale are strictly prohibited. * * Module Function: * * ERPC routines * * Original Author: Jonathan Taylor Created on: 84/06/22 * * Revision Control Information: * * $Header: /annex/mckinley/src/libannex/RCS/erpc_subr.c,v 1.18.5.3 1995/09/26 13:07:41 dfox Exp $ * * This file created by RCS from: * * $Source: /annex/mckinley/src/libannex/RCS/erpc_subr.c,v $ * * Revision History: * * $Log: erpc_subr.c,v $ * Revision 1.18.5.3 1995/09/26 13:07:41 dfox * externalize alarm_flag * * Revision 1.18.5.2 1995/08/30 16:58:37 slu * Clenaup the debug variable slubuf. * * Revision 1.18.5.1 1995/08/16 12:43:39 slu * Support NT. * * Revision 1.18 1995/04/21 13:15:40 carlson * SPR 4199 -- added conditionals for hosts which have POSIX-style * msghdrs, instead of the Berkeley-style. * * Revision 1.17 1994/11/22 13:39:18 parker * Changed NT support to use the NuTcracker library. * * Revision 1.16 1994/11/16 09:25:16 parker * Changes for port to windows NT * * Revision 1.15 1994/08/04 10:55:05 sasson * SPR 3211: SGI compiler requires arguments in select() call to * be of type "fd_set". * * Revision 1.14 1993/12/30 13:12:31 carlson * SPR 2084 -- made compatible with 64 bit machines. * * Revision 1.13 1992/11/13 14:36:05 carlson * SPR 1080 -- added a parameter to erpc_callresp to skip the first * transmission of data. This is used by srpc_callresp to ignore out- * of-sequence packets. * * Revision 1.12 92/01/24 14:30:08 carlson * SPR 512 -- fix for Bull DPX/360 -- use correct size for messages. * * Revision 1.11 91/05/19 16:36:12 emond * Assure erpc_callresp() returns -a if recvmsg fails, otherwise we end up with * hung erpcd's. (that's suppose to be a -1 not a -a). * * Revision 1.10 91/04/24 19:18:03 emond * Pass debug flat to api_sendmsg() don't pass TRUE otherwise it will always * print debug mesgs. * * Revision 1.9 91/04/08 14:24:58 emond * Modified to work with TLI as well as Socket interface. * * Revision 1.8 89/10/16 17:29:17 loverso * Generalize for all machines missing select (sigh) * * Revision 1.7 89/04/11 01:06:58 loverso * workaround for missing select with CMC, remove htonl externs * * Revision 1.6 89/04/05 12:40:12 loverso * Changed copyright notice * * Revision 1.5 88/06/10 10:11:40 mattes * erpc_callresp: also fill in the responding host's address * * Revision 1.4 88/05/25 12:09:06 harris * Merger differences between r1.1 and r1.2 BACK into r1.3 to produce r1.4?! * * Revision 1.3 88/05/24 18:35:29 parker * Changes for new install-annex script * * Revision 1.2 88/05/04 17:38:27 harris * Erpc_callresp now updates (to)->sin_port based on from.sin_port. * * Revision 1.1 88/04/15 11:56:30 mattes * Initial revision * * Revision 2.10 88/02/24 11:26:59 harris * For MACH. Since SUN and MACH have ntohl macros, I made code universal. * * Revision 2.9 87/12/04 12:26:42 harris * Use special SENDMSG RECVMSG compatibility code. See sendrecv.c. * * Revision 2.8 87/09/22 11:38:35 parker * Fixed some bugs uncovered in build on SUN. * * Revision 2.7 87/07/28 11:56:25 parker * Fixed calculation of sdelay in erpc_call() for xenix code. * * Revision 2.6 87/06/10 18:12:34 parker * Added support for Xenix/Excelan PC. * * Revision 2.5 86/12/10 15:49:12 parker * Added {get,set}_unspec_l() functions. * * Revision 2.4 86/06/11 10:38:05 harris * Checked in changes form Release_1 1.2.1.6 version. * * Revision 1.2.1.6 86/06/10 18:57:02 harris * Use constants to determine size of structs when not zero mod 4. * * Revision 1.2.1.5 86/06/10 14:23:51 harris * Made more portable by using special functions to convert host/network formats * which work even when longs are not on a long boundary (get_long(), setlong()). * Change SYS_V version to look for a "../inc/port/SYS_V.h" include file. * Change EXOS version to look for a "../inc/port/EXOS.h" include file. * * Revision 1.2.1.4 86/05/29 16:26:54 harris * Added definitions of and _errno (helps compile!). * * Revision 1.2.1.3 86/05/29 14:57:49 harris * Merged Excelan (Rel.1) and gould and other release 2 changes for rel. 1. * Moved include file to ../inc/exos/EXOS.h, make SUN use SENDMSG (not sendmsg). * * Revision 1.12.1.2 86/05/23 18:32:24 harris * Support for Excelan. #ifdefs to handle include file differences in 4.1. * * Revision 2.0 86/02/20 14:40:39 parker * First development revision for Release 2 * * Revision 1.2 86/02/14 11:00:34 goodmon * Removed non-relative pathnames of include files. * * Revision 1.1 85/11/18 13:45:17 brennan * Initial revision * * Revision 1.10 85/10/15 14:20:16 goodmon * Cleaned out some lint. * * Revision 1.9 85/08/12 11:46:00 taylor * Removed include of xns.h and pep.h * * Revision 1.8 85/07/22 10:19:12 goodmon * Added debugging code to go with the -D switch. * * Revision 1.7 85/07/08 15:44:34 taylor * Define rcsid[]. * * Revision 1.6 85/06/19 16:50:17 taylor * Include common protocol definition files. * * Revision 1.5 85/06/10 18:37:12 goodmon * fixed a bug in erpc_sendresp() that caused the courier header to be * stripped off, which it shouldn't have been. * * Revision 1.4 85/06/04 14:45:09 taylor * Modify erpc_callresp to return -1 on timeout. * * Revision 1.3 85/06/04 14:19:25 taylor * Modify erpc_callresp to check, then strip PEP header in return message. * * Revision 1.2 85/05/30 20:44:57 taylor * Added routine erpc_sendresp() * * Revision 1.1 85/05/01 21:39:30 taylor * Initial revision * * * This file is currently under revision by: * * $Locker: $ * ***************************************************************************** */ #define RCSDATE $Date: 1995/09/26 13:07:41 $ #define RCSREV $Revision: 1.18.5.3 $ #define RCSID "$Header: /annex/mckinley/src/libannex/RCS/erpc_subr.c,v 1.18.5.3 1995/09/26 13:07:41 dfox Exp $" #ifndef lint static char rcsid[] = RCSID; #endif /* * Include Files */ #include "../inc/config.h" #include "../inc/port/port.h" #include #include "api_if.h" #ifndef _WIN32 #include #if !defined(EXOS) && !defined(SLIP) && !defined(need_select) #include #endif #include #else #include "../inc/port/xuio.h" #endif #include #include #include "../inc/courier/courier.h" #include "../inc/erpc/erpc.h" #if TLIPOLL #include #include #endif #ifdef need_select #include #endif /* * External Data Declarations */ UINT32 get_unspec_long(), get_long(); void set_long(); /* * Defines and Macros */ #define NPOLL 1 /* number of file descriptors to poll (TLI only) */ #ifdef FD_ZERO #define FDSETNULLPTR (fd_set *)0 #else #define FDSETNULLPTR (int *)0 #endif /* * Structure Definitions */ /* * Forward Routine Declarations */ static void send_call(); /* common call message sender */ int api_recvmsg(); int api_sendmsg (); int api_sndud(); /* * Global Data Declarations */ int alarm_flag = 0; extern int debug; /* 1 iff -d switch seen by erpcd; 0 otherwise */ /* * Send an ERPC Call message without waiting for a response. * * "s" is a descriptor for a UDP socket * "to" if non-zero, names recipient of message * if zero, indicates socket is connect()ed to peer * "pid" is PEP ID from call message being responded to * "rpnum" * "rpver" * "rproc" * "iov" is an array of iovecs * "iovlen" is the number of iovecs in the array */ void erpc_call (s, to, pid, rpnum, rpver, rproc, iovlen, iov) struct sockaddr_in *to; /* optional */ UINT32 pid, rpnum; u_short rpver, rproc; struct iovec *iov; /* optional */ { /* call common send routine to send the CALL message */ send_call(s, to, pid, rpnum, rpver, rproc, iovlen, iov); return; } #ifdef need_select /* * Signal handler for alarm that replaces select * */ void alrm_hndlr() { /* set flag indicating that there ihas been an alarm */ alarm_flag = 1; /* reset signal handleing for an alarm */ signal(SIGALRM, SIG_DFL); } #endif /* * Send an ERPC CALL message and return what comes back. * * Sends message and awaits response on UDP socket "s". If "s" is * not bound, "to" must name the recipient of the message. "pid" is * the PEP ID assigned to the outgoing message and matched to the * incoming message. It should be chosen in such a way that it is * unlikely to be reused in the lifetime of a message. "rpnum", "rpver", * and "rproc" are the remote program, remote program version, and remote * procedure desired, respectively. "iov" is an array of iovecs. The * first element of "iov" should not be used. "iovlen" is the * number of iovecs in the array that are actually used. "delay" is the * expected turnaround time (in seconds) of the message at the remote * end. "timeout" is the total amount of time the caller wishes to wait * for a response. * * "riov" is an array of iovecs that describe the buffer(s) into which * the result is to be placed. The first element of "riov" should not be used. * "riovlen" is the number of iovecs in "riov" that are actually used. * * erpc_callresp returns as a function value the number of bytes received * in the response or -1 if a timeout occurred. */ int erpc_callresp (s, to, pid, rpnum, rpver, rproc, iovlen, iov, delay, timeout, riovlen, riov, skipsend) int s, iovlen, timeout, delay, riovlen,skipsend; struct sockaddr_in *to; /* optional */ UINT32 pid, rpnum; u_short rpver, rproc; struct iovec *iov, /* optional */ *riov; { #if defined(EXOS) || defined(need_select) INT32 readfds; INT32 sdelay; #else #ifndef SLIP #ifdef FD_ZERO fd_set readfds; #else int readfds; #endif struct timeval timeval; #endif #endif int nfound, cc; struct msghdr msg; struct sockaddr_in from; struct pephdr pephdr; register struct pephdr *ph = &pephdr; static char *app_nam="erpc_callresp"; #if TLIPOLL #define NPOLL 1 struct pollfd pollfds[NPOLL]; #endif while (timeout > 0) { /* call common send routine to send the CALL message */ if (skipsend) skipsend = 0; else send_call(s, to, pid, rpnum, rpver, rproc, iovlen, iov); /* await a return message or timeout */ for (;;) { #ifdef SLIP /* post a read timeout */ if(so_schedule_timeout(s, delay)) { perror("erpc_callresp: so_schedule_timeout"); return(-1); } #else #ifdef need_select /* use alarm for timeout on recv */ signal(SIGALRM, alrm_hndlr); alarm(delay); alarm_flag = 0; /* clear alarm signal flag */ #else /* use select to wait for data */ #if TLIPOLL pollfds[0].fd=s; pollfds[0].events=POLLIN; /* delay is in sec and poll wants it in msec */ if(poll(pollfds,NPOLL,(delay*1000)) < 0) { if(errno != EINTR) { /* is this wrong ?? */ perror("erpc_sendresp: poll"); return(-1); } if(debug) printf("erpc_subr: poll returned -1\n"); } if ((pollfds[0].revents == 0) || ((pollfds[0].revents != POLLIN) && (errno == EINTR))) { timeout -= delay; break; } #else #ifdef FD_ZERO FD_ZERO(&readfds); FD_SET(s, &readfds); #else readfds = (1 << s); #endif #ifdef EXOS /* use old-style (4.1) select */ sdelay = delay; sdelay = sdelay << 10; nfound = select(32, &readfds, (INT32 *)0, sdelay); #else /* use real select */ timeval.tv_sec = delay; timeval.tv_usec = 0; nfound = select(s + 1, &readfds, FDSETNULLPTR, FDSETNULLPTR, &timeval); #endif /*EXOS*/ /* error? */ if (nfound < 0 && errno != EINTR) { perror("erpc_sendresp: select"); return(-1); } /* timeout? */ if (nfound == 0 || (nfound <0 && errno == EINTR)) { timeout -= delay; break; } #endif /*TLIPOLL*/ #endif /*need_select*/ #endif /*SLIP*/ /* * Read PEP header into local buffer, rest of message * into caller's buffer. */ riov->iov_base = (caddr_t)ph; riov->iov_len = PEPSIZE; msg.msg_name = (caddr_t)&from; msg.msg_namelen = sizeof(from); msg.msg_iov = riov; msg.msg_iovlen = riovlen + 1; #ifndef _WIN32 #ifdef HAS_CTRL_NOT_ACC msg.msg_control = (caddr_t)0; msg.msg_controllen = 0; msg.msg_flags = 0; #else msg.msg_accrights = (caddr_t)0; msg.msg_accrightslen = 0; #endif #endif cc = api_recvmsg(s,&msg,&timeout,delay,app_nam,debug); if (cc == -1) return(-1); if (cc == -2) /* EINTR on SLIP or need_select */ break; if (cc < PEPSIZE) continue; if(get_long(ph->ph_id) != pid) continue; if (ntohs(ph->ph_client) != PET_ERPR) continue; if (to) { to->sin_port = from.sin_port; to->sin_addr.s_addr = from.sin_addr.s_addr; } return(cc - PEPSIZE); } } /* timeout */ return(-1); } /* * Send an ERPC reject message. * ('to' doesn't look optional to me!) */ void erpc_reject(s, to, pid, det, verlo, verhi) struct sockaddr_in *to; /* optional */ UINT32 pid; u_short det, verlo, verhi; { TLI_PTR(struct t_unitdata,tlireqsnd,NULL) char *app_nam="erpc_reject"; struct { struct jhdr jhdr; u_short vers[2]; } jbuff; register struct jhdr *jh = &jbuff.jhdr; int nb = PEPSIZE + CMJSIZE; if (debug) printf("erpc_reject: %d %d %d\n", det, verlo, verhi); /* * Format reject message. */ set_long(jh->jh_id, pid); jh->jh_client = ntohs(PET_ERPR); jh->jh_type = ntohs(C_REJECT); jh->jh_tid = 0; jh->jh_det = ntohs(det); if (det == CMJ_NOVERS) { jbuff.vers[0] = ntohs(verlo); jbuff.vers[1] = ntohs(verhi); nb += 2*sizeof(u_short); } TLI_ALLOC(tlireqsnd,t_unitdata,s,T_UNITDATA,T_ADDR|T_UDATA, app_nam,exit(1)); (void)api_sndud(s, ((to==NULL)?0:sizeof(struct sockaddr_in)), to, tlireqsnd, (u_char *)jh, nb, app_nam, TRUE); return; } /* * Send an ERPC Return message. * This is a normal case path; a return message usually implies that the * call message was understood and acted on. * * "s" is a descriptor for a UDP socket * "to" if non-zero, names recipient of message * if zero, indicates socket is connect()ed to peer * "pid" is PEP ID from call message being responded to * "iov" is an array of iovecs * "iovlen" is the number of iovecs in the array */ void erpc_return (s, to, pid, iovlen, iov) struct sockaddr_in *to; /* optional */ UINT32 pid; struct iovec *iov; /* optional */ { static char *app_nam="erpc_return"; struct rhdr rhdr; register struct rhdr *rh = &rhdr; struct msghdr msg; struct iovec liov[1], *piov; #ifndef lint int bufsize = 0; /* for debug */ static u_char buffer[1600]; /* for debug, holds max size buffer*/ #endif set_long (&rh->rh_id[0], pid); if (debug) { printf ("erpc_return: iovlen=%d\n", iovlen); printf ("erpc_return: rh_id[0]=%x rh_id[1]=%x\n", rh->rh_id[0], rh->rh_id[1]); } rh->rh_client = ntohs(PET_ERPR); rh->rh_type = ntohs(C_RETURN); rh->rh_tid = 0; piov = iovlen ? iov : liov; piov->iov_base = (caddr_t)rh; piov->iov_len = RHDRSIZE; msg.msg_name = (caddr_t)to; msg.msg_namelen = (to == NULL) ? 0 : sizeof(struct sockaddr_in); msg.msg_iov = piov; msg.msg_iovlen = iovlen + 1; #ifndef _WIN32 #ifdef HAS_CTRL_NOT_ACC msg.msg_control = (caddr_t)0; msg.msg_controllen = 0; msg.msg_flags = 0; #else msg.msg_accrights = (caddr_t)0; msg.msg_accrightslen = 0; #endif #endif /* * if you want to print the message being returned here * SENDMSG() in ../erpc/sendrecv.c has some code that can help */ (void)api_sendmsg(s, &msg, app_nam, debug); return; } /* * Send an ERPC Abort message. * * "err" error code * "" all other arguments same as erpc_return() */ void erpc_abort (s, to, pid, err, iovlen, iov) struct sockaddr_in *to; /* optional */ UINT32 pid; u_short err; int iovlen; struct iovec *iov; /* optional */ { struct ahdr ahdr; struct msghdr msg; struct iovec liov[1], *piov; char *app_nam="erpc_abort"; if (debug) printf("erpc_abort: %d %d\n", err, iovlen); set_long(ahdr.ah_id, pid); ahdr.ah_client = ntohs(PET_ERPR); ahdr.ah_type = ntohs(C_ABORT); ahdr.ah_tid = 0; ahdr.ah_err = ntohs(err); piov = iovlen ? iov : liov; piov->iov_base = (caddr_t)&ahdr; piov->iov_len = sizeof(ahdr); msg.msg_name = (caddr_t)to; msg.msg_namelen = (to == NULL) ? 0 : sizeof(struct sockaddr_in); msg.msg_iov = piov; msg.msg_iovlen = iovlen + 1; #ifndef _WIN32 #ifdef HAS_CTRL_NOT_ACC msg.msg_control = (caddr_t)0; msg.msg_controllen = 0; msg.msg_flags = 0; #else msg.msg_accrights = (caddr_t)0; msg.msg_accrightslen = 0; #endif #endif (void)api_sendmsg(s, &msg, app_nam, debug); return; } /* * Common Call message sender shared by erpc_call and erpc_callresp. */ static void send_call (s, to, pid, rpnum, rpver, rproc, iovlen, iov) struct sockaddr_in *to; /* optional */ UINT32 pid, rpnum; u_short rpver, rproc; struct iovec *iov; /* optional */ { char *app_nam="send_call"; struct chdr chdr; register struct chdr *ch = &chdr; struct msghdr msg; struct iovec liov, *piov; if (debug) printf("send_call %d\n", iovlen); set_long(ch->ch_id, pid); ch->ch_client = ntohs(PET_ERPC); ch->ch_type = ntohs(C_CALL); ch->ch_tid = 0; set_long(ch->ch_rpnum, rpnum); ch->ch_rpver = ntohs(rpver); ch->ch_rproc = ntohs(rproc); piov = iovlen ? iov : &liov; piov->iov_base = (caddr_t)ch; piov->iov_len = CHDRSIZE; msg.msg_name = (caddr_t)to; msg.msg_namelen = (to == NULL) ? 0 : sizeof(struct sockaddr_in); msg.msg_iov = piov; msg.msg_iovlen = iovlen + 1; #ifndef _WIN32 #ifdef HAS_CTRL_NOT_ACC msg.msg_control = (caddr_t)0; msg.msg_controllen = 0; msg.msg_flags = 0; #else msg.msg_accrights = (caddr_t)0; msg.msg_accrightslen = 0; #endif #endif (void)api_sendmsg(s, &msg, app_nam, debug); return; } /* * get_long: get a 32-bit value from an array of 2 u_short's, first * convert it from network to host byte ordering; this is * to ensure correct return even if not aligned at a long! */ UINT32 get_long(shorts) u_short *shorts; { union split { UINT32 sp_long; u_short sp_shorts[2]; } SP; #define Sp_long SP.sp_long #define Sp_shorts SP.sp_shorts Sp_shorts[0] = shorts[0]; Sp_shorts[1] = shorts[1]; return ntohl(Sp_long); } /* * set_long: convert 32-bit value from host to network ordering, and * place result in a location which might not be properly * aligned (not on a 32-bit boundary) */ void set_long(two_shorts, a_long) u_short *two_shorts; UINT32 a_long; { union split { UINT32 sp_long; u_short sp_shorts[2]; } SP; #define Sp_long SP.sp_long #define Sp_shorts SP.sp_shorts Sp_long = htonl(a_long); two_shorts[0] = Sp_shorts[0]; two_shorts[1] = Sp_shorts[1]; return; } /* * get_unspec_long: get a 32-bit value from an array of 2 u_short's */ UINT32 get_unspec_long(shorts) u_short *shorts; { union split { UINT32 sp_long; u_short sp_shorts[2]; } SP; #define Sp_long SP.sp_long #define Sp_shorts SP.sp_shorts Sp_shorts[0] = shorts[0]; Sp_shorts[1] = shorts[1]; return(Sp_long); } /* * set_unspec_long: place long in a location which might not be properly * aligned (not on a 32-bit boundary) */ void set_unspec_long(two_shorts, a_long) u_short *two_shorts; UINT32 a_long; { union split { UINT32 sp_long; u_short sp_shorts[2]; } SP; #define Sp_long SP.sp_long #define Sp_shorts SP.sp_shorts Sp_long = a_long; two_shorts[0] = Sp_shorts[0]; two_shorts[1] = Sp_shorts[1]; return; } /* prints messages * assumes contigous string of bytes * prints in hex * used by bfs.c, generically handy */ void display(buffer, buflen) u_char *buffer; int buflen; { char pbuff[20]; register u_char *bp; register i; if (!debug) /* don't dump under non-debug mode */ return; pbuff[0] = '*'; pbuff[17] = '*'; pbuff[18] = '\0'; for (bp = buffer, i = 0; i < buflen; bp++, i++) { if ((i % 16) == 0) { printf("%5d ", i); memset(&pbuff[2], ' ', 15); } printf("%x%x ", *bp >> 4, *bp & 0x0f); pbuff[i % 16 + 1] = (*bp >= 32 && *bp <= 127) ? *bp : '.'; if ((i % 16) == 15) printf(" %s\n", pbuff); } if ((i % 16) == 0) return; while ((i++ % 16) > 0) printf(" "); printf(" %s\n", pbuff); } /* display */