mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-25 04:38:23 +00:00
Send correct paddings in improved TCP protocol.
This commit is contained in:
parent
c7a4d67cfb
commit
8c2f11de7d
@ -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)):
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)) {
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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: {
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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: {
|
||||
|
Loading…
Reference in New Issue
Block a user