#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];} voiddelclient(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);} voidwriteannounces(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;} voidclientproc(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;} voidserver(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");} voidusage(void){ fprint(2, "usage: %s [-d] [-n addr] [-c volcfg] [dir]\n", argv0); sysfatal("usage");} voidthreadmain(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);}
#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);
}