OSDN Git Service

hidden_def/hidden_proto: convert all users (I hope) termios split, add some missing...
[uclinux-h8/uClibc.git] / libc / inet / rpc / pmap_rmt.c
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.
9  *
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.
13  *
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.
17  *
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.
21  *
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.
25  *
26  * Sun Microsystems, Inc.
27  * 2550 Garcia Avenue
28  * Mountain View, California  94043
29  */
30 #if 0
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
42 #define __FORCE_GLIBC
43 #include <features.h>
44
45 #include <unistd.h>
46 #include <string.h>
47 #include <rpc/rpc.h>
48 #include <rpc/pmap_prot.h>
49 #include <rpc/pmap_clnt.h>
50 #include <rpc/pmap_rmt.h>
51 #include <sys/poll.h>
52 #include <sys/socket.h>
53 #include <stdio.h>
54 #include <errno.h>
55 #undef   _POSIX_SOURCE          /* Ultrix <sys/param.h> needs --roland@gnu */
56 #include <sys/param.h>          /* Ultrix needs before net/if --roland@gnu */
57 #include <net/if.h>
58 #include <sys/ioctl.h>
59 #include <arpa/inet.h>
60 #define MAX_BROADCAST_SIZE 1400
61
62 libc_hidden_proto(memset)
63 libc_hidden_proto(ioctl)
64 libc_hidden_proto(perror)
65 libc_hidden_proto(socket)
66 libc_hidden_proto(close)
67 libc_hidden_proto(authunix_create_default)
68 libc_hidden_proto(xdrmem_create)
69 libc_hidden_proto(xdr_callmsg)
70 libc_hidden_proto(xdr_replymsg)
71 libc_hidden_proto(xdr_reference)
72 libc_hidden_proto(xdr_u_long)
73 libc_hidden_proto(inet_makeaddr)
74 libc_hidden_proto(inet_netof)
75 libc_hidden_proto(clntudp_create)
76 libc_hidden_proto(setsockopt)
77 libc_hidden_proto(recvfrom)
78 libc_hidden_proto(sendto)
79 libc_hidden_proto(poll)
80 libc_hidden_proto(fprintf)
81
82
83 extern u_long _create_xid (void) attribute_hidden;
84
85 static const struct timeval timeout = {3, 0};
86
87 /*
88  * XDR remote call arguments
89  * written for XDR_ENCODE direction only
90  */
91 bool_t
92 xdr_rmtcall_args (XDR *xdrs, struct rmtcallargs *cap)
93 {
94   u_int lenposition, argposition, position;
95
96   if (xdr_u_long (xdrs, &(cap->prog)) &&
97       xdr_u_long (xdrs, &(cap->vers)) &&
98       xdr_u_long (xdrs, &(cap->proc)))
99     {
100       lenposition = XDR_GETPOS (xdrs);
101       if (!xdr_u_long (xdrs, &(cap->arglen)))
102         return FALSE;
103       argposition = XDR_GETPOS (xdrs);
104       if (!(*(cap->xdr_args)) (xdrs, cap->args_ptr))
105         return FALSE;
106       position = XDR_GETPOS (xdrs);
107       cap->arglen = (u_long) position - (u_long) argposition;
108       XDR_SETPOS (xdrs, lenposition);
109       if (!xdr_u_long (xdrs, &(cap->arglen)))
110         return FALSE;
111       XDR_SETPOS (xdrs, position);
112       return TRUE;
113     }
114   return FALSE;
115 }
116 libc_hidden_proto(xdr_rmtcall_args)
117 libc_hidden_def(xdr_rmtcall_args)
118
119 /*
120  * pmapper remote-call-service interface.
121  * This routine is used to call the pmapper remote call service
122  * which will look up a service program in the port maps, and then
123  * remotely call that routine with the given parameters.  This allows
124  * programs to do a lookup and call in one step.
125  */
126 enum clnt_stat
127 pmap_rmtcall (addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr)
128      struct sockaddr_in *addr;
129      u_long prog, vers, proc;
130      xdrproc_t xdrargs, xdrres;
131      caddr_t argsp, resp;
132      struct timeval tout;
133      u_long *port_ptr;
134 {
135   int socket = -1;
136   CLIENT *client;
137   struct rmtcallargs a;
138   struct rmtcallres r;
139   enum clnt_stat stat;
140
141   addr->sin_port = htons (PMAPPORT);
142   client = clntudp_create (addr, PMAPPROG, PMAPVERS, timeout, &socket);
143   if (client != (CLIENT *) NULL)
144     {
145       a.prog = prog;
146       a.vers = vers;
147       a.proc = proc;
148       a.args_ptr = argsp;
149       a.xdr_args = xdrargs;
150       r.port_ptr = port_ptr;
151       r.results_ptr = resp;
152       r.xdr_results = xdrres;
153       stat = CLNT_CALL (client, PMAPPROC_CALLIT, (xdrproc_t)xdr_rmtcall_args,
154                         (caddr_t)&a, (xdrproc_t)xdr_rmtcallres,
155                         (caddr_t)&r, tout);
156       CLNT_DESTROY (client);
157     }
158   else
159     {
160       stat = RPC_FAILED;
161     }
162   /* (void)close(socket); CLNT_DESTROY already closed it */
163   addr->sin_port = 0;
164   return stat;
165 }
166
167
168 /*
169  * XDR remote call results
170  * written for XDR_DECODE direction only
171  */
172 bool_t
173 xdr_rmtcallres (xdrs, crp)
174      XDR *xdrs;
175      struct rmtcallres *crp;
176 {
177   caddr_t port_ptr;
178
179   port_ptr = (caddr_t) crp->port_ptr;
180   if (xdr_reference (xdrs, &port_ptr, sizeof (u_long), (xdrproc_t) xdr_u_long)
181       && xdr_u_long (xdrs, &crp->resultslen))
182     {
183       crp->port_ptr = (u_long *) port_ptr;
184       return (*(crp->xdr_results)) (xdrs, crp->results_ptr);
185     }
186   return FALSE;
187 }
188
189
190 /*
191  * The following is kludged-up support for simple rpc broadcasts.
192  * Someday a large, complicated system will replace these trivial
193  * routines which only support udp/ip .
194  */
195
196 static int
197 internal_function
198 getbroadcastnets (struct in_addr *addrs, int sock, char *buf)
199   /* int sock:  any valid socket will do */
200   /* char *buf: why allocate more when we can use existing... */
201 {
202   struct ifconf ifc;
203   struct ifreq ifreq, *ifr;
204   struct sockaddr_in *sin;
205   int n, i;
206
207   ifc.ifc_len = UDPMSGSIZE;
208   ifc.ifc_buf = buf;
209   if (ioctl (sock, SIOCGIFCONF, (char *) &ifc) < 0)
210     {
211       perror (_("broadcast: ioctl (get interface configuration)"));
212       return (0);
213     }
214   ifr = ifc.ifc_req;
215   for (i = 0, n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++)
216     {
217       ifreq = *ifr;
218       if (ioctl (sock, SIOCGIFFLAGS, (char *) &ifreq) < 0)
219         {
220           perror (_("broadcast: ioctl (get interface flags)"));
221           continue;
222         }
223       if ((ifreq.ifr_flags & IFF_BROADCAST) &&
224           (ifreq.ifr_flags & IFF_UP) &&
225           ifr->ifr_addr.sa_family == AF_INET)
226         {
227           sin = (struct sockaddr_in *) &ifr->ifr_addr;
228 #ifdef SIOCGIFBRDADDR           /* 4.3BSD */
229           if (ioctl (sock, SIOCGIFBRDADDR, (char *) &ifreq) < 0)
230             {
231               addrs[i++] = inet_makeaddr (inet_netof
232               /* Changed to pass struct instead of s_addr member
233                  by roland@gnu.  */
234                                           (sin->sin_addr), INADDR_ANY);
235             }
236           else
237             {
238               addrs[i++] = ((struct sockaddr_in *)
239                             &ifreq.ifr_addr)->sin_addr;
240             }
241 #else /* 4.2 BSD */
242           addrs[i++] = inet_makeaddr (inet_netof
243                                       (sin->sin_addr.s_addr), INADDR_ANY);
244 #endif
245         }
246     }
247   return i;
248 }
249
250
251 enum clnt_stat
252 clnt_broadcast (prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult)
253      u_long prog;               /* program number */
254      u_long vers;               /* version number */
255      u_long proc;               /* procedure number */
256      xdrproc_t xargs;           /* xdr routine for args */
257      caddr_t argsp;             /* pointer to args */
258      xdrproc_t xresults;        /* xdr routine for results */
259      caddr_t resultsp;          /* pointer to results */
260      resultproc_t eachresult;   /* call with each result obtained */
261 {
262   enum clnt_stat stat = RPC_FAILED;
263   AUTH *unix_auth = authunix_create_default ();
264   XDR xdr_stream;
265   XDR *xdrs = &xdr_stream;
266   struct timeval t;
267   int outlen, inlen, nets;
268   socklen_t fromlen;
269   int sock;
270   int on = 1;
271   struct pollfd fd;
272   int milliseconds;
273   int i;
274   bool_t done = FALSE;
275   u_long xid;
276   u_long port;
277   struct in_addr addrs[20];
278   struct sockaddr_in baddr, raddr;      /* broadcast and response addresses */
279   struct rmtcallargs a;
280   struct rmtcallres r;
281   struct rpc_msg msg;
282   char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];
283
284   /*
285    * initialization: create a socket, a broadcast address, and
286    * preserialize the arguments into a send buffer.
287    */
288   if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
289     {
290       perror (_("Cannot create socket for broadcast rpc"));
291       stat = RPC_CANTSEND;
292       goto done_broad;
293     }
294 #ifdef SO_BROADCAST
295   if (setsockopt (sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0)
296     {
297       perror (_("Cannot set socket option SO_BROADCAST"));
298       stat = RPC_CANTSEND;
299       goto done_broad;
300     }
301 #endif /* def SO_BROADCAST */
302   fd.fd = sock;
303   fd.events = POLLIN;
304   nets = getbroadcastnets (addrs, sock, inbuf);
305   memset ((char *) &baddr, 0, sizeof (baddr));
306   baddr.sin_family = AF_INET;
307   baddr.sin_port = htons (PMAPPORT);
308   baddr.sin_addr.s_addr = htonl (INADDR_ANY);
309 /*      baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */
310   msg.rm_xid = xid = _create_xid ();
311   t.tv_usec = 0;
312   msg.rm_direction = CALL;
313   msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
314   msg.rm_call.cb_prog = PMAPPROG;
315   msg.rm_call.cb_vers = PMAPVERS;
316   msg.rm_call.cb_proc = PMAPPROC_CALLIT;
317   msg.rm_call.cb_cred = unix_auth->ah_cred;
318   msg.rm_call.cb_verf = unix_auth->ah_verf;
319   a.prog = prog;
320   a.vers = vers;
321   a.proc = proc;
322   a.xdr_args = xargs;
323   a.args_ptr = argsp;
324   r.port_ptr = &port;
325   r.xdr_results = xresults;
326   r.results_ptr = resultsp;
327   xdrmem_create (xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
328   if ((!xdr_callmsg (xdrs, &msg)) || (!xdr_rmtcall_args (xdrs, &a)))
329     {
330       stat = RPC_CANTENCODEARGS;
331       goto done_broad;
332     }
333   outlen = (int) xdr_getpos (xdrs);
334   xdr_destroy (xdrs);
335   /*
336    * Basic loop: broadcast a packet and wait a while for response(s).
337    * The response timeout grows larger per iteration.
338    */
339   for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2)
340     {
341       for (i = 0; i < nets; i++)
342         {
343           baddr.sin_addr = addrs[i];
344           if (sendto (sock, outbuf, outlen, 0,
345                       (struct sockaddr *) &baddr,
346                       sizeof (struct sockaddr)) != outlen)
347             {
348               perror (_("Cannot send broadcast packet"));
349               stat = RPC_CANTSEND;
350               goto done_broad;
351             }
352         }
353       if (eachresult == NULL)
354         {
355           stat = RPC_SUCCESS;
356           goto done_broad;
357         }
358     recv_again:
359       msg.acpted_rply.ar_verf = _null_auth;
360       msg.acpted_rply.ar_results.where = (caddr_t) & r;
361       msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_rmtcallres;
362       milliseconds = t.tv_sec * 1000 + t.tv_usec / 1000;
363       switch (poll(&fd, 1, milliseconds))
364         {
365
366         case 0:         /* timed out */
367           stat = RPC_TIMEDOUT;
368           continue;
369
370         case -1:                /* some kind of error */
371           if (errno == EINTR)
372             goto recv_again;
373           perror (_("Broadcast poll problem"));
374           stat = RPC_CANTRECV;
375           goto done_broad;
376
377         }                       /* end of poll results switch */
378     try_again:
379       fromlen = sizeof (struct sockaddr);
380       inlen = recvfrom (sock, inbuf, UDPMSGSIZE, 0,
381                         (struct sockaddr *) &raddr, &fromlen);
382       if (inlen < 0)
383         {
384           if (errno == EINTR)
385             goto try_again;
386           perror (_("Cannot receive reply to broadcast"));
387           stat = RPC_CANTRECV;
388           goto done_broad;
389         }
390       if ((size_t) inlen < sizeof (u_long))
391         goto recv_again;
392       /*
393        * see if reply transaction id matches sent id.
394        * If so, decode the results.
395        */
396       xdrmem_create (xdrs, inbuf, (u_int) inlen, XDR_DECODE);
397       if (xdr_replymsg (xdrs, &msg))
398         {
399           if (((u_int32_t) msg.rm_xid == (u_int32_t) xid) &&
400               (msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
401               (msg.acpted_rply.ar_stat == SUCCESS))
402             {
403               raddr.sin_port = htons ((u_short) port);
404               done = (*eachresult) (resultsp, &raddr);
405             }
406           /* otherwise, we just ignore the errors ... */
407         }
408       else
409         {
410 #ifdef notdef
411           /* some kind of deserialization problem ... */
412           if ((u_int32_t) msg.rm_xid == (u_int32_t) xid)
413             fprintf (stderr, "Broadcast deserialization problem");
414           /* otherwise, just random garbage */
415 #endif
416         }
417       xdrs->x_op = XDR_FREE;
418       msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
419       (void) xdr_replymsg (xdrs, &msg);
420       (void) (*xresults) (xdrs, resultsp);
421       xdr_destroy (xdrs);
422       if (done)
423         {
424           stat = RPC_SUCCESS;
425           goto done_broad;
426         }
427       else
428         {
429           goto recv_again;
430         }
431     }
432 done_broad:
433   (void) close (sock);
434   AUTH_DESTROY (unix_auth);
435   return stat;
436 }