diff --git a/support/aphlict/server/aphlict_server.js b/support/aphlict/server/aphlict_server.js index 6635a230c0..8d1bd61a03 100644 --- a/support/aphlict/server/aphlict_server.js +++ b/support/aphlict/server/aphlict_server.js @@ -1,196 +1,179 @@ /** * Notification server. Launch with: * * sudo node aphlict_server.js --user=aphlict * * You can also specify `port`, `admin`, `host` and `log`. */ var JX = require('./lib/javelin').JX; +JX.require('lib/AphlictFlashPolicyServer', __dirname); JX.require('lib/AphlictListenerList', __dirname); JX.require('lib/AphlictLog', __dirname); var debug = new JX.AphlictLog() .addConsole(console); var clients = new JX.AphlictListenerList(); var config = parse_command_line_arguments(process.argv); if (config.logfile) { debug.addLogfile(config.logfile); } function parse_command_line_arguments(argv) { var config = { port : 22280, admin : 22281, host : '127.0.0.1', user : null, log: '/var/log/aphlict.log' }; for (var ii = 2; ii < argv.length; ii++) { var arg = argv[ii]; var matches = arg.match(/^--([^=]+)=(.*)$/); if (!matches) { throw new Error("Unknown argument '"+arg+"'!"); } if (!(matches[1] in config)) { throw new Error("Unknown argument '"+matches[1]+"'!"); } config[matches[1]] = matches[2]; } config.port = parseInt(config.port, 10); config.admin = parseInt(config.admin, 10); return config; } if (process.getuid() !== 0) { console.log( "ERROR: "+ "This server must be run as root because it needs to bind to privileged "+ "port 843 to start a Flash policy server. It will downgrade to run as a "+ "less-privileged user after binding if you pass a user in the command "+ "line arguments with '--user=alincoln'."); process.exit(1); } var net = require('net'); var http = require('http'); var url = require('url'); var querystring = require('querystring'); - process.on('uncaughtException', function (err) { - log("\n<<< UNCAUGHT EXCEPTION! >>>\n\n" + err); + debug.log("\n<<< UNCAUGHT EXCEPTION! >>>\n\n" + err); process.exit(1); }); -function getFlashPolicy() { - return [ - '', - '', - '', - '', - '' - ].join('\n'); -} - -net.createServer(function(socket) { - socket.write(getFlashPolicy() + '\0'); - socket.end(); - - debug.log('[' + socket.remoteAddress + '] Sent Flash Policy'); - - socket.on('error', function (e) { - debug.log('Error in policy server: ' + e); - }); -}).listen(843); +var flash_server = new JX.AphlictFlashPolicyServer() + .setDebugLog(debug) + .setAccessPort(config.port) + .start(); var send_server = net.createServer(function(socket) { var listener = clients.addListener(socket); debug.log('<%s> Connected from %s', listener.getDescription(), socket.remoteAddress); socket.on('close', function() { clients.removeListener(listener); debug.log('<%s> Disconnected', listener.getDescription()); }); socket.on('timeout', function() { debug.log('<%s> Timed Out', listener.getDescription()); }); socket.on('end', function() { debug.log('<%s> Ended Connection', listener.getDescription()); }); socket.on('error', function (e) { debug.log('<%s> Error: %s', listener.getDescription(), e); }); }).listen(config.port); var messages_out = 0; var messages_in = 0; var start_time = new Date().getTime(); var receive_server = http.createServer(function(request, response) { response.writeHead(200, {'Content-Type' : 'text/plain'}); // Publishing a notification. if (request.method == 'POST') { var body = ''; request.on('data', function (data) { body += data; }); request.on('end', function () { ++messages_in; var data = querystring.parse(body); debug.log('notification: ' + JSON.stringify(data)); broadcast(data); response.end(); }); } else if (request.url == '/status/') { request.on('data', function(data) { // We just ignore the request data, but newer versions of Node don't // get to 'end' if we don't process the data. See T2953. }); request.on('end', function() { var status = { 'uptime': (new Date().getTime() - start_time), 'clients.active': clients.getActiveListenerCount(), 'clients.total': clients.getTotalListenerCount(), 'messages.in': messages_in, 'messages.out': messages_out, 'log': config.log, 'version': 3 }; response.write(JSON.stringify(status)); response.end(); }); } else { response.statusCode = 400; response.write('400 Bad Request'); response.end(); } }).listen(config.admin, config.host); function broadcast(data) { var listeners = clients.getListeners(); for (var id in listeners) { var listener = listeners[id]; try { listener.writeMessage(data); ++messages_out; debug.log('<%s> Wrote Message', listener.getDescription()); } catch (error) { clients.removeListener(listener); debug.log('<%s> Write Error: %s', error); } } } // If we're configured to drop permissions, get rid of them now that we've // bound to the ports we need and opened logfiles. if (config.user) { process.setuid(config.user); } debug.log('Started Server (PID %d)', process.pid); diff --git a/support/aphlict/server/lib/AphlictFlashPolicyServer.js b/support/aphlict/server/lib/AphlictFlashPolicyServer.js new file mode 100644 index 0000000000..77cb6311f8 --- /dev/null +++ b/support/aphlict/server/lib/AphlictFlashPolicyServer.js @@ -0,0 +1,68 @@ +var JX = require('javelin').JX; + +var net = require('net'); + +/** + * Server which handles cross-domain policy requests for Flash. + * + * var server = new AphlictFlashPolicyServer() + * .setAccessPort(9999) + * .start(); + */ +JX.install('AphlictFlashPolicyServer', { + + members: { + _server: null, + _port: 843, + _accessPort: null, + _debug: null, + + setDebugLog : function(log) { + this._debug = log; + return this; + }, + + setAccessPort : function(port) { + this._accessPort = port; + return this; + }, + + start: function() { + this._server = net.createServer(JX.bind(this, this._didConnect)); + this._server.listen(this._port); + return this; + }, + + _didConnect: function(socket) { + this._log(' Policy Request From %s', socket.remoteAddress); + + socket.on('error', JX.bind(this, this._didSocketError, socket)); + + socket.write(this._getFlashPolicyResponse()); + socket.end(); + }, + + _didSocketError: function(socket, error) { + this._log(' Socket Error: %s', error); + }, + + _log: function(pattern) { + this._debug && this._debug.log.apply(this._debug, arguments); + }, + + _getFlashPolicyResponse: function() { + var policy = [ + '', + '', + '', + '', + '' + ]; + + return policy.join("\n") + "\0"; + } + + } + +});