📄 nserve.c
字号:
/* @(#)nserve.c 1.1 92/07/30 SMI *//* Copyright (c) 1984 AT&T *//* All Rights Reserved *//* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T *//* The copyright notice above does not evidence any *//* actual or intended publication of such source code. */#ident "@(#)nserve:nserve.c 1.26.1.1"#include <stdio.h>#include <string.h>#include <errno.h>#include <signal.h>#include <sys/utsname.h>#include <errno.h>#include <fcntl.h>#include "nsdb.h"#include "nslog.h"#include <tiuser.h>#include <rfs/nsaddr.h>#include "stdns.h"#include <rfs/nserve.h>#include "nsports.h"#include "nsrec.h"#include <unistd.h>#include <rfs/rfsys.h>#ifdef LOGGING#define USAGE "Usage: %s [-krv][-l level][-f logfile][-n master][-t secs][-p addr] net_spec\n\ level = one or more of 'abcdmnopst'\n"#define GETOPT_ARG "t:n:l:f:p:krvN"#else#define USAGE "Usage: %s [-kv][-p address] net_spec\n"#define GETOPT_ARG "p:kv"#endifchar Dname[MAXDNAME]; /* machine's full domain name */int Done=FALSE; /* set before exit */char *Netmaster=NETMASTER; /* master file for name server */int Primary=FALSE; /* is this machine primary? */int Oedipus=FALSE; /* kill parent after startup? */int Verify=FALSE; /* verify incoming requests? */int Recover=TRUE; /* Recovery enabled */struct address *Paddress[MAXNS]; /* address(es) of primaries */struct address *Myaddress=NULL; /* address of this machine */struct address *getmyaddr(); /* just what you would think */static int sigterm(); /* function for SIGTERM */static int waitcld(); /* function for SIGUSR2 */static int savecld(); /* save info about children */static int setnslock(); /* put pid in NSPID, lock. */int r_init(); /* set up recovery and ns addrs */void (*Alarmsig)()=SIG_IGN; /* current value for alarm */char *dompart();char *aatos();struct address *astoa();static struct childinfo { /* struct to keep active children */ int c_pid; struct request *c_req;} Children[MAXCHILDREN];extern char *Net_spec; /* listener's network id */extern int Polltime; /* polling interval for backup */extern char *optarg;extern int optind, opterr;extern int sys_nerr;extern char *sys_errlist[];#define CHILDTIME 300 /* length of sanity timer for child process */#define CHILDWAIT 10 /* maximum time to wait for child to exit */main(argc,argv)int argc;char *argv[];{ int c; int ret; int errflg=0; FILE *fopen(); int pd; int ppid; char tmpbuf[BUFSIZ]; int nofork = 0; while ((c = getopt(argc,argv,GETOPT_ARG)) != EOF) switch (c) { case 'n': /* net master file */ Netmaster = optarg; break; case 'l': /* log level */ Loglevel = setlog(optarg); break; case 'f': /* log file */ if ((Logfd = fopen(optarg,"w")) == NULL) { Logfd = stderr; fprintf(stderr, "nserve: WARNING can't open logfile '%s'\n",optarg); } else { fclose(Logfd); Logfd = freopen(optarg,"w",stderr); } break; case 'p': /* here is the primary's address */ sprintf(tmpbuf,"%s",optarg); LOG3(L_ALL,"(%5d) nserve: set Paddress to %s\n", Logstamp,tmpbuf); if ((Paddress[0] = astoa(tmpbuf,NULL)) == NULL) { fprintf(stderr, "nserve: -p option given bad primary address=%s\n", tmpbuf); errflg++; } break; case 'k': /* kill parent */ Oedipus = TRUE; break; case 'v': /* enable verification. */ Verify = TRUE; break; case 'r': /* turn recovery off */ Recover = FALSE; break; case 't': /* set poll time */ if ((Polltime = atoi(optarg)) < 0) Polltime = POLLTIME; break; case 'N': nofork = 1; break; case '?': errflg++; break; } ppid = getppid(); if (errflg || optind >= argc) { if (Oedipus) kill(ppid, SIGUSR2); else fprintf(stderr,USAGE,argv[0]); exit(2); } Net_spec = argv[optind]; if (netname(Dname) == -1) { if (Oedipus) kill(ppid, SIGUSR2); exit(2); } /* need to put this in background if not started by rfstart */ if (!nofork) { if (!Oedipus && fork()) exit(0); } sigset(SIGHUP,SIG_IGN); sigset(SIGINT,SIG_IGN); sigset(SIGQUIT,SIG_IGN); sigset(SIGTERM,SIG_IGN); sigset(SIGALRM,SIG_IGN); if (setnslock()) { PLOG1("RFS Name server already running\n"); if (Oedipus) kill(ppid, SIGUSR2); exit(2); } /* initialize the database */ if (Paddress[0]) { Paddress[0]->protocol = copystr(Net_spec); if (putprime(Paddress[0]) == RFS_FAILURE) { if (Oedipus) kill(ppid, SIGUSR2); clrnslock(); exit(2); } } else if ((errflg = readdb(Netmaster)) <= 0) { if (errflg == 0) PLOG2("RFS name server: %s is empty\n",Netmaster); else PLOG3("RFS name server: can't open %s, error %s\n", Netmaster, (errno > sys_nerr)?"unknown error":sys_errlist[errno]); if (Oedipus) kill(ppid, SIGUSR2); clrnslock(); exit(2); } if (merge(DOMMASTER,FALSE) == 0) LOG2(L_OVER,"nserve: warning, %s file empty or missing\n", DOMMASTER); if (nslisten() == -1) { if (Oedipus) kill(ppid, SIGUSR2); clrnslock(); exit(2); } LOG1(L_OVER,"nserve: listen port opened\n"); sigset(SIGTERM,sigterm); if (r_init() == RFS_FAILURE) { if (Oedipus) kill(ppid, SIGUSR2); exit(2); } /* alarm signal may have been set by r_init, so hold it quick */ sigset(SIGALRM,SIG_HOLD); /* notify rfstart of successful start up */ if (Oedipus) kill(ppid, SIGUSR1); setpgrp(); fclose(stdin); fclose(stdout); if (Verify) rfsys(RF_VFLAG,V_SET); else rfsys(RF_VFLAG,V_CLEAR); for (Logstamp=0; Done == FALSE; Logstamp++) { /* only allow these signals in poll */ sigset(SIGUSR2,waitcld); sigset(SIGALRM,Alarmsig); ret = nswait(&pd); sigset(SIGALRM,SIG_HOLD); sigset(SIGUSR2,SIG_HOLD); LOG3(L_ALL,"(%5d) nserve: got req %d\n",Logstamp, ret); switch (ret) { case LOC_REQ: nsreq(pd,LOCAL); break; case REC_CON: case REC_HUP: case REC_ACC: if (nsrecover(pd,ret) == RFS_FAILURE) Done = TRUE; break; case REM_REQ: case REC_IN: nsreq(pd,REMOTE); break; case NON_FATAL: break; case FATAL: Done = TRUE; break; } LOG3(L_ALL,"(%5d) nserve: processed req %d\n",Logstamp, ret); /* if we got sigterm or fatal, we will exit, else continue */#ifdef LOGGING fflush(Logfd);#endif } LOG2(L_ALL,"(%5d) nserve: normal exit\n",Logstamp); sigterm(0); /* sigterm cleans up and exits */ exit(0); /* NOTREACHED */}static intnsreq(pd,mode)int pd; /* port descriptor for incoming request */int mode; /* source of request: REMOTE or LOCAL */{ char *block=NULL; struct request *req; struct request *nsfunc(); struct request *nreq; struct header *hp; int cwait=FALSE; /* set if we need to wait for child */ int size; LOG4(L_TRANS | L_OVER,"(%5d) nsreq: rcvd %s request on port %d\n", Logstamp,(mode==LOCAL)?"LOCAL":"REMOTE",pd); if ((size = nsread(pd,&block,0)) == -1) { LOG2(L_ALL,"(%5d) nsreq: nsread failed\n",Logstamp); nsrclose(pd); return; } if ((req = btoreq(block,size)) == NULL) { LOG2(L_ALL,"(%5d) nsreq: btoreq failed\n",Logstamp); if (sndback(pd,R_FORMAT) == RFS_FAILURE) nsrclose(pd); if (block) free(block); return; } if ((nreq = nsfunc(req,pd)) == NULL) { LOG2(L_ALL,"(%5d) nsreq: nsfunc returns NULL\n",Logstamp); if (req->rq_head->h_flags & QUERY) { if (sndback(pd,R_NSFAIL) == RFS_FAILURE) nsrclose(pd); } free(block); freerp(req); return; } hp = nreq->rq_head; hp->h_flags &= ~QUERY; if (mode == REMOTE || (hp->h_rcode != R_NOERR && hp->h_rcode != R_NONAME) || req->rq_head->h_opcode == NS_REL || (Primary && domauth(dompart(req->rq_qd[0]->q_name)))) { LOG3(L_TRANS | L_OVER,"(%5d) nsreq: request returns %s\n", Logstamp,prtype(hp->h_rcode)); free(block); block = NULL; if (req->rq_head->h_flags & QUERY) { block = reqtob(nreq,block,&size); if (nswrite(pd,block,size) == -1) { LOG2(L_ALL,"(%5d) nsreq: nswrite failed\n", Logstamp); nsrclose(pd); } if (block) free(block); } freerp(req); freerp(nreq); return; } /* we now have good response, check for any remote operations */ switch ((int) req->rq_head->h_opcode) { /* anything going to the primary name server ONLY, goes here */ case NS_ADV: case NS_UNADV: case NS_MODADV: case NS_INIT: case NS_VERIFY: case NS_SENDPASS: case NS_FINDP: if (!Primary) { /* remsend takes care of reply */ remsend(pd,block,size,nreq,req); if (req->rq_head->h_opcode == NS_INIT) { waitcld(); /* NS_INIT child does not signal */ if (!Primary && alarm(0) != 0) alarm(10); /* make first poll immediate */ } cwait=TRUE; /* wait for child */ break; } LOG3(L_TRANS | L_OVER,"(%5d) nsreq: ADV/UNADV returns rcode = %s\n", Logstamp,prtype(hp->h_rcode)); if (block) { free(block); block = NULL; } block = reqtob(nreq,block,&size); if (nswrite(pd,block,size) == -1) { LOG2(L_ALL,"(%5d) nsreq: nswrite failed\n",Logstamp); nsrclose(pd); } break; case NS_BYMACHINE: case NS_QUERY: /* * check to see if response was answer or indirect. * The presence of an answer section means that there * is a response to return. But, if we are not primary, * go to primary for authoritative answer. If we are * primary, check out any indirection. */ if (!Primary) { remsend(pd,block,size,nreq,NULL); break; } if (hp->h_ancnt != 0) { LOG4(L_TRANS | L_OVER, "(%5d) nsreq: returns %d records rcode = %s\n", Logstamp,hp->h_ancnt,prtype(hp->h_rcode)); if (block) { free(block); block = NULL; } block = reqtob(nreq,block,&size); if (nswrite(pd,block,size) == -1) { LOG2(L_ALL,"(%5d) nsreq: nswrite failed\n", Logstamp); nsrclose(pd); } } else if (hp->h_nscnt == 0 || hp->h_arcnt == 0) { LOG2(L_ALL,"(%5d) nsreq: can't make indirect ref.\n", Logstamp); if (sndback(pd,R_RCV) == RFS_FAILURE) nsrclose(pd); } else { /* we have some indirect references to try */ remsend(pd,block,size,nreq,NULL); } break; default: /* unknown type */ LOG3(L_ALL,"(%5d) nsreq: unknown req type = %d\n", Logstamp,req->rq_head->h_opcode); if (sndback(pd,R_FORMAT) == RFS_FAILURE) nsrclose(pd); break; } /* now just clean up and continue */ if (!cwait) freerp(req); if (block) free(block); freerp(nreq); return;}/* * * remsend assigns a new port, and forks. * The parent continues as a normal name server. * The child completes the remote part of the transaction. * * When oreq is set, the request will be stored for backout if the * operation fails. Oreq should only be set for those functions * that go to the primary domain name server, because remsend relies * on this to return the correct failure message when the primary * cannot be reached. * */static intremsend(pd,block,size,req,oreq)int pd; /* local port descriptor */char *block;int size;struct request *req; /* request, if non-NULL, contains addresses */struct request *oreq; /* request, if non-NULL, contains undo info */{ int npd; int chg = 0; /* return from mkalist, no. of new addresses */ int i; char *nblock; int nsize; int child; int ret=R_NOERR; struct address *addrlist[MAX_RETRY]; struct request *nreq; struct header *hp=NULL; static int sane_cld(); /* sanity check for child process */ LOG2(L_OVER,"(%5d) remsend: send request to remote ns\n",Logstamp); /* now fork to handle the remote part */ switch(child = fork()) { case (-1): /* error */ LOG2(L_ALL,"(%5d) remsend: fork() failed\n",Logstamp); if (sndback(pd,R_SYS) == RFS_FAILURE) nsrclose(pd); return; default: /* parent */ /* if request was passed in, save for possible backout */ if (oreq) savecld(child,oreq); nsrclose(pd); return; case 0: /* child */#ifdef LOGGING Logstamp += 1000; /* differentiate child in output */#endif alarm(CHILDTIME); sigset(SIGALRM,sane_cld); sigset(SIGTERM,SIG_IGN); break; } /* * only get here if child, now need to handle remote stuff * and exit. */ addrlist[0] = NULL; /* list ended by null (unless full) */ chg = mkalist(addrlist,req,NULL); if (!Primary) mkalist(addrlist,NULL,Paddress); for (i=0; i < MAX_RETRY && addrlist[i] != NULL; i++) { if (eqaddr(Myaddress,addrlist[i])) continue; LOG3(L_ALL,"(%5d) remsend: try to connect to %s\n", Logstamp,aatos(Logbuf,addrlist[i],KEEP | HEX)); if ((npd = rconnect(addrlist[i],REMOTE)) == -1) { LOG3(L_ALL,"(%5d) remsend: can't connect to %s\n", Logstamp,aatos(Logbuf,addrlist[i],KEEP | HEX)); continue; } if (nswrite(npd,block,size) == -1) { LOG2(L_ALL,"(%5d) remsend: nswrite failed\n",Logstamp); nsrclose(npd); continue; } nblock = NULL; if ((nsize=nsread(npd,&nblock,0)) == -1) { LOG2(L_ALL,"(%5d) remsend: nsread failed\n",Logstamp); nsrclose(npd); continue; } if ((nreq = btoreq(nblock,nsize)) == NULL) { LOG4(L_ALL,"(%5d) remsend: btoreq(%x,%d) failed\n", Logstamp,nblock,nsize); free(nblock); nsrclose(npd); continue; } hp = nreq->rq_head;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -