blob: 34fc9ab73393299488035eb4e0bcf3b7ca066421 [file] [log] [blame]
Patrick Schaaf2dd59ef2012-02-27 22:27:31 +01001/* @(#)clnt_udp.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
31static char sccsid[] = "@(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";
32#endif
33
34/*
35 * clnt_udp.c, Implements a UDP/IP based, client side RPC.
36 *
37 * Copyright (C) 1984, Sun Microsystems, Inc.
38 */
39
40#define __FORCE_GLIBC
41#include <features.h>
42
43#include <stdio.h>
44#include <unistd.h>
maxwen27116ba2015-08-14 21:41:28 +020045#include <string.h>
Patrick Schaaf2dd59ef2012-02-27 22:27:31 +010046#include <rpc/rpc.h>
47#include <rpc/xdr.h>
48#include <rpc/clnt.h>
49#include <sys/poll.h>
50#include <sys/socket.h>
51#include <sys/ioctl.h>
52#include <netdb.h>
53#include <errno.h>
54#include <rpc/pmap_clnt.h>
55#include <net/if.h>
56#ifdef USE_IN_LIBIO
57# include <wchar.h>
58#endif
59
60#ifdef IP_RECVERR
61#include "errqueue.h"
62#include <sys/uio.h>
63#endif
64
65/* CMSG_NXTHDR is using it */
66
67
68extern u_long _create_xid (void) attribute_hidden;
69
70/*
71 * UDP bases client side rpc operations
72 */
73static enum clnt_stat clntudp_call (CLIENT *, u_long, xdrproc_t, caddr_t,
74 xdrproc_t, caddr_t, struct timeval);
75static void clntudp_abort (void);
76static void clntudp_geterr (CLIENT *, struct rpc_err *);
77static bool_t clntudp_freeres (CLIENT *, xdrproc_t, caddr_t);
78static bool_t clntudp_control (CLIENT *, int, char *);
79static void clntudp_destroy (CLIENT *);
80
81static const struct clnt_ops udp_ops =
82{
83 clntudp_call,
84 clntudp_abort,
85 clntudp_geterr,
86 clntudp_freeres,
87 clntudp_destroy,
88 clntudp_control
89};
90
91/*
92 * Private data kept per client handle
93 */
94struct cu_data
95 {
96 int cu_sock;
97 bool_t cu_closeit;
98 struct sockaddr_in cu_raddr;
99 int cu_rlen;
100 struct timeval cu_wait;
101 struct timeval cu_total;
102 struct rpc_err cu_error;
103 XDR cu_outxdrs;
104 u_int cu_xdrpos;
105 u_int cu_sendsz;
106 char *cu_outbuf;
107 u_int cu_recvsz;
108 char cu_inbuf[1];
109 };
110
111/*
112 * Create a UDP based client handle.
113 * If *sockp<0, *sockp is set to a newly created UPD socket.
114 * If raddr->sin_port is 0 a binder on the remote machine
115 * is consulted for the correct port number.
116 * NB: It is the clients responsibility to close *sockp.
117 * NB: The rpch->cl_auth is initialized to null authentication.
118 * Caller may wish to set this something more useful.
119 *
120 * wait is the amount of time used between retransmitting a call if
121 * no response has been heard; retransmission occurs until the actual
122 * rpc call times out.
123 *
124 * sendsz and recvsz are the maximum allowable packet sizes that can be
125 * sent and received.
126 */
127CLIENT *
128clntudp_bufcreate (struct sockaddr_in *raddr, u_long program, u_long version,
129 struct timeval wait, int *sockp, u_int sendsz,
130 u_int recvsz)
131{
132 CLIENT *cl;
133 struct cu_data *cu = NULL;
134 struct rpc_msg call_msg;
135
136 cl = (CLIENT *) mem_alloc (sizeof (CLIENT));
137 sendsz = ((sendsz + 3) / 4) * 4;
138 recvsz = ((recvsz + 3) / 4) * 4;
139 cu = (struct cu_data *) mem_alloc (sizeof (*cu) + sendsz + recvsz);
140 if (cl == NULL || cu == NULL)
141 {
142 struct rpc_createerr *ce = &get_rpc_createerr ();
143#ifdef USE_IN_LIBIO
144 if (_IO_fwide (stderr, 0) > 0)
145 (void) fwprintf (stderr, L"%s",
146 _("clntudp_create: out of memory\n"));
147 else
148#endif
149 (void) fputs (_("clntudp_create: out of memory\n"), stderr);
150 ce->cf_stat = RPC_SYSTEMERROR;
151 ce->cf_error.re_errno = ENOMEM;
152 goto fooy;
153 }
154 cu->cu_outbuf = &cu->cu_inbuf[recvsz];
155
156 if (raddr->sin_port == 0)
157 {
158 u_short port;
159 if ((port =
160 pmap_getport (raddr, program, version, IPPROTO_UDP)) == 0)
161 {
162 goto fooy;
163 }
164 raddr->sin_port = htons (port);
165 }
166 cl->cl_ops = &udp_ops;
167 cl->cl_private = (caddr_t) cu;
168 cu->cu_raddr = *raddr;
169 cu->cu_rlen = sizeof (cu->cu_raddr);
170 cu->cu_wait = wait;
171 cu->cu_total.tv_sec = -1;
172 cu->cu_total.tv_usec = -1;
173 cu->cu_sendsz = sendsz;
174 cu->cu_recvsz = recvsz;
175 call_msg.rm_xid = _create_xid ();
176 call_msg.rm_direction = CALL;
177 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
178 call_msg.rm_call.cb_prog = program;
179 call_msg.rm_call.cb_vers = version;
180 xdrmem_create (&(cu->cu_outxdrs), cu->cu_outbuf,
181 sendsz, XDR_ENCODE);
182 if (!xdr_callhdr (&(cu->cu_outxdrs), &call_msg))
183 {
184 goto fooy;
185 }
186 cu->cu_xdrpos = XDR_GETPOS (&(cu->cu_outxdrs));
187 if (*sockp < 0)
188 {
189 int dontblock = 1;
190
191 *sockp = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
192 if (*sockp < 0)
193 {
194 struct rpc_createerr *ce = &get_rpc_createerr ();
195 ce->cf_stat = RPC_SYSTEMERROR;
196 ce->cf_error.re_errno = errno;
197 goto fooy;
198 }
199 /* attempt to bind to prov port */
200 (void) bindresvport (*sockp, (struct sockaddr_in *) 0);
201 /* the sockets rpc controls are non-blocking */
202 (void) ioctl (*sockp, FIONBIO, (char *) &dontblock);
203#ifdef IP_RECVERR
204 {
205 int on = 1;
206 setsockopt(*sockp, SOL_IP, IP_RECVERR, &on, sizeof(on));
207 }
208#endif
209 cu->cu_closeit = TRUE;
210 }
211 else
212 {
213 cu->cu_closeit = FALSE;
214 }
215 cu->cu_sock = *sockp;
216 cl->cl_auth = authnone_create ();
217 return cl;
218fooy:
219 if (cu)
220 mem_free ((caddr_t) cu, sizeof (*cu) + sendsz + recvsz);
221 if (cl)
222 mem_free ((caddr_t) cl, sizeof (CLIENT));
223 return (CLIENT *) NULL;
224}
225libc_hidden_def(clntudp_bufcreate)
226
227CLIENT *
228clntudp_create (struct sockaddr_in *raddr, u_long program, u_long version, struct timeval wait, int *sockp)
229{
230
231 return clntudp_bufcreate (raddr, program, version, wait, sockp,
232 UDPMSGSIZE, UDPMSGSIZE);
233}
234libc_hidden_def(clntudp_create)
235
236static int
237is_network_up (int sock)
238{
239 struct ifconf ifc;
240 char buf[UDPMSGSIZE];
241 struct ifreq ifreq, *ifr;
242 int n;
243
244 ifc.ifc_len = sizeof (buf);
245 ifc.ifc_buf = buf;
246 if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) == 0)
247 {
248 ifr = ifc.ifc_req;
249 for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++)
250 {
251 ifreq = *ifr;
252 if (ioctl (sock, SIOCGIFFLAGS, (char *) &ifreq) < 0)
253 break;
254
255 if ((ifreq.ifr_flags & IFF_UP)
256 && ifr->ifr_addr.sa_family == AF_INET)
257 return 1;
258 }
259 }
260 return 0;
261}
262
263static enum clnt_stat
264clntudp_call (
265 CLIENT *cl, /* client handle */
266 u_long proc, /* procedure number */
267 xdrproc_t xargs, /* xdr routine for args */
268 caddr_t argsp, /* pointer to args */
269 xdrproc_t xresults, /* xdr routine for results */
270 caddr_t resultsp, /* pointer to results */
271 struct timeval utimeout /* seconds to wait before giving up */)
272{
273 struct cu_data *cu = (struct cu_data *) cl->cl_private;
274 XDR *xdrs;
275 int outlen = 0;
276 int inlen;
277 socklen_t fromlen;
278 struct pollfd fd;
279 int milliseconds = (cu->cu_wait.tv_sec * 1000) +
280 (cu->cu_wait.tv_usec / 1000);
281 struct sockaddr_in from;
282 struct rpc_msg reply_msg;
283 XDR reply_xdrs;
284 struct timeval time_waited;
285 bool_t ok;
286 int nrefreshes = 2; /* number of times to refresh cred */
287 struct timeval timeout;
288 int anyup; /* any network interface up */
289
290 if (cu->cu_total.tv_usec == -1)
291 {
292 timeout = utimeout; /* use supplied timeout */
293 }
294 else
295 {
296 timeout = cu->cu_total; /* use default timeout */
297 }
298
299 time_waited.tv_sec = 0;
300 time_waited.tv_usec = 0;
301call_again:
302 xdrs = &(cu->cu_outxdrs);
303 if (xargs == NULL)
304 goto get_reply;
305 xdrs->x_op = XDR_ENCODE;
306 XDR_SETPOS (xdrs, cu->cu_xdrpos);
307 /*
308 * the transaction is the first thing in the out buffer
309 */
310 (*(uint32_t *) (cu->cu_outbuf))++;
311 if ((!XDR_PUTLONG (xdrs, (long *) &proc)) ||
312 (!AUTH_MARSHALL (cl->cl_auth, xdrs)) ||
313 (!(*xargs) (xdrs, argsp)))
314 return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
315 outlen = (int) XDR_GETPOS (xdrs);
316
317send_again:
318 if (sendto (cu->cu_sock, cu->cu_outbuf, outlen, 0,
319 (struct sockaddr *) &(cu->cu_raddr), cu->cu_rlen)
320 != outlen)
321 {
322 cu->cu_error.re_errno = errno;
323 return (cu->cu_error.re_status = RPC_CANTSEND);
324 }
325
326 /*
327 * Hack to provide rpc-based message passing
328 */
329 if (timeout.tv_sec == 0 && timeout.tv_usec == 0)
330 {
331 return (cu->cu_error.re_status = RPC_TIMEDOUT);
332 }
333 get_reply:
334 /*
335 * sub-optimal code appears here because we have
336 * some clock time to spare while the packets are in flight.
337 * (We assume that this is actually only executed once.)
338 */
339 reply_msg.acpted_rply.ar_verf = _null_auth;
340 reply_msg.acpted_rply.ar_results.where = resultsp;
341 reply_msg.acpted_rply.ar_results.proc = xresults;
342 fd.fd = cu->cu_sock;
343 fd.events = POLLIN;
344 anyup = 0;
345 for (;;)
346 {
347 switch (poll (&fd, 1, milliseconds))
348 {
349
350 case 0:
351 if (anyup == 0)
352 {
353 anyup = is_network_up (cu->cu_sock);
354 if (!anyup)
355 return (cu->cu_error.re_status = RPC_CANTRECV);
356 }
357
358 time_waited.tv_sec += cu->cu_wait.tv_sec;
359 time_waited.tv_usec += cu->cu_wait.tv_usec;
360 while (time_waited.tv_usec >= 1000000)
361 {
362 time_waited.tv_sec++;
363 time_waited.tv_usec -= 1000000;
364 }
365 if ((time_waited.tv_sec < timeout.tv_sec) ||
366 ((time_waited.tv_sec == timeout.tv_sec) &&
367 (time_waited.tv_usec < timeout.tv_usec)))
368 goto send_again;
369 return (cu->cu_error.re_status = RPC_TIMEDOUT);
370
371 /*
372 * buggy in other cases because time_waited is not being
373 * updated.
374 */
375 case -1:
376 if (errno == EINTR)
377 continue;
378 cu->cu_error.re_errno = errno;
379 return (cu->cu_error.re_status = RPC_CANTRECV);
380 }
381#ifdef IP_RECVERR
382 if (fd.revents & POLLERR)
383 {
384 struct msghdr msg;
385 struct cmsghdr *cmsg;
386 struct sock_extended_err *e;
387 struct sockaddr_in err_addr;
388 struct iovec iov;
389 char *cbuf = (char *) alloca (outlen + 256);
390 int ret;
391
392 iov.iov_base = cbuf + 256;
393 iov.iov_len = outlen;
394 msg.msg_name = (void *) &err_addr;
395 msg.msg_namelen = sizeof (err_addr);
396 msg.msg_iov = &iov;
397 msg.msg_iovlen = 1;
398 msg.msg_flags = 0;
399 msg.msg_control = cbuf;
400 msg.msg_controllen = 256;
401 ret = recvmsg (cu->cu_sock, &msg, MSG_ERRQUEUE);
402 if (ret >= 0
403 && memcmp (cbuf + 256, cu->cu_outbuf, ret) == 0
404 && (msg.msg_flags & MSG_ERRQUEUE)
405 && ((msg.msg_namelen == 0
406 && ret >= 12)
407 || (msg.msg_namelen == sizeof (err_addr)
408 && err_addr.sin_family == AF_INET
409 && memcmp (&err_addr.sin_addr, &cu->cu_raddr.sin_addr,
410 sizeof (err_addr.sin_addr)) == 0
411 && err_addr.sin_port == cu->cu_raddr.sin_port)))
412 for (cmsg = CMSG_FIRSTHDR (&msg); cmsg;
413 cmsg = CMSG_NXTHDR (&msg, cmsg))
414 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
415 {
416 e = (struct sock_extended_err *) CMSG_DATA(cmsg);
417 cu->cu_error.re_errno = e->ee_errno;
418 return (cu->cu_error.re_status = RPC_CANTRECV);
419 }
420 }
421#endif
422 do
423 {
424 fromlen = sizeof (struct sockaddr);
425 inlen = recvfrom (cu->cu_sock, cu->cu_inbuf,
426 (int) cu->cu_recvsz, 0,
427 (struct sockaddr *) &from, &fromlen);
428 }
429 while (inlen < 0 && errno == EINTR);
430 if (inlen < 0)
431 {
432 if (errno == EWOULDBLOCK)
433 continue;
434 cu->cu_error.re_errno = errno;
435 return (cu->cu_error.re_status = RPC_CANTRECV);
436 }
437 if (inlen < 4)
438 continue;
439
440 /* see if reply transaction id matches sent id.
441 Don't do this if we only wait for a replay */
442 if (xargs != NULL
443 && (*((u_int32_t *) (cu->cu_inbuf))
444 != *((u_int32_t *) (cu->cu_outbuf))))
445 continue;
446 /* we now assume we have the proper reply */
447 break;
448 }
449
450 /*
451 * now decode and validate the response
452 */
453 xdrmem_create (&reply_xdrs, cu->cu_inbuf, (u_int) inlen, XDR_DECODE);
454 ok = xdr_replymsg (&reply_xdrs, &reply_msg);
455 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
456 if (ok)
457 {
458 _seterr_reply (&reply_msg, &(cu->cu_error));
459 if (cu->cu_error.re_status == RPC_SUCCESS)
460 {
461 if (!AUTH_VALIDATE (cl->cl_auth,
462 &reply_msg.acpted_rply.ar_verf))
463 {
464 cu->cu_error.re_status = RPC_AUTHERROR;
465 cu->cu_error.re_why = AUTH_INVALIDRESP;
466 }
467 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
468 {
469 xdrs->x_op = XDR_FREE;
470 (void) xdr_opaque_auth (xdrs,
471 &(reply_msg.acpted_rply.ar_verf));
472 }
473 } /* end successful completion */
474 else
475 {
476 /* maybe our credentials need to be refreshed ... */
477 if (nrefreshes > 0 && AUTH_REFRESH (cl->cl_auth))
478 {
479 nrefreshes--;
480 goto call_again;
481 }
482 } /* end of unsuccessful completion */
483 } /* end of valid reply message */
484 else
485 {
486 cu->cu_error.re_status = RPC_CANTDECODERES;
487 }
488 return cu->cu_error.re_status;
489}
490
491static void
492clntudp_geterr (CLIENT *cl, struct rpc_err *errp)
493{
494 struct cu_data *cu = (struct cu_data *) cl->cl_private;
495
496 *errp = cu->cu_error;
497}
498
499
500static bool_t
501clntudp_freeres (CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr)
502{
503 struct cu_data *cu = (struct cu_data *) cl->cl_private;
504 XDR *xdrs = &(cu->cu_outxdrs);
505
506 xdrs->x_op = XDR_FREE;
507 return (*xdr_res) (xdrs, res_ptr);
508}
509
510static void
511clntudp_abort (void)
512{
513}
514
515static bool_t
516clntudp_control (CLIENT *cl, int request, char *info)
517{
518 struct cu_data *cu = (struct cu_data *) cl->cl_private;
519
520 switch (request)
521 {
522 case CLSET_FD_CLOSE:
523 cu->cu_closeit = TRUE;
524 break;
525 case CLSET_FD_NCLOSE:
526 cu->cu_closeit = FALSE;
527 break;
528 case CLSET_TIMEOUT:
529 cu->cu_total = *(struct timeval *) info;
530 break;
531 case CLGET_TIMEOUT:
532 *(struct timeval *) info = cu->cu_total;
533 break;
534 case CLSET_RETRY_TIMEOUT:
535 cu->cu_wait = *(struct timeval *) info;
536 break;
537 case CLGET_RETRY_TIMEOUT:
538 *(struct timeval *) info = cu->cu_wait;
539 break;
540 case CLGET_SERVER_ADDR:
541 *(struct sockaddr_in *) info = cu->cu_raddr;
542 break;
543 case CLGET_FD:
544 *(int *)info = cu->cu_sock;
545 break;
546 case CLGET_XID:
547 /*
548 * use the knowledge that xid is the
549 * first element in the call structure *.
550 * This will get the xid of the PREVIOUS call
551 */
552 *(u_long *)info = ntohl(*(u_long *)cu->cu_outbuf);
553 break;
554 case CLSET_XID:
555 /* This will set the xid of the NEXT call */
556 *(u_long *)cu->cu_outbuf = htonl(*(u_long *)info - 1);
557 /* decrement by 1 as clntudp_call() increments once */
558 break;
559 case CLGET_VERS:
560 /*
561 * This RELIES on the information that, in the call body,
562 * the version number field is the fifth field from the
563 * begining of the RPC header. MUST be changed if the
564 * call_struct is changed
565 */
566 *(u_long *)info = ntohl(*(u_long *)(cu->cu_outbuf +
567 4 * BYTES_PER_XDR_UNIT));
568 break;
569 case CLSET_VERS:
570 *(u_long *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT)
571 = htonl(*(u_long *)info);
572 break;
573 case CLGET_PROG:
574 /*
575 * This RELIES on the information that, in the call body,
576 * the program number field is the field from the
577 * begining of the RPC header. MUST be changed if the
578 * call_struct is changed
579 */
580 *(u_long *)info = ntohl(*(u_long *)(cu->cu_outbuf +
581 3 * BYTES_PER_XDR_UNIT));
582 break;
583 case CLSET_PROG:
584 *(u_long *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT)
585 = htonl(*(u_long *)info);
586 break;
587 /* The following are only possible with TI-RPC */
588 case CLGET_SVC_ADDR:
589 case CLSET_SVC_ADDR:
590 case CLSET_PUSH_TIMOD:
591 case CLSET_POP_TIMOD:
592 default:
593 return FALSE;
594 }
595 return TRUE;
596}
597
598static void
599clntudp_destroy (CLIENT *cl)
600{
601 struct cu_data *cu = (struct cu_data *) cl->cl_private;
602
603 if (cu->cu_closeit)
604 {
605 (void) close (cu->cu_sock);
606 }
607 XDR_DESTROY (&(cu->cu_outxdrs));
608 mem_free ((caddr_t) cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz));
609 mem_free ((caddr_t) cl, sizeof (CLIENT));
610}