diff options
author | wpaul <wpaul@FreeBSD.org> | 1995-05-10 23:02:41 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 1995-05-10 23:02:41 +0000 |
commit | 78ce3864de28cf6df1d35bae1167167384cc0d42 (patch) | |
tree | 15506e5f44e5d963ae837e0f056122342dfb7a7d /usr.sbin/ypbind | |
parent | fd82b3cc6a0b17cf6d88502f54836c2783332e13 (diff) | |
download | FreeBSD-src-78ce3864de28cf6df1d35bae1167167384cc0d42.zip FreeBSD-src-78ce3864de28cf6df1d35bae1167167384cc0d42.tar.gz |
Performace improvements/simplifications/cleanups:
- Make the child process reaper signal-driven. (Previously, we called reaper()
once a second each time we went through the select() loop. This was
convenient, but inefficient.)
- Increase main select() timeout from 1 second to 60 seconds and use
this as the ping timer instead of using timestamps in the _dom_binding
structure. This nd the reaper() change noted above makes ypbind a little
less CPU-intensive.
- Don't flag EINTR's from select() as errors since they will happen as a
result of incoming SIGCHLD's interrupting select().
- Prevent possible resource hogging. Currently we malloc() memory
each time a user process asks us to establish a binding for a domain,
but we never free it. This could lead to serious memory leakage if a
'clever' user did something like ask ypwhich to check the bindings
for domains 0.0.0.0.0.0.0.0.0.0 through 9.9.9.9.9.9.9.9.9.9 inclusive.
(This would also make a mess out of the /var/yp/binding directory.)
We now avoid this silliness by a) limiting the maximum number of
simultaneous bindings we can manage to 200, and b) free()ing _dom_binding
structures of secondary domains whose servers have stopped responding.
We unlink the /var/yp/binding/domain.vers files for the free()ed
domains too.
(This is safe to do since a client can prod us into reestablishing the
binding, at which time we'll simply allocate a new _dom_binding structure
for it.)
We keep count of the total number of domains. If asked to
allocate more than the maximum, we return an error. I have yet to hear
of anybody needing 200 simultaneous NIS bindings, so this should be
enough. (I chose the number 200 arbitrarily. It can be increased if need
be.)
- Changed "server not responding"/"server OK" messages to display server
IP addresses again since it looks spiffier.
- Use daemon() to daemonify ourselves,
- Added a SIGTERM handler that removes all binding files and unregisters
the ypbind service from the portmapper when a SIGTERM in received.
- The comment 'blow away everything in BINDINGDIR' has no associated code.
Give it some: clean out /var/yp/binding at startup (if it exists).
This completes my ypbind wishlist. Barring bug fixes, I shouldn't need to
go poking around in here anymore. (Of course, this means I can start
working on my ypserv whishlist now... :)
Diffstat (limited to 'usr.sbin/ypbind')
-rw-r--r-- | usr.sbin/ypbind/ypbind.c | 185 |
1 files changed, 110 insertions, 75 deletions
diff --git a/usr.sbin/ypbind/ypbind.c b/usr.sbin/ypbind/ypbind.c index 5c35b9a..e985e58 100644 --- a/usr.sbin/ypbind/ypbind.c +++ b/usr.sbin/ypbind/ypbind.c @@ -28,7 +28,7 @@ */ #ifndef LINT -static char rcsid[] = "$Id: ypbind.c,v 1.8 1995/04/26 19:03:14 wpaul Exp $"; +static char rcsid[] = "$Id: ypbind.c,v 1.9 1995/05/03 18:34:22 wpaul Exp $"; #endif #include <sys/param.h> @@ -65,17 +65,6 @@ static char rcsid[] = "$Id: ypbind.c,v 1.8 1995/04/26 19:03:14 wpaul Exp $"; #define BINDINGDIR "/var/yp/binding" #endif -/* - * Ping the server once every PING_INTERVAL seconds to make sure it's - * still there. - */ -#ifndef PING_INTERVAL -#define PING_INTERVAL 60 -#endif -#ifndef FAIL_THRESHOLD -#define FAIL_THRESHOLD 20 -#endif - struct _dom_binding { struct _dom_binding *dom_pnext; char dom_domain[YPMAXDOMAIN + 1]; @@ -86,7 +75,6 @@ struct _dom_binding { int dom_alive; int dom_broadcasting; int dom_default; - time_t dom_check; }; extern bool_t xdr_domainname(), xdr_ypbind_resp(); @@ -98,8 +86,10 @@ void *ypbindproc_null_2 __P((SVCXPRT *, void *, CLIENT *)); bool_t *ypbindproc_setdom_2 __P((SVCXPRT *, struct ypbind_setdom *, CLIENT *)); void rpc_received __P((char *, struct sockaddr_in *, int )); void broadcast __P((struct _dom_binding *)); -int ping __P((struct _dom_binding *, int)); +int ping __P((struct _dom_binding *)); void handle_children __P(( int )); +void reaper __P((int)); +void terminate __P((int)); static char *broad_domain; char *domainname; @@ -113,9 +103,18 @@ int ypsecuremode = 0; /* No more than MAX_CHILDREN child broadcasters at a time. */ #define MAX_CHILDREN 5 +/* No more than MAX_DOMAINS simultaneous domains */ +#define MAX_DOMAINS 200 +#ifndef FAIL_THRESHOLD +#define FAIL_THRESHOLD 20 +#endif + +#define KILLME_MAGIC 0xdeaddead + int child_fds[FD_SETSIZE]; static int fd[2]; int children = 0; +int domains = 0; SVCXPRT *udptransp, *tcptransp; @@ -150,6 +149,12 @@ CLIENT *clnt; break; if(ypdb==NULL) { + if (domains > MAX_DOMAINS) { + syslog(LOG_WARNING, "domain limit (%d) exceeded", + MAX_DOMAINS); + res.ypbind_respbody.ypbind_error = YPBIND_ERR_RESC; + return; + } ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); if (ypdb == NULL) { syslog(LOG_WARNING, "malloc: %s", strerror(errno)); @@ -162,17 +167,15 @@ CLIENT *clnt; ypdb->dom_alive = 0; ypdb->dom_default = 0; ypdb->dom_lockfd = -1; - sprintf(path, "%s/%s.%ld", BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers); + sprintf(path, "%s/%s.%ld", BINDINGDIR, + ypdb->dom_domain, ypdb->dom_vers); unlink(path); ypdb->dom_pnext = ypbindlist; ypbindlist = ypdb; - return &res; + domains++; } - if(ypdb->dom_alive==0) - return &res; - - if (ping(ypdb, 1)) + if (ping(ypdb)) return &res; res.ypbind_status = YPBIND_SUCC_VAL; @@ -298,6 +301,22 @@ int sig; wait3(&st, WNOHANG, NULL); } +void terminate(sig) +int sig; +{ + struct _dom_binding *ypdb; + char path[MAXPATHLEN]; + + for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { + close(ypdb->dom_lockfd); + sprintf(path, "%s/%s.%ld", BINDINGDIR, + ypdb->dom_domain, ypdb->dom_vers); + unlink(path); + } + pmap_unset(YPBINDPROG, YPBINDVERS); + exit(0); +} + void main(argc, argv) int argc; @@ -307,6 +326,8 @@ char **argv; struct timeval tv; fd_set fdsr; int i; + DIR *dird; + struct dirent *dirp; yp_get_default_domain(&domainname); if( domainname[0] == '\0') { @@ -323,45 +344,48 @@ char **argv; ypsecuremode++; } - /* blow away everything in BINDINGDIR */ - + /* blow away everything in BINDINGDIR (if it exists) */ + if ((dird = opendir(BINDINGDIR)) != NULL) { + char path[MAXPATHLEN]; + while ((dirp = readdir(dird)) != NULL) + if (strcmp(dirp->d_name, ".") && + strcmp(dirp->d_name, "..")) { + sprintf(path,"%s/%s",BINDINGDIR,dirp->d_name); + unlink(path); + } + closedir(dird); + } #ifdef DAEMON - switch(fork()) { - case 0: - break; - case -1: + if (daemon(0,0)) { perror("fork"); exit(1); - default: - exit(0); } - setsid(); #endif pmap_unset(YPBINDPROG, YPBINDVERS); udptransp = svcudp_create(RPC_ANYSOCK); if (udptransp == NULL) { - fprintf(stderr, "cannot create udp service."); + fprintf(stderr, "cannot create udp service.\n"); exit(1); } if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, IPPROTO_UDP)) { - fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, udp)."); + fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, udp).\n"); exit(1); } tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0); if (tcptransp == NULL) { - fprintf(stderr, "cannot create tcp service."); + fprintf(stderr, "cannot create tcp service.\n"); exit(1); } if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, IPPROTO_TCP)) { - fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, tcp)."); + fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, tcp).\n"); exit(1); } @@ -378,9 +402,10 @@ char **argv; ypbindlist->dom_lockfd = -1; ypbindlist->client_handle = NULL; ypbindlist->dom_default = 1; - sprintf(path, "%s/%s.%ld", BINDINGDIR, ypbindlist->dom_domain, - ypbindlist->dom_vers); - (void)unlink(path); + domains++; + + signal(SIGCHLD, reaper); + signal(SIGTERM, terminate); /* Initialize children fds. */ for (i = 0; i < FD_SETSIZE; i++) @@ -388,6 +413,9 @@ char **argv; openlog(argv[0], LOG_PID, LOG_DAEMON); + /* Kick off the default domain */ + broadcast(ypbindlist); + while(1) { fdsr = svc_fdset; @@ -395,17 +423,20 @@ char **argv; if (child_fds[i] > 0 ) FD_SET(child_fds[i], &fdsr); - tv.tv_sec = 1; + tv.tv_sec = 60; tv.tv_usec = 0; switch(select(_rpc_dtablesize(), &fdsr, NULL, NULL, &tv)) { case 0: checkwork(); - reaper(); break; case -1: - syslog(LOG_WARNING, "select: %s", strerror(errno)); - break; + if (errno == EINTR) + continue; + else { + syslog(LOG_WARNING, "select: %s", strerror(errno)); + break; + } default: for(i = 0; i < FD_SETSIZE; i++) { if (child_fds[i] > 0 && FD_ISSET(child_fds[i],&fdsr)) { @@ -427,19 +458,9 @@ void checkwork() { struct _dom_binding *ypdb; - time_t t; - time(&t); - for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { - if (!ypdb->dom_alive && !ypdb->dom_broadcasting) { - if (!ypdb->dom_default) - ypdb->dom_alive = 1; - ypdb->dom_broadcasting = 1; - broadcast(ypdb); - } - if (ypdb->dom_alive && ypdb->dom_check < t) - ping(ypdb, 0); - } + for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) + ping(ypdb); } /* The clnt_broadcast() callback mechanism sucks. */ @@ -527,16 +548,22 @@ struct _dom_binding *ypdb; enum clnt_stat stat; int i; - if (children > MAX_CHILDREN) + if (children > MAX_CHILDREN || ypdb->dom_broadcasting) return; - broad_domain = ypdb->dom_domain; - if (pipe(fd) < 0) { syslog(LOG_WARNING, "pipe: %s",strerror(errno)); return; } + if (ypdb->dom_vers = -1 && (long)ypdb->dom_server_addr.sin_addr.s_addr) + syslog(LOG_WARNING, "NIS server [%s] for domain %s not responding", + inet_ntoa(ypdb->dom_server_addr.sin_addr), ypdb->dom_domain); + + broad_domain = ypdb->dom_domain; + ypdb->dom_broadcasting = 1; + flock(ypdb->dom_lockfd, LOCK_UN); + switch(fork()) { case 0: close(fd[0]); @@ -564,10 +591,10 @@ struct _dom_binding *ypdb; broadcast_result); if (stat != RPC_SUCCESS) { - syslog(LOG_WARNING, "NIS server for domain %s not responding", - ypdb->dom_domain); bzero((char *)&ypdb->dom_server_addr, sizeof(struct sockaddr_in)); + if (!ypdb->dom_default) + ypdb->dom_server_addr.sin_addr.s_addr = KILLME_MAGIC; if (tell_parent(&ypdb->dom_domain, &ypdb->dom_server_addr)) syslog(LOG_WARNING, "lost connection to parent"); } @@ -578,8 +605,8 @@ struct _dom_binding *ypdb; * The right way to check if a server is alive. * Attempt to get a client handle pointing to the server and send a * YPPROC_DOMAIN_NONACK. If we don't get a response, we invalidate - * this binding entry, which will cause checkwork() to dispatch a - * broadcaster process. Note that we treat non-default domains + * this binding entry and send out a broadcast to try to establish + * a new binding. Note that we treat non-default domains * specially: once bound, we keep tabs on our server, but if it * goes away and fails to respond after one round of broadcasting, we * abandon it until a client specifically references it again. We make @@ -587,9 +614,8 @@ struct _dom_binding *ypdb; * need it to keep the system on its feet. */ int -ping(ypdb, force) +ping(ypdb) struct _dom_binding *ypdb; -int force; { bool_t out; struct timeval interval, timeout; @@ -605,9 +631,6 @@ int force; if (ypdb->dom_broadcasting) return(1); - if (!ypdb->dom_default && ypdb->dom_vers == -1 && !force) - return(1); - if (ypdb->client_handle == NULL) { if ((ypdb->client_handle = clntudp_bufcreate( &ypdb->dom_server_addr, YPPROG, YPVERS, @@ -617,7 +640,7 @@ int force; ypdb->client_handle = NULL; ypdb->dom_alive = 0; ypdb->dom_vers = -1; - flock(ypdb->dom_lockfd, LOCK_UN); + broadcast(ypdb); return(1); } } @@ -628,14 +651,9 @@ int force; ypdb->client_handle = NULL; ypdb->dom_alive = 0; ypdb->dom_vers = -1; - flock(ypdb->dom_lockfd, LOCK_UN); + broadcast(ypdb); return(1); } - /* - * We pinged successfully. Reset the timer. - */ - time(&t); - ypdb->dom_check = t + PING_INTERVAL; return(0); } @@ -645,7 +663,7 @@ char *dom; struct sockaddr_in *raddrp; int force; { - struct _dom_binding *ypdb; + struct _dom_binding *ypdb, *prev = NULL; struct iovec iov[2]; struct ypbind_resp ybr; char path[MAXPATHLEN]; @@ -657,9 +675,11 @@ int force; if(dom==NULL) return; - for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) + for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { if( strcmp(ypdb->dom_domain, dom) == 0) break; + prev = ypdb; + } /* if in securemode, check originating port number */ if (ypsecuremode && (ntohs(raddrp->sin_port) >= IPPORT_RESERVED)) { @@ -676,6 +696,21 @@ int force; if (raddrp->sin_addr.s_addr == (long)0) { ypdb->dom_broadcasting = 0; ypdb->dom_alive = 0; + broadcast(ypdb); + return; + } + + if (raddrp->sin_addr.s_addr == KILLME_MAGIC) { + if (prev == NULL) + ypbindlist = ypdb->dom_pnext; + else + prev->dom_pnext = ypdb->dom_pnext; + sprintf(path, "%s/%s.%ld", BINDINGDIR, + ypdb->dom_domain, YPVERS); /* XXX dom_vers can't */ + close(ypdb->dom_lockfd); /* be trusted here */ + unlink(path); + free(ypdb); + domains--; return; } @@ -699,8 +734,8 @@ int force; /* We've recovered from a crash: inform the world. */ if (ypdb->dom_vers = -1 && ypdb->dom_server_addr.sin_addr.s_addr) - syslog(LOG_WARNING, "NIS server for domain %s OK", - ypdb->dom_domain); + syslog(LOG_WARNING, "NIS server [%s] for domain %s OK", + inet_ntoa(ypdb->dom_server_addr.sin_addr), ypdb->dom_domain); bcopy((char *)raddrp, (char *)&ypdb->dom_server_addr, sizeof ypdb->dom_server_addr); |