Add the missing "; \".
[glibc.git] / sunrpc / clnt_udp.c
blob62ee3a1c99b3578d784da61695691fcd74050efc
1 /*
2 * clnt_udp.c, Implements a UDP/IP based, client side RPC.
4 * Copyright (C) 1984, Sun Microsystems, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
16 * * Neither the name of Sun Microsystems, Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <stdio.h>
35 #include <unistd.h>
36 #include <libintl.h>
37 #include <rpc/rpc.h>
38 #include <rpc/xdr.h>
39 #include <rpc/clnt.h>
40 #include <sys/poll.h>
41 #include <sys/socket.h>
42 #include <sys/ioctl.h>
43 #include <netdb.h>
44 #include <errno.h>
45 #include <rpc/pmap_clnt.h>
46 #include <net/if.h>
47 #include <ifaddrs.h>
48 #ifdef USE_IN_LIBIO
49 # include <wchar.h>
50 #endif
51 #include <fcntl.h>
53 #ifdef IP_RECVERR
54 #include <errqueue.h>
55 #include <sys/uio.h>
56 #endif
58 #include <kernel-features.h>
60 extern bool_t xdr_opaque_auth (XDR *, struct opaque_auth *);
61 extern u_long _create_xid (void);
64 * UDP bases client side rpc operations
66 static enum clnt_stat clntudp_call (CLIENT *, u_long, xdrproc_t, caddr_t,
67 xdrproc_t, caddr_t, struct timeval);
68 static void clntudp_abort (void);
69 static void clntudp_geterr (CLIENT *, struct rpc_err *);
70 static bool_t clntudp_freeres (CLIENT *, xdrproc_t, caddr_t);
71 static bool_t clntudp_control (CLIENT *, int, char *);
72 static void clntudp_destroy (CLIENT *);
74 static const struct clnt_ops udp_ops =
76 clntudp_call,
77 clntudp_abort,
78 clntudp_geterr,
79 clntudp_freeres,
80 clntudp_destroy,
81 clntudp_control
85 * Private data kept per client handle
87 struct cu_data
89 int cu_sock;
90 bool_t cu_closeit;
91 struct sockaddr_in cu_raddr;
92 int cu_rlen;
93 struct timeval cu_wait;
94 struct timeval cu_total;
95 struct rpc_err cu_error;
96 XDR cu_outxdrs;
97 u_int cu_xdrpos;
98 u_int cu_sendsz;
99 char *cu_outbuf;
100 u_int cu_recvsz;
101 char cu_inbuf[1];
105 * Create a UDP based client handle.
106 * If *sockp<0, *sockp is set to a newly created UPD socket.
107 * If raddr->sin_port is 0 a binder on the remote machine
108 * is consulted for the correct port number.
109 * NB: It is the clients responsibility to close *sockp.
110 * NB: The rpch->cl_auth is initialized to null authentication.
111 * Caller may wish to set this something more useful.
113 * wait is the amount of time used between retransmitting a call if
114 * no response has been heard; retransmission occurs until the actual
115 * rpc call times out.
117 * sendsz and recvsz are the maximum allowable packet sizes that can be
118 * sent and received.
120 CLIENT *
121 __libc_clntudp_bufcreate (struct sockaddr_in *raddr, u_long program,
122 u_long version, struct timeval wait, int *sockp,
123 u_int sendsz, u_int recvsz, int flags)
125 CLIENT *cl;
126 struct cu_data *cu = NULL;
127 struct rpc_msg call_msg;
129 cl = (CLIENT *) mem_alloc (sizeof (CLIENT));
130 sendsz = ((sendsz + 3) / 4) * 4;
131 recvsz = ((recvsz + 3) / 4) * 4;
132 cu = (struct cu_data *) mem_alloc (sizeof (*cu) + sendsz + recvsz);
133 if (cl == NULL || cu == NULL)
135 struct rpc_createerr *ce = &get_rpc_createerr ();
136 (void) __fxprintf (NULL, "%s: %s",
137 "clntudp_create", _("out of memory\n"));
138 ce->cf_stat = RPC_SYSTEMERROR;
139 ce->cf_error.re_errno = ENOMEM;
140 goto fooy;
142 cu->cu_outbuf = &cu->cu_inbuf[recvsz];
144 if (raddr->sin_port == 0)
146 u_short port;
147 if ((port =
148 pmap_getport (raddr, program, version, IPPROTO_UDP)) == 0)
150 goto fooy;
152 raddr->sin_port = htons (port);
154 cl->cl_ops = (struct clnt_ops *) &udp_ops;
155 cl->cl_private = (caddr_t) cu;
156 cu->cu_raddr = *raddr;
157 cu->cu_rlen = sizeof (cu->cu_raddr);
158 cu->cu_wait = wait;
159 cu->cu_total.tv_sec = -1;
160 cu->cu_total.tv_usec = -1;
161 cu->cu_sendsz = sendsz;
162 cu->cu_recvsz = recvsz;
163 call_msg.rm_xid = _create_xid ();
164 call_msg.rm_direction = CALL;
165 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
166 call_msg.rm_call.cb_prog = program;
167 call_msg.rm_call.cb_vers = version;
168 INTUSE(xdrmem_create) (&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE);
169 if (!INTUSE(xdr_callhdr) (&(cu->cu_outxdrs), &call_msg))
171 goto fooy;
173 cu->cu_xdrpos = XDR_GETPOS (&(cu->cu_outxdrs));
174 if (*sockp < 0)
176 int dontblock = 1;
178 #ifdef SOCK_NONBLOCK
179 # ifndef __ASSUME_SOCK_CLOEXEC
180 if (__have_sock_cloexec >= 0)
181 # endif
183 *sockp = __socket (AF_INET, SOCK_DGRAM|SOCK_NONBLOCK|flags,
184 IPPROTO_UDP);
185 # ifndef __ASSUME_SOCK_CLOEXEC
186 if (__have_sock_cloexec == 0)
187 __have_sock_cloexec = *sockp >= 0 || errno != EINVAL ? 1 : -1;
188 # endif
190 #endif
191 #ifndef __ASSUME_SOCK_CLOEXEC
192 # ifdef SOCK_CLOEXEC
193 if (__have_sock_cloexec < 0)
194 # endif
196 *sockp = __socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
197 # ifdef SOCK_CLOEXEC
198 if (flags & SOCK_CLOEXEC)
199 __fcntl (*sockp, F_SETFD, FD_CLOEXEC);
200 # endif
202 #endif
203 if (__builtin_expect (*sockp < 0, 0))
205 struct rpc_createerr *ce = &get_rpc_createerr ();
206 ce->cf_stat = RPC_SYSTEMERROR;
207 ce->cf_error.re_errno = errno;
208 goto fooy;
210 /* attempt to bind to prov port */
211 (void) bindresvport (*sockp, (struct sockaddr_in *) 0);
212 #ifndef __ASSUME_SOCK_CLOEXEC
213 # ifdef SOCK_CLOEXEC
214 if (__have_sock_cloexec < 0)
215 # endif
216 /* the sockets rpc controls are non-blocking */
217 (void) __ioctl (*sockp, FIONBIO, (char *) &dontblock);
218 #endif
219 #ifdef IP_RECVERR
221 int on = 1;
222 __setsockopt (*sockp, SOL_IP, IP_RECVERR, &on, sizeof(on));
224 #endif
225 cu->cu_closeit = TRUE;
227 else
229 cu->cu_closeit = FALSE;
231 cu->cu_sock = *sockp;
232 cl->cl_auth = INTUSE(authnone_create) ();
233 return cl;
234 fooy:
235 if (cu)
236 mem_free ((caddr_t) cu, sizeof (*cu) + sendsz + recvsz);
237 if (cl)
238 mem_free ((caddr_t) cl, sizeof (CLIENT));
239 return (CLIENT *) NULL;
241 INTDEF (__libc_clntudp_bufcreate)
243 CLIENT *
244 clntudp_bufcreate (struct sockaddr_in *raddr, u_long program, u_long version,
245 struct timeval wait, int *sockp, u_int sendsz,
246 u_int recvsz)
248 return INTUSE(__libc_clntudp_bufcreate) (raddr, program, version, wait,
249 sockp, sendsz, recvsz, 0);
251 INTDEF (clntudp_bufcreate)
253 CLIENT *
254 clntudp_create (raddr, program, version, wait, sockp)
255 struct sockaddr_in *raddr;
256 u_long program;
257 u_long version;
258 struct timeval wait;
259 int *sockp;
261 return INTUSE(__libc_clntudp_bufcreate) (raddr, program, version, wait,
262 sockp, UDPMSGSIZE, UDPMSGSIZE, 0);
264 INTDEF (clntudp_create)
266 static int
267 is_network_up (int sock)
269 struct ifaddrs *ifa;
271 if (getifaddrs (&ifa) != 0)
272 return 0;
274 struct ifaddrs *run = ifa;
275 while (run != NULL)
277 if ((run->ifa_flags & IFF_UP) != 0
278 && run->ifa_addr != NULL
279 && run->ifa_addr->sa_family == AF_INET)
280 break;
282 run = run->ifa_next;
285 freeifaddrs (ifa);
287 return run != NULL;
290 static enum clnt_stat
291 clntudp_call (cl, proc, xargs, argsp, xresults, resultsp, utimeout)
292 CLIENT *cl; /* client handle */
293 u_long proc; /* procedure number */
294 xdrproc_t xargs; /* xdr routine for args */
295 caddr_t argsp; /* pointer to args */
296 xdrproc_t xresults; /* xdr routine for results */
297 caddr_t resultsp; /* pointer to results */
298 struct timeval utimeout; /* seconds to wait before giving up */
300 struct cu_data *cu = (struct cu_data *) cl->cl_private;
301 XDR *xdrs;
302 int outlen = 0;
303 int inlen;
304 socklen_t fromlen;
305 struct pollfd fd;
306 int milliseconds = (cu->cu_wait.tv_sec * 1000) +
307 (cu->cu_wait.tv_usec / 1000);
308 struct sockaddr_in from;
309 struct rpc_msg reply_msg;
310 XDR reply_xdrs;
311 struct timeval time_waited;
312 bool_t ok;
313 int nrefreshes = 2; /* number of times to refresh cred */
314 struct timeval timeout;
315 int anyup; /* any network interface up */
317 if (cu->cu_total.tv_usec == -1)
319 timeout = utimeout; /* use supplied timeout */
321 else
323 timeout = cu->cu_total; /* use default timeout */
326 time_waited.tv_sec = 0;
327 time_waited.tv_usec = 0;
328 call_again:
329 xdrs = &(cu->cu_outxdrs);
330 if (xargs == NULL)
331 goto get_reply;
332 xdrs->x_op = XDR_ENCODE;
333 XDR_SETPOS (xdrs, cu->cu_xdrpos);
335 * the transaction is the first thing in the out buffer
337 (*(uint32_t *) (cu->cu_outbuf))++;
338 if ((!XDR_PUTLONG (xdrs, (long *) &proc)) ||
339 (!AUTH_MARSHALL (cl->cl_auth, xdrs)) ||
340 (!(*xargs) (xdrs, argsp)))
341 return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
342 outlen = (int) XDR_GETPOS (xdrs);
344 send_again:
345 if (__sendto (cu->cu_sock, cu->cu_outbuf, outlen, 0,
346 (struct sockaddr *) &(cu->cu_raddr), cu->cu_rlen)
347 != outlen)
349 cu->cu_error.re_errno = errno;
350 return (cu->cu_error.re_status = RPC_CANTSEND);
354 * Hack to provide rpc-based message passing
356 if (timeout.tv_sec == 0 && timeout.tv_usec == 0)
358 return (cu->cu_error.re_status = RPC_TIMEDOUT);
360 get_reply:
362 * sub-optimal code appears here because we have
363 * some clock time to spare while the packets are in flight.
364 * (We assume that this is actually only executed once.)
366 reply_msg.acpted_rply.ar_verf = _null_auth;
367 reply_msg.acpted_rply.ar_results.where = resultsp;
368 reply_msg.acpted_rply.ar_results.proc = xresults;
369 fd.fd = cu->cu_sock;
370 fd.events = POLLIN;
371 anyup = 0;
372 for (;;)
374 switch (__poll (&fd, 1, milliseconds))
377 case 0:
378 if (anyup == 0)
380 anyup = is_network_up (cu->cu_sock);
381 if (!anyup)
382 return (cu->cu_error.re_status = RPC_CANTRECV);
385 time_waited.tv_sec += cu->cu_wait.tv_sec;
386 time_waited.tv_usec += cu->cu_wait.tv_usec;
387 while (time_waited.tv_usec >= 1000000)
389 time_waited.tv_sec++;
390 time_waited.tv_usec -= 1000000;
392 if ((time_waited.tv_sec < timeout.tv_sec) ||
393 ((time_waited.tv_sec == timeout.tv_sec) &&
394 (time_waited.tv_usec < timeout.tv_usec)))
395 goto send_again;
396 return (cu->cu_error.re_status = RPC_TIMEDOUT);
399 * buggy in other cases because time_waited is not being
400 * updated.
402 case -1:
403 if (errno == EINTR)
404 continue;
405 cu->cu_error.re_errno = errno;
406 return (cu->cu_error.re_status = RPC_CANTRECV);
408 #ifdef IP_RECVERR
409 if (fd.revents & POLLERR)
411 struct msghdr msg;
412 struct cmsghdr *cmsg;
413 struct sock_extended_err *e;
414 struct sockaddr_in err_addr;
415 struct iovec iov;
416 char *cbuf = (char *) alloca (outlen + 256);
417 int ret;
419 iov.iov_base = cbuf + 256;
420 iov.iov_len = outlen;
421 msg.msg_name = (void *) &err_addr;
422 msg.msg_namelen = sizeof (err_addr);
423 msg.msg_iov = &iov;
424 msg.msg_iovlen = 1;
425 msg.msg_flags = 0;
426 msg.msg_control = cbuf;
427 msg.msg_controllen = 256;
428 ret = __recvmsg (cu->cu_sock, &msg, MSG_ERRQUEUE);
429 if (ret >= 0
430 && memcmp (cbuf + 256, cu->cu_outbuf, ret) == 0
431 && (msg.msg_flags & MSG_ERRQUEUE)
432 && ((msg.msg_namelen == 0
433 && ret >= 12)
434 || (msg.msg_namelen == sizeof (err_addr)
435 && err_addr.sin_family == AF_INET
436 && memcmp (&err_addr.sin_addr, &cu->cu_raddr.sin_addr,
437 sizeof (err_addr.sin_addr)) == 0
438 && err_addr.sin_port == cu->cu_raddr.sin_port)))
439 for (cmsg = CMSG_FIRSTHDR (&msg); cmsg;
440 cmsg = CMSG_NXTHDR (&msg, cmsg))
441 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
443 e = (struct sock_extended_err *) CMSG_DATA(cmsg);
444 cu->cu_error.re_errno = e->ee_errno;
445 return (cu->cu_error.re_status = RPC_CANTRECV);
448 #endif
451 fromlen = sizeof (struct sockaddr);
452 inlen = __recvfrom (cu->cu_sock, cu->cu_inbuf,
453 (int) cu->cu_recvsz, MSG_DONTWAIT,
454 (struct sockaddr *) &from, &fromlen);
456 while (inlen < 0 && errno == EINTR);
457 if (inlen < 0)
459 if (errno == EWOULDBLOCK)
460 continue;
461 cu->cu_error.re_errno = errno;
462 return (cu->cu_error.re_status = RPC_CANTRECV);
464 if (inlen < 4)
465 continue;
467 /* see if reply transaction id matches sent id.
468 Don't do this if we only wait for a replay */
469 if (xargs != NULL
470 && (*((u_int32_t *) (cu->cu_inbuf))
471 != *((u_int32_t *) (cu->cu_outbuf))))
472 continue;
473 /* we now assume we have the proper reply */
474 break;
478 * now decode and validate the response
480 INTUSE(xdrmem_create) (&reply_xdrs, cu->cu_inbuf, (u_int) inlen, XDR_DECODE);
481 ok = INTUSE(xdr_replymsg) (&reply_xdrs, &reply_msg);
482 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
483 if (ok)
485 _seterr_reply (&reply_msg, &(cu->cu_error));
486 if (cu->cu_error.re_status == RPC_SUCCESS)
488 if (!AUTH_VALIDATE (cl->cl_auth,
489 &reply_msg.acpted_rply.ar_verf))
491 cu->cu_error.re_status = RPC_AUTHERROR;
492 cu->cu_error.re_why = AUTH_INVALIDRESP;
494 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
496 xdrs->x_op = XDR_FREE;
497 (void) INTUSE(xdr_opaque_auth) (xdrs,
498 &(reply_msg.acpted_rply.ar_verf));
500 } /* end successful completion */
501 else
503 /* maybe our credentials need to be refreshed ... */
504 if (nrefreshes > 0 && AUTH_REFRESH (cl->cl_auth))
506 nrefreshes--;
507 goto call_again;
509 } /* end of unsuccessful completion */
510 } /* end of valid reply message */
511 else
513 cu->cu_error.re_status = RPC_CANTDECODERES;
515 return cu->cu_error.re_status;
518 static void
519 clntudp_geterr (CLIENT *cl, struct rpc_err *errp)
521 struct cu_data *cu = (struct cu_data *) cl->cl_private;
523 *errp = cu->cu_error;
527 static bool_t
528 clntudp_freeres (CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr)
530 struct cu_data *cu = (struct cu_data *) cl->cl_private;
531 XDR *xdrs = &(cu->cu_outxdrs);
533 xdrs->x_op = XDR_FREE;
534 return (*xdr_res) (xdrs, res_ptr);
537 static void
538 clntudp_abort (void)
542 static bool_t
543 clntudp_control (CLIENT *cl, int request, char *info)
545 struct cu_data *cu = (struct cu_data *) cl->cl_private;
547 switch (request)
549 case CLSET_FD_CLOSE:
550 cu->cu_closeit = TRUE;
551 break;
552 case CLSET_FD_NCLOSE:
553 cu->cu_closeit = FALSE;
554 break;
555 case CLSET_TIMEOUT:
556 cu->cu_total = *(struct timeval *) info;
557 break;
558 case CLGET_TIMEOUT:
559 *(struct timeval *) info = cu->cu_total;
560 break;
561 case CLSET_RETRY_TIMEOUT:
562 cu->cu_wait = *(struct timeval *) info;
563 break;
564 case CLGET_RETRY_TIMEOUT:
565 *(struct timeval *) info = cu->cu_wait;
566 break;
567 case CLGET_SERVER_ADDR:
568 *(struct sockaddr_in *) info = cu->cu_raddr;
569 break;
570 case CLGET_FD:
571 *(int *)info = cu->cu_sock;
572 break;
573 case CLGET_XID:
575 * use the knowledge that xid is the
576 * first element in the call structure *.
577 * This will get the xid of the PREVIOUS call
579 *(u_long *)info = ntohl(*(u_long *)cu->cu_outbuf);
580 break;
581 case CLSET_XID:
582 /* This will set the xid of the NEXT call */
583 *(u_long *)cu->cu_outbuf = htonl(*(u_long *)info - 1);
584 /* decrement by 1 as clntudp_call() increments once */
585 case CLGET_VERS:
587 * This RELIES on the information that, in the call body,
588 * the version number field is the fifth field from the
589 * begining of the RPC header. MUST be changed if the
590 * call_struct is changed
592 *(u_long *)info = ntohl(*(u_long *)(cu->cu_outbuf +
593 4 * BYTES_PER_XDR_UNIT));
594 break;
595 case CLSET_VERS:
596 *(u_long *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT)
597 = htonl(*(u_long *)info);
598 break;
599 case CLGET_PROG:
601 * This RELIES on the information that, in the call body,
602 * the program number field is the field from the
603 * begining of the RPC header. MUST be changed if the
604 * call_struct is changed
606 *(u_long *)info = ntohl(*(u_long *)(cu->cu_outbuf +
607 3 * BYTES_PER_XDR_UNIT));
608 break;
609 case CLSET_PROG:
610 *(u_long *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT)
611 = htonl(*(u_long *)info);
612 break;
613 /* The following are only possible with TI-RPC */
614 case CLGET_SVC_ADDR:
615 case CLSET_SVC_ADDR:
616 case CLSET_PUSH_TIMOD:
617 case CLSET_POP_TIMOD:
618 default:
619 return FALSE;
621 return TRUE;
624 static void
625 clntudp_destroy (CLIENT *cl)
627 struct cu_data *cu = (struct cu_data *) cl->cl_private;
629 if (cu->cu_closeit)
631 (void) __close (cu->cu_sock);
633 XDR_DESTROY (&(cu->cu_outxdrs));
634 mem_free ((caddr_t) cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz));
635 mem_free ((caddr_t) cl, sizeof (CLIENT));