13 var cluster = require(
'cluster');
14 var numCPUs = require(
"os").cpus().length;
15 var fs = require(
'fs');
16 var path_module = require(
'path');
17 var module_holder = {};
21 var child_process = require(
'child_process');
23 var util = require(
'util');
24 var log_file = fs.createWriteStream(
'/tmp/server.' + process.env[
"USER"] +
'.log', { flags:
'a' });
25 var log_stdout = process.stdout;
27 var getversion =
function () {
28 console.log(
"Getting Server Version");
29 if (fs.existsSync(
"./version.txt")) {
30 console.log(
"Reading Server Version from File");
31 return "" + fs.readFileSync(
"./version.txt");
34 child_process.exec(
"git describe --tags",
function (error, stdout, stderr) {
35 version = stdout.trim() +
"-Git";
36 child_process.exec(
"git status --porcelain",
function (error, stdout) {
37 if (stdout.length > 0) {
44 var version = getversion();
50 hostname:
"localhost",
53 function loadConfig() {
54 if (fs.existsSync(
"config.json")) {
55 config = JSON.parse(fs.readFileSync(
"config.json"));
57 fs.writeFileSync(
"config.json", JSON.stringify(config));
60 if (process.env.ARTDAQDEMO_BASE_PORT) {
61 config.baseport = parseInt(process.env[
"ARTDAQDEMO_BASE_PORT"]) + config.portOffset;
64 if (config.hostname ===
"localhost" && cluster.isMaster) {
65 console.log(
"Listening only on localhost. To listen on a different address, set \"hostname\" in config.json.\nUse \"0.0.0.0\" to listen on all interfaces.");
71 console.log =
function (d) {
72 log_file.write(util.format(d) +
'\n');
73 log_stdout.write(util.format(d) +
'\n');
76 function LoadCerts(path) {
78 var files = fs.readdirSync(path);
79 for (var i = 0; i < files.length; i++) {
80 if (files[i].search(
".pem") > 0 || files[i].search(
".crt") > 0) {
81 output.push(fs.readFileSync(path +
"/" + files[i]));
87 function GetCILogonCRL(path) {
89 var file = fs.createWriteStream(path_module.join(path,
"cilogon-basic.r0"));
90 http.get(
"http://crl-cilogon.ncsa-security.net/cilogon-basic.r0",
function (res) { res.pipe(file); });
91 var file2 = fs.createWriteStream(path_module.join(path,
"cilogon-basic.crl"));
92 http.get(
"http://crl-cilogon.ncsa-security.net/cilogon-basic.crl",
function (res) { res.pipe(file2); });
95 function LoadCRLs(path) {
98 var files = fs.readdirSync(path);
99 for (var i = 0; i < files.length; i++) {
100 if (files[i].search(
".r0") > 0 || files[i].search(
".crl") > 0) {
101 output.push(fs.readFileSync(path +
"/" + files[i]));
109 function LoadModules(path) {
110 var stat = fs.lstatSync(path);
111 if (stat.isDirectory()) {
113 var files = fs.readdirSync(path);
114 var f, l = files.length;
115 for (var i = 0; i < l; i++) {
116 f = path_module.join(path, files[i]);
119 }
else if (path.search(
"_module.js") > 0 && path.search(
"js~") < 0) {
120 for (var im in config.ignored_modules) {
121 if (config.ignored_modules.hasOwnProperty(im) && path.search(config.ignored_modules[im]) >= 0) {
125 console.log(
"Loading Submodule " + path);
128 require(path)(module_holder);
129 console.log(
"Initialized Submodule " + path);
132 var DIR = path_module.join(__dirname,
"modules");
137 if (cluster.isMaster) {
139 function messageHandler(msg) {
143 console.log(
"Depreciated message recieved!");
146 if (msg[
"name"] ===
"request") {
147 console.log(
"Request for Worker Data received");
148 Object.keys(cluster.workers).forEach(
function (
id) {
149 cluster.workers[id].send(workerData);
152 else if (!msg[
"target"]) {
153 console.log(
"Depreciated message recieved!");
160 if (!msg[
"method"]) {
162 workerData[msg.name][msg.target] = msg.data;
164 else if (msg[
"method"] ===
"push") {
166 workerData[msg.name][msg.target].push(msg.data);
168 Object.keys(cluster.workers).forEach(
function (
id) {
169 cluster.workers[id].send({ name: msg.name, target: msg.target, data: workerData[msg.name][msg.target] });
176 for (var name in module_holder) {
177 if (module_holder.hasOwnProperty(name)) {
179 module_holder[name].MasterInitFunction(workerData,config.module_config[name]);
183 module_holder[name].on(
"message", messageHandler);
188 cluster.on(
'online',
function (worker) {
189 worker.send(workerData);
193 for (var i = 0; i < numCPUs; i++) {
195 var worker = cluster.fork();
196 worker.on(
'message', messageHandler);
200 cluster.on(
"exit",
function () {
201 var newWorker = cluster.fork();
202 newWorker.on(
'message', messageHandler);
206 var https = require(
'https');
207 var http = require(
'http');
208 var url = require(
'url');
209 var qs = require(
'querystring');
211 function workerMessageHandler(msg) {
216 for (var name in module_holder) {
217 if (module_holder.hasOwnProperty(name)) {
219 module_holder[name].Update(workerData[name]);
226 if (!msg[
"target"]) {
228 workerData[msg.name] = msg.data;
231 workerData[msg.name][msg.target] = msg.data;
234 module_holder[msg.name].Update(workerData[msg.name]);
239 process.send({ name:
'request' });
240 process.on(
'message', workerMessageHandler);
242 for (var name in module_holder) {
243 if (module_holder.hasOwnProperty(name)) {
244 module_holder[name].on(
"message",
function (data) {
250 module_holder[name].WorkerInitFunction(workerData);
257 function serve(req, res, readOnly, username) {
260 var pathname = url.parse(req.url,
true).pathname;
261 if (pathname[0] ===
'/') {
262 pathname = pathname.substr(1);
265 var moduleName = pathname.substr(0, pathname.indexOf(
'/'));
266 var functionName = pathname.substr(pathname.indexOf(
'/') + 1);
267 if (workerData[
"serverbase"][req.connection.remoteAddress]) {
268 var clientInfo = workerData[
"serverbase"][req.connection.remoteAddress];
269 if (clientInfo.lastModuleName === moduleName && clientInfo.lastFunctionName === functionName) {
270 if (clientInfo.lastReqTime >= Date.now() - 500) {
271 console.log(
"Flood control active, denying request!");
272 res.writeHeader(200, {
'Content-Type':
'text/html' });
273 res.end(
"{\"Success\": true}");
278 process.send({name:
"serverbase", target:req.connection.remoteAddress, data: {
279 lastModuleName: moduleName,
280 lastFunctionName: functionName,
281 lastReqTime: Date.now()
286 require(
'dns').reverse(req.connection.remoteAddress, function (err, domains) {
289 if (functionName.search(
".min.map") < 0) {
291 console.log(
"Received " + req.method +
", Client: " + domains[0] +
" [" + req.connection.remoteAddress +
"], PID: " + process.pid +
" Module: " + moduleName +
", function: " + functionName);
296 if (functionName.search(
".min.map") < 0) {
298 console.log(
"Received " + req.method +
", Client: " + req.connection.remoteAddress +
", PID: " + process.pid +
" Module: " + moduleName +
", function: " + functionName);
304 if (functionName.search(
"GET_ServerVersion") >= 0) {
305 res.setHeader(
"Content-Type",
"text/plain");
306 res.statusCode = 200;
310 if (moduleName ===
".." || functionName.search(
"\\.\\.") >= 0) {
311 console.log(
"Possible break-in attempt!: " + pathname);
312 res.writeHeader(404, {
'Content-Type':
'text/html' });
316 res.setHeader(
"Content-Type",
"application/json");
317 res.statusCode = 200;
324 if (req.method ===
"POST") {
328 req.on(
'data',
function (data) {
332 req.on(
'end',
function () {
336 post = JSON.parse(body);
338 post = qs.parse(body);
342 if (module_holder[moduleName] != null) {
343 console.log(
"Module " + moduleName +
", function " + functionName +
" accessType " + (readOnly ?
"RO" :
"RW"));
345 module_holder[moduleName].removeAllListeners(
'data').on(
'data',
function (data) {
348 module_holder[moduleName].removeAllListeners(
'end').on(
'end',
function (data) {
350 res.end(JSON.stringify(dataTemp + data));
352 module_holder[moduleName].removeAllListeners(
'stream').on(
'stream',
function (str, hdrs, code) {
353 console.log(
"Stream message received: " + hdrs +
" CODE: " + code);
354 res.writeHead(code, hdrs);
360 data = module_holder[moduleName][
"RO_" + functionName](post, workerData[moduleName]);
363 res.end(JSON.stringify(data));
366 if (err instanceof TypeError) {
368 res.end(JSON.stringify(null));
373 data = module_holder[moduleName][
"RW_" + functionName](post, workerData[moduleName]);
376 res.end(JSON.stringify(data));
379 console.log(
"Error caught; text: " + JSON.stringify(err2));
380 if (err2 instanceof TypeError) {
382 data = module_holder[moduleName][
"RO_" + functionName](post, workerData[moduleName]);
385 res.end(JSON.stringify(data));
391 console.log(
"Unknown POST URL: " + pathname);
392 res.writeHeader(404, {
'Content-Type':
'text/html' });
398 if (req.method ===
"GET" || req.method ===
"HEAD") {
400 if (functionName.indexOf(
".") > 0) {
402 var ext = functionName.substr(functionName.lastIndexOf(
".") + 1);
403 res.setHeader(
"Content-Type",
"text/plain");
407 res.setHeader(
"Content-Type",
"text/css");
410 res.setHeader(
"Content-Type",
"text/javascript");
413 res.setHeader(
"Content-Type",
"text/html");
416 res.setHeader(
"Content-Type",
"text/html");
419 res.setHeader(
"Content-Type",
"application/root+root.exe");
422 res.setHeader(
"Content-Type",
"image/gif");
426 var filename =
"./modules/" + moduleName +
"/client/" + functionName;
427 if (functionName.search(
"favicon.ico") >= 0) {
428 filename =
"./modules/base/client/images/favicon.ico";
430 if (fs.existsSync(filename)) {
431 res.setHeader(
"Content-Length", fs.statSync(filename)[
"size"]);
432 if (req.headers.range != null) {
433 var range = req.headers.range;
434 var offset = parseInt(range.substr(range.indexOf(
'=') + 1, range.indexOf(
'-') - (range.indexOf(
'=') + 1)));
435 var endOffset = parseInt(range.substr(range.indexOf(
'-') + 1));
436 console.log(
"Reading (" + offset +
", " + endOffset +
")");
438 res.setHeader(
"Content-Length", (endOffset - offset + 1).toString());
439 var readStream = fs.createReadStream(filename, { start: parseInt(offset), end: parseInt(endOffset) });
440 readStream.pipe(res);
442 res.end(fs.readFileSync(filename));
446 console.log(
"File not found: " + filename);
447 res.setHeader(
"Content-Type",
"text/plain");
448 res.end(
"File Not Found.");
450 }
else if (module_holder[moduleName] != null) {
454 module_holder[moduleName].removeAllListeners(
'data').on(
'data',
function (data) {
458 module_holder[moduleName].removeAllListeners(
'end').on(
'end',
function (data) {
460 res.end(JSON.stringify(dataTemp + data));
462 module_holder[moduleName].removeAllListeners(
'stream').on(
'stream',
function (str, hdrs, code) {
463 res.writeHead(code, hdrs);
466 var data = module_holder[moduleName][
"GET_" + functionName](workerData[moduleName]);
469 res.end(JSON.stringify(data));
472 console.log(
"Sending client.html");
474 res.setHeader(
"Content-Type",
"text/html");
475 res.end(fs.readFileSync(
"./client.html"),
'utf-8');
476 console.log(
"Done sending client.html");
481 console.log(
"Setting up options");
483 key: fs.readFileSync(
'./certs/server.key'),
484 cert: fs.readFileSync(
'./certs/server.crt'),
485 ca: LoadCerts(
"./certs/certificates"),
486 crl: LoadCRLs(
"./certs/certificates"),
488 rejectUnauthorized:
false
490 var authlist =
" " + fs.readFileSync(
"./certs/authorized_users");
491 console.log(
"Done setting up options");
494 var server = https.createServer(options,
function (req, res) {
496 var clientCertificate = req.connection.getPeerCertificate();
497 var username =
"HTTPS User";
498 if (req.client.authorized) {
504 username = clientCertificate.subject.CN[0];
505 var useremail = clientCertificate.subjectaltname.substr(6);
506 if (authlist.search(username) > 0 || authlist.search(useremail) > 0) {
511 console.log(
"User: " + username +
", readOnly: " + readOnly);
514 serve(req, res, readOnly, username);
516 console.trace(
"Unhandled error in serve: " + JSON.stringify(e));
519 var insecureServer = http.createServer(
function (req, res) {
522 serve(req, res,
false,
"HTTP User");
524 console.trace(
"Unhandled error in serve: " + JSON.stringify(e));
528 console.log(
"Listening on " + config.hostname +
" ports " + config.baseport +
" and " + (config.baseport + 1));
529 server.listen(config.baseport + 1, config.hostname);
530 insecureServer.listen(config.baseport, config.hostname);