Sun RPC on Linux

WPI Worcester Polytechnic Institute

Computer Science Department


Sun RPC code on Linux

Sample Session on ccc7

< ccc7 /cs/cs4513/public/RPC-Linux/Date >ls
date.x       dateproc.c   rdate.c
< ccc7 /cs/cs4513/public/RPC-Linux/Date >rpcgen date.x
< ccc7 /cs/cs4513/public/RPC-Linux/Date >ls
date.h        date_clnt.c   dateproc.c
date.x        date_svc.c    rdate.c
< ccc7 /cs/cs4513/public/RPC-Linux/Date >cc -o rdate rdate.c date_clnt.c
< ccc7 /cs/cs4513/public/RPC-Linux/Date >cc -o dateproc dateproc.c date_svc.c
< ccc7 /cs/cs4513/public/RPC-Linux/Date >./dateproc&
[1] 15663
< ccc7 /cs/cs4513/public/RPC-Linux/Date >./rdate ccc7
time on host ccc7 = 1081360462
time on host ccc7 = Wed Apr  7 13:54:22 2004
< ccc7 /cs/cs4513/public/example/Date 8 >exit

Jae Chung's explanation of Linux differences for Sun RPC

README by Jae Chung (goos@cs.wpi.edu) Date: April 4, 2004

The RPC examples under ./ex-linux work on Linux machines
(ccc, fossil server and clients, and etc.)

The RPC examples under ./ex-unix work on Digital Unix machines
(cpu).

The difference is due to that "rpcgen" in Linux and Digital 
Unix generate slightly different server side rpc definition.
For example, assuming the following date.x:

   program DATE_PROG {
     version DATE_VERS {
        long BIN_DATE(void) = 1;    /* procedure number = 1 */
        string STR_DATE(long) = 2;  /* procedure number = 2 */
     } = 1;                         /* version number = 1 */
   } = 0x31234567;           

The server side rpc definitions (in date.h) generated by Linux
are:

   extern  long * bin_date_1_svc(void *, struct svc_req *);
   extern  char ** str_date_1_svc(long *, struct svc_req *);

while Digital Unix generates:

   extern long *bin_date_1();
   extern char **str_date_1();

The Linux generated rpc definitions always have two arguements
of which the second one can be ignored for general purpose rpc
implementations.


date.x

/*
 * date.x  Specification of the remote date and time server
 */
 
/*
 * Define two procedures
 *      bin_date_1() returns the binary date and time (no arguments)
 *      str_date_1() takes a binary time and returns a string
 *
 */
 
program DATE_PROG {
    version DATE_VERS {
        long BIN_DATE(void) = 1;    /* procedure number = 1 */
        string STR_DATE(long) = 2;  /* procedure number = 2 */
    } = 1;                          /* version number = 1 */
} = 0x31234567;                     /* program number = 0x31234567 */

date.h

/*
 * Please do not edit this file.
 * It was generated using rpcgen.
 */

#ifndef _DATE_H_RPCGEN
#define _DATE_H_RPCGEN

#include 


#ifdef __cplusplus
extern "C" {
#endif


#define DATE_PROG 0x31234567
#define DATE_VERS 1

#if defined(__STDC__) || defined(__cplusplus)
#define BIN_DATE 1
extern  long * bin_date_1(void *, CLIENT *);
extern  long * bin_date_1_svc(void *, struct svc_req *);
#define STR_DATE 2
extern  char ** str_date_1(long *, CLIENT *);
extern  char ** str_date_1_svc(long *, struct svc_req *);
extern int date_prog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);

#else /* K&R C */
#define BIN_DATE 1
extern  long * bin_date_1();
extern  long * bin_date_1_svc();
#define STR_DATE 2
extern  char ** str_date_1();
extern  char ** str_date_1_svc();
extern int date_prog_1_freeresult ();
#endif /* K&R C */

#ifdef __cplusplus
}
#endif

#endif /* !_DATE_H_RPCGEN */

date_svc.c "the server stub generated by rpcgen"

/*
 * Please do not edit this file.
 * It was generated using rpcgen.
 */

#include "date.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#ifndef SIG_PF
#define SIG_PF void(*)(int)
#endif

static void
date_prog_1(struct svc_req *rqstp, register SVCXPRT *transp)
{
	union {
		long str_date_1_arg;
	} argument;
	char *result;
	xdrproc_t _xdr_argument, _xdr_result;
	char *(*local)(char *, struct svc_req *);

	switch (rqstp->rq_proc) {
	case NULLPROC:
		(void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL);
		return;

	case BIN_DATE:
		_xdr_argument = (xdrproc_t) xdr_void;
		_xdr_result = (xdrproc_t) xdr_long;
		local = (char *(*)(char *, struct svc_req *)) bin_date_1_svc;
		break;

	case STR_DATE:
		_xdr_argument = (xdrproc_t) xdr_long;
		_xdr_result = (xdrproc_t) xdr_wrapstring;
		local = (char *(*)(char *, struct svc_req *)) str_date_1_svc;
		break;

	default:
		svcerr_noproc (transp);
		return;
	}
	memset ((char *)&argument, 0, sizeof (argument));
	if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
		svcerr_decode (transp);
		return;
	}
	result = (*local)((char *)&argument, rqstp);
	if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
		svcerr_systemerr (transp);
	}
	if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
		fprintf (stderr, "%s", "unable to free arguments");
		exit (1);
	}
	return;
}

int
main (int argc, char **argv)
{
	register SVCXPRT *transp;

	pmap_unset (DATE_PROG, DATE_VERS);

	transp = svcudp_create(RPC_ANYSOCK);
	if (transp == NULL) {
		fprintf (stderr, "%s", "cannot create udp service.");
		exit(1);
	}
	if (!svc_register(transp, DATE_PROG, DATE_VERS, date_prog_1, IPPROTO_UDP)) {
		fprintf (stderr, "%s", "unable to register (DATE_PROG, DATE_VERS, udp).");
		exit(1);
	}

	transp = svctcp_create(RPC_ANYSOCK, 0, 0);
	if (transp == NULL) {
		fprintf (stderr, "%s", "cannot create tcp service.");
		exit(1);
	}
	if (!svc_register(transp, DATE_PROG, DATE_VERS, date_prog_1, IPPROTO_TCP)) {
		fprintf (stderr, "%s", "unable to register (DATE_PROG, DATE_VERS, tcp).");
		exit(1);
	}

	svc_run ();
	fprintf (stderr, "%s", "svc_run returned");
	exit (1);
	/* NOTREACHED */
}

date_clnt.c "the client stub generated by rpcgen"

/*
 * Please do not edit this file.
 * It was generated using rpcgen.
 */

#include  /* for memset */
#include "date.h"

/* Default timeout can be changed using clnt_control() */
static struct timeval TIMEOUT = { 25, 0 };

long *
bin_date_1(void *argp, CLIENT *clnt)
{
	static long clnt_res;

	memset((char *)&clnt_res, 0, sizeof(clnt_res));
	if (clnt_call (clnt, BIN_DATE,
		(xdrproc_t) xdr_void, (caddr_t) argp,
		(xdrproc_t) xdr_long, (caddr_t) &clnt_res,
		TIMEOUT) != RPC_SUCCESS) {
		return (NULL);
	}
	return (&clnt_res);
}

char **
str_date_1(long *argp, CLIENT *clnt)
{
	static char *clnt_res;

	memset((char *)&clnt_res, 0, sizeof(clnt_res));
	if (clnt_call (clnt, STR_DATE,
		(xdrproc_t) xdr_long, (caddr_t) argp,
		(xdrproc_t) xdr_wrapstring, (caddr_t) &clnt_res,
		TIMEOUT) != RPC_SUCCESS) {
		return (NULL);
	}
	return (&clnt_res);
}

dateproc.c "the server program"

/*
 * dateproc.c   remote procedures; called by server stub
 */

#include 
#include         /* standard RPC include file */
#include "date.h"           /* this file is generated by rpcgen */

/*
 * Return the binary date and time
 */
 
 long *bin_date_1_svc(void *arg1, struct svc_req *arg2)
 {
    static long timeval;    /* must be static */
 
    timeval = time((long *) 0);
    return(&timeval);
 }
 
/*
 * Convert a binary time and return a human readable string
 */
  
char **str_date_1_svc(long *bintime, struct svc_req *arg2)
{
    static char *ptr;       /* must be static */
    ptr = ctime(bintime);   /* convert to local time */
    return(&ptr);
}

rdate.c "the client program"

/*
 * rdate.c  client program for remote date program
 */
 
#include 
#include     /* standard RPC include file */
#include "date.h"       /* this file is generated by rpcgen */

main(int argc, char *argv[])
{
    CLIENT *cl;         /* RPC handle */
    char *server;
    long *lresult;      /* return value from bin_date_1() */
    char **sresult;     /* return value from str_date_1() */
    
    if (argc != 2) {
        fprintf(stderr, "usage: %s hostname\n", argv[0]);
        exit(1);
    }
    
    server = argv[1];
    
    /*
     * Create client handle
     */
    
    if ((cl = clnt_create(server, DATE_PROG, DATE_VERS, "udp")) == NULL) {
        /*
         * can't establish connection with server
         */
         clnt_pcreateerror(server);
         exit(2);
    }
    
    /*
     * First call the remote procedure "bin_date".
     */
     
    if ( (lresult = bin_date_1(NULL, cl)) == NULL) {
        clnt_perror(cl, server);
        exit(3);
    }
    printf("time on host %s = %ld\n",server, *lresult);
    
    /*
     * Now call the remote procedure str_date
     */
     
    if ( (sresult = str_date_1(lresult, cl)) == NULL) {
        clnt_perror(cl, server);
        exit(4);
    }
    printf("time on host %s = %s", server, *sresult);
    
    clnt_destroy(cl);         /* done with the handle */
    exit(0);
}

Bob Kinicki
Fuller Labs 135
Computer Science Department
Worcester Polytechnic Institute
Worcester, MA 01609
rek@cs.wpi.edu
Last modified: 8 April 2004

REK's Home Page