From d0605e00e98fb47bbcc86b9f05b66a406537d94c Mon Sep 17 00:00:00 2001 From: sbosse Date: Mon, 21 Jul 2025 22:46:58 +0200 Subject: [PATCH] Mon 21 Jul 22:43:21 CEST 2025 --- js/dos/host.js | 637 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 637 insertions(+) create mode 100644 js/dos/host.js diff --git a/js/dos/host.js b/js/dos/host.js new file mode 100644 index 0000000..30ab20e --- /dev/null +++ b/js/dos/host.js @@ -0,0 +1,637 @@ +/** + ** ================================== + ** 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