/** ** ================================== ** OOOO OOOO OOOO O O OOOO ** O O O O O O O O O ** O O O O O O O O O ** OOOO OOOO OOOO O OOO OOOO ** O O O O O O O O O ** O O O O O O O O O ** OOOO OOOO 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. ** 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-2016 BSSLAB ** $CREATED: 5/25/15 by sbosse. ** $VERSION: 1.2.6 ** ** $INFO: ** ** DOS: Host Server ** * The HOST Server listening on the public host port. * Provides a simple plain DNS (one root directory) used for publishing local servers. * * Basic directory structure: * * / * /hosts * /domains * /dns * ** ** $ENDOFINFO */ var log = 0; var util = require('util'); var Io = Require('com/io'); var trace = Io.tracing; var Net = Require('dos/network'); var Rpc = Require('dos/rpc'); var Router = Require('dos/router'); var Compat = Require('com/compat'); var Perv = Compat.pervasives; var String = Compat.string; var Array = Compat.array; var assert = Compat.assert; var Sch = Require('dos/scheduler'); var Buf = Require('dos/buf'); var DnsCom = Require('dos/dns_srv_common'); var DnsEMB = Require('dos/dns_srv_emb'); var Dns = Require('dos/dns'); var Cs = Require('dos/capset'); var Status = Net.Status; var Command = Net.Command; var Rights = Net.Rights; var isNodeJS = Compat.isNodeJS(); /** Create a HOST server with embedded DNS * * @param {rpcint} rpc * @param {port} pubport * @param {port} privport * @param {string} [name] * @param {object} [env] * @constructor * @typedef {{CsInt:csint,random:port,dns:dns_server,hostcap:capability,hostsdir:dns_dir, * domains:dns_dir,dnsdir:dns_dir,thread}} hostserver~obj * @see hostserver~obj */ var hostserver = function (rpc,pubport,privport,name,env) { var self = this; this.env=env||{}; var router = rpc.router; this.CsInt = Cs.CsInt(rpc); this.name=name||('HOST Server '+(router.brokerserver == undefined ? ' (Broker) ' : '')+Net.Print.port(pubport)); /* ** Simple DNS (only one root directory) table */ this.random=Net.uniqport(); this.dns = DnsEMB.Server(rpc); this.dns.create_dns(pubport,privport,this.random,false,Dns.DNS_DEFAULT_COLS); Io.out('[HOST] My host port is '+Net.Print.port(router.hostport)); Io.out('[HOST] My host name is '+this.name); Io.out('[HOST] DNS Root is '+Net.Print.capability(this.CsInt.cs_to_cap(this.dns.rootcs))); this.hostcap = Net.Capability(pubport,Net.Private(0,Rights.PRV_ALL_RIGHTS,this.random)); if (env) env.rootdir=this.dns.rootcs; // Server var main = this; this.services = []; this.dns_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 ]; this.host_rights = [ Rights.HOST_INFO|Rights.HOST_READ|Rights.HOST_WRITE|Rights.HOST_EXEC, Rights.HOST_INFO|Rights.HOST_READ|Rights.HOST_WRITE|Rights.HOST_EXEC, Rights.HOST_INFO ]; this.afs_rights = [ Rights.AFS_RGT_ADMIN|Rights.AFS_RGT_CREATE|Rights.AFS_RGT_DESTROY|Rights.AFS_RGT_MODIFY|Rights.AFS_RGT_READ, Rights.AFS_RGT_READ, Rights.AFS_RGT_READ ]; /* ** Create initial directory structure... */ main.hostsdir=main.dns.create_dir(Dns.DNS_DEFAULT_COLS); main.domainsdir=main.dns.create_dir(Dns.DNS_DEFAULT_COLS); main.dnsdir=main.dns.create_dir(Dns.DNS_DEFAULT_COLS); main.afsdir=main.dns.create_dir(Dns.DNS_DEFAULT_COLS); main.dns.append_row(main.hostsdir, DnsCom.Dns_row(main.name,main.dns.time(),this.host_rights, main.CsInt.cs_singleton(main.hostcap))); main.dns.append_row(main.dns.rootdir,DnsCom.Dns_row('hosts',main.dns.time(),this.dns_rights, main.dns.capset_of_dir(main.hostsdir))); main.dns.append_row(main.dns.rootdir,DnsCom.Dns_row('domains',main.dns.time(),this.dns_rights, main.dns.capset_of_dir(main.domainsdir))); main.dns.append_row(main.dns.rootdir,DnsCom.Dns_row('dns',main.dns.time(),this.dns_rights, main.dns.capset_of_dir(main.dnsdir))); main.dns.append_row(main.dns.rootdir,DnsCom.Dns_row('afs',main.dns.time(),this.dns_rights, main.dns.capset_of_dir(main.afsdir))); main.dns.release_dir(main.hostsdir); main.dns.release_dir(main.domainsdir); main.dns.release_dir(main.dnsdir); main.dns.release_dir(main.afsdir); self.geo={}; this.thread = function (arg) { var thr = this; var dying=false; var rpcio = router.pkt_get(); this.init = function () { Io.out('[HOST'+arg+'] Starting host server with public port ' + Net.Print.port(pubport)); router.add_port(privport); }; this.request = function () { Io.log((log < 1) || ('[HOST'+arg+'] waiting for a request')); rpcio.init(); rpcio.operation = Rpc.Operation.GETREQ; rpcio.header.h_port = privport; rpcio.header.h_status = undefined; rpcio.header.h_command = undefined; rpcio.header.h_priv = undefined; // Io.out(util.inspect(rpcio)); rpc.getreq(rpcio); assert((rpcio.index != -1) || ('RPCIO invalid')); }; this.service = function () { var mem, str, used, i, service, name, path, cs, rights, ncols, cols, colnames, found, off, mask, priv, paramn, params, stat, serviced; Io.log((log < 1) || ('[HOST'+arg+'] service request')); assert(rpcio.index != -1, 'RPCIO invalid'); Io.log((log < 1) || (Net.Print.header(rpcio.header))); rpcio.pos = 0; rpcio.header.h_status = Status.STD_OK; var obj = Net.prv_number(rpcio.header.h_priv); switch (rpcio.header.h_command) { /* ** Standard Calls */ case Command.STD_INFO: Io.log((log < 1) || 'hostsrv.STD_INFO ' + Net.Print.private(rpcio.header.h_priv)); Buf.buf_init(rpcio); if (obj == 0) Buf.buf_put_string(rpcio, self.name); else { // It is a directory object. TODO str = '/'; main.dns.dns_info(rpcio.header.h_priv, function (_stat, _str) { Buf.buf_put_string(rpcio, _str); }); } break; case Command.STD_AGE: /* ** Force memory garbage collection! */ if (isNodeJS && global.gc != undefined) { mem = process.memoryUsage(); var mem0 = mem; var progress = 1000; var count = 20; while (count > 0 && progress >= 1000) { global.gc(); mem = process.memoryUsage(); progress = mem0.rss - mem.rss; if (progress < 0) progress = mem0.heapUsed - mem.heapUsed; mem0 = mem; count--; } } else rpcio.header.h_status = Status.STD_SYSERR; break; case Command.STD_STATUS: Buf.buf_init(rpcio); str = 'Statistics\n==========\n'; if (process != undefined) { mem = process.memoryUsage(); str = str + 'MEMORY: RSS=' + Perv.div(mem.rss, 1024) + ' HEAP=' + Perv.div(mem.heapTotal, 1024) + ' USED=' + Perv.div(mem.heapUsed, 1024) + ' kB\n'; } str = str + router.status()+'\n'; Buf.buf_put_string(rpcio, str); break; case Command.STD_LOCATION: break; case Command.STD_RESTRICT: /* * ---------- * mask (int16) * ---------- * priv (privat) * ---------- */ Io.log((log < 1) || 'hostsrv.STD_RESTRICT ' + Net.Print.private(rpcio.header.h_priv)); mask=Buf.buf_get_int16(rpcio); Buf.buf_init(rpcio); priv=Net.restrict(rpcio.header.h_priv,mask,main.random); if (priv!=undefined) { Buf.buf_put_priv(rpcio,priv); rpcio.header.h_status=Status.STD_OK; } else rpcio.header.h_status=Status.STD_SYSERR; break; case Command.STD_SETPARAMS: Io.log((log < 1) || 'hostsrv.STD_SETPARAMS ' + Net.Print.private(rpcio.header.h_priv)); paramn=Buf.buf_get_int16(rpcio); params = []; stat=Status.STD_OK; if (paramn > 0 && paramn < 256) { for (i = 0; i < paramn; i++) { var pn = Buf.buf_get_string(rpcio); var pv = Buf.buf_get_string(rpcio); params.push([pn,pv]); } } else stat=Status.STD_ARGBAD; Array.iter (params,function (param) { String.match(param[0], [ ['monitor',function () { router.monitor=Perv.int_of_string(param[1]); }] ]) }); Buf.buf_init(rpcio); rpcio.header.h_status=stat; break; /********************* ** DNS Calls **********************/ case Command.DNS_APPEND: /* * ------------ * name:string * obj:capset * ncols:number * ------------ * ------------ */ Io.log((log < 1) || 'hostsrv.DNS_APPEND ' + Net.Print.private(rpcio.header.h_priv)); name = Buf.buf_get_string(rpcio); cs = Cs.buf_get_capset(rpcio); ncols = Buf.buf_get_int16(rpcio); cols = []; for (i = 0; i < ncols; i++) { cols.push(Dns.buf_get_rights(rpcio)); } if (log > 1) { Io.inspect(name); Io.inspect(cs); Io.inspect(cols); } Sch.ScheduleBlock([ function () { main.dns.dns_append(rpcio.header.h_priv, name, cols, cs, function (_stat) { rpcio.header.h_status = _stat; Buf.buf_init(rpcio); Io.log((log < 1) || ('hostsrv.DNS_APPEND returns: ' + Net.Status.print(_stat))); }); }]); Io.log((log < 1) || ('hostsrv.DNS_APPEND passes through')); break; case Command.DNS_LOOKUP: Io.log((log < 1) || 'hostsrv.DNS_LOOKUP ' + Net.Print.private(rpcio.header.h_priv)); path = Buf.buf_get_string(rpcio); Sch.ScheduleBlock([ function () { main.dns.dns_lookup(rpcio.header.h_priv, path, function (_stat, _cs, _path) { Io.log((log < 1) || ('hostsrv.DNS_LOOKUP returns: ' + Net.Status.print(_stat))); Buf.buf_init(rpcio); if (_stat == Status.STD_OK) { /* ** Put the path_rest string and the capability set. */ Buf.buf_put_string(rpcio, _path); Cs.buf_put_capset(rpcio, _cs); } else { rpcio.header.h_status = _stat; } }); }]); Io.log((log < 1) || ('hostsrv.DNS_LOOKUP passes through')); break; case Command.DNS_RENAME: /* * ------------ * oldname:string * newname:string * ------------ * ------------ */ Io.log((log < 1) || 'hostsrv.DNS_RENAME ' + Net.Print.private(rpcio.header.h_priv)); name = Buf.buf_get_string(rpcio); var newname = Buf.buf_get_string(rpcio); Sch.ScheduleBlock([ function () { main.dns.dns_rename(rpcio.header.h_priv, name, newname, function (_stat) { Buf.buf_init(rpcio); rpcio.header.h_status = _stat; }); }]); break; case Command.DNS_DELETE: /* * ------------ * rowname:string * ------------ * ------------ */ Io.log((log < 1) || ('hostsrv.DNS_DELETE ' + Net.Print.private(rpcio.header.h_priv))); name = Buf.buf_get_string(rpcio); Sch.ScheduleBlock([ function () { main.dns.dns_delete(rpcio.header.h_priv, name, function (_stat) { Buf.buf_init(rpcio); rpcio.header.h_status = _stat; }); }]); break; case Command.DNS_CREATE: /* * ----- * ncols(int16) * [colname(string)] #ncols * ----- * cs(capset) * ----- */ Io.log((log < 1) || 'hostsrv.DNS_CREATE ' + Net.Print.private(rpcio.header.h_priv)); ncols = Buf.buf_get_int16(rpcio); colnames = []; for (i = 0; i < ncols; i++) { colnames.push(Buf.buf_get_string(rpcio)); } Sch.ScheduleBlock([ function () { main.dns.dns_create(rpcio.header.h_priv, colnames, function (_stat, _cs) { Buf.buf_init(rpcio); rpcio.header.h_status = _stat; if (_stat == Status.STD_OK) { Cs.buf_put_capset(rpcio, _cs); } }); }]); break; case Command.DNS_LIST: /* * -------------- * rowoff(int16) * --------------- * next_row(int16) * ncols(int16) * nrows(int16) * colnames: [name(string)] #ncols * rows: [ * name(string) * time(int32) * [rights(int16)] #ncols * ] #nrows * -------------- */ Io.log((log < 1) || 'hostsrv.DNS_LIST ' + Net.Print.private(rpcio.header.h_priv)); off = Buf.buf_get_int16(rpcio); rpcio.pos = 0; Sch.ScheduleBlock([ function () { main.dns.dns_list(rpcio.header.h_priv, off, 1000, function (_stat, nrows, ncols, colnames, rows) { rpcio.header.h_status = _stat; Buf.buf_init(rpcio); if (_stat == Status.STD_OK) { Buf.buf_put_int16(rpcio, Dns.DNS_NOMOREROWS); Buf.buf_put_int16(rpcio, ncols); Buf.buf_put_int16(rpcio, nrows); /* ** Push the column names */ Array.iter(colnames, function (col) { Buf.buf_put_string(rpcio, col); }); /* ** Assumption: all rows fit in one transaction */ Array.iter(rows, function (row, index) { Buf.buf_put_string(rpcio, row[0]); Buf.buf_put_int32(rpcio, row[1]); Array.iter(row[2], function (col, index) { Dns.buf_put_rights(rpcio, col); }); }); } }); }]); break; case Command.DNS_SETLOOKUP: /* * ------------ * nrows(int16) * [ * dir(capset) * name(string) * ] #nrows * ------------ * [ * status(int16) * cs(capset) * ] #nrows * ------------ */ Io.log((log < 1) || 'hostsrv.DNS_SETLOOKUP ' + Net.Print.private(rpcio.header.h_priv)); var nrows = Buf.buf_get_int16(rpcio); var dirs=[]; for(i=0;i