9front - general discussion about 9front
 help / color / mirror / Atom feed
* ndb/registry
@ 2020-08-29  4:17 Michael Misch
  2020-09-01  4:57 ` [9front] ndb/registry ori
  0 siblings, 1 reply; 2+ messages in thread
From: Michael Misch @ 2020-08-29  4:17 UTC (permalink / raw)
  To: 9front

[-- Attachment #1: Type: text/plain, Size: 1650 bytes --]

Hey, I’ve been working this last week on bringing ndb/registry over from inferno, but in a way that matches well with the rest of our ndb. 
I have two binaries, ndb/registry and ndb/regquery. ndb/registry reads from /lib/ndb/registry, which would contain a list of local services you want to register on start up. They’re in regular ndb format, and look like

service=tcp!myipaddr!1234
	auth=none label=myservice
	mtpt=/n/myservice

You can add a service by writing, `add tcp!myipaddr!1234 label myservice [mtpt mymtpt label mylabel]` to /net/registry, rm `rm tcp!myipaddr!1234`, edit, `update tcp!myipaddr!1234 label newlabel` or any other tuple. Dump will create a dump of the current registry to /lib/ndb/regdump, refresh will reload the services from the db - while keeping any that you’ve added after startup untouched. 

regquery opens and reads /net/registry, and outputs any matching service descriptions `ndb/regquery myservice`, in tuple format; or as a plumbable string (currently only srv and srvtls) with -s, and will list all services when passed `ndb/regquery all`.

eg:

ndb/regquery grid
service=tcp!myservice!1234 label=gridchat auth=none mtpt=/n/chat
[ … ] // any other matches

ndb/regquery -s grid 
srv tcp!myservice!1234 gridchat /n/chat
[ … ] // any other matches

I use this with a database containing, at the moment the 9grid list of services, but would be useful for a general index of what services exist on a given network outright, on a remote network for bookkeeping, etc.

The code is fresh, and may have bugs I haven’t caught! I’ll include the diff here, thanks!

 - halfwit 


[-- Attachment #2: ndb.patch --]
[-- Type: application/octet-stream, Size: 24478 bytes --]

diff -r 8127893f53b1 sys/src/cmd/ndb/dns.h
--- a/sys/src/cmd/ndb/dns.h	Wed Aug 26 21:17:17 2020 -0700
+++ b/sys/src/cmd/ndb/dns.h	Fri Aug 28 20:55:56 2020 -0700
@@ -143,6 +143,9 @@
 
 	Maxpath=	128,	/* size of mntpt */
 	Maxlcks=	10,	/* max. query-type locks per domain name */
+	Maxauth=	16,	/* proto for auth */
+	Maxmdns=	255,	/* Limits for mDNS messages */
+	Maxdial= 	271,	/* port + trns + !! + host */
 
 	RRmagic=	0xdeadbabe,
 	DNmagic=	0xa110a110,
@@ -168,6 +171,7 @@
 typedef struct Request	Request;
 typedef struct SOA	SOA;
 typedef struct Server	Server;
+typedef struct Service	Service;
 typedef struct Sig	Sig;
 typedef struct Srv	Srv;
 typedef struct Txt	Txt;
@@ -247,6 +251,21 @@
 };
 
 /*
+ * registry service
+ */
+struct Service
+{
+	Service *next;
+	char	labl[Maxmdns]; /* Use mDNS limits */
+	char	host[Maxmdns];
+	char	mtpt[Maxpath];
+	char	auth[Maxauth];
+	char	trns[16]; /* transport tcp/ssh/gopher/carrierpidgeon */
+	char	port[8]; /* 9fs, numerical, etc - switch to #? */
+	uchar	perm; /* flag: from db */
+};
+
+/*
  *  an unpacked resource record
  */
 struct RR
@@ -426,10 +445,13 @@
 extern char	*trace;
 extern int	traceactivity;
 extern char	*zonerefreshprogram;
+extern Service  *registry;
 
 #pragma	varargck	type	"R"	RR*
 #pragma	varargck	type	"Q"	RR*
-
+#pragma varargck 	type 	"G" 	Service*
+#pragma varargck	type	"D"	Service*
+#pragma varargck	type	"N"	Service*
 
 /* dn.c */
 extern char	*rrtname[];
@@ -463,7 +485,12 @@
 int	getactivity(Request*, int);
 Area*	inmyarea(char*);
 void	putactivity(int);
+void	reg2cache(void);
+char*	rstr2cache(char*, int);
+char*	rstrdtch(char*);
+char*	rstrupdt(char*);
 RR*	randomize(RR*);
+void	reglog(char*, ...);
 RR*	rralloc(int);
 void	rrattach(RR*, int);
 int	rravfmt(Fmt*);
@@ -523,6 +550,9 @@
 void	dnnotify(DNSmsg*, DNSmsg*, Request*);
 void	notifyproc(void);
 
+/* reglookup.c */
+int	openregistry(void);	
+
 /* convDNS2M.c */
 int	convDNS2M(DNSmsg*, uchar*, int);
 
diff -r 8127893f53b1 sys/src/cmd/ndb/mkfile
--- a/sys/src/cmd/ndb/mkfile	Wed Aug 26 21:17:17 2020 -0700
+++ b/sys/src/cmd/ndb/mkfile	Fri Aug 28 20:55:56 2020 -0700
@@ -13,6 +13,8 @@
 	dnstcp\
 	dnsdebug\
 	dnsgetip\
+	registry\
+	regquery\
 	ipquery\
 	inform\
 
@@ -49,6 +51,9 @@
 $O.cs: cs.$O
 	$LD -o $target $prereq
 
+$O.registry: registry.$O reglookup.$O
+	$LD -o $target $prereq
+
 $O.testipinfo: testipinfo.$O ipinfo.$O
 	$LD -o $target $prereq
 
diff -r 8127893f53b1 sys/src/cmd/ndb/registry.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/cmd/ndb/registry.c	Fri Aug 28 20:55:56 2020 -0700
@@ -0,0 +1,896 @@
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+#include <fcall.h>
+#include <bio.h>
+#include <ip.h>
+#include "dns.h"
+
+enum
+{
+	Maxrequest=		1024,
+	Maxreply=		8192,
+	Maxrecords=		192,
+	Maxfdata=		8192,
+
+	Qdir=			0,
+	Qreg=			1,
+};
+
+typedef struct Mfile	Mfile;
+typedef struct Job	Job;
+typedef struct Records  Records;
+
+struct Mfile
+{
+	Mfile	*next;
+
+	char	*user;
+	Qid	qid;
+	int	fid;
+
+	char	reply[Maxreply];
+	ushort	rr[Maxrecords]; /* offset of record */
+	ushort	nrr;		/* number of records */	
+};
+
+/*
+ *  active requests
+ */
+struct Job
+{
+	Job	*next;
+	int	flushed;
+	Fcall	request;
+	Fcall	reply;
+};
+Lock	joblock;
+Job	*joblist;
+
+struct {
+	Lock;
+	Mfile	*inuse;		/* active mfile's */
+} mfalloc;
+
+Service *registry;
+int	vers;
+int	debug;
+char	*dbfile = "/lib/ndb/registry";
+char	*reguser;
+char	mntpt[Maxpath];
+int	mfd[2];
+char	*logfile = "registry";
+
+void	rversion(Job*);
+void	rflush(Job*);
+void	rattach(Job*, Mfile*);
+char*	rwalk(Job*, Mfile*);
+void	ropen(Job*, Mfile*);
+void	rcreate(Job*, Mfile*);
+void	rread(Job*, Mfile*);
+void	rwrite(Job*, Mfile*);
+void	rclunk(Job*, Mfile*);
+void	rremove(Job*, Mfile*);
+void	rstat(Job*, Mfile*);
+void	rwstat(Job*, Mfile*);
+void	rauth(Job*);
+void	mountinit(char*, char*);
+void	setext(char*, int, char*);
+void	io(void);
+
+char*	addsrv(char*);
+char*	rmsrv(char*);
+char*	updatesrv(char*);
+void	refresh(void);
+void	regdump(char*);
+void	sendmsg(Job*, char*);
+
+int	scanfmt(Fmt*);
+int	srvfmt(Fmt*);
+int	dumpfmt(Fmt*);
+
+static char* query(Job*, Mfile*, char*, int);
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s [-xr] [-f ndb-file]\n", argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char* argv[])
+{
+	char servefile[Maxpath], ext[Maxpath];
+	Dir *dir;
+	
+	setnetmtpt(mntpt, sizeof mntpt, nil);
+	ext[0] = 0;
+
+	ARGBEGIN{
+	case 'd':
+		debug = 1;
+		break;
+	case 'f':
+		dbfile = EARGF(usage());
+		break;
+	case 'x':
+		setnetmtpt(mntpt, sizeof mntpt, EARGF(usage()));
+		setext(ext, sizeof ext, mntpt);
+		break;
+	} ARGEND;
+	if(argc != 0)
+		usage();
+    
+	rfork(RFREND|RFNOTEG);
+
+	fmtinstall('F', fcallfmt);
+	fmtinstall('G', srvfmt);
+	fmtinstall('N', scanfmt);
+	fmtinstall('D', dumpfmt);
+
+	reglog("starting registry on %s", mntpt);
+
+	if(openregistry())
+		sysfatal("unable to open db file");
+
+	reguser = estrdup(getuser());
+	snprint(servefile, sizeof servefile, "#s/registry%s", ext);
+	
+	dir = dirstat(servefile);
+	if (dir)
+		sysfatal("%s exists; another registry instance is running", servefile);
+	free(dir);
+
+	mountinit(servefile, mntpt);
+	reg2cache();
+	io();
+
+	_exits(0);
+}
+
+void
+setext(char *ext, int n, char *p)
+{
+	int i, c;
+
+	n--;
+	for(i = 0; i < n; i++){
+		c = p[i];
+		if(c == 0)
+			break;
+		if(c == '/')
+			c = '_';
+		ext[i] = c;
+	}
+	ext[i] = 0;
+}
+
+void
+mountinit(char *service, char *mntpt)
+{
+	int f;
+	int p[2];
+	char buf[32];
+
+	if(pipe(p) < 0)
+		sysfatal("pipe failed: %r");
+
+	/*
+	 *  make a /srv/registry
+	 */
+	if((f = create(service, OWRITE|ORCLOSE, 0666)) < 0)
+		sysfatal("create %s failed: %r", service);
+	snprint(buf, sizeof buf, "%d", p[1]);
+	if(write(f, buf, strlen(buf)) != strlen(buf))
+		sysfatal("write %s failed: %r", service);
+
+	/* copy namespace to avoid a deadlock */
+	switch(rfork(RFFDG|RFPROC|RFNAMEG)){
+	case 0:			/* child: start main proc */
+		close(p[1]);
+		procsetname("%s", mntpt);
+		break;
+	case -1:
+		sysfatal("fork failed: %r");
+	default:		/* parent: make /srv/registry, mount it, exit */
+		close(p[0]);
+
+		/*
+		 *  put ourselves into the file system
+		 */
+		if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
+			fprint(2, "registry mount failed: %r\n");
+		_exits(0);
+	}
+	mfd[0] = mfd[1] = p[0];
+}
+
+Mfile*
+newfid(int fid, int needunused)
+{
+	Mfile *mf;
+
+	lock(&mfalloc);
+	for(mf = mfalloc.inuse; mf != nil; mf = mf->next)
+		if(mf->fid == fid){
+			unlock(&mfalloc);
+			if(needunused)
+				return nil;
+			return mf;
+		}
+	mf = emalloc(sizeof(*mf));
+	mf->fid = fid;
+	mf->qid.vers = vers;
+	mf->qid.type = QTDIR;
+	mf->qid.path = 0LL;
+	mf->user = estrdup(reguser);
+	mf->next = mfalloc.inuse;
+	mfalloc.inuse = mf;
+	unlock(&mfalloc);
+	return mf;
+}
+
+void
+freefid(Mfile *mf)
+{
+	Mfile **l;
+
+	lock(&mfalloc);
+	for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next)
+		if(*l == mf){
+			*l = mf->next;
+			free(mf->user);
+			memset(mf, 0, sizeof *mf);	/* cause trouble */
+			free(mf);
+			unlock(&mfalloc);
+			return;
+		}
+	unlock(&mfalloc);
+	sysfatal("freeing unused fid");
+}
+
+Mfile*
+copyfid(Mfile *mf, int fid)
+{
+	Mfile *nmf;
+
+	nmf = newfid(fid, 1);
+	if(nmf == nil)
+		return nil;
+	nmf->fid = fid;
+	free(nmf->user);
+	nmf->user = estrdup(mf->user);
+	nmf->qid.type = mf->qid.type;
+	nmf->qid.path = mf->qid.path;
+	nmf->qid.vers = vers++;
+	return nmf;
+}
+
+Job*
+newjob(void)
+{
+	Job *job;
+
+	job = emalloc(sizeof *job);
+	lock(&joblock);
+	job->next = joblist;
+	joblist = job;
+	job->request.tag = -1;
+	unlock(&joblock);
+	return job;
+}
+
+void
+freejob(Job *job)
+{
+	Job **l;
+
+	lock(&joblock);
+	for(l = &joblist; *l; l = &(*l)->next)
+		if(*l == job){
+			*l = job->next;
+			memset(job, 0, sizeof *job);	/* cause trouble */
+			free(job);
+			break;
+		}
+	unlock(&joblock);
+}
+
+void
+flushjob(int tag)
+{
+	Job *job;
+
+	lock(&joblock);
+	for(job = joblist; job; job = job->next)
+		if(job->request.tag == tag && job->request.type != Tflush){
+			job->flushed = 1;
+			break;
+		}
+	unlock(&joblock);
+}
+
+void
+io(void)
+{
+	long n;
+	Mfile *mf;
+	uchar mdata[IOHDRSZ + Maxfdata];
+	Job *job;
+
+	while((n = read9pmsg(mfd[0], mdata, sizeof mdata)) != 0){
+		if(n < 0){
+			syslog(1, logfile, "error reading 9P from %s: %r", mntpt);
+			break;
+		}
+
+		job = newjob();
+		if(convM2S(mdata, n, &job->request) != n){
+			reglog("format error %ux %ux %ux %ux %ux",
+				mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]);
+			freejob(job);
+			break;
+		}
+		mf = newfid(job->request.fid, 0);
+		if(debug)
+			reglog("%F", &job->request);
+
+		switch(job->request.type){
+		default:
+			warning("unknown request type %d", job->request.type);
+			break;
+		case Tversion:
+			rversion(job);
+			break;
+		case Tauth:
+			rauth(job);
+			break;
+		case Tflush:
+			rflush(job);
+			break;
+		case Tattach:
+			rattach(job, mf);
+			break;
+		case Twalk:
+			rwalk(job, mf);
+			break;
+		case Topen:
+			ropen(job, mf);
+			break;
+		case Tcreate:
+			rcreate(job, mf);
+			break;
+		case Tread:
+			rread(job, mf);
+			break;
+		case Twrite:
+			rwrite(job, mf);
+			break;
+		case Tclunk:
+			rclunk(job, mf);
+			break;
+		case Tremove:
+			rremove(job, mf);
+			break;
+		case Tstat:
+			rstat(job, mf);
+			break;
+		case Twstat:
+			rwstat(job, mf);
+			break;
+		}
+
+		freejob(job);
+	}
+}
+
+void
+rversion(Job *job)
+{
+	if(job->request.msize > IOHDRSZ + Maxfdata)
+		job->reply.msize = IOHDRSZ + Maxfdata;
+	else
+		job->reply.msize = job->request.msize;
+	job->reply.version = "9P2000";
+	if(strncmp(job->request.version, "9P", 2) != 0)
+		job->reply.version = "unknown";
+	sendmsg(job, nil);
+}
+
+void
+rauth(Job *job)
+{
+	sendmsg(job, "registry: authentication not required");
+}
+
+void
+rflush(Job *job)
+{
+	flushjob(job->request.oldtag);
+	sendmsg(job, 0);
+}
+
+void
+rattach(Job *job, Mfile *mf)
+{
+	if(mf->user != nil)
+		free(mf->user);
+	mf->user = estrdup(job->request.uname);
+	mf->qid.vers = vers++;
+	mf->qid.type = QTDIR;
+	mf->qid.path = 0LL;
+	job->reply.qid = mf->qid;
+	sendmsg(job, 0);
+}
+
+char*
+rwalk(Job *job, Mfile *mf)
+{
+	int i, nelems;
+	char *err;
+	char **elems;
+	Mfile *nmf;
+	Qid qid;
+
+	err = 0;
+	nmf = nil;
+	elems = job->request.wname;
+	nelems = job->request.nwname;
+	job->reply.nwqid = 0;
+
+	if(job->request.newfid != job->request.fid){
+		/* clone fid */
+		nmf = copyfid(mf, job->request.newfid);
+		if(nmf == nil){
+			err = "clone bad newfid";
+			goto send;
+		}
+		mf = nmf;
+	}
+	/* else nmf will be nil */
+
+	qid = mf->qid;
+	if(nelems > 0){
+		/* walk fid */
+		for(i=0; i<nelems && i<MAXWELEM; i++){
+			if((qid.type & QTDIR) == 0){
+				err = "not a directory";
+				break;
+			}
+			if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){
+				qid.type = QTDIR;
+				qid.path = Qdir;
+    Found:
+				job->reply.wqid[i] = qid;
+				job->reply.nwqid++;
+				continue;
+			}
+			if(strcmp(elems[i], "registry") == 0){
+				qid.type = QTFILE;
+				qid.path = Qreg;
+				goto Found;
+			}
+			err = "file does not exist";
+			break;
+		}
+	}
+
+    send:
+	if(nmf != nil && (err!=nil || job->reply.nwqid<nelems))
+		freefid(nmf);
+	if(err == nil)
+		mf->qid = qid;
+	sendmsg(job, err);
+	return err;
+}
+
+void
+ropen(Job *job, Mfile *mf)
+{
+	int mode;
+	char *err;
+
+	err = 0;
+	mode = job->request.mode;
+	if(mf->qid.type & QTDIR)
+		if(mode)
+			err = "permission denied";
+	job->reply.qid = mf->qid;
+	job->reply.iounit = 0;
+	sendmsg(job, err);
+}
+
+void
+rcreate(Job *job, Mfile *mf)
+{
+	USED(mf);
+	sendmsg(job, "creation permission denied");
+}
+
+void rclunk(Job *job, Mfile *mf)
+{
+	freefid(mf);
+	sendmsg(job, 0);
+}
+
+void
+rremove(Job *job, Mfile *mf)
+{
+	USED(mf);
+	sendmsg(job, "remove permission denied");
+}
+
+void 
+rread(Job *job, Mfile *mf)
+{
+	int i, n;
+	long clock;
+	ulong cnt;
+	vlong off;
+	char *err;
+	uchar buf[Maxfdata];
+	Dir dir;
+
+	n = 0;
+	err = nil;
+	off = job->request.offset;
+	cnt = job->request.count;
+	*buf = '\0';
+	job->reply.data = (char*)buf;
+	if(mf->qid.type & QTDIR){
+		clock = time(nil);
+		if(off == 0){
+			memset(&dir, 0, sizeof dir);
+			dir.name = "registry";
+			dir.qid.type = QTFILE;
+			dir.qid.vers = vers;
+			dir.qid.path = Qreg;
+			dir.mode = 0666;
+			dir.length = 0;
+			dir.uid = dir.gid = dir.muid = mf->user;
+			dir.atime = dir.mtime = clock;
+			n = convD2M(&dir, buf, sizeof buf);
+		}
+	} else if (off < 0)
+		err = "negative read offset";
+	else {
+		for(i = 1; i < mf->nrr; i++)
+			if(mf->rr[i] > off)
+				break;
+		if(i <= mf->nrr){
+			if(off + cnt > mf->rr[i])
+				n = mf->rr[i] - off;
+			else
+				n = cnt;
+			assert(n >= 0);
+			job->reply.data = mf->reply + off;
+		}
+	}
+	job->reply.count = n;
+	sendmsg(job, err);	
+}
+
+void 
+rwrite(Job *job, Mfile *mf)
+{
+	int send, pipe2rc;
+	ulong cnt;	
+	char *err, *atype;
+	char errbuf[ERRMAX];
+	
+	err = nil;
+	cnt = job->request.count;
+	send = 1;
+	if(mf->qid.type & QTDIR)
+		err = "can't write directory";
+	else if (job->request.offset != 0)
+		err = "writing at non-zero offset";
+	else if (cnt >= Maxrequest)
+		err = "request too long";
+	else
+		send = 0;
+	if(send)
+		goto send;
+
+	job->request.data[cnt] = 0;
+	if(cnt > 0 && job->request.data[cnt-1] == '\n')
+		job->request.data[cnt-1] = 0;
+
+	if(strcmp(mf->user, "none") == 0 || strcmp(mf->user, reguser) != 0)
+		goto query; /* We don't want remote clients to modify our local */
+
+	/*
+	 * special commands
+	 */
+	send = 1;
+	if(strcmp(job->request.data, "debug")==0)
+		debug ^= 1;
+	else if(strcmp(job->request.data, "dump")==0)
+		regdump("/lib/ndb/regdump");
+	else if (strcmp(job->request.data, "refresh")==0)
+		refresh();
+	else if (strncmp(job->request.data, "add ", 4)==0)
+		err = addsrv(job->request.data + 4);
+	else if (strncmp(job->request.data, "rm ", 3)==0)
+		err = rmsrv(job->request.data + 3);
+	else if (strncmp(job->request.data, "update ", 7)==0)
+		err = updatesrv(job->request.data + 7);
+	else
+		send = 0;
+	if (send)
+		goto send;
+
+query:
+	/*
+	 *	kill previous reply
+	 */
+	mf->nrr = 0;
+	mf->rr[0] = 0;
+	pipe2rc = 0;
+	
+	atype = strchr(job->request.data, ' ');
+	if(atype == 0){
+		snprint(errbuf, sizeof errbuf, "illegal request %s", job->request.data);
+		err = errbuf;
+		goto send;
+	} else
+		*atype++ = 0;
+
+	if(strcmp(atype, "srv") == 0)
+		pipe2rc++;
+	else if(strcmp(atype, "scan") != 0){
+		snprint(errbuf, sizeof errbuf, "unknown query %s", atype);
+		err = errbuf;
+		goto send;
+	}
+
+	err = query(job, mf,job->request.data, pipe2rc);
+send:
+	job->reply.count = cnt;
+	sendmsg(job, err);
+}
+
+void
+rstat(Job *job, Mfile *mf)
+{
+	Dir dir;
+	uchar buf[IOHDRSZ+Maxfdata];
+	
+	memset(&dir, 0, sizeof dir);
+	if(mf->qid.type & QTDIR){
+		dir.name = ".";
+		dir.mode = DMDIR|0555;
+	}else{
+		dir.name = "registry";
+		dir.mode = 0666;
+	}
+	dir.qid = mf->qid;
+	dir.length = 0;
+	dir.uid = dir.gid = dir.muid = mf->user;
+	dir.atime = dir.mtime = time(nil);
+	job->reply.nstat = convD2M(&dir, buf, sizeof buf);
+	job->reply.stat = buf;
+	sendmsg(job, 0);
+}
+
+void
+rwstat(Job *job, Mfile *mf)
+{
+	USED(mf);
+	sendmsg(job, "wstat permission denied");
+}
+
+static char *
+query(Job *job, Mfile *mf, char *p, int pipe2rc)
+{
+	int n;
+
+	Service *c;
+	lock(&joblock);
+	if(!job->flushed){
+		n = 0;
+		mf->nrr = 0;
+		for(c = registry; c && n < Maxreply; c = c->next)
+			if((strncmp(p, c->labl, strlen(p))==0) || (strcmp(p, "all")==0)){
+				mf->rr[mf->nrr++] = n;
+				if(pipe2rc)
+					n += snprint(mf->reply+n, Maxreply-n, "%G", c);
+				else
+					n += snprint(mf->reply+n, Maxreply-n, "%N", c);
+			}
+		mf->rr[mf->nrr] = n;
+	}
+	unlock(&joblock);
+	return nil;
+}
+
+void
+sendmsg(Job *job, char *err)
+{
+	int n;
+	uchar mdata[IOHDRSZ+Maxfdata];
+	char ename[ERRMAX];
+
+	if(err){
+		job->reply.type = Rerror;
+		snprint(ename, sizeof ename, "registry: %s", err);
+		job->reply.ename = ename;
+	}else
+		job->reply.type = job->request.type+1;
+	job->reply.tag = job->request.tag;
+	n = convS2M(&job->reply, mdata, sizeof mdata);
+	if(n == 0){
+		warning("sendmsg convS2M of %F returns 0", &job->reply);
+		abort();
+	}
+	lock(&joblock);
+	if(job->flushed == 0)
+		if(write(mfd[1], mdata, n)!=n)
+			sysfatal("mount write");
+	unlock(&joblock);
+	if(debug)
+		reglog("%F %d", &job->reply, n);
+}
+
+void
+regdump(char *file)
+{
+	Service *rp;
+	int fd;
+
+	fd = create(file, OWRITE, 0666);
+	if(fd < 0)
+		return;
+	lock(&mfalloc);
+	for(rp = registry; rp; rp = rp->next)
+		fprint(fd, "%D\n\n", rp);
+	unlock(&mfalloc);
+	close(fd);
+}
+
+void
+refresh(void)
+{	
+	Service *c;
+	char dial[Maxdial];
+
+	for(c = registry; c; c = c->next){
+		/* Don't remove the ones we've added since startup */
+		if(!c->perm)
+			continue;
+		snprint(dial, Maxdial, "%s!%s!%s", c->trns, c->host, c->port);
+		rmsrv(dial);
+		/* Reset so we don't have messy loops */
+		c = registry;
+	}
+	reg2cache();
+}
+
+char *
+addsrv(char *args)
+{
+	if(debug)
+		reglog("Adding entry: %s", args);
+
+	return rstr2cache(args, 0);
+}
+
+char *
+rmsrv(char *args)
+{
+	if(debug)
+		reglog("Removing entry: %s", args);
+
+	return rstrdtch(args);
+}
+
+char *
+updatesrv(char *args)
+{
+	if(debug)
+		reglog("Updating entry: %s", args);
+
+	return rstrupdt(args);
+}
+
+void
+warning(char *fmt, ...)
+{
+	char regerr[256];
+	va_list arg;
+
+	va_start(arg, fmt);
+	vseprint(regerr, regerr+sizeof(regerr), fmt, arg);
+	va_end(arg);
+	syslog(1, logfile, regerr);
+}
+
+void
+reglog(char *fmt, ...)
+{
+	char regerr[256];
+	va_list arg;
+	
+	va_start(arg, fmt);
+	vseprint(regerr, regerr+sizeof(regerr), fmt, arg);
+	va_end(arg);
+	syslog(0, logfile, regerr);
+}
+
+void*
+emalloc(int size)
+{
+	void *x;
+
+	x = malloc(size);
+	if(x == nil)
+		sysfatal("out of memory");
+	memset(x, 0, size);
+	return x;
+}
+
+char*
+estrdup(char *s)
+{
+	int size;
+	char *p;
+
+	size = strlen(s);
+	p = malloc(size+1);
+	if(p == nil)
+		sysfatal("out of memory");
+	memmove(p, s, size);
+	p[size] = 0;
+	return p;
+}
+
+int
+srvfmt(Fmt *f)
+{
+	Service *r;
+	char mf[Maxpath+1], auth[7];
+	
+	r = va_arg(f->args, Service*);
+	mf[0] = 0;
+	auth[0] = 0;
+		
+	if(strcmp(r->mtpt, "")!= 0)
+		snprint(mf, sizeof(r->mtpt)+1, " %s", r->mtpt);
+
+	if(strcmp(r->auth, "none")==0)
+		snprint(auth, 4, "srv");
+	else
+		snprint(auth, 7, "srvtls");
+
+	return fmtprint(f, "%s %s!%s!%s '%s'%s",
+		auth, r->trns, r->host, r->port, r->labl, mf);
+}
+
+int
+scanfmt(Fmt *f)
+{
+	Service *r;
+	char mf[Maxpath+6]; /* pad for our tuple attrs */
+
+	mf[0] = 0;
+	r = va_arg(f->args, Service*);
+	if(strcmp(r->mtpt, "")!=0)
+		snprint(mf, sizeof(r->mtpt)+6, " mtpt=%s", r->mtpt);
+	return fmtprint(f, "service=%s!%s!%s label='%s' auth=%s%s",
+		r->trns, r->host, r->port, r->labl, r->auth, mf);
+}
+
+int
+dumpfmt(Fmt *f)
+{
+	Service *r;
+	char mf[Maxpath+7]; /* pad for our tuple attrs */
+
+	r = va_arg(f->args, Service*);
+	if(r->mtpt != 0)
+		snprint(mf, sizeof(r->mtpt) + 7, "\n\tmtpt=%s", r->mtpt);
+	return fmtprint(f, "service=%s!%s!%s\n\tlabel=%s\n\tauth=%s%s",
+		r->trns, r->host, r->port, r->labl, r->auth, mf);
+}
+
diff -r 8127893f53b1 sys/src/cmd/ndb/reglookup.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/cmd/ndb/reglookup.c	Fri Aug 28 20:55:56 2020 -0700
@@ -0,0 +1,204 @@
+#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(Service* svc, int persist)
+{
+	svc->perm = !!persist;
+
+	if(registry != nil){
+		svc->next = registry;
+	}
+
+	svc->next = registry;
+	registry = svc;
+}
+
+static char*
+detach(char *dial)
+{
+	Service *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(Service *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;
+	Service *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);
+	}
+
+
+}
+
+/* For now, we expect properly formatted strings */
+char*
+rstr2cache(char *entry, int persist)
+{
+	Service *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]);
+	attach(svc, persist);
+	return 0;
+}
+
+char*
+rstrdtch(char *svc)
+{
+	return detach(svc);
+}
+
+/* e.g. update tcp!foo!9fs label newlabel */
+char*
+rstrupdt(char *entry)
+{
+	Service *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
+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);
+}
diff -r 8127893f53b1 sys/src/cmd/ndb/regquery.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/cmd/ndb/regquery.c	Fri Aug 28 20:55:56 2020 -0700
@@ -0,0 +1,69 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include <ndb.h>
+#include "dns.h"
+#include "ip.h"
+
+void
+usage(void)
+{
+	fprint(2, "usage: regquery [-s] [-f registry] query\n");
+	exits("usage");
+}
+
+static void
+queryregistry(int fd, char *line, int n)
+{
+	char buf[8192+1];
+
+	seek(fd, 0, 0);
+	write(fd, line, n);
+
+	seek(fd, 0, 0);
+	while((n = read(fd, buf, sizeof(buf)-1)) > 0){
+		buf[n++] = '\n';
+		write(1, buf, n);
+	}
+}
+
+static void
+query(int fd, char *q, int pipe2rc)
+{
+	char arg[260];
+
+	if(strlen(q) > 255)
+		sysfatal("query too long");
+
+	sprint(arg, "%s %s", q, (pipe2rc) ? "srv":"scan");
+	queryregistry(fd, arg, sizeof(arg));
+}
+
+void
+main(int argc, char *argv[])
+{
+	int fd, pipe2rc = 0;
+	char *rst  = "/net/registry";
+
+	ARGBEGIN {
+	case 's':
+		pipe2rc++;
+		break;
+	case 'f':
+		rst = EARGF(usage());
+		break;
+	default:
+		usage();
+	} ARGEND;
+
+	if(argc != 1)
+		usage();
+
+	fd = open(rst, ORDWR);
+	if(fd < 0)
+		sysfatal("can't open %s: %r", rst);
+
+	query(fd, argv[0], pipe2rc);
+	exits(0);
+}

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [9front] ndb/registry
  2020-08-29  4:17 ndb/registry Michael Misch
@ 2020-09-01  4:57 ` ori
  0 siblings, 0 replies; 2+ messages in thread
From: ori @ 2020-09-01  4:57 UTC (permalink / raw)
  To: 9front

> Hey, I’ve been working this last week on bringing ndb/registry over from inferno, but in a way that matches well with the rest of our ndb. 
> I have two binaries, ndb/registry and ndb/regquery. ndb/registry reads from /lib/ndb/registry, which would contain a list of local services you want to register on start up. They’re in regular ndb format, and look like
> 
> service=tcp!myipaddr!1234
> 	auth=none label=myservice
> 	mtpt=/n/myservice
> 
> You can add a service by writing, `add tcp!myipaddr!1234 label myservice [mtpt mymtpt label mylabel]` to /net/registry, rm `rm tcp!myipaddr!1234`, edit, `update tcp!myipaddr!1234 label newlabel` or any other tuple. Dump will create a dump of the current registry to /lib/ndb/regdump, refresh will reload the services from the db - while keeping any that you’ve added after startup untouched. 
> 
> regquery opens and reads /net/registry, and outputs any matching service descriptions `ndb/regquery myservice`, in tuple format; or as a plumbable string (currently only srv and srvtls) with -s, and will list all services when passed `ndb/regquery all`.
> 
> eg:
> 
> ndb/regquery grid
> service=tcp!myservice!1234 label=gridchat auth=none mtpt=/n/chat
> [ … ] // any other matches
> 
> ndb/regquery -s grid 
> srv tcp!myservice!1234 gridchat /n/chat
> [ … ] // any other matches
> 
> I use this with a database containing, at the moment the 9grid list of services, but would be useful for a general index of what services exist on a given network outright, on a remote network for bookkeeping, etc.
> 
> The code is fresh, and may have bugs I haven’t caught! I’ll include the diff here, thanks!
> 
>  - halfwit 

(Mostly repeating what I said on grid)

I'll try to take a look at this soon, but I'd be against
merging it until this gets used in anger. Usually it's
when an API actually gets used that improvements come
out. If you have code that uses this, I'd like to see it.



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2020-09-01  4:57 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-29  4:17 ndb/registry Michael Misch
2020-09-01  4:57 ` [9front] ndb/registry ori

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).