V10/cmd/limiter.c

Compare this file to the similar file:
Show the results in this format:

#include <sys/types.h>
#include <sys/filio.h>
#include <stdio.h>
#include <sys/stream.h>

extern int conn_ld;
extern int mesg_ld;
#define	msglen(mp)	((mp)->losize + ((mp)->hisize<<8))

int count;		/* max connections */
fd_set serving;		/* clients being served */
int nserving;
fd_set waiting;		/* clients waiting */
int nwaiting;
int fd;			/* mounted fd */


main(ac, av)
	int ac;
	char *av[];
{
	if(ac!=3)
		die("usage: %s path count\n", av[0]);
	fd=mountit(av[1]);
	count=atoi(av[2]);
	if(count<=0)
		die("usage: %s path count\n", av[0]);
	detach();
	doit();
}

doit()
{
	int i, n;
	fd_set afds;

	FD_ZERO(serving);
	for(;;){
		afds=serving;
		FD_SET(fd, afds);
		switch(n=select(NOFILE, &afds, 0, 10000L)){
		case -1:
			/* there's a bad fd in the group */
			afds=serving;
			for(i=0; i<NOFILE; i++)
				if(FD_ISSET(i, afds))
					dropclient(i);
			break;
		case 0:
			/* timeout, try again */
			break;
		default:
			/* look for new clients */
			if(FD_ISSET(fd, afds)){
				request();
				n--;
			}

			/* someone needs servicing */
			for(i=0; n && i<NOFILE; i++){
				if(FD_ISSET(i, afds)){
					dropclient(i);
					n--;
				}
			}
			break;
		}
	}
}

newclient(cfd)
	int cfd;
{
	FD_SET(cfd, waiting);
	nwaiting++;
	wtos();
}

dropclient(cfd)
	int cfd;
{
	FD_CLR(cfd, serving);
	nserving--;
	close(cfd);
	wtos();
}

wtos()
{
	int i=0;
	struct mesg m;

	while(nwaiting && nserving<count){
		for(;i<NOFILE;i++){
			if(FD_ISSET(i,waiting)){
				nwaiting--;
				nserving++;
				FD_SET(i, serving);
				FD_CLR(i, waiting);
				m.losize = 0;
				m.hisize = 0 >> 8;
				m.type = M_HANGUP;
				m.magic = MSGMAGIC;
				if(ioctl(i, FIOACCEPT, (void *)0)<0
				|| ioctl(i, FIOPUSHLD, &mesg_ld)<0
				|| write(i, &m, sizeof(m))!=sizeof(m)){
					close(i);
					FD_CLR(i, serving);
					nserving--;
					continue;
				}
			}
		}
	}
}

request()
{
	struct passfd pass;

	if(ioctl(fd, FIORCVFD, &pass)<0)
		abort();
	newclient(pass.fd);
}

mountit(path)
	char *path;
{
	int pfd[2];

	/* make a node to mount onto */
	if (access(path,0)<0 && creat(path, 0666)<0)
		die("can't creat %s\n", path);

	/* get the stream to mount */
	if (pipe(pfd) < 0)
		die("out of pipes\n", 0);
	if (ioctl(pfd[1], FIOPUSHLD, &conn_ld) < 0)
		die("can't push line discipline\n", 0);

	/* mount */
	if (fmount(3, pfd[1], path, 0) < 0)
		die("can't mount onto %s\n", path);
	umask(0);
	chmod(path, 0666);
	close(pfd[1]);
	return pfd[0];
}

detach()
{
	switch(fork()){
	case -1:
		die("can't fork\n", 0);
	case 0:
		break;
	default:
		exit(0);
	}
	for(fd=0; fd<NSYSFILE; fd++)
		close(fd);
	setpgrp(getpid(), getpid());
}

die(a, b)
	char *a;
{
	fprintf(stderr, a, b);
	exit(1);
}