1 /*********************************************************************
2 * RPC for the Windows NT Operating System
3 * 1993 by Martin F. Gergeleit
4 * Users may use, copy or modify Sun RPC for the Windows NT Operating
5 * System according to the Sun copyright below.
7 * RPC for the Windows NT Operating System COMES WITH ABSOLUTELY NO
8 * WARRANTY, NOR WILL I BE LIABLE FOR ANY DAMAGES INCURRED FROM THE
9 * USE OF. USE ENTIRELY AT YOUR OWN RISK!!!
10 *********************************************************************/
11 /* @(#)pmap_rmt.c 2.2 88/08/01 4.0 RPCSRC */
13 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
14 * unrestricted use provided that this legend is included on all tape
15 * media and as a part of the software program in whole or part. Users
16 * may copy or modify Sun RPC without charge, but are not authorized
17 * to license or distribute it to anyone else except as part of a product or
18 * program developed by the user.
20 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
21 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
24 * Sun RPC is provided with no support and without any obligation on the
25 * part of Sun Microsystems, Inc. to assist in its use, correction,
26 * modification or enhancement.
28 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
29 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
30 * OR ANY PART THEREOF.
32 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
33 * or profits or other special, indirect and consequential damages, even if
34 * Sun has been advised of the possibility of such damages.
36 * Sun Microsystems, Inc.
38 * Mountain View, California 94043
40 #if !defined(lint) && defined(SCCSIDS)
41 static char sccsid[] = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";
46 * Client interface to pmap rpc service.
47 * remote call and broadcast service
49 * Copyright (C) 1984, Sun Microsystems, Inc.
54 #include <rpc/pmap_prot.h>
55 #include <rpc/pmap_clnt.h>
56 #include <rpc/pmap_rmt.h>
59 #define MAX_BROADCAST_SIZE 1400
61 #include <rpc/pmap_prot.h>
62 #include <rpc/pmap_clnt.h>
63 #include <rpc/pmap_rmt.h>
64 #include <sys/socket.h>
68 #include <sys/ioctl.h>
69 #include <arpa/inet.h>
70 #define MAX_BROADCAST_SIZE 1400
73 #include <sys/sockio.h>
78 static struct timeval timeout = { 3, 0 };
82 * pmapper remote-call-service interface.
83 * This routine is used to call the pmapper remote call service
84 * which will look up a service program in the port maps, and then
85 * remotely call that routine with the given parameters. This allows
86 * programs to do a lookup and call in one step.
89 pmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr)
90 struct sockaddr_in *addr;
91 u_long prog, vers, proc;
92 xdrproc_t xdrargs, xdrres;
98 register CLIENT *client;
103 addr->sin_port = htons(PMAPPORT);
104 client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &socket);
105 if (client != (CLIENT *)NULL) {
110 a.xdr_args = xdrargs;
111 r.port_ptr = port_ptr;
112 r.results_ptr = resp;
113 r.xdr_results = xdrres;
114 stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a,
115 xdr_rmtcallres, &r, tout);
116 CLNT_DESTROY(client);
121 (void)closesocket(socket);
131 * XDR remote call arguments
132 * written for XDR_ENCODE direction only
135 xdr_rmtcall_args(xdrs, cap)
137 register struct rmtcallargs *cap;
139 u_int lenposition, argposition, position;
141 if (xdr_u_long(xdrs, &(cap->prog)) &&
142 xdr_u_long(xdrs, &(cap->vers)) &&
143 xdr_u_long(xdrs, &(cap->proc))) {
144 lenposition = XDR_GETPOS(xdrs);
145 if (! xdr_u_long(xdrs, &(cap->arglen)))
147 argposition = XDR_GETPOS(xdrs);
148 if (! (*(cap->xdr_args))(xdrs, cap->args_ptr))
150 position = XDR_GETPOS(xdrs);
151 cap->arglen = (u_long)position - (u_long)argposition;
152 XDR_SETPOS(xdrs, lenposition);
153 if (! xdr_u_long(xdrs, &(cap->arglen)))
155 XDR_SETPOS(xdrs, position);
162 * XDR remote call results
163 * written for XDR_DECODE direction only
166 xdr_rmtcallres(xdrs, crp)
168 register struct rmtcallres *crp;
172 port_ptr = (caddr_t)crp->port_ptr;
173 if (xdr_reference(xdrs, &port_ptr, sizeof (u_long),
174 xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) {
175 crp->port_ptr = (u_long *)port_ptr;
176 return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
183 * The following is kludged-up support for simple rpc broadcasts.
184 * Someday a large, complicated system will replace these trivial
185 * routines which only support udp/ip .
189 getbroadcastnets(addrs, sock, buf)
190 struct in_addr *addrs;
191 int sock; /* any valid socket will do */
192 char *buf; /* why allocxate more when we can use existing... */
195 /* try to do a global broadcast, this is not a clean solution */
196 addrs[0].s_addr = INADDR_BROADCAST;
199 /* was return 0 in version 1.04 */
203 struct ifreq ifreq, *ifr;
204 struct sockaddr_in *sin;
207 ifc.ifc_len = UDPMSGSIZE;
209 if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
210 perror("broadcast: ioctl (get interface configuration)");
214 for (i = 0, n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) {
216 if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
217 perror("broadcast: ioctl (get interface flags)");
220 if ((ifreq.ifr_flags & IFF_BROADCAST) &&
221 (ifreq.ifr_flags & IFF_UP) &&
222 ifr->ifr_addr.sa_family == AF_INET) {
223 sin = (struct sockaddr_in *)&ifr->ifr_addr;
224 #ifdef SIOCGIFBRDADDR /* 4.3BSD */
225 if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
226 addrs[i++] = inet_makeaddr(inet_netof
227 (sin->sin_addr), INADDR_ANY);
229 addrs[i++] = ((struct sockaddr_in*)
230 &ifreq.ifr_addr)->sin_addr;
233 addrs[i++] = inet_makeaddr(inet_netof
234 (sin->sin_addr.s_addr), INADDR_ANY);
242 typedef bool_t (*resultproc_t)();
245 clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult)
246 u_long prog; /* program number */
247 u_long vers; /* version number */
248 u_long proc; /* procedure number */
249 xdrproc_t xargs; /* xdr routine for args */
250 caddr_t argsp; /* pointer to args */
251 xdrproc_t xresults; /* xdr routine for results */
252 caddr_t resultsp; /* pointer to results */
253 resultproc_t eachresult; /* call with each result obtained */
256 AUTH *unix_auth = authunix_create_default();
258 register XDR *xdrs = &xdr_stream;
259 int outlen, inlen, fromlen, nets;
268 #endif /* def FD_SETSIZE */
273 struct in_addr addrs[20];
274 struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
275 struct rmtcallargs a;
279 char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];
282 * initialization: create a socket, a broadcast address, and
283 * preserialize the arguments into a send buffer.
286 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
288 if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
290 perror("Cannot create socket for broadcast rpc");
295 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
296 perror("Cannot set socket option SO_BROADCAST");
300 #endif /* def SO_BROADCAST */
306 #endif /* def FD_SETSIZE */
307 nets = getbroadcastnets(addrs, sock, inbuf);
308 bzero((char *)&baddr, sizeof (baddr));
309 baddr.sin_family = AF_INET;
310 baddr.sin_port = htons(PMAPPORT);
311 baddr.sin_addr.s_addr = htonl(INADDR_ANY);
312 /* baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */
313 (void)gettimeofday(&t, (struct timezone *)0);
314 msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec;
316 msg.rm_direction = CALL;
317 msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
318 msg.rm_call.cb_prog = PMAPPROG;
319 msg.rm_call.cb_vers = PMAPVERS;
320 msg.rm_call.cb_proc = PMAPPROC_CALLIT;
321 msg.rm_call.cb_cred = unix_auth->ah_cred;
322 msg.rm_call.cb_verf = unix_auth->ah_verf;
329 r.xdr_results = xresults;
330 r.results_ptr = resultsp;
331 xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
332 if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) {
333 stat = RPC_CANTENCODEARGS;
336 outlen = (int)xdr_getpos(xdrs);
339 * Basic loop: broadcast a packet and wait a while for response(s).
340 * The response timeout grows larger per iteration.
342 for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) {
343 for (i = 0; i < nets; i++) {
344 baddr.sin_addr = addrs[i];
345 if (sendto(sock, outbuf, outlen, 0,
346 (struct sockaddr *)&baddr,
347 sizeof (struct sockaddr)) != outlen) {
348 perror("Cannot send broadcast packet");
353 if (eachresult == NULL) {
358 msg.acpted_rply.ar_verf = _null_auth;
359 msg.acpted_rply.ar_results.where = (caddr_t)&r;
360 msg.acpted_rply.ar_results.proc = xdr_rmtcallres;
363 switch (select(0 /* unused in winsock */, &readfds, (int *)NULL, (int*)NULL,
365 switch (select(FD_SETSIZE, &readfds, NULL, NULL,
368 case 0: /* timed out */
372 case -1: /* some kind of error */
374 if (WSAerrno == EINTR)
379 perror("Broadcast select problem");
383 } /* end of select results switch */
385 fromlen = sizeof(struct sockaddr);
386 inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0,
387 (struct sockaddr *)&raddr, &fromlen);
390 if (WSAerrno == EINTR)
395 perror("Cannot receive reply to broadcast");
399 if (inlen < sizeof(u_long))
402 * see if reply transaction id matches sent id.
403 * If so, decode the results.
405 xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE);
406 if (xdr_replymsg(xdrs, &msg)) {
407 if ((msg.rm_xid == xid) &&
408 (msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
409 (msg.acpted_rply.ar_stat == SUCCESS)) {
410 raddr.sin_port = htons((u_short)port);
411 done = (*eachresult)(resultsp, &raddr);
413 /* otherwise, we just ignore the errors ... */
416 /* some kind of deserialization problem ... */
417 if (msg.rm_xid == xid)
419 nt_rpc_report("Broadcast deserialization problem");
421 fprintf(stderr, "Broadcast deserialization problem");
423 /* otherwise, just random garbage */
426 xdrs->x_op = XDR_FREE;
427 msg.acpted_rply.ar_results.proc = xdr_void;
428 (void)xdr_replymsg(xdrs, &msg);
429 (void)(*xresults)(xdrs, resultsp);
440 (void)closesocket(sock);
444 AUTH_DESTROY(unix_auth);