mirror of https://github.com/procxx/kepka.git
parent
13a9b967e9
commit
383b29dbd8
|
@ -40,27 +40,27 @@ constexpr auto kMinLayer = 65;
|
||||||
constexpr auto kHangupTimeoutMs = 5000;
|
constexpr auto kHangupTimeoutMs = 5000;
|
||||||
constexpr auto kSha256Size = 32;
|
constexpr auto kSha256Size = 32;
|
||||||
|
|
||||||
using tgvoip::Endpoint;
|
void AppendEndpoint(
|
||||||
|
std::vector<tgvoip::Endpoint> &list,
|
||||||
void ConvertEndpoint(
|
const MTPPhoneConnection &connection) {
|
||||||
std::vector<tgvoip::Endpoint> &ep,
|
connection.match([&](const MTPDphoneConnection &data) {
|
||||||
const MTPDphoneConnection &mtc) {
|
if (data.vpeer_tag.v.length() != 16) {
|
||||||
if (mtc.vpeer_tag.v.length() != 16) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
auto ipv4 = tgvoip::IPv4Address(std::string(
|
||||||
auto ipv4 = tgvoip::IPv4Address(std::string(
|
data.vip.v.constData(),
|
||||||
mtc.vip.v.constData(),
|
data.vip.v.size()));
|
||||||
mtc.vip.v.size()));
|
auto ipv6 = tgvoip::IPv6Address(std::string(
|
||||||
auto ipv6 = tgvoip::IPv6Address(std::string(
|
data.vipv6.v.constData(),
|
||||||
mtc.vipv6.v.constData(),
|
data.vipv6.v.size()));
|
||||||
mtc.vipv6.v.size()));
|
list.emplace_back(
|
||||||
ep.push_back(Endpoint(
|
(int64_t)data.vid.v,
|
||||||
(int64_t)mtc.vid.v,
|
(uint16_t)data.vport.v,
|
||||||
(uint16_t)mtc.vport.v,
|
ipv4,
|
||||||
ipv4,
|
ipv6,
|
||||||
ipv6,
|
tgvoip::Endpoint::Type::UDP_RELAY,
|
||||||
tgvoip::Endpoint::Type::UDP_RELAY,
|
(unsigned char*)data.vpeer_tag.v.data());
|
||||||
(unsigned char*)mtc.vpeer_tag.v.data()));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto kFingerprintDataSize = 256;
|
constexpr auto kFingerprintDataSize = 256;
|
||||||
|
@ -252,7 +252,8 @@ void Call::actuallyAnswer() {
|
||||||
Expects(_type == Type::Incoming);
|
Expects(_type == Type::Incoming);
|
||||||
|
|
||||||
if (_state != State::Starting && _state != State::WaitingIncoming) {
|
if (_state != State::Starting && _state != State::WaitingIncoming) {
|
||||||
if (_state != State::ExchangingKeys || !_answerAfterDhConfigReceived) {
|
if (_state != State::ExchangingKeys
|
||||||
|
|| !_answerAfterDhConfigReceived) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,18 +272,19 @@ void Call::actuallyAnswer() {
|
||||||
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
|
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
|
||||||
MTP_int(kMinLayer),
|
MTP_int(kMinLayer),
|
||||||
MTP_int(tgvoip::VoIPController::GetConnectionMaxLayer()))
|
MTP_int(tgvoip::VoIPController::GetConnectionMaxLayer()))
|
||||||
)).done([this](const MTPphone_PhoneCall &result) {
|
)).done([=](const MTPphone_PhoneCall &result) {
|
||||||
Expects(result.type() == mtpc_phone_phoneCall);
|
Expects(result.type() == mtpc_phone_phoneCall);
|
||||||
auto &call = result.c_phone_phoneCall();
|
auto &call = result.c_phone_phoneCall();
|
||||||
Auth().data().processUsers(call.vusers);
|
Auth().data().processUsers(call.vusers);
|
||||||
if (call.vphone_call.type() != mtpc_phoneCallWaiting) {
|
if (call.vphone_call.type() != mtpc_phoneCallWaiting) {
|
||||||
LOG(("Call Error: Expected phoneCallWaiting in response to phone.acceptCall()"));
|
LOG(("Call Error: "
|
||||||
|
"Not phoneCallWaiting in response to phone.acceptCall."));
|
||||||
finish(FinishType::Failed);
|
finish(FinishType::Failed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUpdate(call.vphone_call);
|
handleUpdate(call.vphone_call);
|
||||||
}).fail([this](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
handleRequestError(error);
|
handleRequestError(error);
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
@ -371,7 +373,9 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
||||||
Unexpected("phoneCallRequested call inside an existing call handleUpdate()");
|
Unexpected("phoneCallRequested call inside an existing call handleUpdate()");
|
||||||
}
|
}
|
||||||
if (Auth().userId() != data.vparticipant_id.v) {
|
if (Auth().userId() != data.vparticipant_id.v) {
|
||||||
LOG(("Call Error: Wrong call participant_id %1, expected %2.").arg(data.vparticipant_id.v).arg(Auth().userId()));
|
LOG(("Call Error: Wrong call participant_id %1, expected %2."
|
||||||
|
).arg(data.vparticipant_id.v
|
||||||
|
).arg(Auth().userId()));
|
||||||
finish(FinishType::Failed);
|
finish(FinishType::Failed);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -379,7 +383,9 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
||||||
_accessHash = data.vaccess_hash.v;
|
_accessHash = data.vaccess_hash.v;
|
||||||
auto gaHashBytes = bytes::make_span(data.vg_a_hash.v);
|
auto gaHashBytes = bytes::make_span(data.vg_a_hash.v);
|
||||||
if (gaHashBytes.size() != kSha256Size) {
|
if (gaHashBytes.size() != kSha256Size) {
|
||||||
LOG(("Call Error: Wrong g_a_hash size %1, expected %2.").arg(gaHashBytes.size()).arg(kSha256Size));
|
LOG(("Call Error: Wrong g_a_hash size %1, expected %2."
|
||||||
|
).arg(gaHashBytes.size()
|
||||||
|
).arg(kSha256Size));
|
||||||
finish(FinishType::Failed);
|
finish(FinishType::Failed);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -400,7 +406,9 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
||||||
if (data.vid.v != _id) {
|
if (data.vid.v != _id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (_type == Type::Outgoing && _state == State::Waiting && data.vreceive_date.v != 0) {
|
if (_type == Type::Outgoing
|
||||||
|
&& _state == State::Waiting
|
||||||
|
&& data.vreceive_date.v != 0) {
|
||||||
_discardByTimeoutTimer.callOnce(Global::CallRingTimeoutMs());
|
_discardByTimeoutTimer.callOnce(Global::CallRingTimeoutMs());
|
||||||
setState(State::Ringing);
|
setState(State::Ringing);
|
||||||
startWaitingTrack();
|
startWaitingTrack();
|
||||||
|
@ -427,16 +435,23 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
||||||
if (data.is_need_debug()) {
|
if (data.is_need_debug()) {
|
||||||
auto debugLog = _controller ? _controller->GetDebugLog() : std::string();
|
auto debugLog = _controller ? _controller->GetDebugLog() : std::string();
|
||||||
if (!debugLog.empty()) {
|
if (!debugLog.empty()) {
|
||||||
MTP::send(MTPphone_SaveCallDebug(MTP_inputPhoneCall(MTP_long(_id), MTP_long(_accessHash)), MTP_dataJSON(MTP_string(debugLog))));
|
MTP::send(
|
||||||
|
MTPphone_SaveCallDebug(
|
||||||
|
MTP_inputPhoneCall(
|
||||||
|
MTP_long(_id),
|
||||||
|
MTP_long(_accessHash)),
|
||||||
|
MTP_dataJSON(MTP_string(debugLog))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (data.is_need_rating() && _id && _accessHash) {
|
if (data.is_need_rating() && _id && _accessHash) {
|
||||||
Ui::show(Box<RateCallBox>(_id, _accessHash));
|
Ui::show(Box<RateCallBox>(_id, _accessHash));
|
||||||
}
|
}
|
||||||
if (data.has_reason() && data.vreason.type() == mtpc_phoneCallDiscardReasonDisconnect) {
|
if (data.has_reason()
|
||||||
|
&& data.vreason.type() == mtpc_phoneCallDiscardReasonDisconnect) {
|
||||||
LOG(("Call Info: Discarded with DISCONNECT reason."));
|
LOG(("Call Info: Discarded with DISCONNECT reason."));
|
||||||
}
|
}
|
||||||
if (data.has_reason() && data.vreason.type() == mtpc_phoneCallDiscardReasonBusy) {
|
if (data.has_reason()
|
||||||
|
&& data.vreason.type() == mtpc_phoneCallDiscardReasonBusy) {
|
||||||
setState(State::Busy);
|
setState(State::Busy);
|
||||||
} else if (_type == Type::Outgoing || _state == State::HangingUp) {
|
} else if (_type == Type::Outgoing || _state == State::HangingUp) {
|
||||||
setState(State::Ended);
|
setState(State::Ended);
|
||||||
|
@ -451,7 +466,8 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (_type != Type::Outgoing) {
|
if (_type != Type::Outgoing) {
|
||||||
LOG(("Call Error: Unexpected phoneCallAccepted for an incoming call."));
|
LOG(("Call Error: "
|
||||||
|
"Unexpected phoneCallAccepted for an incoming call."));
|
||||||
finish(FinishType::Failed);
|
finish(FinishType::Failed);
|
||||||
} else if (checkCallFields(data)) {
|
} else if (checkCallFields(data)) {
|
||||||
confirmAcceptedCall(data);
|
confirmAcceptedCall(data);
|
||||||
|
@ -465,8 +481,17 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
||||||
void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) {
|
void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) {
|
||||||
Expects(_type == Type::Outgoing);
|
Expects(_type == Type::Outgoing);
|
||||||
|
|
||||||
auto firstBytes = bytes::make_span(call.vg_b.v);
|
if (_state == State::ExchangingKeys
|
||||||
auto computedAuthKey = MTP::CreateAuthKey(firstBytes, _randomPower, _dhConfig.p);
|
|| _controller) {
|
||||||
|
LOG(("Call Warning: Unexpected confirmAcceptedCall."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto firstBytes = bytes::make_span(call.vg_b.v);
|
||||||
|
const auto computedAuthKey = MTP::CreateAuthKey(
|
||||||
|
firstBytes,
|
||||||
|
_randomPower,
|
||||||
|
_dhConfig.p);
|
||||||
if (computedAuthKey.empty()) {
|
if (computedAuthKey.empty()) {
|
||||||
LOG(("Call Error: Could not compute mod-exp final."));
|
LOG(("Call Error: Could not compute mod-exp final."));
|
||||||
finish(FinishType::Failed);
|
finish(FinishType::Failed);
|
||||||
|
@ -561,10 +586,10 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &protocol = call.vprotocol.c_phoneCallProtocol();
|
const auto &protocol = call.vprotocol.c_phoneCallProtocol();
|
||||||
auto endpoints = std::vector<Endpoint>();
|
auto endpoints = std::vector<tgvoip::Endpoint>();
|
||||||
ConvertEndpoint(endpoints, call.vconnection.c_phoneConnection());
|
AppendEndpoint(endpoints, call.vconnection);
|
||||||
for (int i = 0; i < call.valternative_connections.v.length(); i++) {
|
for (const auto &connection : call.valternative_connections.v) {
|
||||||
ConvertEndpoint(endpoints, call.valternative_connections.v[i].c_phoneConnection());
|
AppendEndpoint(endpoints, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto callbacks = tgvoip::VoIPController::Callbacks();
|
auto callbacks = tgvoip::VoIPController::Callbacks();
|
||||||
|
@ -602,7 +627,7 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
|
||||||
_controller->SetCallbacks(callbacks);
|
_controller->SetCallbacks(callbacks);
|
||||||
if (Global::UseProxyForCalls()
|
if (Global::UseProxyForCalls()
|
||||||
&& (Global::ProxySettings() == ProxyData::Settings::Enabled)) {
|
&& (Global::ProxySettings() == ProxyData::Settings::Enabled)) {
|
||||||
const auto proxy = Global::SelectedProxy();
|
const auto &proxy = Global::SelectedProxy();
|
||||||
if (proxy.supportsCalls()) {
|
if (proxy.supportsCalls()) {
|
||||||
Assert(proxy.type == ProxyData::Type::Socks5);
|
Assert(proxy.type == ProxyData::Type::Socks5);
|
||||||
_controller->SetProxy(
|
_controller->SetProxy(
|
||||||
|
|
|
@ -121,7 +121,7 @@ public:
|
||||||
bytes::vector getKeyShaForFingerprint() const;
|
bytes::vector getKeyShaForFingerprint() const;
|
||||||
|
|
||||||
QString getDebugLog() const;
|
QString getDebugLog() const;
|
||||||
|
|
||||||
void setCurrentAudioDevice(bool input, std::string deviceID);
|
void setCurrentAudioDevice(bool input, std::string deviceID);
|
||||||
void setAudioVolume(bool input, float level);
|
void setAudioVolume(bool input, float level);
|
||||||
void setAudioDuckingEnabled(bool enabled);
|
void setAudioDuckingEnabled(bool enabled);
|
||||||
|
|
|
@ -106,10 +106,13 @@ void Instance::destroyCall(not_null<Call*> call) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::destroyCurrentPanel() {
|
void Instance::destroyCurrentPanel() {
|
||||||
_pendingPanels.erase(std::remove_if(_pendingPanels.begin(), _pendingPanels.end(), [](auto &&panel) {
|
_pendingPanels.erase(
|
||||||
return !panel;
|
std::remove_if(
|
||||||
}), _pendingPanels.end());
|
_pendingPanels.begin(),
|
||||||
_pendingPanels.push_back(_currentCallPanel.release());
|
_pendingPanels.end(),
|
||||||
|
[](auto &&panel) { return !panel; }),
|
||||||
|
_pendingPanels.end());
|
||||||
|
_pendingPanels.emplace_back(_currentCallPanel.release());
|
||||||
_pendingPanels.back()->hideAndDestroy(); // Always queues the destruction.
|
_pendingPanels.back()->hideAndDestroy(); // Always queues the destruction.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,56 +133,65 @@ void Instance::createCall(not_null<UserData*> user, Call::Type type) {
|
||||||
|
|
||||||
void Instance::refreshDhConfig() {
|
void Instance::refreshDhConfig() {
|
||||||
Expects(_currentCall != nullptr);
|
Expects(_currentCall != nullptr);
|
||||||
|
|
||||||
|
const auto weak = base::make_weak(_currentCall);
|
||||||
request(MTPmessages_GetDhConfig(
|
request(MTPmessages_GetDhConfig(
|
||||||
MTP_int(_dhConfig.version),
|
MTP_int(_dhConfig.version),
|
||||||
MTP_int(MTP::ModExpFirst::kRandomPowerSize)
|
MTP_int(MTP::ModExpFirst::kRandomPowerSize)
|
||||||
)).done([this, call = base::make_weak(_currentCall)](
|
)).done([=](const MTPmessages_DhConfig &result) {
|
||||||
const MTPmessages_DhConfig &result) {
|
const auto call = weak.get();
|
||||||
auto random = bytes::const_span();
|
const auto random = updateDhConfig(result);
|
||||||
switch (result.type()) {
|
|
||||||
case mtpc_messages_dhConfig: {
|
|
||||||
auto &config = result.c_messages_dhConfig();
|
|
||||||
if (!MTP::IsPrimeAndGood(bytes::make_span(config.vp.v), config.vg.v)) {
|
|
||||||
LOG(("API Error: bad p/g received in dhConfig."));
|
|
||||||
callFailed(call.get());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_dhConfig.g = config.vg.v;
|
|
||||||
_dhConfig.p = bytes::make_vector(config.vp.v);
|
|
||||||
random = bytes::make_span(config.vrandom.v);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case mtpc_messages_dhConfigNotModified: {
|
|
||||||
auto &config = result.c_messages_dhConfigNotModified();
|
|
||||||
random = bytes::make_span(config.vrandom.v);
|
|
||||||
if (!_dhConfig.g || _dhConfig.p.empty()) {
|
|
||||||
LOG(("API Error: dhConfigNotModified on zero version."));
|
|
||||||
callFailed(call.get());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: Unexpected("Type in messages.getDhConfig");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (random.size() != MTP::ModExpFirst::kRandomPowerSize) {
|
|
||||||
LOG(("API Error: dhConfig random bytes wrong size: %1").arg(random.size()));
|
|
||||||
callFailed(call.get());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (call) {
|
|
||||||
call->start(random);
|
|
||||||
}
|
|
||||||
}).fail([this, call = base::make_weak(_currentCall)](
|
|
||||||
const RPCError &error) {
|
|
||||||
if (!call) {
|
if (!call) {
|
||||||
DEBUG_LOG(("API Warning: call was destroyed before got dhConfig."));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callFailed(call.get());
|
if (!random.empty()) {
|
||||||
|
Assert(random.size() == MTP::ModExpFirst::kRandomPowerSize);
|
||||||
|
call->start(random);
|
||||||
|
} else {
|
||||||
|
callFailed(call);
|
||||||
|
}
|
||||||
|
}).fail([=](const RPCError &error) {
|
||||||
|
const auto call = weak.get();
|
||||||
|
if (!call) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callFailed(call);
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bytes::const_span Instance::updateDhConfig(
|
||||||
|
const MTPmessages_DhConfig &data) {
|
||||||
|
const auto validRandom = [](const QByteArray & random) {
|
||||||
|
if (random.size() != MTP::ModExpFirst::kRandomPowerSize) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
return data.match([&](const MTPDmessages_dhConfig &data)
|
||||||
|
-> bytes::const_span {
|
||||||
|
auto primeBytes = bytes::make_vector(data.vp.v);
|
||||||
|
if (!MTP::IsPrimeAndGood(primeBytes, data.vg.v)) {
|
||||||
|
LOG(("API Error: bad p/g received in dhConfig."));
|
||||||
|
return {};
|
||||||
|
} else if (!validRandom(data.vrandom.v)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
_dhConfig.g = data.vg.v;
|
||||||
|
_dhConfig.p = std::move(primeBytes);
|
||||||
|
_dhConfig.version = data.vversion.v;
|
||||||
|
return bytes::make_span(data.vrandom.v);
|
||||||
|
}, [&](const MTPDmessages_dhConfigNotModified &data)
|
||||||
|
-> bytes::const_span {
|
||||||
|
if (!_dhConfig.g || _dhConfig.p.empty()) {
|
||||||
|
LOG(("API Error: dhConfigNotModified on zero version."));
|
||||||
|
return {};
|
||||||
|
} else if (!validRandom(data.vrandom.v)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return bytes::make_span(data.vrandom.v);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void Instance::refreshServerConfig() {
|
void Instance::refreshServerConfig() {
|
||||||
if (_serverConfigRequestId) {
|
if (_serverConfigRequestId) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -60,6 +60,7 @@ private:
|
||||||
|
|
||||||
void refreshDhConfig();
|
void refreshDhConfig();
|
||||||
void refreshServerConfig();
|
void refreshServerConfig();
|
||||||
|
bytes::const_span updateDhConfig(const MTPmessages_DhConfig &data);
|
||||||
|
|
||||||
bool alreadyInCall();
|
bool alreadyInCall();
|
||||||
void handleCallUpdate(const MTPPhoneCall &call);
|
void handleCallUpdate(const MTPPhoneCall &call);
|
||||||
|
|
Loading…
Reference in New Issue