Add extra checks to channel.js for deadness

This commit is contained in:
calzoneman 2013-09-18 18:16:12 -05:00
parent d5c5de41e1
commit 39fe452e96
3 changed files with 116 additions and 8 deletions

View file

@ -1,3 +1,9 @@
Wed Sep 18 18:14 2013 CDT
* lib/channel.js: Add a bunch of checks to prevent callbacks from doing
things with a dead channel
* tests/channelDeadRace.js: Add a few client tests that cause exceptions
in the pre-patched channel code
Tue Sep 17 22:24 2013 CDT
* lib/user.js: Fix what I assume was a race condition that caused an error message
when a user's login callback fired after the channel unloaded.

View file

@ -122,7 +122,7 @@ var Channel = function(name, Server) {
Server.db.loadChannelData(self, function (err) {
if (err && err === "channel_dead")
return;
return;
else if (!err || err === "channel_unregistered")
self.dbloaded = true;
@ -214,11 +214,12 @@ Channel.prototype.loadDump = function() {
}
// Current
else if(data.playlist) {
var chan = self;
self.playlist.load(data.playlist, function() {
chan.sendAll("playlist", chan.playlist.items.toArray());
chan.broadcastPlaylistMeta();
chan.playlist.startPlayback(data.playlist.time);
if (self.dead)
return;
self.sendAll("playlist", self.playlist.items.toArray());
self.broadcastPlaylistMeta();
self.playlist.startPlayback(data.playlist.time);
});
}
for(var key in data.opts) {
@ -270,7 +271,7 @@ Channel.prototype.loadDump = function() {
self.js = data.js || "";
self.sendAll("channelCSSJS", {css: self.css, js: self.js});
self.initialized = true;
setTimeout(function() { incrementalDump(self); }.bind(self), 300000);
setTimeout(function() { incrementalDump(self); }, 300000);
}
catch(e) {
Logger.errlog.log("Channel dump load failed: ");
@ -281,6 +282,8 @@ Channel.prototype.loadDump = function() {
}
Channel.prototype.saveDump = function() {
if (this.dead)
return;
if(!this.initialized || this.name === "")
return;
var filts = new Array(this.filters.length);
@ -306,7 +309,7 @@ Channel.prototype.saveDump = function() {
// Save channel dumps every 5 minutes, in case of crash
function incrementalDump(chan) {
if(chan && chan.users && chan.users.length > 0) {
if(!chan.dead && chan.users && chan.users.length > 0) {
chan.saveDump();
setTimeout(function() { incrementalDump(chan); }, 300000);
}
@ -415,6 +418,8 @@ Channel.prototype.tryRegister = function (user) {
self.server.actionlog.record(user.ip, user.name,
"channel-register-success", self.name);
if (self.dead)
return;
self.registered = true;
self.initialized = true;
self.saveDump();
@ -454,14 +459,18 @@ Channel.prototype.unregister = function (user) {
return;
}
self.registered = false;
user.socket.emit("unregisterChannel", { success: true });
if (!self.dead)
self.registered = false;
});
}
Channel.prototype.getRank = function (name, callback) {
var self = this;
self.server.db.getGlobalRank(name, function (err, global) {
if (self.dead)
return;
if(err) {
callback(err, null);
return;
@ -495,8 +504,13 @@ Channel.prototype.saveRank = function (user, callback) {
Channel.prototype.getIPRank = function (ip, callback) {
var self = this;
self.server.db.listAliases(ip, function (err, names) {
if (self.dead)
return;
self.server.db.listChannelUserRanks(self.name, names,
function (err, res) {
if (self.dead)
return;
if(err) {
callback(err, null);
return;
@ -550,6 +564,8 @@ Channel.prototype.tryNameBan = function(actor, name) {
}
self.getRank(name, function (err, rank) {
if (self.dead)
return;
if(err) {
actor.socket.emit("errorMsg", {
msg: "Internal error " + err
@ -604,6 +620,8 @@ Channel.prototype.unbanName = function(actor, name) {
self.logger.log("*** " + actor.name + " un-namebanned " + name);
self.server.db.clearChannelNameBan(self.name, name, function (err, res) {
if (self.dead)
return;
self.users.forEach(function(u) {
self.sendBanlist(u);
@ -627,6 +645,9 @@ Channel.prototype.tryIPBan = function(actor, name, range) {
return;
}
self.server.db.listIPsForName(name, function (err, ips) {
if (self.dead)
return;
if(err) {
actor.socket.emit("errorMsg", {
msg: "Internal error: " + err
@ -637,6 +658,9 @@ Channel.prototype.tryIPBan = function(actor, name, range) {
if(range)
ip = ip.replace(/(\d+)\.(\d+)\.(\d+)\.(\d+)/, "$1.$2.$3");
self.getIPRank(ip, function (err, rank) {
if (self.dead)
return;
if(err) {
actor.socket.emit("errorMsg", {
msg: "Internal error: " + err
@ -669,6 +693,9 @@ Channel.prototype.tryIPBan = function(actor, name, range) {
self.server.db.addChannelBan(self.name, ip, name,
actor.name,
function (err, res) {
if (self.dead)
return;
var notice = {
username: "[server]",
msg: actor.name + " banned " + $util.maskIP(ip) +
@ -782,6 +809,8 @@ Channel.prototype.userJoin = function(user) {
this.broadcastVoteskipUpdate();
if(user.name != "") {
self.getRank(user.name, function (err, rank) {
if (self.dead)
return;
if(err) {
user.rank = user.global_rank;
user.saverank = false;
@ -1343,6 +1372,9 @@ Channel.prototype.addMedia = function(data, user) {
: this.opts.maxlength;
var postAdd = function (item, cached) {
if (self.dead)
return;
if(item.media.type === "cu" && data.title) {
var t = data.title;
if(t.length > 100)
@ -1362,6 +1394,9 @@ Channel.prototype.addMedia = function(data, user) {
// No need to check library for livestreams - they aren't cached
if(isLive(data.type)) {
self.playlist.addMedia(data, function (err, data) {
if (self.dead)
return;
if(err) {
if(err === true)
err = false;
@ -1379,6 +1414,9 @@ Channel.prototype.addMedia = function(data, user) {
// Don't search library if the channel isn't registered
if(!self.registered) {
self.playlist.addMedia(data, function(err, item) {
if (self.dead)
return;
if(err) {
if(err === true)
err = false;
@ -1393,6 +1431,9 @@ Channel.prototype.addMedia = function(data, user) {
}
self.server.db.getLibraryItem(self.name, data.id,
function (err, item) {
if (self.dead)
return;
if(err) {
user.socket.emit("queueFail", "Internal error: " + err);
return;
@ -1407,6 +1448,9 @@ Channel.prototype.addMedia = function(data, user) {
data.media = m;
self.playlist.addCachedMedia(data, function (err, item) {
if (self.dead)
return;
if(err) {
if(err === true)
err = false;
@ -1419,6 +1463,9 @@ Channel.prototype.addMedia = function(data, user) {
});
} else {
self.playlist.addMedia(data, function(err, item) {
if (self.dead)
return;
if(err) {
if(err === true)
err = false;
@ -1438,6 +1485,9 @@ Channel.prototype.addMedia = function(data, user) {
Channel.prototype.addMediaList = function(data, user) {
var chan = this;
this.playlist.addMediaList(data, function(err, item) {
if (chan.dead)
return;
if(err) {
if(err === true)
err = false;
@ -1477,6 +1527,9 @@ Channel.prototype.tryQueuePlaylist = function(user, data) {
self.server.db.getUserPlaylist(user.name, data.name,
function (err, pl) {
if (self.dead)
return;
if(err) {
user.socket.emit("errorMsg", {
msg: "Playlist load failed: " + err
@ -1552,6 +1605,9 @@ Channel.prototype.tryUncache = function(user, data) {
}
self.server.db.removeFromLibrary(self.name, data.id,
function (err, res) {
if (self.dead)
return;
if(err)
return;
@ -1662,6 +1718,9 @@ Channel.prototype.tryUpdate = function(user, data) {
Channel.prototype.move = function(data, user) {
var chan = this;
function afterMove() {
if (chan.dead)
return;
var moveby = user && user.name ? user.name : null;
if(typeof data.moveby !== "undefined")
moveby = data.moveby;
@ -2117,6 +2176,9 @@ Channel.prototype.trySetRank = function(user, data) {
receiver.rank = data.rank;
if(receiver.loggedIn) {
self.saveRank(receiver, function (err, res) {
if (self.dead)
return;
self.logger.log("*** " + user.name + " set " +
data.user + "'s rank to " + data.rank);
self.sendAllWithPermission("acl", "setChannelRank", data);
@ -2125,6 +2187,9 @@ Channel.prototype.trySetRank = function(user, data) {
self.broadcastUserUpdate(receiver);
} else if(self.registered) {
self.getRank(data.user, function (err, rrank) {
if (self.dead)
return;
if(err)
return;
if(rrank >= user.rank)
@ -2132,6 +2197,9 @@ Channel.prototype.trySetRank = function(user, data) {
self.server.db.setChannelRank(self.name, data.user,
data.rank, function (err, res) {
if (self.dead)
return;
self.logger.log("*** " + user.name + " set " +
data.user + "'s rank to " + data.rank);
self.sendAllWithPermission("acl", "setChannelRank", data);

34
tests/channelDeadRace.js Normal file
View file

@ -0,0 +1,34 @@
var io = require('socket.io-client');
function testLogin() {
var socket = io.connect('http://localhost:1337');
socket.on('connect', function () {
socket.emit('login', { name: 'test', pw: 'test' });
socket.emit('joinChannel', { name: 'test' });
socket.disconnect();
});
}
function testBan() {
var socket = io.connect('http://localhost:1337');
socket.on('connect', function () {
socket.emit('login', { name: 'test', pw: 'test' });
socket.emit('joinChannel', { name: 'test' });
socket.emit('chatMsg', { msg: '/ban asdf' });
socket.disconnect();
});
}
function testRankChange() {
var socket = io.connect('http://localhost:1337');
socket.on('connect', function () {
socket.emit('login', { name: 'test', pw: 'test' });
socket.emit('joinChannel', { name: 'test' });
socket.emit('setChannelRank', { user: 'test2', rank: 2 });
socket.disconnect();
});
}
testLogin();
testBan();
testRankChange();