Plan 9 from Bell Labs’s /usr/web/sources/contrib/nemo/sys/src/cmd/adsrv.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <thread.h>
#include <bio.h>
#include <b.h>
enum {
	Nclients = 256,
};

typedef struct Cli Cli;

struct Cli {
	ulong	epoch;
	int	fd;
	char*	ad;
	char*	addr;
	int	adfd;
};

int	reportall = 1;
ulong	epoch;
char*	adsdir	= "/lib/ndb/vol";
char*	cvols;
QLock	clilk;
Cli*	cli[Nclients];

#define dprint if(debug)fprint
#define Dprint if(debug>1)fprint

int	debug;

Cli*
newclient(int fd)
{
	int	i;

	qlock(&clilk);
	for (i = 0; i < nelem(cli); i++)
		if (cli[i] == nil)
			break;
	if (i == nelem(cli)){
		qunlock(&clilk);
		fprint(2, "adsrv: fixme: cli table exhausted\n");
		return nil;
	}
	cli[i] = malloc(sizeof(Cli));
	assert(cli[i]);
	cli[i]->addr = nil;
	cli[i]->epoch = 0;
	cli[i]->fd = fd;
	cli[i]->adfd= -1;
	cli[i]->ad = nil;
	qunlock(&clilk);
	return cli[i];
}

void
delclient(Cli* c)
{
	int	i;

	close(c->fd);
	close(c->adfd);	// ORCLOSE
	qlock(&clilk);
	for (i = 0; i < nelem(cli); i++)
		if (cli[i] == c){
			if (cli[i]->ad != nil)
				dprint(2, "gone: %s\n", cli[i]->ad);
			free(cli[i]->ad);
			free(cli[i]);
			free(cli[i]->addr);
			cli[i] = nil;
			break;
		}
	qunlock(&clilk);
}

void
writeannounces(int fd, Cli* c)
{
	int	i;

	qlock(&clilk);
	for (i = 0; i < nelem(cli); i++){
		if (cli[i] != nil && cli[i]->ad != nil)
			if (reportall || cli[i]->epoch > c->epoch)
				fprint(fd, "%s\n", cli[i]->ad);
	}
	if (cvols != nil)
		fprint(fd, "%s", cvols);
	c->epoch = epoch;
	write(fd, "\n", 1);
	qunlock(&clilk);
}

char*
readannounce(Biobuf* bin, Cli* c)
{
	char*	a;
	long	l;
	char*	p;
	char*	s;
	char*	fname;
	char*	path;

	if (c->ad != nil && c->adfd != -1)
		return nil;
	fname = nil;
	a = Brdline(bin, '\n');
	l = Blinelen(bin);
	if (l < 1)
		return nil;
	a[--l] = 0;
	if (l > 0 && a[l-1] == '\r')
		a[--l] = 0;
	if (strncmp(a, "tcp!", 4))
		goto fail;
	s = strchr(a, '\t');
	if (s == nil)
		goto fail;
	*s++ = 0;
	fname = strdup(a);
	p = strchr(fname, '!');
	if (p == nil)
		goto fail;
	p++;
	p = strchr(p, '!');
	if (p == nil)
		goto fail;
	p++;
	path = smprint("%s/%s", adsdir, fname);
	qlock(&clilk);
	c->epoch = ++epoch;
	free(c->ad);
	c->ad = smprint("tcp!%s!%s\t%s", c->addr, p, s);
	if (c->adfd != -1)
		close(c->adfd);
	c->adfd = create(path, OWRITE|ORCLOSE, 0666);
	if (c->adfd == -1 || fprint(c->adfd, "%s\n", c->ad) < 0){
		fprint(2, "%s: %s: %r\n", argv0, s);
		free(c->ad);
		c->ad = nil;
		close(c->adfd);
		c->adfd = -1;
	}
	// leave it open.
	qunlock(&clilk);
	free(path);
	free(fname);
	return c->ad;
fail:
	fprint(2, "bad announce: %s\n", a);
	free(fname);
	return nil;
}

void
clientproc(void* a)
{
	Cli*	c = a;
	Biobuf	bin;
	char*	ln;
	long	l;

	Binit(&bin, c->fd, OREAD);
	while(ln = Brdline(&bin, '\n')){
		l = Blinelen(&bin);
		if (l < 2)
			continue;
		ln[--l] = 0;
		if (ln[l-1] == '\r')
			ln[--l] = 0;
		if (!strcmp(ln, "PlanB announces")){
			Dprint(2, "write announces to %d\n", c->fd);
			writeannounces(c->fd, c);
		} else if (!strcmp(ln, "PlanB announce:")){
			if (readannounce(&bin, c))
				dprint(2, "announce from %d: %s\n", c->fd, c->ad);
		} else
			Dprint(2, "unknown messsage: %s\n", ln);
	}
	Dprint(2, "gone client %d: %r\n", c->fd);
	Bterm(&bin);
	delclient(c);
	threadexits(nil);
}

static char*
getremotesys(char *ndir)
{
	char buf[128], *serv, *sys;
	int fd, n;

	snprint(buf, sizeof buf, "%s/remote", ndir);
	sys = nil;
	fd = open(buf, OREAD);
	if(fd >= 0){
		n = read(fd, buf, sizeof(buf)-1);
		if(n>0){
			buf[n-1] = 0;
			serv = strchr(buf, '!');
			if(serv)
				*serv = 0;
			sys = strdup(buf);
		}
		close(fd);
	}
	if(sys == nil)
		sys = strdup("unknown");
	return sys;
}

void
server(char* addr)
{
	char	adir[40], ldir[40];
	int	cfd, fd;
	Cli*	c;

	cfd = announce(addr, adir);
	if (cfd < 0)
		sysfatal("%s: announce: %r", argv0);
	for (;;){
		cfd = listen(adir, ldir);
		if (cfd < 0)
			sysfatal("%s: listen: %r", argv0);
		fd = accept(cfd, ldir);
		if(fd < 0){
			fprint(2, "%s: accept: %r\n", argv0);
			continue; 
		}
		fprint(cfd, "keepalive 2000\n");
		close(cfd);
		c = newclient(fd);
		c->addr = getremotesys(ldir);
		Dprint(2, "new client %d %s\n", fd, c->addr);
		proccreate(clientproc, c, 16*1024);
	}
	sysfatal("server died");
}

void
usage(void)
{
	fprint(2, "usage: %s [-d] [-n addr] [-c volcfg] [dir]\n", argv0);
	sysfatal("usage");
}

void
threadmain(int argc, char *argv[])
{
	char*	addr;
	char*	cfg;

	addr= "tcp!*!11010";
	cfg = "/lib/ndb/vol/vols";
	ARGBEGIN{
	case 'c':
		cfg = EARGF(usage());
		break;
	case 'n':
		addr = EARGF(usage());
		break;
	case 'd':
		debug++;
		break;
	default:
		usage();
	}ARGEND;
	switch(argc){
	case 0:
		break;
	case 1:
		adsdir = argv[0];
		break;
	default:
		usage();
	}
	if (cfg != nil && access(cfg, AREAD) == 0)
		cvols = readfstr(cfg);
	dprint(2, "%s %s %s\n", argv0, adsdir, addr);
	server(addr);
	threadexits(nil);
}


Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.