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

📄 sockd_child.c

📁 sock protocol ,it is useful!
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1997, 1998, 1999 *      Inferno Nettverk A/S, Norway.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. The above copyright notice, this list of conditions and the following *    disclaimer must appear in all copies of the software, derivative works *    or modified versions, and any portions thereof, aswell as in all *    supporting documentation. * 2. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *      This product includes software developed by *      Inferno Nettverk A/S, Norway. * 3. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Inferno Nettverk A/S requests users of this software to return to * *  Software Distribution Coordinator  or  sdc@inet.no *  Inferno Nettverk A/S *  Oslo Research Park *  Gaustadal閑n 21 *  N-0349 Oslo *  Norway * * any improvements or extensions that they make and grant Inferno Nettverk A/S * the rights to redistribute these changes. * */#include "common.h"static const char rcsid[] ="$Id: sockd_child.c,v 1.118 2000/01/05 10:38:58 michaels Exp $";#define MOTHER	0	/* descriptor mother reads/writes on.	*/#define CHILD	1	/* descriptor child reads/writes on.	*/__BEGIN_DECLSstatic intsetchildtype __P((int type, struct sockd_child_t ***childv, int **childc,						void (**function)(struct sockd_mother_t *mother)));/* * Sets "childv", "childc" and "function" to the correct value depending * on "type". */static intfindchild __P((pid_t pid, int childc, const struct sockd_child_t *childv));/* * Finds the child with pid "pid" in the array "childv".  Searching * Elements in "childv" is given by "childc". * Returns: *		On success: the index of the child in "childv". *		On failure: -1. */__END_DECLSstatic struct sockd_child_t *iochildv;				/* all our iochildren			*/static int iochildc;static struct sockd_child_t *negchildv;			/* all our negotiatorchildren */static int negchildc;static struct sockd_child_t *reqchildv;			/* all our requestchildren		*/static int reqchildc;struct sockd_child_t *addchild(type)	int type;{	const char *function = "addchild()";	/*    * It is better to reserve some descriptors for temporary use    * than to get errors when passing them and thus lose clients.    */	const int reserved = FDPASS_MAX	/* max descriptors we pass.			*/							 + 1				/* need a descriptor for accept().	*/							 + 2;				/* for each new child.					*/	struct sockd_mother_t mother;	struct sockd_child_t **childv;	int *childc;	void (*childfunction)(struct sockd_mother_t *mother);	pid_t pid;	int optval, flags;	int pipev[] = { -1, -1 };	int ackpipev[] = { -1, -1 };	/*	 * XXX This is a expensive test which shouldn't be hard to optimize	 * away.  It only happens when we are running low on slots though,	 * so assume it's "good enough" until I get the time to fix it.	 */	if (freedescriptors(NULL) < reserved) {		errno = EMFILE;		swarn(function);		return NULL;	}	/* create datapipe. */	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipev) != 0) {		swarn("%s: socketpair(AF_LOCAL, SOCK_STREAM)", function);		return NULL;	}	/* and ackpipe. */	if (pipe(ackpipev) != 0) {		swarn("%s: pipe()", function);		closev(pipev, ELEMENTS(pipev));		return NULL;	}	/*	 * Try to set socketbuffer and watermarks to a optimal size.	 */	switch (type = setchildtype(type, &childv, &childc, &childfunction)) {		case CHILD_NEGOTIATE:			/*			 * A negotiator child receives only descriptors, so mothers			 * send buffer can be small, and so can the child's receive buffer.			 * The child sends a sockd_request_t struct back to mother, so			 * mothers recv buffer has to be considerably bigger, as does			 * childs send buffer.			 */			/* negotiator shouldn't block on sending to mother. */			if ((flags = fcntl(pipev[CHILD], F_GETFL, 0)) == -1			||  fcntl(pipev[CHILD], F_SETFL, flags | O_NONBLOCK) == -1)				swarn("%s: fcntl()", function);#if HAVE_SENDMSG_DEADLOCK			if ((mother.lock = socks_mklock(SOCKS_LOCKFILE)) == -1) {				swarn("%s: socks_mklock()", function);				closev(pipev, ELEMENTS(pipev));				closev(ackpipev, ELEMENTS(ackpipev));				return NULL;			}#endif /* HAVE_SENDMSG_DEADLOCK */			optval = sizeof(struct sockd_request_t) * (SOCKD_NEGOTIATEMAX + 1);			if (setsockopt(pipev[MOTHER], SOL_SOCKET, SO_RCVBUF, &optval,			sizeof(optval)) != 0			||  setsockopt(pipev[CHILD], SOL_SOCKET, SO_SNDBUF, &optval,			sizeof(optval)) != 0)				swarn("%s: setsockopt(SO_RCVBUF/SO_SNDBUF)", function);#if HAVE_SO_SNDLOWAT			optval = sizeof(struct sockd_request_t) * LOWATSKEW;			if (setsockopt(pipev[CHILD], SOL_SOCKET, SO_SNDLOWAT, &optval,			sizeof(optval)) != 0			|| setsockopt(pipev[MOTHER], SOL_SOCKET, SO_RCVLOWAT, &optval,			sizeof(optval)) != 0)				swarn("%s: setsockopt(SO_SNDLOWAT/SO_RCVLOWAT)", function);#endif			break;		case CHILD_REQUEST:			/*			 * A request child receives a sockd_request_t structure,			 * it sends back a sockd_io_t structure.			 */#if HAVE_SENDMSG_DEADLOCK			mother.lock = -1;	/* doesn't need lock. */#endif /* HAVE_SENDMSG_DEADLOCK */			optval = sizeof(struct sockd_request_t) * (SOCKD_REQUESTMAX + 1);			if (setsockopt(pipev[MOTHER], SOL_SOCKET, SO_SNDBUF, &optval,			sizeof(optval)) != 0			||  setsockopt(pipev[CHILD], SOL_SOCKET, SO_RCVBUF, &optval,			sizeof(optval)) != 0)				swarn("%s: setsockopt()", function);			optval = sizeof(struct sockd_io_t) * (SOCKD_REQUESTMAX + 1);			if (setsockopt(pipev[MOTHER], SOL_SOCKET, SO_RCVBUF, &optval,			sizeof(optval)) != 0			||  setsockopt(pipev[CHILD], SOL_SOCKET, SO_SNDBUF, &optval,			sizeof(optval)) != 0)				swarn("%s: setsockopt()", function);#if HAVE_SO_SNDLOWAT			optval = sizeof(struct sockd_request_t) * LOWATSKEW;			if (setsockopt(pipev[CHILD], SOL_SOCKET, SO_RCVLOWAT, &optval,			sizeof(optval)) != 0			|| setsockopt(pipev[MOTHER], SOL_SOCKET, SO_SNDLOWAT, &optval,			sizeof(optval)) != 0)				swarn("%s: setsockopt(SO_RCVLOWAT)", function);			optval = sizeof(struct sockd_io_t) * LOWATSKEW;			if (setsockopt(pipev[CHILD], SOL_SOCKET, SO_SNDLOWAT, &optval,			sizeof(optval)) != 0			|| setsockopt(pipev[MOTHER], SOL_SOCKET, SO_RCVLOWAT, &optval,			sizeof(optval)) != 0)				swarn("%s: setsockopt(SO_RCVLOWAT/SO_SNDLOWAT)", function);#endif			break;		case CHILD_IO:			/*			 * A io child receives a sockd_io_t structure,			 * it sends back only a ack.			 */#if HAVE_SENDMSG_DEADLOCK			mother.lock = -1;	/* doesn't need lock. */#endif /* HAVE_SENDMSG_DEADLOCK */			optval = sizeof(struct sockd_io_t) * (SOCKD_IOMAX + 1);			if (setsockopt(pipev[MOTHER], SOL_SOCKET, SO_SNDBUF, &optval,			sizeof(optval)) != 0			||  setsockopt(pipev[CHILD], SOL_SOCKET, SO_RCVBUF, &optval,			sizeof(optval)) != 0)				swarn("%s: setsockopt(SO_SNDBUF/SO_RCVBUF)", function);			optval = sizeof(int) * (SOCKD_IOMAX + 1);			if (setsockopt(pipev[MOTHER], SOL_SOCKET, SO_RCVBUF, &optval,			sizeof(optval)) != 0			||  setsockopt(pipev[CHILD], SOL_SOCKET, SO_SNDBUF, &optval,			sizeof(optval)) != 0)				swarn("%s: setsockopt(SO_RCVBUF/SO_SNDBUF)", function);#if HAVE_SO_SNDLOWAT			optval = sizeof(struct sockd_io_t) * LOWATSKEW;			if (setsockopt(pipev[CHILD], SOL_SOCKET, SO_RCVLOWAT, &optval,			sizeof(optval)) != 0			|| setsockopt(pipev[MOTHER], SOL_SOCKET, SO_SNDLOWAT, &optval,			sizeof(optval)) != 0)				swarn("%s: setsockopt(SO_RCVLOWAT)", function);#endif			break;		default:			SERRX(type);	}	switch ((pid = fork())) {		case -1:			swarn("%s: fork()", function);			closev(pipev, ELEMENTS(pipev));			closev(ackpipev, ELEMENTS(ackpipev));#if HAVE_SENDMSG_DEADLOCK			if (mother.lock != -1)				close(mother.lock);#endif /* HAVE_SENDMSG_DEADLOCK */			return NULL;		case 0: {			size_t i, maxfd;			struct sigaction sigact;			config.state.type	= type;			config.state.pid	= getpid();			initlog();			slog(LOG_DEBUG, "created new %schild", childtype2string(type));#if 0			slog(LOG_DEBUG, "sleeping...");			sleep(20);#endif			mother.s		= pipev[CHILD];			mother.ack	= ackpipev[CHILD];			/*			 * It would be nice to be able to lose all privileges here			 * but unfortunately we can't, yet.			 *			 * negotiation children:			 *		could need privileges to check password.			 *			 * request children:			 *		could need privileges to bind port.			 *			 * io children:			 *		doesn't really need any, but a sighup() performs misc.			 *		seteuid() tests that would fail if we lose privileges.			 */			switch (type) {				case CHILD_NEGOTIATE:#if HAVE_LIBWRAP#if SOCKD_NEGOTIATEMAX > 1					resident = 1;#endif /* SOCKD_NEGOTIATEMAX > 1 */#endif  /* HAVE_LIBWRAP */					break;				case CHILD_REQUEST:#if HAVE_LIBWRAP#if SOCKD_REQUESTMAX > 1					resident = 1;#endif /* SOCKD_REQUESTMAX > 1 */#endif  /* HAVE_LIBWRAP */					break;				case CHILD_IO:#if HAVE_LIBWRAP#if SOCKD_IOMAX > 1					resident = 1;#endif /* SOCKD_IOMAX > 1 */#endif  /* HAVE_LIBWRAP */					break;				default:					SERRX(type);			}			sigemptyset(&sigact.sa_mask);			sigact.sa_flags	= 0;			/* signals mother has set up but which we ignore at this point. */			sigact.sa_handler = SIG_IGN;#if HAVE_SIGNAL_SIGINFO			if (sigaction(SIGINFO, &sigact, NULL) != 0)				swarn("%s: sigaction(SIGINFO)", function);#endif  /* HAVE_SIGNAL_SIGINFO */			if (sigaction(SIGUSR1, &sigact, NULL) != 0)				swarn("%s: sigaction(USR1)", function);			/* delete everything we got from parent. */			for (i = 0, maxfd = getdtablesize(); i < maxfd; ++i) {				/* exceptions */				if (i == (size_t)mother.s#if HAVE_SENDMSG_DEADLOCK				||	i == (size_t)mother.lock#endif /* HAVE_SENDMSG_DEADLOCK */				||	i == (size_t)mother.ack)					continue;				if (socks_logmatch(i, &config.log))					continue;				close((int)i);			}			initlog(); /* for syslog. */			childfunction(&mother);			/* NOTREACHED */		}		default: {			struct sockd_child_t *newchildv;			if ((newchildv = (struct sockd_child_t *)realloc(*childv,			sizeof(**childv) * (*childc + 1))) == NULL) {				slog(LOG_WARNING, "%s: %s", function, NOMEM);				closev(pipev, ELEMENTS(pipev));				closev(ackpipev, ELEMENTS(ackpipev));				return NULL;			}			*childv = newchildv;			(*childv)[*childc].type	= type;			(*childv)[*childc].pid	= pid;			(*childv)[*childc].s		= pipev[MOTHER];#if HAVE_SENDMSG_DEADLOCK			(*childv)[*childc].lock	= mother.lock;#endif /* HAVE_SENDMSG_DEADLOCK */			(*childv)[*childc].ack	= ackpipev[MOTHER];			close(pipev[CHILD]);			close(ackpipev[CHILD]);			switch ((*childv)[*childc].type) {				case CHILD_NEGOTIATE:					(*childv)[*childc].freec = SOCKD_NEGOTIATEMAX;					break;				case CHILD_REQUEST:					(*childv)[*childc].freec = SOCKD_REQUESTMAX;					break;				case CHILD_IO:					(*childv)[*childc].freec = SOCKD_IOMAX;					break;				default:					SERRX((*childv)[*childc].type);			}			return &(*childv)[(*childc)++];		}	}}intchildcheck(type)	int type;{	int child, proxyc;	int min, max;	struct sockd_child_t **childv;	int *childc;	switch (type) {		case -CHILD_NEGOTIATE:		case CHILD_NEGOTIATE:			childc	= &negchildc;			childv	= &negchildv;			min		= SOCKD_FREESLOTS;			max		= SOCKD_NEGOTIATEMAX;			break;		case -CHILD_REQUEST:		case CHILD_REQUEST:			childc	= &reqchildc;			childv	= &reqchildv;			min		= SOCKD_FREESLOTS;			max		= SOCKD_REQUESTMAX;			break;		case -CHILD_IO:		case CHILD_IO:			childc	= &iochildc;			childv	= &iochildv;			/* attempt to keep in a state where we can accept all requests. */			min		= MAX(SOCKD_FREESLOTS, childcheck(-CHILD_REQUEST));			max		= SOCKD_IOMAX;			break;		default:			SERRX(type);	}	/*	 * get a estimate over how many (new) clients our children are able to	 * accept in total.    */	for (child = 0, proxyc = 0; child < *childc; ++child) {		SASSERTX((*childv)[child].freec <= max);		proxyc += type < 0 ? max : (*childv)[child].freec;	}	if (type >= 0)		if (proxyc < min && config.state.addchild)			if (addchild(type) != NULL)				return childcheck(type);			else				config.state.addchild = 0;	/* don't retry until a child dies. */	return proxyc;}intfillset(set)	fd_set *set;{	int negc, reqc, ioc;	int i, dbits;	/*	 * There is no point in setting data descriptor of child N unless	 * child N+1 is able to accept the data from child N.  So find	 * out if we have slots of the various types available .	 */	ioc	= childcheck(CHILD_IO);	reqc	= childcheck(CHILD_REQUEST);	negc	= childcheck(CHILD_NEGOTIATE);	FD_ZERO(set);	dbits = -1;	/* new clients we accept. */	if (negc > 0)		for (i = 0; i < config.internalc; ++i) {			SASSERTX(config.internalv[i].s >= 0);			FD_SET(config.internalv[i].s, set);			dbits = MAX(dbits, config.internalv[i].s);		}	/* negotiator children. */	for (i = 0; i < negchildc; ++i) {		if (reqc > 0) {			SASSERTX(negchildv[i].s >= 0);			FD_SET(negchildv[i].s, set);			dbits = MAX(dbits, negchildv[i].s);		}		/* we can always accept a ack ofcourse. */		SASSERTX(negchildv[i].ack >= 0);		FD_SET(negchildv[i].ack, set);		dbits = MAX(dbits, negchildv[i].ack);	}	/* request children. */	for (i = 0; i < reqchildc; ++i) {		if (ioc > 0) {			SASSERTX(reqchildv[i].s >= 0);			FD_SET(reqchildv[i].s, set);			dbits = MAX(dbits, reqchildv[i].s);		}		/* we can always accept a ack ofcourse. */		SASSERTX(reqchildv[i].ack >= 0);		FD_SET(reqchildv[i].ack, set);		dbits = MAX(dbits, reqchildv[i].ack);

⌨️ 快捷键说明

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