ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/collab/proxy.b/
implement Proxy;
include "sys.m";
sys: Sys;
include "srvmgr.m";
include "proxy.m";
Srvreq, Srvreply: import Srvmgr;
init(root: string, fd: ref Sys->FD, rc: chan of ref Srvreq, user: string)
{
sys = load Sys Sys->PATH;
if(fd == nil)
raise "err: fd for export was nil";
sys->chdir(root);
sys->bind("export/services", "export/services", Sys->MCREATE);
sys->bind("#s", "export/services", Sys->MBEFORE);
ctlio := sys->file2chan("export/services", "ctl");
if(ctlio == nil)
raise "err: export/services file2chan failed -- " + root + "/export/services directory does not exist" ;
hangup := chan of int;
spawn export(fd, "export", hangup);
fd = nil;
for (;;) alt {
<- hangup =>
# closedown all clients
sys->print("client exit [%s]\n", user);
rmclients(rc);
return;
(offset, count, fid, r) := <- ctlio.read =>
client := fid2client(fid);
if (r == nil) {
if (client != nil)
rmclient(rc, client);
continue;
}
if (client == nil) {
rreply(r, (nil, "service not set"));
continue;
}
rreply(r, reads(client.path, offset, count));
(offset, data, fid, w) := <- ctlio.write =>
client := fid2client(fid);
if (w == nil) {
if (client != nil)
rmclient(rc, client);
continue;
}
if (client != nil) {
wreply(w, (0, "service set"));
continue;
}
err := newclient(rc, user, fid, string data);
if (err != nil)
wreply(w, (0, err));
else
wreply(w, (len data, nil));
}
}
rreply(rc: chan of (array of byte, string), reply: (array of byte, string))
{
alt {
rc <-= reply =>;
* =>;
}
}
wreply(wc: chan of (int, string), reply: (int, string))
{
alt {
wc <-= reply=>;
* =>;
}
}
reads(str: string, off, nbytes: int): (array of byte, string)
{
bstr := array of byte str;
slen := len bstr;
if(off < 0 || off >= slen)
return (nil, nil);
if(off + nbytes > slen)
nbytes = slen - off;
if(nbytes <= 0)
return (nil, nil);
return (bstr[off:off+nbytes], nil);
}
export(exportfd: ref Sys->FD, dir: string, done: chan of int)
{
sys->export(exportfd, dir, Sys->EXPWAIT);
done <-= 1;
}
Client: adt {
fid: int;
path: string;
sname: string;
id: string;
};
clients: list of ref Client;
freepaths: list of string;
nextpath := 0;
fid2client(fid: int): ref Client
{
for(cl := clients; cl != nil; cl = tl cl)
if ((c := hd cl).fid == fid)
return c;
return nil;
}
newclient(rc: chan of ref Srvreq, user: string, fid: int, cmd: string): string
{
sys->print("new Client %s [%s]\n", user, cmd);
for (i := 0; i < len cmd; i++)
if (cmd[i] == ' ')
break;
if (i == 0 || i == len cmd)
return "bad command";
sname := cmd[:i];
id := cmd[i:];
reply := chan of Srvreply;
rc <-= ref Srvreq.Acquire(sname, id, user, reply);
(err, root, fd) := <- reply;
if (err != nil)
return err;
path := "";
if (freepaths != nil)
(path, freepaths) = (hd freepaths, tl freepaths);
else
path = string nextpath++;
sys->mount(fd, nil, "mnt", Sys->MREPL, nil); # connection to the active service fs
mkdir("export/services/"+path);
sys->bind("mnt/"+root, "export/services/"+path, Sys->MREPL|Sys->MCREATE);
sys->unmount("mnt", nil);
clients = ref Client(fid, path, sname, id) :: clients;
return nil;
}
rmclient(rc: chan of ref Srvreq, client: ref Client)
{
sys->print("rmclient [%s %s]\n", client.sname, client.id);
nl: list of ref Client;
for(cl := clients; cl != nil; cl = tl cl)
if((c := hd cl) == client){
sys->unmount("export/services/" + client.path, nil);
freepaths = client.path :: freepaths;
rc <-= ref Srvreq.Release(client.sname, client.id);
} else
nl = c :: nl;
clients = nl;
}
rmclients(rc: chan of ref Srvreq)
{
for(cl := clients; cl != nil; cl = tl cl){
c := hd cl;
sys->print("rmclients [%s %s]\n", c.sname, c.id);
rc <-= ref Srvreq.Release(c.sname, c.id);
}
clients = nil;
}
mkdir(path: string)
{
sys->print("mkdir [%s]\n", path);
sys->create(path, Sys->OREAD, 8r777 | Sys->DMDIR);
}