⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rpc.prog.ms

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 MS
📖 第 1 页 / 共 5 页
字号:
.sp.IP "\fIServer Side\fP".LPThe server side is a lot simpler than the client side.  Here is theprevious example rewritten to use.I AUTH_DESinstead of.I AUTH_UNIX :.ie t .DS.el .DS L.ft CW.vs 11#include <sys/time.h>#include <rpc/auth_des.h>	. . .	. . .nuser(rqstp, transp)	struct svc_req *rqstp;	SVCXPRT *transp;{	struct authdes_cred *des_cred;	int uid;	int gid;	int gidlen;	int gidlist[10];.ft I	/*	 * we don't care about authentication for null proc	 */.ft CW	if (rqstp->rq_proc == NULLPROC) { 		/* \fIsame as before\fP */	}.ft I	/*	 * now get the uid	 */.ft CW	switch (rqstp->rq_cred.oa_flavor) {	case AUTH_DES:		des_cred =			(struct authdes_cred *) rqstp->rq_clntcred;		if (! netname2user(des_cred->adc_fullname.name,			&uid, &gid, &gidlen, gidlist))		{			fprintf(stderr, "unknown user: %s\n",				des_cred->adc_fullname.name);			svcerr_systemerr(transp);			return;		}		break;	case AUTH_NULL:	default:		svcerr_weakauth(transp);		return;	}.ft I	/*	 * The rest is the same as before 	 */	.ft CW.vs.DENote the use of the routine.I netname2user (),the inverse of.I user2netname ():it takes a network ID and converts to a unix ID..I netname2user () also supplies the group IDs which we don't use in this example,but which may be useful to other UNIX programs..NH 2\&Using Inetd.IX inetd "" "using \fIinetd\fP".LPAn RPC server can be started from.I inetdThe only difference from the usual code is that the servicecreation routine should be called in the following form:.ie t .DS.el .DS L.ft CWtransp = svcudp_create(0);     /* \fIFor UDP\fP */transp = svctcp_create(0,0,0); /* \fIFor listener TCP sockets\fP */transp = svcfd_create(0,0,0);  /* \fIFor connected TCP sockets\fP */.DEsince.I inetpasses a socket as file descriptor 0.Also,.I svc_register()should be called as.ie t .DS.el .DS L.ft CWsvc_register(transp, PROGNUM, VERSNUM, service, 0);.DEwith the final flag as 0,since the program would already be registered by.I inetdRemember that if you want to exitfrom the server process and return control to.I inetyou need to explicitly exit, since.I svc_run()never returns..LPThe format of entries in .I /etc/inetd.conf for RPC services is in one of the following two forms:.ie t .DS.el .DS L.ft CWp_name/version dgram  rpc/udp wait/nowait user server argsp_name/version stream rpc/tcp wait/nowait user server args.DEwhere.I p_nameis the symbolic name of the program as it appears in.I rpc(5) ,.I serveris the program implementing the server,and.I programand.I versionare the program and version numbers of the service.For more information, see.I inetd.conf(5) ..LPIf the same program handles multiple versions,then the version number can be a range,as in this example:.ie t .DS.el .DS L.ft CWrstatd/1-2 dgram rpc/udp wait root /usr/etc/rpc.rstatd.DE.NH 1\&More Examples.sp 1.NH 2\&Versions.IX "versions".IX "RPC" "versions".LPBy convention, the first version number of program.I PROGis.I PROGVERS_ORIGand the most recent version is.I PROGVERSSuppose there is a new version of the.I userprogram that returns an.I "unsigned short"rather than a.I long .If we name this version.I RUSERSVERS_SHORTthen a server that wants to support both versionswould do a double register..ie t .DS.el .DS L.ft CWif (!svc_register(transp, RUSERSPROG, RUSERSVERS_ORIG,  nuser, IPPROTO_TCP)) {	fprintf(stderr, "can't register RUSER service\en");	exit(1);}if (!svc_register(transp, RUSERSPROG, RUSERSVERS_SHORT,  nuser, IPPROTO_TCP)) {	fprintf(stderr, "can't register RUSER service\en");	exit(1);}.DEBoth versions can be handled by the same C procedure:.ie t .DS.el .DS L.ft CW.vs 11nuser(rqstp, transp)	struct svc_req *rqstp;	SVCXPRT *transp;{	unsigned long nusers;	unsigned short nusers2;	switch (rqstp->rq_proc) {	case NULLPROC:		if (!svc_sendreply(transp, xdr_void, 0)) {			fprintf(stderr, "can't reply to RPC call\en");            return (1);		}		return;	case RUSERSPROC_NUM:.ft I		/*         * Code here to compute the number of users         * and assign it to the variable \fInusers\fP		 */.ft CW		nusers2 = nusers;		switch (rqstp->rq_vers) {		case RUSERSVERS_ORIG:            if (!svc_sendreply(transp, xdr_u_long, 		    &nusers)) {                fprintf(stderr,"can't reply to RPC call\en");			}			break;		case RUSERSVERS_SHORT:            if (!svc_sendreply(transp, xdr_u_short, 		    &nusers2)) {                fprintf(stderr,"can't reply to RPC call\en");			}			break;		}	default:		svcerr_noproc(transp);		return;	}}.vs.DE.KS.NH 2\&TCP.IX "TCP".LPHere is an example that is essentially.I rcp.The initiator of the RPC.I sndcall takes its standard input and sends it to the server.I rcvwhich prints it on standard output.The RPC call uses TCP.This also illustrates an XDR procedure that behaves differentlyon serialization than on deserialization..ie t .DS.el .DS L.vs 11.ft I/* * The xdr routine: *		on decode, read from wire, write onto fp *		on encode, read from fp, write onto wire */.ft CW#include <stdio.h>#include <rpc/rpc.h>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 1;	while (1) {		if (xdrs->x_op == XDR_ENCODE) {			if ((size = fread(buf, sizeof(char), BUFSIZ,			  fp)) == 0 && ferror(fp)) {				fprintf(stderr, "can't fread\en");				return (1);			}		}		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\en");				return (1);			}		}	}}.vs.DE.KE.ie t .DS.el .DS L.vs 11.ft I/* * The sender routines */.ft CW#include <stdio.h>#include <netdb.h>#include <rpc/rpc.h>#include <sys/socket.h>#include <sys/time.h>main(argc, argv)	int argc;	char **argv;{	int xdr_rcp();	int err;	if (argc < 2) {		fprintf(stderr, "usage: %s servername\en", argv[0]);		exit(-1);	}	if ((err = callrpctcp(argv[1], RCPPROG, RCPPROC,	  RCPVERS, xdr_rcp, stdin, xdr_void, 0) != 0)) {		clnt_perrno(err);		fprintf(stderr, "can't make RPC call\en");		exit(1);	}	exit(0);}callrpctcp(host, prognum, procnum, versnum,           inproc, in, outproc, out)	char *host, *in, *out;	xdrproc_t inproc, outproc;{	struct sockaddr_in server_addr;	int socket = RPC_ANYSOCK;	enum clnt_stat clnt_stat;	struct hostent *hp;	register CLIENT *client;	struct timeval total_timeout;	if ((hp = gethostbyname(host)) == NULL) {		fprintf(stderr, "can't get addr for '%s'\en", host);		return (-1);	}	bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,		hp->h_length);	server_addr.sin_family = AF_INET;	server_addr.sin_port =  0;	if ((client = clnttcp_create(&server_addr, prognum,	  versnum, &socket, BUFSIZ, BUFSIZ)) == NULL) {		perror("rpctcp_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);	return (int)clnt_stat;}.vs.DE.ie t .DS.el .DS L.vs 11.ft I/* * The receiving routines */.ft CW#include <stdio.h>#include <rpc/rpc.h>main(){	register SVCXPRT *transp;     int rcp_service(), xdr_rcp(); 	if ((transp = svctcp_create(RPC_ANYSOCK,	  BUFSIZ, BUFSIZ)) == NULL) {		fprintf("svctcp_create: error\en");		exit(1);	}	pmap_unset(RCPPROG, RCPVERS);	if (!svc_register(transp,	  RCPPROG, RCPVERS, rcp_service, IPPROTO_TCP)) {		fprintf(stderr, "svc_register: error\en");		exit(1);	}	svc_run();  /* \fInever returns\fP */	fprintf(stderr, "svc_run should never return\en");}rcp_service(rqstp, transp)	register struct svc_req *rqstp;	register SVCXPRT *transp;{	switch (rqstp->rq_proc) {	case NULLPROC:		if (svc_sendreply(transp, xdr_void, 0) == 0) {			fprintf(stderr, "err: rcp_service");			return (1);		}		return;	case RCPPROC_FP:		if (!svc_getargs(transp, xdr_rcp, stdout)) {			svcerr_decode(transp);			return;		}		if (!svc_sendreply(transp, xdr_void, 0)) {			fprintf(stderr, "can't reply\en");			return;		}		return (0);	default:		svcerr_noproc(transp);		return;	}}.vs.DE.NH 2\&Callback Procedures.IX RPC "callback procedures".LPOccasionally, it is useful to have a server become a client,and make an RPC call back to the process which is its client.An example is remote debugging,where the client is a window system program,and the server is a debugger running on the remote machine.Most of the time,the user clicks a mouse button at the debugging window,which converts this to a debugger command,and then makes an RPC call to the server(where the debugger is actually running),telling it to execute that command.However, when the debugger hits a breakpoint, the roles are reversed,and the debugger wants to make an rpc call to the window program,so that it can inform the user that a breakpoint has been reached..LPIn order to do an RPC callback,you need a program number to make the RPC call on.Since this will be a dynamically generated program number,it should be in the transient range,.I "0x40000000 - 0x5fffffff" .The routine.I gettransient()returns a valid program number in the transient range,and registers it with the portmapper.It only talks to the portmapper running on the same machine as the.I gettransient()routine itself.  The call to.I pmap_set()is a test and set operation,in that it indivisibly tests whether a program numberhas already been registered,and if it has not, then reserves it.  On return, the.I sockpargument will contain a socket that can be usedas the argument to an.I svcudp_create()or.I svctcp_create()call..ie t .DS.el .DS L.ft CW.vs 11#include <stdio.h>#include <rpc/rpc.h>#include <sys/socket.h>gettransient(proto, vers, sockp)	int proto, vers, *sockp;{	static int prognum = 0x40000000;	int s, len, socktype;	struct sockaddr_in addr;	switch(proto) {		case IPPROTO_UDP:			socktype = SOCK_DGRAM;			break;		case IPPROTO_TCP:			socktype = SOCK_STREAM;			break;		default:			fprintf(stderr, "unknown protocol type\en");			return 0;	}	if (*sockp == RPC_ANYSOCK) {		if ((s = socket(AF_INET, socktype, 0)) < 0) {			perror("socket");			return (0);		}		*sockp = s;	}	else		s = *sockp;	addr.sin_addr.s_addr = 0;	addr.sin_family = AF_INET;	addr.sin_port = 0;	len = sizeof(addr);.ft I	/*	 * may be already bound, so don't check for error	 */.ft CW	bind(s, &addr, len)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -