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