Fix pthread_cond_*wait with requeue-PI on i386.
[glibc.git] / sunrpc / svc_unix.c
blobf22a23acda0045e64de3c9c720d30996f263c322
1 /*
2 * svc_unix.c, Server side for TCP/IP based 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.
33 * Actually implements two flavors of transporter -
34 * a unix rendezvouser (a listener and connection establisher)
35 * and a record/unix stream.
38 #include <stdio.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <rpc/rpc.h>
42 #include <rpc/svc.h>
43 #include <sys/socket.h>
44 #include <sys/uio.h>
45 #include <sys/poll.h>
46 #include <errno.h>
47 #include <stdlib.h>
48 #include <libintl.h>
50 #ifdef USE_IN_LIBIO
51 # include <wchar.h>
52 #endif
55 * Ops vector for AF_UNIX based rpc service handle
57 static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
58 static enum xprt_stat svcunix_stat (SVCXPRT *);
59 static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
60 static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
61 static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
62 static void svcunix_destroy (SVCXPRT *);
64 static const struct xp_ops svcunix_op =
66 svcunix_recv,
67 svcunix_stat,
68 svcunix_getargs,
69 svcunix_reply,
70 svcunix_freeargs,
71 svcunix_destroy
75 * Ops vector for AF_UNIX rendezvous handler
77 static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
78 static enum xprt_stat rendezvous_stat (SVCXPRT *);
79 static void svcunix_rendezvous_abort (void) __attribute__ ((__noreturn__));
81 /* This function makes sure abort() relocation goes through PLT
82 and thus can be lazy bound. */
83 static void
84 svcunix_rendezvous_abort (void)
86 abort ();
89 static const struct xp_ops svcunix_rendezvous_op =
91 rendezvous_request,
92 rendezvous_stat,
93 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
94 (bool_t (*) (SVCXPRT *, struct rpc_msg *)) svcunix_rendezvous_abort,
95 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
96 svcunix_destroy
99 static int readunix (char*, char *, int);
100 static int writeunix (char *, char *, int);
101 static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
103 struct unix_rendezvous { /* kept in xprt->xp_p1 */
104 u_int sendsize;
105 u_int recvsize;
108 struct unix_conn { /* kept in xprt->xp_p1 */
109 enum xprt_stat strm_stat;
110 u_long x_id;
111 XDR xdrs;
112 char verf_body[MAX_AUTH_BYTES];
116 * Usage:
117 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
119 * Creates, registers, and returns a (rpc) unix based transporter.
120 * Once *xprt is initialized, it is registered as a transporter
121 * see (svc.h, xprt_register). This routine returns
122 * a NULL if a problem occurred.
124 * If sock<0 then a socket is created, else sock is used.
125 * If the socket, sock is not bound to a port then svcunix_create
126 * binds it to an arbitrary port. The routine then starts a unix
127 * listener on the socket's associated port. In any (successful) case,
128 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
129 * associated port number.
131 * Since unix streams do buffered io similar to stdio, the caller can specify
132 * how big the send and receive buffers are via the second and third parms;
133 * 0 => use the system default.
135 SVCXPRT *
136 svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
138 bool_t madesock = FALSE;
139 SVCXPRT *xprt;
140 struct unix_rendezvous *r;
141 struct sockaddr_un addr;
142 socklen_t len = sizeof (struct sockaddr_in);
144 if (sock == RPC_ANYSOCK)
146 if ((sock = __socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
148 perror (_("svc_unix.c - AF_UNIX socket creation problem"));
149 return (SVCXPRT *) NULL;
151 madesock = TRUE;
153 memset (&addr, '\0', sizeof (addr));
154 addr.sun_family = AF_UNIX;
155 len = strlen (path) + 1;
156 memcpy (addr.sun_path, path, len);
157 len += sizeof (addr.sun_family);
159 __bind (sock, (struct sockaddr *) &addr, len);
161 if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0
162 || __listen (sock, SOMAXCONN) != 0)
164 perror (_("svc_unix.c - cannot getsockname or listen"));
165 if (madesock)
166 __close (sock);
167 return (SVCXPRT *) NULL;
170 r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
171 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
172 if (r == NULL || xprt == NULL)
174 __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
175 mem_free (r, sizeof (*r));
176 mem_free (xprt, sizeof (SVCXPRT));
177 return NULL;
179 r->sendsize = sendsize;
180 r->recvsize = recvsize;
181 xprt->xp_p2 = NULL;
182 xprt->xp_p1 = (caddr_t) r;
183 xprt->xp_verf = _null_auth;
184 xprt->xp_ops = &svcunix_rendezvous_op;
185 xprt->xp_port = -1;
186 xprt->xp_sock = sock;
187 xprt_register (xprt);
188 return xprt;
192 * Like svunix_create(), except the routine takes any *open* UNIX file
193 * descriptor as its first input.
195 SVCXPRT *
196 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
198 return makefd_xprt (fd, sendsize, recvsize);
201 static SVCXPRT *
202 internal_function
203 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
205 SVCXPRT *xprt;
206 struct unix_conn *cd;
208 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
209 cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
210 if (xprt == (SVCXPRT *) NULL || cd == (struct unix_conn *) NULL)
212 (void) __fxprintf (NULL, "%s: %s", "svc_unix: makefd_xprt",
213 _("out of memory\n"));
214 mem_free (xprt, sizeof (SVCXPRT));
215 mem_free (cd, sizeof (struct unix_conn));
216 return NULL;
218 cd->strm_stat = XPRT_IDLE;
219 INTUSE(xdrrec_create) (&(cd->xdrs), sendsize, recvsize,
220 (caddr_t) xprt, readunix, writeunix);
221 xprt->xp_p2 = NULL;
222 xprt->xp_p1 = (caddr_t) cd;
223 xprt->xp_verf.oa_base = cd->verf_body;
224 xprt->xp_addrlen = 0;
225 xprt->xp_ops = &svcunix_op; /* truly deals with calls */
226 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
227 xprt->xp_sock = fd;
228 xprt_register (xprt);
229 return xprt;
232 static bool_t
233 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
235 int sock;
236 struct unix_rendezvous *r;
237 struct sockaddr_un addr;
238 struct sockaddr_in in_addr;
239 socklen_t len;
241 r = (struct unix_rendezvous *) xprt->xp_p1;
242 again:
243 len = sizeof (struct sockaddr_un);
244 if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
246 if (errno == EINTR)
247 goto again;
248 return FALSE;
251 * make a new transporter (re-uses xprt)
253 memset (&in_addr, '\0', sizeof (in_addr));
254 in_addr.sin_family = AF_UNIX;
255 xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
256 memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
257 xprt->xp_addrlen = len;
258 return FALSE; /* there is never an rpc msg to be processed */
261 static enum xprt_stat
262 rendezvous_stat (SVCXPRT *xprt)
264 return XPRT_IDLE;
267 static void
268 svcunix_destroy (SVCXPRT *xprt)
270 struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
272 xprt_unregister (xprt);
273 __close (xprt->xp_sock);
274 if (xprt->xp_port != 0)
276 /* a rendezvouser socket */
277 xprt->xp_port = 0;
279 else
281 /* an actual connection socket */
282 XDR_DESTROY (&(cd->xdrs));
284 mem_free ((caddr_t) cd, sizeof (struct unix_conn));
285 mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
288 #ifdef SCM_CREDENTIALS
289 struct cmessage {
290 struct cmsghdr cmsg;
291 struct ucred cmcred;
292 /* hack to make sure we have enough memory */
293 char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
296 /* XXX This is not thread safe, but since the main functions in svc.c
297 and the rpcgen generated *_svc functions for the daemon are also not
298 thread safe and uses static global variables, it doesn't matter. */
299 static struct cmessage cm;
300 #endif
302 static int
303 __msgread (int sock, void *data, size_t cnt)
305 struct iovec iov;
306 struct msghdr msg;
307 int len;
309 iov.iov_base = data;
310 iov.iov_len = cnt;
312 msg.msg_iov = &iov;
313 msg.msg_iovlen = 1;
314 msg.msg_name = NULL;
315 msg.msg_namelen = 0;
316 #ifdef SCM_CREDENTIALS
317 msg.msg_control = (caddr_t) &cm;
318 msg.msg_controllen = sizeof (struct cmessage);
319 #endif
320 msg.msg_flags = 0;
322 #ifdef SO_PASSCRED
324 int on = 1;
325 if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
326 return -1;
328 #endif
330 restart:
331 len = __recvmsg (sock, &msg, 0);
332 if (len >= 0)
334 if (msg.msg_flags & MSG_CTRUNC || len == 0)
335 return 0;
336 else
337 return len;
339 if (errno == EINTR)
340 goto restart;
341 return -1;
344 static int
345 __msgwrite (int sock, void *data, size_t cnt)
347 #ifndef SCM_CREDENTIALS
348 /* We cannot implement this reliably. */
349 __set_errno (ENOSYS);
350 return -1;
351 #else
352 struct iovec iov;
353 struct msghdr msg;
354 struct cmsghdr *cmsg = &cm.cmsg;
355 struct ucred cred;
356 int len;
358 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
359 get?id(). But since keyserv needs geteuid(), we have no other chance.
360 It would be much better, if the kernel could pass both to the server. */
361 cred.pid = __getpid ();
362 cred.uid = __geteuid ();
363 cred.gid = __getegid ();
365 memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
366 cmsg->cmsg_level = SOL_SOCKET;
367 cmsg->cmsg_type = SCM_CREDENTIALS;
368 cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
370 iov.iov_base = data;
371 iov.iov_len = cnt;
373 msg.msg_iov = &iov;
374 msg.msg_iovlen = 1;
375 msg.msg_name = NULL;
376 msg.msg_namelen = 0;
377 msg.msg_control = cmsg;
378 msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
379 msg.msg_flags = 0;
381 restart:
382 len = __sendmsg (sock, &msg, 0);
383 if (len >= 0)
384 return len;
385 if (errno == EINTR)
386 goto restart;
387 return -1;
389 #endif
393 * reads data from the unix connection.
394 * any error is fatal and the connection is closed.
395 * (And a read of zero bytes is a half closed stream => error.)
397 static int
398 readunix (char *xprtptr, char *buf, int len)
400 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
401 int sock = xprt->xp_sock;
402 int milliseconds = 35 * 1000;
403 struct pollfd pollfd;
407 pollfd.fd = sock;
408 pollfd.events = POLLIN;
409 switch (__poll (&pollfd, 1, milliseconds))
411 case -1:
412 if (errno == EINTR)
413 continue;
414 /*FALLTHROUGH*/
415 case 0:
416 goto fatal_err;
417 default:
418 if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
419 || (pollfd.revents & POLLNVAL))
420 goto fatal_err;
421 break;
424 while ((pollfd.revents & POLLIN) == 0);
426 if ((len = __msgread (sock, buf, len)) > 0)
427 return len;
429 fatal_err:
430 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
431 return -1;
435 * writes data to the unix connection.
436 * Any error is fatal and the connection is closed.
438 static int
439 writeunix (char *xprtptr, char * buf, int len)
441 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
442 int i, cnt;
444 for (cnt = len; cnt > 0; cnt -= i, buf += i)
446 if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
448 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
449 return -1;
452 return len;
455 static enum xprt_stat
456 svcunix_stat (SVCXPRT *xprt)
458 struct unix_conn *cd =
459 (struct unix_conn *) (xprt->xp_p1);
461 if (cd->strm_stat == XPRT_DIED)
462 return XPRT_DIED;
463 if (!INTUSE(xdrrec_eof) (&(cd->xdrs)))
464 return XPRT_MOREREQS;
465 return XPRT_IDLE;
468 static bool_t
469 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
471 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
472 XDR *xdrs = &(cd->xdrs);
474 xdrs->x_op = XDR_DECODE;
475 INTUSE(xdrrec_skiprecord) (xdrs);
476 if (INTUSE(xdr_callmsg) (xdrs, msg))
478 cd->x_id = msg->rm_xid;
479 /* set up verifiers */
480 #ifdef SCM_CREDENTIALS
481 msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
482 msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
483 msg->rm_call.cb_verf.oa_length = sizeof (cm);
484 #endif
485 return TRUE;
487 cd->strm_stat = XPRT_DIED; /* XXXX */
488 return FALSE;
491 static bool_t
492 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
494 return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
495 args_ptr);
498 static bool_t
499 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
501 XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
503 xdrs->x_op = XDR_FREE;
504 return (*xdr_args) (xdrs, args_ptr);
507 static bool_t
508 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
510 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
511 XDR *xdrs = &(cd->xdrs);
512 bool_t stat;
514 xdrs->x_op = XDR_ENCODE;
515 msg->rm_xid = cd->x_id;
516 stat = INTUSE(xdr_replymsg) (xdrs, msg);
517 (void) INTUSE(xdrrec_endofrecord) (xdrs, TRUE);
518 return stat;