xref: /csrg-svn/lib/librpc/rpc/pmap_rmt.c (revision 45129)
1*45129Smckusick /* @(#)pmap_rmt.c	2.2 88/08/01 4.0 RPCSRC */
2*45129Smckusick /*
3*45129Smckusick  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
4*45129Smckusick  * unrestricted use provided that this legend is included on all tape
5*45129Smckusick  * media and as a part of the software program in whole or part.  Users
6*45129Smckusick  * may copy or modify Sun RPC without charge, but are not authorized
7*45129Smckusick  * to license or distribute it to anyone else except as part of a product or
8*45129Smckusick  * program developed by the user.
9*45129Smckusick  *
10*45129Smckusick  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
11*45129Smckusick  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
12*45129Smckusick  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13*45129Smckusick  *
14*45129Smckusick  * Sun RPC is provided with no support and without any obligation on the
15*45129Smckusick  * part of Sun Microsystems, Inc. to assist in its use, correction,
16*45129Smckusick  * modification or enhancement.
17*45129Smckusick  *
18*45129Smckusick  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
19*45129Smckusick  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
20*45129Smckusick  * OR ANY PART THEREOF.
21*45129Smckusick  *
22*45129Smckusick  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
23*45129Smckusick  * or profits or other special, indirect and consequential damages, even if
24*45129Smckusick  * Sun has been advised of the possibility of such damages.
25*45129Smckusick  *
26*45129Smckusick  * Sun Microsystems, Inc.
27*45129Smckusick  * 2550 Garcia Avenue
28*45129Smckusick  * Mountain View, California  94043
29*45129Smckusick  */
30*45129Smckusick #if !defined(lint) && defined(SCCSIDS)
31*45129Smckusick static char sccsid[] = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";
32*45129Smckusick #endif
33*45129Smckusick 
34*45129Smckusick /*
35*45129Smckusick  * pmap_rmt.c
36*45129Smckusick  * Client interface to pmap rpc service.
37*45129Smckusick  * remote call and broadcast service
38*45129Smckusick  *
39*45129Smckusick  * Copyright (C) 1984, Sun Microsystems, Inc.
40*45129Smckusick  */
41*45129Smckusick 
42*45129Smckusick #include <rpc/rpc.h>
43*45129Smckusick #include <rpc/pmap_prot.h>
44*45129Smckusick #include <rpc/pmap_clnt.h>
45*45129Smckusick #include <rpc/pmap_rmt.h>
46*45129Smckusick #include <sys/socket.h>
47*45129Smckusick #include <stdio.h>
48*45129Smckusick #include <errno.h>
49*45129Smckusick #include <net/if.h>
50*45129Smckusick #include <sys/ioctl.h>
51*45129Smckusick #include <arpa/inet.h>
52*45129Smckusick #define MAX_BROADCAST_SIZE 1400
53*45129Smckusick 
54*45129Smckusick extern int errno;
55*45129Smckusick static struct timeval timeout = { 3, 0 };
56*45129Smckusick 
57*45129Smckusick 
58*45129Smckusick /*
59*45129Smckusick  * pmapper remote-call-service interface.
60*45129Smckusick  * This routine is used to call the pmapper remote call service
61*45129Smckusick  * which will look up a service program in the port maps, and then
62*45129Smckusick  * remotely call that routine with the given parameters.  This allows
63*45129Smckusick  * programs to do a lookup and call in one step.
64*45129Smckusick */
65*45129Smckusick enum clnt_stat
66*45129Smckusick pmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr)
67*45129Smckusick 	struct sockaddr_in *addr;
68*45129Smckusick 	u_long prog, vers, proc;
69*45129Smckusick 	xdrproc_t xdrargs, xdrres;
70*45129Smckusick 	caddr_t argsp, resp;
71*45129Smckusick 	struct timeval tout;
72*45129Smckusick 	u_long *port_ptr;
73*45129Smckusick {
74*45129Smckusick 	int socket = -1;
75*45129Smckusick 	register CLIENT *client;
76*45129Smckusick 	struct rmtcallargs a;
77*45129Smckusick 	struct rmtcallres r;
78*45129Smckusick 	enum clnt_stat stat;
79*45129Smckusick 
80*45129Smckusick 	addr->sin_port = htons(PMAPPORT);
81*45129Smckusick 	client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &socket);
82*45129Smckusick 	if (client != (CLIENT *)NULL) {
83*45129Smckusick 		a.prog = prog;
84*45129Smckusick 		a.vers = vers;
85*45129Smckusick 		a.proc = proc;
86*45129Smckusick 		a.args_ptr = argsp;
87*45129Smckusick 		a.xdr_args = xdrargs;
88*45129Smckusick 		r.port_ptr = port_ptr;
89*45129Smckusick 		r.results_ptr = resp;
90*45129Smckusick 		r.xdr_results = xdrres;
91*45129Smckusick 		stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a,
92*45129Smckusick 		    xdr_rmtcallres, &r, tout);
93*45129Smckusick 		CLNT_DESTROY(client);
94*45129Smckusick 	} else {
95*45129Smckusick 		stat = RPC_FAILED;
96*45129Smckusick 	}
97*45129Smckusick 	(void)close(socket);
98*45129Smckusick 	addr->sin_port = 0;
99*45129Smckusick 	return (stat);
100*45129Smckusick }
101*45129Smckusick 
102*45129Smckusick 
103*45129Smckusick /*
104*45129Smckusick  * XDR remote call arguments
105*45129Smckusick  * written for XDR_ENCODE direction only
106*45129Smckusick  */
107*45129Smckusick bool_t
108*45129Smckusick xdr_rmtcall_args(xdrs, cap)
109*45129Smckusick 	register XDR *xdrs;
110*45129Smckusick 	register struct rmtcallargs *cap;
111*45129Smckusick {
112*45129Smckusick 	u_int lenposition, argposition, position;
113*45129Smckusick 
114*45129Smckusick 	if (xdr_u_long(xdrs, &(cap->prog)) &&
115*45129Smckusick 	    xdr_u_long(xdrs, &(cap->vers)) &&
116*45129Smckusick 	    xdr_u_long(xdrs, &(cap->proc))) {
117*45129Smckusick 		lenposition = XDR_GETPOS(xdrs);
118*45129Smckusick 		if (! xdr_u_long(xdrs, &(cap->arglen)))
119*45129Smckusick 		    return (FALSE);
120*45129Smckusick 		argposition = XDR_GETPOS(xdrs);
121*45129Smckusick 		if (! (*(cap->xdr_args))(xdrs, cap->args_ptr))
122*45129Smckusick 		    return (FALSE);
123*45129Smckusick 		position = XDR_GETPOS(xdrs);
124*45129Smckusick 		cap->arglen = (u_long)position - (u_long)argposition;
125*45129Smckusick 		XDR_SETPOS(xdrs, lenposition);
126*45129Smckusick 		if (! xdr_u_long(xdrs, &(cap->arglen)))
127*45129Smckusick 		    return (FALSE);
128*45129Smckusick 		XDR_SETPOS(xdrs, position);
129*45129Smckusick 		return (TRUE);
130*45129Smckusick 	}
131*45129Smckusick 	return (FALSE);
132*45129Smckusick }
133*45129Smckusick 
134*45129Smckusick /*
135*45129Smckusick  * XDR remote call results
136*45129Smckusick  * written for XDR_DECODE direction only
137*45129Smckusick  */
138*45129Smckusick bool_t
139*45129Smckusick xdr_rmtcallres(xdrs, crp)
140*45129Smckusick 	register XDR *xdrs;
141*45129Smckusick 	register struct rmtcallres *crp;
142*45129Smckusick {
143*45129Smckusick 	caddr_t port_ptr;
144*45129Smckusick 
145*45129Smckusick 	port_ptr = (caddr_t)crp->port_ptr;
146*45129Smckusick 	if (xdr_reference(xdrs, &port_ptr, sizeof (u_long),
147*45129Smckusick 	    xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) {
148*45129Smckusick 		crp->port_ptr = (u_long *)port_ptr;
149*45129Smckusick 		return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
150*45129Smckusick 	}
151*45129Smckusick 	return (FALSE);
152*45129Smckusick }
153*45129Smckusick 
154*45129Smckusick 
155*45129Smckusick /*
156*45129Smckusick  * The following is kludged-up support for simple rpc broadcasts.
157*45129Smckusick  * Someday a large, complicated system will replace these trivial
158*45129Smckusick  * routines which only support udp/ip .
159*45129Smckusick  */
160*45129Smckusick 
161*45129Smckusick static int
162*45129Smckusick getbroadcastnets(addrs, sock, buf)
163*45129Smckusick 	struct in_addr *addrs;
164*45129Smckusick 	int sock;  /* any valid socket will do */
165*45129Smckusick 	char *buf;  /* why allocxate more when we can use existing... */
166*45129Smckusick {
167*45129Smckusick 	struct ifconf ifc;
168*45129Smckusick         struct ifreq ifreq, *ifr;
169*45129Smckusick 	struct sockaddr_in *sin;
170*45129Smckusick         int n, i;
171*45129Smckusick 
172*45129Smckusick         ifc.ifc_len = UDPMSGSIZE;
173*45129Smckusick         ifc.ifc_buf = buf;
174*45129Smckusick         if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
175*45129Smckusick                 perror("broadcast: ioctl (get interface configuration)");
176*45129Smckusick                 return (0);
177*45129Smckusick         }
178*45129Smckusick         ifr = ifc.ifc_req;
179*45129Smckusick         for (i = 0, n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) {
180*45129Smckusick                 ifreq = *ifr;
181*45129Smckusick                 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
182*45129Smckusick                         perror("broadcast: ioctl (get interface flags)");
183*45129Smckusick                         continue;
184*45129Smckusick                 }
185*45129Smckusick                 if ((ifreq.ifr_flags & IFF_BROADCAST) &&
186*45129Smckusick 		    (ifreq.ifr_flags & IFF_UP) &&
187*45129Smckusick 		    ifr->ifr_addr.sa_family == AF_INET) {
188*45129Smckusick 			sin = (struct sockaddr_in *)&ifr->ifr_addr;
189*45129Smckusick #ifdef SIOCGIFBRDADDR   /* 4.3BSD */
190*45129Smckusick 			if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
191*45129Smckusick 				addrs[i++] = inet_makeaddr(inet_netof
192*45129Smckusick 			    (sin->sin_addr.s_addr), INADDR_ANY);
193*45129Smckusick 			} else {
194*45129Smckusick 				addrs[i++] = ((struct sockaddr_in*)
195*45129Smckusick 				  &ifreq.ifr_addr)->sin_addr;
196*45129Smckusick 			}
197*45129Smckusick #else /* 4.2 BSD */
198*45129Smckusick 			addrs[i++] = inet_makeaddr(inet_netof
199*45129Smckusick 			  (sin->sin_addr.s_addr), INADDR_ANY);
200*45129Smckusick #endif
201*45129Smckusick 		}
202*45129Smckusick 	}
203*45129Smckusick 	return (i);
204*45129Smckusick }
205*45129Smckusick 
206*45129Smckusick typedef bool_t (*resultproc_t)();
207*45129Smckusick 
208*45129Smckusick enum clnt_stat
209*45129Smckusick clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult)
210*45129Smckusick 	u_long		prog;		/* program number */
211*45129Smckusick 	u_long		vers;		/* version number */
212*45129Smckusick 	u_long		proc;		/* procedure number */
213*45129Smckusick 	xdrproc_t	xargs;		/* xdr routine for args */
214*45129Smckusick 	caddr_t		argsp;		/* pointer to args */
215*45129Smckusick 	xdrproc_t	xresults;	/* xdr routine for results */
216*45129Smckusick 	caddr_t		resultsp;	/* pointer to results */
217*45129Smckusick 	resultproc_t	eachresult;	/* call with each result obtained */
218*45129Smckusick {
219*45129Smckusick 	enum clnt_stat stat;
220*45129Smckusick 	AUTH *unix_auth = authunix_create_default();
221*45129Smckusick 	XDR xdr_stream;
222*45129Smckusick 	register XDR *xdrs = &xdr_stream;
223*45129Smckusick 	int outlen, inlen, fromlen, nets;
224*45129Smckusick 	register int sock;
225*45129Smckusick 	int on = 1;
226*45129Smckusick #ifdef FD_SETSIZE
227*45129Smckusick 	fd_set mask;
228*45129Smckusick 	fd_set readfds;
229*45129Smckusick #else
230*45129Smckusick 	int readfds;
231*45129Smckusick 	register int mask;
232*45129Smckusick #endif /* def FD_SETSIZE */
233*45129Smckusick 	register int i;
234*45129Smckusick 	bool_t done = FALSE;
235*45129Smckusick 	register u_long xid;
236*45129Smckusick 	u_long port;
237*45129Smckusick 	struct in_addr addrs[20];
238*45129Smckusick 	struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
239*45129Smckusick 	struct rmtcallargs a;
240*45129Smckusick 	struct rmtcallres r;
241*45129Smckusick 	struct rpc_msg msg;
242*45129Smckusick 	struct timeval t;
243*45129Smckusick 	char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];
244*45129Smckusick 
245*45129Smckusick 	/*
246*45129Smckusick 	 * initialization: create a socket, a broadcast address, and
247*45129Smckusick 	 * preserialize the arguments into a send buffer.
248*45129Smckusick 	 */
249*45129Smckusick 	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
250*45129Smckusick 		perror("Cannot create socket for broadcast rpc");
251*45129Smckusick 		stat = RPC_CANTSEND;
252*45129Smckusick 		goto done_broad;
253*45129Smckusick 	}
254*45129Smckusick #ifdef SO_BROADCAST
255*45129Smckusick 	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
256*45129Smckusick 		perror("Cannot set socket option SO_BROADCAST");
257*45129Smckusick 		stat = RPC_CANTSEND;
258*45129Smckusick 		goto done_broad;
259*45129Smckusick 	}
260*45129Smckusick #endif /* def SO_BROADCAST */
261*45129Smckusick #ifdef FD_SETSIZE
262*45129Smckusick 	FD_ZERO(&mask);
263*45129Smckusick 	FD_SET(sock, &mask);
264*45129Smckusick #else
265*45129Smckusick 	mask = (1 << sock);
266*45129Smckusick #endif /* def FD_SETSIZE */
267*45129Smckusick 	nets = getbroadcastnets(addrs, sock, inbuf);
268*45129Smckusick 	bzero((char *)&baddr, sizeof (baddr));
269*45129Smckusick 	baddr.sin_family = AF_INET;
270*45129Smckusick 	baddr.sin_port = htons(PMAPPORT);
271*45129Smckusick 	baddr.sin_addr.s_addr = htonl(INADDR_ANY);
272*45129Smckusick /*	baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */
273*45129Smckusick 	(void)gettimeofday(&t, (struct timezone *)0);
274*45129Smckusick 	msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec;
275*45129Smckusick 	t.tv_usec = 0;
276*45129Smckusick 	msg.rm_direction = CALL;
277*45129Smckusick 	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
278*45129Smckusick 	msg.rm_call.cb_prog = PMAPPROG;
279*45129Smckusick 	msg.rm_call.cb_vers = PMAPVERS;
280*45129Smckusick 	msg.rm_call.cb_proc = PMAPPROC_CALLIT;
281*45129Smckusick 	msg.rm_call.cb_cred = unix_auth->ah_cred;
282*45129Smckusick 	msg.rm_call.cb_verf = unix_auth->ah_verf;
283*45129Smckusick 	a.prog = prog;
284*45129Smckusick 	a.vers = vers;
285*45129Smckusick 	a.proc = proc;
286*45129Smckusick 	a.xdr_args = xargs;
287*45129Smckusick 	a.args_ptr = argsp;
288*45129Smckusick 	r.port_ptr = &port;
289*45129Smckusick 	r.xdr_results = xresults;
290*45129Smckusick 	r.results_ptr = resultsp;
291*45129Smckusick 	xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
292*45129Smckusick 	if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) {
293*45129Smckusick 		stat = RPC_CANTENCODEARGS;
294*45129Smckusick 		goto done_broad;
295*45129Smckusick 	}
296*45129Smckusick 	outlen = (int)xdr_getpos(xdrs);
297*45129Smckusick 	xdr_destroy(xdrs);
298*45129Smckusick 	/*
299*45129Smckusick 	 * Basic loop: broadcast a packet and wait a while for response(s).
300*45129Smckusick 	 * The response timeout grows larger per iteration.
301*45129Smckusick 	 */
302*45129Smckusick 	for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) {
303*45129Smckusick 		for (i = 0; i < nets; i++) {
304*45129Smckusick 			baddr.sin_addr = addrs[i];
305*45129Smckusick 			if (sendto(sock, outbuf, outlen, 0,
306*45129Smckusick 				(struct sockaddr *)&baddr,
307*45129Smckusick 				sizeof (struct sockaddr)) != outlen) {
308*45129Smckusick 				perror("Cannot send broadcast packet");
309*45129Smckusick 				stat = RPC_CANTSEND;
310*45129Smckusick 				goto done_broad;
311*45129Smckusick 			}
312*45129Smckusick 		}
313*45129Smckusick 		if (eachresult == NULL) {
314*45129Smckusick 			stat = RPC_SUCCESS;
315*45129Smckusick 			goto done_broad;
316*45129Smckusick 		}
317*45129Smckusick 	recv_again:
318*45129Smckusick 		msg.acpted_rply.ar_verf = _null_auth;
319*45129Smckusick 		msg.acpted_rply.ar_results.where = (caddr_t)&r;
320*45129Smckusick                 msg.acpted_rply.ar_results.proc = xdr_rmtcallres;
321*45129Smckusick 		readfds = mask;
322*45129Smckusick 		switch (select(_rpc_dtablesize(), &readfds, (int *)NULL,
323*45129Smckusick 			       (int *)NULL, &t)) {
324*45129Smckusick 
325*45129Smckusick 		case 0:  /* timed out */
326*45129Smckusick 			stat = RPC_TIMEDOUT;
327*45129Smckusick 			continue;
328*45129Smckusick 
329*45129Smckusick 		case -1:  /* some kind of error */
330*45129Smckusick 			if (errno == EINTR)
331*45129Smckusick 				goto recv_again;
332*45129Smckusick 			perror("Broadcast select problem");
333*45129Smckusick 			stat = RPC_CANTRECV;
334*45129Smckusick 			goto done_broad;
335*45129Smckusick 
336*45129Smckusick 		}  /* end of select results switch */
337*45129Smckusick 	try_again:
338*45129Smckusick 		fromlen = sizeof(struct sockaddr);
339*45129Smckusick 		inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0,
340*45129Smckusick 			(struct sockaddr *)&raddr, &fromlen);
341*45129Smckusick 		if (inlen < 0) {
342*45129Smckusick 			if (errno == EINTR)
343*45129Smckusick 				goto try_again;
344*45129Smckusick 			perror("Cannot receive reply to broadcast");
345*45129Smckusick 			stat = RPC_CANTRECV;
346*45129Smckusick 			goto done_broad;
347*45129Smckusick 		}
348*45129Smckusick 		if (inlen < sizeof(u_long))
349*45129Smckusick 			goto recv_again;
350*45129Smckusick 		/*
351*45129Smckusick 		 * see if reply transaction id matches sent id.
352*45129Smckusick 		 * If so, decode the results.
353*45129Smckusick 		 */
354*45129Smckusick 		xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE);
355*45129Smckusick 		if (xdr_replymsg(xdrs, &msg)) {
356*45129Smckusick 			if ((msg.rm_xid == xid) &&
357*45129Smckusick 				(msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
358*45129Smckusick 				(msg.acpted_rply.ar_stat == SUCCESS)) {
359*45129Smckusick 				raddr.sin_port = htons((u_short)port);
360*45129Smckusick 				done = (*eachresult)(resultsp, &raddr);
361*45129Smckusick 			}
362*45129Smckusick 			/* otherwise, we just ignore the errors ... */
363*45129Smckusick 		} else {
364*45129Smckusick #ifdef notdef
365*45129Smckusick 			/* some kind of deserialization problem ... */
366*45129Smckusick 			if (msg.rm_xid == xid)
367*45129Smckusick 				fprintf(stderr, "Broadcast deserialization problem");
368*45129Smckusick 			/* otherwise, just random garbage */
369*45129Smckusick #endif
370*45129Smckusick 		}
371*45129Smckusick 		xdrs->x_op = XDR_FREE;
372*45129Smckusick 		msg.acpted_rply.ar_results.proc = xdr_void;
373*45129Smckusick 		(void)xdr_replymsg(xdrs, &msg);
374*45129Smckusick 		(void)(*xresults)(xdrs, resultsp);
375*45129Smckusick 		xdr_destroy(xdrs);
376*45129Smckusick 		if (done) {
377*45129Smckusick 			stat = RPC_SUCCESS;
378*45129Smckusick 			goto done_broad;
379*45129Smckusick 		} else {
380*45129Smckusick 			goto recv_again;
381*45129Smckusick 		}
382*45129Smckusick 	}
383*45129Smckusick done_broad:
384*45129Smckusick 	(void)close(sock);
385*45129Smckusick 	AUTH_DESTROY(unix_auth);
386*45129Smckusick 	return (stat);
387*45129Smckusick }
388*45129Smckusick 
389