diff options
-rw-r--r-- | usr.sbin/ypserv/Makefile | 2 | ||||
-rw-r--r-- | usr.sbin/ypserv/yp_async.c | 276 | ||||
-rw-r--r-- | usr.sbin/ypserv/yp_extern.h | 4 | ||||
-rw-r--r-- | usr.sbin/ypserv/yp_main.c | 41 | ||||
-rw-r--r-- | usr.sbin/ypserv/yp_server.c | 68 |
5 files changed, 92 insertions, 299 deletions
diff --git a/usr.sbin/ypserv/Makefile b/usr.sbin/ypserv/Makefile index 50b5024..2911c37 100644 --- a/usr.sbin/ypserv/Makefile +++ b/usr.sbin/ypserv/Makefile @@ -2,7 +2,7 @@ PROG= ypserv SRCS= yp_svc.c yp_server.c yp_dblookup.c yp_dnslookup.c \ - ypxfr_clnt.c yp_main.c yp_error.c yp_access.c yp_async.c + ypxfr_clnt.c yp_main.c yp_error.c yp_access.c MAN8= ypserv.8 diff --git a/usr.sbin/ypserv/yp_async.c b/usr.sbin/ypserv/yp_async.c deleted file mode 100644 index 0070c7f..0000000 --- a/usr.sbin/ypserv/yp_async.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (c) 1995, 1996 - * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Bill Paul. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: yp_async.c,v 1.5 1996/11/30 21:22:48 wpaul Exp $ - */ - -#include <sys/types.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <limits.h> -#include <db.h> -#include <errno.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/queue.h> -#include <rpc/rpc.h> -#include <rpcsvc/yp.h> -#include "yp_extern.h" - -#ifndef lint -static const char rcsid[] = "$Id: yp_async.c,v 1.5 1996/11/30 21:22:48 wpaul Exp $"; -#endif - -/* - * This is the code that lets us handle yp_all() requests without - * using fork(). The idea is that we steal away the transport and - * XDR handles from the RPC library and handle the transactions - * ourselves. Normally, for a TCP request, the RPC library will - * send all the entire response at once, which means that if the - * response is large (like, say, a huge password map), then we could - * block for a long time inside the XDR filter. This would cause other - * clients to block while waiting for us to finish, which is bad. - * - * Previously, we handled this by fork()ing off the request into a - * child process, thereby allowing the parent (us) to service other - * requests. But this can incurr a lot of overhead and we have to - * limit the number of simultaneous children to avoid swapming the - * system. - * - * What we do now is handle the request one record at a time. We send - * the first record, then head back to the svc_run() loop to handle - * more requests. If select() says we can still write data to the - * socket, we send the next record. When we reach the end of the - * map or the client stops receiving, we dequeue the request and - * destroy the handle. - * - * The mechanism we use to steal the transport and XDR handles away - * from the RPC library is quite evil. Basically, we call svc_sendreply() - * and hand it a custom XDR filter that calls yp_add_async() to register - * the request, then bails out via longjmp() back to the ypproc_all_2_svc() - * routine before the library can shut down the pipe on us. We then - * unregister the transport from the library (so that svc_getreqset() - * will no longer talk to it) and handle it ourselves. - */ - -extern int _rpc_dtablesize __P(( void )); - -#ifndef QUEUE_TTL -#define QUEUE_TTL 255 -#endif - -static fd_set writefds; -static int fd_setsize; - -static CIRCLEQ_HEAD(asynchead, asyncq_entry) ahead; - -struct asyncq_entry { - DB *dbp; /* database handle */ - XDR *xdrs; /* XDR handle */ - SVCXPRT *xprt; /* transport handle */ - DBT key; - int ttl; - CIRCLEQ_ENTRY(asyncq_entry) links; -}; - -void yp_init_async() -{ - struct rlimit rlim; - - CIRCLEQ_INIT(&ahead); - - /* - * Jack up the number of file descriptors. - * We may need them if we end up with a lot - * of requests queued. - */ - - if (getrlimit(RLIMIT_NOFILE, &rlim) == -1) { - yp_error("couldn't get filedesc limit: %s", strerror(errno)); - return; - } - rlim.rlim_cur = rlim.rlim_max; - if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) { - yp_error("couldn't set filedesc limit: %s", strerror(errno)); - return; - } - - return; -} - -static bool_t yp_xmit_ypresp_all(q) - struct asyncq_entry *q; -{ - DBT data = { NULL, 0 }; - ypresp_all obj; - - /* Get a record */ - if ((obj.ypresp_all_u.val.stat = - yp_next_record(q->dbp, &q->key, &data, 1, 0)) == YP_TRUE) { - obj.ypresp_all_u.val.val.valdat_len = data.size; - obj.ypresp_all_u.val.val.valdat_val = data.data; - obj.ypresp_all_u.val.key.keydat_len = q->key.size; - obj.ypresp_all_u.val.key.keydat_val = q->key.data; - obj.more = TRUE; - } else { - obj.more = FALSE; - } - - /* Serialize */ - q->xdrs->x_op = XDR_ENCODE; - if (xdr_ypresp_all(q->xdrs, &obj) == FALSE) - return(FALSE); - - return(obj.more); -} - -static void yp_remove_async(q) - struct asyncq_entry *q; -{ - xdrrec_endofrecord(q->xdrs, TRUE); - svc_destroy(q->xprt); - (void)(q->dbp->close)(q->dbp); - CIRCLEQ_REMOVE(&ahead, q, links); - free(q); - - return; -} - -bool_t yp_add_async(xdrs, xprt, dbp) - XDR *xdrs; - SVCXPRT *xprt; - DB *dbp; -{ - register struct asyncq_entry *q; - - q = (struct asyncq_entry *)calloc(1, sizeof(struct asyncq_entry)); - if (q == NULL) { - yp_error("failed to malloc() asyncq entry: %s", - strerror(errno)); - return(FALSE); - } - - xprt_unregister(xprt); - q->xdrs = xdrs; - q->xdrs->x_op = XDR_ENCODE; - q->dbp = dbp; - q->xprt = xprt; - q->key.size = 0; - q->key.data = NULL; - q->ttl = QUEUE_TTL; - CIRCLEQ_INSERT_HEAD(&ahead, q, links); - - return(TRUE); -} - -static void yp_handle_async() -{ - register struct asyncq_entry *q; - -restart: - - for (q = ahead.cqh_first; q != (void *)&ahead; q = q->links.cqe_next) { - if (FD_ISSET(q->xprt->xp_sock, &writefds)) { - q->ttl = QUEUE_TTL; - if (yp_xmit_ypresp_all(q) == FALSE) { - yp_remove_async(q); - goto restart; - } - } - } -} - -static int yp_set_async_fds() -{ - register struct asyncq_entry *q; - int havefds; - -restart: - havefds = 0; - FD_ZERO(&writefds); - - for (q = ahead.cqh_first; q != (void *)&ahead; q = q->links.cqe_next) { - q->ttl--; - if (q->ttl <= 0) { - yp_remove_async(q); - goto restart; - } else { - FD_SET(q->xprt->xp_sock, &writefds); - havefds++; - } - } - - return(havefds); -} - -void -yp_svc_run() -{ -#ifdef FD_SETSIZE - fd_set readfds; -#else - int readfds; -#endif /* def FD_SETSIZE */ - extern int forked; - int pid; - int w; - - fd_setsize = _rpc_dtablesize(); - - /* Establish the identity of the parent ypserv process. */ - pid = getpid(); - - for (;;) { -#ifdef FD_SETSIZE - readfds = svc_fdset; -#else - readfds = svc_fds; -#endif /* def FD_SETSIZE */ - w = yp_set_async_fds(); - - switch (select(fd_setsize, &readfds, w ? &writefds : NULL, - NULL, (struct timeval *)0)) { - case -1: - if (errno == EINTR) { - continue; - } - perror("svc_run: - select failed"); - return; - case 0: - continue; - default: - yp_handle_async(); - svc_getreqset(&readfds); - if (forked && pid != getpid()) - exit(0); - } - } -} diff --git a/usr.sbin/ypserv/yp_extern.h b/usr.sbin/ypserv/yp_extern.h index 049315d..bdb99f9 100644 --- a/usr.sbin/ypserv/yp_extern.h +++ b/usr.sbin/ypserv/yp_extern.h @@ -85,7 +85,3 @@ extern void yp_flush_all __P(( void )); extern void yp_init_dbs __P(( void )); extern int yp_testflag __P(( char *, char *, int )); extern void load_securenets __P(( void )); - -extern void yp_svc_run __P(( void )); -extern void yp_init_async __P(( void )); -extern bool_t yp_add_async __P(( XDR *, SVCXPRT *, DB * )); diff --git a/usr.sbin/ypserv/yp_main.c b/usr.sbin/ypserv/yp_main.c index 54a36d2..5c22d89 100644 --- a/usr.sbin/ypserv/yp_main.c +++ b/usr.sbin/ypserv/yp_main.c @@ -79,6 +79,7 @@ static int _rpcfdtype; extern void ypprog_1 __P((struct svc_req, register SVCXPRT)); extern void ypprog_2 __P((struct svc_req, register SVCXPRT)); +extern int _rpc_dtablesize __P((void)); extern int _rpcsvcstate; /* Set when a request is serviced */ char *progname = "ypserv"; char *yp_dir = _PATH_YP; @@ -97,6 +98,45 @@ void _msgout(char* msg) syslog(LOG_ERR, msg); } +static void +yp_svc_run() +{ +#ifdef FD_SETSIZE + fd_set readfds; +#else + int readfds; +#endif /* def FD_SETSIZE */ + extern int forked; + int pid; + int fd_setsize = _rpc_dtablesize(); + + /* Establish the identity of the parent ypserv process. */ + pid = getpid(); + + for (;;) { +#ifdef FD_SETSIZE + readfds = svc_fdset; +#else + readfds = svc_fds; +#endif /* def FD_SETSIZE */ + switch (select(fd_setsize, &readfds, NULL, NULL, + (struct timeval *)0)) { + case -1: + if (errno == EINTR) { + continue; + } + perror("svc_run: - select failed"); + return; + case 0: + continue; + default: + svc_getreqset(&readfds); + if (forked && pid != getpid()) + exit(0); + } + } +} + static void unregister() { (void) pmap_unset(YPPROG, YPVERS); @@ -190,7 +230,6 @@ main(argc, argv) } load_securenets(); - yp_init_async(); #ifdef DB_CACHE yp_init_dbs(); #endif diff --git a/usr.sbin/ypserv/yp_server.c b/usr.sbin/ypserv/yp_server.c index 837c1cc..77cc6f7 100644 --- a/usr.sbin/ypserv/yp_server.c +++ b/usr.sbin/ypserv/yp_server.c @@ -43,21 +43,18 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <rpc/rpc.h> -#include <setjmp.h> #ifndef lint -static const char rcsid[] = "$Id: yp_server.c,v 1.10 1996/05/31 16:01:51 wpaul Exp $"; +static const char rcsid[] = "$Id: yp_server.c,v 1.12 1996/10/24 18:58:26 wpaul Exp $"; #endif /* not lint */ int forked = 0; int children = 0; static DB *spec_dbp = NULL; /* Special global DB handle for ypproc_all. */ -static SVCXPRT *xprt; /* Special SVCXPRT handle for ypproc_all. */ static char *master_string = "YP_MASTER_NAME"; static char *order_string = "YP_LAST_MODIFIED"; static int master_sz = sizeof("YP_MASTER_NAME") - 1; static int order_sz = sizeof("YP_LAST_MODIFIED") - 1; -static jmp_buf env; /* * NIS v2 support. This is where most of the action happens. @@ -476,19 +473,34 @@ ypproc_clear_2_svc(void *argp, struct svc_req *rqstp) */ /* - * Custom XDR routine for serialzing results of ypproc_all: grab control - * of the transport and xdr handle from the RPC library and this request - * to the async queue. It will multiplex the record transmission in such - * a way that we can service other requests between transmissions and - * avoid blocking. (It will also close the DB handle for us when the - * request is done.) + * Custom XDR routine for serialzing results of ypproc_all: keep + * reading from the database and spew until we run out of records + * or encounter an error. */ static bool_t xdr_my_ypresp_all(register XDR *xdrs, ypresp_all *objp) { - if (yp_add_async(xdrs, xprt, spec_dbp) == FALSE) - return(FALSE); - longjmp(env, 1); /* XXX EVIL!! */ + DBT key = { NULL, 0 } , data = { NULL, 0 }; + + while (1) { + /* Get a record. */ + if ((objp->ypresp_all_u.val.stat = + yp_next_record(spec_dbp,&key,&data,1,0)) == YP_TRUE) { + objp->ypresp_all_u.val.val.valdat_len = data.size; + objp->ypresp_all_u.val.val.valdat_val = data.data; + objp->ypresp_all_u.val.key.keydat_len = key.size; + objp->ypresp_all_u.val.key.keydat_val = key.data; + objp->more = TRUE; + } else { + objp->more = FALSE; + } + + /* Serialize. */ + if (!xdr_ypresp_all(xdrs, objp)) + return(FALSE); + if (objp->more == FALSE) + return(TRUE); + } } ypresp_all * @@ -519,16 +531,38 @@ ypproc_all_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) return (&result); } + /* + * The ypproc_all procedure can take a while to complete. + * Best to handle it in a subprocess so the parent doesn't + * block. (Is there a better way to do this? Maybe with + * async socket I/O?) + */ + if (!debug && children < MAX_CHILDREN && fork()) { + children++; + forked = 0; + return (NULL); + } else { + forked++; + } + +#ifndef DB_CACHE if ((spec_dbp = yp_open_db(argp->domain, argp->map)) == NULL) { result.ypresp_all_u.val.stat = yp_errno; return(&result); } +#else + if ((spec_dbp = yp_open_db_cache(argp->domain, argp->map, NULL, 0)) == NULL) { + result.ypresp_all_u.val.stat = yp_errno; + return(&result); + } +#endif /* Kick off the actual data transfer. */ - xprt = rqstp->rq_xprt; - if (!setjmp(env)) /* XXX EVIL!!! */ - svc_sendreply(rqstp->rq_xprt, xdr_my_ypresp_all, - (char *)&result); + svc_sendreply(rqstp->rq_xprt, xdr_my_ypresp_all, (char *)&result); + +#ifndef DB_CACHE + (void)(spec_dbp->close)(spec_dbp); +#endif /* * Returning NULL prevents the dispatcher from calling * svc_sendreply() since we already did it. |