📄 nsrec.c
字号:
} } alarm(0); LOG2(L_COMM,"(%5d) recovery: ready to decide\n",Logstamp); for (np=Nsinfo; np < &Nsinfo[MAXNS]; np++) { switch (np->n_state) { case R_PRIME: if (pnp != NULL) { PLOG3("RFS name server: WARNING: found 2 name servers, %s and %s\n", pnp->n_dname, np->n_dname); PLOG2("RFS name server: Using %s as primary\n", pnp->n_dname); break; } pnp = np; LOG3(L_COMM,"(%5d) recovery: state of %s is R_PRIME\n", Logstamp, np->n_dname); break; case R_NOTPRIME: LOG4(L_COMM,"(%5d) recovery: state of %s is %s R_NOTPRIME\n", Logstamp, np->n_dname, (npnp)?"":"first"); if (!npnp) npnp = np; break; case R_UNK: LOG3(L_COMM,"(%d) recovery: no resp from connected ns %s\n", Logstamp, np->n_dname); np->n_state = R_DEAD; /* fall through to clean up port */ case R_DEAD: case R_PENDING: LOG4(L_COMM,"(%5d) recovery state of %s is %s\n", Logstamp, np->n_dname, (np->n_state == R_DEAD)? "R_DEAD":"R_PENDING, set to R_DEAD"); np->n_state = R_DEAD; if (np->n_pd != -1) { nsrclose(np->n_pd); np->n_pd = -1; } break; } } if (!pnp && !(pnp = npnp)) { PLOG1("RFS name server: recovery: no primary assignment possible\n"); sigset(SIGUSR2,usr2sig); return(RFS_FAILURE); } pnp->n_state = R_PRIME; if (Mynp == pnp) { LOG2(L_ALL,"(%5d) recovery: becoming PRIMARY\n", Logstamp); Primary = TRUE; } else { LOG3(L_ALL,"(%5d) recovery: using %s as PRIMARY\n", Logstamp, pnp->n_dname); } if (Primary) /* tell the world */ for (np=Nsinfo; np < &Nsinfo[MAXNS]; np++) if (np->n_state == R_NOTPRIME) r_sndreq(np->n_pd, np, QUERY, NS_IM_P); /* now re-set sigsets for polling and do any initialization. */ if (!Primary) { sigset(SIGALRM,r_poll); Alarmsig = (void (*)()) r_poll; } else { sigset(SIGALRM,r_checkup); Alarmsig = (void (*)()) r_checkup; } alarm((timesave)?timesave:Polltime); sigset(SIGUSR2,usr2sig); return(RFS_SUCCESS);}intr_sndreq(pd, np, flags, opcode)int pd;struct ns_info *np;int flags;int opcode;{ char *block=NULL; static int size=0; static struct header Head; static struct request Req; Req.rq_head = &Head; Head.h_version = NSVERSION; Head.h_flags = flags; Head.h_opcode = opcode; Head.h_dname = Dname; LOG6(L_COMM,"(%5d) r_sndreq: send %s %s to machine %s on pd %d\n", Logstamp, fntype(opcode), (flags&QUERY)?"query":"response", np->n_dname, pd); if ((block = reqtob(&Req, block, &size)) == NULL) { LOG3(L_ALL,"(%5d) recovery reqtob 2 failed, ns=%s\n", Logstamp,np->n_dname); return(RFS_FAILURE); } if (nswrite(pd,block,size) == -1) { LOG3(L_ALL,"(%5d) recovery: can't reply IM_NP to %s\n", Logstamp,np->n_dname); np->n_state = R_DEAD; free(block); return(RFS_FAILURE); } free(block); return(RFS_SUCCESS);}struct ns_info *pdtonp(pd)int pd;{ register struct ns_info *np = &Nsinfo[0]; register struct ns_info *ep = &Nsinfo[MAXNS]; if (pd == -1) return(NULL); while (np < ep) { if (np->n_pd == pd && np->n_state != R_UNUSED) return(np); np++; } return(NULL);}/* * check a port descriptor, pd, before it is closed and clean up * any ns_info structure associated with it. */intnp_clean(pd)int pd;{ struct ns_info *np; if ((np = pdtonp(pd)) != NULL) { np->n_pd = -1; np->n_state = R_DEAD; } return;}voidrst_alrm(){ alarm(0); Rdone = TRUE;}struct ns_info *nmtonp(name)char *name;{ register struct ns_info *np = &Nsinfo[0]; register struct ns_info *ep = &Nsinfo[MAXNS]; if (name == NULL) return(NULL); while (np < ep) { if (np->n_state != R_UNUSED && strcmp(name,np->n_dname) == NULL) return(np); np++; } return(NULL);}checkver(req)struct request *req;{ if (req->rq_head->h_version > NSVERSION) { LOG4(L_ALL,"(%5d) checkver: version mismatch, reqver %d, nsver %d\n", Logstamp, req->rq_head->h_version, NSVERSION); return(RFS_FAILURE); } return(RFS_SUCCESS);}intnsrecover(pd,type)int pd;int type;{ struct ns_info *np; LOG2(L_COMM,"(%5d) nsrecover: enter\n",Logstamp); np = pdtonp(pd); switch(type) { case REC_CON: /* wait for poll message */ break; case REC_ACC: /* got reply to checkup connection, send poll. */ if (r_sndreq(pd, np, QUERY, (Primary)?NS_IM_P:NS_IM_NP) == RFS_FAILURE) { nsrclose(pd); np->n_state = R_DEAD; np->n_pd = -1; } else np->n_state = R_UNK; break; case REC_HUP: nsrclose(pd); if (np) { np->n_pd = -1; if (np->n_state == R_PRIME) return(setrstate()); np->n_state = R_DEAD; } break; } return(RFS_SUCCESS);}/* * check an incoming request of type NS_IM_P or NS_IM_NP for * basic sanity. I.e., make sure there are no conflicts with * what is known about the machine already. */intr_sane(req,pd)struct request *req;int pd;{ struct ns_info *np; struct header *hp = req->rq_head; if ((np = nmtonp(hp->h_dname)) == NULL) { LOG3(L_ALL,"RFS name server: rcvd %s msg from unk NS %s\n", getctype(hp->h_opcode),hp->h_dname); /* return success since we don't want to stop here */ nsrclose(pd); return(RFS_SUCCESS); } if (np->n_pd == -1) np->n_pd = pd; switch (hp->h_opcode) { case NS_IM_P: if (Primary) { PLOG2("RFS name server: NS %s, primary collision\n", hp->h_dname); /* yield if other machine is higher on list */ if (nmtonp(Dname) > np) return(setrstate()); /* otherwise tell it who's boss */ if (r_sndreq(pd, np, QUERY, NS_IM_P) == RFS_FAILURE) { nsrclose(pd); np->n_state = R_DEAD; np->n_pd = -1; return(setrstate()); } return(RFS_SUCCESS); } if (np->n_state != R_PRIME) { LOG3(L_ALL,"(%5d): found possible second primary %s\n", Logstamp, hp->h_dname); return(setrstate()); } break; case NS_IM_NP: switch (np->n_state) { case R_UNK: case R_DEAD: np->n_state = R_NOTPRIME; break; case R_NOTPRIME: break; default: LOG3(L_ALL,"(%5d) %s changing state to NS_IM_NP\n", Logstamp,hp->h_dname); return(setrstate()); } break; } return(RFS_SUCCESS);}/* * periodic polling routine for primary machine. */intr_checkup(){ register struct ns_info *np = &Nsinfo[0]; register struct ns_info *ep = &Nsinfo[MAXNS]; void (*usr2sig)(); usr2sig = sigset(SIGUSR2,SIG_HOLD); sigset(SIGALRM,SIG_IGN); alarm(0); for (; np < ep; np++) { if (np->n_state == R_UNUSED) continue; if (strcmp(Dname,np->n_dname) == 0) continue; if (np->n_pd == -1) { if ((np->n_pd = rconnect(np->n_addr,RECOVER)) == -1) np->n_state = R_DEAD; else np->n_state = R_PENDING; } else if (r_sndreq(np->n_pd, np, QUERY,(Primary)?NS_IM_P:NS_IM_NP) == RFS_FAILURE) { np->n_state = R_DEAD; nsrclose(np->n_pd); np->n_pd = -1; } } sigset(SIGALRM,r_checkup); alarm(Polltime); sigset(SIGUSR2,usr2sig); return;}/* * periodic polling routine for secondary machine. */intr_poll(){ int i; int pd; char qbuf[BUFSIZ]; char *block = NULL; int size = 0; void (*usr2sig)(); static struct header Head; static struct request Req; static struct question Question; struct question *qp = &Question; LOG2(L_COMM,"(%5d) r_poll: enter\n",Logstamp); usr2sig = sigset(SIGUSR2,SIG_HOLD); sigset(SIGALRM,SIG_IGN); alarm(0); if ((pd = primepd()) == -1) { if (setrstate() == RFS_FAILURE) Done = TRUE; /* don't reset SIGALRM, setrstate will do that */ sigset(SIGUSR2,usr2sig); return; } LOG2(L_COMM,"(%5d) r_poll: polling primary\n",Logstamp); Req.rq_head = &Head; Head.h_version = NSVERSION; Head.h_flags = QUERY; Head.h_opcode = NS_QUERY; Head.h_dname = Dname; Head.h_qdcnt = 1; Req.rq_qd = &qp; Question.q_name = qbuf; Question.q_type = ANYTYPE; for (i=0; i < Mylastdom; i++) {#ifdef RIGHT_TO_LEFT sprintf(qbuf,"%c%c%s",WILDCARD,SEPARATOR,Mydomains[i]);#else sprintf(qbuf,"%s%c%c",Mydomains[i],SEPARATOR,WILDCARD);#endif LOG3(L_COMM,"(%5d) r_poll: poll primary for domain %s\n", Logstamp, Mydomains[i]); if ((block = reqtob(&Req,block,&size)) == NULL) { LOG3(L_ALL,"(%5d) r_poll: reqtob failed domain = %s\n", Logstamp, Mydomains[i]); continue; } if (nswrite(pd,block,size) == -1) { LOG2(L_ALL,"(%5d) r_poll: write to primary failed\n", Logstamp); free(block); if (setrstate() == RFS_FAILURE) Done = TRUE; /* don't reset SIGALRM, setrstate will do that */ sigset(SIGUSR2,usr2sig); return; } free(block); block = NULL; } sigset(SIGALRM,r_poll); alarm(Polltime); sigset(SIGUSR2,usr2sig); return;}intprimepd(){ register struct ns_info *np = &Nsinfo[0]; register struct ns_info *ep = &Nsinfo[MAXNS]; while (np < ep) { if (np->n_state == R_PRIME) return(np->n_pd); np++; } return(-1);}/* * add data collected by poll to database */intnsdata(req)struct request *req;{ long i; char fname[BUFSIZ]; char dname[BUFSIZ]; struct header *hp; LOG2(L_COMM,"(%5d) nsdata: enter\n",Logstamp); hp = req->rq_head; if (hp->h_rcode != R_NOERR || hp->h_qdcnt <= 0) { LOG4(L_ALL,"(%5d) nsdata: rcode %d or qdcnt %d bad\n", Logstamp, hp->h_rcode, hp->h_qdcnt); return(R_NSFAIL); } if (!(hp->h_flags & AUTHORITY)) { if (setrstate() == RFS_FAILURE) { Done = TRUE; return(R_NSFAIL); } return(R_NOERR); } strcpy(dname,dompart(req->rq_qd[0]->q_name)); LOG3(L_COMM,"(%5d) nsdata: reply for domain %s\n", Logstamp,dname); if (!mydom(dname)) { LOG3(L_ALL,"(%5d) nsdata: reply rcvd for un-owned domain %s\n", Logstamp,dname); return(R_NSFAIL); } cleardom(dname); for (i=0; i < hp->h_ancnt; i++) {#ifdef RIGHT_TO_LEFT sprintf(fname,"%s%c%s",req->rq_an[i]->rr_name,SEPARATOR,dname);#else sprintf(fname,"%s%c%s",dname,SEPARATOR,req->rq_an[i]->rr_name);#endif LOG4(L_COMM,"(%5d) nsdata: addrr %s, %s\n", Logstamp,fname,prec(req->rq_an[i])); addrr(fname,req->rq_an[i]); } return(R_NOERR);}/* * ns_rel handles rfadmin -p. if the request is local, it sends * a copy of its current database to the secondaries and goes into * recovery, sending NS_RELs to each secondary. If the request * is remote, it should be from the primary, and signals the need * to go into recovery to get a new primary. */intns_rel(pd)int pd;{ struct res_rec **rlist; struct request *req; struct header *hp; struct request *nreq; int ret; int i; char *key=NULL; struct request *newreq(); struct request *nsfunc(); struct ns_info *np; struct nsport *pptr = pdtoptr(pd); if (!pptr) return(R_FAIL); switch(pptr->p_mode) { case LOCAL: /* this is the primary side of rfadmin -p */ if (!Primary) return(R_PERM); break; case RECOVER: /* this is the secondary side of rfadmin -p */ if ((np=pdtonp(pd)) == NULL) return(R_FAIL); if (Primary || np->n_state != R_PRIME) return(R_PERM); /* now "remove" primary from recovery algorithm */ np->n_state = R_UNUSED; remfrsel(pptr); if (setrstate() == RFS_FAILURE) { PLOG1("RFS name server: FATAL recovery error\n"); Done = TRUE; return(R_NSFAIL); } addtosel(pptr); np->n_state = R_UNK; return(R_NOERR); default: return(R_FORMAT); } /* at this point we have legitimate local requests only */ if ((req = newreq(NS_QUERY,QUERY,Dname)) == NULL) return(R_NSFAIL); if ((key = malloc(MAXDNAME)) == NULL || (req->rq_qd=(struct question **)malloc(sizeof(struct question *))) == NULL|| (req->rq_qd[0]=(struct question *)malloc(sizeof(struct question))) == NULL){ if (key) free(key); freerp(req); return(R_NSFAIL); } hp = req->rq_head; hp->h_qdcnt = 1; req->rq_qd[0]->q_name = key; req->rq_qd[0]->q_type = ANYTYPE; for (i=0; i < Mylastdom; i++) { sprintf(key,"%s.%c",Mydomains[i],WILDCARD); if ((nreq = nsfunc(req,-1)) == NULL) { freerp(req); return(R_NSFAIL); } if (nspass(nreq) == RFS_FAILURE) { freerp(req); freerp(nreq); return(R_NSFAIL); } freerp(nreq); } freerp(req); ret = nsrel(); return(ret);}intnspass(nreq)struct request *nreq;{ char *block = NULL; int size = 0; int i; struct ns_info *np; struct header *hp = nreq->rq_head; LOG2(L_ALL,"(%5d) nsrel: relinquish primary status\n",Logstamp); if ((block = reqtob(nreq,block,&size)) == NULL) { LOG2(L_ALL,"(%5d) nsrel: reqtob failed\n",Logstamp); return(RFS_FAILURE); } for (i=0, np = Nsinfo; i < MAXNS; i++, np++) if (np->n_state == R_NOTPRIME) nswrite(np->n_pd,block,size); free(block); return(RFS_SUCCESS);}intnsrel(){ int i; int polled = 0; struct ns_info *np; struct nsport *pptr; for (i=0, np = Nsinfo; i < MAXNS; i++, np++) if (np->n_state == R_NOTPRIME && strcmp(Dname,np->n_dname)) { if (r_sndreq(np->n_pd, np, QUERY, NS_REL) == RFS_FAILURE) { nsrclose(np->n_pd); np->n_pd = -1; np->n_state = R_DEAD; } else polled++; } if (polled == 0) { LOG2(L_ALL,"(%5d) nsrel: can't pass control, no secondaries\n", Logstamp); return(R_NONAME); } alarm(0); sigrelse(SIGALRM); sleep(R_TIMEOUT+5); for (i=0, np = Nsinfo; i < MAXNS; i++, np++) if (np->n_state == R_NOTPRIME && strcmp(Dname,np->n_dname)) { pptr = pdtoptr(np->n_pd); if (ioctl(pptr->p_fd,I_FLUSH,FLUSHR) == -1) { nsrclose(np->n_pd); np->n_pd = -1; np->n_state = R_DEAD; } } if (setrstate() == RFS_FAILURE) { PLOG1("RFS name server: FATAL error, nsrel recovery failure\n"); Done = TRUE; return(R_NSFAIL); } /* make sure we still aren't primary */ if (Primary) return(R_NONAME); return(R_NOERR);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -