From ed5652777ac3e52ccc450ec571dfbd1c2649185a Mon Sep 17 00:00:00 2001 From: Scott Hardin Date: Sat, 20 May 2017 18:11:49 +0200 Subject: [PATCH 1/5] Add userstate helpers for self_mute and self_deaf --- include/mumlib.hpp | 4 ++++ src/mumlib.cpp | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/include/mumlib.hpp b/include/mumlib.hpp index 95afe02..4d0e331 100644 --- a/include/mumlib.hpp +++ b/include/mumlib.hpp @@ -54,6 +54,10 @@ namespace mumlib { void joinChannel(int channelId); + void self_mute(int muteness); + + void self_deaf(int deafness); + private: _Mumlib_Private *impl; }; diff --git a/src/mumlib.cpp b/src/mumlib.cpp index 08197d1..a14deb9 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -404,4 +404,19 @@ namespace mumlib { impl->transport.sendControlMessage(MessageType::USERSTATE, userState); impl->channelId = channelId; } + + void Mumlib::self_mute(int muteness) { + MumbleProto::UserState userState; + userState.set_self_mute(muteness); + impl->transport.sendControlMessage(MessageType::USERSTATE, userState); + } + + void Mumlib::self_deaf(int deafness) { + MumbleProto::UserState userState; + userState.set_self_deaf(deafness); + impl->transport.sendControlMessage(MessageType::USERSTATE, userState); + } + + + } From 2a407b7c22fe5c6314c4ff1d6a5b1b63fac1f762 Mon Sep 17 00:00:00 2001 From: Scott Hardin Date: Wed, 24 May 2017 22:42:05 +0200 Subject: [PATCH 2/5] replace self_mute/self_deaf() with sendUserState() --- include/mumlib.hpp | 6 ++++- include/mumlib/enums.hpp | 13 +++++++++- src/mumlib.cpp | 53 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/include/mumlib.hpp b/include/mumlib.hpp index 4d0e331..a9ed524 100644 --- a/include/mumlib.hpp +++ b/include/mumlib.hpp @@ -54,8 +54,12 @@ namespace mumlib { void joinChannel(int channelId); - void self_mute(int muteness); + void sendUserState(mumlib::UserState field, bool val); + + void sendUserState(mumlib::UserState field, string val); + // These two are deprecated by sendUserState + void self_mute(int muteness); void self_deaf(int deafness); private: diff --git a/include/mumlib/enums.hpp b/include/mumlib/enums.hpp index b4a9b43..d368e30 100644 --- a/include/mumlib/enums.hpp +++ b/include/mumlib/enums.hpp @@ -44,5 +44,16 @@ namespace mumlib { CELT_Beta, OPUS }; + + enum class UserState { + MUTE, + DEAF, + SUPPRESS, + SELF_MUTE, + SELF_DEAF, + COMMENT, + PRIORITY_SPEAKER, + RECORDING + }; -} \ No newline at end of file +} diff --git a/src/mumlib.cpp b/src/mumlib.cpp index a14deb9..d2cac4b 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -405,18 +405,67 @@ namespace mumlib { impl->channelId = channelId; } + void Mumlib::sendUserState(mumlib::UserState field, bool val) { + MumbleProto::UserState userState; + + switch (field) { + case UserState::MUTE: + userState.set_mute(val); + break; + case UserState::DEAF: + userState.set_deaf(val); + break; + case UserState::SUPPRESS: + userState.set_suppress(val); + break; + case UserState::SELF_MUTE: + userState.set_self_mute(val); + break; + case UserState::SELF_DEAF: + userState.set_self_deaf(val); + break; + case UserState::PRIORITY_SPEAKER: + userState.set_priority_speaker(val); + break; + case UserState::RECORDING: + userState.set_recording(val); + break; + default: + // in any other case, just ignore the command + return; + } + + impl->transport.sendControlMessage(MessageType::USERSTATE, userState); + } + + void Mumlib::sendUserState(mumlib::UserState field, string val) { + MumbleProto::UserState userState; + + switch (field) { + case UserState::COMMENT: + // TODO: if comment longer than 128 bytes, we need to set the SHA1 hash + userState.set_comment(val); + break; + default: + // in any other case, just ignore the command + return; + } + + impl->transport.sendControlMessage(MessageType::USERSTATE, userState); + } + + // deprecated by sendUserState() void Mumlib::self_mute(int muteness) { MumbleProto::UserState userState; userState.set_self_mute(muteness); impl->transport.sendControlMessage(MessageType::USERSTATE, userState); } + // deprecated by sendUserState() void Mumlib::self_deaf(int deafness) { MumbleProto::UserState userState; userState.set_self_deaf(deafness); impl->transport.sendControlMessage(MessageType::USERSTATE, userState); } - - } From ccf21cc65021e01b773e6631ba1cebc2618df54a Mon Sep 17 00:00:00 2001 From: Scott Hardin Date: Sat, 27 May 2017 18:42:22 +0200 Subject: [PATCH 3/5] hack --- src/mumlib.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mumlib.cpp b/src/mumlib.cpp index d2cac4b..24ff347 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -438,7 +438,7 @@ namespace mumlib { impl->transport.sendControlMessage(MessageType::USERSTATE, userState); } - void Mumlib::sendUserState(mumlib::UserState field, string val) { + void Mumlib::sendUserState(mumlib::UserState field, std::string val) { MumbleProto::UserState userState; switch (field) { From cedb233da88f201f06a4df7c74b2458eb163ca66 Mon Sep 17 00:00:00 2001 From: Scott Hardin Date: Sat, 27 May 2017 21:17:18 +0200 Subject: [PATCH 4/5] change packet logging from info to debug --- src/Transport.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Transport.cpp b/src/Transport.cpp index f134512..78dfd74 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -527,10 +527,10 @@ void mumlib::Transport::sendEncodedAudioPacket(uint8_t *buffer, int length) { } if (udpActive) { - logger.info("Sending %d B of audio data via UDP.", length); + logger.debug("Sending %d B of audio data via UDP.", length); sendUdpAsync(buffer, length); } else { - logger.info("Sending %d B of audio data via TCP.", length); + logger.debug("Sending %d B of audio data via TCP.", length); const uint16_t netUdptunnelType = htons(static_cast(MessageType::UDPTUNNEL)); From 70a99d1edf535fe906a01bf7078694d2583a40f9 Mon Sep 17 00:00:00 2001 From: Scott Hardin Date: Sun, 28 May 2017 21:02:45 +0200 Subject: [PATCH 5/5] add initial support for client certs --- README.md | 4 +++- include/mumlib.hpp | 2 ++ include/mumlib/Transport.hpp | 24 +++++++++++++++++++++++- mumlib_example.cpp | 10 +++++++--- src/Transport.cpp | 16 +++++++++++++++- src/mumlib.cpp | 16 ++++++++++++---- 6 files changed, 62 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index efae754..90bb781 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,8 @@ make Sample usage is covered in *mumlib_example.cpp* file. Basically, you should extend *mumlib::Callback* class to implement your own handlers. +To use a client certificate, you'll need a PEM certificate and private key without a passphrase. These are assed in the MumlibConfig struct to the Mumlib object constructor. Support for passphrase still needs to be added. + ## Credits 2015 Michał Słomkowski. The code is published under the terms of Lesser General Public License Version 3. @@ -42,4 +44,4 @@ to implement your own handlers. The library contains code from following 3rd party projects: * official Mumble Client: https://github.com/mumble-voip/mumble -* *libmumble*: https://github.com/cornejo/libmumble \ No newline at end of file +* *libmumble*: https://github.com/cornejo/libmumble diff --git a/include/mumlib.hpp b/include/mumlib.hpp index a9ed524..faad2db 100644 --- a/include/mumlib.hpp +++ b/include/mumlib.hpp @@ -22,6 +22,8 @@ namespace mumlib { struct MumlibConfiguration { int opusEncoderBitrate = DEFAULT_OPUS_ENCODER_BITRATE; + std::string cert_file = ""; + std::string privkey_file = ""; // additional fields will be added in the future }; diff --git a/include/mumlib/Transport.hpp b/include/mumlib/Transport.hpp index ccf94a7..17e8b77 100644 --- a/include/mumlib/Transport.hpp +++ b/include/mumlib/Transport.hpp @@ -33,12 +33,26 @@ namespace mumlib { TransportException(string message) : MumlibException(message) { } }; + /* This helper is needed because the sslContext and sslSocket are initialized in + * the Transport constructor and there wasn't an easier way of passing these two + * arguments. + * TODO: add support for password callback. + */ + class SslContextHelper : boost::noncopyable { + public: + SslContextHelper(boost::asio::ssl::context &ctx, + std::string cert_file, std::string privkey_file); + ~SslContextHelper() { }; + }; + class Transport : boost::noncopyable { public: Transport(io_service &ioService, ProcessControlMessageFunction processControlMessageFunc, ProcessEncodedAudioPacketFunction processEncodedAudioPacketFunction, - bool noUdp = false); + bool noUdp = false, + std::string cert_file = "", + std::string privkey_file = ""); ~Transport(); @@ -47,6 +61,13 @@ namespace mumlib { string user, string password); + void connect(string host, + int port, + string user, + string password, + string cert_file, + string privkey_file); + void disconnect(); ConnectionState getConnectionState() { @@ -84,6 +105,7 @@ namespace mumlib { CryptState cryptState; ssl::context sslContext; + SslContextHelper sslContextHelper; ssl::stream sslSocket; uint8_t *sslIncomingBuffer; diff --git a/mumlib_example.cpp b/mumlib_example.cpp index 2e874d6..6cebc0f 100644 --- a/mumlib_example.cpp +++ b/mumlib_example.cpp @@ -39,8 +39,8 @@ int main(int argc, char *argv[]) { logger.setPriority(log4cpp::Priority::NOTICE); logger.addAppender(appender1); - if (argc < 3) { - logger.crit("Usage: %s {server} {password}", argv[0]); + if (argc < 3 || argc == 4 || argc > 5) { + logger.crit("Usage: %s {server} {password} [{certfile} {keyfile}]", argv[0]); return 1; } @@ -50,6 +50,10 @@ int main(int argc, char *argv[]) { try { mumlib::MumlibConfiguration conf; conf.opusEncoderBitrate = 32000; + if ( argc > 3 && argc <= 5 ) { + conf.cert_file = argv[3]; + conf.privkey_file = argv[4]; + } mumlib::Mumlib mum(myCallback, conf); myCallback.mum = &mum; mum.connect(argv[1], 64738, "mumlib_example", argv[2]); @@ -61,4 +65,4 @@ int main(int argc, char *argv[]) { std::this_thread::sleep_for(std::chrono::seconds(5)); } } -} \ No newline at end of file +} diff --git a/src/Transport.cpp b/src/Transport.cpp index 78dfd74..5276131 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -29,7 +29,9 @@ mumlib::Transport::Transport( io_service &ioService, mumlib::ProcessControlMessageFunction processMessageFunc, ProcessEncodedAudioPacketFunction processEncodedAudioPacketFunction, - bool noUdp) : + bool noUdp, + std::string cert_file, + std::string privkey_file) : logger(log4cpp::Category::getInstance("mumlib.Transport")), ioService(ioService), processMessageFunction(processMessageFunc), @@ -38,6 +40,7 @@ mumlib::Transport::Transport( state(ConnectionState::NOT_CONNECTED), udpSocket(ioService), sslContext(ssl::context::sslv23), + sslContextHelper(sslContext, cert_file, privkey_file), sslSocket(ioService, sslContext), pingTimer(ioService, PING_INTERVAL), asyncBufferPool(max(MAX_UDP_LENGTH, MAX_TCP_LENGTH)) { @@ -67,6 +70,7 @@ void mumlib::Transport::connect( sslSocket.set_verify_mode(boost::asio::ssl::verify_peer); + //todo for now it accepts every certificate, move it to callback sslSocket.set_verify_callback([](bool preverified, boost::asio::ssl::verify_context &ctx) { return true; @@ -520,6 +524,16 @@ void mumlib::Transport::throwTransportException(string message) { throw TransportException(message); } +mumlib::SslContextHelper::SslContextHelper(ssl::context &ctx, std::string cert_file, std::string privkey_file) { + if ( cert_file.size() > 0 ) { + ctx.use_certificate_file(cert_file, ssl::context::file_format::pem); + } + if ( privkey_file.size() > 0 ) { + ctx.use_private_key_file(privkey_file, ssl::context::file_format::pem); + } +} + + void mumlib::Transport::sendEncodedAudioPacket(uint8_t *buffer, int length) { if (state != ConnectionState::CONNECTED) { logger.warn("Connection not established."); diff --git a/src/mumlib.cpp b/src/mumlib.cpp index 24ff347..1c21e49 100644 --- a/src/mumlib.cpp +++ b/src/mumlib.cpp @@ -38,12 +38,20 @@ namespace mumlib { externalIoService = false; } - _Mumlib_Private(Callback &callback, io_service &ioService, MumlibConfiguration &configuration) + _Mumlib_Private( + Callback &callback, + io_service &ioService, + MumlibConfiguration &configuration) : callback(callback), ioService(ioService), externalIoService(true), - transport(ioService, boost::bind(&_Mumlib_Private::processIncomingTcpMessage, this, _1, _2, _3), - boost::bind(&_Mumlib_Private::processAudioPacket, this, _1, _2, _3)) { + transport( + ioService, + boost::bind(&_Mumlib_Private::processIncomingTcpMessage, this, _1, _2, _3), + boost::bind(&_Mumlib_Private::processAudioPacket, this, _1, _2, _3), + false, + configuration.cert_file, + configuration.privkey_file) { audio.setOpusEncoderBitrate(configuration.opusEncoderBitrate); } @@ -347,7 +355,7 @@ namespace mumlib { impl = new _Mumlib_Private(callback, ioService, conf); } - Mumlib::Mumlib(Callback &callback, MumlibConfiguration &configuration) + Mumlib::Mumlib(Callback &callback, MumlibConfiguration &configuration) : impl(new _Mumlib_Private(callback, configuration)) { } Mumlib::Mumlib(Callback &callback, io_service &ioService, MumlibConfiguration &configuration)