⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nserve.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	@(#)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 + -