Safe and Simple Sun RPC routines

Flame Bait joshua at athertn.Atherton.COM
Fri Sep 29 16:08:27 AEST 1989


Currently the simplest way to use Sun's RPC system is to use two routines:
registerrpc and callrpc.  Unfortunately, the RPC call generated by these
routines are not always reliable.  

This shar contains code with the same interface as registerrpc and callrpc,
but the RPC calls it makes are much more reliable, perhaps totally so.

I'm releasing this code here in order to test it, and to get general feedback
on it.  Assuming people tell me they find it useful, and there are no fatal 
bugs in it, I'll give it wider distribution in a month or so.

Joshua Levy                          joshua at atherton.com  home:(415)968-3718
                        {decwrl|sun|hpda}!athertn!joshua  work:(408)734-9822 
-------------------------------- cut here ----------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	clnt_safe.c
#	svc_safe.c
#	safe.c
#	Makefile
# This archive created: Thu Sep 28 22:56:36 1989
# By:	Flame Bait ()
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
X
XSafe rpccall and registerrpc for Sun's RPC system.   (Version 1.0)
XFrom Sun's RPC 3.9 code, modified by Joshua Levy
X
XThese routines use the TCP transport layer, and so they are safe to
Xuse.  They are also just as easy to use as Sun's "simple" (but unsafe) 
XUDP routines.  There is also an interesting RPC test program in here.
X
XTo run this stuff, just unpack it and type "make test".  This will make
Xa bunch of servers and a bunch of clients, and run them.  You must kill
Xthe servers by hand when the test is done.
X
XTo use it with your code, link clnt_safe.o with your client code, and
Xsvc_safe.o with you server code.
X
XNote that these routines (safe_registerrpc and safe_callrpc) are plug
Xcompatible with the sun routines (registerrpc and callrpc).  Since these 
XTCP based routines are much more reliable than the UDP based default which 
XSun supplies.  I'd always use these routines instead of Sun's, unless speed 
Xis critical and you are willing to check for repeat RPC calls yourself. 
X
XFor quantitative information on the unreliablity of Sun's, see my 
Xpaper "A Comparison of Commercial RPCs".  To get a copy of this paper send 
Xmail containing the line "send other comprpc.shar" or "send other comprpc.txt"
Xto the address archive-server at joshua.atherton.com or {sun|decwrl|hpda}!
Xathertn!archive-server. The first file uses troff's me macros, the second is 
Xalmost plain text.
X
XI have tested these routines, but only on one sort of network and one sort
Xof machine, so there may be problems.  This code is worth more than you
Xpaid for it, but not much. :-)  Please email me bug reports.  I plan to
Xrelease this code to a wider audience soon, so bug reports are important.
X
XIf you find these routines useful, please send me a postcard.  Thanks.
X
X	Joshua Levy @ Atherton Technology
X	1333 Bordeaux Dr.
X	Sunnyvale, CA
X	94089
X
X	(408) 734-9822
X	joshua at atherton.com
X        {hpda,sun,decwrl,coherent,pyramid}!athertn!joshua
SHAR_EOF
fi
if test -f 'clnt_safe.c'
then
	echo shar: "will not over-write existing file 'clnt_safe.c'"
else
sed 's/^X//' << \SHAR_EOF > 'clnt_safe.c'
X/* @(#)clnt_safe.c	1.1 87/11/04 3.9 RPCSRC */
X/*
X * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
X * unrestricted use provided that this legend is included on all tape
X * media and as a part of the software program in whole or part.  Users
X * may copy or modify Sun RPC without charge, but are not authorized
X * to license or distribute it to anyone else except as part of a product or
X * program developed by the user.
X * 
X * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
X * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
X * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
X * 
X * Sun RPC is provided with no support and without any obligation on the
X * part of Sun Microsystems, Inc. to assist in its use, correction,
X * modification or enhancement.
X * 
X * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
X * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
X * OR ANY PART THEREOF.
X * 
X * In no event will Sun Microsystems, Inc. be liable for any lost revenue
X * or profits or other special, indirect and consequential damages, even if
X * Sun has been advised of the possibility of such damages.
X * 
X * Sun Microsystems, Inc.
X * 2550 Garcia Avenue
X * Mountain View, California  94043
X *
X * This file has been modified by Joshua Levy in 1989.
X * These changes are (C) 1989 Joshua Levy All Rights Reserved.
X */
X#if !defined(lint) && defined(SCCSIDS)
Xstatic char sccsid[] = "@(#)clnt_safe.c 1.35 87/08/11 Copyr 1984 Sun Micro";
X#endif
X
X/* 
X * clnt_safe.c
X * Simplified and safe front end to rpc.
X *
X * Copyright (C) 1984, Sun Microsystems, Inc.
X * Changes Copyright (C) 1989, Joshua Levy.
X */
X
X#include <stdio.h>
X#include <rpc/rpc.h>
X#include <sys/socket.h>
X#include <sys/time.h>
X#include <netdb.h>
X#include <strings.h>
X
Xstatic struct callrpc_private {
X	CLIENT	*client;
X	int	socket;
X	int	oldprognum, oldversnum, valid;
X	char	*oldhost;
X} *callrpc_private;
X
Xsafe_callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out)
X	char *host;
X	xdrproc_t inproc, outproc;
X	char *in, *out;
X{
X	register struct callrpc_private *crp = callrpc_private;
X	struct sockaddr_in server_addr;
X	enum clnt_stat clnt_stat;
X	struct hostent *hp;
X	struct timeval timeout, tottimeout;
X
X	if (crp == 0) {
X		crp = (struct callrpc_private *)calloc(1, sizeof (*crp));
X		if (crp == 0)
X			return (0);
X		callrpc_private = crp;
X	}
X	if (crp->oldhost == NULL) {
X		crp->oldhost = malloc(256);
X		crp->oldhost[0] = 0;
X		crp->socket = RPC_ANYSOCK;
X	}
X	if (crp->valid && crp->oldprognum == prognum && crp->oldversnum == versnum
X		&& strcmp(crp->oldhost, host) == 0) {
X		/* reuse old client */		
X	} else {
X		crp->valid = 0;
X		(void)close(crp->socket);
X		crp->socket = RPC_ANYSOCK;
X		if (crp->client) {
X			clnt_destroy(crp->client);
X			crp->client = NULL;
X		}
X		if ((hp = gethostbyname(host)) == NULL)
X			return ((int) RPC_UNKNOWNHOST);
X		timeout.tv_usec = 0;
X		timeout.tv_sec = 5;
X		bcopy(hp->h_addr, (char *)&server_addr.sin_addr, hp->h_length);
X		server_addr.sin_family = AF_INET;
X		server_addr.sin_port =  0;
X		if ((crp->client = clnttcp_create(&server_addr, (u_long)prognum,
X		    (u_long)versnum, &crp->socket,0,0)) == NULL)
X			return ((int) rpc_createerr.cf_stat);
X		crp->valid = 1;
X		crp->oldprognum = prognum;
X		crp->oldversnum = versnum;
X		(void) strcpy(crp->oldhost, host);
X	}
X	tottimeout.tv_sec = 25;
X	tottimeout.tv_usec = 0;
X	clnt_stat = clnt_call(crp->client, procnum, inproc, in,
X	    outproc, out, tottimeout);
X	/* 
X	 * if call failed, empty cache
X	 */
X	if (clnt_stat != RPC_SUCCESS)
X		crp->valid = 0;
X	return ((int) clnt_stat);
X}
SHAR_EOF
fi
if test -f 'svc_safe.c'
then
	echo shar: "will not over-write existing file 'svc_safe.c'"
else
sed 's/^X//' << \SHAR_EOF > 'svc_safe.c'
X/* @(#)svc_safe.c	1.1 87/11/04 3.9 RPCSRC */
X/*
X * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
X * unrestricted use provided that this legend is included on all tape
X * media and as a part of the software program in whole or part.  Users
X * may copy or modify Sun RPC without charge, but are not authorized
X * to license or distribute it to anyone else except as part of a product or
X * program developed by the user.
X * 
X * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
X * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
X * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
X * 
X * Sun RPC is provided with no support and without any obligation on the
X * part of Sun Microsystems, Inc. to assist in its use, correction,
X * modification or enhancement.
X * 
X * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
X * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
X * OR ANY PART THEREOF.
X * 
X * In no event will Sun Microsystems, Inc. be liable for any lost revenue
X * or profits or other special, indirect and consequential damages, even if
X * Sun has been advised of the possibility of such damages.
X * 
X * Sun Microsystems, Inc.
X * 2550 Garcia Avenue
X * Mountain View, California  94043
X */
X#if !defined(lint) && defined(SCCSIDS)
Xstatic char sccsid[] = "@(#)svc_simple.c 1.18 87/08/11 Copyr 1984 Sun Micro";
X#endif
X
X/* 
X * svc_safe.c
X * Simplified and safe front end to rpc.
X *
X * Copyright (C) 1984, Sun Microsystems, Inc.
X * Changes Copyright (C) 1989, Joshua Levy.
X */
X
X#include <stdio.h>
X#include <rpc/rpc.h>
X#include <sys/socket.h>
X#include <sys/time.h>
X#include <netdb.h>
X
X#define TCPMSGSIZE 66000   /* bigger than 64K */
X
Xstatic struct proglst {
X	char *(*p_progname)();
X	int  p_prognum;
X	int  p_procnum;
X	xdrproc_t p_inproc, p_outproc;
X	struct proglst *p_nxt;
X} *proglst;
Xstatic void safe_universal();
Xstatic SVCXPRT *transp;
Xstruct proglst *pl;
X
Xsafe_registerrpc(prognum, versnum, procnum, progname, inproc, outproc)
X	char *(*progname)();
X	xdrproc_t inproc, outproc;
X{
X	
X	if (procnum == NULLPROC) {
X		(void) fprintf(stderr,
X		    "can't reassign procedure number %d\n", NULLPROC);
X		return (-1);
X	}
X	if (transp == 0) {
X		transp = svctcp_create(RPC_ANYSOCK,0,0);
X		if (transp == NULL) {
X			(void) fprintf(stderr, "couldn't create an rpc server\n");
X			return (-1);
X		}
X	}
X	(void) pmap_unset((u_long)prognum, (u_long)versnum);
X	if (!svc_register(transp, (u_long)prognum, (u_long)versnum, 
X	    safe_universal, IPPROTO_TCP)) {
X	    	(void) fprintf(stderr, "couldn't register prog %d vers %d\n",
X		    prognum, versnum);
X		return (-1);
X	}
X	pl = (struct proglst *)malloc(sizeof(struct proglst));
X	if (pl == NULL) {
X		(void) fprintf(stderr, "registerrpc: out of memory\n");
X		return (-1);
X	}
X	pl->p_progname = progname;
X	pl->p_prognum = prognum;
X	pl->p_procnum = procnum;
X	pl->p_inproc = inproc;
X	pl->p_outproc = outproc;
X	pl->p_nxt = proglst;
X	proglst = pl;
X	return (0);
X}
X
Xstatic void
Xsafe_universal(rqstp, transp)
X	struct svc_req *rqstp;
X	SVCXPRT *transp;
X{
X	int prog, proc;
X	char *outdata;
X	char xdrbuf[TCPMSGSIZE];
X	struct proglst *pl;
X
X	/* 
X	 * enforce "procnum 0 is echo" convention
X	 */
X	if (rqstp->rq_proc == NULLPROC) {
X		if (svc_sendreply(transp, xdr_void, (char *)NULL) == FALSE) {
X			(void) fprintf(stderr, "xxx\n");
X			exit(1);
X		}
X		return;
X	}
X	prog = rqstp->rq_prog;
X	proc = rqstp->rq_proc;
X	for (pl = proglst; pl != NULL; pl = pl->p_nxt)
X		if (pl->p_prognum == prog && pl->p_procnum == proc) {
X			/* decode arguments into a CLEAN buffer */
X			bzero(xdrbuf, sizeof(xdrbuf)); /* required ! */
X			if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) {
X				svcerr_decode(transp);
X				return;
X			}
X			outdata = (*(pl->p_progname))(xdrbuf);
X			if (outdata == NULL && pl->p_outproc != xdr_void)
X				/* there was an error */
X				return;
X			if (!svc_sendreply(transp, pl->p_outproc, outdata)) {
X				(void) fprintf(stderr,
X				    "trouble replying to prog %d\n",
X				    pl->p_prognum);
X				exit(1);
X			}
X			/* free the decoded arguments */
X			(void)svc_freeargs(transp, pl->p_inproc, xdrbuf);
X			return;
X		}
X	(void) fprintf(stderr, "never registered prog %d\n", prog);
X	exit(1);
X}
X
SHAR_EOF
fi
if test -f 'safe.c'
then
	echo shar: "will not over-write existing file 'safe.c'"
else
sed 's/^X//' << \SHAR_EOF > 'safe.c'
X/*
X * Data Reprsentation Test for Sun: this file tests all simple types
X * by Joshua Levy
X */
X
X#include <stdio.h>
X#include <assert.h>
X#include <sys/time.h>  /* this includes <time.h> */
X#include <rpc/rpc.h>
X
X#define PROG  0x72938007L      /* The base program number */
X#define VERS  0L               /* The version number */
X
X/* 
X * These macros are totally sleezy.  I know this.  I did it anyway.
X * TYPEN TYPE and SIZE should be defined on the command line
X *    TYPEN should be unique for each type, and a multiple of 10,000
X *    TYPE can be: float, int, double, etc.
X *    SIZE can be: 10, 100, 1000, etc.
X *    COUNT can be any number
X *    remember that sizeof(TYPE)*SIZE < 8K or this will not work
X * See the Makefile for examples.
X */
X
X/* set up defaults */
X#ifndef TYPEN
X#define TYPEN 10000
X#endif
X#ifndef TYPE
X#define TYPE int
X#endif
X#ifndef SIZE
X#define SIZE 1000
X#endif
X#ifndef COUNT
X#define COUNT 100
X#endif
X
X
Xxdr_routine(xdr,ptr) XDR *xdr ; TYPE *ptr ; {
X    u_int size = SIZE ;
X    return xdr_array(xdr,&ptr,&size,size,sizeof(TYPE),xdr_/**/TYPE) ;
X}
X
X
X
X#ifdef CLNT
X
X/*
X * This page become the code of the client process.
X * It just sends data to the server and waits for replies.
X */
X
Xmain(argc,argv) int argc ;  char *argv[] ;
X{
X    char *machine = "                                  " ;
X    struct timeval start ;
X    struct timeval end ;
X    int i ;
X    long sec, usec, t ;
X    static TYPE send[SIZE], recv[SIZE] ;
X
X    if (argc==2) {
X	machine = argv[1] ;
X    } else {
X	gethostname(machine,32) ;
X    }
X    gettimeofday(&start,(struct timezone *)NULL) ;
X    for(i=0 ; i<COUNT ; i++) {
X	if ( safe_callrpc(machine,PROG,VERS,TYPEN+SIZE,xdr_routine,
X		     send,xdr_routine,recv) != 0) {
X	    printf("%s: callrpc failure\n",argv[0]) ;
X	    exit(-1) ;
X	}
X    }
X    gettimeofday(&end,(struct timezone *)NULL) ;
X    usec = end.tv_usec-start.tv_usec ;
X    sec = end.tv_sec-start.tv_sec ;
X    if (usec<0) {
X	sec -= 1 ;
X	usec += 1000000 ;
X    }
X    t = time((long*)0) ;
X    printf("%s: %ld %ld sec/usec for %d\t%s",argv[0],sec,usec,i,ctime(&t)) ;
X    exit(0) ;
X}
X#endif
X
X#ifdef SRVR
X
X/*
X * The code on this page becomes the server routine.
X * Complete with stub server.
X */
X
X
Xchar *routine(indata) TYPE indata[SIZE] ;
X{
X    /* do not actually do anything here */
X    return (char*)indata ;
X}
X
Xmain(argc,argv) int argc ;  char *argv[] ;
X{
X    int s ;
X
X    s = safe_registerrpc(PROG,VERS,TYPEN+SIZE,routine,xdr_routine,
X		    xdr_routine) ;
X    if (s != 0)
X	printf("%s: registerrpc death (bummer)\n",argv[0]) ;
X    svc_run() ;
X    printf("%s: svc_run returned\n",argv[0]) ;
X    exit(2) ;
X}
X
X#endif
SHAR_EOF
fi
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X#
X# Data Representation Test for Sun: Makefile 
X# by Joshua Levy
X#
XC = -g
XL = clnt_safe.o svc_safe.o
XF = safe.c
XS = safe.c $L
X
Xeverything: ints intc shorts shortc longs longc floats floatc doubles doublec chars charc
X
Xintc: $S
X	cc $C -DTYPEN=10000 -DTYPE=int -DSIZE=1000 -DCLNT safe.c -o intc $L
X
Xints: $S
X	cc $C -DTYPEN=10000 -DTYPE=int -DSIZE=1000 -DSRVR safe.c -o ints $L
X
Xshortc: $S
X	cc $C -DTYPEN=20000 -DTYPE=short -DSIZE=1000 -DCLNT safe.c -o shortc $L
X
Xshorts: $S
X	cc $C -DTYPEN=20000 -DTYPE=short -DSIZE=1000 -DSRVR safe.c -o shorts $L
X
Xlongc: $S
X	cc $C -DTYPEN=30000 -DTYPE=long -DSIZE=1000 -DCLNT safe.c -o longc $L
X
Xlongs: $S
X	cc $C -DTYPEN=30000 -DTYPE=long -DSIZE=1000 -DSRVR safe.c -o longs $L
X
Xfloatc: $S
X	cc $C -DTYPEN=40000 -DTYPE=float -DSIZE=1000 -DCLNT safe.c -o floatc $L
X
Xfloats: $S
X	cc $C -DTYPEN=40000 -DTYPE=float -DSIZE=1000 -DSRVR safe.c -o floats $L
X
Xdoublec: $S
X	cc $C -DTYPEN=50000 -DTYPE=double -DSIZE=1000 -DCLNT $F -o doublec $L
X
Xdoubles: $S
X	cc $C -DTYPEN=50000 -DTYPE=double -DSIZE=1000 -DSRVR $F -o doubles $L
X
Xcharc: $S
X	cc $C -DTYPEN=60000 -DTYPE=char -DSIZE=1000 -DCLNT safe.c -o charc $L
X
Xchars: $S
X	cc $C -DTYPEN=60000 -DTYPE=char -DSIZE=1000 -DSRVR safe.c -o chars $L
X
Xclean:
X	rm -f ints intc shorts shortc longs longc floats floatc doubles doublec chars charc
X
Xtest:
X	make
X	ints & intc
X	shorts & shortc
X	longs &	longc
X	floats & floatc 
X	doubles & doublec
X	chars & charc
X	echo "Remember to kill the servers.  They are named:"
X	echo "ints shorts longs floats doubles chars "
X
X
SHAR_EOF
fi
exit 0
#	End of shell archive



More information about the Alt.sources mailing list