Send correct paddings in improved TCP protocol.

This commit is contained in:
John Preston 2018-06-25 19:55:27 +01:00
parent c7a4d67cfb
commit 8c2f11de7d
22 changed files with 846 additions and 536 deletions

View File

@ -462,7 +462,7 @@ def addTextSerialize(lst, dct, dataLetter):
templateArgument = ''
if (isTemplate != ''):
templateArgument = '<mtpRequest>'
templateArgument = '<MTP::SecureRequest>'
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)):

View File

@ -92,14 +92,22 @@ void aesIgeDecryptRaw(const void *src, void *dst, uint32 len, const void *key, c
AES_ige_encrypt(static_cast<const uchar*>(src), static_cast<uchar*>(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<const uchar*>(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<const uchar*>(data), static_cast<uchar*>(data), len, &aes, state->ivec, state->ecount, &state->num, (block128_f) AES_encrypt);
CRYPTO_ctr128_encrypt(
reinterpret_cast<const uchar*>(data.data()),
reinterpret_cast<uchar*>(data.data()),
data.size(),
&aes,
state->ivec,
state->ecount,
&state->num,
(block128_f)AES_encrypt);
}
} // namespace MTP

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <array>
#include <memory>
#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

View File

@ -110,7 +110,7 @@ auto ConcurrentSender::with_instance(Method &&method)
ConcurrentSender::RequestBuilder::RequestBuilder(
not_null<ConcurrentSender*> sender,
mtpRequest &&serialized) noexcept
SecureRequest &&serialized) noexcept
: _sender(sender)
, _serialized(std::move(serialized)) {
}

View File

@ -61,7 +61,7 @@ class ConcurrentSender : public base::has_weak_ptr {
protected:
RequestBuilder(
not_null<ConcurrentSender*> 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<ConcurrentSender*> _sender;
mtpRequest _serialized;
SecureRequest _serialized;
ShiftedDcId _dcId = 0;
TimeMs _canWait = 0;
@ -224,7 +224,7 @@ template <typename Request>
ConcurrentSender::SpecificRequestBuilder<Request>::SpecificRequestBuilder(
not_null<ConcurrentSender*> sender,
Request &&request
) noexcept : RequestBuilder(sender, mtpRequestData::serialize(request)) {
) noexcept : RequestBuilder(sender, SecureRequest::Serialize(request)) {
}
template <typename Request>

View File

@ -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<mtpMsgId, mtpMsgId> 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<mtpMsgId, mtpMsgId>();
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<mtpPingId>();
@ -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<MTPlong>(ackRequestData)));
ackRequest = mtpRequestData::prepare(ack.innerLength() >> 2);
ack.write(*ackRequest);
ackRequest = SecureRequest::Serialize(MTPMsgsAck(
MTP_msgs_ack(MTP_vector<MTPlong>(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<MTPlong>(resendRequestData)));
resendRequest = mtpRequestData::prepare(resend.innerLength() >> 2);
resend.write(*resendRequest);
resendRequest = SecureRequest::Serialize(MTPMsgResendReq(
MTP_msg_resend_req(MTP_vector<MTPlong>(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<MTPlong> 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<MTPlong>(stateReq)));
stateRequest = mtpRequestData::prepare(req.innerLength() >> 2);
req.write(*stateRequest);
stateRequest = SecureRequest::Serialize(MTPMsgsStateReq(
MTP_msgs_state_req(MTP_vector<MTPlong>(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<mtpRequest> initWrapper;
MTPInitConnection<SecureRequest> 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<mtpRequest>::Flag;
initWrapper = MTPInitConnection<mtpRequest>(
using Flag = MTPInitConnection<SecureRequest>::Flag;
initWrapper = MTPInitConnection<SecureRequest>(
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<quint64> 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<MTPlong> &ids, bool byRespon
QVector<MTPlong> 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<MTPlong> &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<MTPlong> &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<ConnectionPrivate::AuthKeyCreateData>();
_authKeyStrings = std::make_unique<ConnectionPrivate::AuthKeyCreateStrings>();
_authKeyData->req_num = 0;
_authKeyData->nonce = rand_value<MTPint128>();
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 <typename TRequest>
void ConnectionPrivate::sendRequestNotSecure(const TRequest &request) {
try {
mtpBuffer buffer;
uint32 requestSize = request.innerLength() >> 2;
template <typename Request>
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 <typename TResponse>
bool ConnectionPrivate::readResponseNotSecure(TResponse &response) {
template <typename Response>
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;

View File

@ -169,11 +169,18 @@ private:
void removeTestConnection(not_null<AbstractConnection*> 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<quint64> msgIds, qint64 msCanWait = 0, bool forceContainer = false, bool sendMsgStateInfo = false);
template <typename TRequest>
void sendRequestNotSecure(const TRequest &request);
template <typename Request>
void sendNotSecureRequest(const Request &request);
template <typename TResponse>
bool readResponseNotSecure(TResponse &response);
template <typename Response>
bool readNotSecureResponse(Response &response);
not_null<Instance*> _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;

View File

@ -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<uint64*>(&result[kAuthKeyIdPosition]) = keyId;
*reinterpret_cast<MTPint128*>(&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) {

View File

@ -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 <typename Request>
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 <typename Request>
mtpBuffer AbstractConnection::prepareNotSecurePacket(const Request &request) const {
const auto intsSize = request.innerLength() >> 2;
const auto intsPadding = requiresExtendedPadding()
? uint32(rand_value<uchar>() & 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<mtpMsgId*>(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

View File

@ -29,17 +29,14 @@ ConnectionPointer HttpConnection::clone(const ProxyData &proxy) {
return ConnectionPointer::New<HttpConnection>(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) {

View File

@ -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,

View File

@ -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() {

View File

@ -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;

View File

@ -37,6 +37,147 @@ const auto QTcpSocket_error = ErrorSignal(&QAbstractSocket::error);
} // namespace
class TcpConnection::Protocol {
public:
static std::unique_ptr<Protocol> 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<uchar*>(&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<uint32>() & 0x0F;
const auto bytesSize = intsSize * sizeof(mtpPrime) + padding;
buffer[1] = bytesSize;
for (auto added = 0; added < padding; added += 4) {
buffer.push_back(rand_value<mtpPrime>());
}
return bytes::make_span(buffer).subspan(4, 4 + bytesSize);
}
auto TcpConnection::Protocol::Create(bytes::vector &&secret)
-> std::unique_ptr<Protocol> {
if (secret.size() == 17 && static_cast<uchar>(secret[0]) == 0xDD) {
return std::make_unique<VersionD>(
bytes::make_vector(bytes::make_span(secret).subspan(1)));
} else if (secret.size() == 16) {
return std::make_unique<Version1>(std::move(secret));
} else if (secret.empty()) {
return std::make_unique<Version0>();
}
Unexpected("Secret bytes in TcpConnection::Protocol::Create.");
}
TcpConnection::TcpConnection(QThread *thread, const ProxyData &proxy)
: AbstractConnection(thread, proxy)
, _currentPosition(reinterpret_cast<char*>(_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<uint32*>(nonce.data() + 56);
*protocol = 0xEFEFEFEFU;
*protocol = _protocol->id();
const auto dcId = reinterpret_cast<int16*>(nonce.data() + 60);
*dcId = _protocolDcId;
_socket.write(reinterpret_cast<const char*>(nonce.data()), 56);
aesCtrEncrypt(nonce.data(), 64, _sendKey, &_sendState);
aesCtrEncrypt(nonce, _sendKey, &_sendState);
_socket.write(reinterpret_cast<const char*>(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<char*>(&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<uchar*>(data)[5] = uchar(size & 0xFF);
reinterpret_cast<uchar*>(data)[6] = uchar((size >> 8) & 0xFF);
reinterpret_cast<uchar*>(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<const char*>(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

View File

@ -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<uint32*>(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> _protocol;
int16 _protocolDcId = 0;
bytes::vector _protocolSecret;
Status _status = Status::Waiting;
MTPint128 _checkNonce;

View File

@ -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<uchar>() & 0x0F) << 2);
}
return result;
#endif // TDESKTOP_MTPROTO_OLD
}
} // namespace
SecureRequest::SecureRequest(const details::SecureRequestCreateTag &tag)
: _data(std::make_shared<SecureRequestData>(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: {

View File

@ -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<mtpPrime>;
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<mtpPrime>;
using mtpTypeId = uint32;
class mtpRequestData;
class mtpRequest : public std::shared_ptr<mtpRequestData> {
public:
mtpRequest() = default;
explicit mtpRequest(mtpRequestData *ptr)
: std::shared_ptr<mtpRequestData>(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 <typename TRequest>
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<mtpRequestId, mtpRequest>;
using mtpRequestMap = QMap<mtpMsgId, mtpRequest>;
using mtpMsgIdsSet = QMap<mtpMsgId, bool>;
class mtpRequestIdsMap : public QMap<mtpMsgId, mtpRequestId> {
public:
using ParentType = QMap<mtpMsgId, mtpRequestId>;
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<MTPBoxed<T> > {
typename T::CantMakeBoxedBoxedType v;
};
namespace MTP {
namespace details {
struct SecureRequestCreateTag {
};
} // namespace details
template <typename T>
struct is_boxed : std::false_type {
};
template <typename T>
struct is_boxed<MTPBoxed<T>> : std::true_type {
};
template <typename T>
constexpr bool is_boxed_v = is_boxed<T>::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<is_boxed_v<Request>>>
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<SecureRequestData> _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 <typename Request, typename>
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;

View File

@ -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<RPCCallbackClear> &&ids);
void execCallback(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end);
bool hasCallbacks(mtpRequestId requestId);
@ -199,7 +199,7 @@ private:
std::map<mtpRequestId, RPCResponseHandler> _parserMap;
QMutex _parserMapLock;
std::map<mtpRequestId, mtpRequest> _requestMap;
std::map<mtpRequestId, SecureRequest> _requestMap;
QReadWriteLock _requestMapLock;
std::deque<std::pair<mtpRequestId, TimeMs>> _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,

View File

@ -60,9 +60,9 @@ public:
not_null<DcOptions*> dcOptions();
template <typename TRequest>
template <typename Request>
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 <typename TRequest>
template <typename Request>
mtpRequestId send(
const TRequest &request,
const Request &request,
RPCDoneHandlerPtr &&onDone,
RPCFailHandlerPtr &&onFail = nullptr,
ShiftedDcId shiftedDcId = 0,
@ -94,14 +94,14 @@ public:
afterRequestId);
}
template <typename TRequest>
template <typename Request>
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,

View File

@ -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<mtpMsgId> 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"

View File

@ -21,6 +21,24 @@ namespace internal {
class Dcenter;
class Connection;
using PreRequestMap = QMap<mtpRequestId, SecureRequest>;
using RequestMap = QMap<mtpMsgId, SecureRequest>;
class RequestIdsMap : public QMap<mtpMsgId, mtpRequestId> {
public:
using ParentType = QMap<mtpMsgId, mtpRequestId>;
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<mtpRequestId, SerializedMessage> &haveReceivedResponses() {
@ -233,10 +251,10 @@ public:
const QList<SerializedMessage> &haveReceivedUpdates() const {
return _receivedUpdates;
}
mtpMsgIdsSet &stateRequestMap() {
QMap<mtpMsgId, bool> &stateRequestMap() {
return _stateRequest;
}
const mtpMsgIdsSet &stateRequestMap() const {
const QMap<mtpMsgId, bool> &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<mtpMsgId, bool> _stateRequest; // set of msg_id's, whose state should be requested
QMap<mtpRequestId, SerializedMessage> _receivedResponses; // map of request_id -> response that should be processed in the main thread
QList<SerializedMessage> _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);

View File

@ -583,8 +583,8 @@ void mtpFileLoader::cdnPartLoaded(const MTPupload_CdnFile &result, mtpRequestId
state.ivec[12] = static_cast<uchar>((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: {