1998-10-26 Roland McGrath <roland@baalperazim.frob.com>
[glibc.git] / sunrpc / clnt_unix.c
blobf5d06ce5f509aedb22aa2a6cb9d4ad147f5786c8
1 /*
2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3 * unrestricted use provided that this legend is included on all tape
4 * media and as a part of the software program in whole or part. Users
5 * may copy or modify Sun RPC without charge, but are not authorized
6 * to license or distribute it to anyone else except as part of a product or
7 * program developed by the user.
9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13 * Sun RPC is provided with no support and without any obligation on the
14 * part of Sun Microsystems, Inc. to assist in its use, correction,
15 * modification or enhancement.
17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19 * OR ANY PART THEREOF.
21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22 * or profits or other special, indirect and consequential damages, even if
23 * Sun has been advised of the possibility of such damages.
25 * Sun Microsystems, Inc.
26 * 2550 Garcia Avenue
27 * Mountain View, California 94043
31 * clnt_unix.c, Implements a TCP/IP based, client side RPC.
33 * Copyright (C) 1984, Sun Microsystems, Inc.
35 * TCP based RPC supports 'batched calls'.
36 * A sequence of calls may be batched-up in a send buffer. The rpc call
37 * return immediately to the client even though the call was not necessarily
38 * sent. The batching occurs if the results' xdr routine is NULL (0) AND
39 * the rpc timeout value is zero (see clnt.h, rpc).
41 * Clients should NOT casually batch calls that in fact return results; that is,
42 * the server side should be aware that a call is batched and not produce any
43 * return message. Batched calls that produce many result messages can
44 * deadlock (netlock) the client and the server....
46 * Now go hang yourself.
49 #include <netdb.h>
50 #include <errno.h>
51 #include <stdio.h>
52 #include <unistd.h>
53 #include <rpc/rpc.h>
54 #include <sys/uio.h>
55 #include <sys/poll.h>
56 #include <sys/socket.h>
57 #include <rpc/pmap_clnt.h>
59 #define MCALL_MSG_SIZE 24
61 struct ct_data
63 int ct_sock;
64 bool_t ct_closeit;
65 struct timeval ct_wait;
66 bool_t ct_waitset; /* wait set by clnt_control? */
67 struct sockaddr_un ct_addr;
68 struct rpc_err ct_error;
69 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
70 u_int ct_mpos; /* pos after marshal */
71 XDR ct_xdrs;
74 static int readunix (char *, char *, int);
75 static int writeunix (char *, char *, int);
77 static enum clnt_stat clntunix_call (CLIENT *, u_long, xdrproc_t, caddr_t,
78 xdrproc_t, caddr_t, struct timeval);
79 static void clntunix_abort (void);
80 static void clntunix_geterr (CLIENT *, struct rpc_err *);
81 static bool_t clntunix_freeres (CLIENT *, xdrproc_t, caddr_t);
82 static bool_t clntunix_control (CLIENT *, int, char *);
83 static void clntunix_destroy (CLIENT *);
85 static struct clnt_ops unix_ops =
87 clntunix_call,
88 clntunix_abort,
89 clntunix_geterr,
90 clntunix_freeres,
91 clntunix_destroy,
92 clntunix_control
96 * Create a client handle for a tcp/ip connection.
97 * If *sockp<0, *sockp is set to a newly created TCP socket and it is
98 * connected to raddr. If *sockp non-negative then
99 * raddr is ignored. The rpc/tcp package does buffering
100 * similar to stdio, so the client must pick send and receive buffer sizes,];
101 * 0 => use the default.
102 * If raddr->sin_port is 0, then a binder on the remote machine is
103 * consulted for the right port number.
104 * NB: *sockp is copied into a private area.
105 * NB: It is the clients responsibility to close *sockp.
106 * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this
107 * something more useful.
109 CLIENT *
110 clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
111 int *sockp, u_int sendsz, u_int recvsz)
113 CLIENT *h;
114 struct ct_data *ct = (struct ct_data *) mem_alloc (sizeof (*ct));
115 struct timeval now;
116 struct rpc_msg call_msg;
117 int len;
119 h = (CLIENT *) mem_alloc (sizeof (*h));
120 if (h == NULL)
122 (void) fputs (_("clntunix_create: out of memory\n"), stderr);
123 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
124 rpc_createerr.cf_error.re_errno = errno;
125 goto fooy;
127 /* ct = (struct ct_data *) mem_alloc (sizeof (*ct)); */
128 if (ct == NULL)
130 (void) fputs (_("clntunix_create: out of memory\n"), stderr);
131 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
132 rpc_createerr.cf_error.re_errno = errno;
133 goto fooy;
137 * If no socket given, open one
139 if (*sockp < 0)
141 *sockp = __socket (AF_UNIX, SOCK_STREAM, 0);
142 len = strlen (raddr->sun_path) + sizeof (raddr->sun_family) + 1;
143 if (*sockp < 0
144 || __connect (*sockp, (struct sockaddr *) raddr, len) < 0)
146 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
147 rpc_createerr.cf_error.re_errno = errno;
148 if (*sockp != -1)
149 __close (*sockp);
150 goto fooy;
152 ct->ct_closeit = TRUE;
154 else
156 ct->ct_closeit = FALSE;
160 * Set up private data struct
162 ct->ct_sock = *sockp;
163 ct->ct_wait.tv_usec = 0;
164 ct->ct_waitset = FALSE;
165 ct->ct_addr = *raddr;
168 * Initialize call message
170 __gettimeofday (&now, (struct timezone *) 0);
171 call_msg.rm_xid = __getpid () ^ now.tv_sec ^ now.tv_usec;
172 call_msg.rm_direction = CALL;
173 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
174 call_msg.rm_call.cb_prog = prog;
175 call_msg.rm_call.cb_vers = vers;
178 * pre-serialize the static part of the call msg and stash it away
180 xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE);
181 if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
183 if (ct->ct_closeit)
184 __close (*sockp);
185 goto fooy;
187 ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
188 XDR_DESTROY (&(ct->ct_xdrs));
191 * Create a client handle which uses xdrrec for serialization
192 * and authnone for authentication.
194 xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
195 (caddr_t) ct, readunix, writeunix);
196 h->cl_ops = &unix_ops;
197 h->cl_private = (caddr_t) ct;
198 h->cl_auth = authnone_create ();
199 return h;
201 fooy:
203 * Something goofed, free stuff and barf
205 mem_free ((caddr_t) ct, sizeof (struct ct_data));
206 mem_free ((caddr_t) h, sizeof (CLIENT));
207 return (CLIENT *) NULL;
210 static enum clnt_stat
211 clntunix_call (h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
212 CLIENT *h;
213 u_long proc;
214 xdrproc_t xdr_args;
215 caddr_t args_ptr;
216 xdrproc_t xdr_results;
217 caddr_t results_ptr;
218 struct timeval timeout;
220 struct ct_data *ct = (struct ct_data *) h->cl_private;
221 XDR *xdrs = &(ct->ct_xdrs);
222 struct rpc_msg reply_msg;
223 u_long x_id;
224 u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall); /* yuk */
225 bool_t shipnow;
226 int refreshes = 2;
228 if (!ct->ct_waitset)
230 ct->ct_wait = timeout;
233 shipnow =
234 (xdr_results == (xdrproc_t) 0 && timeout.tv_sec == 0
235 && timeout.tv_usec == 0) ? FALSE : TRUE;
237 call_again:
238 xdrs->x_op = XDR_ENCODE;
239 ct->ct_error.re_status = RPC_SUCCESS;
240 x_id = ntohl (--(*msg_x_id));
241 if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
242 (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
243 (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
244 (!(*xdr_args) (xdrs, args_ptr)))
246 if (ct->ct_error.re_status == RPC_SUCCESS)
247 ct->ct_error.re_status = RPC_CANTENCODEARGS;
248 (void) xdrrec_endofrecord (xdrs, TRUE);
249 return ct->ct_error.re_status;
251 if (!xdrrec_endofrecord (xdrs, shipnow))
252 return ct->ct_error.re_status = RPC_CANTSEND;
253 if (!shipnow)
254 return RPC_SUCCESS;
256 * Hack to provide rpc-based message passing
258 if (timeout.tv_sec == 0 && timeout.tv_usec == 0)
259 return ct->ct_error.re_status = RPC_TIMEDOUT;
263 * Keep receiving until we get a valid transaction id
265 xdrs->x_op = XDR_DECODE;
266 while (TRUE)
268 reply_msg.acpted_rply.ar_verf = _null_auth;
269 reply_msg.acpted_rply.ar_results.where = NULL;
270 reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
271 if (!xdrrec_skiprecord (xdrs))
272 return ct->ct_error.re_status;
273 /* now decode and validate the response header */
274 if (!xdr_replymsg (xdrs, &reply_msg))
276 if (ct->ct_error.re_status == RPC_SUCCESS)
277 continue;
278 return ct->ct_error.re_status;
280 if (reply_msg.rm_xid == x_id)
281 break;
285 * process header
287 _seterr_reply (&reply_msg, &(ct->ct_error));
288 if (ct->ct_error.re_status == RPC_SUCCESS)
290 if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
292 ct->ct_error.re_status = RPC_AUTHERROR;
293 ct->ct_error.re_why = AUTH_INVALIDRESP;
295 else if (!(*xdr_results) (xdrs, results_ptr))
297 if (ct->ct_error.re_status == RPC_SUCCESS)
298 ct->ct_error.re_status = RPC_CANTDECODERES;
300 /* free verifier ... */
301 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
303 xdrs->x_op = XDR_FREE;
304 (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
306 } /* end successful completion */
307 else
309 /* maybe our credentials need to be refreshed ... */
310 if (refreshes-- && AUTH_REFRESH (h->cl_auth))
311 goto call_again;
312 } /* end of unsuccessful completion */
313 return ct->ct_error.re_status;
316 static void
317 clntunix_geterr (CLIENT *h, struct rpc_err *errp)
319 struct ct_data *ct = (struct ct_data *) h->cl_private;
321 *errp = ct->ct_error;
324 static bool_t
325 clntunix_freeres (cl, xdr_res, res_ptr)
326 CLIENT *cl;
327 xdrproc_t xdr_res;
328 caddr_t res_ptr;
330 struct ct_data *ct = (struct ct_data *) cl->cl_private;
331 XDR *xdrs = &(ct->ct_xdrs);
333 xdrs->x_op = XDR_FREE;
334 return (*xdr_res) (xdrs, res_ptr);
337 static void
338 clntunix_abort ()
342 static bool_t
343 clntunix_control (CLIENT *cl, int request, char *info)
345 struct ct_data *ct = (struct ct_data *) cl->cl_private;
348 switch (request)
350 case CLSET_FD_CLOSE:
351 ct->ct_closeit = TRUE;
352 break;
353 case CLSET_FD_NCLOSE:
354 ct->ct_closeit = FALSE;
355 break;
356 case CLSET_TIMEOUT:
357 ct->ct_wait = *(struct timeval *) info;
358 break;
359 case CLGET_TIMEOUT:
360 *(struct timeval *) info = ct->ct_wait;
361 break;
362 case CLGET_SERVER_ADDR:
363 *(struct sockaddr_un *) info = ct->ct_addr;
364 break;
365 case CLGET_FD:
366 *(int *)info = ct->ct_sock;
367 break;
368 case CLGET_XID:
370 * use the knowledge that xid is the
371 * first element in the call structure *.
372 * This will get the xid of the PREVIOUS call
374 *(u_long *) info = ntohl (*(u_long *)ct->ct_mcall);
375 break;
376 case CLSET_XID:
377 /* This will set the xid of the NEXT call */
378 *(u_long *) ct->ct_mcall = htonl (*(u_long *)info - 1);
379 /* decrement by 1 as clntunix_call() increments once */
380 case CLGET_VERS:
382 * This RELIES on the information that, in the call body,
383 * the version number field is the fifth field from the
384 * begining of the RPC header. MUST be changed if the
385 * call_struct is changed
387 *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
388 + 4 * BYTES_PER_XDR_UNIT));
389 break;
390 case CLSET_VERS:
391 *(u_long *) (ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT)
392 = htonl (*(u_long *) info);
393 break;
394 case CLGET_PROG:
396 * This RELIES on the information that, in the call body,
397 * the program number field is the field from the
398 * begining of the RPC header. MUST be changed if the
399 * call_struct is changed
401 *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
402 + 3 * BYTES_PER_XDR_UNIT));
403 break;
404 case CLSET_PROG:
405 *(u_long *) (ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT)
406 = htonl(*(u_long *) info);
407 break;
408 /* The following are only possible with TI-RPC */
409 case CLGET_RETRY_TIMEOUT:
410 case CLSET_RETRY_TIMEOUT:
411 case CLGET_SVC_ADDR:
412 case CLSET_SVC_ADDR:
413 case CLSET_PUSH_TIMOD:
414 case CLSET_POP_TIMOD:
415 default:
416 return FALSE;
418 return TRUE;
422 static void
423 clntunix_destroy (CLIENT *h)
425 struct ct_data *ct =
426 (struct ct_data *) h->cl_private;
428 if (ct->ct_closeit)
430 (void) close (ct->ct_sock);
432 XDR_DESTROY (&(ct->ct_xdrs));
433 mem_free ((caddr_t) ct, sizeof (struct ct_data));
434 mem_free ((caddr_t) h, sizeof (CLIENT));
437 struct cmessage {
438 struct cmsghdr cmsg;
439 struct ucred cmcred;
442 static int
443 __msgread (int sock, void *buf, size_t cnt)
445 struct iovec iov[1];
446 struct msghdr msg;
447 struct cmessage cm;
448 int on = 1;
450 iov[0].iov_base = buf;
451 iov[0].iov_len = cnt;
453 msg.msg_iov = iov;
454 msg.msg_iovlen = 1;
455 msg.msg_name = NULL;
456 msg.msg_namelen = 0;
457 msg.msg_control = (caddr_t)&cm;
458 msg.msg_controllen = sizeof(struct cmessage);
459 msg.msg_flags = 0;
461 #ifdef SO_PASSCRED
462 if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
463 return -1;
464 #endif
466 return recvmsg (sock, &msg, 0);
469 static int
470 __msgwrite (int sock, void *buf, size_t cnt)
472 #ifndef SCM_CREDENTIALS
473 /* We cannot implement this reliably. */
474 __set_errno (ENOSYS);
475 return -1;
476 #else
477 struct iovec iov[1];
478 struct msghdr msg;
479 struct cmessage cm;
481 iov[0].iov_base = buf;
482 iov[0].iov_len = cnt;
484 cm.cmsg.cmsg_type = SCM_CREDENTIALS;
485 cm.cmsg.cmsg_level = SOL_SOCKET;
486 cm.cmsg.cmsg_len = sizeof (struct cmessage);
487 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
488 get?id(). But since keyserv needs geteuid(), we have no other chance.
489 It would be much better, if the kernel could pass both to the server. */
490 cm.cmcred.pid = __getpid ();
491 cm.cmcred.uid = __geteuid ();
492 cm.cmcred.gid = __getegid ();
494 msg.msg_iov = iov;
495 msg.msg_iovlen = 1;
496 msg.msg_name = NULL;
497 msg.msg_namelen = 0;
498 msg.msg_control = (caddr_t) &cm;
499 msg.msg_controllen = sizeof (struct cmessage);
500 msg.msg_flags = 0;
502 return sendmsg (sock, &msg, 0);
503 #endif
508 * Interface between xdr serializer and unix connection.
509 * Behaves like the system calls, read & write, but keeps some error state
510 * around for the rpc level.
512 static int
513 readunix (char *ctptr, char *buf, int len)
515 struct ct_data *ct = (struct ct_data *) ctptr;
516 struct pollfd fd;
517 int milliseconds = ((ct->ct_wait.tv_sec * 1000)
518 + (ct->ct_wait.tv_usec / 1000));
520 if (len == 0)
521 return 0;
523 fd.fd = ct->ct_sock;
524 fd.events = POLLIN;
525 while (TRUE)
527 switch (__poll (&fd, 1, milliseconds))
529 case 0:
530 ct->ct_error.re_status = RPC_TIMEDOUT;
531 return -1;
533 case -1:
534 if (errno == EINTR)
535 continue;
536 ct->ct_error.re_status = RPC_CANTRECV;
537 ct->ct_error.re_errno = errno;
538 return -1;
540 break;
542 switch (len = __msgread (ct->ct_sock, buf, len))
545 case 0:
546 /* premature eof */
547 ct->ct_error.re_errno = ECONNRESET;
548 ct->ct_error.re_status = RPC_CANTRECV;
549 len = -1; /* it's really an error */
550 break;
552 case -1:
553 ct->ct_error.re_errno = errno;
554 ct->ct_error.re_status = RPC_CANTRECV;
555 break;
557 return len;
560 static int
561 writeunix (char *ctptr, char *buf, int len)
563 int i, cnt;
564 struct ct_data *ct = (struct ct_data *) ctptr;
566 for (cnt = len; cnt > 0; cnt -= i, buf += i)
568 if ((i = __msgwrite (ct->ct_sock, buf, cnt)) == -1)
570 ct->ct_error.re_errno = errno;
571 ct->ct_error.re_status = RPC_CANTSEND;
572 return -1;
575 return len;