From 8c2f11de7dcb2c168039d298367888c2059d1c28 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 25 Jun 2018 19:55:27 +0100 Subject: [PATCH] Send correct paddings in improved TCP protocol. --- .../codegen/scheme/codegen_scheme.py | 2 +- Telegram/SourceFiles/mtproto/auth_key.cpp | 12 +- Telegram/SourceFiles/mtproto/auth_key.h | 3 +- .../SourceFiles/mtproto/concurrent_sender.cpp | 2 +- .../SourceFiles/mtproto/concurrent_sender.h | 6 +- Telegram/SourceFiles/mtproto/connection.cpp | 424 +++++++++--------- Telegram/SourceFiles/mtproto/connection.h | 26 +- .../mtproto/connection_abstract.cpp | 44 +- .../SourceFiles/mtproto/connection_abstract.h | 57 ++- .../SourceFiles/mtproto/connection_http.cpp | 15 +- .../SourceFiles/mtproto/connection_http.h | 2 +- .../mtproto/connection_resolving.cpp | 10 +- .../mtproto/connection_resolving.h | 3 +- .../SourceFiles/mtproto/connection_tcp.cpp | 232 +++++++--- Telegram/SourceFiles/mtproto/connection_tcp.h | 10 +- Telegram/SourceFiles/mtproto/core_types.cpp | 217 +++++---- Telegram/SourceFiles/mtproto/core_types.h | 185 ++++---- Telegram/SourceFiles/mtproto/mtp_instance.cpp | 28 +- Telegram/SourceFiles/mtproto/mtp_instance.h | 20 +- Telegram/SourceFiles/mtproto/session.cpp | 32 +- Telegram/SourceFiles/mtproto/session.h | 50 ++- .../SourceFiles/storage/file_download.cpp | 2 +- 22 files changed, 846 insertions(+), 536 deletions(-) diff --git a/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py b/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py index 988adeca9..4369d7681 100644 --- a/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py +++ b/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py @@ -462,7 +462,7 @@ def addTextSerialize(lst, dct, dataLetter): templateArgument = '' if (isTemplate != ''): - templateArgument = '' + templateArgument = '' result += 'void Serialize_' + name + '(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, uint32 iflag) {\n'; if (len(conditions)): diff --git a/Telegram/SourceFiles/mtproto/auth_key.cpp b/Telegram/SourceFiles/mtproto/auth_key.cpp index 633d1345f..b9ef48800 100644 --- a/Telegram/SourceFiles/mtproto/auth_key.cpp +++ b/Telegram/SourceFiles/mtproto/auth_key.cpp @@ -92,14 +92,22 @@ void aesIgeDecryptRaw(const void *src, void *dst, uint32 len, const void *key, c AES_ige_encrypt(static_cast(src), static_cast(dst), len, &aes, aes_iv, AES_DECRYPT); } -void aesCtrEncrypt(void *data, uint32 len, const void *key, CTRState *state) { +void aesCtrEncrypt(bytes::span data, const void *key, CTRState *state) { AES_KEY aes; AES_set_encrypt_key(static_cast(key), 256, &aes); static_assert(CTRState::IvecSize == AES_BLOCK_SIZE, "Wrong size of ctr ivec!"); static_assert(CTRState::EcountSize == AES_BLOCK_SIZE, "Wrong size of ctr ecount!"); - CRYPTO_ctr128_encrypt(static_cast(data), static_cast(data), len, &aes, state->ivec, state->ecount, &state->num, (block128_f) AES_encrypt); + CRYPTO_ctr128_encrypt( + reinterpret_cast(data.data()), + reinterpret_cast(data.data()), + data.size(), + &aes, + state->ivec, + state->ecount, + &state->num, + (block128_f)AES_encrypt); } } // namespace MTP diff --git a/Telegram/SourceFiles/mtproto/auth_key.h b/Telegram/SourceFiles/mtproto/auth_key.h index c6a92eadc..dcc84291b 100644 --- a/Telegram/SourceFiles/mtproto/auth_key.h +++ b/Telegram/SourceFiles/mtproto/auth_key.h @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include +#include "base/bytes.h" namespace MTP { @@ -145,6 +146,6 @@ struct CTRState { uint32 num = 0; uchar ecount[EcountSize] = { 0 }; }; -void aesCtrEncrypt(void *data, uint32 len, const void *key, CTRState *state); +void aesCtrEncrypt(bytes::span data, const void *key, CTRState *state); } // namespace MTP diff --git a/Telegram/SourceFiles/mtproto/concurrent_sender.cpp b/Telegram/SourceFiles/mtproto/concurrent_sender.cpp index 043053da1..a1f8b67ef 100644 --- a/Telegram/SourceFiles/mtproto/concurrent_sender.cpp +++ b/Telegram/SourceFiles/mtproto/concurrent_sender.cpp @@ -110,7 +110,7 @@ auto ConcurrentSender::with_instance(Method &&method) ConcurrentSender::RequestBuilder::RequestBuilder( not_null sender, - mtpRequest &&serialized) noexcept + SecureRequest &&serialized) noexcept : _sender(sender) , _serialized(std::move(serialized)) { } diff --git a/Telegram/SourceFiles/mtproto/concurrent_sender.h b/Telegram/SourceFiles/mtproto/concurrent_sender.h index 3afc11600..aed431a2c 100644 --- a/Telegram/SourceFiles/mtproto/concurrent_sender.h +++ b/Telegram/SourceFiles/mtproto/concurrent_sender.h @@ -61,7 +61,7 @@ class ConcurrentSender : public base::has_weak_ptr { protected: RequestBuilder( not_null sender, - mtpRequest &&serialized) noexcept; + SecureRequest &&serialized) noexcept; void setToDC(ShiftedDcId dcId) noexcept; void setCanWait(TimeMs ms) noexcept; @@ -74,7 +74,7 @@ class ConcurrentSender : public base::has_weak_ptr { private: not_null _sender; - mtpRequest _serialized; + SecureRequest _serialized; ShiftedDcId _dcId = 0; TimeMs _canWait = 0; @@ -224,7 +224,7 @@ template ConcurrentSender::SpecificRequestBuilder::SpecificRequestBuilder( not_null sender, Request &&request -) noexcept : RequestBuilder(sender, mtpRequestData::serialize(request)) { +) noexcept : RequestBuilder(sender, SecureRequest::Serialize(request)) { } template diff --git a/Telegram/SourceFiles/mtproto/connection.cpp b/Telegram/SourceFiles/mtproto/connection.cpp index 87d9c6329..ddbbdaf81 100644 --- a/Telegram/SourceFiles/mtproto/connection.cpp +++ b/Telegram/SourceFiles/mtproto/connection.cpp @@ -210,9 +210,9 @@ ModExpFirst CreateModExp( return result; } -void wrapInvokeAfter(mtpRequest &to, const mtpRequest &from, const mtpRequestMap &haveSent, int32 skipBeforeRequest = 0) { - mtpMsgId afterId(*(mtpMsgId*)(from->after->data() + 4)); - mtpRequestMap::const_iterator i = afterId ? haveSent.constFind(afterId) : haveSent.cend(); +void wrapInvokeAfter(SecureRequest &to, const SecureRequest &from, const RequestMap &haveSent, int32 skipBeforeRequest = 0) { + const auto afterId = *(mtpMsgId*)(from->after->data() + 4); + const auto i = afterId ? haveSent.constFind(afterId) : haveSent.cend(); int32 size = to->size(), lenInInts = (from.innerLength() >> 2), headlen = 4, fulllen = headlen + lenInInts; if (i == haveSent.constEnd()) { // no invoke after or such msg was not sent or was completed recently to->resize(size + fulllen + skipBeforeRequest); @@ -508,17 +508,16 @@ void ConnectionPrivate::resetSession() { // recreate all msg_id and msg_seqno QWriteLocker locker2(sessionData->toResendMutex()); QWriteLocker locker3(sessionData->toSendMutex()); QWriteLocker locker4(sessionData->wereAckedMutex()); - mtpRequestMap &haveSent(sessionData->haveSentMap()); - mtpRequestIdsMap &toResend(sessionData->toResendMap()); - mtpPreRequestMap &toSend(sessionData->toSendMap()); - mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap()); + auto &haveSent = sessionData->haveSentMap(); + auto &toResend = sessionData->toResendMap(); + auto &toSend = sessionData->toSendMap(); + auto &wereAcked = sessionData->wereAckedMap(); - mtpMsgId newId = msgid(); - mtpRequestMap setSeqNumbers; - typedef QMap Replaces; - Replaces replaces; - for (mtpRequestMap::const_iterator i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { - if (!mtpRequestData::isSentContainer(i.value())) { + auto newId = msgid(); + auto setSeqNumbers = RequestMap(); + auto replaces = QMap(); + for (auto i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { + if (!i.value().isSentContainer()) { if (!*(mtpMsgId*)(i.value()->constData() + 4)) continue; mtpMsgId id = i.key(); @@ -541,11 +540,11 @@ void ConnectionPrivate::resetSession() { // recreate all msg_id and msg_seqno setSeqNumbers.insert(id, i.value()); } } - for (mtpRequestIdsMap::const_iterator i = toResend.cbegin(), e = toResend.cend(); i != e; ++i) { // collect all non-container requests - mtpPreRequestMap::const_iterator j = toSend.constFind(i.value()); + for (auto i = toResend.cbegin(), e = toResend.cend(); i != e; ++i) { // collect all non-container requests + const auto j = toSend.constFind(i.value()); if (j == toSend.cend()) continue; - if (!mtpRequestData::isSentContainer(j.value())) { + if (!j.value().isSentContainer()) { if (!*(mtpMsgId*)(j.value()->constData() + 4)) continue; mtpMsgId id = i.key(); @@ -573,36 +572,36 @@ void ConnectionPrivate::resetSession() { // recreate all msg_id and msg_seqno DEBUG_LOG(("MTP Info: creating new session after bad_msg_notification, setting random server_session %1").arg(session)); sessionData->setSession(session); - for (mtpRequestMap::const_iterator i = setSeqNumbers.cbegin(), e = setSeqNumbers.cend(); i != e; ++i) { // generate new seq_numbers + for (auto i = setSeqNumbers.cbegin(), e = setSeqNumbers.cend(); i != e; ++i) { // generate new seq_numbers bool wasNeedAck = (*(i.value()->data() + 6) & 1); *(i.value()->data() + 6) = sessionData->nextRequestSeqNumber(wasNeedAck); } if (!replaces.isEmpty()) { - for (Replaces::const_iterator i = replaces.cbegin(), e = replaces.cend(); i != e; ++i) { // replace msgIds keys in all data structs - mtpRequestMap::iterator j = haveSent.find(i.key()); + for (auto i = replaces.cbegin(), e = replaces.cend(); i != e; ++i) { // replace msgIds keys in all data structs + const auto j = haveSent.find(i.key()); if (j != haveSent.cend()) { - mtpRequest req = j.value(); + const auto req = j.value(); haveSent.erase(j); haveSent.insert(i.value(), req); } - mtpRequestIdsMap::iterator k = toResend.find(i.key()); + const auto k = toResend.find(i.key()); if (k != toResend.cend()) { - mtpRequestId req = k.value(); + const auto req = k.value(); toResend.erase(k); toResend.insert(i.value(), req); } - k = wereAcked.find(i.key()); - if (k != wereAcked.cend()) { - mtpRequestId req = k.value(); - wereAcked.erase(k); + const auto l = wereAcked.find(i.key()); + if (l != wereAcked.cend()) { + const auto req = l.value(); + wereAcked.erase(l); wereAcked.insert(i.value(), req); } } - for (mtpRequestMap::const_iterator i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { // replace msgIds in saved containers - if (mtpRequestData::isSentContainer(i.value())) { - mtpMsgId *ids = (mtpMsgId *)(i.value()->data() + 8); + for (auto i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { // replace msgIds in saved containers + if (i.value().isSentContainer()) { + mtpMsgId *ids = (mtpMsgId*)(i.value()->data() + 8); for (uint32 j = 0, l = (i.value()->size() - 8) >> 1; j < l; ++j) { - Replaces::const_iterator k = replaces.constFind(ids[j]); + const auto k = replaces.constFind(ids[j]); if (k != replaces.cend()) { ids[j] = k.value(); } @@ -621,24 +620,24 @@ void ConnectionPrivate::resetSession() { // recreate all msg_id and msg_seqno emit sessionResetDone(); } -mtpMsgId ConnectionPrivate::prepareToSend(mtpRequest &request, mtpMsgId currentLastId) { +mtpMsgId ConnectionPrivate::prepareToSend(SecureRequest &request, mtpMsgId currentLastId) { if (request->size() < 9) return 0; mtpMsgId msgId = *(mtpMsgId*)(request->constData() + 4); if (msgId) { // resending this request QWriteLocker locker(sessionData->toResendMutex()); - mtpRequestIdsMap &toResend(sessionData->toResendMap()); - mtpRequestIdsMap::iterator i = toResend.find(msgId); + auto &toResend = sessionData->toResendMap(); + const auto i = toResend.find(msgId); if (i != toResend.cend()) { toResend.erase(i); } } else { msgId = *(mtpMsgId*)(request->data() + 4) = currentLastId; - *(request->data() + 6) = sessionData->nextRequestSeqNumber(mtpRequestData::needAck(request)); + *(request->data() + 6) = sessionData->nextRequestSeqNumber(request.needAck()); } return msgId; } -mtpMsgId ConnectionPrivate::replaceMsgId(mtpRequest &request, mtpMsgId newId) { +mtpMsgId ConnectionPrivate::replaceMsgId(SecureRequest &request, mtpMsgId newId) { if (request->size() < 9) return 0; mtpMsgId oldMsgId = *(mtpMsgId*)(request->constData() + 4); @@ -647,45 +646,45 @@ mtpMsgId ConnectionPrivate::replaceMsgId(mtpRequest &request, mtpMsgId newId) { QWriteLocker locker(sessionData->toResendMutex()); // haveSentMutex() and wereAckedMutex() were locked in tryToSend() - mtpRequestIdsMap &toResend(sessionData->toResendMap()); - mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap()); - mtpRequestMap &haveSent(sessionData->haveSentMap()); + auto &toResend = sessionData->toResendMap(); + auto &wereAcked = sessionData->wereAckedMap(); + auto &haveSent = sessionData->haveSentMap(); while (true) { if (toResend.constFind(newId) == toResend.cend() && wereAcked.constFind(newId) == wereAcked.cend() && haveSent.constFind(newId) == haveSent.cend()) { break; } - mtpMsgId m = msgid(); + const auto m = msgid(); if (m <= newId) break; // wtf newId = m; } - mtpRequestIdsMap::iterator i = toResend.find(oldMsgId); + const auto i = toResend.find(oldMsgId); if (i != toResend.cend()) { - mtpRequestId req = i.value(); + const auto req = i.value(); toResend.erase(i); toResend.insert(newId, req); } - mtpRequestIdsMap::iterator j = wereAcked.find(oldMsgId); + const auto j = wereAcked.find(oldMsgId); if (j != wereAcked.cend()) { - mtpRequestId req = j.value(); + const auto req = j.value(); wereAcked.erase(j); wereAcked.insert(newId, req); } - mtpRequestMap::iterator k = haveSent.find(oldMsgId); + const auto k = haveSent.find(oldMsgId); if (k != haveSent.cend()) { - mtpRequest req = k.value(); + const auto req = k.value(); haveSent.erase(k); haveSent.insert(newId, req); } - for (k = haveSent.begin(); k != haveSent.cend(); ++k) { - mtpRequest req(k.value()); - if (mtpRequestData::isSentContainer(req)) { - mtpMsgId *ids = (mtpMsgId *)(req->data() + 8); + for (auto l = haveSent.begin(); l != haveSent.cend(); ++l) { + const auto req = l.value(); + if (req.isSentContainer()) { + const auto ids = (mtpMsgId *)(req->data() + 8); for (uint32 i = 0, l = (req->size() - 8) >> 1; i < l; ++i) { if (ids[i] == oldMsgId) { ids[i] = newId; @@ -694,20 +693,20 @@ mtpMsgId ConnectionPrivate::replaceMsgId(mtpRequest &request, mtpMsgId newId) { } } } else { - *(request->data() + 6) = sessionData->nextRequestSeqNumber(mtpRequestData::needAck(request)); + *(request->data() + 6) = sessionData->nextRequestSeqNumber(request.needAck()); } *(mtpMsgId*)(request->data() + 4) = newId; } return newId; } -mtpMsgId ConnectionPrivate::placeToContainer(mtpRequest &toSendRequest, mtpMsgId &bigMsgId, mtpMsgId *&haveSentArr, mtpRequest &req) { +mtpMsgId ConnectionPrivate::placeToContainer(SecureRequest &toSendRequest, mtpMsgId &bigMsgId, mtpMsgId *&haveSentArr, SecureRequest &req) { mtpMsgId msgId = prepareToSend(req, bigMsgId); if (msgId > bigMsgId) msgId = replaceMsgId(req, bigMsgId); if (msgId >= bigMsgId) bigMsgId = msgid(); *(haveSentArr++) = msgId; - uint32 from = toSendRequest->size(), len = mtpRequestData::messageSize(req); + uint32 from = toSendRequest->size(), len = req.messageSize(); toSendRequest->resize(from + len); memcpy(toSendRequest->data() + from, req->constData() + 4, len * sizeof(mtpPrime)); @@ -720,10 +719,10 @@ void ConnectionPrivate::tryToSend() { return; } - bool needsLayer = !_connectionOptions->inited; - int32 state = getState(); - bool prependOnly = (state != ConnectedState); - mtpRequest pingRequest; + auto needsLayer = !_connectionOptions->inited; + auto state = getState(); + auto prependOnly = (state != ConnectedState); + auto pingRequest = SecureRequest(); if (_shiftedDcId == BareDcId(_shiftedDcId)) { // main session if (!prependOnly && !_pingIdToSend && !_pingId && _pingSendAt <= getms(true)) { _pingIdToSend = rand_value(); @@ -731,17 +730,17 @@ void ConnectionPrivate::tryToSend() { } if (_pingIdToSend) { if (prependOnly || _shiftedDcId != BareDcId(_shiftedDcId)) { - MTPPing ping(MTPping(MTP_long(_pingIdToSend))); - uint32 pingSize = ping.innerLength() >> 2; // copy from Session::send - pingRequest = mtpRequestData::prepare(pingSize); - ping.write(*pingRequest); - DEBUG_LOG(("MTP Info: sending ping, ping_id: %1").arg(_pingIdToSend)); + pingRequest = SecureRequest::Serialize(MTPPing( + MTP_long(_pingIdToSend) + )); + DEBUG_LOG(("MTP Info: sending ping, ping_id: %1" + ).arg(_pingIdToSend)); } else { - MTPPing_delay_disconnect ping(MTP_long(_pingIdToSend), MTP_int(kPingDelayDisconnect)); - uint32 pingSize = ping.innerLength() >> 2; // copy from Session::send - pingRequest = mtpRequestData::prepare(pingSize); - ping.write(*pingRequest); - DEBUG_LOG(("MTP Info: sending ping_delay_disconnect, ping_id: %1").arg(_pingIdToSend)); + pingRequest = SecureRequest::Serialize(MTPPing_delay_disconnect( + MTP_long(_pingIdToSend), + MTP_int(kPingDelayDisconnect))); + DEBUG_LOG(("MTP Info: sending ping_delay_disconnect, " + "ping_id: %1").arg(_pingIdToSend)); } pingRequest->msDate = getms(true); // > 0 - can send without container @@ -763,24 +762,18 @@ void ConnectionPrivate::tryToSend() { } } - mtpRequest ackRequest, resendRequest, stateRequest, httpWaitRequest; + SecureRequest ackRequest, resendRequest, stateRequest, httpWaitRequest; if (!prependOnly && !ackRequestData.isEmpty()) { - MTPMsgsAck ack(MTP_msgs_ack(MTP_vector(ackRequestData))); - - ackRequest = mtpRequestData::prepare(ack.innerLength() >> 2); - ack.write(*ackRequest); - + ackRequest = SecureRequest::Serialize(MTPMsgsAck( + MTP_msgs_ack(MTP_vector(ackRequestData)))); ackRequest->msDate = getms(true); // > 0 - can send without container ackRequest->requestId = 0; // dont add to haveSent / wereAcked maps ackRequestData.clear(); } if (!prependOnly && !resendRequestData.isEmpty()) { - MTPMsgResendReq resend(MTP_msg_resend_req(MTP_vector(resendRequestData))); - - resendRequest = mtpRequestData::prepare(resend.innerLength() >> 2); - resend.write(*resendRequest); - + resendRequest = SecureRequest::Serialize(MTPMsgResendReq( + MTP_msg_resend_req(MTP_vector(resendRequestData)))); resendRequest->msDate = getms(true); // > 0 - can send without container resendRequest->requestId = 0; // dont add to haveSent / wereAcked maps @@ -790,36 +783,30 @@ void ConnectionPrivate::tryToSend() { QVector stateReq; { QWriteLocker locker(sessionData->stateRequestMutex()); - mtpMsgIdsSet &ids(sessionData->stateRequestMap()); + auto &ids = sessionData->stateRequestMap(); if (!ids.isEmpty()) { stateReq.reserve(ids.size()); - for (mtpMsgIdsSet::const_iterator i = ids.cbegin(), e = ids.cend(); i != e; ++i) { + for (auto i = ids.cbegin(), e = ids.cend(); i != e; ++i) { stateReq.push_back(MTP_long(i.key())); } } ids.clear(); } if (!stateReq.isEmpty()) { - MTPMsgsStateReq req(MTP_msgs_state_req(MTP_vector(stateReq))); - - stateRequest = mtpRequestData::prepare(req.innerLength() >> 2); - req.write(*stateRequest); - + stateRequest = SecureRequest::Serialize(MTPMsgsStateReq( + MTP_msgs_state_req(MTP_vector(stateReq)))); stateRequest->msDate = getms(true); // > 0 - can send without container stateRequest->requestId = GetNextRequestId();// add to haveSent / wereAcked maps, but don't add to requestMap } if (_connection->usingHttpWait()) { - MTPHttpWait req(MTP_http_wait(MTP_int(100), MTP_int(30), MTP_int(25000))); - - httpWaitRequest = mtpRequestData::prepare(req.innerLength() >> 2); - req.write(*httpWaitRequest); - + httpWaitRequest = SecureRequest::Serialize(MTPHttpWait( + MTP_http_wait(MTP_int(100), MTP_int(30), MTP_int(25000)))); httpWaitRequest->msDate = getms(true); // > 0 - can send without container httpWaitRequest->requestId = 0; // dont add to haveSent / wereAcked maps } } - MTPInitConnection initWrapper; + MTPInitConnection initWrapper; int32 initSize = 0, initSizeInInts = 0; if (needsLayer) { Assert(_connectionOptions != nullptr); @@ -845,8 +832,8 @@ void ConnectionPrivate::tryToSend() { MTP_string(_connectionOptions->proxy.host), MTP_int(_connectionOptions->proxy.port)) : MTPInputClientProxy(); - using Flag = MTPInitConnection::Flag; - initWrapper = MTPInitConnection( + using Flag = MTPInitConnection::Flag; + initWrapper = MTPInitConnection( MTP_flags(mtprotoProxy ? Flag::f_proxy : Flag(0)), MTP_int(ApiId), MTP_string(deviceModel), @@ -856,17 +843,18 @@ void ConnectionPrivate::tryToSend() { MTP_string(langPack), MTP_string(cloudLangCode), clientProxyFields, - mtpRequest()); + SecureRequest()); initSizeInInts = (initWrapper.innerLength() >> 2) + 2; initSize = initSizeInInts * sizeof(mtpPrime); } bool needAnyResponse = false; - mtpRequest toSendRequest; + SecureRequest toSendRequest; { QWriteLocker locker1(sessionData->toSendMutex()); - mtpPreRequestMap toSendDummy, &toSend(prependOnly ? toSendDummy : sessionData->toSendMap()); + auto toSendDummy = PreRequestMap(); + auto &toSend = prependOnly ? toSendDummy : sessionData->toSendMap(); if (prependOnly) locker1.unlock(); uint32 toSendCount = toSend.size(); @@ -878,7 +866,7 @@ void ConnectionPrivate::tryToSend() { if (!toSendCount) return; // nothing to send - mtpRequest first = pingRequest ? pingRequest : (ackRequest ? ackRequest : (resendRequest ? resendRequest : (stateRequest ? stateRequest : (httpWaitRequest ? httpWaitRequest : toSend.cbegin().value())))); + auto first = pingRequest ? pingRequest : (ackRequest ? ackRequest : (resendRequest ? resendRequest : (stateRequest ? stateRequest : (httpWaitRequest ? httpWaitRequest : toSend.cbegin().value())))); if (toSendCount == 1 && first->msDate > 0) { // if can send without container toSendRequest = first; if (!prependOnly) { @@ -895,32 +883,35 @@ void ConnectionPrivate::tryToSend() { } if (toSendRequest->requestId) { - if (mtpRequestData::needAck(toSendRequest)) { - toSendRequest->msDate = mtpRequestData::isStateRequest(toSendRequest) ? 0 : getms(true); + if (toSendRequest.needAck()) { + toSendRequest->msDate = toSendRequest.isStateRequest() ? 0 : getms(true); QWriteLocker locker2(sessionData->haveSentMutex()); - mtpRequestMap &haveSent(sessionData->haveSentMap()); + auto &haveSent = sessionData->haveSentMap(); haveSent.insert(msgId, toSendRequest); if (needsLayer && !toSendRequest->needsLayer) needsLayer = false; if (toSendRequest->after) { - int32 toSendSize = toSendRequest.innerLength() >> 2; - mtpRequest wrappedRequest(mtpRequestData::prepare(toSendSize, toSendSize + 3)); // cons + msg_id + const auto toSendSize = toSendRequest.innerLength() >> 2; + auto wrappedRequest = SecureRequest::Prepare( + toSendSize, + toSendSize + 3); wrappedRequest->resize(4); memcpy(wrappedRequest->data(), toSendRequest->constData(), 4 * sizeof(mtpPrime)); wrapInvokeAfter(wrappedRequest, toSendRequest, haveSent); - toSendRequest = wrappedRequest; + toSendRequest = std::move(wrappedRequest); } if (needsLayer) { - int32 noWrapSize = (toSendRequest.innerLength() >> 2), toSendSize = noWrapSize + initSizeInInts; - mtpRequest wrappedRequest(mtpRequestData::prepare(toSendSize)); + const auto noWrapSize = (toSendRequest.innerLength() >> 2); + const auto toSendSize = noWrapSize + initSizeInInts; + auto wrappedRequest = SecureRequest::Prepare(toSendSize); memcpy(wrappedRequest->data(), toSendRequest->constData(), 7 * sizeof(mtpPrime)); // all except length wrappedRequest->push_back(mtpc_invokeWithLayer); wrappedRequest->push_back(internal::CurrentLayer); initWrapper.write(*wrappedRequest); wrappedRequest->resize(wrappedRequest->size() + noWrapSize); memcpy(wrappedRequest->data() + wrappedRequest->size() - noWrapSize, toSendRequest->constData() + 8, noWrapSize * sizeof(mtpPrime)); - toSendRequest = wrappedRequest; + toSendRequest = std::move(wrappedRequest); } needAnyResponse = true; @@ -932,13 +923,13 @@ void ConnectionPrivate::tryToSend() { } else { // send in container bool willNeedInit = false; uint32 containerSize = 1 + 1, idsWrapSize = (toSendCount << 1); // cons + vector size, idsWrapSize - size of "request-like" wrap for msgId vector - if (pingRequest) containerSize += mtpRequestData::messageSize(pingRequest); - if (ackRequest) containerSize += mtpRequestData::messageSize(ackRequest); - if (resendRequest) containerSize += mtpRequestData::messageSize(resendRequest); - if (stateRequest) containerSize += mtpRequestData::messageSize(stateRequest); - if (httpWaitRequest) containerSize += mtpRequestData::messageSize(httpWaitRequest); - for (mtpPreRequestMap::iterator i = toSend.begin(), e = toSend.end(); i != e; ++i) { - containerSize += mtpRequestData::messageSize(i.value()); + if (pingRequest) containerSize += pingRequest.messageSize(); + if (ackRequest) containerSize += ackRequest.messageSize(); + if (resendRequest) containerSize += resendRequest.messageSize(); + if (stateRequest) containerSize += stateRequest.messageSize(); + if (httpWaitRequest) containerSize += httpWaitRequest.messageSize(); + for (auto i = toSend.begin(), e = toSend.end(); i != e; ++i) { + containerSize += i.value().messageSize(); if (needsLayer && i.value()->needsLayer) { containerSize += initSizeInInts; willNeedInit = true; @@ -951,22 +942,28 @@ void ConnectionPrivate::tryToSend() { initSerialized.push_back(internal::CurrentLayer); initWrapper.write(initSerialized); } - toSendRequest = mtpRequestData::prepare(containerSize, containerSize + 3 * toSend.size()); // prepare container + each in invoke after + // prepare container + each in invoke after + toSendRequest = SecureRequest::Prepare( + containerSize, + containerSize + 3 * toSend.size()); toSendRequest->push_back(mtpc_msg_container); toSendRequest->push_back(toSendCount); mtpMsgId bigMsgId = msgid(); // check for a valid container - QWriteLocker locker2(sessionData->haveSentMutex()); // the fact of this lock is used in replaceMsgId() - mtpRequestMap &haveSent(sessionData->haveSentMap()); + // the fact of this lock is used in replaceMsgId() + QWriteLocker locker2(sessionData->haveSentMutex()); + auto &haveSent = sessionData->haveSentMap(); - QWriteLocker locker3(sessionData->wereAckedMutex()); // the fact of this lock is used in replaceMsgId() - mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap()); + // the fact of this lock is used in replaceMsgId() + QWriteLocker locker3(sessionData->wereAckedMutex()); + auto &wereAcked = sessionData->wereAckedMap(); - mtpRequest haveSentIdsWrap(mtpRequestData::prepare(idsWrapSize)); // prepare "request-like" wrap for msgId vector + // prepare "request-like" wrap for msgId vector + auto haveSentIdsWrap = SecureRequest::Prepare(idsWrapSize); haveSentIdsWrap->requestId = 0; haveSentIdsWrap->resize(haveSentIdsWrap->size() + idsWrapSize); - mtpMsgId *haveSentArr = (mtpMsgId*)(haveSentIdsWrap->data() + 8); + auto haveSentArr = (mtpMsgId*)(haveSentIdsWrap->data() + 8); if (pingRequest) { _pingMsgId = placeToContainer(toSendRequest, bigMsgId, haveSentArr, pingRequest); @@ -974,16 +971,16 @@ void ConnectionPrivate::tryToSend() { } else if (resendRequest || stateRequest) { needAnyResponse = true; } - for (mtpPreRequestMap::iterator i = toSend.begin(), e = toSend.end(); i != e; ++i) { - mtpRequest &req(i.value()); - mtpMsgId msgId = prepareToSend(req, bigMsgId); + for (auto i = toSend.begin(), e = toSend.end(); i != e; ++i) { + auto &req = i.value(); + auto msgId = prepareToSend(req, bigMsgId); if (msgId > bigMsgId) msgId = replaceMsgId(req, bigMsgId); if (msgId >= bigMsgId) bigMsgId = msgid(); *(haveSentArr++) = msgId; bool added = false; if (req->requestId) { - if (mtpRequestData::needAck(req)) { - req->msDate = mtpRequestData::isStateRequest(req) ? 0 : getms(true); + if (req.needAck()) { + req->msDate = req.isStateRequest() ? 0 : getms(true); int32 reqNeedsLayer = (needsLayer && req->needsLayer) ? toSendRequest->size() : 0; if (req->after) { wrapInvokeAfter(toSendRequest, req, haveSent, reqNeedsLayer ? initSizeInInts : 0); @@ -993,7 +990,7 @@ void ConnectionPrivate::tryToSend() { } added = true; } else if (reqNeedsLayer) { - toSendRequest->resize(reqNeedsLayer + initSizeInInts + mtpRequestData::messageSize(req)); + toSendRequest->resize(reqNeedsLayer + initSizeInInts + req.messageSize()); memcpy(toSendRequest->data() + reqNeedsLayer, req->constData() + 4, 4 * sizeof(mtpPrime)); memcpy(toSendRequest->data() + reqNeedsLayer + 4, initSerialized.constData(), initSize); memcpy(toSendRequest->data() + reqNeedsLayer + 4 + initSizeInInts, req->constData() + 8, req.innerLength()); @@ -1008,7 +1005,7 @@ void ConnectionPrivate::tryToSend() { } } if (!added) { - uint32 from = toSendRequest->size(), len = mtpRequestData::messageSize(req); + uint32 from = toSendRequest->size(), len = req.messageSize(); toSendRequest->resize(from + len); memcpy(toSendRequest->data() + from, req->constData() + 4, len * sizeof(mtpPrime)); } @@ -1029,8 +1026,10 @@ void ConnectionPrivate::tryToSend() { toSend.clear(); } } - mtpRequestData::padding(toSendRequest); - sendRequest(toSendRequest, needAnyResponse, lockFinished); + sendSecureRequest( + std::move(toSendRequest), + needAnyResponse, + lockFinished); } void ConnectionPrivate::retryByTimer() { @@ -1709,12 +1708,12 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(const mtpPr || (errorCode == 64); // bad container if (errorCode == 64) { // bad container! if (Logs::DebugEnabled()) { - mtpRequest request; + SecureRequest request; { QWriteLocker locker(sessionData->haveSentMutex()); - mtpRequestMap &haveSent(sessionData->haveSentMap()); + auto &haveSent = sessionData->haveSentMap(); - mtpRequestMap::const_iterator i = haveSent.constFind(resendId); + const auto i = haveSent.constFind(resendId); if (i == haveSent.cend()) { LOG(("Message Error: Container not found!")); } else { @@ -1722,9 +1721,9 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(const mtpPr } } if (request) { - if (mtpRequestData::isSentContainer(request)) { + if (request.isSentContainer()) { QStringList lst; - const auto ids = (const mtpMsgId *)(request->constData() + 8); + const auto ids = (const mtpMsgId*)(request->constData() + 8); for (uint32 i = 0, l = (request->size() - 8) >> 1; i < l; ++i) { lst.push_back(QString::number(ids[i])); } @@ -1834,8 +1833,8 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(const mtpPr auto maxRecv = receivedIds.max(); QReadLocker locker(sessionData->wereAckedMutex()); - const mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap()); - mtpRequestIdsMap::const_iterator wereAckedEnd(wereAcked.cend()); + const auto &wereAcked = sessionData->wereAckedMap(); + const auto wereAckedEnd = wereAcked.cend(); for (uint32 i = 0, l = idsCount; i < l; ++i) { char state = 0; @@ -1875,11 +1874,11 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(const mtpPr auto &states = data.vinfo.v; DEBUG_LOG(("Message Info: msg state received, msgId %1, reqMsgId: %2, HEX states %3").arg(msgId).arg(reqMsgId).arg(Logs::mb(states.data(), states.length()).str())); - mtpRequest requestBuffer; + SecureRequest requestBuffer; { // find this request in session-shared sent requests map QReadLocker locker(sessionData->haveSentMutex()); - const mtpRequestMap &haveSent(sessionData->haveSentMap()); - mtpRequestMap::const_iterator replyTo = haveSent.constFind(reqMsgId); + const auto &haveSent = sessionData->haveSentMap(); + const auto replyTo = haveSent.constFind(reqMsgId); if (replyTo == haveSent.cend()) { // do not look in toResend, because we do not resend msgs_state_req requests DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(reqMsgId)); return (badTime ? HandleResult::Ignored : HandleResult::Success); @@ -2087,9 +2086,9 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(const mtpPr QVector toResend; { QReadLocker locker(sessionData->haveSentMutex()); - const mtpRequestMap &haveSent(sessionData->haveSentMap()); + const auto &haveSent = sessionData->haveSentMap(); toResend.reserve(haveSent.size()); - for (mtpRequestMap::const_iterator i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { + for (auto i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { if (i.key() >= firstMsgId) break; if (i.value()->requestId) toResend.push_back(i.key()); } @@ -2247,15 +2246,15 @@ void ConnectionPrivate::requestsAcked(const QVector &ids, bool byRespon QVector toAckMore; { QWriteLocker locker1(sessionData->wereAckedMutex()); - mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap()); + auto &wereAcked = sessionData->wereAckedMap(); { QWriteLocker locker2(sessionData->haveSentMutex()); - mtpRequestMap &haveSent(sessionData->haveSentMap()); + auto &haveSent = sessionData->haveSentMap(); for (uint32 i = 0; i < idsCount; ++i) { mtpMsgId msgId = ids[i].v; - mtpRequestMap::iterator req = haveSent.find(msgId); + const auto req = haveSent.find(msgId); if (req != haveSent.cend()) { if (!req.value()->msDate) { DEBUG_LOG(("Message Info: container ack received, msgId %1").arg(ids[i].v)); @@ -2282,18 +2281,18 @@ void ConnectionPrivate::requestsAcked(const QVector &ids, bool byRespon } else { DEBUG_LOG(("Message Info: msgId %1 was not found in recent sent, while acking requests, searching in resend...").arg(msgId)); QWriteLocker locker3(sessionData->toResendMutex()); - mtpRequestIdsMap &toResend(sessionData->toResendMap()); - mtpRequestIdsMap::iterator reqIt = toResend.find(msgId); + auto &toResend = sessionData->toResendMap(); + const auto reqIt = toResend.find(msgId); if (reqIt != toResend.cend()) { - mtpRequestId reqId = reqIt.value(); + const auto reqId = reqIt.value(); bool moveToAcked = byResponse; if (!moveToAcked) { // ignore ACK, if we need a response (if we have a handler) moveToAcked = !_instance->hasCallbacks(reqId); } if (moveToAcked) { QWriteLocker locker4(sessionData->toSendMutex()); - mtpPreRequestMap &toSend(sessionData->toSendMap()); - mtpPreRequestMap::iterator req = toSend.find(reqId); + auto &toSend = sessionData->toSendMap(); + const auto req = toSend.find(reqId); if (req != toSend.cend()) { wereAcked.insert(msgId, req.value()->requestId); if (req.value()->requestId != reqId) { @@ -2356,13 +2355,13 @@ void ConnectionPrivate::handleMsgsStates(const QVector &ids, const QByt uint64 requestMsgId = ids[i].v; { QReadLocker locker(sessionData->haveSentMutex()); - const mtpRequestMap &haveSent(sessionData->haveSentMap()); - mtpRequestMap::const_iterator haveSentEnd = haveSent.cend(); + const auto &haveSent = sessionData->haveSentMap(); + const auto haveSentEnd = haveSent.cend(); if (haveSent.find(requestMsgId) == haveSentEnd) { DEBUG_LOG(("Message Info: state was received for msgId %1, but request is not found, looking in resent requests...").arg(requestMsgId)); QWriteLocker locker2(sessionData->toResendMutex()); - mtpRequestIdsMap &toResend(sessionData->toResendMap()); - mtpRequestIdsMap::iterator reqIt = toResend.find(requestMsgId); + auto &toResend = sessionData->toResendMap(); + const auto reqIt = toResend.find(requestMsgId); if (reqIt != toResend.cend()) { if ((state & 0x07) != 0x04) { // was received DEBUG_LOG(("Message Info: state was received for msgId %1, state %2, already resending in container").arg(requestMsgId).arg((int32)state)); @@ -2532,7 +2531,6 @@ void ConnectionPrivate::updateAuthKey() { _authKeyData = std::make_unique(); _authKeyStrings = std::make_unique(); - _authKeyData->req_num = 0; _authKeyData->nonce = rand_value(); MTPReq_pq_multi req_pq; @@ -2544,7 +2542,7 @@ void ConnectionPrivate::updateAuthKey() { DEBUG_LOG(("AuthKey Info: sending Req_pq...")); lockFinished.unlock(); - sendRequestNotSecure(req_pq); + sendNotSecureRequest(req_pq); } void ConnectionPrivate::clearMessages() { @@ -2558,7 +2556,7 @@ void ConnectionPrivate::pqAnswered() { DEBUG_LOG(("AuthKey Info: receiving Req_pq answer...")); MTPReq_pq::ResponseType res_pq; - if (!readResponseNotSecure(res_pq)) { + if (!readNotSecureResponse(res_pq)) { return restart(); } @@ -2619,7 +2617,7 @@ void ConnectionPrivate::pqAnswered() { req_DH_params.vp = p_q_inner.c_p_q_inner_data_dc().vp; req_DH_params.vq = p_q_inner.c_p_q_inner_data_dc().vq; req_DH_params.vencrypted_data = MTP_bytes(dhEncString); - sendRequestNotSecure(req_DH_params); + sendNotSecureRequest(req_DH_params); } bytes::vector ConnectionPrivate::encryptPQInnerRSA( @@ -2658,7 +2656,7 @@ void ConnectionPrivate::dhParamsAnswered() { DEBUG_LOG(("AuthKey Info: receiving Req_DH_params answer...")); MTPReq_DH_params::ResponseType res_DH_params; - if (!readResponseNotSecure(res_DH_params)) { + if (!readNotSecureResponse(res_DH_params)) { return restart(); } @@ -2808,7 +2806,7 @@ void ConnectionPrivate::dhClientParamsSend() { req_client_DH_params.vencrypted_data = MTP_string(std::move(sdhEncString)); DEBUG_LOG(("AuthKey Info: sending Req_client_DH_params...")); - sendRequestNotSecure(req_client_DH_params); + sendNotSecureRequest(req_client_DH_params); } std::string ConnectionPrivate::encryptClientDHInner(const MTPClient_DH_Inner_Data &data) { @@ -2845,7 +2843,7 @@ void ConnectionPrivate::dhClientParamsAnswered() { DEBUG_LOG(("AuthKey Info: receiving Req_client_DH_params answer...")); MTPSet_client_DH_params::ResponseType res_client_DH_params; - if (!readResponseNotSecure(res_client_DH_params)) { + if (!readNotSecureResponse(res_client_DH_params)) { lockFinished.unlock(); return restart(); } @@ -3045,38 +3043,23 @@ void ConnectionPrivate::handleError(int errorCode) { void ConnectionPrivate::onReadyData() { } -template -void ConnectionPrivate::sendRequestNotSecure(const TRequest &request) { - try { - mtpBuffer buffer; - uint32 requestSize = request.innerLength() >> 2; +template +void ConnectionPrivate::sendNotSecureRequest(const Request &request) { + auto packet = _connection->prepareNotSecurePacket(request); - buffer.resize(0); - buffer.reserve(8 + requestSize); - buffer.push_back(0); // tcp packet len - buffer.push_back(0); // tcp packet num - buffer.push_back(0); - buffer.push_back(0); - buffer.push_back(_authKeyData->req_num); - buffer.push_back(unixtime()); - buffer.push_back(requestSize * 4); - request.write(buffer); - buffer.push_back(0); // tcp crc32 hash - ++_authKeyData->msgs_sent; + DEBUG_LOG(("AuthKey Info: sending request, size: %1, time: %3" + ).arg(packet.size() - 8 + ).arg(packet[5])); - DEBUG_LOG(("AuthKey Info: sending request, size: %1, num: %2, time: %3").arg(requestSize).arg(_authKeyData->req_num).arg(buffer[5])); + const auto bytesSize = packet.size() * sizeof(mtpPrime); - _connection->sendData(buffer); + _connection->sendData(std::move(packet)); - onSentSome(buffer.size() * sizeof(mtpPrime)); - - } catch (Exception &) { - return restart(); - } + onSentSome(bytesSize); } -template -bool ConnectionPrivate::readResponseNotSecure(TResponse &response) { +template +bool ConnectionPrivate::readNotSecureResponse(Response &response) { onReceivedSome(); try { @@ -3114,12 +3097,20 @@ bool ConnectionPrivate::readResponseNotSecure(TResponse &response) { return true; } -bool ConnectionPrivate::sendRequest(mtpRequest &request, bool needAnyResponse, QReadLocker &lockFinished) { +bool ConnectionPrivate::sendSecureRequest( + SecureRequest &&request, + bool needAnyResponse, + QReadLocker &lockFinished) { + request.addPadding(_connection->requiresExtendedPadding()); uint32 fullSize = request->size(); - if (fullSize < 9) return false; + if (fullSize < 9) { + return false; + } - auto messageSize = mtpRequestData::messageSize(request); - if (messageSize < 5 || fullSize < messageSize + 4) return false; + auto messageSize = request.messageSize(); + if (messageSize < 5 || fullSize < messageSize + 4) { + return false; + } auto lock = ReadLockerAttempt(sessionData->keyMutex()); if (!lock) { @@ -3153,14 +3144,21 @@ bool ConnectionPrivate::sendRequest(mtpRequest &request, bool needAnyResponse, Q uchar encryptedSHA[20]; MTPint128 &msgKey(*(MTPint128*)(encryptedSHA + 4)); - hashSha1(request->constData(), (fullSize - padding) * sizeof(mtpPrime), encryptedSHA); + hashSha1( + request->constData(), + (fullSize - padding) * sizeof(mtpPrime), + encryptedSHA); - mtpBuffer result; - result.resize(9 + fullSize); - *((uint64*)&result[2]) = keyId; - *((MTPint128*)&result[4]) = msgKey; + auto packet = _connection->prepareSecurePacket(keyId, msgKey, fullSize); + const auto prefix = packet.size(); + packet.resize(prefix + fullSize); - aesIgeEncrypt_oldmtp(request->constData(), &result[8], fullSize * sizeof(mtpPrime), key, msgKey); + aesIgeEncrypt_oldmtp( + request->constData(), + &packet[prefix], + fullSize * sizeof(mtpPrime), + key, + msgKey); #else // TDESKTOP_MTPROTO_OLD uchar encryptedSHA256[32]; MTPint128 &msgKey(*(MTPint128*)(encryptedSHA256 + 8)); @@ -3171,21 +3169,25 @@ bool ConnectionPrivate::sendRequest(mtpRequest &request, bool needAnyResponse, Q SHA256_Update(&msgKeyLargeContext, request->constData(), fullSize * sizeof(mtpPrime)); SHA256_Final(encryptedSHA256, &msgKeyLargeContext); - mtpBuffer result; - result.resize(9 + fullSize); - *((uint64*)&result[2]) = keyId; - *((MTPint128*)&result[4]) = msgKey; + auto packet = _connection->prepareSecurePacket(keyId, msgKey, fullSize); + const auto prefix = packet.size(); + packet.resize(prefix + fullSize); - aesIgeEncrypt(request->constData(), &result[8], fullSize * sizeof(mtpPrime), key, msgKey); + aesIgeEncrypt( + request->constData(), + &packet[prefix], + fullSize * sizeof(mtpPrime), + key, + msgKey); #endif // TDESKTOP_MTPROTO_OLD DEBUG_LOG(("MTP Info: sending request, size: %1, num: %2, time: %3").arg(fullSize + 6).arg((*request)[4]).arg((*request)[5])); _connection->setSentEncrypted(); - _connection->sendData(result); + _connection->sendData(std::move(packet)); if (needAnyResponse) { - onSentSome(result.size() * sizeof(mtpPrime)); + onSentSome((prefix + fullSize) * sizeof(mtpPrime)); } return true; @@ -3195,20 +3197,24 @@ mtpRequestId ConnectionPrivate::wasSent(mtpMsgId msgId) const { if (msgId == _pingMsgId) return mtpRequestId(0xFFFFFFFF); { QReadLocker locker(sessionData->haveSentMutex()); - const mtpRequestMap &haveSent(sessionData->haveSentMap()); - mtpRequestMap::const_iterator i = haveSent.constFind(msgId); - if (i != haveSent.cend()) return i.value()->requestId ? i.value()->requestId : mtpRequestId(0xFFFFFFFF); + const auto &haveSent = sessionData->haveSentMap(); + const auto i = haveSent.constFind(msgId); + if (i != haveSent.cend()) { + return i.value()->requestId + ? i.value()->requestId + : mtpRequestId(0xFFFFFFFF); + } } { QReadLocker locker(sessionData->toResendMutex()); - const mtpRequestIdsMap &toResend(sessionData->toResendMap()); - mtpRequestIdsMap::const_iterator i = toResend.constFind(msgId); + const auto &toResend = sessionData->toResendMap(); + const auto i = toResend.constFind(msgId); if (i != toResend.cend()) return i.value(); } { QReadLocker locker(sessionData->wereAckedMutex()); - const mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap()); - mtpRequestIdsMap::const_iterator i = wereAcked.constFind(msgId); + const auto &wereAcked = sessionData->wereAckedMap(); + const auto i = wereAcked.constFind(msgId); if (i != wereAcked.cend()) return i.value(); } return 0; diff --git a/Telegram/SourceFiles/mtproto/connection.h b/Telegram/SourceFiles/mtproto/connection.h index 2f4c8b9b8..10a7ffe7c 100644 --- a/Telegram/SourceFiles/mtproto/connection.h +++ b/Telegram/SourceFiles/mtproto/connection.h @@ -169,11 +169,18 @@ private: void removeTestConnection(not_null connection); int16 getProtocolDcId() const; - mtpMsgId placeToContainer(mtpRequest &toSendRequest, mtpMsgId &bigMsgId, mtpMsgId *&haveSentArr, mtpRequest &req); - mtpMsgId prepareToSend(mtpRequest &request, mtpMsgId currentLastId); - mtpMsgId replaceMsgId(mtpRequest &request, mtpMsgId newId); + mtpMsgId placeToContainer( + SecureRequest &toSendRequest, + mtpMsgId &bigMsgId, + mtpMsgId *&haveSentArr, + SecureRequest &req); + mtpMsgId prepareToSend(SecureRequest &request, mtpMsgId currentLastId); + mtpMsgId replaceMsgId(SecureRequest &request, mtpMsgId newId); - bool sendRequest(mtpRequest &request, bool needAnyResponse, QReadLocker &lockFinished); + bool sendSecureRequest( + SecureRequest &&request, + bool needAnyResponse, + QReadLocker &lockFinished); mtpRequestId wasSent(mtpMsgId msgId) const; enum class HandleResult { @@ -207,11 +214,11 @@ private: void resend(quint64 msgId, qint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false); void resendMany(QVector msgIds, qint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false); - template - void sendRequestNotSecure(const TRequest &request); + template + void sendNotSecureRequest(const Request &request); - template - bool readResponseNotSecure(TResponse &response); + template + bool readNotSecureResponse(Response &response); not_null _instance; DcType _dcType = DcType::Regular; @@ -281,9 +288,6 @@ private: uchar aesKey[32] = { 0 }; uchar aesIV[32] = { 0 }; MTPlong auth_key_hash; - - uint32 req_num = 0; // sent not encrypted request number - uint32 msgs_sent = 0; }; struct AuthKeyCreateStrings { bytes::vector dh_prime; diff --git a/Telegram/SourceFiles/mtproto/connection_abstract.cpp b/Telegram/SourceFiles/mtproto/connection_abstract.cpp index b4b8ff077..2e1bdd75d 100644 --- a/Telegram/SourceFiles/mtproto/connection_abstract.cpp +++ b/Telegram/SourceFiles/mtproto/connection_abstract.cpp @@ -107,30 +107,34 @@ ConnectionPointer::~ConnectionPointer() { reset(); } -AbstractConnection::~AbstractConnection() { +mtpBuffer AbstractConnection::prepareSecurePacket( + uint64 keyId, + MTPint128 msgKey, + uint32 size) const { + auto result = mtpBuffer(); + constexpr auto kTcpPrefixInts = 2; + constexpr auto kAuthKeyIdPosition = kTcpPrefixInts; + constexpr auto kAuthKeyIdInts = 2; + constexpr auto kMessageKeyPosition = kAuthKeyIdPosition + + kAuthKeyIdInts; + constexpr auto kMessageKeyInts = 4; + constexpr auto kPrefixInts = kTcpPrefixInts + + kAuthKeyIdInts + + kMessageKeyInts; + constexpr auto kTcpPostfixInts = 4; + result.reserve(kPrefixInts + size + kTcpPostfixInts); + result.resize(kPrefixInts); + *reinterpret_cast(&result[kAuthKeyIdPosition]) = keyId; + *reinterpret_cast(&result[kMessageKeyPosition]) = msgKey; + return result; } -mtpBuffer AbstractConnection::preparePQFake(const MTPint128 &nonce) { - MTPReq_pq req_pq(nonce); - mtpBuffer buffer; - uint32 requestSize = req_pq.innerLength() >> 2; - - buffer.resize(0); - buffer.reserve(8 + requestSize); - buffer.push_back(0); // tcp packet len - buffer.push_back(0); // tcp packet num - buffer.push_back(0); - buffer.push_back(0); - buffer.push_back(0); - buffer.push_back(unixtime()); - buffer.push_back(requestSize * 4); - req_pq.write(buffer); - buffer.push_back(0); // tcp crc32 hash - - return buffer; +mtpBuffer AbstractConnection::preparePQFake(const MTPint128 &nonce) const { + return prepareNotSecurePacket(MTPReq_pq(nonce)); } -MTPResPQ AbstractConnection::readPQFakeReply(const mtpBuffer &buffer) { +MTPResPQ AbstractConnection::readPQFakeReply( + const mtpBuffer &buffer) const { const mtpPrime *answer(buffer.constData()); uint32 len = buffer.size(); if (len < 5) { diff --git a/Telegram/SourceFiles/mtproto/connection_abstract.h b/Telegram/SourceFiles/mtproto/connection_abstract.h index d7bb8dd09..02c1b898b 100644 --- a/Telegram/SourceFiles/mtproto/connection_abstract.h +++ b/Telegram/SourceFiles/mtproto/connection_abstract.h @@ -59,7 +59,7 @@ public: const ProxyData &proxy); AbstractConnection(const AbstractConnection &other) = delete; AbstractConnection &operator=(const AbstractConnection &other) = delete; - virtual ~AbstractConnection() = 0; + virtual ~AbstractConnection() = default; // virtual constructor static ConnectionPointer Create( @@ -72,7 +72,7 @@ public: virtual TimeMs pingTime() const = 0; virtual TimeMs fullConnectTimeout() const = 0; - virtual void sendData(mtpBuffer &buffer) = 0; // has size + 3, buffer[0] = len, buffer[1] = packetnum, buffer[last] = crc32 + virtual void sendData(mtpBuffer &&buffer) = 0; virtual void disconnectFromServer() = 0; virtual void connectToServer( const QString &ip, @@ -86,6 +86,9 @@ public: virtual bool needHttpWait() { return false; } + virtual bool requiresExtendedPadding() const { + return false; + } virtual int32 debugState() const = 0; @@ -101,6 +104,13 @@ public: return _receivedQueue; } + template + mtpBuffer prepareNotSecurePacket(const Request &request) const; + mtpBuffer prepareSecurePacket( + uint64 keyId, + MTPint128 msgKey, + uint32 size) const; + // Used to emit error(...) with no real code from the server. static constexpr auto kErrorCodeOther = -499; @@ -121,10 +131,49 @@ protected: // first we always send fake MTPReq_pq to see if connection works at all // we send them simultaneously through TCP/HTTP/IPv4/IPv6 to choose the working one - static mtpBuffer preparePQFake(const MTPint128 &nonce); - static MTPResPQ readPQFakeReply(const mtpBuffer &buffer); + mtpBuffer preparePQFake(const MTPint128 &nonce) const; + MTPResPQ readPQFakeReply(const mtpBuffer &buffer) const; }; +template +mtpBuffer AbstractConnection::prepareNotSecurePacket(const Request &request) const { + const auto intsSize = request.innerLength() >> 2; + const auto intsPadding = requiresExtendedPadding() + ? uint32(rand_value() & 0x3F) + : 0; + + auto result = mtpBuffer(); + constexpr auto kTcpPrefixInts = 2; + constexpr auto kAuthKeyIdInts = 2; + constexpr auto kMessageIdInts = 2; + constexpr auto kMessageLengthInts = 1; + constexpr auto kPrefixInts = kTcpPrefixInts + + kAuthKeyIdInts + + kMessageIdInts + + kMessageLengthInts; + constexpr auto kTcpPostfixInts = 4; + + result.reserve(kPrefixInts + intsSize + intsPadding + kTcpPostfixInts); + result.resize(kPrefixInts); + + const auto messageId = &result[kTcpPrefixInts + kAuthKeyIdInts]; + *reinterpret_cast(messageId) = msgid(); + + request.write(result); + + const auto messageLength = messageId + kMessageIdInts; + *messageLength = (result.size() - kPrefixInts + intsPadding) << 2; + + if (intsPadding > 0) { + result.resize(result.size() + intsPadding); + memset_rand( + result.data() + result.size() - intsPadding, + intsPadding * sizeof(mtpPrime)); + } + + return result; +} + } // namespace internal } // namespace MTP diff --git a/Telegram/SourceFiles/mtproto/connection_http.cpp b/Telegram/SourceFiles/mtproto/connection_http.cpp index 7029dacf1..7882a09ce 100644 --- a/Telegram/SourceFiles/mtproto/connection_http.cpp +++ b/Telegram/SourceFiles/mtproto/connection_http.cpp @@ -29,17 +29,14 @@ ConnectionPointer HttpConnection::clone(const ProxyData &proxy) { return ConnectionPointer::New(thread(), proxy); } -void HttpConnection::sendData(mtpBuffer &buffer) { - if (_status == Status::Finished) return; +void HttpConnection::sendData(mtpBuffer &&buffer) { + Expects(buffer.size() > 2); - if (buffer.size() < 3) { - LOG(("TCP Error: writing bad packet, len = %1").arg(buffer.size() * sizeof(mtpPrime))); - TCP_LOG(("TCP Error: bad packet %1").arg(Logs::mb(&buffer[0], buffer.size() * sizeof(mtpPrime)).str())); - emit error(kErrorCodeOther); + if (_status == Status::Finished) { return; } - int32 requestSize = (buffer.size() - 3) * sizeof(mtpPrime); + int32 requestSize = (buffer.size() - 2) * sizeof(mtpPrime); QNetworkRequest request(url()); request.setHeader(QNetworkRequest::ContentLengthHeader, QVariant(requestSize)); @@ -77,7 +74,7 @@ void HttpConnection::connectToServer( this, &HttpConnection::requestFinished); - mtpBuffer buffer(preparePQFake(_checkNonce)); + auto buffer = preparePQFake(_checkNonce); DEBUG_LOG(("HTTP Info: " "dc:%1 - Sending fake req_pq to '%2'" @@ -85,7 +82,7 @@ void HttpConnection::connectToServer( ).arg(url().toDisplayString())); _pingTime = getms(); - sendData(buffer); + sendData(std::move(buffer)); } mtpBuffer HttpConnection::handleResponse(QNetworkReply *reply) { diff --git a/Telegram/SourceFiles/mtproto/connection_http.h b/Telegram/SourceFiles/mtproto/connection_http.h index 3a8ed3e92..6e92d20f7 100644 --- a/Telegram/SourceFiles/mtproto/connection_http.h +++ b/Telegram/SourceFiles/mtproto/connection_http.h @@ -20,7 +20,7 @@ public: TimeMs pingTime() const override; TimeMs fullConnectTimeout() const override; - void sendData(mtpBuffer &buffer) override; + void sendData(mtpBuffer &&buffer) override; void disconnectFromServer() override; void connectToServer( const QString &address, diff --git a/Telegram/SourceFiles/mtproto/connection_resolving.cpp b/Telegram/SourceFiles/mtproto/connection_resolving.cpp index 5f528a7a0..b32a2e275 100644 --- a/Telegram/SourceFiles/mtproto/connection_resolving.cpp +++ b/Telegram/SourceFiles/mtproto/connection_resolving.cpp @@ -189,10 +189,16 @@ TimeMs ResolvingConnection::fullConnectTimeout() const { return kOneConnectionTimeout * qMax(int(_proxy.resolvedIPs.size()), 1); } -void ResolvingConnection::sendData(mtpBuffer &buffer) { +void ResolvingConnection::sendData(mtpBuffer &&buffer) { Expects(_child != nullptr); - _child->sendData(buffer); + _child->sendData(std::move(buffer)); +} + +bool ResolvingConnection::requiresExtendedPadding() const { + Expects(_child != nullptr); + + return _child->requiresExtendedPadding(); } void ResolvingConnection::disconnectFromServer() { diff --git a/Telegram/SourceFiles/mtproto/connection_resolving.h b/Telegram/SourceFiles/mtproto/connection_resolving.h index ed80ba3d5..bd8df9aa4 100644 --- a/Telegram/SourceFiles/mtproto/connection_resolving.h +++ b/Telegram/SourceFiles/mtproto/connection_resolving.h @@ -26,7 +26,7 @@ public: TimeMs pingTime() const override; TimeMs fullConnectTimeout() const override; - void sendData(mtpBuffer &buffer) override; + void sendData(mtpBuffer &&buffer) override; void disconnectFromServer() override; void connectToServer( const QString &address, @@ -34,6 +34,7 @@ public: const bytes::vector &protocolSecret, int16 protocolDcId) override; bool isConnected() const override; + bool requiresExtendedPadding() const override; int32 debugState() const override; diff --git a/Telegram/SourceFiles/mtproto/connection_tcp.cpp b/Telegram/SourceFiles/mtproto/connection_tcp.cpp index 0b6ce1af6..978c08623 100644 --- a/Telegram/SourceFiles/mtproto/connection_tcp.cpp +++ b/Telegram/SourceFiles/mtproto/connection_tcp.cpp @@ -37,6 +37,147 @@ const auto QTcpSocket_error = ErrorSignal(&QAbstractSocket::error); } // namespace +class TcpConnection::Protocol { +public: + static std::unique_ptr Create(bytes::vector &&secret); + + virtual uint32 id() const = 0; + virtual bool requiresExtendedPadding() const = 0; + virtual bool supportsArbitraryLength() const = 0; + virtual void prepareKey(bytes::span key, bytes::const_span source) = 0; + virtual bytes::span finalizePacket(mtpBuffer &buffer) = 0; + + virtual ~Protocol() = default; + +private: + class Version0; + class Version1; + class VersionD; + +}; + +class TcpConnection::Protocol::Version0 : public Protocol { +public: + uint32 id() const override; + bool requiresExtendedPadding() const override; + bool supportsArbitraryLength() const override; + void prepareKey(bytes::span key, bytes::const_span source) override; + bytes::span finalizePacket(mtpBuffer &buffer) override; + +}; + +uint32 TcpConnection::Protocol::Version0::id() const { + return 0xEFEFEFEFU; +} + +bool TcpConnection::Protocol::Version0::requiresExtendedPadding() const { + return false; +} + +bool TcpConnection::Protocol::Version0::supportsArbitraryLength() const { + return false; +} + +void TcpConnection::Protocol::Version0::prepareKey( + bytes::span key, + bytes::const_span source) { + bytes::copy(key, source); +} + +bytes::span TcpConnection::Protocol::Version0::finalizePacket( + mtpBuffer &buffer) { + Expects(buffer.size() > 2 && buffer.size() < 0x1000003U); + + const auto intsSize = uint32(buffer.size() - 2); + const auto bytesSize = intsSize * sizeof(mtpPrime); + const auto data = reinterpret_cast(&buffer[0]); + const auto added = [&] { + if (intsSize < 0x7F) { + data[7] = uchar(intsSize); + return 1; + } + data[4] = uchar(0x7F); + data[5] = uchar(intsSize & 0xFF); + data[6] = uchar((intsSize >> 8) & 0xFF); + data[7] = uchar((intsSize >> 16) & 0xFF); + return 4; + }(); + return bytes::make_span(buffer).subspan(8 - added, added + bytesSize); +} + +class TcpConnection::Protocol::Version1 : public Version0 { +public: + explicit Version1(bytes::vector &&secret); + + bool requiresExtendedPadding() const override; + void prepareKey(bytes::span key, bytes::const_span source) override; + +private: + bytes::vector _secret; + +}; + +TcpConnection::Protocol::Version1::Version1(bytes::vector &&secret) +: _secret(std::move(secret)) { +} + +bool TcpConnection::Protocol::Version1::requiresExtendedPadding() const { + return true; +} + +void TcpConnection::Protocol::Version1::prepareKey( + bytes::span key, + bytes::const_span source) { + const auto payload = bytes::concatenate(source, _secret); + bytes::copy(key, openssl::Sha256(payload)); +} + +class TcpConnection::Protocol::VersionD : public Version1 { +public: + using Version1::Version1; + + uint32 id() const override; + bool supportsArbitraryLength() const override; + bytes::span finalizePacket(mtpBuffer &buffer) override; + +}; + +uint32 TcpConnection::Protocol::VersionD::id() const { + return 0xDDDDDDDDU; +} + +bool TcpConnection::Protocol::VersionD::supportsArbitraryLength() const { + return true; +} + +bytes::span TcpConnection::Protocol::VersionD::finalizePacket( + mtpBuffer &buffer) { + Expects(buffer.size() > 2 && buffer.size() < 0x1000003U); + + const auto intsSize = uint32(buffer.size() - 2); + const auto padding = rand_value() & 0x0F; + const auto bytesSize = intsSize * sizeof(mtpPrime) + padding; + buffer[1] = bytesSize; + for (auto added = 0; added < padding; added += 4) { + buffer.push_back(rand_value()); + } + + return bytes::make_span(buffer).subspan(4, 4 + bytesSize); +} + +auto TcpConnection::Protocol::Create(bytes::vector &&secret) +-> std::unique_ptr { + if (secret.size() == 17 && static_cast(secret[0]) == 0xDD) { + return std::make_unique( + bytes::make_vector(bytes::make_span(secret).subspan(1))); + } else if (secret.size() == 16) { + return std::make_unique(std::move(secret)); + } else if (secret.empty()) { + return std::make_unique(); + } + Unexpected("Secret bytes in TcpConnection::Protocol::Create."); +} + TcpConnection::TcpConnection(QThread *thread, const ProxyData &proxy) : AbstractConnection(thread, proxy) , _currentPosition(reinterpret_cast(_shortBuffer)) @@ -99,7 +240,10 @@ void TcpConnection::socketRead() { } int32 bytes = (int32)_socket.read(_currentPosition, toRead); if (bytes > 0) { - aesCtrEncrypt(_currentPosition, bytes, _receiveKey, &_receiveState); + aesCtrEncrypt( + bytes::make_span(_currentPosition, bytes), + _receiveKey, + &_receiveState); TCP_LOG(("TCP Info: read %1 bytes").arg(bytes)); _packetRead += bytes; @@ -182,11 +326,10 @@ mtpBuffer TcpConnection::handleResponse(const char *packet, uint32 length) { if (size == 1) { LOG(("TCP Error: " "error packet received, endpoint: '%1:%2', " - "protocolDcId: %3, secret_len: %4, code = %5" + "protocolDcId: %3, code = %4" ).arg(_address.isEmpty() ? ("proxy_" + _proxy.host) : _address ).arg(_address.isEmpty() ? _proxy.port : _port ).arg(_protocolDcId - ).arg(_protocolSecret.size() ).arg(*packetdata)); return mtpBuffer(1, *packetdata); } @@ -247,7 +390,7 @@ void TcpConnection::socketConnected() { ).arg(_address + ':' + QString::number(_port))); _pingTime = getms(); - sendData(buffer); + sendData(std::move(buffer)); } void TcpConnection::socketDisconnected() { @@ -256,20 +399,23 @@ void TcpConnection::socketDisconnected() { } } -void TcpConnection::sendData(mtpBuffer &buffer) { - if (_status == Status::Finished) return; +bool TcpConnection::requiresExtendedPadding() const { + Expects(_protocol != nullptr); - if (buffer.size() < 3) { - LOG(("TCP Error: writing bad packet, len = %1").arg(buffer.size() * sizeof(mtpPrime))); - TCP_LOG(("TCP Error: bad packet %1").arg(Logs::mb(&buffer[0], buffer.size() * sizeof(mtpPrime)).str())); - emit error(kErrorCodeOther); - return; + return _protocol->requiresExtendedPadding(); +} + +void TcpConnection::sendData(mtpBuffer &&buffer) { + Expects(buffer.size() > 2); + + if (_status != Status::Finished) { + sendBuffer(std::move(buffer)); } - - sendBuffer(buffer); } void TcpConnection::writeConnectionStart() { + Expects(_protocol != nullptr); + // prepare random part auto nonceBytes = bytes::vector(64); const auto nonce = bytes::make_span(nonceBytes); @@ -282,6 +428,7 @@ void TcpConnection::writeConnectionStart() { const auto reserved12 = 0x54534F50U; const auto reserved13 = 0x20544547U; const auto reserved14 = 0xEEEEEEEEU; + const auto reserved15 = 0xDDDDDDDDU; const auto reserved21 = 0x00000000U; do { bytes::set_random(nonce); @@ -290,21 +437,11 @@ void TcpConnection::writeConnectionStart() { || *first == reserved12 || *first == reserved13 || *first == reserved14 + || *first == reserved15 || *second == reserved21); - const auto prepareKey = [&](bytes::span key, bytes::const_span from) { - if (_protocolSecret.size() == 16) { - const auto payload = bytes::concatenate(from, _protocolSecret); - bytes::copy(key, openssl::Sha256(payload)); - } else if (_protocolSecret.empty()) { - bytes::copy(key, from); - } else { - bytes::set_with_const(key, gsl::byte{}); - } - }; - // prepare encryption key/iv - prepareKey( + _protocol->prepareKey( bytes::make_span(_sendKey), nonce.subspan(8, CTRState::KeySize)); bytes::copy( @@ -316,7 +453,7 @@ void TcpConnection::writeConnectionStart() { const auto reversed = bytes::make_span(reversedBytes); bytes::copy(reversed, nonce.subspan(8, reversed.size())); std::reverse(reversed.begin(), reversed.end()); - prepareKey( + _protocol->prepareKey( bytes::make_span(_receiveKey), reversed.subspan(0, CTRState::KeySize)); bytes::copy( @@ -325,40 +462,32 @@ void TcpConnection::writeConnectionStart() { // write protocol and dc ids const auto protocol = reinterpret_cast(nonce.data() + 56); - *protocol = 0xEFEFEFEFU; + *protocol = _protocol->id(); const auto dcId = reinterpret_cast(nonce.data() + 60); *dcId = _protocolDcId; _socket.write(reinterpret_cast(nonce.data()), 56); - aesCtrEncrypt(nonce.data(), 64, _sendKey, &_sendState); + aesCtrEncrypt(nonce, _sendKey, &_sendState); _socket.write(reinterpret_cast(nonce.subspan(56).data()), 8); } -void TcpConnection::sendBuffer(mtpBuffer &buffer) { +void TcpConnection::sendBuffer(mtpBuffer &&buffer) { if (!_packetIndex++) { writeConnectionStart(); } - uint32 size = buffer.size() - 3, len = size * 4; - char *data = reinterpret_cast(&buffer[0]); - if (size < 0x7f) { - data[7] = char(size); - TCP_LOG(("TCP Info: write %1 packet %2").arg(_packetIndex).arg(len + 1)); - - aesCtrEncrypt(data + 7, len + 1, _sendKey, &_sendState); - _socket.write(data + 7, len + 1); - } else { - data[4] = 0x7f; - reinterpret_cast(data)[5] = uchar(size & 0xFF); - reinterpret_cast(data)[6] = uchar((size >> 8) & 0xFF); - reinterpret_cast(data)[7] = uchar((size >> 16) & 0xFF); - TCP_LOG(("TCP Info: write %1 packet %2").arg(_packetIndex).arg(len + 4)); - - aesCtrEncrypt(data + 4, len + 4, _sendKey, &_sendState); - _socket.write(data + 4, len + 4); - } + // buffer: 2 available int-s + data + available int. + const auto bytes = _protocol->finalizePacket(buffer); + TCP_LOG(("TCP Info: write %1 packet %2" + ).arg(_packetIndex + ).arg(bytes.size())); + aesCtrEncrypt(bytes, _sendKey, &_sendState); + _socket.write( + reinterpret_cast(bytes.data()), + bytes.size()); } + void TcpConnection::disconnectFromServer() { if (_status == Status::Finished) return; _status = Status::Finished; @@ -377,13 +506,14 @@ void TcpConnection::connectToServer( int16 protocolDcId) { Expects(_address.isEmpty()); Expects(_port == 0); - Expects(_protocolSecret.empty()); + Expects(_protocol == nullptr); Expects(_protocolDcId == 0); if (_proxy.type == ProxyData::Type::Mtproto) { _address = _proxy.host; _port = _proxy.port; - _protocolSecret = ProtocolSecretFromPassword(_proxy.password); + _protocol = Protocol::Create( + ProtocolSecretFromPassword(_proxy.password)); DEBUG_LOG(("TCP Info: " "dc:%1 - Connecting to proxy '%2'" @@ -392,7 +522,7 @@ void TcpConnection::connectToServer( } else { _address = address; _port = port; - _protocolSecret = protocolSecret; + _protocol = Protocol::Create(base::duplicate(protocolSecret)); DEBUG_LOG(("TCP Info: " "dc:%1 - Connecting to '%2'" @@ -479,5 +609,7 @@ void TcpConnection::socketError(QAbstractSocket::SocketError e) { emit error(kErrorCodeOther); } +TcpConnection::~TcpConnection() = default; + } // namespace internal } // namespace MTP diff --git a/Telegram/SourceFiles/mtproto/connection_tcp.h b/Telegram/SourceFiles/mtproto/connection_tcp.h index cbe399653..c98c66087 100644 --- a/Telegram/SourceFiles/mtproto/connection_tcp.h +++ b/Telegram/SourceFiles/mtproto/connection_tcp.h @@ -24,7 +24,7 @@ public: TimeMs pingTime() const override; TimeMs fullConnectTimeout() const override; - void sendData(mtpBuffer &buffer) override; + void sendData(mtpBuffer &&buffer) override; void disconnectFromServer() override; void connectToServer( const QString &address, @@ -32,12 +32,15 @@ public: const bytes::vector &protocolSecret, int16 protocolDcId) override; bool isConnected() const override; + bool requiresExtendedPadding() const override; int32 debugState() const override; QString transport() const override; QString tag() const override; + ~TcpConnection(); + private: enum class Status { Waiting = 0, @@ -62,7 +65,7 @@ private: return *reinterpret_cast(ch); } - void sendBuffer(mtpBuffer &buffer); + void sendBuffer(mtpBuffer &&buffer); QTcpSocket _socket; uint32 _packetIndex = 0; // sent packet number @@ -78,8 +81,9 @@ private: CTRState _sendState; uchar _receiveKey[CTRState::KeySize]; CTRState _receiveState; + class Protocol; + std::unique_ptr _protocol; int16 _protocolDcId = 0; - bytes::vector _protocolSecret; Status _status = Status::Waiting; MTPint128 _checkNonce; diff --git a/Telegram/SourceFiles/mtproto/core_types.cpp b/Telegram/SourceFiles/mtproto/core_types.cpp index b54241c04..8a2761950 100644 --- a/Telegram/SourceFiles/mtproto/core_types.cpp +++ b/Telegram/SourceFiles/mtproto/core_types.cpp @@ -9,6 +9,144 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "zlib.h" +namespace MTP { +namespace { + +uint32 CountPaddingAmountInInts(uint32 requestSize, bool extended) { +#ifdef TDESKTOP_MTPROTO_OLD + return ((8 + requestSize) & 0x03) + ? (4 - ((8 + requestSize) & 0x03)) + : 0; +#else // TDESKTOP_MTPROTO_OLD + auto result = ((8 + requestSize) & 0x03) + ? (4 - ((8 + requestSize) & 0x03)) + : 0; + + // At least 12 bytes of random padding. + if (result < 3) { + result += 4; + } + + if (extended) { + // Some more random padding. + result += ((rand_value() & 0x0F) << 2); + } + + return result; +#endif // TDESKTOP_MTPROTO_OLD +} + +} // namespace + +SecureRequest::SecureRequest(const details::SecureRequestCreateTag &tag) +: _data(std::make_shared(tag)) { +} + +SecureRequest SecureRequest::Prepare(uint32 size, uint32 reserveSize) { + const auto finalSize = std::max(size, reserveSize); + + auto result = SecureRequest(details::SecureRequestCreateTag{}); + result->reserve(kMessageBodyPosition + finalSize); + result->resize(kMessageBodyPosition); + result->back() = (size << 2); + return result; +} + +uint32 SecureRequest::innerLength() const { + if (!_data || _data->size() <= kMessageBodyPosition) { + return 0; + } + return (*_data)[kMessageLengthPosition]; +} + +void SecureRequest::write(mtpBuffer &to) const { + if (!_data || _data->size() <= kMessageBodyPosition) { + return; + } + uint32 was = to.size(), s = innerLength() / sizeof(mtpPrime); + to.resize(was + s); + memcpy( + to.data() + was, + _data->constData() + kMessageBodyPosition, + s * sizeof(mtpPrime)); +} + +SecureRequestData *SecureRequest::operator->() const { + Expects(_data != nullptr); + + return _data.get(); +} + +SecureRequestData &SecureRequest::operator*() const { + Expects(_data != nullptr); + + return *_data; +} + +SecureRequest::operator bool() const { + return (_data != nullptr); +} + +void SecureRequest::addPadding(bool extended) { + if (_data->size() <= kMessageBodyPosition) return; + + const auto requestSize = (innerLength() >> 2); + const auto padding = CountPaddingAmountInInts(requestSize, extended); + const auto fullSize = kMessageBodyPosition + requestSize + padding; + if (uint32(_data->size()) != fullSize) { + _data->resize(fullSize); + if (padding > 0) { + memset_rand( + _data->data() + (fullSize - padding), + padding * sizeof(mtpPrime)); + } + } +} + +uint32 SecureRequest::messageSize() const { + if (_data->size() <= kMessageBodyPosition) { + return 0; + } + const auto ints = (innerLength() >> 2); + return kMessageIdInts + kSeqNoInts + kMessageLengthInts + ints; +} + +bool SecureRequest::isSentContainer() const { + if (_data->size() <= kMessageBodyPosition) { + return false; + } + return (!_data->msDate && !(*_data)[kSeqNoPosition]); // msDate = 0, seqNo = 0 +} + +bool SecureRequest::isStateRequest() const { + if (_data->size() <= kMessageBodyPosition) { + return false; + } + const auto type = mtpTypeId((*_data)[kMessageBodyPosition]); + return (type == mtpc_msgs_state_req); +} + +bool SecureRequest::needAck() const { + if (_data->size() <= kMessageBodyPosition) { + return false; + } + const auto type = mtpTypeId((*_data)[kMessageBodyPosition]); + switch (type) { + case mtpc_msg_container: + case mtpc_msgs_ack: + case mtpc_http_wait: + case mtpc_bad_msg_notification: + case mtpc_msgs_all_info: + case mtpc_msgs_state_info: + case mtpc_msg_detailed_info: + case mtpc_msg_new_detailed_info: + return false; + } + return true; +} + +} // namespace MTP + Exception::Exception(const QString &msg) noexcept : _msg(msg.toUtf8()) { LOG(("Exception: %1").arg(msg)); } @@ -91,85 +229,6 @@ void MTPstring::write(mtpBuffer &to) const { memcpy(buf, v.constData(), l); } -uint32 mtpRequest::innerLength() const { // for template MTP requests and MTPBoxed instanciation - const auto value = get(); - if (!value || value->size() < 9) { - return 0; - } - return value->at(7); -} - -void mtpRequest::write(mtpBuffer &to) const { - const auto value = get(); - if (!value || value->size() < 9) { - return; - } - uint32 was = to.size(), s = innerLength() / sizeof(mtpPrime); - to.resize(was + s); - memcpy(to.data() + was, value->constData() + 8, s * sizeof(mtpPrime)); -} - -bool mtpRequestData::isSentContainer(const mtpRequest &request) { // "request-like" wrap for msgIds vector - if (request->size() < 9) return false; - return (!request->msDate && !(*request)[6]); // msDate = 0, seqNo = 0 -} - -bool mtpRequestData::isStateRequest(const mtpRequest &request) { - if (request->size() < 9) return false; - return (mtpTypeId((*request)[8]) == mtpc_msgs_state_req); -} - -bool mtpRequestData::needAckByType(mtpTypeId type) { - switch (type) { - case mtpc_msg_container: - case mtpc_msgs_ack: - case mtpc_http_wait: - case mtpc_bad_msg_notification: - case mtpc_msgs_all_info: - case mtpc_msgs_state_info: - case mtpc_msg_detailed_info: - case mtpc_msg_new_detailed_info: - return false; - } - return true; -} - -mtpRequest mtpRequestData::prepare(uint32 requestSize, uint32 maxSize) { - if (!maxSize) maxSize = requestSize; - mtpRequest result(new mtpRequestData(true)); - result->reserve(8 + maxSize + _padding(maxSize)); // 2: salt, 2: session_id, 2: msg_id, 1: seq_no, 1: message_length - result->resize(7); - result->push_back(requestSize << 2); - return result; -} - -void mtpRequestData::padding(mtpRequest &request) { - if (request->size() < 9) return; - - uint32 requestSize = (request.innerLength() >> 2), padding = _padding(requestSize), fullSize = 8 + requestSize + padding; // 2: salt, 2: session_id, 2: msg_id, 1: seq_no, 1: message_length - if (uint32(request->size()) != fullSize) { - request->resize(fullSize); - if (padding) { - memset_rand(request->data() + (fullSize - padding), padding * sizeof(mtpPrime)); - } - } -} - -uint32 mtpRequestData::_padding(uint32 requestSize) { -#ifdef TDESKTOP_MTPROTO_OLD - return ((8 + requestSize) & 0x03) ? (4 - ((8 + requestSize) & 0x03)) : 0; -#else // TDESKTOP_MTPROTO_OLD - auto result = ((8 + requestSize) & 0x03) ? (4 - ((8 + requestSize) & 0x03)) : 0; - - // At least 12 bytes of random padding. - if (result < 3) { - result += 4; - } - - return result; -#endif // TDESKTOP_MTPROTO_OLD -} - void mtpTextSerializeCore(MTPStringLogger &to, const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons, uint32 level, mtpPrime vcons) { switch (mtpTypeId(cons)) { case mtpc_int: { diff --git a/Telegram/SourceFiles/mtproto/core_types.h b/Telegram/SourceFiles/mtproto/core_types.h index d5ae244c9..1658a26dd 100644 --- a/Telegram/SourceFiles/mtproto/core_types.h +++ b/Telegram/SourceFiles/mtproto/core_types.h @@ -19,6 +19,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/algorithm.h" #include "base/assertion.h" +using mtpPrime = int32; +using mtpRequestId = int32; +using mtpMsgId = uint64; +using mtpPingId = uint64; + +using mtpBuffer = QVector; +using mtpTypeId = uint32; + namespace MTP { // type DcId represents actual data center id, while in most cases @@ -51,89 +59,6 @@ constexpr int GetDcIdShift(ShiftedDcId shiftedDcId) { } // namespace MTP -using mtpPrime = int32; -using mtpRequestId = int32; -using mtpMsgId = uint64; -using mtpPingId = uint64; - -using mtpBuffer = QVector; -using mtpTypeId = uint32; - -class mtpRequestData; -class mtpRequest : public std::shared_ptr { -public: - mtpRequest() = default; - explicit mtpRequest(mtpRequestData *ptr) - : std::shared_ptr(ptr) { - } - - uint32 innerLength() const; - void write(mtpBuffer &to) const; - - using ResponseType = void; // don't know real response type =( - -}; - -class mtpRequestData : public mtpBuffer { -public: - // in toSend: = 0 - must send in container, > 0 - can send without container - // in haveSent: = 0 - container with msgIds, > 0 - when was sent - int64 msDate = 0; - - mtpRequestId requestId = 0; - mtpRequest after; - bool needsLayer = false; - - mtpRequestData(bool/* sure*/) { - } - - static mtpRequest prepare(uint32 requestSize, uint32 maxSize = 0); - static void padding(mtpRequest &request); - - template - static mtpRequest serialize(const TRequest &request) { - const auto requestSize = request.innerLength() >> 2; - auto serialized = prepare(requestSize); - request.write(*serialized); - return serialized; - } - - static uint32 messageSize(const mtpRequest &request) { - if (request->size() < 9) return 0; - return 4 + (request.innerLength() >> 2); // 2: msg_id, 1: seq_no, q: message_length - } - - static bool isSentContainer(const mtpRequest &request); // "request-like" wrap for msgIds vector - static bool isStateRequest(const mtpRequest &request); - static bool needAck(const mtpRequest &request) { - if (request->size() < 9) return false; - return mtpRequestData::needAckByType((*request)[8]); - } - static bool needAckByType(mtpTypeId type); - -private: - static uint32 _padding(uint32 requestSize); - -}; - -using mtpPreRequestMap = QMap; -using mtpRequestMap = QMap; -using mtpMsgIdsSet = QMap; - -class mtpRequestIdsMap : public QMap { -public: - using ParentType = QMap; - - mtpMsgId min() const { - return size() ? cbegin().key() : 0; - } - - mtpMsgId max() const { - ParentType::const_iterator e(cend()); - return size() ? (--e).key() : 0; - } -}; - class Exception : public std::exception { public: explicit Exception(const QString &msg) noexcept; @@ -349,6 +274,100 @@ class MTPBoxed > { typename T::CantMakeBoxedBoxedType v; }; +namespace MTP { +namespace details { + +struct SecureRequestCreateTag { +}; + +} // namespace details + +template +struct is_boxed : std::false_type { +}; + +template +struct is_boxed> : std::true_type { +}; + +template +constexpr bool is_boxed_v = is_boxed::value; + +class SecureRequestData; +class SecureRequest { +public: + SecureRequest() = default; + + static constexpr auto kSaltInts = 2; + static constexpr auto kSessionIdInts = 2; + static constexpr auto kMessageIdInts = 2; + static constexpr auto kSeqNoPosition = kSaltInts + + kSessionIdInts + + kMessageIdInts; + static constexpr auto kSeqNoInts = 1; + static constexpr auto kMessageLengthPosition = kSeqNoPosition + + kSeqNoInts; + static constexpr auto kMessageLengthInts = 1; + static constexpr auto kMessageBodyPosition = kMessageLengthPosition + + kMessageLengthInts; + + static SecureRequest Prepare(uint32 size, uint32 reserveSize = 0); + + template < + typename Request, + typename = std::enable_if_t>> + static SecureRequest Serialize(const Request &request); + + // For template MTP requests and MTPBoxed instanciation. + uint32 innerLength() const; + void write(mtpBuffer &to) const; + + SecureRequestData *operator->() const; + SecureRequestData &operator*() const; + explicit operator bool() const; + + void addPadding(bool extended); + uint32 messageSize() const; + + // "request-like" wrap for msgIds vector + bool isSentContainer() const; + bool isStateRequest() const; + bool needAck() const; + + using ResponseType = void; // don't know real response type =( + +private: + explicit SecureRequest(const details::SecureRequestCreateTag &); + + std::shared_ptr _data; + +}; + +class SecureRequestData : public mtpBuffer { +public: + explicit SecureRequestData(const details::SecureRequestCreateTag &) { + } + + // in toSend: = 0 - must send in container, > 0 - can send without container + // in haveSent: = 0 - container with msgIds, > 0 - when was sent + int64 msDate = 0; + + mtpRequestId requestId = 0; + SecureRequest after; + bool needsLayer = false; + +}; + +template +SecureRequest SecureRequest::Serialize(const Request &request) { + const auto requestSize = request.innerLength() >> 2; + auto serialized = Prepare(requestSize); + request.write(*serialized); + return serialized; +} + +} // namespace MTP + class MTPint { public: int32 v = 0; diff --git a/Telegram/SourceFiles/mtproto/mtp_instance.cpp b/Telegram/SourceFiles/mtproto/mtp_instance.cpp index ea35f2235..67d8d6918 100644 --- a/Telegram/SourceFiles/mtproto/mtp_instance.cpp +++ b/Telegram/SourceFiles/mtproto/mtp_instance.cpp @@ -78,7 +78,7 @@ public: void sendRequest( mtpRequestId requestId, - mtpRequest &&request, + SecureRequest &&request, RPCResponseHandler &&callbacks, ShiftedDcId shiftedDcId, TimeMs msCanWait, @@ -88,9 +88,9 @@ public: void unregisterRequest(mtpRequestId requestId); void storeRequest( mtpRequestId requestId, - const mtpRequest &request, + const SecureRequest &request, RPCResponseHandler &&callbacks); - mtpRequest getRequest(mtpRequestId requestId); + SecureRequest getRequest(mtpRequestId requestId); void clearCallbacksDelayed(std::vector &&ids); void execCallback(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end); bool hasCallbacks(mtpRequestId requestId); @@ -199,7 +199,7 @@ private: std::map _parserMap; QMutex _parserMapLock; - std::map _requestMap; + std::map _requestMap; QReadWriteLock _requestMapLock; std::deque> _delayedRequests; @@ -831,7 +831,7 @@ void Instance::Private::checkDelayedRequests() { continue; } - auto request = mtpRequest(); + auto request = SecureRequest(); { QReadLocker locker(&_requestMapLock); auto it = _requestMap.find(requestId); @@ -852,7 +852,7 @@ void Instance::Private::checkDelayedRequests() { void Instance::Private::sendRequest( mtpRequestId requestId, - mtpRequest &&request, + SecureRequest &&request, RPCResponseHandler &&callbacks, ShiftedDcId shiftedDcId, TimeMs msCanWait, @@ -900,7 +900,7 @@ void Instance::Private::unregisterRequest(mtpRequestId requestId) { void Instance::Private::storeRequest( mtpRequestId requestId, - const mtpRequest &request, + const SecureRequest &request, RPCResponseHandler &&callbacks) { if (callbacks.onDone || callbacks.onFail) { QMutexLocker locker(&_parserMapLock); @@ -912,8 +912,8 @@ void Instance::Private::storeRequest( } } -mtpRequest Instance::Private::getRequest(mtpRequestId requestId) { - auto result = mtpRequest(); +SecureRequest Instance::Private::getRequest(mtpRequestId requestId) { + auto result = SecureRequest(); { QReadLocker locker(&_requestMapLock); auto it = _requestMap.find(requestId); @@ -1217,7 +1217,7 @@ bool Instance::Private::onErrorDefault(mtpRequestId requestId, const RPCError &e newdcWithShift = ShiftDcId(newdcWithShift, GetDcIdShift(dcWithShift)); } - auto request = mtpRequest(); + auto request = SecureRequest(); { QReadLocker locker(&_requestMapLock); auto it = _requestMap.find(requestId); @@ -1288,7 +1288,7 @@ bool Instance::Private::onErrorDefault(mtpRequestId requestId, const RPCError &e if (badGuestDc) _badGuestDcRequests.insert(requestId); return true; } else if (err == qstr("CONNECTION_NOT_INITED") || err == qstr("CONNECTION_LAYER_INVALID")) { - mtpRequest request; + SecureRequest request; { QReadLocker locker(&_requestMapLock); auto it = _requestMap.find(requestId); @@ -1313,7 +1313,7 @@ bool Instance::Private::onErrorDefault(mtpRequestId requestId, const RPCError &e } else if (err == qstr("CONNECTION_LANG_CODE_INVALID")) { Lang::CurrentCloudManager().resetToDefault(); } else if (err == qstr("MSG_WAIT_FAILED")) { - mtpRequest request; + SecureRequest request; { QReadLocker locker(&_requestMapLock); auto it = _requestMap.find(requestId); @@ -1332,7 +1332,7 @@ bool Instance::Private::onErrorDefault(mtpRequestId requestId, const RPCError &e if (const auto afterDcId = queryRequestByDc(request->after->requestId)) { dcWithShift = *shiftedDcId; if (*shiftedDcId != *afterDcId) { - request->after = mtpRequest(); + request->after = SecureRequest(); } } else { LOG(("MTP Error: could not find dependent request %1 by dc").arg(request->after->requestId)); @@ -1676,7 +1676,7 @@ void Instance::onKeyDestroyed(qint32 shiftedDcId) { } void Instance::sendRequest( mtpRequestId requestId, - mtpRequest &&request, + SecureRequest &&request, RPCResponseHandler &&callbacks, ShiftedDcId shiftedDcId, TimeMs msCanWait, diff --git a/Telegram/SourceFiles/mtproto/mtp_instance.h b/Telegram/SourceFiles/mtproto/mtp_instance.h index 7c71e6865..be489553b 100644 --- a/Telegram/SourceFiles/mtproto/mtp_instance.h +++ b/Telegram/SourceFiles/mtproto/mtp_instance.h @@ -60,9 +60,9 @@ public: not_null dcOptions(); - template + template mtpRequestId send( - const TRequest &request, + const Request &request, RPCResponseHandler &&callbacks = {}, ShiftedDcId shiftedDcId = 0, TimeMs msCanWait = 0, @@ -70,7 +70,7 @@ public: const auto requestId = GetNextRequestId(); sendSerialized( requestId, - mtpRequestData::serialize(request), + SecureRequest::Serialize(request), std::move(callbacks), shiftedDcId, msCanWait, @@ -78,9 +78,9 @@ public: return requestId; } - template + template mtpRequestId send( - const TRequest &request, + const Request &request, RPCDoneHandlerPtr &&onDone, RPCFailHandlerPtr &&onFail = nullptr, ShiftedDcId shiftedDcId = 0, @@ -94,14 +94,14 @@ public: afterRequestId); } - template + template mtpRequestId sendProtocolMessage( ShiftedDcId shiftedDcId, - const TRequest &request) { + const Request &request) { const auto requestId = GetNextRequestId(); sendRequest( requestId, - mtpRequestData::serialize(request), + SecureRequest::Serialize(request), {}, shiftedDcId, 0, @@ -112,7 +112,7 @@ public: void sendSerialized( mtpRequestId requestId, - mtpRequest &&request, + SecureRequest &&request, RPCResponseHandler &&callbacks, ShiftedDcId shiftedDcId, TimeMs msCanWait, @@ -195,7 +195,7 @@ private slots: private: void sendRequest( mtpRequestId requestId, - mtpRequest &&request, + SecureRequest &&request, RPCResponseHandler &&callbacks, ShiftedDcId shiftedDcId, TimeMs msCanWait, diff --git a/Telegram/SourceFiles/mtproto/session.cpp b/Telegram/SourceFiles/mtproto/session.cpp index b12888b29..c0bec07af 100644 --- a/Telegram/SourceFiles/mtproto/session.cpp +++ b/Telegram/SourceFiles/mtproto/session.cpp @@ -290,14 +290,14 @@ void Session::checkRequestsByTimer() { { QReadLocker locker(data.haveSentMutex()); - mtpRequestMap &haveSent(data.haveSentMap()); - uint32 haveSentCount(haveSent.size()); + auto &haveSent = data.haveSentMap(); + const auto haveSentCount = haveSent.size(); auto ms = getms(true); - for (mtpRequestMap::iterator i = haveSent.begin(), e = haveSent.end(); i != e; ++i) { - mtpRequest &req(i.value()); + for (auto i = haveSent.begin(), e = haveSent.end(); i != e; ++i) { + auto &req = i.value(); if (req->msDate > 0) { if (req->msDate + MTPCheckResendTimeout < ms) { // need to resend or check state - if (mtpRequestData::messageSize(req) < MTPResendThreshold) { // resend + if (req.messageSize() < MTPResendThreshold) { // resend resendingIds.reserve(haveSentCount); resendingIds.push_back(i.key()); } else { @@ -396,8 +396,8 @@ int32 Session::requestState(mtpRequestId requestId) const { if (!requestId) return MTP::RequestSent; QWriteLocker locker(data.toSendMutex()); - const mtpPreRequestMap &toSend(data.toSendMap()); - mtpPreRequestMap::const_iterator i = toSend.constFind(requestId); + const auto &toSend = data.toSendMap(); + const auto i = toSend.constFind(requestId); if (i != toSend.cend()) { return MTP::RequestSending; } else { @@ -433,10 +433,10 @@ QString Session::transport() const { } mtpRequestId Session::resend(quint64 msgId, qint64 msCanWait, bool forceContainer, bool sendMsgStateInfo) { - mtpRequest request; + SecureRequest request; { QWriteLocker locker(data.haveSentMutex()); - mtpRequestMap &haveSent(data.haveSentMap()); + auto &haveSent = data.haveSentMap(); auto i = haveSent.find(msgId); if (i == haveSent.end()) { @@ -458,14 +458,14 @@ mtpRequestId Session::resend(quint64 msgId, qint64 msCanWait, bool forceContaine request = i.value(); haveSent.erase(i); } - if (mtpRequestData::isSentContainer(request)) { // for container just resend all messages we can + if (request.isSentContainer()) { // for container just resend all messages we can DEBUG_LOG(("Message Info: resending container from haveSent, msgId %1").arg(msgId)); const mtpMsgId *ids = (const mtpMsgId *)(request->constData() + 8); for (uint32 i = 0, l = (request->size() - 8) >> 1; i < l; ++i) { resend(ids[i], 10, true); } return 0xFFFFFFFF; - } else if (!mtpRequestData::isStateRequest(request)) { + } else if (!request.isStateRequest()) { request->msDate = forceContainer ? 0 : getms(true); sendPrepared(request, msCanWait, false); { @@ -488,10 +488,12 @@ void Session::resendAll() { QVector toResend; { QReadLocker locker(data.haveSentMutex()); - const mtpRequestMap &haveSent(data.haveSentMap()); + const auto &haveSent = data.haveSentMap(); toResend.reserve(haveSent.size()); - for (mtpRequestMap::const_iterator i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { - if (i.value()->requestId) toResend.push_back(i.key()); + for (auto i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { + if (i.value()->requestId) { + toResend.push_back(i.key()); + } } } for (uint32 i = 0, l = toResend.size(); i < l; ++i) { @@ -500,7 +502,7 @@ void Session::resendAll() { } void Session::sendPrepared( - const mtpRequest &request, + const SecureRequest &request, TimeMs msCanWait, bool newRequest) { DEBUG_LOG(("MTP Info: adding request to toSendMap, msCanWait %1" diff --git a/Telegram/SourceFiles/mtproto/session.h b/Telegram/SourceFiles/mtproto/session.h index 531ce6c09..ce4dbb0c2 100644 --- a/Telegram/SourceFiles/mtproto/session.h +++ b/Telegram/SourceFiles/mtproto/session.h @@ -21,6 +21,24 @@ namespace internal { class Dcenter; class Connection; +using PreRequestMap = QMap; +using RequestMap = QMap; + +class RequestIdsMap : public QMap { +public: + using ParentType = QMap; + + mtpMsgId min() const { + return size() ? cbegin().key() : 0; + } + + mtpMsgId max() const { + ParentType::const_iterator e(cend()); + return size() ? (--e).key() : 0; + } + +}; + class ReceivedMsgIds { public: bool registerMsgId(mtpMsgId msgId, bool needAck) { @@ -191,22 +209,22 @@ public: return &_stateRequestLock; } - mtpPreRequestMap &toSendMap() { + PreRequestMap &toSendMap() { return _toSend; } - const mtpPreRequestMap &toSendMap() const { + const PreRequestMap &toSendMap() const { return _toSend; } - mtpRequestMap &haveSentMap() { + RequestMap &haveSentMap() { return _haveSent; } - const mtpRequestMap &haveSentMap() const { + const RequestMap &haveSentMap() const { return _haveSent; } - mtpRequestIdsMap &toResendMap() { // msgId -> requestId, on which toSend: requestId -> request for resended requests + RequestIdsMap &toResendMap() { // msgId -> requestId, on which toSend: requestId -> request for resended requests return _toResend; } - const mtpRequestIdsMap &toResendMap() const { + const RequestIdsMap &toResendMap() const { return _toResend; } ReceivedMsgIds &receivedIdsSet() { @@ -215,10 +233,10 @@ public: const ReceivedMsgIds &receivedIdsSet() const { return _receivedIds; } - mtpRequestIdsMap &wereAckedMap() { + RequestIdsMap &wereAckedMap() { return _wereAcked; } - const mtpRequestIdsMap &wereAckedMap() const { + const RequestIdsMap &wereAckedMap() const { return _wereAcked; } QMap &haveReceivedResponses() { @@ -233,10 +251,10 @@ public: const QList &haveReceivedUpdates() const { return _receivedUpdates; } - mtpMsgIdsSet &stateRequestMap() { + QMap &stateRequestMap() { return _stateRequest; } - const mtpMsgIdsSet &stateRequestMap() const { + const QMap &stateRequestMap() const { return _stateRequest; } @@ -269,12 +287,12 @@ private: bool _layerInited = false; ConnectionOptions _options; - mtpPreRequestMap _toSend; // map of request_id -> request, that is waiting to be sent - mtpRequestMap _haveSent; // map of msg_id -> request, that was sent, msDate = 0 for msgs_state_req (no resend / state req), msDate = 0, seqNo = 0 for containers - mtpRequestIdsMap _toResend; // map of msg_id -> request_id, that request_id -> request lies in toSend and is waiting to be resent + PreRequestMap _toSend; // map of request_id -> request, that is waiting to be sent + RequestMap _haveSent; // map of msg_id -> request, that was sent, msDate = 0 for msgs_state_req (no resend / state req), msDate = 0, seqNo = 0 for containers + RequestIdsMap _toResend; // map of msg_id -> request_id, that request_id -> request lies in toSend and is waiting to be resent ReceivedMsgIds _receivedIds; // set of received msg_id's, for checking new msg_ids - mtpRequestIdsMap _wereAcked; // map of msg_id -> request_id, this msg_ids already were acked or do not need ack - mtpMsgIdsSet _stateRequest; // set of msg_id's, whose state should be requested + RequestIdsMap _wereAcked; // map of msg_id -> request_id, this msg_ids already were acked or do not need ack + QMap _stateRequest; // set of msg_id's, whose state should be requested QMap _receivedResponses; // map of request_id -> response that should be processed in the main thread QList _receivedUpdates; // list of updates that should be processed in the main thread @@ -321,7 +339,7 @@ public: // Nulls msgId and seqNo in request, if newRequest = true. void sendPrepared( - const mtpRequest &request, + const SecureRequest &request, TimeMs msCanWait = 0, bool newRequest = true); diff --git a/Telegram/SourceFiles/storage/file_download.cpp b/Telegram/SourceFiles/storage/file_download.cpp index c6e9fe4dd..4953693ea 100644 --- a/Telegram/SourceFiles/storage/file_download.cpp +++ b/Telegram/SourceFiles/storage/file_download.cpp @@ -583,8 +583,8 @@ void mtpFileLoader::cdnPartLoaded(const MTPupload_CdnFile &result, mtpRequestId state.ivec[12] = static_cast((counterOffset >> 24) & 0xFF); auto decryptInPlace = result.c_upload_cdnFile().vbytes.v; - MTP::aesCtrEncrypt(decryptInPlace.data(), decryptInPlace.size(), key.data(), &state); auto buffer = bytes::make_span(decryptInPlace); + MTP::aesCtrEncrypt(buffer, key.data(), &state); switch (checkCdnFileHash(offset, buffer)) { case CheckCdnHashResult::NoHash: {