jam/js/dos/dns_srv_rpc.js

1393 lines
50 KiB
JavaScript

/**
** ==============================
** OOOO O O OOOO
** O O 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
** ==============================
** 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-2016 BSSLAB
** $CREATED: 7/7/15 by sbosse.
** $VERSION: 1.2.4
**
** $INFO:
**
** DOS: DNS RPC Interface
**
** $ENDOFINFO
*/
/*
*********************
** PUBLIC INTERFACE
*********************
*/
"use strict";
var log = 0;
var util = Require('util');
var Io = Require('com/io');
var Net = Require('dos/network');
var Status = Net.Status;
var Command = Net.Command;
var Rights = Net.Rights;
var Std = Require('dos/std');
var Sch = Require('dos/scheduler');
var Buf = Require('dos/buf');
var Rpc = Require('dos/rpc');
var Fs = Require('fs');
var Comp = Require('com/compat');
var String = Comp.string;
var Array = Comp.array;
var Perv = Comp.pervasives;
var Hashtbl = Comp.hashtbl;
var Filename = Comp.filename;
var assert = Comp.assert;
var div = Comp.div;
var Afs = Require('dos/afs_srv_common');
var Afs_file_state = Afs.Afs_file_state;
var Afs_commit_flag= Afs.Afs_commit_flag;
var DnsInt = Require('dos/dns');
var Dns = Require('dos/dns_srv_common');
var Cs = Require('dos/capset');
/**
* @augments dns_server
* @augments dns_server_emb
* @see dns_server
* @see dns_server_emb
* @see dns_server_rpc~meth
* @constructor
*/
var dns_server_rpc = function() {
};
/**
* @typedef {{
* dns_lookup:dns_server.dns_lookup,
* dns_create:dns_server.dns_create,
* dns_append:dns_server.dns_append,
* dns_info:dns_server.dns_info,
* dns_stat:dns_server.dns_stat,
* dns_list:dns_server.dns_list,
* dns_setlookup:dns_server.dns_setlookup}} dns_server_emb~meth
*
/**
** DNS_LOOKUP:
** Traverse a path as far as possible, and return the resulting (restricted) capability
** set and the rest of the path.
*
* @param {private} priv
* @param {string} path
* @param {function((Status.STD_OK|*),capset|undefined,string)} callback
*/
dns_server_rpc.prototype.dns_lookup = function(priv,path,callback) {
var self=this;
//var log=1;
var path = Filename.path_normalize(path);
var path_rel = Filename.is_relative(path);
var pathl = String.split ('/', path);
var finished = false;
/*
** Avoid recursion. Visit each directory only once!
*/
var visited=[];
Io.log((log<1)||('Dns_server.dns_lookup '+Net.Print.private(priv)));
/*
** During we iterate over the path components, this
** rights value will be adjusted with the rights from the
** path components and used finally to restrict the
** capability set of the last path component
** resolved by this server.
*/
var have_rights = Rights.PRV_ALL_RIGHTS;
var rights = Net.prv_rights(priv);
/**
*
* @type {dns_dir|undefined}
*/
var dir = undefined;
/**
*
* @type {dns_dir|undefined}
*/
var dir_last = undefined;
/**
*
* @type {dns_row|undefined}
*/
var row_last = undefined;
var stat= Status.STD_OK;
var mask = rights & Rights.PRV_ALL_RIGHTS;
var colmask=0;
var cs;
Sch.ScheduleBlock([
/*
** The root directory for the iteration...
*/
function () {self.request_dir(priv,Rights.DNS_RGT_READ,function (_stat,_dir) {
Io.log((log<1)||('Dns_server.dns_lookup request_dir: '+Status.print(_stat)));
stat=_stat;
dir=_dir;
})},
function () {
var i;
if (stat!=Status.STD_OK) throw stat;
dir_last=dir;
visited.push(dir.dd_objnum);
Sch.ScheduleLoop(function(index){
return !finished && stat==Status.STD_OK;
},[
function () {
Array.match(pathl,function (hd,tl) {
pathl = tl;
dir_last = dir;
/*
** When checking the presence of column rights, only take
** the *actual* columns present into account,
** so do not use DNS_COLMASK here.
*/
var ncols = dir.dd_ncols;
var colrights=Dns.dns_col_bits[ncols]-1;
/*
** The columns mask for the calculation for the
** next lookup, if any,
** and the permission for the row lookup in the current
** directory.
** The current have_rights are logical
** and-ed with the current mask (limited to ncol bits).
*/
colmask= mask & have_rights & colrights;
Io.log((log<1)||('Dns_server.dns_lookup: rowname='+hd+' colrights='+colrights+' have_rights='+have_rights+' mask='+mask+' colmask='+colmask));
if (colmask==0) {
self.release_unmodified_dir(dir);
throw Status.STD_DENIED;
}
var row = self.search_row(dir,hd);
if (row==undefined) {
self.release_unmodified_dir(dir);
dir_last=undefined;
throw Status.STD_NOTFOUND;
}
row_last=row;
/*
** Calculate the new have_rights value.
** All the columns rights from the current row
** are logical or-ed,if, and only if the i-th
** bit in the current column mask is set.
** The i-th bit corresponds to the i-th rights column
** in the current row.
*/
var colmasknew=0;
var cols = row.dr_columns;
for(i=0;i<ncols;i++) {
var coli=cols[i];
var colbits = Dns.dns_col_bits[i];
/*
** If the i-th bit in column mask is set,
** add the i-th column of the row to
** the new column mask.
*/
if ((colmask & colbits) == colbits) {
colmasknew=colmasknew | coli;
}
}
have_rights = colmasknew;
Io.log((log<1)||('Dns_server.dns_lookup: new have_rights='+have_rights));
/*
** Get and acquire the next directory. If the next
** object belongs not to this server, exit.
*/
priv=self.check_dir(row.dr_capset);
Io.log((log<1)||('Dns_server.dns_lookup: stat='+Status.print(stat)+' newdir priv='+Net.Print.private(priv)));
if (priv !=undefined && !Array.member(visited,Net.prv_number(priv)))
self.request_dir(priv,0,function (_stat,_dir) {
stat=_stat;
dir=_dir;
});
else {
stat=Status.STD_OK;
finished=true;
}
}, function () {
dir_last = dir;
finished = true;
})
},
function () {
if (stat!=Status.STD_OK) finished=true;
if (!finished) {
/*
** The current column mask must be finally
** logical and-ed with the rights field
** of the next directory.
*/
colmask = colmask & Net.prv_rights(priv);
self.release_unmodified_dir(dir_last);
dir_last=undefined;
mask=colmask;
}
}
],[
function () {
Io.log((log<1)||('Dns_server.dns_lookup: finalize dir_last='+util.inspect(dir_last)));
Io.log((log<1)||('Dns_server.dns_lookup: finalize row_last='+util.inspect(row_last)));
self.release_unmodified_dir(dir_last);
dir_last=undefined;
/*
** Build the restricted object capability set
*/
if (row_last.dr_capset!=undefined)
self.restrict(row_last.dr_capset,have_rights,function (_stat,_cs) {
stat=_stat;
cs=_cs;
});
else {
stat=Status.STD_OBJBAD;
cs=Cs.emptycapset;
}
},
function () {
var path_rest=Filename.join(pathl);
callback(stat,cs,path_rest);
}
])
}
],function (e) {
if (dir_last!=undefined) self.release_unmodified_dir(dir_last);
if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_looukp'); }
if (typeof e == 'number') callback(e,undefined,''); else callback(Status.STD_SYSERR,undefined,'');
});
};
/** Create a new empty directory table entry.
*
* @param {private} priv
* @param {string []} colnames
* @param {function((Status.STD_OK|*),capset|undefined)} callback
*/
dns_server_rpc.prototype.dns_create = function(priv,colnames,callback) {
var self=this;
var ncols=colnames.length;
if (ncols > Dns.DNS_MAXCOLUMNS) {
callback(Status.STD_ARGBAD,undefined);
return;
}
var dir=undefined;
var new_dir=undefined;
var stat=Status.STD_UNKNOWN;
Sch.ScheduleBlock([
function () {
self.request_dir(priv,Rights.DNS_RGT_CREATE,function (_stat,_dir) {
stat=_stat;
dir=_dir;
})
},
function () {
if (stat != Status.STD_OK) throw stat;
self.release_unmodified_dir(dir);
self.alloc_dir(colnames,function (_stat,_dir) {
stat=_stat;
new_dir=_dir;
});
},
function () {
if (stat!=Status.STD_OK) throw Status.STD_NOSPACE;
var cs=self.capset_of_dir(new_dir,Rights.PRV_ALL_RIGHTS);
self.release_dir(new_dir,function (_stat) {
if(_stat==Status.STD_OK) callback(Status.STD_OK,cs);
else callback(_stat,undefined);
});
}
],function (e) {
if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_create');}
if (typeof e == 'number') callback(e,undefined); else callback(Status.STD_SYSERR,undefined);
})
};
/** Append a row to a directory. The name, right masks (cols), and initial
** capability set must be specified.
*
* @param priv
* @param name
* @param {number []} cols
* @param {capset} cs
* @param {function((Status.STD_OK|*))} callback
*/
dns_server_rpc.prototype.dns_append = function(priv,name,cols,cs,callback) {
var self=this;
var ncols=cols.length;
var dir=undefined;
var stat=Status.STD_UNKNOWN;
if (ncols > Dns.DNS_MAXCOLUMNS || String.equal(name,'')) {
callback(Status.STD_ARGBAD);
return;
}
Sch.ScheduleBlock([
function () {
Io.log((log<2)||('Dns_server.dns_append: request_dir '+Net.Print.private(priv)));
self.request_dir(priv,Rights.DNS_RGT_MODIFY,function (_stat,_dir) {
Io.log((log<2)||('Dns_server.dns_append: request_dir returns '+Status.print(_stat)));
stat=_stat;
dir=_dir;
})
},
function () {
if (stat != Status.STD_OK) throw stat;
var row = self.search_row(dir,name);
if (row!=undefined) throw Status.STD_EXISTS;
var new_row = Dns.Dns_row(name,self.time(),cols,cs);
self.append_row(dir,new_row);
self.release_dir(dir,function (_stat) {
callback(_stat);
});
}
],function (e) {
if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_append');}
if (typeof e == 'number') callback(e); else callback(Status.STD_SYSERR);
})
};
/** Rename a row of a directory.
*
* @param priv
* @param oldname
* @param newname
* @param {function((Status.STD_OK|*))} callback
*/
dns_server_rpc.prototype.dns_rename = function(priv,oldname,newname,callback) {
var self=this;
var dir=undefined;
var stat=Status.STD_UNKNOWN;
if (String.equal(oldname,'') || String.equal(newname,'')) {
callback(Status.STD_ARGBAD);
return;
}
Sch.ScheduleBlock([
function () {
self.request_dir(priv,Rights.DNS_RGT_MODIFY,function (_stat,_dir) {
stat=_stat;
dir=_dir;
})
},
function () {
if (stat != Status.STD_OK) {
throw stat;
}
stat=self.rename_row(dir,oldname,newname);
self.release_dir(dir,function (_stat) {
if (stat==Status.STD_OK) callback(_stat); else callback(stat);
});
}
],function (e) {
if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_rename');}
if (typeof e == 'number') callback(e); else callback(Status.STD_SYSERR);
})
};
/** Change columns rights of a row in a directory.
*
* @param priv
* @param rowname
* @param {number []} cols
* @param {function((Status.STD_OK|*))} callback
*/
dns_server_rpc.prototype.dns_chmod = function(priv,rowname,cols,callback) {
var self=this;
var dir=undefined;
var row=undefined;
var ncols=cols.length;
var stat=Status.STD_UNKNOWN;
if (String.equal(rowname,'') || Array.empty(cols)) {
callback(Status.STD_ARGBAD);
return;
}
Sch.ScheduleBlock([
function () {
self.request_dir(priv,Rights.DNS_RGT_MODIFY,function (_stat,_dir) {
stat=_stat;
dir=_dir;
})
},
function () {
if (stat != Status.STD_OK) {
throw stat;
}
row=self.search_row(dir,rowname);
if (row==undefined) stat=Status.STD_NOTFOUND; else {
stat=Status.STD_OK;
var maxcols=Perv.min(Array.length(row.dr_columns),ncols);
for(var i=0;i<maxcols;i++) {
row.dr_columns[i]=cols[i];
}
}
self.release_dir(dir,function (_stat) {
if (stat==Status.STD_OK) callback(_stat); else callback(stat);
});
}
],function (e) {
if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_chmod');}
if (typeof e == 'number') callback(e); else callback(Status.STD_SYSERR);
})
};
/** Rename a row of a directory.
*
* @param priv
* @param name
* @param newcs
* @param {function((Status.STD_OK|*))} callback
*/
dns_server_rpc.prototype.dns_replace = function(priv,name,newcs,callback) {
var self=this;
var dir=undefined;
var stat=Status.STD_UNKNOWN;
if (String.equal(name,'')) {
callback(Status.STD_ARGBAD);
return;
}
Sch.ScheduleBlock([
function () {
self.request_dir(priv,Rights.DNS_RGT_MODIFY,function (_stat,_dir) {
stat=_stat;
dir=_dir;
})
},
function () {
if (stat != Status.STD_OK) {
throw stat;
}
stat=self.replace_row(dir,name,cs);
self.release_dir(dir,function (_stat) {
if (stat==Status.STD_OK) callback(_stat); else callback(stat);
});
}
],function (e) {
if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_replace');}
if (typeof e == 'number') callback(e); else callback(Status.STD_SYSERR);
})
};
/** Delete a row of a directory.
*
* @param priv
* @param name
* @param {function((Status.STD_OK|*))} callback
*/
dns_server_rpc.prototype.dns_delete = function(priv,name,callback) {
var self=this;
var dir=undefined;
var stat=Status.STD_UNKNOWN;
if (String.equal(name,'')) {
callback(Status.STD_ARGBAD);
return;
}
Sch.ScheduleBlock([
function () {
self.request_dir(priv,Rights.DNS_RGT_MODIFY,function (_stat,_dir) {
stat=_stat;
dir=_dir;
})
},
function () {
if (stat != Status.STD_OK) {
throw stat;
}
stat=self.delete_row(dir,name);
self.release_dir(dir,function (_stat) {
if (stat==Status.STD_OK) callback(_stat); else callback(stat);
});
}
],function (e) {
if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_delete');}
if (typeof e == 'number') callback(e); else callback(Status.STD_SYSERR);
})
};
/** Delete a directory and destroy AFS objects (directory table).
*
* @param priv
* @param {function((Status.STD_OK|*))} callback
*/
dns_server_rpc.prototype.dns_delete_dir = function(priv,callback) {
var self=this;
var dir=undefined;
var stat=Status.STD_UNKNOWN;
Sch.ScheduleBlock([
function () {
self.request_dir(priv,Rights.DNS_RGT_DELETE,function (_stat,_dir) {
stat=_stat;
dir=_dir;
})
},
function () {
if (stat != Status.STD_OK) {
throw stat;
}
self.delete_dir(dir, function (_stat) {
stat=_stat;
});
},
function () {
callback(stat);
}
],function (e) {
if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_delete_dir');}
if (typeof e == 'number') callback(e); else callback(Status.STD_SYSERR);
})
};
/** Touch a directory.
*
* @param priv
* @param {function((Status.STD_OK|*))} callback
*/
dns_server_rpc.prototype.dns_touch = function(priv,callback) {
var self=this,
dir=undefined,
stat=Status.STD_UNKNOWN;
Sch.ScheduleBlock([
function () {
self.request_dir(priv,Rights.DNS_RGT_MODIFY,function (_stat,_dir) {
stat=_stat;
dir=_dir;
})
},
function () {
if (stat != Status.STD_OK) {
throw stat;
}
self.touch(dir,function (_stat) {stat=_stat});
self.release_dir(dir,function (_stat){
if (stat==Status.STD_OK) callback(_stat); else callback(stat);
});
}
],function (e) {
if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_touch');}
if (typeof e == 'number') callback(e); else callback(Status.STD_SYSERR);
})
};
/** Age all objects from this server. Destroy objects with live time = 0.
** Only allowed with the super capability (obj = 0).
*
* @param priv
* @param {function((Status.STD_OK|*))} callback
*/
dns_server_rpc.prototype.dns_age = function(priv,callback) {
var self=this;
var dir=undefined;
var stat=Status.STD_UNKNOWN;
var obj = Net.prv_number(priv);
var rights = Net.prv_rights(priv);
Sch.ScheduleBlock([
function () {
self.request_dir(priv,Rights.DNS_RGT_MODIFY,function (_stat,_dir) {
stat=_stat;
dir=_dir;
})
},
function () {
if (stat != Status.STD_OK) {
throw stat;
}
self.age(function (_stat) {
stat=_stat;
});
},
function () {
self.release_dir(dir,function (_stat) {
if (stat==Status.STD_OK) callback(_stat); else callback(stat);
});
}
],function (e) {
if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_age');}
if (typeof e == 'number') callback(e); else callback(Status.STD_SYSERR);
})
};
/**
** Restrict dir capability
*
* @param {private} priv
* @param {number} mask
* @param {function((Status.STD_OK|*),(privat|undefined))} callback return status
*/
dns_server_rpc.prototype.dns_restrict =function (priv,mask,callback) {
var self = this;
var privres=undefined;
var stat = Status.STD_UNKNOWN;
var dir = undefined;
var obj = Net.prv_number(priv);
var rights = Net.prv_rights(priv);
Sch.ScheduleBlock([
function () {
self.acquire_dir(obj,function (_stat,_dir) {
stat=_stat;
dir=_dir;
});
},
function () {
if (stat != Status.STD_OK) {
throw stat;
}
if (Net.prv_decode(priv, dir.dd_random) == false) {
throw Status.STD_DENIED;
}
stat=Status.STD_OK;
privres=Net.prv_encode(obj,mask,dir.dd_random);
self.release_unmodified_dir(dir);
dir=undefined;
callback(stat,privres);
}
],function (e) {
if (dir!=undefined) self.release_unmodified_dir(dir);
if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.afs_restrict');}
if (typeof e == 'number') callback(e,undefined); else callback(Status.STD_SYSERR,undefined);
});
};
/** Get information of a directory
*
* @param priv
* @param callback
*/
dns_server_rpc.prototype.dns_info = function(priv,callback) {
var self=this;
var dir=undefined;
var stat=Status.STD_UNKNOWN;
var rights = Net.prv_rights(priv);
Sch.ScheduleBlock([
function () {
self.request_dir(priv,0,function (_stat,_dir) {
stat=_stat;
dir=_dir;
})
},
function () {
if (stat==Status.STD_OK)
self.release_dir(dir,function (_stat) {
stat=_stat;
});
else throw stat;
},
function () {
if (stat != Status.STD_OK) throw stat;
var str='/';
if ((rights & Rights.DNS_RGT_DELETE) == Rights.DNS_RGT_DELETE) str=str+'D'; else str=str+'-';
if ((rights & Rights.DNS_RGT_DELETE) == Rights.DNS_RGT_DELETE) str=str+'M'; else str=str+'-';
if ((rights & Rights.DNS_RGT_CREATE) == Rights.DNS_RGT_CREATE) str=str+'C'; else str=str+'-';
if ((rights & Rights.DNS_RGT_READ) == Rights.DNS_RGT_READ) str=str+'R'; else str=str+'-';
if ((rights & Rights.DNS_RGT_COL1) == Rights.DNS_RGT_COL1) str=str+'1'; else str=str+'-';
if ((rights & Rights.DNS_RGT_COL2) == Rights.DNS_RGT_COL2) str=str+'2'; else str=str+'-';
if ((rights & Rights.DNS_RGT_COL3) == Rights.DNS_RGT_COL3) str=str+'3'; else str=str+'-';
if ((rights & Rights.DNS_RGT_COL4) == Rights.DNS_RGT_COL4) str=str+'4'; else str=str+'-';
callback(stat,str);
}
],function (e) {
if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_info');}
if (typeof e == 'number') callback(e,''); else callback(Status.STD_SYSERR,'');
})
};
/** Get information of server
*
* @param priv
* @param callback
*/
dns_server_rpc.prototype.dns_stat = function(priv,callback) {
var self=this;
var dir=undefined;
var stat=Status.STD_UNKNOWN;
var rights = Net.prv_rights(priv);
Sch.ScheduleBlock([
function () {
self.request_dir(priv,0,function (_stat,_dir) {
stat=_stat;
dir=_dir;
})
},
function () {
if (stat==Status.STD_OK)
self.release_dir(dir,function (_stat) {
stat=_stat;
});
else
throw stat;
},
function () {
if (stat != Status.STD_OK) throw stat;
var str=self.stat();
callback(stat,str);
}
],function (e) {
if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_stat');}
if (typeof e == 'number') callback(e,''); else callback(Status.STD_SYSERR,'');
})
};
/** List a directory. Returns a flattened representation of the number of
** columns, the number of rows, the names of the columns, the names of the
** rows and the right masks.
** Return status,
** the number of total rows and columns,
** the col names list,
** the (dr_name,dr_time,dr_columns) list starting with firstrow.
* @param priv
* @param firstrow
* @param maxrows
* @param {function((Status.STD_OK|*),number,number,string [], *[])} callback (stat,nrows,ncols,colnames,rowlist)
*/
dns_server_rpc.prototype.dns_list = function(priv,firstrow,maxrows,callback) {
var self=this;
var dir=undefined;
var stat=Status.STD_UNKNOWN;
Io.log((log<1)||('Dns_server.dns_list '+Net.Print.private(priv)));
if (firstrow < 0) {
callback(Status.STD_ARGBAD,0,0,[],[]);
return;
}
Sch.ScheduleBlock([
function () {
self.request_dir(priv,Rights.DNS_RGT_READ,function (_stat,_dir) {
stat=_stat;
dir=_dir;
})
},
function () {
var i,j;
if (stat != Status.STD_OK) throw stat;
var rows = dir.dd_rows;
var ncols = dir.dd_ncols;
var nrows = Perv.min(maxrows,dir.dd_nrows-firstrow);
var list = [];
for(i=firstrow;i<(firstrow+nrows);i++) {
var row = dir.dd_rows[i];
var cols = row.dr_columns;
if (cols.length == ncols)
list.push([row.dr_name,row.dr_time,cols]);
}
self.release_dir(dir,function (_stat) {
callback(_stat,nrows,ncols,dir.dd_colnames,list);
});
}
],function (e) {
if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_list');}
if (typeof e == 'number') callback(e,0,0,[],[]); else callback(Status.STD_SYSERR,0,0,[],[]);
})
};
/**
** Lookup row names in a set of directories. The 'dirs' argument
** is a list of (dir_cs,row name) tuples. Return the resolved rows list with
** (status,capability set). Always, in the case of failed partial look-ups, too,
** all directory entries must be looked up.
*
*
* @param {private} priv required for authorization only
* @param {* []} dirs (capset,string) []
* @param {function((Status.STD_OK|*),* [])} callback
*/
dns_server_rpc.prototype.dns_setlookup = function(priv,dirs,callback) {
var self=this;
var stat=Status.STD_UNKNOWN;
var dir;
var lookup;
var skip=false;
var priv=priv;
Sch.ScheduleBlock([
function () {
self.request_dir(priv,Rights.DNS_RGT_READ,function (_stat,_dir) {
stat=_stat;
dir=_dir;
})
},
function () {
if (stat != Status.STD_OK) throw stat;
self.release_dir(dir, function (_stat) {
stat = _stat;
});
},
function () {
var nrows=dirs.length;
var list=[];
var index=0;
Sch.ScheduleLoop(function() {
return index<nrows;
},[
function () {
lookup=dirs[index];
var cs=lookup[0];
priv = self.check_dir(cs);
if (priv != undefined) {
self.request_dir(priv,0,function (_stat,_dir) {
dir=_dir;
stat=_stat;
})
} else {
stat=Status.STD_NOTFOUND;
dir=undefined;
}
},
function () {
var i;
if(stat==Status.STD_OK) {
var name=lookup[1];
var row = self.search_row(dir,name);
if (row != undefined) {
/*
** calculate the rights mask
*/
var colmask = Net.prv_rights(priv);
var have_rights = 0;
var ncols = dir.dd_ncols;
var cols = row.dr_columns;
for(i=0;i<ncols;i++) {
if ((colmask & Dns.dns_col_bits[i]) == Dns.dns_col_bits[i])
have_rights = have_rights | cols[i];
}
self.restrict(dir,have_rights,function (_cs) {
// Assuming non-blocking---
list.push(Status.STD_OK,_cs);
});
} else
list.push(Status.STD_NOTFOUND,undefined);
self.release_dir(dir,function (_stat) {
stat=_stat;
});
} else {
list.push(stat,undefined);
}
}
],[
function () {
callback(Status.STD_OK,list);
}
]);
}
],function (e) {
if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_setlooukp');}
if (typeof e == 'number') callback(e,[]); else callback(Status.STD_SYSERR,[]);
})
};
/** DNS Exit Request
* @param {privat} [priv]
*
* @returns {(Status.STD_OK|*)}
*/
dns_server_rpc.prototype.dns_exit =function (priv) {
var self=this;
var stat=Status.STD_OK;
if (priv!=undefined) {
var obj = Net.prv_number(priv);
var rights = Net.prv_rights(priv);
if (obj!=0 || !Net.prv_decode(priv,self.dns_super.dns_checkfield)) return Status.STD_DENIED;
}
stat=self.exit();
return stat;
};
/** DNS Start the RPC server
*
* @param {number} index
* @param {taskscheduler} scheduler
*/
dns_server_rpc.prototype.dns_start_server = function (index,scheduler) {
var dns = this;
var server = function () {
// Server
var self = this;
var rpc = dns.rpc;
var port = dns.dns_super.dns_getport;
var router = rpc.router;
var rpcio = router.pkt_get();
var dying=false;
this.init = function () {
Io.out('[DNS'+index+'] Starting RPC Server with public port '+Net.Print.port(dns.dns_super.dns_putport));
router.add_port(port);
};
this.request = function () {
Io.log((log<10)||('[DNS'+index+'] request'));
rpcio.init();
rpcio.operation = Rpc.Operation.GETREQ;
rpcio.header.h_port = port;
rpcio.header.h_status=undefined;
rpcio.header.h_command=undefined;
rpcio.header.h_priv=undefined;
rpc.getreq(rpcio);
};
this.service = function () {
var used, i, name, path, cs, rights, ncols, cols, colnames, found, mask, priv;
var ss,sc,stat,info,size,flag,off,buf;
buf=Buf.Buffer();
Io.log((log<1)||('[DNS'+index+'] service: '+Net.Print.header(rpcio.header)));
assert((rpcio.index!=-1) ||'RPCIO invalid');
switch (rpcio.header.h_command) {
/*********************
** DNS Calls
**********************/
case Command.DNS_APPEND:
/*
* ------------
* name:string
* obj:capset
* ncols:number
* cols: rights []
* ------------
* ------------
*/
Io.log((log < 1) || ('Dns_srv_rpc.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(DnsInt.buf_get_rights(rpcio));
}
if (log > 0) {
Io.inspect(name);
Io.inspect(cs);
Io.inspect(cols);
}
Sch.ScheduleBlock([
function () {
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) || ('Dns_srv_rpc.DNS_APPEND returns: ' + Net.Status.print(_stat)));
});
}]);
Io.log((log < 1) || ('Dns_srv_rpc.DNS_APPEND passes through'));
break;
case Command.DNS_LOOKUP:
Io.log((log < 1) || ('dns_srv_rpc.DNS_LOOKUP ' + Net.Print.private(rpcio.header.h_priv)));
path = Buf.buf_get_string(rpcio);
Sch.ScheduleBlock([
function () {
dns.dns_lookup(rpcio.header.h_priv, path, function (_stat, _cs, _path) {
Io.log((log < 1) || ('Dns_srv_rpc.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);
};
rpcio.header.h_status = _stat;
});
}]);
Io.log((log < 1) || ('Dns_srv_rpc.DNS_LOOKUP passes through'));
break;
case Command.DNS_RENAME:
/*
* ------------
* oldname:string
* newname:string
* ------------
* ------------
*/
Io.log((log < 1) || ('Dns_srv_rpc.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 () {
dns.dns_rename(rpcio.header.h_priv, name, newname, function (_stat) {
Buf.buf_init(rpcio);
rpcio.header.h_status = _stat;
});
}]);
break;
case Command.DNS_REPLACE:
/*
* ------------
* name:string
* newcs:capset
* ------------
* ------------
*/
Io.log((log < 1) || ('Dns_srv_rpc.DNS_REPLACE ' + Net.Print.private(rpcio.header.h_priv)));
name = Buf.buf_get_string(rpcio);
var newcs = Cs.buf_get_capset(rpcio);
Sch.ScheduleBlock([
function () {
dns.dns_replace(rpcio.header.h_priv, name, newcs, function (_stat) {
Buf.buf_init(rpcio);
rpcio.header.h_status = _stat;
});
}]);
break;
case Command.DNS_DELETE:
/*
* ------------
* rowname:string
* ------------
* ------------
*/
Io.log((log < 1) || ('Dns_srv_rpc.DNS_DELETE ' + Net.Print.private(rpcio.header.h_priv)));
name = Buf.buf_get_string(rpcio);
Sch.ScheduleBlock([
function () {
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) || ('Dns_srv_rpc.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 () {
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_CHMOD:
/*
* -----
* rowname(string)
* ncols(int16)
* cols: rights []
* -----
* -----
*/
Io.log((log < 1) || ('Dns_srv_rpc.DNS_CHMOD ' + Net.Print.private(rpcio.header.h_priv)));
ncols = Buf.buf_get_int16(rpcio);
cols = [];
for (i = 0; i < ncols; i++) {
cols.push(DnsInt.buf_get_rights(rpcio));
}
Sch.ScheduleBlock([
function () {
dns.dns_chmod(rpcio.header.h_priv, cols, function (_stat) {
Buf.buf_init(rpcio);
rpcio.header.h_status = _stat;
});
}]);
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) || ('Dns_srv_rpc.DNS_LIST ' + Net.Print.private(rpcio.header.h_priv)));
off = Buf.buf_get_int16(rpcio);
rpcio.pos = 0;
Sch.ScheduleBlock([
function () {
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, DnsInt.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
*/
Io.log((log < 1) || 'dnssrv.DNS_LIST #rows=' +rows.length);
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) {
DnsInt.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) || ('Dns_srv_rpc.DNS_SETLOOKUP ' + Net.Print.private(rpcio.header.h_priv)));
var nrows = Buf.buf_get_int16(rpcio);
var dirs=[];
for(i=0;i<nrows;i++) {
cs=Cs.buf_get_capset(rpcio);
name=Buf.buf_get_string(rpcio);
dirs.push([cs,name]);
}
Sch.ScheduleBlock([
function () {
dns.dns_setlookup(rpcio.header.h_priv, dirs, function (_stat, _rows) {
rpcio.header.h_status = _stat;
Buf.buf_init(rpcio);
Array.iter(_rows, function (statcs) {
Buf.buf_put_int16(statcs[0]);
Cs.buf_put_capset(statcs[1]);
});
})
}
]);
break;
case Command.DNS_GETDEFAFS:
/*
* -------------
* -------------
* cap(capability)
* -------------
*/
Io.log((log < 1) || ('Dns_srv_rpc.DNS_GETDEFAFS: ' + Net.Print.private(rpcio.header.h_priv)));
Buf.buf_init(rpcio);
Sch.ScheduleBlock([
function () {
/*
** Return the default file server capability.
*/
dns.std.std_restrict(dns.dns_super.dns_fs.fs_cap[dns.dns_super.dns_fs.fs_default], Rights.PRV_ALL_RIGHTS,
function (_stat, _cap) {
if (_stat == Status.STD_OK) {
Buf.buf_put_cap(rpcio, _cap);
}
rpcio.header.h_status = _stat;
});
}
]);
break;
case Command.STD_DESTROY:
/*
** +---
* |===
* +---
*/
Buf.buf_init(rpcio);
Sch.ScheduleBlock([
function () {
dns.dns_delete_dir(rpcio.header.h_priv, function (_stat) {
rpcio.header.h_status = _stat;
});
}]);
break;
case Command.STD_INFO:
/*
** +---
* |===
* | info(string)
* +---
*/
Buf.buf_init(rpcio);
Sch.ScheduleBlock([
function () {
dns.dns_info(rpcio.header.h_priv, function (_stat, _info) {
rpcio.header.h_status = _stat;
if (_stat == Status.STD_OK) Buf.buf_put_string(rpcio, _info);
});
}]);
break;
case Command.STD_STATUS:
/*
** +---
* |===
* | info(string)
* +---
*/
Buf.buf_init(rpcio);
Sch.ScheduleBlock([
function () {
dns.dns_stat(rpcio.header.h_priv, function (_stat, _info) {
rpcio.header.h_status = _stat;
if (_stat == Status.STD_OK) Buf.buf_put_string(rpcio, _info);
});
}]);
break;
case Command.STD_TOUCH:
/*
** +---
* |===
* +---
*/
Buf.buf_init(rpcio);
Sch.ScheduleBlock([
function () {
dns.dns_touch(rpcio.header.h_priv, function (_stat) {
rpcio.header.h_status = _stat;
});
}]);
break;
case Command.STD_AGE:
/*
** +---
* |===
* +---
*/
Buf.buf_init(rpcio);
Sch.ScheduleBlock([
function () {
dns.dns_age(rpcio.header.h_priv, function (_stat) {
rpcio.header.h_status = _stat;
});
}]);
break;
case Command.STD_RESTRICT:
/*
* ----------
* mask (int16)
* ----------
* priv (privat)
* ----------
*/
mask = Buf.buf_get_int16(rpcio);
Buf.buf_init(rpcio);
Sch.ScheduleBlock([
function () {
dns.dns_restrict(rpcio.header.h_priv, mask, function (_stat, _priv) {
rpcio.header.h_status = _stat;
if (_stat == Status.STD_OK) Buf.buf_put_priv(rpcio, _priv);
});
}]);
break;
case Command.STD_EXIT:
/*
** +---
* |===
* +---
*/
Buf.buf_init(rpcio);
stat=dns.dns_exit(rpcio.header.h_priv);
rpcio.header.h_status=stat;
if (stat==Status.STD_OK) dying=true;
break;
default:
rpcio.header.h_status=Status.STD_COMBAD;
Buf.buf_init(rpcio);
}
};
this.reply = function () {
Io.log((log<1)||('[DNS'+index+'] reply: '+Net.Print.header(rpcio.header)));
rpc.putrep(rpcio);
assert((rpcio.index!=-1) ||'RPCIO invalid');
};
this.onexit = function () {
// TODO exit context?
};
this.transitions = function () {
var trans;
trans =
[
[undefined, this.init, function (self) {return true}],
[this.init, this.request, function (self) {return true}],
[this.request, this.service, function (self) {return !self.context.blocked}],
[this.service, this.reply, function (self) {return true}],
[this.reply, this.request, function (self) {return !dying}],
[this.reply, this.onexit, function (self) {return dying}]
];
return trans;
};
this.context = Sch.TaskContext('DNS'+index+' '+Net.Print.port(port), self);
};
var proc1 = new server();
scheduler.Add(proc1.context);
};
module.exports = {
dns_server_rpc:dns_server_rpc
};