Alter channel unload behavior, add additional checks

- Should prevent "write after end" errors caused by unloading a channel before it finishes loading
- Might prevent strange cases of playlists gone wild
This commit is contained in:
calzoneman 2013-09-08 17:43:30 -05:00
parent b3ea7069a8
commit f7e968a13c
6 changed files with 61 additions and 5 deletions

View File

@ -1,3 +1,15 @@
Sun Sep 8 17:41 2013 CDT
* lib/server.js: Change behavior of unloadChannel - deletes all object
keys in the channel object and then sets channel.dead = true
* lib/channel.js: Add extra checks in callbacks to ensure certain things
don't happen if the channel is dead
* lib/playlist.js: Add extra checks to kill the playlist if the channel
it is associated with is dead
* lib/database.js: Add extra checks to prevent loading channel data into
a dead channel object
* tests/fastQuit.js: A simple script to open a connection, join a
channel, and disconnect immediately to test for race conditions
Sat Sep 7 23:38 2013 CDT
* lib/user.js: Add "loggingIn" field to act as a lock on async logins.
Delay further login attempts until the current login attempt finishes.

View File

@ -119,8 +119,12 @@ var Channel = function(name, Server) {
self.ipkey += "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[parseInt(Math.random() * 65)]
}
Server.db.loadChannelData(self, function () {
self.dbloaded = true;
Server.db.loadChannelData(self, function (err) {
if (err && err === "channel_dead")
return;
else if (!err || err === "channel_unregistered")
self.dbloaded = true;
if(self.registered) {
self.loadDump();
}
@ -150,6 +154,9 @@ Channel.prototype.loadDump = function() {
return;
fs.stat(path.join(__dirname, "../chandump", self.name),
function (err, stats) {
if (self.dead)
return;
if(!err) {
var mb = stats.size / 1048576;
mb = parseInt(mb * 100) / 100;
@ -165,6 +172,9 @@ Channel.prototype.loadDump = function() {
}
fs.readFile(path.join(__dirname, "../chandump", self.name),
function(err, data) {
if (self.dead)
return;
if(err) {
if(err.code == "ENOENT") {
Logger.errlog.log("WARN: missing dump for " + self.name);

View File

@ -405,7 +405,12 @@ Database.prototype.loadChannelData = function (chan, callback) {
}
if(res.length == 0) {
callback("Channel is unregistered", null);
callback("channel_unregistered", null);
return;
}
if (chan.dead) {
callback("channel_dead", null);
return;
}
@ -416,6 +421,11 @@ Database.prototype.loadChannelData = function (chan, callback) {
// Load bans
query = "SELECT * FROM `chan_" + chan.name + "_bans`";
self.query(query, function (err, res) {
if (chan.dead) {
callback("channel_dead", null);
return;
}
if(err) {
callback(err, null);
return;

View File

@ -59,14 +59,26 @@ function Playlist(chan) {
this.server = chan.server;
var pl = this;
this.on("mediaUpdate", function(m) {
if (chan.dead) {
pl.die();
return;
}
chan.sendAll("mediaUpdate", m.timeupdate());
});
this.on("changeMedia", function(m) {
if (chan.dead) {
pl.die();
return;
}
chan.onVideoChange();
chan.sendAll("setCurrent", pl.current.uid);
chan.sendAll("changeMedia", m.fullupdate());
});
this.on("remove", function(item) {
if (chan.dead) {
pl.die();
return;
}
chan.broadcastPlaylistMeta();
chan.sendAll("delete", {
uid: item.uid

View File

@ -62,8 +62,11 @@ var Server = {
break;
}
}
chan.name = "";
chan.canonical_name = "";
var keys = Object.keys(chan);
for (var i in keys) {
delete chan[keys[i]];
}
chan.dead = true;
},
stats: null,
app: null,

9
tests/fastQuit.js Normal file
View File

@ -0,0 +1,9 @@
var io = require('socket.io-client');
var socket = io.connect('http://localhost:1337');
// connect, join a room, then disconnect as quickly as possible
socket.on('connect', function () {
socket.emit('joinChannel', { name: 'test' });
socket.disconnect();
});