Declare wcs functions only if compiling with MBS_SUPPORT. Don't use #elif for tradi...
[glibc.git] / sunrpc / clnt_unix.c
blob19356ad032b7553744e5439bebc92fa3551f4cfd
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 <libintl.h>
54 #include <rpc/rpc.h>
55 #include <sys/uio.h>
56 #include <sys/poll.h>
57 #include <sys/socket.h>
58 #include <rpc/pmap_clnt.h>
60 extern u_long _create_xid (void);
62 #define MCALL_MSG_SIZE 24
64 struct ct_data
66 int ct_sock;
67 bool_t ct_closeit;
68 struct timeval ct_wait;
69 bool_t ct_waitset; /* wait set by clnt_control? */
70 struct sockaddr_un ct_addr;
71 struct rpc_err ct_error;
72 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
73 u_int ct_mpos; /* pos after marshal */
74 XDR ct_xdrs;
77 static int readunix (char *, char *, int);
78 static int writeunix (char *, char *, int);
80 static enum clnt_stat clntunix_call (CLIENT *, u_long, xdrproc_t, caddr_t,
81 xdrproc_t, caddr_t, struct timeval);
82 static void clntunix_abort (void);
83 static void clntunix_geterr (CLIENT *, struct rpc_err *);
84 static bool_t clntunix_freeres (CLIENT *, xdrproc_t, caddr_t);
85 static bool_t clntunix_control (CLIENT *, int, char *);
86 static void clntunix_destroy (CLIENT *);
88 static struct clnt_ops unix_ops =
90 clntunix_call,
91 clntunix_abort,
92 clntunix_geterr,
93 clntunix_freeres,
94 clntunix_destroy,
95 clntunix_control
99 * Create a client handle for a tcp/ip connection.
100 * If *sockp<0, *sockp is set to a newly created TCP socket and it is
101 * connected to raddr. If *sockp non-negative then
102 * raddr is ignored. The rpc/tcp package does buffering
103 * similar to stdio, so the client must pick send and receive buffer sizes,];
104 * 0 => use the default.
105 * If raddr->sin_port is 0, then a binder on the remote machine is
106 * consulted for the right port number.
107 * NB: *sockp is copied into a private area.
108 * NB: It is the clients responsibility to close *sockp.
109 * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this
110 * something more useful.
112 CLIENT *
113 clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
114 int *sockp, u_int sendsz, u_int recvsz)
116 CLIENT *h;
117 struct ct_data *ct = (struct ct_data *) mem_alloc (sizeof (*ct));
118 struct rpc_msg call_msg;
119 int len;
121 h = (CLIENT *) mem_alloc (sizeof (*h));
122 if (h == NULL)
124 struct rpc_createerr *ce = &get_rpc_createerr ();
125 (void) fputs (_("clntunix_create: out of memory\n"), stderr);
126 ce->cf_stat = RPC_SYSTEMERROR;
127 ce->cf_error.re_errno = errno;
128 goto fooy;
130 /* ct = (struct ct_data *) mem_alloc (sizeof (*ct)); */
131 if (ct == NULL)
133 struct rpc_createerr *ce = &get_rpc_createerr ();
134 (void) fputs (_("clntunix_create: out of memory\n"), stderr);
135 ce->cf_stat = RPC_SYSTEMERROR;
136 ce->cf_error.re_errno = errno;
137 goto fooy;
141 * If no socket given, open one
143 if (*sockp < 0)
145 *sockp = __socket (AF_UNIX, SOCK_STREAM, 0);
146 len = strlen (raddr->sun_path) + sizeof (raddr->sun_family) + 1;
147 if (*sockp < 0
148 || __connect (*sockp, (struct sockaddr *) raddr, len) < 0)
150 struct rpc_createerr *ce = &get_rpc_createerr ();
151 ce->cf_stat = RPC_SYSTEMERROR;
152 ce->cf_error.re_errno = errno;
153 if (*sockp != -1)
154 __close (*sockp);
155 goto fooy;
157 ct->ct_closeit = TRUE;
159 else
161 ct->ct_closeit = FALSE;
165 * Set up private data struct
167 ct->ct_sock = *sockp;
168 ct->ct_wait.tv_usec = 0;
169 ct->ct_waitset = FALSE;
170 ct->ct_addr = *raddr;
173 * Initialize call message
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 = prog;
179 call_msg.rm_call.cb_vers = vers;
182 * pre-serialize the static part of the call msg and stash it away
184 xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE);
185 if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
187 if (ct->ct_closeit)
188 __close (*sockp);
189 goto fooy;
191 ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
192 XDR_DESTROY (&(ct->ct_xdrs));
195 * Create a client handle which uses xdrrec for serialization
196 * and authnone for authentication.
198 xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
199 (caddr_t) ct, readunix, writeunix);
200 h->cl_ops = &unix_ops;
201 h->cl_private = (caddr_t) ct;
202 h->cl_auth = authnone_create ();
203 return h;
205 fooy:
207 * Something goofed, free stuff and barf
209 mem_free ((caddr_t) ct, sizeof (struct ct_data));
210 mem_free ((caddr_t) h, sizeof (CLIENT));
211 return (CLIENT *) NULL;
214 static enum clnt_stat
215 clntunix_call (h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
216 CLIENT *h;
217 u_long proc;
218 xdrproc_t xdr_args;
219 caddr_t args_ptr;
220 xdrproc_t xdr_results;
221 caddr_t results_ptr;
222 struct timeval timeout;
224 struct ct_data *ct = (struct ct_data *) h->cl_private;
225 XDR *xdrs = &(ct->ct_xdrs);
226 struct rpc_msg reply_msg;
227 u_long x_id;
228 u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall); /* yuk */
229 bool_t shipnow;
230 int refreshes = 2;
232 if (!ct->ct_waitset)
234 ct->ct_wait = timeout;
237 shipnow =
238 (xdr_results == (xdrproc_t) 0 && ct->ct_wait.tv_sec == 0
239 && ct->ct_wait.tv_usec == 0) ? FALSE : TRUE;
241 call_again:
242 xdrs->x_op = XDR_ENCODE;
243 ct->ct_error.re_status = RPC_SUCCESS;
244 x_id = ntohl (--(*msg_x_id));
245 if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
246 (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
247 (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
248 (!(*xdr_args) (xdrs, args_ptr)))
250 if (ct->ct_error.re_status == RPC_SUCCESS)
251 ct->ct_error.re_status = RPC_CANTENCODEARGS;
252 (void) xdrrec_endofrecord (xdrs, TRUE);
253 return ct->ct_error.re_status;
255 if (!xdrrec_endofrecord (xdrs, shipnow))
256 return ct->ct_error.re_status = RPC_CANTSEND;
257 if (!shipnow)
258 return RPC_SUCCESS;
260 * Hack to provide rpc-based message passing
262 if (ct->ct_wait.tv_sec == 0 && ct->ct_wait.tv_usec == 0)
263 return ct->ct_error.re_status = RPC_TIMEDOUT;
267 * Keep receiving until we get a valid transaction id
269 xdrs->x_op = XDR_DECODE;
270 while (TRUE)
272 reply_msg.acpted_rply.ar_verf = _null_auth;
273 reply_msg.acpted_rply.ar_results.where = NULL;
274 reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
275 if (!xdrrec_skiprecord (xdrs))
276 return ct->ct_error.re_status;
277 /* now decode and validate the response header */
278 if (!xdr_replymsg (xdrs, &reply_msg))
280 if (ct->ct_error.re_status == RPC_SUCCESS)
281 continue;
282 return ct->ct_error.re_status;
284 if (reply_msg.rm_xid == x_id)
285 break;
289 * process header
291 _seterr_reply (&reply_msg, &(ct->ct_error));
292 if (ct->ct_error.re_status == RPC_SUCCESS)
294 if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
296 ct->ct_error.re_status = RPC_AUTHERROR;
297 ct->ct_error.re_why = AUTH_INVALIDRESP;
299 else if (!(*xdr_results) (xdrs, results_ptr))
301 if (ct->ct_error.re_status == RPC_SUCCESS)
302 ct->ct_error.re_status = RPC_CANTDECODERES;
304 /* free verifier ... */
305 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
307 xdrs->x_op = XDR_FREE;
308 (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
310 } /* end successful completion */
311 else
313 /* maybe our credentials need to be refreshed ... */
314 if (refreshes-- && AUTH_REFRESH (h->cl_auth))
315 goto call_again;
316 } /* end of unsuccessful completion */
317 return ct->ct_error.re_status;
320 static void
321 clntunix_geterr (CLIENT *h, struct rpc_err *errp)
323 struct ct_data *ct = (struct ct_data *) h->cl_private;
325 *errp = ct->ct_error;
328 static bool_t
329 clntunix_freeres (cl, xdr_res, res_ptr)
330 CLIENT *cl;
331 xdrproc_t xdr_res;
332 caddr_t res_ptr;
334 struct ct_data *ct = (struct ct_data *) cl->cl_private;
335 XDR *xdrs = &(ct->ct_xdrs);
337 xdrs->x_op = XDR_FREE;
338 return (*xdr_res) (xdrs, res_ptr);
341 static void
342 clntunix_abort ()
346 static bool_t
347 clntunix_control (CLIENT *cl, int request, char *info)
349 struct ct_data *ct = (struct ct_data *) cl->cl_private;
352 switch (request)
354 case CLSET_FD_CLOSE:
355 ct->ct_closeit = TRUE;
356 break;
357 case CLSET_FD_NCLOSE:
358 ct->ct_closeit = FALSE;
359 break;
360 case CLSET_TIMEOUT:
361 ct->ct_wait = *(struct timeval *) info;
362 break;
363 case CLGET_TIMEOUT:
364 *(struct timeval *) info = ct->ct_wait;
365 break;
366 case CLGET_SERVER_ADDR:
367 *(struct sockaddr_un *) info = ct->ct_addr;
368 break;
369 case CLGET_FD:
370 *(int *)info = ct->ct_sock;
371 break;
372 case CLGET_XID:
374 * use the knowledge that xid is the
375 * first element in the call structure *.
376 * This will get the xid of the PREVIOUS call
378 *(u_long *) info = ntohl (*(u_long *)ct->ct_mcall);
379 break;
380 case CLSET_XID:
381 /* This will set the xid of the NEXT call */
382 *(u_long *) ct->ct_mcall = htonl (*(u_long *)info - 1);
383 /* decrement by 1 as clntunix_call() increments once */
384 case CLGET_VERS:
386 * This RELIES on the information that, in the call body,
387 * the version number field is the fifth field from the
388 * begining of the RPC header. MUST be changed if the
389 * call_struct is changed
391 *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
392 + 4 * BYTES_PER_XDR_UNIT));
393 break;
394 case CLSET_VERS:
395 *(u_long *) (ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT)
396 = htonl (*(u_long *) info);
397 break;
398 case CLGET_PROG:
400 * This RELIES on the information that, in the call body,
401 * the program number field is the field from the
402 * begining of the RPC header. MUST be changed if the
403 * call_struct is changed
405 *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
406 + 3 * BYTES_PER_XDR_UNIT));
407 break;
408 case CLSET_PROG:
409 *(u_long *) (ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT)
410 = htonl(*(u_long *) info);
411 break;
412 /* The following are only possible with TI-RPC */
413 case CLGET_RETRY_TIMEOUT:
414 case CLSET_RETRY_TIMEOUT:
415 case CLGET_SVC_ADDR:
416 case CLSET_SVC_ADDR:
417 case CLSET_PUSH_TIMOD:
418 case CLSET_POP_TIMOD:
419 default:
420 return FALSE;
422 return TRUE;
426 static void
427 clntunix_destroy (CLIENT *h)
429 struct ct_data *ct =
430 (struct ct_data *) h->cl_private;
432 if (ct->ct_closeit)
434 (void) __close (ct->ct_sock);
436 XDR_DESTROY (&(ct->ct_xdrs));
437 mem_free ((caddr_t) ct, sizeof (struct ct_data));
438 mem_free ((caddr_t) h, sizeof (CLIENT));
441 static int
442 __msgread (int sock, void *data, size_t cnt)
444 struct iovec iov;
445 struct msghdr msg;
446 #ifdef SCM_CREDENTIALS
447 static char cm[CMSG_SPACE(sizeof (struct ucred))];
448 #endif
449 int len;
451 iov.iov_base = data;
452 iov.iov_len = cnt;
454 msg.msg_iov = &iov;
455 msg.msg_iovlen = 1;
456 msg.msg_name = NULL;
457 msg.msg_namelen = 0;
458 #ifdef SCM_CREDENTIALS
459 msg.msg_control = (caddr_t) &cm;
460 msg.msg_controllen = CMSG_SPACE(sizeof (struct ucred));
461 #endif
462 msg.msg_flags = 0;
464 #ifdef SO_PASSCRED
466 int on = 1;
467 if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
468 return -1;
470 #endif
472 restart:
473 len = recvmsg (sock, &msg, 0);
474 if (len >= 0)
476 if (msg.msg_flags & MSG_CTRUNC || len == 0)
477 return 0;
478 else
479 return len;
481 if (errno == EINTR)
482 goto restart;
483 return -1;
486 static int
487 __msgwrite (int sock, void *data, size_t cnt)
489 #ifndef SCM_CREDENTIALS
490 /* We cannot implement this reliably. */
491 __set_errno (ENOSYS);
492 return -1;
493 #else
494 struct iovec iov;
495 struct msghdr msg;
496 struct cmsghdr *cmsg = alloca (CMSG_SPACE(sizeof (struct ucred)));
497 struct ucred cred;
498 int len;
500 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
501 get?id(). But since keyserv needs geteuid(), we have no other chance.
502 It would be much better, if the kernel could pass both to the server. */
503 cred.pid = __getpid ();
504 cred.uid = __geteuid ();
505 cred.gid = __getegid ();
507 memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
508 cmsg->cmsg_level = SOL_SOCKET;
509 cmsg->cmsg_type = SCM_CREDENTIALS;
510 cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
512 iov.iov_base = data;
513 iov.iov_len = cnt;
515 msg.msg_iov = &iov;
516 msg.msg_iovlen = 1;
517 msg.msg_name = NULL;
518 msg.msg_namelen = 0;
519 msg.msg_control = cmsg;
520 msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
521 msg.msg_flags = 0;
523 restart:
524 len = sendmsg (sock, &msg, 0);
525 if (len >= 0)
526 return len;
527 if (errno == EINTR)
528 goto restart;
529 return -1;
531 #endif
536 * Interface between xdr serializer and unix connection.
537 * Behaves like the system calls, read & write, but keeps some error state
538 * around for the rpc level.
540 static int
541 readunix (char *ctptr, char *buf, int len)
543 struct ct_data *ct = (struct ct_data *) ctptr;
544 struct pollfd fd;
545 int milliseconds = ((ct->ct_wait.tv_sec * 1000)
546 + (ct->ct_wait.tv_usec / 1000));
548 if (len == 0)
549 return 0;
551 fd.fd = ct->ct_sock;
552 fd.events = POLLIN;
553 while (TRUE)
555 switch (__poll (&fd, 1, milliseconds))
557 case 0:
558 ct->ct_error.re_status = RPC_TIMEDOUT;
559 return -1;
561 case -1:
562 if (errno == EINTR)
563 continue;
564 ct->ct_error.re_status = RPC_CANTRECV;
565 ct->ct_error.re_errno = errno;
566 return -1;
568 break;
570 switch (len = __msgread (ct->ct_sock, buf, len))
573 case 0:
574 /* premature eof */
575 ct->ct_error.re_errno = ECONNRESET;
576 ct->ct_error.re_status = RPC_CANTRECV;
577 len = -1; /* it's really an error */
578 break;
580 case -1:
581 ct->ct_error.re_errno = errno;
582 ct->ct_error.re_status = RPC_CANTRECV;
583 break;
585 return len;
588 static int
589 writeunix (char *ctptr, char *buf, int len)
591 int i, cnt;
592 struct ct_data *ct = (struct ct_data *) ctptr;
594 for (cnt = len; cnt > 0; cnt -= i, buf += i)
596 if ((i = __msgwrite (ct->ct_sock, buf, cnt)) == -1)
598 ct->ct_error.re_errno = errno;
599 ct->ct_error.re_status = RPC_CANTSEND;
600 return -1;
603 return len;