/** ** ============================== ** O O O OOOO ** O O O O O O ** O O O O O O ** OOOO OOOO O OOO OOOO ** O O O O O O O ** O O O O O O O ** OOOO OOOO O O OOOO ** ============================== ** BSSLAB, Dr. Stefan Bosse http://www.bsslab.de ** ** COPYRIGHT: THIS SOFTWARE, EXECUTABLE AND SOURCE CODE IS OWNED ** BY THE AUTHOR(S). ** THIS SOURCE CODE MAY NOT BE COPIED, EXTRACTED, ** MODIFIED, OR OTHERWISE USED IN A CONTEXT ** OUTSIDE OF THE SOFTWARE SYSTEM. ** ** $AUTHORS: Stefan Bosse ** $INITIAL: (C) 2006-2017 bLAB ** $CREATED: 31-3-15 by sbosse. ** $VERSION: 1.1.8 ** ** $INFO: ** ** DOS: DNS Client Interface ** ** $ENDOFINFO */ "use strict"; var log = 0; var util = Require('util'); var Io = Require('com/io'); var Net = Require('dos/network'); var Std = Require('dos/std'); var Sch = Require('dos/scheduler'); var Buf = Require('dos/buf'); var Rpc = Require('dos/rpc'); var Cs = Require('dos/capset'); var Comp = Require('com/compat'); var String = Comp.string; var Filename = Comp.filename; var Array = Comp.array; var Perv = Comp.pervasives; var Rand = Comp.random; var Status = Net.Status; var Command = Net.Command; var Rights = Net.Rights; /* ** Use the default DNS server */ var DNS_DEFAULT = undefined; var DNS_MAXPATH = 255; var DNS_DEFAULT_COLS = ['owner','group','others']; var DNS_DEFAULT_RIGHTS = [ Rights.DNS_RGT_OWNER|Rights.DNS_RGT_GROUP|Rights.DNS_RGT_OTHERS| Rights.DNS_RGT_READ|Rights.DNS_RGT_MODIFY|Rights.DNS_RGT_DELETE|Rights.DNS_RGT_CREATE, Rights.DNS_RGT_GROUP|Rights.DNS_RGT_OTHERS| Rights.DNS_RGT_READ, Rights.DNS_RGT_OTHERS| Rights.DNS_RGT_READ ]; var DNS_NTRY = 3; var DNS_NOMOREROWS = -1; var DNS_MAXCOLUMNS = Net.DNS_MAXCOLUMNS; /** {@link dir_entry~obj} * Directory Entry Class - one row * * @param {string} de_name * @param {string} de_time * @param {number []} de_columns * @constructor * @typedef {{de_name,de_time,de_columns}} dir_entry~obj */ var dir_entry = function (de_name,de_time,de_columns) { this.de_name = de_name; // string; this.de_time = de_time; // number; this.de_columns = de_columns; // rights_bits array; }; /** {@link dir~obj} ** Directory Class - One directory * * * @param {capset} [di_capset] * @param {number} [di_ncols] * @param {number} [di_nrows] * @param {string []} [di_colnames] * @param {dir_entry []} [di_rows] * @param {number} [di_curpos] * @constructor * @typedef {{di_capset,di_ncols,di_nrows,di_colnames,di_rows,di_curpos}} dir~obj */ var dir = function (di_capset,di_ncols,di_nrows,di_colnames,di_rows,di_curpos) { this.di_capset = di_capset; // capset this.di_ncols = di_ncols||0; // int this.di_nrows = di_nrows||0; // int this.di_colnames = di_colnames||[]; // string array this.di_rows = di_rows||[]; // dns_dir_entry array this.di_curpos = di_curpos||0; // int }; /** Directory Entry Object * * @param de_name * @param de_time * @param de_columns * @returns {dir_entry} * @constructor */ function Dir_entry (de_name,de_time,de_columns) { var obj = new dir_entry(de_name,de_time,de_columns); Object.preventExtensions(obj); return obj; } /** ** One directory * * * @param {capset} [di_capset] * @param {number} [di_ncols] * @param {number} [di_nrows] * @param {string []} [di_colnames] * @param {dir_entry []} [di_rows] * @param {number} [di_curpos] * @returns {dir} */ function Dir (di_capset,di_ncols,di_nrows,di_colnames,di_rows,di_curpos) { var obj = new dir(di_capset,di_ncols,di_nrows,di_colnames,di_rows,di_curpos); Object.preventExtensions(obj); return obj; } /* ** BUFFER operations */ function buf_put_rights (buf,rights) { Buf.buf_put_int32(buf,rights); } function buf_get_rights (buf) { var rights=0; rights=Buf.buf_get_int32(buf); return rights; } /* ** ========== ** DNS CLIENT * ========== */ /** {@link dns~obj} * DNS Client Programming Interface * @param {rpcint} rpc * @constructor */ var dnsint = function(rpc,env) { this.rpc=rpc; this.std=Std.StdInt(rpc); this.cs=Cs.CsInt(rpc); this.env=env||{}; if (!this.env.rootdir) this.env.rootdir=Cs.nilcapset; if (!this.env.rootdir) this.env.workdir=Cs.nilcapset; }; /** * * @returns {[]} */ dnsint.prototype.default_colmask = function () { var nmasks = Net.DNS_MAXCOLUMNS; var def_mask = Io.getenv('DNSMASK',''); var mask_array=[]; if (String.equal(def_mask,'')) { mask_array=Array.create(nmasks,0xff) } else { var def_mask_list = def_mask.split(':'); var def_mask_len = def_mask_list.length; if (def_mask_len > nmasks) Io.err('default_colmask: invalid dns mask from environment'); for (var i=0;i1) { buf=Buf.Buffer(); // we must save the rpcio data, it may be overridden by a previous transaction! Buf.buf_copy(buf,rpcio); } Io.log((log<1)||('Dns.mktrans max('+ntries+') '+Cs.Print.capset(cs))); Sch.ScheduleLoop(function () { return (tries <= ntries && err != Net.Status.STD_OK); },[ function () { s = cs.cs_suite[i]; i++; if (i==cs.cs_final) { i=0; tries++; } if (s.s_current == true) { rpcio.header.h_port = s.s_object.cap_port; Net.Copy.private(s.s_object.cap_priv,rpcio.header.h_priv); if (ntries>1) Buf.buf_copy(rpcio,buf); Io.log((log<1)||('Dns.mktrans ('+(tries-1)+') '+Rpc.Print.rpcio(rpcio))); Sch.ScheduleBlock([ /* ** Do the real transaction */ [Sch.Bind(self.rpc, self.rpc.trans), rpcio], [function () { Io.log((log<10)||('mktrans returned ' + Rpc.Print.rpcio(rpcio))); err = rpcio.status||rpcio.header.h_status; if (err==Status.RPC_FAILURE && ntries > 1) { /* ** Retry idempotent operation, but return RPC_FAILURE ** in case we don't succeed in a following iteration. */ failed=Status.RPC_FAILURE; } }] ]); } } ],[ function () {if (failed!=Status.STD_UNKNOWN) rpcio.status=failed;} ], function(e) { if (typeof e == 'number') rpcio.status=e; else { Io.printstack(e,'Dns.mktrans'); rpcio.status=Status.STD_SYSERR; } }) }; /** ** lookup returns the capability-set stored under the name ** 'path' relative to the directory 'root'. The root directory ** can be any directory in the directory tree. The path rest ** that can not be eresolved will be returned, too. * * * @param {capset} rootcs * @param {string} path * @param {function(status:(Status.STD_OK|*),cs:(capset|undefined),string)} callback */ dnsint.prototype.dns_lookup = function (rootcs,path,callback) { var self=this, err,cs,res, rpcio,depth,pos,path_len,cs_parent,finished,max_steps; Io.log((log<1)||('Dns.dns_lookup ('+path+') root='+(rootcs?Cs.Print.capset(rootcs):'[]'))); try { if (String.equal(path, '/')) { rootcs=rootcs||this.get_rootdir(); if (rootcs) callback(Status.STD_OK, rootcs, ''); else throw Status.STD_NOTNOW; } else { path = Filename.path_normalize(path); if (path.length==0) throw Status.STD_ARGBAD; max_steps=10; if (rootcs==DNS_DEFAULT) { if (String.get(path,0)=='/') cs=self.get_rootdir(); else cs=self.get_workdir(); if (cs==undefined) res=[Status.STD_STD_NOTNOW]; else res=[Status.STD_OK,cs]; } else res=[Status.STD_OK,self.cs.cs_copy(rootcs)]; err=res[0]; cs=res[1]; if (err != Status.STD_OK) throw (err==undefined?Status.STD_SYSERR:err); /* ** Loop over the path components step by step and resolve the path. ** Each run, the next path component is the new parent directory ** for the next lookup. */ rpcio=self.rpc.router.pkt_get(); depth= 1; pos; path_len=path.length; cs_parent=cs; finished=false; if (path_len>0 && String.get(path,0)=='/') { // remove a leading slash from path path=String.trim(path,1,0); } Sch.ScheduleLoop(function () { return (finished==false && err==Status.STD_OK); },[ function () { if (depth>max_steps) {finished=true; cs=undefined; err=Status.STD_OVERFLOW;} path_len=path.length; if (String.equal(path,'.') || path_len==0) { finished=true; cs=cs_parent; } }, function () { if (!finished && err==Status.STD_OK) { rpcio.header.h_command=Command.DNS_LOOKUP; rpcio.header.h_status=Status.STD_UNKNOWN; rpcio.pos=0; Buf.buf_put_string(rpcio,path); /* * ------------ * name(string) * ------------ * path(string) * cs(capset) * ------------ */ self.mktrans(DNS_NTRY,rpcio,cs_parent); } }, function () { if (!finished && err==Status.STD_OK) { err=rpcio.status||rpcio.header.h_status; if (err==Status.STD_OK) { // Get path rpcio.pos=0; path=Buf.buf_get_string(rpcio); // Get capset cs=Cs.buf_get_capset(rpcio); cs_parent=cs; // Remove a leading slash from path if (path.length>0 && path[0]=='/') path=String.trim(path,1,0); depth++; } else { finished=true; cs=undefined; } } } ],[ // Finalize block function () { callback(err,cs,path); self.rpc.router.pkt_discard(rpcio); } ], // Exception handler function function(e) { if (typeof e == 'number') callback(e, undefined, ''); else { Io.printstack(e,'Dns.dns_lookup'); callback(Status.STD_SYSERR, undefined, ''); } self.rpc.router.pkt_discard(rpcio); } ); } } catch (e) { if (typeof e == 'number') callback(e, undefined, ''); else { Io.printstack(e,'Dns.dns_lookup'); callback(Status.STD_SYSERR, undefined, ''); } } }; /** ** Lookup a set of directory capabilities specified by a (directory capability set - row name) list. ** The (status, row capset) tuple list is returned. * * @param {capset} server root directory * @param {* []} dirs (dir:capset * rowname:string) [] * @param {function((Status.STD_OK|*),* [])} callback (Status*capset) [] */ dnsint.prototype.dns_setlookup = function (server,dirs,callback) { var rpcio=self.rpc.router.pkt_get(); var ndirs = dirs.length; var stat; Sch.ScheduleBlock([ function () { /* * ------------ * nrows(int16) * [ * dir(capset) * rowname(string) * ] #nrows * ------------ * [ * status(int16) * cs(capset) * ] #nrows * ------------ */ rpcio.header.h_command=Command.DNS_SETLOOKUP; rpcio.header.h_status=Status.STD_UNKNOWN; rpcio.pos=0; Buf.buf_put_int16(dirs.length); Array.iter (dirs,function(dir) { Cs.buf_put_capset(rpcio,dir[0]); // directory capability set Buf.buf_put_string(rpcio,dir[1]); // row name }); self.mktrans(DNS_NTRY,rpcio,server); }, function(){ var i; var res; if (rpcio.status==Status.STD_OK) stat=rpcio.header.h_status; if (stat != Status.STD_OK) throw(stat); rpcio.pos=0; for(i=0;i