#include "TgVoip.h" #include "VoIPController.h" #include "VoIPServerConfig.h" #include #ifndef TGVOIP_USE_CUSTOM_CRYPTO extern "C" { #include #include #include #include } void tgvoip_openssl_aes_ige_encrypt(uint8_t *in, uint8_t *out, size_t length, uint8_t *key, uint8_t *iv) { AES_KEY akey; AES_set_encrypt_key(key, 32 * 8, &akey); AES_ige_encrypt(in, out, length, &akey, iv, AES_ENCRYPT); } void tgvoip_openssl_aes_ige_decrypt(uint8_t *in, uint8_t *out, size_t length, uint8_t *key, uint8_t *iv) { AES_KEY akey; AES_set_decrypt_key(key, 32 * 8, &akey); AES_ige_encrypt(in, out, length, &akey, iv, AES_DECRYPT); } void tgvoip_openssl_rand_bytes(uint8_t *buffer, size_t len) { RAND_bytes(buffer, len); } void tgvoip_openssl_sha1(uint8_t *msg, size_t len, uint8_t *output) { SHA1(msg, len, output); } void tgvoip_openssl_sha256(uint8_t *msg, size_t len, uint8_t *output) { SHA256(msg, len, output); } void tgvoip_openssl_aes_ctr_encrypt(uint8_t *inout, size_t length, uint8_t *key, uint8_t *iv, uint8_t *ecount, uint32_t *num) { AES_KEY akey; AES_set_encrypt_key(key, 32 * 8, &akey); CRYPTO_ctr128_encrypt(inout, inout, length, &akey, iv, ecount, num, (block128_f)AES_encrypt); } void tgvoip_openssl_aes_cbc_encrypt(uint8_t *in, uint8_t *out, size_t length, uint8_t *key, uint8_t *iv) { AES_KEY akey; AES_set_encrypt_key(key, 256, &akey); AES_cbc_encrypt(in, out, length, &akey, iv, AES_ENCRYPT); } void tgvoip_openssl_aes_cbc_decrypt(uint8_t *in, uint8_t *out, size_t length, uint8_t *key, uint8_t *iv) { AES_KEY akey; AES_set_decrypt_key(key, 256, &akey); AES_cbc_encrypt(in, out, length, &akey, iv, AES_DECRYPT); } tgvoip::CryptoFunctions tgvoip::VoIPController::crypto = { tgvoip_openssl_rand_bytes, tgvoip_openssl_sha1, tgvoip_openssl_sha256, tgvoip_openssl_aes_ige_encrypt, tgvoip_openssl_aes_ige_decrypt, tgvoip_openssl_aes_ctr_encrypt, tgvoip_openssl_aes_cbc_encrypt, tgvoip_openssl_aes_cbc_decrypt}; #else struct TgVoipCrypto { void (*rand_bytes)(uint8_t *buffer, size_t length); void (*sha1)(uint8_t *msg, size_t length, uint8_t *output); void (*sha256)(uint8_t *msg, size_t length, uint8_t *output); void (*aes_ige_encrypt)(uint8_t *in, uint8_t *out, size_t length, uint8_t *key, uint8_t *iv); void (*aes_ige_decrypt)(uint8_t *in, uint8_t *out, size_t length, uint8_t *key, uint8_t *iv); void (*aes_ctr_encrypt)(uint8_t *inout, size_t length, uint8_t *key, uint8_t *iv, uint8_t *ecount, uint32_t *num); void (*aes_cbc_encrypt)(uint8_t *in, uint8_t *out, size_t length, uint8_t *key, uint8_t *iv); void (*aes_cbc_decrypt)(uint8_t *in, uint8_t *out, size_t length, uint8_t *key, uint8_t *iv); }; tgvoip::CryptoFunctions tgvoip::VoIPController::crypto; // set it yourself upon initialization #endif class TgVoipImpl : public TgVoip { public: tgvoip::VoIPController *controller_; std::function onStateUpdated_; std::function onSignalBarsUpdated_; TgVoipImpl( std::vector const &endpoints, TgVoipPersistentState const &persistentState, std::unique_ptr const &proxy, TgVoipConfig const &config, TgVoipEncryptionKey const &encryptionKey, TgVoipNetworkType initialNetworkType #ifdef TGVOIP_USE_CUSTOM_CRYPTO , TgVoipCrypto const &crypto #endif #ifdef TGVOIP_USE_CALLBACK_AUDIO_IO , TgVoipAudioDataCallbacks const &audioDataCallbacks #endif ) { #ifdef TGVOIP_USE_CUSTOM_CRYPTO tgvoip::VoIPController::crypto.sha1 = crypto.sha1; tgvoip::VoIPController::crypto.sha256 = crypto.sha256; tgvoip::VoIPController::crypto.rand_bytes = crypto.rand_bytes; tgvoip::VoIPController::crypto.aes_ige_encrypt = crypto.aes_ige_encrypt; tgvoip::VoIPController::crypto.aes_ige_decrypt = crypto.aes_ige_decrypt; tgvoip::VoIPController::crypto.aes_ctr_encrypt = crypto.aes_ctr_encrypt; #endif controller_ = new tgvoip::VoIPController(); controller_->implData = this; #ifdef TGVOIP_USE_CALLBACK_AUDIO_IO controller_->SetAudioDataCallbacks(audioDataCallbacks.input, audioDataCallbacks.output, audioDataCallbacks.preprocessed); #endif controller_->SetPersistentState(persistentState.value); if (proxy != nullptr) { controller_->SetProxy(tgvoip::PROXY_SOCKS5, proxy->host, proxy->port, proxy->login, proxy->password); } auto callbacks = tgvoip::VoIPController::Callbacks(); callbacks.connectionStateChanged = &TgVoipImpl::controllerStateCallback; callbacks.groupCallKeyReceived = NULL; callbacks.groupCallKeySent = NULL; callbacks.signalBarCountChanged = &TgVoipImpl::signalBarsCallback; callbacks.upgradeToGroupCallRequested = NULL; controller_->SetCallbacks(callbacks); std::vector mappedEndpoints; for (auto endpoint : endpoints) { bool isIpv6 = false; struct in6_addr addrIpV6; if (inet_pton(AF_INET6, endpoint.host.c_str(), &addrIpV6)) { isIpv6 = true; } tgvoip::Endpoint::Type mappedType = tgvoip::Endpoint::Type::UDP_RELAY; switch (endpoint.type) { case TgVoipEndpointType::UdpRelay: mappedType = tgvoip::Endpoint::Type::UDP_RELAY; break; case TgVoipEndpointType::Lan: mappedType = tgvoip::Endpoint::Type::UDP_P2P_LAN; break; case TgVoipEndpointType::Inet: mappedType = tgvoip::Endpoint::Type::UDP_P2P_INET; break; case TgVoipEndpointType::TcpRelay: mappedType = tgvoip::Endpoint::Type::TCP_RELAY; break; default: mappedType = tgvoip::Endpoint::Type::UDP_RELAY; break; } tgvoip::IPv4Address address(isIpv6 ? std::string() : endpoint.host); tgvoip::IPv6Address addressv6(isIpv6 ? endpoint.host : std::string()); mappedEndpoints.push_back(tgvoip::Endpoint(endpoint.endpointId, endpoint.port, address, addressv6, mappedType, endpoint.peerTag)); } int mappedDataSaving = tgvoip::DATA_SAVING_NEVER; switch (config.dataSaving) { case TgVoipDataSaving::Mobile: mappedDataSaving = tgvoip::DATA_SAVING_MOBILE; break; case TgVoipDataSaving::Always: mappedDataSaving = tgvoip::DATA_SAVING_ALWAYS; break; default: mappedDataSaving = tgvoip::DATA_SAVING_NEVER; break; } tgvoip::VoIPController::Config mappedConfig( config.initializationTimeout, config.receiveTimeout, mappedDataSaving, config.enableAEC, config.enableNS, config.enableAGC, config.enableCallUpgrade); mappedConfig.logFilePath = config.logPath; mappedConfig.statsDumpFilePath = ""; controller_->SetConfig(mappedConfig); setNetworkType(initialNetworkType); std::vector encryptionKeyValue = encryptionKey.value; controller_->SetEncryptionKey((char *)(encryptionKeyValue.data()), encryptionKey.isOutgoing); controller_->SetRemoteEndpoints(mappedEndpoints, config.enableP2P, config.maxApiLayer); controller_->Start(); controller_->Connect(); } ~TgVoipImpl() { } void setOnStateUpdated(std::function onStateUpdated) { onStateUpdated_ = onStateUpdated; } void setOnSignalBarsUpdated(std::function onSignalBarsUpdated) { onSignalBarsUpdated_ = onSignalBarsUpdated; } void setNetworkType(TgVoipNetworkType networkType) { int mappedType = tgvoip::NET_TYPE_UNKNOWN; switch (networkType) { case TgVoipNetworkType::Unknown: mappedType = tgvoip::NET_TYPE_UNKNOWN; break; case TgVoipNetworkType::Gprs: mappedType = tgvoip::NET_TYPE_GPRS; break; case TgVoipNetworkType::Edge: mappedType = tgvoip::NET_TYPE_EDGE; break; case TgVoipNetworkType::ThirdGeneration: mappedType = tgvoip::NET_TYPE_3G; break; case TgVoipNetworkType::Hspa: mappedType = tgvoip::NET_TYPE_HSPA; break; case TgVoipNetworkType::Lte: mappedType = tgvoip::NET_TYPE_LTE; break; case TgVoipNetworkType::WiFi: mappedType = tgvoip::NET_TYPE_WIFI; break; case TgVoipNetworkType::Ethernet: mappedType = tgvoip::NET_TYPE_ETHERNET; break; case TgVoipNetworkType::OtherHighSpeed: mappedType = tgvoip::NET_TYPE_OTHER_HIGH_SPEED; break; case TgVoipNetworkType::OtherLowSpeed: mappedType = tgvoip::NET_TYPE_OTHER_LOW_SPEED; break; case TgVoipNetworkType::OtherMobile: mappedType = tgvoip::NET_TYPE_OTHER_MOBILE; break; case TgVoipNetworkType::Dialup: mappedType = tgvoip::NET_TYPE_DIALUP; break; default: mappedType = tgvoip::NET_TYPE_UNKNOWN; break; } controller_->SetNetworkType(mappedType); } void setMuteMicrophone(bool muteMicrophone) { controller_->SetMicMute(muteMicrophone); } std::string getVersion() { return controller_->GetVersion(); } TgVoipPersistentState getPersistentState() { std::vector persistentStateValue = controller_->GetPersistentState(); TgVoipPersistentState persistentState = { .value = persistentStateValue}; return persistentState; } std::string getDebugInfo() { return controller_->GetDebugString(); } TgVoipFinalState stop() { controller_->Stop(); auto debugLog = controller_->GetDebugLog(); tgvoip::VoIPController::TrafficStats stats; controller_->GetStats(&stats); TgVoipTrafficStats trafficStats = { .bytesSentWifi = stats.bytesSentWifi, .bytesReceivedWifi = stats.bytesRecvdWifi, .bytesSentMobile = stats.bytesSentMobile, .bytesReceivedMobile = stats.bytesRecvdMobile}; std::vector persistentStateValue = controller_->GetPersistentState(); TgVoipPersistentState persistentState = { .value = persistentStateValue}; TgVoipFinalState finalState = { .persistentState = persistentState, .debugLog = debugLog, .trafficStats = trafficStats, .isRatingSuggested = controller_->NeedRate()}; delete controller_; controller_ = NULL; return finalState; } static void controllerStateCallback(tgvoip::VoIPController *controller, int state) { TgVoipImpl *self = (TgVoipImpl *)controller->implData; if (self->onStateUpdated_) { TgVoipState mappedState; switch (state) { case tgvoip::STATE_WAIT_INIT: mappedState = TgVoipState::WaitInit; break; case tgvoip::STATE_WAIT_INIT_ACK: mappedState = TgVoipState::WaitInitAck; break; case tgvoip::STATE_ESTABLISHED: mappedState = TgVoipState::Estabilished; break; case tgvoip::STATE_FAILED: mappedState = TgVoipState::Failed; break; case tgvoip::STATE_RECONNECTING: mappedState = TgVoipState::Reconnecting; break; default: mappedState = TgVoipState::Estabilished; break; } self->onStateUpdated_(mappedState); } } static void signalBarsCallback(tgvoip::VoIPController *controller, int signalBars) { TgVoipImpl *self = (TgVoipImpl *)controller->implData; if (self->onSignalBarsUpdated_) { self->onSignalBarsUpdated_(signalBars); } } }; std::function globalLoggingFunction; void __tgvoip_call_tglog(const char *format, ...) { va_list vaArgs; va_start(vaArgs, format); va_list vaCopy; va_copy(vaCopy, vaArgs); const int length = std::vsnprintf(NULL, 0, format, vaCopy); va_end(vaCopy); std::vector zc(length + 1); std::vsnprintf(zc.data(), zc.size(), format, vaArgs); va_end(vaArgs); if (globalLoggingFunction != nullptr) { globalLoggingFunction(std::string(zc.data(), zc.size())); } } void TgVoip::setLoggingFunction(std::function loggingFunction) { globalLoggingFunction = loggingFunction; } void TgVoip::setGlobalServerConfig(const std::string &serverConfig) { tgvoip::ServerConfig::GetSharedInstance()->Update(serverConfig); } TgVoip *TgVoip::makeInstance( TgVoipConfig const &config, TgVoipPersistentState const &persistentState, std::vector const &endpoints, std::unique_ptr const &proxy, TgVoipNetworkType initialNetworkType, TgVoipEncryptionKey const &encryptionKey #ifdef TGVOIP_USE_CUSTOM_CRYPTO , TgVoipCrypto const &crypto #endif #ifdef TGVOIP_USE_CALLBACK_AUDIO_IO , TgVoipAudioDataCallbacks const &audioDataCallbacks #endif ) { return new TgVoipImpl( endpoints, persistentState, proxy, config, encryptionKey, initialNetworkType #ifdef TGVOIP_USE_CUSTOM_CRYPTO , crypto #endif #ifdef TGVOIP_USE_CALLBACK_AUDIO_IO , audioDataCallbacks #endif ); } TgVoip::~TgVoip() { }