From 60e71510bfc097b97ee77073db8a12663aca064a Mon Sep 17 00:00:00 2001 From: Thorvald Natvig Date: Sun, 17 Jan 2010 03:49:32 +0100 Subject: [PATCH] Serverside comment/texture send-on-demand --- src/Channel.h | 1 + src/Message.h | 19 ++++++- src/Mumble.proto | 9 +++ src/User.h | 2 + src/murmur/Messages.cpp | 123 +++++++++++++++++++++++++++++++++------- src/murmur/Server.cpp | 28 +++++++-- src/murmur/Server.h | 11 ++-- src/murmur/ServerDB.cpp | 8 +-- 8 files changed, 168 insertions(+), 33 deletions(-) diff --git a/src/Channel.h b/src/Channel.h index 36d377517..b2c682844 100644 --- a/src/Channel.h +++ b/src/Channel.h @@ -52,6 +52,7 @@ class Channel : public QObject { Channel *cParent; QString qsName; QString qsDesc; + QByteArray qbaDescHash; QList qlChannels; QList qlUsers; QHash qhGroups; diff --git a/src/Message.h b/src/Message.h index 17c0a3baf..7980606ca 100644 --- a/src/Message.h +++ b/src/Message.h @@ -57,7 +57,8 @@ MUMBLE_MH_MSG(VoiceTarget) \ MUMBLE_MH_MSG(PermissionQuery) \ MUMBLE_MH_MSG(CodecVersion) \ - MUMBLE_MH_MSG(UserStats) + MUMBLE_MH_MSG(UserStats) \ + MUMBLE_MH_MSG(RequestBlob) class MessageHandler { public: @@ -83,6 +84,22 @@ inline ::std::string u8(const QString &str) { return ::std::string(qba.constData(), qba.length()); } +inline QByteArray blob(const ::std::string &str) { + return QByteArray(str.data(), static_cast(str.length())); +} + +inline ::std::string blob(const QByteArray &str) { + return ::std::string(str.constData(), str.length()); +} + +inline QByteArray sha1(const QByteArray &blob) { + return QCryptographicHash::hash(blob, QCryptographicHash::Sha1); +} + +inline QByteArray sha1(const QString &str) { + return QCryptographicHash::hash(str.toUtf8(), QCryptographicHash::Sha1); +} + #else class Message; #endif diff --git a/src/Mumble.proto b/src/Mumble.proto index b329c696c..071b5e992 100644 --- a/src/Mumble.proto +++ b/src/Mumble.proto @@ -71,6 +71,7 @@ message ChannelState { repeated uint32 links_remove = 7; optional bool temporary = 8 [default = false]; optional int32 position = 9 [default = 0]; + optional bytes description_hash = 10; } message UserRemove { @@ -96,6 +97,8 @@ message UserState { optional string plugin_identity = 13; optional string comment = 14; optional string hash = 15; + optional bytes comment_hash = 16; + optional bytes texture_hash = 17; } message BanList { @@ -256,3 +259,9 @@ message UserStats { optional uint32 idlesecs = 17; optional bool strong_certificate = 18 [default = false]; } + +message RequestBlob { + repeated uint32 session_texture = 1; + repeated uint32 session_comment = 2; + repeated uint32 channel_description = 3; +} diff --git a/src/User.h b/src/User.h index d47862a07..30acb0238 100644 --- a/src/User.h +++ b/src/User.h @@ -43,11 +43,13 @@ class User { int iId; QString qsName; QString qsComment; + QByteArray qbaCommentHash; QString qsHash; bool bMute, bDeaf, bSuppress; bool bSelfMute, bSelfDeaf; Channel *cChannel; QByteArray qbaTexture; + QByteArray qbaTextureHash; User(); virtual ~User() {}; diff --git a/src/murmur/Messages.cpp b/src/murmur/Messages.cpp index 416e8df48..0bb4a7867 100644 --- a/src/murmur/Messages.cpp +++ b/src/murmur/Messages.cpp @@ -220,7 +220,7 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg uSource->qlCodecs.append(static_cast(0x8000000a)); } recheckCodecVersions(); - + MumbleProto::CodecVersion mpcv; mpcv.set_alpha(iCodecAlpha); mpcv.set_beta(iCodecBeta); @@ -245,10 +245,14 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg mpcs.set_name(u8(qsRegName.isEmpty() ? QLatin1String("Root") : qsRegName)); else mpcs.set_name(u8(c->qsName)); - if (! c->qsDesc.isEmpty()) - mpcs.set_description(u8(c->qsDesc)); + mpcs.set_position(c->iPosition); + if ((uSource->uiVersion >= 0x010202) && ! c->qbaDescHash.isEmpty()) + mpcs.set_description_hash(blob(c->qbaDescHash)); + else if (! c->qsDesc.isEmpty()) + mpcs.set_description(u8(c->qsDesc)); + sendMessage(uSource, mpcs); foreach(c, c->qlChannels) @@ -281,20 +285,27 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg lc = root; userEnterChannel(uSource, lc, mpus); - + uSource->sState = ServerUser::Authenticated; mpus.set_session(uSource->uiSession); mpus.set_name(u8(uSource->qsName)); if (uSource->iId >= 0) { - uSource->qbaTexture = getUserTexture(uSource->iId); mpus.set_user_id(uSource->iId); - if (! uSource->qbaTexture.isEmpty()) + + hashAssign(uSource->qbaTexture, uSource->qbaTextureHash, getUserTexture(uSource->iId)); + + if (! uSource->qbaTextureHash.isEmpty()) + mpus.set_texture_hash(blob(uSource->qbaTextureHash)); + else if (! uSource->qbaTexture.isEmpty()) mpus.set_texture(std::string(uSource->qbaTexture.constData(), uSource->qbaTexture.size())); const QMap &info = getRegistration(uSource->iId); if (info.contains(ServerDB::User_Comment)) { - uSource->qsComment = info.value(ServerDB::User_Comment); - mpus.set_comment(u8(uSource->qsComment)); + hashAssign(uSource->qsComment, uSource->qbaCommentHash, info.value(ServerDB::User_Comment)); + if (! uSource->qbaCommentHash.isEmpty()) + mpus.set_comment_hash(blob(uSource->qbaCommentHash)); + else if (! uSource->qsComment.isEmpty()) + mpus.set_comment(u8(uSource->qsComment)); } } if (! uSource->qsHash.isEmpty()) @@ -302,7 +313,13 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg if (uSource->cChannel->iId != 0) mpus.set_channel_id(uSource->cChannel->iId); - sendAll(mpus); + sendAll(mpus, 0x010202); + + if (! uSource->qbaTexture.isEmpty()) + mpus.set_texture(blob(uSource->qbaTexture)); + if (! uSource->qsComment.isEmpty()) + mpus.set_comment(u8(uSource->qsComment)); + sendAll(mpus, ~ 0x010202); // Transmit other users profiles foreach(ServerUser *u, qhUsers) { @@ -333,7 +350,9 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg mpus.set_self_deaf(true); else if (u->bSelfMute) mpus.set_self_mute(true); - if (! u->qsComment.isEmpty()) + if ((uSource->uiVersion >= 0x010202) && ! u->qbaCommentHash.isEmpty()) + mpus.set_comment_hash(blob(u->qbaCommentHash)); + else if (! u->qsComment.isEmpty()) mpus.set_comment(u8(u->qsComment)); if (! u->qsHash.isEmpty()) mpus.set_hash(u8(u->qsHash)); @@ -543,9 +562,11 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) { if (msg.has_comment()) { pDstServerUser->qsComment = u8(msg.comment()); - - if (! bAllowHTML) { - pDstServerUser->qsComment = toPlainText(pDstServerUser->qsComment); + + if (bAllowHTML) { + hashAssign(pDstServerUser->qsComment, pDstServerUser->qbaCommentHash, u8(msg.comment())); + } else { + hashAssign(pDstServerUser->qsComment, pDstServerUser->qbaCommentHash, toPlainText(u8(msg.comment()))); msg.set_comment(u8(pDstServerUser->qsComment)); } @@ -603,8 +624,18 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) { } } - if (! bNoBroadcast) - sendAll(msg); + if (! bNoBroadcast) { + sendAll(msg, ~ 0x010202); + if (msg.has_texture() && ! pDstServerUser->qbaTextureHash.isEmpty()) { + msg.clear_texture(); + msg.set_texture_hash(blob(pDstServerUser->qbaTextureHash)); + } + if (msg.has_comment() && ! pDstServerUser->qbaCommentHash.isEmpty()) { + msg.clear_comment(); + msg.set_comment_hash(blob(pDstServerUser->qbaCommentHash)); + } + sendAll(msg, 0x010202); + } emit userStateChanged(pDstServerUser); } @@ -732,7 +763,7 @@ void Server::msgChannelState(ServerUser *uSource, MumbleProto::ChannelState &msg } c = addChannel(p, qsName, msg.temporary(), msg.position()); - c->qsDesc = qsDesc; + hashAssign(c->qsDesc, c->qbaDescHash, qsDesc); if (uSource->iId >= 0) { Group *g = new Group(c, "admin"); @@ -757,7 +788,13 @@ void Server::msgChannelState(ServerUser *uSource, MumbleProto::ChannelState &msg msg.set_channel_id(c->iId); log(uSource, QString("Added channel %1 under %2").arg(QString(*c), QString(*p))); emit channelCreated(c); - sendAll(msg); + + sendAll(msg, ~ 0x010202); + if (! c->qbaDescHash.isEmpty()) { + msg.clear_description(); + msg.set_description_hash(blob(c->qbaDescHash)); + } + sendAll(msg, 0x010202); if (c->bTemporary) { // If a temporary channel has been created move the creator right in there @@ -875,7 +912,7 @@ void Server::msgChannelState(ServerUser *uSource, MumbleProto::ChannelState &msg c->qsName = qsName; } if (! qsDesc.isNull()) - c->qsDesc = qsDesc; + hashAssign(c->qsDesc, c->qbaDescHash, qsDesc); if (msg.has_position()) c->iPosition = msg.position(); @@ -889,7 +926,13 @@ void Server::msgChannelState(ServerUser *uSource, MumbleProto::ChannelState &msg updateChannel(c); emit channelStateChanged(c); - sendAll(msg); + + sendAll(msg, ~ 0x010202); + if (msg.has_description() && ! c->qbaDescHash.isEmpty()) { + msg.clear_description(); + msg.set_description_hash(blob(c->qbaDescHash)); + } + sendAll(msg, 0x010202); } } @@ -1444,3 +1487,45 @@ void Server::msgUserStats(ServerUser*uSource, MumbleProto::UserStats &msg) { sendMessage(uSource, msg); } + +void Server::msgRequestBlob(ServerUser *uSource, MumbleProto::RequestBlob &msg) { + int ntextures = msg.session_texture_size(); + int ncomments = msg.session_comment_size(); + int ndescriptions = msg.channel_description_size(); + + if (ndescriptions) { + MumbleProto::ChannelState mpcs; + for(int i=0;iqsDesc.isEmpty()) { + mpcs.set_channel_id(id); + mpcs.set_description(u8(c->qsDesc)); + sendMessage(uSource, mpcs); + } + } + } + if (ntextures || ncomments) { + MumbleProto::UserState mpus; + for(int i=0;iqbaTexture.isEmpty()) { + mpus.set_session(session); + mpus.set_texture(std::string(su->qbaTexture.constData(), su->qbaTexture.length())); + sendMessage(uSource, mpus); + } + } + if (ntextures) + mpus.clear_texture(); + for(int i=0;iqsComment.isEmpty()) { + mpus.set_session(session); + mpus.set_comment(u8(su->qsComment)); + sendMessage(uSource, mpus); + } + } + } +} diff --git a/src/murmur/Server.cpp b/src/murmur/Server.cpp index c9f041776..f42683d2f 100644 --- a/src/murmur/Server.cpp +++ b/src/murmur/Server.cpp @@ -108,7 +108,7 @@ Server::Server(int snum, QObject *p) : QThread(p) { iCodecAlpha = iCodecBeta = 0; bPreferAlpha = false; - + qnamNetwork = NULL; readParams(); @@ -1230,15 +1230,16 @@ void Server::sendProtoMessage(ServerUser *u, const ::google::protobuf::Message & u->sendMessage(msg, msgType, cache); } -void Server::sendProtoAll(const ::google::protobuf::Message &msg, unsigned int msgType) { - sendProtoExcept(NULL, msg, msgType); +void Server::sendProtoAll(const ::google::protobuf::Message &msg, unsigned int msgType, unsigned int minversion) { + sendProtoExcept(NULL, msg, msgType, minversion); } -void Server::sendProtoExcept(ServerUser *u, const ::google::protobuf::Message &msg, unsigned int msgType) { +void Server::sendProtoExcept(ServerUser *u, const ::google::protobuf::Message &msg, unsigned int msgType, unsigned int minversion) { QByteArray cache; foreach(ServerUser *usr, qhUsers) if ((usr != u) && (usr->sState == ServerUser::Authenticated)) - usr->sendMessage(msg, msgType, cache); + if ((minversion == 0) || (usr->uiVersion >= minversion) || ((minversion & 0x80000000) && (usr->uiVersion < (~minversion)))) + usr->sendMessage(msg, msgType, cache); } void Server::removeChannel(int id) { @@ -1501,6 +1502,7 @@ void Server::recheckCodecVersions() { QMap qmCodecUsercount; QMap::const_iterator i; int users = 0; + // Count how many users use which codec foreach(ServerUser *u, qhUsers) { if (u->qlCodecs.isEmpty()) @@ -1553,3 +1555,19 @@ void Server::recheckCodecVersions() { log(QString::fromLatin1("CELT codec switch %1 %2 (prefer %3)").arg(iCodecAlpha,0,16).arg(iCodecBeta,0,16).arg(bPreferAlpha ? iCodecAlpha : iCodecBeta,0,16)); } + +void Server::hashAssign(QString &dest, QByteArray &hash, const QString &src) { + dest = src; + if (src.length() > 128) + hash = sha1(dest); + else + hash = QByteArray(); +} + +void Server::hashAssign(QByteArray &dest, QByteArray &hash, const QByteArray &src) { + dest = src; + if (src.length() > 128) + hash = sha1(dest); + else + hash = QByteArray(); +} diff --git a/src/murmur/Server.h b/src/murmur/Server.h index 2a78a0b79..e202b6146 100644 --- a/src/murmur/Server.h +++ b/src/murmur/Server.h @@ -294,18 +294,21 @@ class Server : public QThread { void flushClientPermissionCache(ServerUser *u, MumbleProto::PermissionQuery &mpqq); void clearACLCache(User *p = NULL); - void sendProtoAll(const ::google::protobuf::Message &msg, unsigned int msgType); - void sendProtoExcept(ServerUser *, const ::google::protobuf::Message &msg, unsigned int msgType); + void sendProtoAll(const ::google::protobuf::Message &msg, unsigned int msgType, unsigned int minversion); + void sendProtoExcept(ServerUser *, const ::google::protobuf::Message &msg, unsigned int msgType, unsigned int minversion); void sendProtoMessage(ServerUser *, const ::google::protobuf::Message &msg, unsigned int msgType); #define MUMBLE_MH_MSG(x) \ - void sendAll(const MumbleProto:: x &msg) { sendProtoAll(msg, MessageHandler:: x); } \ - void sendExcept(ServerUser *u, const MumbleProto:: x &msg) { sendProtoExcept(u, msg, MessageHandler:: x); } \ + void sendAll(const MumbleProto:: x &msg, unsigned int v = 0) { sendProtoAll(msg, MessageHandler:: x, v); } \ + void sendExcept(ServerUser *u, const MumbleProto:: x &msg, unsigned int v = 0) { sendProtoExcept(u, msg, MessageHandler:: x, v); } \ void sendMessage(ServerUser *u, const MumbleProto:: x &msg) { sendProtoMessage(u, msg, MessageHandler:: x); } MUMBLE_MH_ALL #undef MUMBLE_MH_MSG + static void hashAssign(QString &destination, QByteArray &hash, const QString &str); + static void hashAssign(QByteArray &destination, QByteArray &hash, const QByteArray &source); + void setLiveConf(const QString &key, const QString &value); QString addressToString(const QHostAddress &, unsigned short port); diff --git a/src/murmur/ServerDB.cpp b/src/murmur/ServerDB.cpp index d78f4f0fe..dc1b66750 100644 --- a/src/murmur/ServerDB.cpp +++ b/src/murmur/ServerDB.cpp @@ -762,7 +762,7 @@ int Server::authenticate(QString &name, const QString &pw, const QStringList &em if (query.next()) { res = -1; QString storedpw = query.value(2).toString(); - QString hashedpw = QString::fromLatin1(QCryptographicHash::hash(pw.toUtf8(), QCryptographicHash::Sha1).toHex()); + QString hashedpw = QString::fromLatin1(sha1(pw).toHex()); if (! storedpw.isEmpty() && (storedpw == hashedpw)) { name = query.value(1).toString(); @@ -932,8 +932,8 @@ bool Server::setTexture(int id, const QByteArray &texture) { tex = qCompress(tex); ServerUser *u = qhUsers.value(id); - if (u) - u->qbaTexture = tex; + if (u) + hashAssign(u->qbaTexture, u->qbaTextureHash, tex); int res = -2; emit setTextureSig(res, id, tex); @@ -1248,7 +1248,7 @@ void Server::readChannelPrivs(Channel *c) { int key = query.value(0).toInt(); const QString &value = query.value(1).toString(); if (key == ServerDB::Channel_Description) { - c->qsDesc = value; + hashAssign(c->qsDesc, c->qbaDescHash, value); } else if (key == ServerDB::Channel_Position) { c->iPosition = QVariant(value).toInt(); // If the conversion fails it'll return the default value 0 }