hlfw.ca

registry

ref: c8e22551dfa03a040dd6561eac5446e395658aee
dir: /reglookup.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ndb.h>
#include "dns.h"

static Ndb	*db;
static QLock	dblock;

int
openregistry(void)
{
	if(db != nil)
		return 0;

	db = ndbopen(dbfile);
	return db!=nil ? 0: -1;
}

static void
attach(Svc* svc, int persist)
{
	svc->perm = !!persist;

	if(registry != nil){
		svc->next = registry;
	}

	svc->next = registry;
	registry = svc;
}

static char*
detach(char *dial)
{
	Svc *c, *last = 0;
	char buf[Maxdial]; /* trns is capped at 16, port 8 */

	for(c = registry; c; c = c->next){
		snprint(buf, Maxdial, "%s!%s!%s", c->trns, c->host, c->port);
		if(strcmp(buf, dial)==0){
			if(last == 0)
				registry = c->next;
			else
				last->next = c->next;
			free(c);
			return 0;
		}
		last = c;
	}

	return "found no matching service";
}

static void
host2svc(Svc *svc, char *dial)
{
	int n;

	/* 
	 * entry host=tcp!mything!9fs
	 * for now, tokenize but we should allow short strings
         */
	n = strcspn(dial, "!");
	if(n < 1)
		strcpy(svc->trns, "tcp");
	else
		strecpy(svc->trns, svc->trns+n+1, dial);
	dial = dial + n + 1;

	n = strcspn(dial, "!");
	strecpy(svc->host, svc->host+n+1, dial);

	dial = dial + n + 1;
	if(sizeof(dial) < 1)
		strcpy(svc->port, "9fs");
	else if(sizeof(dial) > 8)
		/* If this starts happening, we should bump the number */
		strecpy(svc->port, svc->port + 8, dial);
	else
		strcpy(svc->port, dial);
}

static void
dbtuple2cache(Ndbtuple *t, int persist)
{
	Ndbtuple *et, *nt;
	Svc *svc;


	for(et = t; et; et = et->entry)
		if(strncmp(et->attr, "serv", 4)==0){
			svc = emalloc(sizeof(*svc));
			host2svc(svc, et->val);
			for(nt = et->entry; nt; nt = nt->entry)
				if(strcmp(nt->attr, "label")==0)
					strecpy(svc->labl, svc->labl+Maxmdns, nt->val);
				else if(strcmp(nt->attr, "auth")==0)
					strecpy(svc->auth, svc->auth+Maxauth, nt->val);
				else if(strcmp(nt->attr, "mtpt")==0)
					strecpy(svc->mtpt, svc->mtpt+Maxpath, nt->val);
			attach(svc, persist);
		};
}

static void
dbfile2cache(Ndb *db)
{
	Ndbtuple *t;

	if(debug)
		reglog("reading %s", db->file);
	Bseek(&db->b, 0, 0);
	while(t = ndbparse(db)){
		dbtuple2cache(t, 1);
		ndbfree(t);
	}


}

Svc*
rstr2svc(char *entry)
{
	Svc *svc;
	char *args[7];
	
	int i, n;

	n = tokenize(entry, args, 7);

	svc = emalloc(sizeof(*svc));
	host2svc(svc, estrdup(args[0]));

	for(i = 1; i < n - 1; i++)
		if(strcmp(args[i], "label")==0)	
			strecpy(svc->labl, svc->labl+Maxmdns, args[++i]);
		else if(strcmp(args[i], "auth")==0)
			strecpy(svc->auth, svc->auth+Maxauth, args[++i]);
		else if(strcmp(args[i], "mtpt")==0)
			strecpy(svc->mtpt, svc->mtpt+Maxpath, args[++i]);

	return svc;
}

char*
rstr2cache(char *entry, int persist)
{
	Svc *svc;

	svc = rstr2svc(entry);
	attach(svc, persist);
	return 0;
}

char*
rstrdtch(char *svc)
{
	return detach(svc);
}

/* e.g. update tcp!foo!9fs label newlabel */
char*
rstrupdt(char *entry)
{
	Svc *c, *svc = 0;
	char *args[7], buf[Maxdial];
	int i, n;

	n = tokenize(entry, args, 7);

	/* Find our service */
	for(c = registry; c; c = c->next){
		snprint(buf, Maxdial, "%s!%s!%s", c->trns, c->host, c->port);
		if(strcmp(buf, args[0])==0){
			svc = c;
			break;
		}
	}
	
	if(svc == 0)
		return "found no matching service";

	for(i = 1; i < n - 1; i++)
		if(strcmp(args[i], "label")==0)
			strecpy(svc->labl, svc->labl+Maxmdns, args[++i]);
		else if(strcmp(args[i], "auth")==0)
			strecpy(svc->auth, svc->auth+Maxauth, args[++i]);
		else if(strcmp(args[i], "mtpt")==0)
			strecpy(svc->mtpt, svc->mtpt+Maxpath, args[++i]);

	return 0;
}

void
regconnect(void)
{
	Ndb *adb;
	Ndbtuple *t;
	char *host, *list[1];
	int rfdn, fd;

	rfdn = 0;
	adb = ndbopen(0);

	/* Start with us */
	host = getenv("sysname");
	list[0] = "registry";
	t = ndbipinfo(adb, "sys", host, list, 1);
	if(t->val != nil){
		fd = dial(t->val, 0, 0, 0);
		if(fd >= 0)
			rfd[rfdn++] = fd;
	}
	ndbfree(t);

	/* Here we want to find our other registry= tuples in the ndb
         * I don't claim to know the best way to do this. registry= entries 
	 * in an ipnet= is the solution i see best fitting, but for now 
         * this will be marked as TODO and left alone 
	 * the goal will be, however, to iterate through upstream resolvers
         * which act as lists for services one may add, like the 9ants grid
         * registry, as a good example; and when a local resolve misses, it
         * bubbles up to the next resolver, etc, until we exhaust the list 
         * or find a match
         */

	if(rfdn < 1)
		sysfatal("unable to dial any registry server");
	rfd[rfdn] = 0;
}

void
reg2cache(void)
{
	Ndb *ndb;
	
	qlock(&dblock);
	if(openregistry() < 0){
		qunlock(&dblock);
		return;
	}
	
	if(debug)
		syslog(0, logfile, "building cache from db");
			
	for(ndb = db; ndb; ndb = ndb->next)
		dbfile2cache(ndb);

	qunlock(&dblock);
}