* 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).