]>
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> | |
4360eafd | 44 | #include <libintl.h> |
28f540f4 RM |
45 | #include <rpc/rpc.h> |
46 | #include <rpc/pmap_prot.h> | |
47 | #include <rpc/pmap_clnt.h> | |
48 | #include <rpc/pmap_rmt.h> | |
099a6fbd | 49 | #include <sys/poll.h> |
28f540f4 RM |
50 | #include <sys/socket.h> |
51 | #include <stdio.h> | |
52 | #include <errno.h> | |
53 | #undef _POSIX_SOURCE /* Ultrix <sys/param.h> needs --roland@gnu */ | |
54 | #include <sys/param.h> /* Ultrix needs before net/if --roland@gnu */ | |
55 | #include <net/if.h> | |
56 | #include <sys/ioctl.h> | |
57 | #include <arpa/inet.h> | |
58 | #define MAX_BROADCAST_SIZE 1400 | |
59 | ||
090ca000 UD |
60 | extern u_long _create_xid (void); |
61 | ||
c4563d2d | 62 | static const struct timeval timeout = {3, 0}; |
28f540f4 RM |
63 | |
64 | /* | |
65 | * pmapper remote-call-service interface. | |
66 | * This routine is used to call the pmapper remote call service | |
67 | * which will look up a service program in the port maps, and then | |
68 | * remotely call that routine with the given parameters. This allows | |
69 | * programs to do a lookup and call in one step. | |
e7fd8a39 | 70 | */ |
28f540f4 | 71 | enum clnt_stat |
e7fd8a39 UD |
72 | pmap_rmtcall (addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr) |
73 | struct sockaddr_in *addr; | |
74 | u_long prog, vers, proc; | |
75 | xdrproc_t xdrargs, xdrres; | |
76 | caddr_t argsp, resp; | |
77 | struct timeval tout; | |
78 | u_long *port_ptr; | |
28f540f4 | 79 | { |
e7fd8a39 UD |
80 | int socket = -1; |
81 | CLIENT *client; | |
82 | struct rmtcallargs a; | |
83 | struct rmtcallres r; | |
84 | enum clnt_stat stat; | |
28f540f4 | 85 | |
e7fd8a39 UD |
86 | addr->sin_port = htons (PMAPPORT); |
87 | client = clntudp_create (addr, PMAPPROG, PMAPVERS, timeout, &socket); | |
88 | if (client != (CLIENT *) NULL) | |
89 | { | |
90 | a.prog = prog; | |
91 | a.vers = vers; | |
92 | a.proc = proc; | |
93 | a.args_ptr = argsp; | |
94 | a.xdr_args = xdrargs; | |
95 | r.port_ptr = port_ptr; | |
96 | r.results_ptr = resp; | |
97 | r.xdr_results = xdrres; | |
98 | stat = CLNT_CALL (client, PMAPPROC_CALLIT, (xdrproc_t)xdr_rmtcall_args, | |
99 | (caddr_t)&a, (xdrproc_t)xdr_rmtcallres, | |
100 | (caddr_t)&r, tout); | |
101 | CLNT_DESTROY (client); | |
102 | } | |
103 | else | |
104 | { | |
105 | stat = RPC_FAILED; | |
106 | } | |
50304ef0 | 107 | /* (void)__close(socket); CLNT_DESTROY already closed it */ |
e7fd8a39 UD |
108 | addr->sin_port = 0; |
109 | return stat; | |
28f540f4 RM |
110 | } |
111 | ||
112 | ||
113 | /* | |
114 | * XDR remote call arguments | |
115 | * written for XDR_ENCODE direction only | |
116 | */ | |
117 | bool_t | |
090ca000 | 118 | xdr_rmtcall_args (XDR *xdrs, struct rmtcallargs *cap) |
28f540f4 | 119 | { |
e7fd8a39 | 120 | u_int lenposition, argposition, position; |
28f540f4 | 121 | |
e7fd8a39 UD |
122 | if (xdr_u_long (xdrs, &(cap->prog)) && |
123 | xdr_u_long (xdrs, &(cap->vers)) && | |
124 | xdr_u_long (xdrs, &(cap->proc))) | |
125 | { | |
126 | lenposition = XDR_GETPOS (xdrs); | |
127 | if (!xdr_u_long (xdrs, &(cap->arglen))) | |
128 | return FALSE; | |
129 | argposition = XDR_GETPOS (xdrs); | |
130 | if (!(*(cap->xdr_args)) (xdrs, cap->args_ptr)) | |
131 | return FALSE; | |
132 | position = XDR_GETPOS (xdrs); | |
133 | cap->arglen = (u_long) position - (u_long) argposition; | |
134 | XDR_SETPOS (xdrs, lenposition); | |
135 | if (!xdr_u_long (xdrs, &(cap->arglen))) | |
136 | return FALSE; | |
137 | XDR_SETPOS (xdrs, position); | |
138 | return TRUE; | |
139 | } | |
140 | return FALSE; | |
28f540f4 RM |
141 | } |
142 | ||
143 | /* | |
144 | * XDR remote call results | |
145 | * written for XDR_DECODE direction only | |
146 | */ | |
147 | bool_t | |
e7fd8a39 UD |
148 | xdr_rmtcallres (xdrs, crp) |
149 | XDR *xdrs; | |
150 | struct rmtcallres *crp; | |
28f540f4 | 151 | { |
e7fd8a39 | 152 | caddr_t port_ptr; |
28f540f4 | 153 | |
e7fd8a39 UD |
154 | port_ptr = (caddr_t) crp->port_ptr; |
155 | if (xdr_reference (xdrs, &port_ptr, sizeof (u_long), (xdrproc_t) xdr_u_long) | |
156 | && xdr_u_long (xdrs, &crp->resultslen)) | |
157 | { | |
158 | crp->port_ptr = (u_long *) port_ptr; | |
159 | return (*(crp->xdr_results)) (xdrs, crp->results_ptr); | |
160 | } | |
161 | return FALSE; | |
28f540f4 RM |
162 | } |
163 | ||
164 | ||
165 | /* | |
166 | * The following is kludged-up support for simple rpc broadcasts. | |
cbd3dceb | 167 | * Someday a large, complicated system will replace these trivial |
28f540f4 RM |
168 | * routines which only support udp/ip . |
169 | */ | |
170 | ||
171 | static int | |
dfd2257a | 172 | internal_function |
e7fd8a39 UD |
173 | getbroadcastnets (struct in_addr *addrs, int sock, char *buf) |
174 | /* int sock: any valid socket will do */ | |
175 | /* char *buf: why allocate more when we can use existing... */ | |
28f540f4 | 176 | { |
e7fd8a39 UD |
177 | struct ifconf ifc; |
178 | struct ifreq ifreq, *ifr; | |
179 | struct sockaddr_in *sin; | |
180 | int n, i; | |
28f540f4 | 181 | |
e7fd8a39 UD |
182 | ifc.ifc_len = UDPMSGSIZE; |
183 | ifc.ifc_buf = buf; | |
50304ef0 | 184 | if (__ioctl (sock, SIOCGIFCONF, (char *) &ifc) < 0) |
e7fd8a39 UD |
185 | { |
186 | perror (_("broadcast: ioctl (get interface configuration)")); | |
187 | return (0); | |
188 | } | |
189 | ifr = ifc.ifc_req; | |
190 | for (i = 0, n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) | |
191 | { | |
192 | ifreq = *ifr; | |
50304ef0 | 193 | if (__ioctl (sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) |
e7fd8a39 UD |
194 | { |
195 | perror (_("broadcast: ioctl (get interface flags)")); | |
196 | continue; | |
197 | } | |
198 | if ((ifreq.ifr_flags & IFF_BROADCAST) && | |
199 | (ifreq.ifr_flags & IFF_UP) && | |
200 | ifr->ifr_addr.sa_family == AF_INET) | |
201 | { | |
202 | sin = (struct sockaddr_in *) &ifr->ifr_addr; | |
203 | #ifdef SIOCGIFBRDADDR /* 4.3BSD */ | |
50304ef0 | 204 | if (__ioctl (sock, SIOCGIFBRDADDR, (char *) &ifreq) < 0) |
e7fd8a39 UD |
205 | { |
206 | addrs[i++] = inet_makeaddr (inet_netof | |
207 | /* Changed to pass struct instead of s_addr member | |
208 | by roland@gnu. */ | |
209 | (sin->sin_addr), INADDR_ANY); | |
210 | } | |
211 | else | |
212 | { | |
213 | addrs[i++] = ((struct sockaddr_in *) | |
214 | &ifreq.ifr_addr)->sin_addr; | |
215 | } | |
28f540f4 | 216 | #else /* 4.2 BSD */ |
e7fd8a39 UD |
217 | addrs[i++] = inet_makeaddr (inet_netof |
218 | (sin->sin_addr.s_addr), INADDR_ANY); | |
28f540f4 | 219 | #endif |
28f540f4 | 220 | } |
e7fd8a39 UD |
221 | } |
222 | return i; | |
28f540f4 RM |
223 | } |
224 | ||
28f540f4 | 225 | |
cbd3dceb | 226 | enum clnt_stat |
e7fd8a39 UD |
227 | clnt_broadcast (prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult) |
228 | u_long prog; /* program number */ | |
229 | u_long vers; /* version number */ | |
230 | u_long proc; /* procedure number */ | |
231 | xdrproc_t xargs; /* xdr routine for args */ | |
232 | caddr_t argsp; /* pointer to args */ | |
233 | xdrproc_t xresults; /* xdr routine for results */ | |
234 | caddr_t resultsp; /* pointer to results */ | |
235 | resultproc_t eachresult; /* call with each result obtained */ | |
28f540f4 | 236 | { |
a1129917 | 237 | enum clnt_stat stat = RPC_FAILED; |
e7fd8a39 UD |
238 | AUTH *unix_auth = authunix_create_default (); |
239 | XDR xdr_stream; | |
240 | XDR *xdrs = &xdr_stream; | |
090ca000 | 241 | struct timeval t; |
f671aeab | 242 | int outlen, inlen, nets; |
41df5ed4 | 243 | socklen_t fromlen; |
e7fd8a39 UD |
244 | int sock; |
245 | int on = 1; | |
099a6fbd UD |
246 | struct pollfd fd; |
247 | int milliseconds; | |
e7fd8a39 UD |
248 | int i; |
249 | bool_t done = FALSE; | |
250 | u_long xid; | |
251 | u_long port; | |
252 | struct in_addr addrs[20]; | |
253 | struct sockaddr_in baddr, raddr; /* broadcast and response addresses */ | |
254 | struct rmtcallargs a; | |
255 | struct rmtcallres r; | |
256 | struct rpc_msg msg; | |
e7fd8a39 | 257 | char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE]; |
28f540f4 | 258 | |
e7fd8a39 UD |
259 | /* |
260 | * initialization: create a socket, a broadcast address, and | |
261 | * preserialize the arguments into a send buffer. | |
262 | */ | |
50304ef0 | 263 | if ((sock = __socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) |
e7fd8a39 UD |
264 | { |
265 | perror (_("Cannot create socket for broadcast rpc")); | |
266 | stat = RPC_CANTSEND; | |
267 | goto done_broad; | |
268 | } | |
28f540f4 | 269 | #ifdef SO_BROADCAST |
e7fd8a39 UD |
270 | if (setsockopt (sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) |
271 | { | |
272 | perror (_("Cannot set socket option SO_BROADCAST")); | |
273 | stat = RPC_CANTSEND; | |
274 | goto done_broad; | |
275 | } | |
28f540f4 | 276 | #endif /* def SO_BROADCAST */ |
099a6fbd UD |
277 | fd.fd = sock; |
278 | fd.events = POLLIN; | |
e7fd8a39 | 279 | nets = getbroadcastnets (addrs, sock, inbuf); |
50304ef0 | 280 | __bzero ((char *) &baddr, sizeof (baddr)); |
e7fd8a39 UD |
281 | baddr.sin_family = AF_INET; |
282 | baddr.sin_port = htons (PMAPPORT); | |
283 | baddr.sin_addr.s_addr = htonl (INADDR_ANY); | |
284 | /* baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */ | |
090ca000 | 285 | msg.rm_xid = xid = _create_xid (); |
e7fd8a39 UD |
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 | { | |
5512461f | 374 | if (((u_int32_t) msg.rm_xid == (u_int32_t) xid) && |
e7fd8a39 UD |
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 | 386 | /* some kind of deserialization problem ... */ |
5512461f | 387 | if ((u_int32_t) msg.rm_xid == (u_int32_t) xid) |
e7fd8a39 UD |
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: |
50304ef0 | 408 | (void) __close (sock); |
e7fd8a39 UD |
409 | AUTH_DESTROY (unix_auth); |
410 | return stat; | |
28f540f4 | 411 | } |