From e41bf778c802b561f872d3f9491eb1090cc7fdbd Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Tue, 24 Dec 2024 17:19:52 +0100 Subject: [PATCH 1/9] DOCS(ice): Document how to mark read-only access functions --- docs/dev/ExtendingTheIceInterface.md | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/dev/ExtendingTheIceInterface.md b/docs/dev/ExtendingTheIceInterface.md index 3ee879db950..21ca58a6ce1 100644 --- a/docs/dev/ExtendingTheIceInterface.md +++ b/docs/dev/ExtendingTheIceInterface.md @@ -13,8 +13,8 @@ The files involved in extending the Ice interface are | `MumbleServer.cpp` | Contains some boilerplate and Ice-internal implementation code. This file is automatically generated. | | `MumbleServerI.h` | Contains the definition of the actually implemented API classes (`ServerI` and `MetaI`). These extend the abstract base classes from `MumbleServer.h` | | `MumbleServerWrapper.cpp` | Contains wrapper implementation of the `*I` API classes. This file is automatically generated. | -| `MumbleServere.h` | Contains the definition of a statically used helper class | -| `MumbleServere.cpp` | Contains the implementation of that helper class **and** _static_ functions used to actually implement the server-side functionality of the Ice API functions | +| `MumbleServer.h` | Contains the definition of a statically used helper class | +| `MumbleServer.cpp` | Contains the implementation of that helper class **and** _static_ functions used to actually implement the server-side functionality of the Ice API functions | | `RPC.cpp` | Contains the implementations of the `Server` (the Mumble server, _not_ the Ice API type) class's member functions that are required to make certain functionality accessible to the static functions in `MumbleServerIce.cpp` | All auto-generated functions will end up in the corresponding directory inside the `build` directory. @@ -62,10 +62,26 @@ Error reporting works via the `cb->ice_exception` function and if everything wen In general it is a good idea to have a look at the existing implementation inside `MumbleServerIce.cpp` and take inspiration from those. Note that the implementations make heavy use of macros (e.g. `NEED_SERVER`, `NEED_CHANNEL`, etc.). These will initialize the corresponding variables -(`server`, `channel`, etc.) based in the parameters fed into the function (In order to obtain the channel, user, etc. you always have to initialize +(`server`, `channel`, etc.) based on the parameters fed into the function (In order to obtain the channel, user, etc. you always have to initialize the `server` variable first). For this to work it is essential that you are using the same parameter names as the existing implementations (e.g. `server_id` for the server's ID). (For historical reasons the macro to obtain the `user` variable is called `NEED_PLAYER`) +Furthermore, you might notice the macro definitions like `ACCESS_Server_isListening_READ`. These are used to determine what kind of access privilege +execution of the associated Ice function is required. By default, all functions are assumed to require write-privilege in order to be able to be +executed. The general form of these macros is +``` +ACCESS___ +``` +where +- `` and `` are used as defined above. They define which function this macro will be associated with. +- `` is the required access privilege. Possible values are `READ` and `ALL`, which allow function execution by anyone who has + read-privilege or simply everyone, regardless of their privileges. +The actual implementation of the access privilege checking is performed in the auto-generated `MumbleServerIceWrapper.cpp` based on whether an +associated macro is defined and if so, which one. +Please remember to `#undef` the respective macro at the end of the `MumbleServerIce.cpp` file in order to avoid macro definitions spilling into other +files when using unity builds. + + If the function requires action on the server's side (beyond its public API), you have to declare a new public function in the `Server` class (this time the Mumble server though; not the Ice server class) defined in `Server.h` (the definitions belong to the group of other RPC functions in there - section marked by a comment). The implementation of this new function should then be written in `RPC.cpp`. From e56f7d37c6e51909ee8fabc7e6b628319637215a Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Tue, 24 Dec 2024 17:21:38 +0100 Subject: [PATCH 2/9] MAINT: Add stringify functions for package type enums --- src/MumbleProtocol.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++ src/MumbleProtocol.h | 8 +++++++ 2 files changed, 55 insertions(+) diff --git a/src/MumbleProtocol.cpp b/src/MumbleProtocol.cpp index a3f162e250d..d8fe9b9bc36 100644 --- a/src/MumbleProtocol.cpp +++ b/src/MumbleProtocol.cpp @@ -17,6 +17,53 @@ namespace Mumble { namespace Protocol { + std::string messageTypeName(TCPMessageType type) { +#define PROCESS_MUMBLE_TCP_MESSAGE(name, value) \ + case TCPMessageType::name: \ + return #name; + + switch (type) { MUMBLE_ALL_TCP_MESSAGES } + +#undef PROCESS_MUMBLE_TCP_MESSAGE + + // Should be unreachable + assert(false); + return "Unknown"; + } + + std::string messageTypeName(UDPMessageType type) { +#define PROCESS_MUMBLE_UDP_MESSAGE(name, value) \ + case UDPMessageType::name: \ + return #name; + + switch (type) { MUMBLE_ALL_UDP_MESSAGES } + +#undef PROCESS_MUMBLE_UDP_MESSAGE + + // Should be unreachable + assert(false); + return "Unknown"; + } + + std::string messageTypeName(LegacyUDPMessageType type) { + switch (type) { + case LegacyUDPMessageType::VoiceCELTAlpha: + return "VoiceCELTAlpha"; + case LegacyUDPMessageType::Ping: + return "Ping"; + case LegacyUDPMessageType::VoiceSpeex: + return "VoiceSpeex"; + case LegacyUDPMessageType::VoiceCELTBeta: + return "VoiceCELTBeta"; + case LegacyUDPMessageType::VoiceOpus: + return "VoiceOpus"; + } + + // Should be unreachable + assert(false); + return "Unknown"; + } + bool protocolVersionsAreCompatible(Version::full_t lhs, Version::full_t rhs) { // At this point the protocol version only makes a difference between pre-protobuf and post-protobuf return (lhs < PROTOBUF_INTRODUCTION_VERSION) == (rhs < PROTOBUF_INTRODUCTION_VERSION); diff --git a/src/MumbleProtocol.h b/src/MumbleProtocol.h index 29543cc3de4..2168f9771b6 100644 --- a/src/MumbleProtocol.h +++ b/src/MumbleProtocol.h @@ -11,6 +11,7 @@ #include "VolumeAdjustment.h" #include +#include #include #include @@ -72,6 +73,9 @@ namespace Protocol { */ enum class TCPMessageType : byte { MUMBLE_ALL_TCP_MESSAGES }; #undef PROCESS_MUMBLE_TCP_MESSAGE + + std::string messageTypeName(TCPMessageType type); + #define PROCESS_MUMBLE_UDP_MESSAGE(name, value) name = value, /** * Enum holding all possible UDP message types @@ -79,8 +83,12 @@ namespace Protocol { enum class UDPMessageType : byte { MUMBLE_ALL_UDP_MESSAGES }; #undef PROCESS_MUMBLE_UDP_MESSAGE + std::string messageTypeName(UDPMessageType type); + enum class LegacyUDPMessageType : byte { VoiceCELTAlpha, Ping, VoiceSpeex, VoiceCELTBeta, VoiceOpus }; + std::string messageTypeName(LegacyUDPMessageType type); + enum class AudioCodec { Opus, CELT_Alpha, // 0.7.0 From cd114ab69808571db032fe934587cf740f524ec6 Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Tue, 24 Dec 2024 17:25:37 +0100 Subject: [PATCH 3/9] MAINT(ice): Add missing exception specifications --- src/murmur/MumbleServer.ice | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/murmur/MumbleServer.ice b/src/murmur/MumbleServer.ice index f971618511a..512a34028f3 100644 --- a/src/murmur/MumbleServer.ice +++ b/src/murmur/MumbleServer.ice @@ -798,52 +798,52 @@ module MumbleServer * @param userid The ID of the user * @param channelid The ID of the channel */ - idempotent void startListening(int userid, int channelid); + idempotent void startListening(int userid, int channelid) throws ServerBootedException, InvalidUserException; /** * Makes the given user stop listening to the given channel. * @param userid The ID of the user * @param channelid The ID of the channel */ - idempotent void stopListening(int userid, int channelid); + idempotent void stopListening(int userid, int channelid) throws ServerBootedException, InvalidUserException; /** * @param userid The ID of the user * @param channelid The ID of the channel * @returns Whether the given user is currently listening to the given channel */ - idempotent bool isListening(int userid, int channelid); + idempotent bool isListening(int userid, int channelid) throws ServerBootedException, InvalidUserException, InvalidSecretException; /** * @param userid The ID of the user * @returns An ID-list of channels the given user is listening to */ - idempotent IntList getListeningChannels(int userid); + idempotent IntList getListeningChannels(int userid) throws ServerBootedException, InvalidSecretException, InvalidUserException; /** * @param channelid The ID of the channel * @returns An ID-list of users listening to the given channel */ - idempotent IntList getListeningUsers(int channelid); + idempotent IntList getListeningUsers(int channelid) throws ServerBootedException, InvalidSecretException, InvalidChannelException; /** * @param channelid The ID of the channel * @param userid The ID of the user * @returns The volume adjustment set for a listener of the given user in the given channel */ - idempotent float getListenerVolumeAdjustment(int channelid, int userid); + idempotent float getListenerVolumeAdjustment(int channelid, int userid) throws ServerBootedException, InvalidUserException, InvalidChannelException; /** * Sets the volume adjustment set for a listener of the given user in the given channel * @param channelid The ID of the channel * @param userid The ID of the user */ - idempotent void setListenerVolumeAdjustment(int channelid, int userid, float volumeAdjustment); + idempotent void setListenerVolumeAdjustment(int channelid, int userid, float volumeAdjustment) throws ServerBootedException, InvalidSecretException, InvalidChannelException, InvalidUserException; /** * @param receiverUserIDs list of IDs of the users the message shall be sent to */ - idempotent void sendWelcomeMessage(IdList receiverUserIDs); + idempotent void sendWelcomeMessage(IdList receiverUserIDs) throws ServerBootedException, InvalidSecretException, InvalidUserException; }; /** Callback interface for Meta. You can supply an implementation of this to receive notifications From 56742152e1031257977f9a9f95fde6b780351b36 Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Tue, 24 Dec 2024 17:29:17 +0100 Subject: [PATCH 4/9] FIX(ice): Mark channel listener getter functions as read-only accessible --- src/murmur/MumbleServerIce.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/murmur/MumbleServerIce.cpp b/src/murmur/MumbleServerIce.cpp index cb6477eb4fd..7f15a047758 100644 --- a/src/murmur/MumbleServerIce.cpp +++ b/src/murmur/MumbleServerIce.cpp @@ -1753,6 +1753,7 @@ static void impl_Server_stopListening(const ::MumbleServer::AMD_Server_stopListe cb->ice_response(); } +#define ACCESS_Server_isListening_READ static void impl_Server_isListening(const ::MumbleServer::AMD_Server_isListeningPtr cb, int server_id, int session, int channelid) { NEED_SERVER; @@ -1762,6 +1763,7 @@ static void impl_Server_isListening(const ::MumbleServer::AMD_Server_isListening cb->ice_response(server->m_channelListenerManager.isListening(user->uiSession, channel->iId)); } +#define ACCESS_Server_getListeningChannels_READ static void impl_Server_getListeningChannels(const ::MumbleServer::AMD_Server_getListeningChannelsPtr cb, int server_id, int session) { NEED_SERVER; @@ -1775,6 +1777,7 @@ static void impl_Server_getListeningChannels(const ::MumbleServer::AMD_Server_ge cb->ice_response(channelIDs); } +#define ACCESS_Server_getListeningUsers_READ static void impl_Server_getListeningUsers(const ::MumbleServer::AMD_Server_getListeningUsersPtr cb, int server_id, int channelid) { NEED_SERVER; @@ -1801,6 +1804,7 @@ static void impl_Server_sendWelcomeMessage(const ::MumbleServer::AMD_Server_send cb->ice_response(); } +#define ACCESS_Server_getListenerVolumeAdjustment_READ static void impl_Server_getListenerVolumeAdjustment(const ::MumbleServer::AMD_Server_getListenerVolumeAdjustmentPtr cb, int server_id, int channelid, int session) { NEED_SERVER; @@ -2019,6 +2023,10 @@ static void impl_Meta_getUptime(const ::MumbleServer::AMD_Meta_getUptimePtr cb, #undef ACCESS_Server_verifyPassword_READ #undef ACCESS_Server_getTexture_READ #undef ACCESS_Server_getUptime_READ +#undef ACCESS_Server_isListening_READ +#undef ACCESS_Server_getListeningChannels_READ +#undef ACCESS_Server_getListeningUsers_READ +#undef ACCESS_Server_getListenerVolumeAdjustment_READ #undef ACCESS_Meta_getSliceChecksums_ALL #undef ACCESS_Meta_getServer_READ #undef ACCESS_Meta_getAllServers_READ From 84214be30c18e0c72c06a249649e6cd765a2485c Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Tue, 24 Dec 2024 17:31:04 +0100 Subject: [PATCH 5/9] FIX(ice): Throw ServerBootedException instead of ObjectNotExistException --- src/murmur/MumbleServerIce.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/murmur/MumbleServerIce.cpp b/src/murmur/MumbleServerIce.cpp index 7f15a047758..cc5d50bf862 100644 --- a/src/murmur/MumbleServerIce.cpp +++ b/src/murmur/MumbleServerIce.cpp @@ -849,7 +849,7 @@ Ice::ObjectPtr ServerLocator::locate(const Ice::Current &, Ice::LocalObjectPtr & } #define NEED_SERVER \ - NEED_SERVER_EXISTS \ + FIND_SERVER \ if (!server) { \ cb->ice_exception(ServerBootedException()); \ return; \ From 4fc312a599751d5e3880e963f3b173136a539ab7 Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Tue, 24 Dec 2024 17:35:05 +0100 Subject: [PATCH 6/9] FIX(ice): Don't throw exception if calling isRunning on unbooted server --- src/murmur/MumbleServerIce.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/murmur/MumbleServerIce.cpp b/src/murmur/MumbleServerIce.cpp index cc5d50bf862..d43b59216f0 100644 --- a/src/murmur/MumbleServerIce.cpp +++ b/src/murmur/MumbleServerIce.cpp @@ -882,7 +882,7 @@ void ServerI::ice_ping(const Ice::Current ¤t) const { #define ACCESS_Server_isRunning_READ static void impl_Server_isRunning(const ::MumbleServer::AMD_Server_isRunningPtr cb, int server_id) { - NEED_SERVER_EXISTS; + FIND_SERVER; cb->ice_response(server != nullptr); } From fa1ff6984b8e38baccd272e61d1a712ff3103ccb Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Tue, 24 Dec 2024 17:35:42 +0100 Subject: [PATCH 7/9] FIX(ice): Remove unnecessary DB call for Server::id() The parameter with the server-ID is not user-provided but rather an implicit parameter identifying the Server object the function is called on (handled by the Ice backend). Therefore, it can be assumed that this ID belongs to a valid server. This makes an explicit check superfluous and since this check may even require a database lookup, it has been removed. Instead, the passed server ID is assumed to be correct and therefore returned as-is. --- src/murmur/MumbleServerIce.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/murmur/MumbleServerIce.cpp b/src/murmur/MumbleServerIce.cpp index d43b59216f0..464688b2342 100644 --- a/src/murmur/MumbleServerIce.cpp +++ b/src/murmur/MumbleServerIce.cpp @@ -970,7 +970,6 @@ static void impl_Server_setAuthenticator(const ::MumbleServer::AMD_Server_setAut #define ACCESS_Server_id_READ static void impl_Server_id(const ::MumbleServer::AMD_Server_idPtr cb, int server_id) { - NEED_SERVER_EXISTS; cb->ice_response(server_id); } From 6969661eef5355aaa5723550db130793bc060c81 Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Tue, 24 Dec 2024 17:38:43 +0100 Subject: [PATCH 8/9] FEAT(server): Allow running while DB is in read-only mode Note that the server's feature set is reduced to the absolute minimum and most requests to the server will simply be dropped. Only users that have already been on the server when it entered this mode will be able to stay on the server and keep talking to each other. No new connections will be accepted and nobody can move channels or perform any other noteworthy actions (except writing text messages, which will still work). This mode is explicitly meant to be used only for short periods of time that might be needed to perform a database backup etc. --- src/Mumble.proto | 2 + src/murmur/DBState.h | 17 ++++++++ src/murmur/Meta.h | 3 ++ src/murmur/MumbleServer.ice | 67 ++++++++++++++++++------------ src/murmur/MumbleServerI.h | 7 ++++ src/murmur/MumbleServerIce.cpp | 75 ++++++++++++++++++++++++++++++++++ src/murmur/Server.cpp | 51 ++++++++++++++++++++++- 7 files changed, 194 insertions(+), 28 deletions(-) create mode 100644 src/murmur/DBState.h diff --git a/src/Mumble.proto b/src/Mumble.proto index 169c18a6925..614da4c66c5 100644 --- a/src/Mumble.proto +++ b/src/Mumble.proto @@ -96,6 +96,8 @@ message Reject { // The user did not provide a certificate but one is required. NoCertificate = 7; AuthenticatorFail = 8; + // The server is currently not accepting new connections + NoNewConnections = 9; } // Rejection type. optional RejectType type = 1; diff --git a/src/murmur/DBState.h b/src/murmur/DBState.h new file mode 100644 index 00000000000..4a62509187f --- /dev/null +++ b/src/murmur/DBState.h @@ -0,0 +1,17 @@ +// Copyright The Mumble Developers. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file at the root of the +// Mumble source tree or at . + +#ifndef MUMBLE_MURMUR_DBSTATE_H_ +#define MUMBLE_MURMUR_DBSTATE_H_ + +/** + * Possible states the database can be in + */ +enum class DBState { + Normal, + ReadOnly, +}; + +#endif // MUMBLE_MURMUR_DBSTATE_H_ diff --git a/src/murmur/Meta.h b/src/murmur/Meta.h index 4a151506e74..3329d75a4b0 100644 --- a/src/murmur/Meta.h +++ b/src/murmur/Meta.h @@ -8,6 +8,7 @@ #include "Timer.h" +#include "DBState.h" #include "Version.h" #ifdef Q_OS_WIN @@ -184,6 +185,8 @@ class Meta : public QObject { QString qsOS, qsOSVersion; Timer tUptime; + DBState assumedDBState = DBState::Normal; + #ifdef Q_OS_WIN static HANDLE hQoS; #endif diff --git a/src/murmur/MumbleServer.ice b/src/murmur/MumbleServer.ice index 512a34028f3..13bd72ead4b 100644 --- a/src/murmur/MumbleServer.ice +++ b/src/murmur/MumbleServer.ice @@ -264,6 +264,9 @@ module MumbleServer UserList users; }; + /** Different states of the underlying database */ + enum DBState { Normal, ReadOnly }; + exception MurmurException {}; /** This is thrown when you specify an invalid session. This may happen if the user has disconnected since your last call to {@link Server.getUsers}. See {@link User.session} */ exception InvalidSessionException extends MurmurException {}; @@ -289,6 +292,8 @@ module MumbleServer exception WriteOnlyException extends MurmurException {}; /** This is thrown when invalid input data was specified. */ exception InvalidInputDataException extends MurmurException {}; + /** This is thrown when the server has its database in read-only mode and whatever you requested is incompatible with that. */ + exception ReadOnlyModeException extends MurmurException {}; /** Callback interface for servers. You can supply an implementation of this to receive notification * messages from the server. @@ -468,16 +473,16 @@ module MumbleServer idempotent bool isRunning() throws InvalidSecretException; /** Start server. */ - void start() throws ServerBootedException, ServerFailureException, InvalidSecretException; + void start() throws ServerBootedException, ServerFailureException, InvalidSecretException, ReadOnlyModeException; /** Stop server. * Note: Server will be restarted on Murmur restart unless explicitly disabled * with setConf("boot", false) */ - void stop() throws ServerBootedException, InvalidSecretException; + void stop() throws ServerBootedException, InvalidSecretException, ReadOnlyModeException; /** Delete server and all it's configuration. */ - void delete() throws ServerBootedException, InvalidSecretException; + void delete() throws ServerBootedException, InvalidSecretException, ReadOnlyModeException; /** Fetch the server id. * @@ -504,41 +509,41 @@ module MumbleServer * * @param auth Authenticator object to perform subsequent authentications. */ - void setAuthenticator(ServerAuthenticator *auth) throws ServerBootedException, InvalidCallbackException, InvalidSecretException; + void setAuthenticator(ServerAuthenticator *auth) throws ServerBootedException, InvalidCallbackException, InvalidSecretException, ReadOnlyModeException; /** Retrieve configuration item. * @param key Configuration key. * @return Configuration value. If this is empty, see {@link Meta.getDefaultConf} */ - idempotent string getConf(string key) throws InvalidSecretException, WriteOnlyException; + idempotent string getConf(string key) throws InvalidSecretException, WriteOnlyException, ReadOnlyModeException; /** Retrieve all configuration items. * @return All configured values. If a value isn't set here, the value from {@link Meta.getDefaultConf} is used. */ - idempotent ConfigMap getAllConf() throws InvalidSecretException; + idempotent ConfigMap getAllConf() throws InvalidSecretException, ReadOnlyModeException; /** Set a configuration item. * @param key Configuration key. * @param value Configuration value. */ - idempotent void setConf(string key, string value) throws InvalidSecretException; + idempotent void setConf(string key, string value) throws InvalidSecretException, ReadOnlyModeException; /** Set superuser password. This is just a convenience for using {@link updateRegistration} on user id 0. * @param pw Password. */ - idempotent void setSuperuserPassword(string pw) throws InvalidSecretException; + idempotent void setSuperuserPassword(string pw) throws InvalidSecretException, ReadOnlyModeException; /** Fetch log entries. * @param first Lowest numbered entry to fetch. 0 is the most recent item. * @param last Last entry to fetch. * @return List of log entries. */ - idempotent LogList getLog(int first, int last) throws InvalidSecretException; + idempotent LogList getLog(int first, int last) throws InvalidSecretException, ReadOnlyModeException; /** Fetch length of log * @return Number of entries in log */ - idempotent int getLogLen() throws InvalidSecretException; + idempotent int getLogLen() throws InvalidSecretException, ReadOnlyModeException; /** Fetch all users. This returns all currently connected users on the server. * @return List of connected users. @@ -573,7 +578,7 @@ module MumbleServer * append to the returned list before calling this method. * @param bans List of bans. */ - idempotent void setBans(BanList bans) throws ServerBootedException, InvalidSecretException; + idempotent void setBans(BanList bans) throws ServerBootedException, InvalidSecretException, ReadOnlyModeException; /** Kick a user. The user is not banned, and is free to rejoin the server. * @param session Connection ID of user. See {@link User.session}. @@ -647,19 +652,19 @@ module MumbleServer * @param state Channel state to set. * @see getChannelState */ - idempotent void setChannelState(Channel state) throws ServerBootedException, InvalidChannelException, InvalidSecretException, NestingLimitException; + idempotent void setChannelState(Channel state) throws ServerBootedException, InvalidChannelException, InvalidSecretException, NestingLimitException, ReadOnlyModeException; /** Remove a channel and all its subchannels. * @param channelid ID of Channel. See {@link Channel.id}. */ - void removeChannel(int channelid) throws ServerBootedException, InvalidChannelException, InvalidSecretException; + void removeChannel(int channelid) throws ServerBootedException, InvalidChannelException, InvalidSecretException, ReadOnlyModeException; /** Add a new channel. * @param name Name of new channel. * @param parent Channel ID of parent channel. See {@link Channel.id}. * @return ID of newly created channel. */ - int addChannel(string name, int parent) throws ServerBootedException, InvalidChannelException, InvalidSecretException, NestingLimitException; + int addChannel(string name, int parent) throws ServerBootedException, InvalidChannelException, InvalidSecretException, NestingLimitException, ReadOnlyModeException; /** Send text message to channel or a tree of channels. * @param channelid Channel ID of channel to send to. See {@link Channel.id}. @@ -683,7 +688,7 @@ module MumbleServer * @param groups List of groups on the channel. * @param inherit Should this channel inherit ACLs from the parent channel? */ - idempotent void setACL(int channelid, ACLList acls, GroupList groups, bool inherit) throws ServerBootedException, InvalidChannelException, InvalidSecretException; + idempotent void setACL(int channelid, ACLList acls, GroupList groups, bool inherit) throws ServerBootedException, InvalidChannelException, InvalidSecretException, ReadOnlyModeException; /** Temporarily add a user to a group on a channel. This state is not saved, and is intended for temporary memberships. * @param channelid Channel ID of channel to add to. See {@link Channel.id}. @@ -723,37 +728,37 @@ module MumbleServer * @param info Information about new user. Must include at least "name". * @return The ID of the user. See {@link RegisteredUser.userid}. */ - int registerUser(UserInfoMap info) throws ServerBootedException, InvalidUserException, InvalidSecretException; + int registerUser(UserInfoMap info) throws ServerBootedException, InvalidUserException, InvalidSecretException, ReadOnlyModeException; /** Remove a user registration. * @param userid ID of registered user. See {@link RegisteredUser.userid}. */ - void unregisterUser(int userid) throws ServerBootedException, InvalidUserException, InvalidSecretException; + void unregisterUser(int userid) throws ServerBootedException, InvalidUserException, InvalidSecretException, ReadOnlyModeException; /** Update the registration for a user. You can use this to set the email or password of a user, * and can also use it to change the user's name. * @param registration Updated registration record. */ - idempotent void updateRegistration(int userid, UserInfoMap info) throws ServerBootedException, InvalidUserException, InvalidSecretException; + idempotent void updateRegistration(int userid, UserInfoMap info) throws ServerBootedException, InvalidUserException, InvalidSecretException, ReadOnlyModeException; /** Fetch registration for a single user. * @param userid ID of registered user. See {@link RegisteredUser.userid}. * @return Registration record. */ - idempotent UserInfoMap getRegistration(int userid) throws ServerBootedException, InvalidUserException, InvalidSecretException; + idempotent UserInfoMap getRegistration(int userid) throws ServerBootedException, InvalidUserException, InvalidSecretException, ReadOnlyModeException; /** Fetch a group of registered users. * @param filter Substring of user name. If blank, will retrieve all registered users. * @return List of registration records. */ - idempotent NameMap getRegisteredUsers(string filter) throws ServerBootedException, InvalidSecretException; + idempotent NameMap getRegisteredUsers(string filter) throws ServerBootedException, InvalidSecretException, ReadOnlyModeException; /** Verify the password of a user. You can use this to verify a user's credentials. * @param name User name. See {@link RegisteredUser.name}. * @param pw User password. * @return User ID of registered user (See {@link RegisteredUser.userid}), -1 for failed authentication or -2 for unknown usernames. */ - idempotent int verifyPassword(string name, string pw) throws ServerBootedException, InvalidSecretException; + idempotent int verifyPassword(string name, string pw) throws ServerBootedException, InvalidSecretException, ReadOnlyModeException; /** Fetch user texture. Textures are stored as zlib compress()ed 600x60 32-bit BGRA data. * @param userid ID of registered user. See {@link RegisteredUser.userid}. @@ -765,7 +770,7 @@ module MumbleServer * @param userid ID of registered user. See {@link RegisteredUser.userid}. * @param tex Texture (as a Byte-Array) to set for the user, or an empty texture to remove the existing texture. */ - idempotent void setTexture(int userid, Texture tex) throws ServerBootedException, InvalidUserException, InvalidTextureException, InvalidSecretException; + idempotent void setTexture(int userid, Texture tex) throws ServerBootedException, InvalidUserException, InvalidTextureException, InvalidSecretException, ReadOnlyModeException; /** Get virtual server uptime. * @return Uptime of the virtual server in seconds @@ -791,21 +796,21 @@ module MumbleServer * - The certificate and/or private key do not contain RSA keys. * - The certificate is not usable with the given private key. */ - idempotent void updateCertificate(string certificate, string privateKey, string passphrase) throws ServerBootedException, InvalidSecretException, InvalidInputDataException; + idempotent void updateCertificate(string certificate, string privateKey, string passphrase) throws ServerBootedException, InvalidSecretException, InvalidInputDataException, ReadOnlyModeException; /** * Makes the given user start listening to the given channel. * @param userid The ID of the user * @param channelid The ID of the channel */ - idempotent void startListening(int userid, int channelid) throws ServerBootedException, InvalidUserException; + idempotent void startListening(int userid, int channelid) throws ServerBootedException, InvalidUserException, ReadOnlyModeException; /** * Makes the given user stop listening to the given channel. * @param userid The ID of the user * @param channelid The ID of the channel */ - idempotent void stopListening(int userid, int channelid) throws ServerBootedException, InvalidUserException; + idempotent void stopListening(int userid, int channelid) throws ServerBootedException, InvalidUserException, ReadOnlyModeException; /** * @param userid The ID of the user @@ -838,7 +843,7 @@ module MumbleServer * @param channelid The ID of the channel * @param userid The ID of the user */ - idempotent void setListenerVolumeAdjustment(int channelid, int userid, float volumeAdjustment) throws ServerBootedException, InvalidSecretException, InvalidChannelException, InvalidUserException; + idempotent void setListenerVolumeAdjustment(int channelid, int userid, float volumeAdjustment) throws ServerBootedException, InvalidSecretException, InvalidChannelException, InvalidUserException, ReadOnlyModeException; /** * @param receiverUserIDs list of IDs of the users the message shall be sent to @@ -937,5 +942,15 @@ module MumbleServer * @return Checksum dict */ idempotent Ice::SliceChecksumDict getSliceChecksums(); + + /** + * @returns The state the underlying database is currently assumed to be in + */ + idempotent DBState getAssumedDatabaseState() throws InvalidSecretException; + + /** + * Sets the assumed state of the underlying database + */ + idempotent void setAssumedDatabaseState(DBState state) throws InvalidSecretException, ReadOnlyModeException; }; }; diff --git a/src/murmur/MumbleServerI.h b/src/murmur/MumbleServerI.h index f2ea1254587..ecfd892752d 100644 --- a/src/murmur/MumbleServerI.h +++ b/src/murmur/MumbleServerI.h @@ -199,6 +199,13 @@ class MetaI : virtual public Meta { virtual void getUptime_async(const ::MumbleServer::AMD_Meta_getUptimePtr &, const Ice::Current &); virtual void getSlice_async(const ::MumbleServer::AMD_Meta_getSlicePtr &, const Ice::Current &); + + virtual void getAssumedDatabaseState_async(const ::MumbleServer::AMD_Meta_getAssumedDatabaseStatePtr &, + const ::Ice::Current &); + + virtual void setAssumedDatabaseState_async(const ::MumbleServer::AMD_Meta_setAssumedDatabaseStatePtr &, + ::MumbleServer::DBState state, + const ::Ice::Current & = ::Ice::Current()); }; } // namespace MumbleServer diff --git a/src/murmur/MumbleServerIce.cpp b/src/murmur/MumbleServerIce.cpp index 464688b2342..f2c3647f144 100644 --- a/src/murmur/MumbleServerIce.cpp +++ b/src/murmur/MumbleServerIce.cpp @@ -8,6 +8,7 @@ #include "Ban.h" #include "Channel.h" #include "ChannelListenerManager.h" +#include "DBState.h" #include "Group.h" #include "Meta.h" #include "MumbleServer.h" @@ -28,6 +29,7 @@ #include #include +#include #include using namespace std; @@ -221,6 +223,30 @@ static void textmessageToTextmessage(const ::TextMessage &tm, ::MumbleServer::Te tmdst.trees.push_back(static_cast< int >(i)); } +::MumbleServer::DBState dbstateToDBState(::DBState state) { + switch (state) { + case ::DBState::Normal: + return ::MumbleServer::DBState::Normal; + case ::DBState::ReadOnly: + return ::MumbleServer::DBState::ReadOnly; + } + + assert(false); + return ::MumbleServer::DBState::Normal; +} + +::DBState dbstateToDBState(::MumbleServer::DBState state) { + switch (state) { + case ::MumbleServer::DBState::Normal: + return ::DBState::Normal; + case ::MumbleServer::DBState::ReadOnly: + return ::DBState::ReadOnly; + } + + assert(false); + return ::DBState::Normal; +} + class ServerLocator : public virtual Ice::ServantLocator { public: virtual Ice::ObjectPtr locate(const Ice::Current &, Ice::LocalObjectPtr &); @@ -873,6 +899,12 @@ Ice::ObjectPtr ServerLocator::locate(const Ice::Current &, Ice::LocalObjectPtr & ::Channel *channel; \ NEED_CHANNEL_VAR(channel, channelid); +#define VERIFY_DB_NOT_IN_READONLY \ + if (meta->assumedDBState == ::DBState::ReadOnly) { \ + cb->ice_exception(ReadOnlyModeException()); \ + return; \ + } + void ServerI::ice_ping(const Ice::Current ¤t) const { // This is executed in the ice thread. int server_id = u8(current.id.name).toInt(); @@ -887,6 +919,7 @@ static void impl_Server_isRunning(const ::MumbleServer::AMD_Server_isRunningPtr } static void impl_Server_start(const ::MumbleServer::AMD_Server_startPtr cb, int server_id) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER_EXISTS; if (server) cb->ice_exception(ServerBootedException()); @@ -897,12 +930,14 @@ static void impl_Server_start(const ::MumbleServer::AMD_Server_startPtr cb, int } static void impl_Server_stop(const ::MumbleServer::AMD_Server_stopPtr cb, int server_id) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; meta->kill(server_id); cb->ice_response(); } static void impl_Server_delete(const ::MumbleServer::AMD_Server_deletePtr cb, int server_id) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER_EXISTS; if (server) { cb->ice_exception(ServerBootedException()); @@ -942,6 +977,7 @@ static void impl_Server_removeCallback(const MumbleServer::AMD_Server_removeCall static void impl_Server_setAuthenticator(const ::MumbleServer::AMD_Server_setAuthenticatorPtr &cb, int server_id, const ::MumbleServer::ServerAuthenticatorPrx &aptr) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; if (mi->getServerAuthenticator(server)) @@ -976,6 +1012,7 @@ static void impl_Server_id(const ::MumbleServer::AMD_Server_idPtr cb, int server #define ACCESS_Server_getConf_READ static void impl_Server_getConf(const ::MumbleServer::AMD_Server_getConfPtr cb, int server_id, const ::std::string &key) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER_EXISTS; if (key == "key" || key == "passphrase") cb->ice_exception(WriteOnlyException()); @@ -985,6 +1022,7 @@ static void impl_Server_getConf(const ::MumbleServer::AMD_Server_getConfPtr cb, #define ACCESS_Server_getAllConf_READ static void impl_Server_getAllConf(const ::MumbleServer::AMD_Server_getAllConfPtr cb, int server_id) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER_EXISTS; ::MumbleServer::ConfigMap cm; @@ -1001,6 +1039,7 @@ static void impl_Server_getAllConf(const ::MumbleServer::AMD_Server_getAllConfPt static void impl_Server_setConf(const ::MumbleServer::AMD_Server_setConfPtr cb, int server_id, const ::std::string &key, const ::std::string &value) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER_EXISTS; QString k = u8(key); QString v = u8(value); @@ -1014,6 +1053,7 @@ static void impl_Server_setConf(const ::MumbleServer::AMD_Server_setConfPtr cb, static void impl_Server_setSuperuserPassword(const ::MumbleServer::AMD_Server_setSuperuserPasswordPtr cb, int server_id, const ::std::string &pw) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER_EXISTS; ServerDB::setSUPW(server_id, u8(pw)); cb->ice_response(); @@ -1022,6 +1062,7 @@ static void impl_Server_setSuperuserPassword(const ::MumbleServer::AMD_Server_se #define ACCESS_Server_getLog_READ static void impl_Server_getLog(const ::MumbleServer::AMD_Server_getLogPtr cb, int server_id, ::Ice::Int min, ::Ice::Int max) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER_EXISTS; ::MumbleServer::LogList ll; @@ -1038,6 +1079,7 @@ static void impl_Server_getLog(const ::MumbleServer::AMD_Server_getLogPtr cb, in #define ACCESS_Server_getLogLen_READ static void impl_Server_getLogLen(const ::MumbleServer::AMD_Server_getLogLenPtr cb, int server_id) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER_EXISTS; int len = ServerDB::getLogLen(server_id); @@ -1141,6 +1183,7 @@ static void impl_Server_getBans(const ::MumbleServer::AMD_Server_getBansPtr cb, static void impl_Server_setBans(const ::MumbleServer::AMD_Server_setBansPtr cb, int server_id, const ::MumbleServer::BanList &bans) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; { QWriteLocker wl(&server->qrwlVoiceThread); @@ -1317,6 +1360,8 @@ static void impl_Server_getChannelState(const ::MumbleServer::AMD_Server_getChan static void impl_Server_setChannelState(const ::MumbleServer::AMD_Server_setChannelStatePtr cb, int server_id, const ::MumbleServer::Channel &state) { + VERIFY_DB_NOT_IN_READONLY; + int channelid = state.id; NEED_SERVER; NEED_CHANNEL; @@ -1347,6 +1392,7 @@ static void impl_Server_setChannelState(const ::MumbleServer::AMD_Server_setChan static void impl_Server_removeChannel(const ::MumbleServer::AMD_Server_removeChannelPtr cb, int server_id, ::Ice::Int channelid) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; NEED_CHANNEL; @@ -1360,6 +1406,7 @@ static void impl_Server_removeChannel(const ::MumbleServer::AMD_Server_removeCha static void impl_Server_addChannel(const ::MumbleServer::AMD_Server_addChannelPtr cb, int server_id, const ::std::string &name, ::Ice::Int parent) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; ::Channel *p, *nc; NEED_CHANNEL_VAR(p, parent); @@ -1455,6 +1502,7 @@ static void impl_Server_getACL(const ::MumbleServer::AMD_Server_getACLPtr cb, in static void impl_Server_setACL(const ::MumbleServer::AMD_Server_setACLPtr cb, int server_id, ::Ice::Int channelid, const ::MumbleServer::ACLList &acls, const ::MumbleServer::GroupList &groups, bool inherit) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; NEED_CHANNEL; @@ -1527,6 +1575,7 @@ static void impl_Server_getUserIds(const ::MumbleServer::AMD_Server_getUserIdsPt static void impl_Server_registerUser(const ::MumbleServer::AMD_Server_registerUserPtr cb, int server_id, const ::MumbleServer::UserInfoMap &im) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; QMap< int, QString > info; @@ -1542,6 +1591,7 @@ static void impl_Server_registerUser(const ::MumbleServer::AMD_Server_registerUs static void impl_Server_unregisterUser(const ::MumbleServer::AMD_Server_unregisterUserPtr cb, int server_id, ::Ice::Int userid) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; bool success = server->unregisterUser(userid); @@ -1555,6 +1605,7 @@ static void impl_Server_unregisterUser(const ::MumbleServer::AMD_Server_unregist static void impl_Server_updateRegistration(const ::MumbleServer::AMD_Server_updateRegistrationPtr cb, int server_id, int id, const ::MumbleServer::UserInfoMap &im) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; if (!server->isUserId(id)) { @@ -1584,6 +1635,7 @@ static void impl_Server_updateRegistration(const ::MumbleServer::AMD_Server_upda #define ACCESS_Server_getRegistration_READ static void impl_Server_getRegistration(const ::MumbleServer::AMD_Server_getRegistrationPtr cb, int server_id, ::Ice::Int userid) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; QMap< int, QString > info = server->getRegistration(userid); @@ -1601,6 +1653,7 @@ static void impl_Server_getRegistration(const ::MumbleServer::AMD_Server_getRegi #define ACCESS_Server_getRegisteredUsers_READ static void impl_Server_getRegisteredUsers(const ::MumbleServer::AMD_Server_getRegisteredUsersPtr cb, int server_id, const ::std::string &filter) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; MumbleServer::NameMap rpl; @@ -1616,6 +1669,7 @@ static void impl_Server_getRegisteredUsers(const ::MumbleServer::AMD_Server_getR #define ACCESS_Server_verifyPassword_READ static void impl_Server_verifyPassword(const ::MumbleServer::AMD_Server_verifyPasswordPtr cb, int server_id, const ::std::string &name, const ::std::string &pw) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; QString uname = u8(name); cb->ice_response(server->authenticate(uname, u8(pw))); @@ -1644,6 +1698,7 @@ static void impl_Server_getTexture(const ::MumbleServer::AMD_Server_getTexturePt static void impl_Server_setTexture(const ::MumbleServer::AMD_Server_setTexturePtr cb, int server_id, ::Ice::Int userid, const ::MumbleServer::Texture &tex) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; if (!server->isUserId(userid)) { @@ -1686,6 +1741,7 @@ static void impl_Server_getUptime(const ::MumbleServer::AMD_Server_getUptimePtr static void impl_Server_updateCertificate(const ::MumbleServer::AMD_Server_updateCertificatePtr cb, int server_id, const ::std::string &certificate, const ::std::string &privateKey, const ::std::string &passphrase) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; QByteArray certPem(certificate.c_str()); @@ -1732,6 +1788,7 @@ static void impl_Server_updateCertificate(const ::MumbleServer::AMD_Server_updat static void impl_Server_startListening(const ::MumbleServer::AMD_Server_startListeningPtr cb, int server_id, int session, int channelid) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; NEED_CHANNEL; NEED_PLAYER; @@ -1743,6 +1800,7 @@ static void impl_Server_startListening(const ::MumbleServer::AMD_Server_startLis static void impl_Server_stopListening(const ::MumbleServer::AMD_Server_stopListeningPtr cb, int server_id, int session, int channelid) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; NEED_CHANNEL; NEED_PLAYER; @@ -1816,6 +1874,7 @@ static void impl_Server_getListenerVolumeAdjustment(const ::MumbleServer::AMD_Se static void impl_Server_setListenerVolumeAdjustment(const ::MumbleServer::AMD_Server_setListenerVolumeAdjustmentPtr cb, int server_id, int channelid, int session, float volumeAdjustment) { + VERIFY_DB_NOT_IN_READONLY; NEED_SERVER; NEED_CHANNEL; NEED_PLAYER; @@ -1991,6 +2050,20 @@ static void impl_Meta_getUptime(const ::MumbleServer::AMD_Meta_getUptimePtr cb, cb->ice_response(static_cast< int >(meta->tUptime.elapsed() / 1000000LL)); } +#define ACCESS_Meta_getAssumedDatabaseState_READ +static void impl_Meta_getAssumedDatabaseState(const ::MumbleServer::AMD_Meta_getAssumedDatabaseStatePtr cb, + const Ice::ObjectAdapterPtr) { + cb->ice_response(dbstateToDBState(meta->assumedDBState)); +} + +static void impl_Meta_setAssumedDatabaseState(const ::MumbleServer::AMD_Meta_setAssumedDatabaseStatePtr cb, + const Ice::ObjectAdapterPtr, ::MumbleServer::DBState state) { + meta->assumedDBState = dbstateToDBState(state); + + cb->ice_response(); +} + + #include "MumbleServerIceWrapper.cpp" #undef FIND_SERVER @@ -1999,6 +2072,7 @@ static void impl_Meta_getUptime(const ::MumbleServer::AMD_Meta_getUptimePtr cb, #undef NEED_PLAYER #undef NEED_CHANNEL_VAR #undef NEED_CHANNEL +#undef VERIFY_DB_NOT_IN_READONLY #undef ACCESS_Server_isRunning_READ #undef ACCESS_Server_id_READ #undef ACCESS_Server_getConf_READ @@ -2033,3 +2107,4 @@ static void impl_Meta_getUptime(const ::MumbleServer::AMD_Meta_getUptimePtr cb, #undef ACCESS_Meta_getBootedServers_READ #undef ACCESS_Meta_getVersion_ALL #undef ACCESS_Meta_getUptime_ALL +#undef ACCESS_Meta_getAssumedDatabaseState_READ diff --git a/src/murmur/Server.cpp b/src/murmur/Server.cpp index 17800b3c667..25dce075f39 100644 --- a/src/murmur/Server.cpp +++ b/src/murmur/Server.cpp @@ -9,6 +9,7 @@ #include "Channel.h" #include "ClientType.h" #include "Connection.h" +#include "DBState.h" #include "EnvUtils.h" #include "Group.h" #include "HTMLFilter.h" @@ -1342,7 +1343,9 @@ void Server::log(ServerUser *u, const QString &str) const { } void Server::log(const QString &msg) const { - dblog(msg); + if (meta->assumedDBState == DBState::Normal) { + dblog(msg); + } qWarning("%d => %s", iServerNum, msg.toUtf8().constData()); } @@ -1598,7 +1601,9 @@ void Server::connectionClosed(QAbstractSocket::SocketError err, const QString &r log(u, QString("Connection closed: %1 [%2]").arg(reason).arg(err)); - setLastDisconnect(u); + if (meta->assumedDBState == DBState::Normal) { + setLastDisconnect(u); + } if (u->sState == ServerUser::Authenticated) { if (m_channelListenerManager.isListeningToAny(u->uiSession)) { @@ -1703,6 +1708,48 @@ void Server::message(Mumble::Protocol::TCPMessageType type, const QByteArray &qb return; } + if (meta->assumedDBState == DBState::ReadOnly) { + // This serves as a filter block to discard all messages that can cause any writes/changes to + // the underlying database. + // This is intentionally somewhat coarse, leaning on the side of dropping messages that due to + // their specific contents wouldn't actually cause a DB change, in order to make it more likely + // for the filtering to remain the same-ish even if the exact handling for a given message type + // (slightly) changes. + // The overall idea is to only allow messages through that are required for still being able to + // allow people on the server to keep switching channels and talking to each other. + switch (type) { + // The essentials + case Mumble::Protocol::TCPMessageType::Ping: + case Mumble::Protocol::TCPMessageType::TextMessage: + case Mumble::Protocol::TCPMessageType::CryptSetup: + case Mumble::Protocol::TCPMessageType::VoiceTarget: + case Mumble::Protocol::TCPMessageType::PluginDataTransmission: + + // These are also possible, but not strictly required + case Mumble::Protocol::TCPMessageType::QueryUsers: + case Mumble::Protocol::TCPMessageType::Version: + case Mumble::Protocol::TCPMessageType::PermissionQuery: + case Mumble::Protocol::TCPMessageType::UserStats: + case Mumble::Protocol::TCPMessageType::RequestBlob: + break; + // In case the user is authenticated as a registered user, a DB update can occur, which is + // why we have to block connections from new clients in read-only mode. + case Mumble::Protocol::TCPMessageType::Authenticate: { + MumbleProto::Reject mpr; + mpr.set_reason("The server is currently in read-only mode and doesn't accept new connections"); + mpr.set_type(MumbleProto::Reject_RejectType_NoNewConnections); + sendMessage(u, mpr); + u->disconnectSocket(); + } + [[fallthrough]]; + default: + // TODO: Notify the user that a package has been dropped due to read-only mode + log(u, QString::fromLatin1("Dropping TCP message of type %1 in read-only mode") + .arg(QString::fromStdString(messageTypeName(type)))); + return; + } + } + #ifdef QT_NO_DEBUG # define PROCESS_MUMBLE_TCP_MESSAGE(name, value) \ case Mumble::Protocol::TCPMessageType::name: { \ From bcdeee6cc8377429f014f8366bb45954b5a529ab Mon Sep 17 00:00:00 2001 From: Robert Adam Date: Tue, 24 Dec 2024 18:28:17 +0100 Subject: [PATCH 9/9] FEAT(server): Print more details about Ice initialization errors --- src/murmur/MumbleServerIce.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/murmur/MumbleServerIce.cpp b/src/murmur/MumbleServerIce.cpp index f2c3647f144..af0c8d4ba36 100644 --- a/src/murmur/MumbleServerIce.cpp +++ b/src/murmur/MumbleServerIce.cpp @@ -31,6 +31,7 @@ #include #include +#include using namespace std; using namespace MumbleServer; @@ -303,11 +304,9 @@ MumbleServerIce::MumbleServerIce() { meta->connectListener(this); } catch (Ice::Exception &e) { -#if ICE_INT_VERSION >= 30700 - qCritical("MumbleServerIce: Initialization failed: %s", qPrintable(u8(e.ice_id()))); -#else - qCritical("MumbleServerIce: Initialization failed: %s", qPrintable(u8(e.ice_name()))); -#endif + std::stringstream stream; + e.ice_print(stream); + qCritical("MumbleServerIce: Initialization failed: %s", qPrintable(u8(stream.str()))); } }