ONC+ Developer's Guide

Connection-Oriented Transports

Example 4–20 copies a file from one host to another. The RPC send() call reads standard input and sends the data to the server receive(), which writes the data to standard output. This example also illustrates an XDR procedure that behaves differently on serialization and on deserialization. A connection-oriented transport is used.


Example 4–20 Remote Copy (Two-Way XDR Routine)

/*
 * The xdr routine:
 *      on decode, read wire, write to fp
 *      on encode, read fp, write to wire
 */
#include <stdio.h>
#include <rpc/rpc.h>
 
bool_t
xdr_rcp(xdrs, fp)
	XDR *xdrs;
	FILE *fp;
{
	unsigned long size;
	char buf[BUFSIZ], *p;
 
	if (xdrs->x_op == XDR_FREE)            /* nothing to free */
		return(TRUE);
	while (TRUE) {
		if (xdrs->x_op == XDR_ENCODE) {
			if ((size = fread( buf, sizeof( char ), BUFSIZ, fp))
				   == 0 && ferror(fp)) {
				fprintf(stderr, "can't fread\n");
				return(FALSE);
			} else
				return(TRUE);
		}
		p = buf;
		if (! xdr_bytes( xdrs, &p, &size, BUFSIZ))
			return(0);
		if (size == 0)
			return(1);
		if (xdrs->x_op == XDR_DECODE) {
			if (fwrite( buf, sizeof(char), size, fp) != size) {
				fprintf(stderr, "can't fwrite\n");
				return(FALSE);
			} else
				return(TRUE);
		}
	}
}

In Example 4–21 and Example 4–22, the serializing and deserializing are done only by the xdr_rcp() routine shown in Example 4–20.


Example 4–21 Remote Copy Client Routines

/* The sender routines */
#include <stdio.h>

#include <netdb.h>
#include <rpc/rpc.h>

#include <sys/socket.h>
#include <sys/time.h>
#include "rcp.h"
 
main(argc, argv)
	int argc;
	char **argv;
{
	int xdr_rcp();
 
	if (argc != 2 7) {
		fprintf(stderr, "usage: %s servername\n", argv[0]);
		exit(1);
	}
	if( callcots( argv[1], RCPPROG, RCPPROC, RCPVERS, xdr_rcp,
stdin,
		  xdr_void, 0 ) != 0 )
		exit(1);
	exit(0);
}
 
callcots(host, prognum, procnum, versnum, inproc, in, outproc,
out)
	char *host, *in, *out;
	xdrproc_t inproc, outproc;
{
	enum clnt_stat clnt_stat;
	register CLIENT *client;
	struct timeval total_timeout;
 
	if ((client = clnt_create( host, prognum, versnum,
"circuit_v")
	   == (CLIENT *) NULL)) {
		clnt_pcreateerror("clnt_create");
		return(-1);
	}
	total_timeout.tv_sec = 20;
	total_timeout.tv_usec = 0;
	clnt_stat = clnt_call(client, procnum, inproc, in, outproc,
out,
	                       total_timeout);
	clnt_destroy(client);
	if (clnt_stat != RPC_SUCCESS)
		clnt_perror("callcots");
	return((int)clnt_stat);
}

The following code example defines the receiving routines. Note that in the server, xdr_rcp() did all the work automatically.


Example 4–22 Remote Copy Server Routines

/*
 * The receiving routines
 */
#include <stdio.h>
#include <rpc/rpc.h
#include "rcp.h"
 
main()
{
	void  rcp_service();
	if (svc_create(rpc_service,RCPPROG,RCPVERS,"circuit_v") == 0) {
		fprintf(stderr, "svc_create: errpr\n");
		exit(1);
	}
	svc_run();                    /* never returns */
	fprintf(stderr, "svc_run should never return\n");
}
 
void
rcp_service(rqstp, transp)
	register struct svc_req *rqstp;
	register SVCXPRT *transp;
{
	switch(rqstp->rq_proc) {
		case NULLPROC:
			if (svc_sendreply(transp, xdr_void, (caddr_t) NULL) == FALSE)
				fprintf(stderr, "err: rcp_service");
			return;
		case RCPPROC:
			if (!svc_getargs( transp, xdr_rcp, stdout)) {
				svcerr_decode(transp);
				return();
			}
			if(!svc_sendreply(transp, xdr_void, (caddr_t) NULL)) {
				fprintf(stderr, "can't reply\n");
				return();
			}
			return();
		default:
			svcerr_noproc(transp);
			return();
	}
}