summaryrefslogtreecommitdiffstats
path: root/usr.sbin/ypbind/ypbind.c
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>1995-04-26 19:03:16 +0000
committerwpaul <wpaul@FreeBSD.org>1995-04-26 19:03:16 +0000
commitb72b2e3557fca50d6b69c47a937520cbe45c26d3 (patch)
treebf5e8345e4fe172879132532c0e299a35e9937b8 /usr.sbin/ypbind/ypbind.c
parent321a03d090577e9d6eb90169b5ded161378501ea (diff)
downloadFreeBSD-src-b72b2e3557fca50d6b69c47a937520cbe45c26d3.zip
FreeBSD-src-b72b2e3557fca50d6b69c47a937520cbe45c26d3.tar.gz
ypbind.c: Major overhaul.
- Moved to a more client-driven model. We aggressively attempt to keep the default domain bound (as before) but we give up on non-default domains if we lose contact with a server and fail to get a response after one round of broadcasting. This helps drastically reduce the amount of network bandwitdh that ypbind consumes: if a client references the secondary domain at some later point, this will prod ypbind into establishing a new binding anyway, so continuously broadcasting without need is pointless. Note that we still actively seek out a binding for our default domain even if no client program has queried us yet. I'm not exactly sure if this matches SunOS's behavior or not, but I decided to do it this way since we can get into all sorts of trouble if our default domain comes unbound. Even so, we're still much quieter than we used to be. - Removed a bunch of no-longer pertinent comments and a couple of chunks of #ifdef 0'ed code that no longer fit in to the new layout. - Theo deRaadt must have become frustrated with the callback mechanism in clnt_broadcast(), because he shamelessly stole the clnt_broadcast() code right out of the RPC library and hacked it up to suit his needs. (Comments and all! :) I can understand why: clnt_broadcast() blocks while awaiting replies. Changing this behavior requires surgery. However, you can work around this: fork the broadcast into a child process and relay the results back to the parent via a pipe. (Careful obervation has shown that the SunOS ypbind forks children for broadcasting too, though I can only guess what sort of interprocess communication it uses. pipe() seems to do the job well enough.) This may seem like the long way around, but it's not really that hard to implement, and I'd prefer to use documented RPC library functions wherever possible. We're careful to limit the number of simultaneous broadcasters to avoid swamping the system (the current limit is 5). Each clnt_broadcast() call only sends out a small number of packets at increasing intervals. We're also careful not to spawn more than one bradcaster for a given domain. - Used clntudp_bufcreate() and clnt_call() to implement a ping() function for directly querying a particular server so that we can check if it's still alive. This lets me completely remove the old bradcasting code and use actual RPC library calls instead, at the cost of more than a few handfulls of torn-out hair. (Make no mistake folks: I *HATE* RPC.) Currently, the ping interval is one minute. - Fixed another potential 'nfds too big for select()' bug: use _rpc_dtablesize() instead of getdtablesize(). - Quieted gcc -Wall a bit. - Probably a bunch of other stuff that I've forgotten. ypbind.8: - Updated man page to reflect modifications. ypwhich.c: - Small mind-o fix from last time: decode error results from ypbind correctly (*groan*) yplib.c: - same as above - Change behavior of _yp_dobind() a little: if we get back a 'Domain not bound' error for a given domain, retry a few times before giving up and passing the error back to the caller. We have to sleep for a few seconds between tries since the 'Domain not bound' error comes back immediately (by repeatedly looping, we end up pounding on ypbind). We retry at most 20 times at 5 second intervals. This gives us a full minute to get a response. This seems to deviate a bit from SunOS behavior -- it appears to wait forever -- but I don't like the idea of perpetually hanging inside a library call. Note that this should fix the problems some people have with bindings not being established fast enough at boot time; sometimes amd is started in /etc/rc after ypbind has run but before it gets a binding set up. The automounter gets annoyed at this and tends to exit. By pausing ther YP calls until a binding is ready, we avoid this situation. - Another _yp_dobind() change: if we determine that our binding files are unlocked or nonexistent, jump directly to code that pokes ypbind into restablishing the binding. Again, if it fails, we'll time out eventually and return.
Diffstat (limited to 'usr.sbin/ypbind/ypbind.c')
-rw-r--r--usr.sbin/ypbind/ypbind.c572
1 files changed, 273 insertions, 299 deletions
diff --git a/usr.sbin/ypbind/ypbind.c b/usr.sbin/ypbind/ypbind.c
index 43c719f..9aaf1e6 100644
--- a/usr.sbin/ypbind/ypbind.c
+++ b/usr.sbin/ypbind/ypbind.c
@@ -28,16 +28,18 @@
*/
#ifndef LINT
-static char rcsid[] = "$Id: ypbind.c,v 1.6 1995/04/15 23:35:46 wpaul Exp $";
+static char rcsid[] = "$Id: ypbind.c,v 1.7 1995/04/21 18:04:36 wpaul Exp $";
#endif
#include <sys/param.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/fcntl.h>
+#include <sys/stat.h>
#include <sys/uio.h>
#include <syslog.h>
#include <stdio.h>
@@ -55,6 +57,7 @@ static char rcsid[] = "$Id: ypbind.c,v 1.6 1995/04/15 23:35:46 wpaul Exp $";
#include <rpc/pmap_prot.h>
#include <rpc/pmap_rmt.h>
#include <unistd.h>
+#include <stdlib.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
@@ -63,9 +66,12 @@ static char rcsid[] = "$Id: ypbind.c,v 1.6 1995/04/15 23:35:46 wpaul Exp $";
#endif
/*
- * Number of seconds to wait before for ping replies before we
- * decide that our server is dead.
+ * 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
@@ -74,38 +80,43 @@ struct _dom_binding {
struct _dom_binding *dom_pnext;
char dom_domain[YPMAXDOMAIN + 1];
struct sockaddr_in dom_server_addr;
- unsigned short int dom_server_port;
- int dom_socket;
- CLIENT *dom_client;
+ CLIENT *client_handle;
long int dom_vers;
- time_t dom_check_t;
int dom_lockfd;
int dom_alive;
- int dom_answered;
- int dom_interval;
+ int dom_broadcasting;
+ int dom_default;
+ time_t dom_check;
};
extern bool_t xdr_domainname(), xdr_ypbind_resp();
extern bool_t xdr_ypreq_key(), xdr_ypresp_val();
extern bool_t xdr_ypbind_setdom();
-char *domainname;
+void checkwork __P((void));
+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));
+void handle_children __P(( int ));
+static char *broad_domain;
+char *domainname;
struct _dom_binding *ypbindlist;
-int check;
#define YPSET_NO 0
#define YPSET_LOCAL 1
#define YPSET_ALL 2
int ypsetmode = YPSET_NO;
-
int ypsecuremode = 0;
-int rpcsock;
-struct rmtcallargs rmtca;
-struct rmtcallres rmtcr;
-char rmtcr_outval;
-u_long rmtcr_port;
+/* No more than MAX_CHILDREN child broadcasters at a time. */
+#define MAX_CHILDREN 5
+int child_fds[FD_SETSIZE];
+static int fd[2];
+int children = 0;
+
SVCXPRT *udptransp, *tcptransp;
void *
@@ -144,8 +155,9 @@ CLIENT *clnt;
strncpy(ypdb->dom_domain, argp, sizeof ypdb->dom_domain);
ypdb->dom_vers = YPVERS;
ypdb->dom_alive = 0;
+ ypdb->dom_default = 0;
ypdb->dom_lockfd = -1;
- sprintf(path, "%s/%s.%d", 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;
@@ -155,32 +167,14 @@ CLIENT *clnt;
if(ypdb->dom_alive==0)
return &res;
-#if 0
- delta = ypdb->dom_check_t - ypdb->dom_ask_t;
- if( !(ypdb->dom_ask_t==0 || delta > 5)) {
- ypdb->dom_ask_t = time(NULL);
- /*
- * Hmm. More than 2 requests in 5 seconds have indicated that my
- * binding is possibly incorrect. Ok, make myself unalive, and
- * find out what the actual state is.
- */
- if(ypdb->dom_lockfd!=-1)
- close(ypdb->dom_lockfd);
- ypdb->dom_lockfd = -1;
- ypdb->dom_alive = 0;
- ypdb->dom_lockfd = -1;
- sprintf(path, "%s/%s.%d", BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers);
- unlink(path);
- return NULL;
- }
-#endif
+ if (ping(ypdb, 1))
+ return &res;
-answer:
res.ypbind_status = YPBIND_SUCC_VAL;
res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr =
ypdb->dom_server_addr.sin_addr.s_addr;
res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port =
- ypdb->dom_server_port;
+ ypdb->dom_server_addr.sin_port;
/*printf("domain %s at %s/%d\n", ypdb->dom_domain,
inet_ntoa(ypdb->dom_server_addr.sin_addr),
ntohs(ypdb->dom_server_addr.sin_port));*/
@@ -289,13 +283,23 @@ register SVCXPRT *transp;
return;
}
+/* Jack the reaper */
+void reaper(sig)
+int sig;
+{
+ int st;
+
+ wait3(&st, WNOHANG, NULL);
+}
+
+void
main(argc, argv)
+int argc;
char **argv;
{
char path[MAXPATHLEN];
struct timeval tv;
fd_set fdsr;
- int width;
int i;
yp_get_default_domain(&domainname);
@@ -355,57 +359,54 @@ char **argv;
exit(1);
}
- if( (rpcsock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
- perror("socket");
- return -1;
- }
-
- fcntl(rpcsock, F_SETFL, fcntl(rpcsock, F_GETFL, 0) | FNDELAY);
- i = 1;
- setsockopt(rpcsock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i));
- rmtca.prog = YPPROG;
- rmtca.vers = YPVERS;
- rmtca.proc = YPPROC_DOMAIN_NONACK;
- rmtca.xdr_args = NULL; /* set at call time */
- rmtca.args_ptr = NULL; /* set at call time */
- rmtcr.port_ptr = &rmtcr_port;
- rmtcr.xdr_results = xdr_bool;
- rmtcr.results_ptr = (caddr_t)&rmtcr_outval;
-
/* build initial domain binding, make it "unsuccessful" */
ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist);
bzero((char *)ypbindlist, sizeof *ypbindlist);
strncpy(ypbindlist->dom_domain, domainname, sizeof ypbindlist->dom_domain);
ypbindlist->dom_vers = YPVERS;
- ypbindlist->dom_interval = 0;
ypbindlist->dom_alive = 0;
- ypbindlist->dom_answered = 0;
ypbindlist->dom_lockfd = -1;
- ypbindlist->dom_check_t = time(NULL) + ypbindlist->dom_interval;
- sprintf(path, "%s/%s.%d", BINDINGDIR, ypbindlist->dom_domain,
+ ypbindlist->client_handle = NULL;
+ ypbindlist->dom_default = 1;
+ sprintf(path, "%s/%s.%ld", BINDINGDIR, ypbindlist->dom_domain,
ypbindlist->dom_vers);
(void)unlink(path);
+ /* Initialize children fds. */
+ for (i = 0; i < FD_SETSIZE; i++)
+ child_fds[i] = -1;
+
openlog(argv[0], LOG_PID, LOG_AUTH);
- width = getdtablesize();
while(1) {
fdsr = svc_fdset;
- FD_SET(rpcsock, &fdsr);
+
+ for (i = 0; i < FD_SETSIZE; i++)
+ if (child_fds[i] > 0 )
+ FD_SET(child_fds[i], &fdsr);
+
tv.tv_sec = 1;
tv.tv_usec = 0;
- switch(select(width, &fdsr, NULL, NULL, &tv)) {
+ switch(select(_rpc_dtablesize(), &fdsr, NULL, NULL, &tv)) {
case 0:
checkwork();
+ reaper();
break;
case -1:
- perror("select\n");
+ perror("select");
+ exit(0);
break;
default:
- if(FD_ISSET(rpcsock, &fdsr)) {
- FD_CLR(rpcsock, &fdsr);
- handle_replies();
+ for(i = 0; i < FD_SETSIZE; i++) {
+ if (child_fds[i] > 0 && FD_ISSET(child_fds[i],&fdsr)) {
+ handle_children(child_fds[i]);
+ close(child_fds[i]);
+ FD_CLR(child_fds[i], &fdsr);
+ child_fds[i] = -1;
+ children--;
+
+ }
}
svc_getreqset(&fdsr);
break;
@@ -413,237 +414,224 @@ char **argv;
}
}
-/*
- * change to do something like this:
- *
- * STATE TIME ACTION NEWTIME NEWSTATE
- * no binding t==* broadcast t=2 no binding
- * binding t==60 check server t=10 binding
- * binding t=10 broadcast t=2 no binding
- */
-
-/*
- * The above comment makes no sense whatsoever. This is what should
- * be happening:
- *
- * - If we have any servers in our binding list marked alive, ping
- * them _and them alone_ only once every 60 seconds to make sure
- * they haven't crapped out on us (i.e. bother only the servers
- * we know about: *DON'T* continually bother everybody with broadcast
- * packets every 5 seconds like we used to).
- * - If they don't respond within FAIL_THRESHOLD seconds after the ping,
- * they're toast: mark them unalive and start to scream and shout.
- * - If we don't have any servers marked alive, then we're in desperate
- * trouble and we need to broadcast a cry for help every 5 seconds
- * until somebody answers us.
- */
-
+void
checkwork()
{
struct _dom_binding *ypdb;
time_t t;
+ time(&t);
for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) {
- time(&t);
- if (ypdb->dom_check_t < t) {
- broadcast(ypdb->dom_domain,
- ypdb->dom_server_addr, ypdb->dom_alive);
- ypdb->dom_check_t = t + ypdb->dom_interval;
- ypdb->dom_answered = 0;
- } else
- if (!ypdb->dom_answered && ypdb->dom_alive &&
- ypdb->dom_check_t < (t + FAIL_THRESHOLD)) {
- ypdb->dom_check_t = ypdb->dom_alive =
- ypdb->dom_vers = 0;
- ypdb->dom_interval = 5;
- syslog (LOG_NOTICE,
- "NIS server [%s] for domain %s not responding.",
- inet_ntoa(ypdb->dom_server_addr.sin_addr),
- ypdb->dom_domain);
+ 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);
}
}
-broadcast(dom, saddr, direct)
+/* The clnt_broadcast() callback mechanism sucks. */
+
+/*
+ * Receive results from broadcaster. Don't worry about passing
+ * bogus info to rpc_received() -- it can handle it.
+ */
+void handle_children(i)
+int i;
+{
+ char buf[YPMAXDOMAIN + 1];
+ struct sockaddr_in addr;
+
+ if (read(i, &buf, sizeof(buf)) < 0)
+ syslog(LOG_WARNING, "could not read from child");
+ if (read(i, &addr, sizeof(struct sockaddr_in)) < 0)
+ syslog(LOG_WARNING, "could not read from child");
+ rpc_received((char *)&buf, &addr, 0);
+}
+
+/*
+ * Send our dying words back to our parent before we perish.
+ */
+int
+tell_parent(dom, addr)
char *dom;
-struct sockaddr_in saddr;
-int direct;
+struct sockaddr_in *addr;
{
- struct rpc_msg rpcmsg;
- char buf[1400], inbuf[8192];
- enum clnt_stat st;
- struct timeval tv;
- int outlen, i, sock, len;
- struct sockaddr_in bsin;
- struct ifconf ifc;
- struct ifreq ifreq, *ifr;
- struct in_addr in;
- AUTH *rpcua;
- XDR rpcxdr;
-
- rmtca.xdr_args = xdr_domainname;
- rmtca.args_ptr = dom;
-
- bzero((char *)&bsin, sizeof bsin);
- bsin.sin_family = AF_INET;
- bsin.sin_port = htons(PMAPPORT);
-
- bzero((char *)&rpcxdr, sizeof rpcxdr);
- bzero((char *)&rpcmsg, sizeof rpcmsg);
-
- rpcua = authunix_create_default();
- if( rpcua == (AUTH *)NULL) {
- /*printf("cannot get unix auth\n");*/
- return RPC_SYSTEMERROR;
- }
- rpcmsg.rm_direction = CALL;
- rpcmsg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
- rpcmsg.rm_call.cb_prog = PMAPPROG;
- rpcmsg.rm_call.cb_vers = PMAPVERS;
- rpcmsg.rm_call.cb_proc = PMAPPROC_CALLIT;
- rpcmsg.rm_call.cb_cred = rpcua->ah_cred;
- rpcmsg.rm_call.cb_verf = rpcua->ah_verf;
-
- gettimeofday(&tv, (struct timezone *)0);
- rpcmsg.rm_xid = (int)dom;
- tv.tv_usec = 0;
- xdrmem_create(&rpcxdr, buf, sizeof buf, XDR_ENCODE);
- if( (!xdr_callmsg(&rpcxdr, &rpcmsg)) ) {
- st = RPC_CANTENCODEARGS;
- AUTH_DESTROY(rpcua);
- return st;
- }
- if( (!xdr_rmtcall_args(&rpcxdr, &rmtca)) ) {
- st = RPC_CANTENCODEARGS;
- AUTH_DESTROY(rpcua);
- return st;
- }
- outlen = (int)xdr_getpos(&rpcxdr);
- xdr_destroy(&rpcxdr);
- if(outlen<1) {
- AUTH_DESTROY(rpcua);
- return st;
- }
- AUTH_DESTROY(rpcua);
+ char buf[YPMAXDOMAIN + 1];
+ struct timeval timeout;
+ fd_set fds;
- /* find all networks and send the RPC packet out them all */
- if( (sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
- perror("socket");
- return -1;
- }
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+
+ sprintf (buf, "%s", broad_domain);
+ if (write(fd[1], &buf, sizeof(buf)) < 0)
+ return(1);
/*
- * It's impolite to blast broadcast packets all over the place
- * when we don't really have to.
+ * Stay in sync with parent: wait for it to read our first
+ * message before sending the second.
*/
- if (!direct) {
- ifc.ifc_len = sizeof inbuf;
- ifc.ifc_buf = inbuf;
- if( ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
- close(sock);
- perror("ioctl(SIOCGIFCONF)");
- return -1;
- }
- ifr = ifc.ifc_req;
- ifreq.ifr_name[0] = '\0';
- for(i=0; i<ifc.ifc_len; i+=len, ifr=(struct ifreq *)((caddr_t)ifr+len)) {
-#if defined(BSD) && BSD >= 199103
- len = sizeof ifr->ifr_name + ifr->ifr_addr.sa_len;
-#else
- len = sizeof ifc.ifc_len / sizeof(struct ifreq);
-#endif
- ifreq = *ifr;
- if( ifreq.ifr_addr.sa_family != AF_INET)
- continue;
- if( ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0) {
- perror("ioctl(SIOCGIFFLAGS)");
- continue;
- }
- if( (ifreq.ifr_flags & IFF_UP) == 0)
- continue;
-
- ifreq.ifr_flags &= (IFF_LOOPBACK | IFF_BROADCAST);
- if( ifreq.ifr_flags==IFF_BROADCAST ) {
- if( ioctl(sock, SIOCGIFBRDADDR, &ifreq) < 0 ) {
- perror("ioctl(SIOCGIFBRDADDR)");
- continue;
- }
- } else if( ifreq.ifr_flags==IFF_LOOPBACK ) {
- if( ioctl(sock, SIOCGIFADDR, &ifreq) < 0 ) {
- perror("ioctl(SIOCGIFADDR)");
- continue;
- }
- } else
- continue;
- in = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
- bsin.sin_addr = in;
- if( sendto(rpcsock, buf, outlen, 0,
- (struct sockaddr *)&bsin, sizeof bsin) < 0 )
- perror("sendto");
- }
+
+ FD_ZERO(&fds);
+ FD_SET(fd[1], &fds);
+ if (select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == -1)
+ return(1);
+ if (FD_ISSET(fd[1], &fds)) {
+ if (write(fd[1], addr, sizeof(struct sockaddr_in)) < 0)
+ return(1);
} else {
- in = ((struct sockaddr_in *)&saddr)->sin_addr;
- bsin.sin_addr = in;
- if( sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bsin,
- sizeof bsin) < 0 )
- perror("sendto");
+ return(1);
}
- close(sock);
- return 0;
+ close(fd[1]);
+ return (0);
}
-/*enum clnt_stat*/
-handle_replies()
+bool_t broadcast_result(out, addr)
+bool_t *out;
+struct sockaddr_in *addr;
+{
+ if (tell_parent(&broad_domain, addr))
+ syslog(LOG_WARNING, "lost connection to parent");
+ return TRUE;
+}
+
+/*
+ * The right way to send RPC broadcasts.
+ * Use the clnt_broadcast() RPC service. Unfortunately, clnt_broadcast()
+ * blocks while waiting for replies, so we have to fork off seperate
+ * broadcaster processes that do the waiting and then transmit their
+ * results back to the parent for processing. We also have to remember
+ * to save the name of the domain we're trying to bind in a global
+ * variable since clnt_broadcast() provides no way to pass things to
+ * the 'eachresult' callback function.
+ */
+void
+broadcast(ypdb)
+struct _dom_binding *ypdb;
{
- char buf[1400];
- int fromlen, inlen;
- struct sockaddr_in raddr;
- struct rpc_msg msg;
- XDR xdr;
-
-recv_again:
- bzero((char *)&xdr, sizeof(xdr));
- bzero((char *)&msg, sizeof(msg));
- msg.acpted_rply.ar_verf = _null_auth;
- msg.acpted_rply.ar_results.where = (caddr_t)&rmtcr;
- msg.acpted_rply.ar_results.proc = xdr_rmtcallres;
-
-try_again:
- fromlen = sizeof (struct sockaddr);
- inlen = recvfrom(rpcsock, buf, sizeof buf, 0,
- (struct sockaddr *)&raddr, &fromlen);
- if(inlen<0) {
- if(errno==EINTR)
- goto try_again;
- return RPC_CANTRECV;
+ bool_t out = FALSE;
+ enum clnt_stat stat;
+ int i;
+
+ if (children > MAX_CHILDREN)
+ return;
+
+ broad_domain = ypdb->dom_domain;
+
+ if (pipe(fd) < 0) {
+ syslog(LOG_WARNING, "pipe: %s",strerror(errno));
+ return;
}
- if(inlen<sizeof(u_long))
- goto recv_again;
- /*
- * see if reply transaction id matches sent id.
- * If so, decode the results.
- */
- xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE);
- if( xdr_replymsg(&xdr, &msg)) {
- if( (msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
- (msg.acpted_rply.ar_stat == SUCCESS)) {
- raddr.sin_port = htons((u_short)rmtcr_port);
- rpc_received(msg.rm_xid, &raddr, 0);
+ switch(fork()) {
+ case 0:
+ close(fd[0]);
+ break;
+ case -1:
+ syslog(LOG_WARNING, "fork: %s", strerror(errno));
+ close(fd[1]);
+ close(fd[0]);
+ return;
+ default:
+ for (i = 0; i < FD_SETSIZE; i++) {
+ if (child_fds[i] < 0) {
+ child_fds[i] = fd[0];
+ break;
+ }
}
+ close(fd[1]);
+ children++;
+ return;
}
- xdr.x_op = XDR_FREE;
- msg.acpted_rply.ar_results.proc = xdr_void;
- xdr_destroy(&xdr);
- return RPC_SUCCESS;
+ close(ypdb->dom_lockfd);
+ stat = clnt_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK,
+ xdr_domainname, (char *)ypdb->dom_domain, xdr_bool, (char *)&out,
+ 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 (tell_parent(&ypdb->dom_domain, &ypdb->dom_server_addr))
+ syslog(LOG_WARNING, "lost connection to parent");
+ }
+ exit(0);
}
/*
- * LOOPBACK IS MORE IMPORTANT: PUT IN HACK
+ * 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
+ * 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
+ * every effort to keep our default domain bound, however, since we
+ * need it to keep the system on its feet.
*/
-rpc_received(dom, raddrp, force)
+int
+ping(ypdb, force)
+struct _dom_binding *ypdb;
+int force;
+{
+ bool_t out;
+ struct timeval interval, timeout;
+ enum clnt_stat stat;
+ int rpcsock = RPC_ANYSOCK;
+ time_t t;
+
+ interval.tv_sec = 5;
+ interval.tv_usec = 0;
+ timeout.tv_sec = FAIL_THRESHOLD;
+ timeout.tv_usec = 0;
+
+ 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,
+ interval, &rpcsock, RPCSMALLMSGSIZE,
+ RPCSMALLMSGSIZE)) == (CLIENT *)NULL) {
+ /* Can't get a handle: we're dead. */
+ ypdb->client_handle = NULL;
+ ypdb->dom_alive = 0;
+ ypdb->dom_vers = -1;
+ flock(ypdb->dom_lockfd, LOCK_UN);
+ return(1);
+ }
+ }
+
+ if ((stat = clnt_call(ypdb->client_handle, YPPROC_DOMAIN_NONACK,
+ xdr_domainname, (char *)ypdb->dom_domain,
+ xdr_bool, (char *)&out, timeout)) != RPC_SUCCESS) {
+ ypdb->client_handle = NULL;
+ ypdb->dom_alive = 0;
+ ypdb->dom_vers = -1;
+ flock(ypdb->dom_lockfd, LOCK_UN);
+ return(1);
+ }
+ /*
+ * We pinged successfully. Reset the timer.
+ */
+ time(&t);
+ ypdb->dom_check = t + PING_INTERVAL;
+
+ return(0);
+}
+
+void rpc_received(dom, raddrp, force)
char *dom;
struct sockaddr_in *raddrp;
int force;
@@ -660,28 +648,21 @@ int force;
if(dom==NULL)
return;
+
+ for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext)
+ if( strcmp(ypdb->dom_domain, dom) == 0)
+ break;
+
/* if in securemode, check originating port number */
if (ypsecuremode && (ntohs(raddrp->sin_port) >= IPPORT_RESERVED)) {
syslog(LOG_WARNING, "Rejected NIS server on [%s/%d] for domain %s.",
inet_ntoa(raddrp->sin_addr), ntohs(raddrp->sin_port),
dom);
+ if (ypdb != NULL)
+ ypdb->dom_alive = -1;
return;
}
- for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext)
- if( strcmp(ypdb->dom_domain, dom) == 0)
- break;
-
- if (ypdb != NULL && ypdb->dom_vers == YPVERS && ypdb->dom_alive == 1 &&
- ypdb->dom_server_addr.sin_addr.s_addr != raddrp->sin_addr.s_addr)
- /*
- * We're received a second response to one of our broadcasts
- * from another server, and we've already bound: drop
- * the response on the floor. No sense changing servers
- * for no reason.
- */
- return;
-
if(ypdb==NULL) {
if(force==0)
return;
@@ -689,39 +670,32 @@ int force;
bzero((char *)ypdb, sizeof *ypdb);
strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain);
ypdb->dom_lockfd = -1;
+ ypdb->dom_default = 0;
ypdb->dom_pnext = ypbindlist;
ypbindlist = ypdb;
}
- /* soft update, alive, less than FAIL_THRESHOLD seconds old */
- if(ypdb->dom_alive==1 && (force==0 || ypdb->dom_answered == 0)
- && (ypdb->dom_check_t - FAIL_THRESHOLD) > time(NULL)
- && (ypdb->dom_server_addr.sin_port == raddrp->sin_port)) {
- ypdb->dom_answered = 1;
- ypdb->dom_interval = 60;
+ if (raddrp->sin_addr.s_addr == (long)0) {
+ ypdb->dom_broadcasting = 0;
return;
}
- /*
- * We've recovered from a crash: inform the world.
- */
- if (ypdb->dom_vers == 0)
- syslog(LOG_NOTICE, "NIS server [%s] for domain %s OK.",
- inet_ntoa(raddrp->sin_addr), ypdb->dom_domain);
+ /* 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);
bcopy((char *)raddrp, (char *)&ypdb->dom_server_addr,
sizeof ypdb->dom_server_addr);
ypdb->dom_vers = YPVERS;
ypdb->dom_alive = 1;
- ypdb->dom_answered = 1;
- ypdb->dom_interval = 60;
- ypdb->dom_check_t = time(NULL) + ypdb->dom_interval;
+ ypdb->dom_broadcasting = 0;
if(ypdb->dom_lockfd != -1)
close(ypdb->dom_lockfd);
- sprintf(path, "%s/%s.%d", BINDINGDIR,
+ sprintf(path, "%s/%s.%ld", BINDINGDIR,
ypdb->dom_domain, ypdb->dom_vers);
#ifdef O_SHLOCK
if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) {
@@ -755,7 +729,7 @@ int force;
ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = raddrp->sin_port;
if( writev(ypdb->dom_lockfd, iov, 2) != iov[0].iov_len + iov[1].iov_len) {
- perror("write");
+ syslog(LOG_WARNING, "write: %s", strerror(errno));
close(ypdb->dom_lockfd);
ypdb->dom_lockfd = -1;
return;
OpenPOWER on IntegriCloud