diff --git a/config.template.yaml b/config.template.yaml index 9d84aa5d..7e3ac1a5 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -9,11 +9,43 @@ mysql: user: 'cytube3' password: '' +# Define IPs/ports to listen on +# Each entry MUST define ip and port (ip can be '' to bind all available addresses) +# Each entry should set http, https, and/or io to true to listen for the corresponding +# service on that port. http/io and https/io can be combined, but if http and https +# are both specified, only https will be bound to that port. +# +# NOTE: You can technically bind an IPv6 address this way, but much of the code has not +# yet been updated to work with IPv6 addresses (ban ranges, IP masking, etc.) +# IPv6 support is planned, and the below method of binding servers is one step in that +# direction +listen: +# Default HTTP server - default interface, port 8080 + - ip: '' + port: 8080 + http: true +# Uncomment below to enable HTTPS/SSL websockets +# Note that you must also set https->enabled = true in the https definition +# - ip: '' +# port: 8443 +# https: true +# io: true +# Default Socket.IO server - default interface, port 1337 + - ip: '' + port: 1337 + io: true +# Example of how to bind an extra port to HTTP and Socket.IO +# - ip: '' +# port: 8081 +# http: true +# io: true + # HTTP server details http: - # If you want to bind a specific IP, put it here, otherwise leave empty - host: '' - port: 8080 + # Even though you may specify multiple ports to listen on for HTTP above, + # one port must be specified as default for the purposes of generating + # links with the appropriate port + default-port: 8080 domain: 'http://localhost' # Specifies the root domain for cookies. If you have multiple domains # e.g. a.example.com and b.example.com, the root domain is example.com @@ -30,7 +62,10 @@ http: # HTTPS server details https: enabled: false - port: 8443 + # Even though you may specify multiple ports to listen on for HTTPS above, + # one port must be specified as default for the purposes of generating + # links with the appropriate port + default-port: 8443 domain: 'https://localhost' keyfile: 'localhost.key' passphrase: '' @@ -51,7 +86,10 @@ io: # If the root of this domain is not the same as the root of your HTTP domain # (or HTTPS if SSL is enabled), logins won't work. domain: 'http://localhost' - port: 1337 + # Even though you may specify multiple ports to listen on for HTTP above, + # one port must be specified as default for the purposes of generating + # links with the appropriate port + default-port: 1337 # limit the number of concurrent socket connections per IP address ip-connection-limit: 10 diff --git a/lib/config.js b/lib/config.js index 21e4b6fc..3bb2f964 100644 --- a/lib/config.js +++ b/lib/config.js @@ -22,10 +22,21 @@ var defaults = { user: "cytube3", password: "" }, + listen: [ + { + ip: "", + port: 8080, + http: true, + }, + { + ip: "", + port: 1337, + io: true + } + ], http: { - host: "", - port: 8080, domain: "http://localhost", + "default-port": 8080, "root-domain": "localhost", "alt-domains": ["127.0.0.1"], minify: false, @@ -33,8 +44,8 @@ var defaults = { }, https: { enabled: false, - port: 8443, domain: "https://localhost", + "default-port": 8443, keyfile: "localhost.key", passphrase: "", certfile: "localhost.cert", @@ -42,7 +53,7 @@ var defaults = { }, io: { domain: "http://localhost", - port: 1337, + "default-port": 1337, "ip-connection-limit": 10 }, mail: { @@ -151,6 +162,40 @@ exports.load = function (file) { }; function preprocessConfig(cfg) { + /* Detect 3.0.0-style config and warng the user about it */ + if ("host" in cfg.http || "port" in cfg.http || "port" in cfg.https) { + Logger.syslog.log("[WARN] The method of specifying which IP/port to bind has "+ + "changed. The config loader will try to handle this "+ + "automatically, but you should read config.template.yaml "+ + "and change your config.yaml to the new format."); + cfg.listen = [ + { + ip: cfg.http.host, + port: cfg.http.port, + http: true + }, + { + ip: cfg.http.host, + port: cfg.io.port, + io: true + } + ]; + + if (cfg.https.enabled) { + cfg.listen.push( + { + ip: cfg.http.host, + port: cfg.https.port, + https: true, + io: true + } + ); + } + + cfg.http["default-port"] = cfg.http.port; + cfg.https["default-port"] = cfg.https.port; + cfg.io["default-port"] = cfg.io.port; + } // Root domain should start with a . for cookies var root = cfg.http["root-domain"]; root = root.replace(/^\.*/, ""); @@ -181,7 +226,7 @@ function preprocessConfig(cfg) { if (!cfg.http["full-address"]) { var httpfa = cfg.http.domain; if (cfg.http.port !== 80) { - httpfa += ":" + cfg.http.port; + httpfa += ":" + cfg.http["default-port"]; } cfg.http["full-address"] = httpfa; } @@ -189,7 +234,7 @@ function preprocessConfig(cfg) { if (!cfg.https["full-address"]) { var httpsfa = cfg.https.domain; if (cfg.https.port !== 443) { - httpsfa += ":" + cfg.https.port; + httpsfa += ":" + cfg.https["default-port"]; } cfg.https["full-address"] = httpsfa; } diff --git a/lib/database.js b/lib/database.js index d02c5aec..e191ab07 100644 --- a/lib/database.js +++ b/lib/database.js @@ -663,9 +663,8 @@ module.exports.loadAnnouncement = function () { var sv = Server.getServer(); sv.announcement = announcement; - sv.io.sockets.emit("announcement", announcement); - if (sv.ioSecure) { - sv.ioSecure.sockets.emit("announcement", announcement); + for (var id in sv.ioServers) { + sv.ioServers[id].sockets.emit("announcement", announcement); } }); }; diff --git a/lib/io/ioserver.js b/lib/io/ioserver.js index 79fe5b6d..04babb41 100644 --- a/lib/io/ioserver.js +++ b/lib/io/ioserver.js @@ -119,27 +119,29 @@ function handleConnection(sock) { module.exports = { init: function (srv) { - var ioport = Config.get("io.port"); - var webport = Config.get("http.port"); - var app; - if (ioport !== webport) { - app = require("express")().listen(ioport, Config.get("http.host")); - srv.ioWeb = app; - } else { - app = srv.express; - } + Config.get("listen").forEach(function (bind) { + if (!bind.io) { + return; + } + var id = bind.ip + ":" + bind.port; + if (id in srv.ioServers) { + Logger.syslog.log("[WARN] Ignoring duplicate listen address " + id); + return; + } - srv.io = sio.listen(app); - srv.io.set("log level", 1); - srv.io.set("authorization", handleAuth); - srv.io.on("connection", handleConnection); - - if (Config.get("https.enabled")) { - srv.ioSecure = sio.listen(srv.https); - srv.ioSecure.set("log level", 1); - srv.ioSecure.set("authorization", handleAuth); - srv.ioSecure.on("connection", handleConnection); - } + var io = null; + if (id in srv.servers) { + io = srv.ioServers[id] = sio.listen(srv.servers[id]); + } else { + io = srv.ioServers[id] = sio.listen(bind.port, bind.ip); + } + + if (io) { + io.set("log level", 1); + io.set("authorization", handleAuth); + io.on("connection", handleConnection); + } + }); } }; diff --git a/lib/server.js b/lib/server.js index ee4b276e..f1cfbfeb 100644 --- a/lib/server.js +++ b/lib/server.js @@ -49,17 +49,14 @@ var Server = function () { var self = this; self.channels = [], self.express = null; - self.http = null; - self.https = null; - self.io = null; - self.ioWeb = null; - self.ioSecure = null; self.db = null; self.api = null; self.announcement = null; self.httplog = null; self.infogetter = null; self.torblocker = null; + self.servers = {}; + self.ioServers = {}; // database init ------------------------------------------------------ var Database = require("./database"); @@ -73,30 +70,37 @@ var Server = function () { require("./web/webserver").init(self.express); // http/https/sio server init ----------------------------------------- - if (Config.get("https.enabled")) { - var key = fs.readFileSync(path.resolve(__dirname, "..", - Config.get("https.keyfile"))); - var cert = fs.readFileSync(path.resolve(__dirname, "..", - Config.get("https.certfile"))); - var ca = undefined; - if (Config.get("https.cafile")) { - ca = fs.readFileSync(path.resolve(__dirname, "..", - Config.get("https.cafile"))); - } - - var opts = { - key: key, - cert: cert, - passphrase: Config.get("https.passphrase"), - ca: ca - }; - - self.https = https.createServer(opts, self.express) - .listen(Config.get("https.port")); + var key = fs.readFileSync(path.resolve(__dirname, "..", + Config.get("https.keyfile"))); + var cert = fs.readFileSync(path.resolve(__dirname, "..", + Config.get("https.certfile"))); + var ca = undefined; + if (Config.get("https.cafile")) { + ca = fs.readFileSync(path.resolve(__dirname, "..", + Config.get("https.cafile"))); } - self.http = self.express.listen(Config.get("http.port"), - Config.get("http.host") || undefined); + var opts = { + key: key, + cert: cert, + passphrase: Config.get("https.passphrase"), + ca: ca + }; + + Config.get("listen").forEach(function (bind) { + var id = bind.ip + ":" + bind.port; + if (id in self.servers) { + Logger.syslog.log("[WARN] Ignoring duplicate listen address " + id); + return; + } + + if (bind.https && Config.get("https.enabled")) { + self.servers[id] = https.createServer(opts, self.express) + .listen(bind.port, bind.ip); + } else if (bind.http) { + self.servers[id] = self.express.listen(bind.port, bind.ip); + } + }); require("./io/ioserver").init(self); @@ -237,9 +241,8 @@ Server.prototype.announce = function (data) { } else { this.announcement = data; db.setAnnouncement(data); - this.io.sockets.emit("announcement", data); - if (this.ioSecure) { - this.ioSecure.sockets.emit("announcement", data); + for (var id in this.ioServers) { + this.ioServers[id].sockets.emit("announcement", data); } } }; diff --git a/lib/web/webserver.js b/lib/web/webserver.js index 0ef95f0f..cf98e969 100644 --- a/lib/web/webserver.js +++ b/lib/web/webserver.js @@ -112,7 +112,7 @@ function handleChannel(req, res) { if (req.secure) { sio = Config.get("https.full-address"); } else { - sio = Config.get("io.domain") + ":" + Config.get("io.port"); + sio = Config.get("io.domain") + ":" + Config.get("io.default-port"); } sio += "/socket.io/socket.io.js"; @@ -159,9 +159,9 @@ function handleSocketConfig(req, res) { res.type("application/javascript"); - var io_url = Config.get("io.domain") + ":" + Config.get("io.port"); - var web_url = Config.get("http.domain") + ":" + Config.get("http.port"); - var ssl_url = Config.get("https.domain") + ":" + Config.get("https.port"); + var io_url = Config.get("io.domain") + ":" + Config.get("io.default-port"); + var web_url = Config.get("http.domain") + ":" + Config.get("http.default-port"); + var ssl_url = Config.get("https.domain") + ":" + Config.get("https.default-port"); res.send("var IO_URL='"+io_url+"',WEB_URL='"+web_url+"',SSL_URL='" + ssl_url + "',ALLOW_SSL="+Config.get("https.enabled")+";" + (Config.get("https.enabled") ?