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

📄 listen.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
 * Following are some general queueing routines.  The call list head contains * a pointer to the head of the queue and to the tail of the queue.  Normally, * calls are added to the tail and removed from the head to ensure they are * processed in the order received, however, because of the possible interruption * of an acceptance with the resulting requeueing, it is necessary to have a * way to do a "priority queueing" which inserts at the head of the queue for * immediate processing *//* * queue: * * add calls to tail of queue */voidqueue(head, cp)register struct call_list *head;register struct callsave *cp;{	if (head->cl_tail == (struct callsave *) NULL) {		cp->c_np = (struct callsave *) NULL;		head->cl_head = head->cl_tail = cp;	}	else {		cp->c_np = head->cl_tail->c_np;		head->cl_tail->c_np = cp;		head->cl_tail = cp;	}}/* * pqueue: * * priority queuer, add calls to head of queue */voidpqueue(head, cp)register struct call_list *head;register struct callsave *cp;{	if (head->cl_head == (struct callsave *) NULL) {		cp->c_np = (struct callsave *) NULL;		head->cl_head = head->cl_tail = cp;	}	else {		cp->c_np = head->cl_head;		head->cl_head = cp;	}}/* * dequeue: * * remove a call from the head of queue */struct callsave *dequeue(head)register struct call_list *head;{	register struct callsave *ret;	if (head->cl_head == (struct callsave *) NULL)		error(E_CANT_HAPPEN, EXIT);	ret = head->cl_head;	head->cl_head = ret->c_np;	if (head->cl_head == (struct callsave *) NULL)		head->cl_tail = (struct callsave *) NULL;	return(ret);}/* * open_bind: * * open the network and bind the endpoint to 'name' * this routine is also used by listen(), so it can't exit * under all error conditions: specifically, if there are * no minor devices avaliable in the network driver, open_bind * returns -1.  (error message will be logged).  All other errors * cause an exit. * * If clen is zero, transport provider picks the name and these * routines (open_bind and bind) ignore name and qlen --  * this option is used when binding a name for accepting a connection  * (not for listening.)  You MUST supply a name, qlen and clen when * opening/binding a name for listening. * * Assumptions: driver returns ENXIO when all devices are allocated. */intopen_bind(name, qlen, clen, conp)char *name;int qlen;int clen;unsigned int *conp;{	register fd;	struct t_info t_info;	extern int t_errno, errno;	unsigned int ret;	extern unsigned int bind();	fd = t_open(Provider, NETOFLAG, &t_info);	if (fd < 0)  {		if ( (t_errno == TSYSERR) && ((errno == ENXIO) ||		    (errno == ENOSR) || (errno == EAGAIN) || (errno == ENOSPC)) )  {			tli_error(E_FD1OPEN, CONTINUE);			logmessage("No network minor devices (ENXIO/ENOSR)");			return(-1);		}		tli_error(E_FD1OPEN, EXIT);	}	DEBUG((7,"fd %d opened",fd));	ret = bind(fd, name, qlen, clen);	if (conp)		*conp = ret;	return(fd);}unsigned intbind(fd, name, qlen, clen)register fd;char *name;int qlen;register int clen;{	register struct t_bind *req = (struct t_bind *)0;	register struct t_bind *ret = (struct t_bind *)0;	register char *p, *q;	unsigned int retval;	extern char *t_alloc();	extern void nlsaddr2c();	extern int memcmp();	extern int errno;	extern char *memcpy();#ifdef S4	extern struct netbuf *lname2addr();#endif /* S4 */#ifdef	CHARADDR	char pbuf[NAMEBUFSZ + 1];#endif	char scratch[BUFSIZ];	DEBUG((9,"in bind, clen = %d", clen));	if (clen)  {		errno = t_errno = 0;		while (!(req = (struct t_bind *)t_alloc(fd,T_BIND,T_ALL)) ) {			if ((t_errno != TSYSERR) || (errno != EAGAIN))				tli_error( E_T_ALLOC, EXIT);			else				tli_error( E_T_ALLOC, CONTINUE);		}		errno = t_errno = 0;		while (!(ret = (struct t_bind *)t_alloc(fd,T_BIND,T_ALL)) ) {			if ((t_errno != TSYSERR) || (errno != EAGAIN))				tli_error( E_T_ALLOC, EXIT);			else				tli_error( E_T_ALLOC, CONTINUE);		}		if (clen > req->addr.maxlen)  {			sprintf(scratch,"Truncating name size from %d to %d", 				clen, req->addr.maxlen);			logmessage(scratch);			clen = req->addr.maxlen;		}		(void)memcpy(req->addr.buf, name, clen);		req->addr.len = clen;		req->qlen = qlen;#if defined(CHARADDR) && defined(DEBUGMODE)		(void)memcpy(pbuf, req->addr.buf, req->addr.len);		pbuf[req->addr.len] = (char)0;		DEBUG((3,"bind: fd=%d, logical name=%c%s%c, len=%d",			fd, '\"',pbuf, '\"', req->addr.len));#endif	/* CHARADDR  && DEBUGMODE */#ifdef S4		if (!lname2addr(fd, &(req->addr)))  {			sprintf(scratch, "lname2addr failed, errno %d", errno);			logmessage(scratch);			error(E_SYS_ERROR, EXIT | NO_MSG);		}#endif /* S4 */#if defined(CHARADDR) && defined(DEBUGMODE)		(void)memcpy(pbuf, req->addr.buf, req->addr.len);		pbuf[req->addr.len] = (char)0;		DEBUG((3,"bind: fd=%d, address=%c%s%c, len=%d",			fd, '\"',pbuf, '\"', req->addr.len));#endif	/* CHARADDR  && DEBUGMODE */	}	if (t_bind(fd, req, ret))  {		DEBUG((1,"t_bind failed; t_errno %d errno %d", t_errno, errno));		if (qlen)	/* starup only */			tli_error(E_T_BIND, EXIT | NOCORE);		/* here during normal service */		if ((t_errno == TNOADDR) || ((t_errno == TSYSERR) && (errno == EAGAIN))) {			/* our name space is all used up */			tli_error(E_T_BIND, CONTINUE);			t_close(fd);			return(-1);		}		/* otherwise, irrecoverable error */		tli_error(E_T_BIND, EXIT | NOCORE);	}#if defined(S4) && defined(DEBUGMODE)	t_dump(Debugfp);  /* show TLI internal name structures on Debugfp */#endif	if (clen)  {		retval = ret->qlen;		if ( (ret->addr.len != req->addr.len) ||		     (memcmp( req->addr.buf, ret->addr.buf, req->addr.len)) )  {			p = (char *) malloc(((ret->addr.len) << 1) + 1);			q = (char *) malloc(((req->addr.len) << 1) + 1);			if (p && q) {				nlsaddr2c(p, ret->addr.buf, ret->addr.len);				nlsaddr2c(q, req->addr.buf, req->addr.len);				sprintf(scratch, "attempted to bind address \\x%s", q);				logmessage(scratch);				sprintf(scratch, "actually bound address \\x%s", p);				logmessage(scratch);			}			error(E_BIND_REQ, EXIT | NOCORE);		}		if ( t_free(req, T_BIND) )			tli_error(E_T_FREE, EXIT);		if ( t_free(ret, T_BIND) )			tli_error(E_T_FREE, EXIT);		return(retval);	}	return((unsigned int) 0);}/*  * Clean-up server children corpses. Invoked on receiving the SIGCHLD signal. */void reap_child(){	wait(0);}/* * divorce_parent: fork a child, make child independent of parent. *		   parent writes child's pid to process id file *		   and exits.  If it can't create or write pidfile, *		   child must be killed. * *	Assumptions: directory previously changed to '/'. * *	Notes: define FOREGROUND to inhibit the listener from running *		in the background.  Useful with DEBUGMODE. */divorce_parent(){	char pidstring[50];	/* holds childs pid in ascii decimal */	char scratch[128];	register ret, i;	extern void exit();	struct sigvec sv;	DEBUG((9,"in divorce_parent"));	setpgrp();		/* listener + kids in own p-group	*/	if ( (Pid = fork()) < 0 )		sys_error(E_LSFORK, EXIT);	if (Pid)  {		/* parent: open pid output file and		 *	   write childs process ID to it.		 *	   If it works, exit 0.		 *	   If it doesn't, kill the child and exit non-zero.		 */		i = sprintf(pidstring,"%d",Pid) + 1; /* add null */		if ( (ret = write(Pidfd,pidstring,(unsigned)i)) != i ) {			if (ret < 0)				sys_error(E_PIDWRITE, CONTINUE);			signal(SIGCHLD, SIG_IGN);			kill(Pid, SIGTERM);			error(E_PIDWRITE, EXIT); /* exit with proper code */		}	/*	 * Lock file will be unlocked when parent exits.	 */		exit( 0 );	/* parent exits -- child does the work */	}	/*	 * child: close everything but the network fd's	 * but first, lock the lock file -- blocking lock will wait	 * for parent to exit.	 */	close(Lckfd);	if ((Lckfd = open(LCKNAME, O_WRONLY | O_CREAT, 0666 )) == -1) {				sprintf(scratch, "Error (%d) re-locking the lock file", errno);		logmessage(scratch);		error(E_SYS_ERROR, EXIT | NOCORE | NO_MSG);	}	if (locking(Lckfd, 1, 0L) == -1)  {		sprintf(scratch, "Error (%d) re-locking the lock file", errno);		logmessage(scratch);		error(E_SYS_ERROR, EXIT | NOCORE | NO_MSG);	}	/* Clean up server children corpses -- using sigvec like this 	   prevents handler from getting reset when caught, whereas 	   system V signal() routine resets handler when caught */	sv.sv_handler = (void (*)())reap_child;	sv.sv_mask = 0;	sv.sv_flags = SV_INTERRUPT;	sigvec(SIGCHLD, &sv, (struct sigvec *) 0);	Background = 1;	close_files();}/* * close_files: *		Close all files except what we opened explicitly *		Including stdout, stderr and anything else *		that may be open by whatever exec'ed me. *		We also set the close on exec flag on all fd's *		Note, that we keep fd's 0, 1, and 2 reserved for *		servers by opening them to "/dev/null". */close_files(){	register int i;	register int ndesc;	fclose(stdin);	fclose(stdout);	fclose(stderr);	if (((i = open("/dev/null", O_RDWR)) != 0) || (dup(i) != 1) ||	    (dup(i) != 2))  {		logmessage("Trouble opening/duping /dev/null");		sys_error(E_SYS_ERROR, EXIT | NOCORE);	}	ndesc = ulimit(4, 0L);	/* get value for NOFILE */	for (i = 3; i < ndesc; i++)  {	/* leave stdout, stderr open	*/		fcntl(i, F_SETFD, 1);	/* set close on exec flag*/	}}/* * catch_signals: *		Ignore some, catch the rest. Use SIGTERM to kill me. */catch_signals(){	extern void sigterm();	register int i;	struct sigvec sv;	for (i = 1; i < SIGKILL; i++)		signal(i, SIG_IGN);	for (i = SIGKILL + 1; i < SIGTERM; i++)		signal(i, SIG_IGN);	sv.sv_handler = (void (*)())sigterm;	sv.sv_mask = 0;	sv.sv_flags = SV_INTERRUPT;	sigvec(SIGTERM, &sv, (struct sigvec *) 0);	for (i = SIGTERM + 1; i < NSIG; i++)		signal(i, SIG_IGN);	errno = 0;	/* SIGWIND and SIGPHONE only on UNIX PC */}/* * rst_signals: *		After forking but before exec'ing a server, *		reset all signals to defaults. *		exec automatically resets 'caught' sigs to SIG_DFL. *		(This is quick and dirty for now.) */rst_signals(){	register int i;	for (i = 1; i < SIGKILL; i++)		signal(i, SIG_DFL);	for (i = SIGKILL + 1; i < SIGTERM; i++)		signal(i, SIG_DFL);	for (i = SIGTERM + 1; i < NSIG; i++)		signal(i, SIG_DFL);	errno = 0;	/* SIGWIND and SIGPHONE only on UNIX PC */}/* * sigterm:	Clean up and exit. */voidsigterm(){	signal(SIGTERM, SIG_IGN);	error(E_SIGTERM, EXIT | NORMAL | NOCORE);	/* calls cleanup */}/* * listen:	listen for and process connection requests. */static struct pollfd pollfds[2];static struct t_discon *disc;listen(){	register fd, i;	int count;	register struct pollfd *sp;	struct call_list *fhead, *phead; /* free and pending heads */	DEBUG((9,"in listen"));	if (Rxname) {		count = 2;	/* how many fd's are we listening on */		pollfds[0].fd = Nfd1;	/* tells poll() what to do		*/		pollfds[1].fd = Nfd2;		pollfds[0].events = pollfds[1].events = POLLIN;	}	else {		count = 1;		pollfds[0].fd = Nfd2;		pollfds[0].events = POLLIN;	}	errno = t_errno = 0;/* * for receiving disconnects allocate one and be done with it */	while (!(disc = (struct t_discon *)t_alloc(Nfd2,T_DIS,T_ALL)) ) {		if ((t_errno != TSYSERR) || (errno != EAGAIN))			tli_error(E_T_ALLOC, EXIT);		else			tli_error(E_T_ALLOC, CONTINUE);	}	for (;;) {		DEBUG((9,"listen(): TOP of loop"));		if (Rxname) {			pollfds[0].revents = pollfds[1].revents = 0;		}		else {			pollfds[0].revents = 0;		}		DEBUG((7,"waiting for a request (via poll)"));		if (poll(pollfds, count, -1) == -1) {			/* Assume due to a child server exiting, so just continue */			if (errno == EINTR)				continue;			else				sys_error(E_POLL, EXIT);		}		for (i = 0, sp = pollfds; i < count; i++, sp++) {			switch (sp->revents) {			case POLLIN:				fd = sp->fd;				if (fd == Nfd1) {					/* This can't happen if no remote login is					   available (Rxname == NULL, count == 1,					   Nfd1 == -1) */					fhead = &Rfree;					phead = &Rpend;				}				else {					fhead = &Lfree;					phead = &Lpend;				}				doevent(fhead, phead, fd);				trycon(fhead, phead, fd);				break;			case 0:				break;			/* distinguish the various errors for the user */			case POLLERR:				logmessage("poll() returned POLLERR");				error(E_SYS_ERROR, EXIT | NO_MSG);			case POLLHUP:				logmessage("poll() returned POLLHUP");				error(E_SYS_ERROR, EXIT | NO_MSG);			case POLLNVAL:				logmessage("poll() returned POLLNVAL");				error(E_SYS_ERROR, EXIT | NO_MSG);			case POLLPRI:				logmessage("poll() returned POLLPRI");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -