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.
27 * Mountain View, California 94043
29 * @(#)svc_unix.c 1.21 87/08/11 Copyr 1984 Sun Micro
30 * @(#)svc_unix.c 2.2 88/08/01 4.0 RPCSRC
31 * $FreeBSD: src/lib/libc/rpc/svc_unix.c,v 1.7.2.2 2001/09/05 22:29:23 dec Exp $
32 * $DragonFly: src/lib/libc/rpc/svc_unix.c,v 1.5 2005/11/13 12:27:04 swildner Exp $
36 * svc_unix.c, Server side for TCP/IP based RPC.
38 * Copyright (C) 1984, Sun Microsystems, Inc.
40 * Actually implements two flavors of transporter -
41 * a unix rendezvouser (a listner and connection establisher)
42 * and a record/unix stream.
45 #include "namespace.h"
51 #include <sys/socket.h>
55 #include "un-namespace.h"
58 * Ops vector for AF_UNIX based rpc service handle
60 static bool_t
svcunix_recv();
61 static enum xprt_stat
svcunix_stat();
62 static bool_t
svcunix_getargs();
63 static bool_t
svcunix_reply();
64 static bool_t
svcunix_freeargs();
65 static void svcunix_destroy();
67 static struct xp_ops svcunix_op
= {
77 * Ops vector for TCP/IP rendezvous handler
79 static bool_t
rendezvous_request();
80 static enum xprt_stat
rendezvous_stat();
82 static struct xp_ops svcunix_rendezvous_op
= {
91 static int readunix(), writeunix();
92 static SVCXPRT
*makefd_xprt();
94 struct unix_rendezvous
{ /* kept in xprt->xp_p1 */
99 struct unix_conn
{ /* kept in xprt->xp_p1 */
100 enum xprt_stat strm_stat
;
103 char verf_body
[MAX_AUTH_BYTES
];
109 struct cmsgcred cmcred
;
112 static struct cmessage cm
;
115 __msgread(int sock
, void *buf
, size_t cnt
)
120 bzero((char *)&cm
, sizeof(cm
));
121 iov
[0].iov_base
= buf
;
122 iov
[0].iov_len
= cnt
;
128 msg
.msg_control
= (caddr_t
)&cm
;
129 msg
.msg_controllen
= sizeof(struct cmessage
);
132 return(_recvmsg(sock
, &msg
, 0));
136 __msgwrite(int sock
, void *buf
, size_t cnt
)
141 bzero((char *)&cm
, sizeof(cm
));
142 iov
[0].iov_base
= buf
;
143 iov
[0].iov_len
= cnt
;
145 cm
.cmsg
.cmsg_type
= SCM_CREDS
;
146 cm
.cmsg
.cmsg_level
= SOL_SOCKET
;
147 cm
.cmsg
.cmsg_len
= sizeof(struct cmessage
);
153 msg
.msg_control
= (caddr_t
)&cm
;
154 msg
.msg_controllen
= sizeof(struct cmessage
);
157 return(_sendmsg(sock
, &msg
, 0));
162 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
164 * Creates, registers, and returns a (rpc) unix based transporter.
165 * Once *xprt is initialized, it is registered as a transporter
166 * see (svc.h, xprt_register). This routine returns
167 * a NULL if a problem occurred.
169 * If sock<0 then a socket is created, else sock is used.
170 * If the socket, sock is not bound to a port then svcunix_create
171 * binds it to an arbitrary port. The routine then starts a unix
172 * listener on the socket's associated port. In any (successful) case,
173 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
174 * associated port number.
176 * Since unix streams do buffered io similar to stdio, the caller can specify
177 * how big the send and receive buffers are via the second and third parms;
178 * 0 => use the system default.
181 svcunix_create(int sock
, u_int sendsize
, u_int recvsize
, char *path
)
183 bool_t madesock
= FALSE
;
185 struct unix_rendezvous
*r
;
186 struct sockaddr_un addr
;
187 int len
= sizeof(struct sockaddr_un
);
189 if (sock
== RPC_ANYSOCK
) {
190 if ((sock
= _socket(AF_UNIX
, SOCK_STREAM
, 0)) < 0) {
191 perror("svc_unix.c - AF_UNIX socket creation problem");
192 return ((SVCXPRT
*)NULL
);
196 memset(&addr
, 0, sizeof (addr
));
197 addr
.sun_family
= AF_UNIX
;
198 strcpy(addr
.sun_path
, path
);
199 len
= strlen(addr
.sun_path
) + sizeof(addr
.sun_family
) +
200 sizeof(addr
.sun_len
) + 1;
203 _bind(sock
, (struct sockaddr
*)&addr
, len
);
205 if ((_getsockname(sock
, (struct sockaddr
*)&addr
, &len
) != 0) ||
206 (_listen(sock
, 2) != 0)) {
207 perror("svc_unix.c - cannot getsockname or listen");
210 return ((SVCXPRT
*)NULL
);
212 r
= (struct unix_rendezvous
*)mem_alloc(sizeof(*r
));
214 fprintf(stderr
, "svcunix_create: out of memory\n");
217 r
->sendsize
= sendsize
;
218 r
->recvsize
= recvsize
;
219 xprt
= (SVCXPRT
*)mem_alloc(sizeof(SVCXPRT
));
221 fprintf(stderr
, "svcunix_create: out of memory\n");
225 xprt
->xp_p1
= (caddr_t
)r
;
226 xprt
->xp_verf
= _null_auth
;
227 xprt
->xp_ops
= &svcunix_rendezvous_op
;
228 xprt
->xp_port
= -1 /*ntohs(addr.sin_port)*/;
229 xprt
->xp_sock
= sock
;
235 * Like svunix_create(), except the routine takes any *open* UNIX file
236 * descriptor as its first input.
239 svcunixfd_create(int fd
, u_int sendsize
, u_int recvsize
)
242 return (makefd_xprt(fd
, sendsize
, recvsize
));
246 makefd_xprt(int fd
, u_int sendsize
, u_int recvsize
)
249 struct unix_conn
*cd
;
251 xprt
= (SVCXPRT
*)mem_alloc(sizeof(SVCXPRT
));
252 if (xprt
== (SVCXPRT
*)NULL
) {
253 fprintf(stderr
, "svc_unix: makefd_xprt: out of memory\n");
256 cd
= (struct unix_conn
*)mem_alloc(sizeof(struct unix_conn
));
257 if (cd
== (struct unix_conn
*)NULL
) {
258 fprintf(stderr
, "svc_unix: makefd_xprt: out of memory\n");
259 mem_free((char *) xprt
, sizeof(SVCXPRT
));
260 xprt
= (SVCXPRT
*)NULL
;
263 cd
->strm_stat
= XPRT_IDLE
;
264 xdrrec_create(&(cd
->xdrs
), sendsize
, recvsize
,
265 (caddr_t
)xprt
, readunix
, writeunix
);
267 xprt
->xp_p1
= (caddr_t
)cd
;
268 xprt
->xp_verf
.oa_base
= cd
->verf_body
;
269 xprt
->xp_addrlen
= 0;
270 xprt
->xp_ops
= &svcunix_op
; /* truely deals with calls */
271 xprt
->xp_port
= 0; /* this is a connection, not a rendezvouser */
279 rendezvous_request(SVCXPRT
*xprt
)
282 struct unix_rendezvous
*r
;
283 struct sockaddr_un addr
;
284 struct sockaddr_in in_addr
;
287 r
= (struct unix_rendezvous
*)xprt
->xp_p1
;
289 len
= sizeof(struct sockaddr_in
);
290 if ((sock
= _accept(xprt
->xp_sock
, (struct sockaddr
*)&addr
,
298 * make a new transporter (re-uses xprt)
300 bzero((char *)&in_addr
, sizeof(in_addr
));
301 in_addr
.sin_family
= AF_UNIX
;
302 xprt
= makefd_xprt(sock
, r
->sendsize
, r
->recvsize
);
303 xprt
->xp_raddr
= in_addr
;
304 xprt
->xp_addrlen
= len
;
305 return (FALSE
); /* there is never an rpc msg to be processed */
308 static enum xprt_stat
309 rendezvous_stat(void)
316 svcunix_destroy(SVCXPRT
*xprt
)
318 struct unix_conn
*cd
= (struct unix_conn
*)xprt
->xp_p1
;
320 xprt_unregister(xprt
);
321 _close(xprt
->xp_sock
);
322 if (xprt
->xp_port
!= 0) {
323 /* a rendezvouser socket */
326 /* an actual connection socket */
327 XDR_DESTROY(&(cd
->xdrs
));
329 mem_free((caddr_t
)cd
, sizeof(struct unix_conn
));
330 mem_free((caddr_t
)xprt
, sizeof(SVCXPRT
));
334 * All read operations timeout after 35 seconds.
335 * A timeout is fatal for the connection.
337 static struct timeval wait_per_try
= { 35, 0 };
340 * reads data from the unix conection.
341 * any error is fatal and the connection is closed.
342 * (And a read of zero bytes is a half closed stream => error.)
344 * Note: we have to be careful here not to allow ourselves to become
345 * blocked too long in this routine. While we're waiting for data from one
346 * client, another client may be trying to connect. To avoid this situation,
347 * some code from svc_run() is transplanted here: the _select() loop checks
348 * all RPC descriptors including the one we want and calls svc_getreqset2()
349 * to handle new requests if any are detected.
352 readunix(SVCXPRT
*xprt
, caddr_t buf
, int len
)
354 int sock
= xprt
->xp_sock
;
355 struct timeval start
, delta
, tv
;
356 struct timeval tmp1
, tmp2
;
358 extern fd_set
*__svc_fdset
;
359 extern int __svc_fdsetsize
;
361 delta
= wait_per_try
;
363 gettimeofday(&start
, NULL
);
365 int bytes
= howmany(__svc_fdsetsize
, NFDBITS
) *
369 fds
= (fd_set
*)malloc(bytes
);
372 memcpy(fds
, __svc_fdset
, bytes
);
374 /* XXX we know the other bits are still clear */
376 tv
= delta
; /* in case _select() implements writeback */
377 switch (_select(svc_maxfd
+ 1, fds
, NULL
, NULL
, &tv
)) {
379 memset(fds
, 0, bytes
);
382 gettimeofday(&tmp1
, NULL
);
383 timersub(&tmp1
, &start
, &tmp2
);
384 timersub(&wait_per_try
, &tmp2
, &tmp1
);
385 if (tmp1
.tv_sec
< 0 || !timerisset(&tmp1
))
392 if (!FD_ISSET(sock
, fds
)) {
393 svc_getreqset2(fds
, svc_maxfd
+ 1);
394 gettimeofday(&tmp1
, NULL
);
395 timersub(&tmp1
, &start
, &tmp2
);
396 timersub(&wait_per_try
, &tmp2
, &tmp1
);
397 if (tmp1
.tv_sec
< 0 || !timerisset(&tmp1
))
403 } while (!FD_ISSET(sock
, fds
));
404 if ((len
= __msgread(sock
, buf
, len
)) > 0) {
410 ((struct unix_conn
*)(xprt
->xp_p1
))->strm_stat
= XPRT_DIED
;
417 * writes data to the unix connection.
418 * Any error is fatal and the connection is closed.
421 writeunix(SVCXPRT
*xprt
, caddr_t buf
, int len
)
425 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
+= i
) {
426 if ((i
= __msgwrite(xprt
->xp_sock
, buf
, cnt
)) < 0) {
427 ((struct unix_conn
*)(xprt
->xp_p1
))->strm_stat
=
435 static enum xprt_stat
436 svcunix_stat(SVCXPRT
*xprt
)
438 struct unix_conn
*cd
=
439 (struct unix_conn
*)(xprt
->xp_p1
);
441 if (cd
->strm_stat
== XPRT_DIED
)
443 if (! xdrrec_eof(&(cd
->xdrs
)))
444 return (XPRT_MOREREQS
);
449 svcunix_recv(SVCXPRT
*xprt
, struct rpc_msg
*msg
)
451 struct unix_conn
*cd
=
452 (struct unix_conn
*)(xprt
->xp_p1
);
453 XDR
*xdrs
= &(cd
->xdrs
);
455 xdrs
->x_op
= XDR_DECODE
;
456 xdrrec_skiprecord(xdrs
);
457 if (xdr_callmsg(xdrs
, msg
)) {
458 cd
->x_id
= msg
->rm_xid
;
459 /* set up verifiers */
460 msg
->rm_call
.cb_verf
.oa_flavor
= AUTH_UNIX
;
461 msg
->rm_call
.cb_verf
.oa_base
= (caddr_t
)&cm
;
462 msg
->rm_call
.cb_verf
.oa_length
= sizeof(cm
);
465 cd
->strm_stat
= XPRT_DIED
; /* XXXX */
470 svcunix_getargs(SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
473 return ((*xdr_args
)(&(((struct unix_conn
*)(xprt
->xp_p1
))->xdrs
), args_ptr
));
477 svcunix_freeargs(SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
480 &(((struct unix_conn
*)(xprt
->xp_p1
))->xdrs
);
482 xdrs
->x_op
= XDR_FREE
;
483 return ((*xdr_args
)(xdrs
, args_ptr
));
487 svcunix_reply(SVCXPRT
*xprt
, struct rpc_msg
*msg
)
489 struct unix_conn
*cd
=
490 (struct unix_conn
*)(xprt
->xp_p1
);
491 XDR
*xdrs
= &(cd
->xdrs
);
494 xdrs
->x_op
= XDR_ENCODE
;
495 msg
->rm_xid
= cd
->x_id
;
496 stat
= xdr_replymsg(xdrs
, msg
);
497 xdrrec_endofrecord(xdrs
, TRUE
);