Use explicit fields for sent container ids wrap.

This commit is contained in:
John Preston 2019-11-22 12:15:38 +03:00
parent 46a42e02bc
commit 8be4dfb346
19 changed files with 392 additions and 468 deletions

View File

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

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/weak_ptr.h" #include "base/weak_ptr.h"
#include "base/flat_map.h" #include "base/flat_map.h"
#include "mtproto/core_types.h" #include "mtproto/core_types.h"
#include "mtproto/details/mtproto_serialized_request.h"
#ifndef _DEBUG #ifndef _DEBUG
#define MTP_SENDER_USE_GENERIC_HANDLERS #define MTP_SENDER_USE_GENERIC_HANDLERS
@ -61,7 +62,7 @@ class ConcurrentSender : public base::has_weak_ptr {
protected: protected:
RequestBuilder( RequestBuilder(
not_null<ConcurrentSender*> sender, not_null<ConcurrentSender*> sender,
SecureRequest &&serialized) noexcept; details::SerializedRequest &&serialized) noexcept;
void setToDC(ShiftedDcId dcId) noexcept; void setToDC(ShiftedDcId dcId) noexcept;
void setCanWait(crl::time ms) noexcept; void setCanWait(crl::time ms) noexcept;
@ -74,7 +75,7 @@ class ConcurrentSender : public base::has_weak_ptr {
private: private:
not_null<ConcurrentSender*> _sender; not_null<ConcurrentSender*> _sender;
SecureRequest _serialized; details::SerializedRequest _serialized;
ShiftedDcId _dcId = 0; ShiftedDcId _dcId = 0;
crl::time _canWait = 0; crl::time _canWait = 0;
@ -224,8 +225,8 @@ void ConcurrentSender::RequestBuilder::setFailHandler(
template <typename Request> template <typename Request>
ConcurrentSender::SpecificRequestBuilder<Request>::SpecificRequestBuilder( ConcurrentSender::SpecificRequestBuilder<Request>::SpecificRequestBuilder(
not_null<ConcurrentSender*> sender, not_null<ConcurrentSender*> sender,
Request &&request Request &&request) noexcept
) noexcept : RequestBuilder(sender, SecureRequest::Serialize(request)) { : RequestBuilder(sender, details::SerializedRequest::Serialize(request)) {
} }
template <typename Request> template <typename Request>

View File

@ -85,11 +85,15 @@ using namespace details;
: TemporaryKeyType::Regular; : TemporaryKeyType::Regular;
} }
void wrapInvokeAfter(SecureRequest &to, const SecureRequest &from, const RequestMap &haveSent, int32 skipBeforeRequest = 0) { void WrapInvokeAfter(
SerializedRequest &to,
const SerializedRequest &from,
const base::flat_map<mtpMsgId, SerializedRequest> &haveSent,
int32 skipBeforeRequest = 0) {
const auto afterId = *(mtpMsgId*)(from->after->data() + 4); const auto afterId = *(mtpMsgId*)(from->after->data() + 4);
const auto i = afterId ? haveSent.constFind(afterId) : haveSent.cend(); const auto i = afterId ? haveSent.find(afterId) : haveSent.end();
int32 size = to->size(), lenInInts = (tl::count_length(from) >> 2), headlen = 4, fulllen = headlen + lenInInts; int32 size = to->size(), lenInInts = (tl::count_length(from) >> 2), headlen = 4, fulllen = headlen + lenInInts;
if (i == haveSent.constEnd()) { // no invoke after or such msg was not sent or was completed recently if (i == haveSent.end()) { // no invoke after or such msg was not sent or was completed recently
to->resize(size + fulllen + skipBeforeRequest); to->resize(size + fulllen + skipBeforeRequest);
if (skipBeforeRequest) { if (skipBeforeRequest) {
memcpy(to->data() + size, from->constData() + 4, headlen * sizeof(mtpPrime)); memcpy(to->data() + size, from->constData() + 4, headlen * sizeof(mtpPrime));
@ -229,41 +233,41 @@ int16 ConnectionPrivate::getProtocolDcId() const {
} }
void ConnectionPrivate::checkSentRequests() { void ConnectionPrivate::checkSentRequests() {
QVector<mtpMsgId> removingIds; // remove very old (10 minutes) containers and resend requests // Remove very old (10 minutes) containers and resend requests.
auto removingIds = std::vector<mtpMsgId>();
auto requesting = false; auto requesting = false;
{ {
QReadLocker locker(_sessionData->haveSentMutex()); QReadLocker locker(_sessionData->haveSentMutex());
auto &haveSent = _sessionData->haveSentMap(); auto &haveSent = _sessionData->haveSentMap();
const auto haveSentCount = haveSent.size(); const auto haveSentCount = haveSent.size();
auto ms = crl::now(); auto now = crl::now();
for (auto i = haveSent.begin(), e = haveSent.end(); i != e; ++i) { for (const auto &[msgId, request] : haveSent) {
auto &req = i.value(); if (request.isStateRequest()) {
if (req->msDate > 0) { continue;
if (req->msDate + kCheckSentRequestTimeout < ms) { } else if (request.isSentContainer()) {
// Need to check state. if (base::unixtime::now()
req->msDate = ms; > int32(msgId >> 32) + kContainerLives) {
if (_stateRequestData.emplace(i.key()).second) { removingIds.push_back(msgId);
requesting = true; }
} } else if (request->lastSentTime + kCheckSentRequestTimeout
< now) {
// Need to check state.
request->lastSentTime = now;
if (_stateRequestData.emplace(msgId).second) {
requesting = true;
} }
} else if (base::unixtime::now()
> int32(i.key() >> 32) + kContainerLives) {
removingIds.reserve(haveSentCount);
removingIds.push_back(i.key());
} }
} }
} }
if (requesting) { if (requesting) {
_sessionData->queueSendAnything(kSendStateRequestWaiting); _sessionData->queueSendAnything(kSendStateRequestWaiting);
} }
if (!removingIds.isEmpty()) { if (!removingIds.empty()) {
QWriteLocker locker(_sessionData->haveSentMutex()); QWriteLocker locker(_sessionData->haveSentMutex());
auto &haveSent = _sessionData->haveSentMap(); auto &haveSent = _sessionData->haveSentMap();
for (uint32 i = 0, l = removingIds.size(); i < l; ++i) { for (const auto msgId : removingIds) {
auto j = haveSent.find(removingIds[i]); if (const auto removed = haveSent.take(msgId)) {
if (j != haveSent.cend()) { Assert(!(*removed)->requestId);
Assert(!j.value()->requestId);
haveSent.erase(j);
} }
} }
} }
@ -436,7 +440,7 @@ bool ConnectionPrivate::markSessionAsStarted() {
} }
mtpMsgId ConnectionPrivate::prepareToSend( mtpMsgId ConnectionPrivate::prepareToSend(
SecureRequest &request, SerializedRequest &request,
mtpMsgId currentLastId, mtpMsgId currentLastId,
bool forceNewMsgId) { bool forceNewMsgId) {
Expects(request->size() > 8); Expects(request->size() > 8);
@ -460,7 +464,7 @@ mtpMsgId ConnectionPrivate::prepareToSend(
return currentLastId; return currentLastId;
} }
mtpMsgId ConnectionPrivate::replaceMsgId(SecureRequest &request, mtpMsgId newId) { mtpMsgId ConnectionPrivate::replaceMsgId(SerializedRequest &request, mtpMsgId newId) {
Expects(request->size() > 8); Expects(request->size() > 8);
const auto oldMsgId = request.getMsgId(); const auto oldMsgId = request.getMsgId();
@ -472,11 +476,14 @@ mtpMsgId ConnectionPrivate::replaceMsgId(SecureRequest &request, mtpMsgId newId)
while (_resendingIds.contains(newId) while (_resendingIds.contains(newId)
|| _ackedIds.contains(newId) || _ackedIds.contains(newId)
|| haveSent.constFind(newId) != haveSent.cend()) { || haveSent.contains(newId)) {
newId = base::unixtime::mtproto_msg_id(); newId = base::unixtime::mtproto_msg_id();
} }
MTP_LOG(_shiftedDcId, ("[r%1] msg_id %2 -> %3").arg(request->requestId).arg(oldMsgId).arg(newId)); MTP_LOG(_shiftedDcId, ("[r%1] msg_id %2 -> %3"
).arg(request->requestId
).arg(oldMsgId
).arg(newId));
const auto i = _resendingIds.find(oldMsgId); const auto i = _resendingIds.find(oldMsgId);
if (i != _resendingIds.end()) { if (i != _resendingIds.end()) {
@ -486,24 +493,23 @@ mtpMsgId ConnectionPrivate::replaceMsgId(SecureRequest &request, mtpMsgId newId)
} }
const auto j = _ackedIds.find(oldMsgId); const auto j = _ackedIds.find(oldMsgId);
if (j != _ackedIds.cend()) { if (j != _ackedIds.end()) {
const auto requestId = j->second; const auto requestId = j->second;
_ackedIds.erase(j); _ackedIds.erase(j);
_ackedIds.emplace(newId, requestId); _ackedIds.emplace(newId, requestId);
} }
const auto k = haveSent.find(oldMsgId); const auto k = haveSent.find(oldMsgId);
if (k != haveSent.cend()) { if (k != haveSent.end()) {
const auto req = k.value(); const auto request = k->second;
haveSent.erase(k); haveSent.erase(k);
haveSent.insert(newId, req); haveSent.emplace(newId, request);
} }
for (auto l = haveSent.begin(); l != haveSent.cend(); ++l) { for (const auto &[requestId, sent] : haveSent) {
const auto req = l.value(); if (sent.isSentContainer()) {
if (req.isSentContainer()) { const auto ids = (mtpMsgId *)(sent->data() + 8);
const auto ids = (mtpMsgId *)(req->data() + 8); for (uint32 i = 0, l = (sent->size() - 8) >> 1; i < l; ++i) {
for (uint32 i = 0, l = (req->size() - 8) >> 1; i < l; ++i) {
if (ids[i] == oldMsgId) { if (ids[i] == oldMsgId) {
ids[i] = newId; ids[i] = newId;
} }
@ -517,11 +523,11 @@ mtpMsgId ConnectionPrivate::replaceMsgId(SecureRequest &request, mtpMsgId newId)
} }
mtpMsgId ConnectionPrivate::placeToContainer( mtpMsgId ConnectionPrivate::placeToContainer(
SecureRequest &toSendRequest, SerializedRequest &toSendRequest,
mtpMsgId &bigMsgId, mtpMsgId &bigMsgId,
bool forceNewMsgId, bool forceNewMsgId,
mtpMsgId *&haveSentArr, mtpMsgId *&haveSentArr,
SecureRequest &req) { SerializedRequest &req) {
const auto msgId = prepareToSend(req, bigMsgId, forceNewMsgId); const auto msgId = prepareToSend(req, bigMsgId, forceNewMsgId);
if (msgId >= bigMsgId) { if (msgId >= bigMsgId) {
bigMsgId = base::unixtime::mtproto_msg_id(); bigMsgId = base::unixtime::mtproto_msg_id();
@ -560,28 +566,28 @@ void ConnectionPrivate::tryToSend() {
_keyCreator->restartBinder(); _keyCreator->restartBinder();
} }
auto pingRequest = SecureRequest(); auto pingRequest = SerializedRequest();
auto ackRequest = SecureRequest(); auto ackRequest = SerializedRequest();
auto resendRequest = SecureRequest(); auto resendRequest = SerializedRequest();
auto stateRequest = SecureRequest(); auto stateRequest = SerializedRequest();
auto httpWaitRequest = SecureRequest(); auto httpWaitRequest = SerializedRequest();
auto bindDcKeyRequest = SecureRequest(); auto bindDcKeyRequest = SerializedRequest();
if (_pingIdToSend) { if (_pingIdToSend) {
if (sendOnlyFirstPing || !isMainSession) { if (sendOnlyFirstPing || !isMainSession) {
DEBUG_LOG(("MTP Info: sending ping, ping_id: %1" DEBUG_LOG(("MTP Info: sending ping, ping_id: %1"
).arg(_pingIdToSend)); ).arg(_pingIdToSend));
pingRequest = SecureRequest::Serialize(MTPPing( pingRequest = SerializedRequest::Serialize(MTPPing(
MTP_long(_pingIdToSend) MTP_long(_pingIdToSend)
)); ));
} else { } else {
DEBUG_LOG(("MTP Info: sending ping_delay_disconnect, " DEBUG_LOG(("MTP Info: sending ping_delay_disconnect, "
"ping_id: %1").arg(_pingIdToSend)); "ping_id: %1").arg(_pingIdToSend));
pingRequest = SecureRequest::Serialize(MTPPing_delay_disconnect( pingRequest = SerializedRequest::Serialize(MTPPing_delay_disconnect(
MTP_long(_pingIdToSend), MTP_long(_pingIdToSend),
MTP_int(kPingDelayDisconnect))); MTP_int(kPingDelayDisconnect)));
_pingSender.callOnce(kPingSendAfterForce); _pingSender.callOnce(kPingSendAfterForce);
} }
_pingSendAt = pingRequest->msDate + kPingSendAfter; _pingSendAt = pingRequest->lastSentTime + kPingSendAfter;
_pingId = base::take(_pingIdToSend); _pingId = base::take(_pingIdToSend);
} else if (!sendAll) { } else if (!sendAll) {
DEBUG_LOG(("MTP Info: dc %1 sending only service or bind." DEBUG_LOG(("MTP Info: dc %1 sending only service or bind."
@ -594,12 +600,12 @@ void ConnectionPrivate::tryToSend() {
if (!sendOnlyFirstPing) { if (!sendOnlyFirstPing) {
if (!_ackRequestData.isEmpty()) { if (!_ackRequestData.isEmpty()) {
ackRequest = SecureRequest::Serialize(MTPMsgsAck( ackRequest = SerializedRequest::Serialize(MTPMsgsAck(
MTP_msgs_ack(MTP_vector<MTPlong>( MTP_msgs_ack(MTP_vector<MTPlong>(
base::take(_ackRequestData))))); base::take(_ackRequestData)))));
} }
if (!_resendRequestData.isEmpty()) { if (!_resendRequestData.isEmpty()) {
resendRequest = SecureRequest::Serialize(MTPMsgResendReq( resendRequest = SerializedRequest::Serialize(MTPMsgResendReq(
MTP_msg_resend_req(MTP_vector<MTPlong>( MTP_msg_resend_req(MTP_vector<MTPlong>(
base::take(_resendRequestData))))); base::take(_resendRequestData)))));
} }
@ -609,13 +615,13 @@ void ConnectionPrivate::tryToSend() {
for (const auto id : base::take(_stateRequestData)) { for (const auto id : base::take(_stateRequestData)) {
ids.push_back(MTP_long(id)); ids.push_back(MTP_long(id));
} }
stateRequest = SecureRequest::Serialize(MTPMsgsStateReq( stateRequest = SerializedRequest::Serialize(MTPMsgsStateReq(
MTP_msgs_state_req(MTP_vector<MTPlong>(ids)))); MTP_msgs_state_req(MTP_vector<MTPlong>(ids))));
// Add to haveSent / _ackedIds, but don't add to requestMap. // Add to haveSent / _ackedIds, but don't add to requestMap.
stateRequest->requestId = GetNextRequestId(); stateRequest->requestId = GetNextRequestId();
} }
if (_connection->usingHttpWait()) { if (_connection->usingHttpWait()) {
httpWaitRequest = SecureRequest::Serialize(MTPHttpWait( httpWaitRequest = SerializedRequest::Serialize(MTPHttpWait(
MTP_http_wait(MTP_int(100), MTP_int(30), MTP_int(25000)))); MTP_http_wait(MTP_int(100), MTP_int(30), MTP_int(25000))));
} }
if (!_bindMsgId && _keyCreator && _keyCreator->readyToBind()) { if (!_bindMsgId && _keyCreator && _keyCreator->readyToBind()) {
@ -631,7 +637,7 @@ void ConnectionPrivate::tryToSend() {
} }
} }
MTPInitConnection<SecureRequest> initWrapper; MTPInitConnection<SerializedRequest> initWrapper;
int32 initSize = 0, initSizeInInts = 0; int32 initSize = 0, initSizeInInts = 0;
if (needsLayer) { if (needsLayer) {
Assert(_connectionOptions != nullptr); Assert(_connectionOptions != nullptr);
@ -660,8 +666,8 @@ void ConnectionPrivate::tryToSend() {
MTP_string(_connectionOptions->proxy.host), MTP_string(_connectionOptions->proxy.host),
MTP_int(_connectionOptions->proxy.port)) MTP_int(_connectionOptions->proxy.port))
: MTPInputClientProxy(); : MTPInputClientProxy();
using Flag = MTPInitConnection<SecureRequest>::Flag; using Flag = MTPInitConnection<SerializedRequest>::Flag;
initWrapper = MTPInitConnection<SecureRequest>( initWrapper = MTPInitConnection<SerializedRequest>(
MTP_flags(mtprotoProxy ? Flag::f_proxy : Flag(0)), MTP_flags(mtprotoProxy ? Flag::f_proxy : Flag(0)),
MTP_int(ApiId), MTP_int(ApiId),
MTP_string(deviceModel), MTP_string(deviceModel),
@ -671,25 +677,22 @@ void ConnectionPrivate::tryToSend() {
MTP_string(langPackName), MTP_string(langPackName),
MTP_string(cloudLangCode), MTP_string(cloudLangCode),
clientProxyFields, clientProxyFields,
SecureRequest()); SerializedRequest());
initSizeInInts = (tl::count_length(initWrapper) >> 2) + 2; initSizeInInts = (tl::count_length(initWrapper) >> 2) + 2;
initSize = initSizeInInts * sizeof(mtpPrime); initSize = initSizeInInts * sizeof(mtpPrime);
} }
bool needAnyResponse = false; bool needAnyResponse = false;
SecureRequest toSendRequest; SerializedRequest toSendRequest;
{ {
QWriteLocker locker1(_sessionData->toSendMutex()); QWriteLocker locker1(_sessionData->toSendMutex());
auto toSendDummy = PreRequestMap(); auto toSendDummy = base::flat_map<mtpRequestId, SerializedRequest>();
auto &toSend = sendAll auto &toSend = sendAll
? _sessionData->toSendMap() ? _sessionData->toSendMap()
: toSendDummy; : toSendDummy;
if (!sendAll) { if (!sendAll) {
locker1.unlock(); locker1.unlock();
} else {
int time = crl::now();
int now = crl::now();
} }
uint32 toSendCount = toSend.size(); uint32 toSendCount = toSend.size();
@ -716,8 +719,8 @@ void ConnectionPrivate::tryToSend() {
? httpWaitRequest ? httpWaitRequest
: bindDcKeyRequest : bindDcKeyRequest
? bindDcKeyRequest ? bindDcKeyRequest
: toSend.cbegin().value(); : toSend.begin()->second;
if (toSendCount == 1 && first->msDate > 0) { // if can send without container if (toSendCount == 1 && !first->forceSendInContainer) {
toSendRequest = first; toSendRequest = first;
if (sendAll) { if (sendAll) {
toSend.clear(); toSend.clear();
@ -740,27 +743,27 @@ void ConnectionPrivate::tryToSend() {
if (toSendRequest->requestId) { if (toSendRequest->requestId) {
if (toSendRequest.needAck()) { if (toSendRequest.needAck()) {
toSendRequest->msDate = toSendRequest.isStateRequest() ? 0 : crl::now(); toSendRequest->lastSentTime = crl::now();
QWriteLocker locker2(_sessionData->haveSentMutex()); QWriteLocker locker2(_sessionData->haveSentMutex());
auto &haveSent = _sessionData->haveSentMap(); auto &haveSent = _sessionData->haveSentMap();
haveSent.insert(msgId, toSendRequest); haveSent.emplace(msgId, toSendRequest);
const auto wrapLayer = needsLayer && toSendRequest->needsLayer; const auto wrapLayer = needsLayer && toSendRequest->needsLayer;
if (toSendRequest->after) { if (toSendRequest->after) {
const auto toSendSize = tl::count_length(toSendRequest) >> 2; const auto toSendSize = tl::count_length(toSendRequest) >> 2;
auto wrappedRequest = SecureRequest::Prepare( auto wrappedRequest = SerializedRequest::Prepare(
toSendSize, toSendSize,
toSendSize + 3); toSendSize + 3);
wrappedRequest->resize(4); wrappedRequest->resize(4);
memcpy(wrappedRequest->data(), toSendRequest->constData(), 4 * sizeof(mtpPrime)); memcpy(wrappedRequest->data(), toSendRequest->constData(), 4 * sizeof(mtpPrime));
wrapInvokeAfter(wrappedRequest, toSendRequest, haveSent); WrapInvokeAfter(wrappedRequest, toSendRequest, haveSent);
toSendRequest = std::move(wrappedRequest); toSendRequest = std::move(wrappedRequest);
} }
if (wrapLayer) { if (wrapLayer) {
const auto noWrapSize = (tl::count_length(toSendRequest) >> 2); const auto noWrapSize = (tl::count_length(toSendRequest) >> 2);
const auto toSendSize = noWrapSize + initSizeInInts; const auto toSendSize = noWrapSize + initSizeInInts;
auto wrappedRequest = SecureRequest::Prepare(toSendSize); auto wrappedRequest = SerializedRequest::Prepare(toSendSize);
memcpy(wrappedRequest->data(), toSendRequest->constData(), 7 * sizeof(mtpPrime)); // all except length memcpy(wrappedRequest->data(), toSendRequest->constData(), 7 * sizeof(mtpPrime)); // all except length
wrappedRequest->push_back(mtpc_invokeWithLayer); wrappedRequest->push_back(mtpc_invokeWithLayer);
wrappedRequest->push_back(internal::CurrentLayer); wrappedRequest->push_back(internal::CurrentLayer);
@ -784,9 +787,9 @@ void ConnectionPrivate::tryToSend() {
if (stateRequest) containerSize += stateRequest.messageSize(); if (stateRequest) containerSize += stateRequest.messageSize();
if (httpWaitRequest) containerSize += httpWaitRequest.messageSize(); if (httpWaitRequest) containerSize += httpWaitRequest.messageSize();
if (bindDcKeyRequest) containerSize += bindDcKeyRequest.messageSize(); if (bindDcKeyRequest) containerSize += bindDcKeyRequest.messageSize();
for (auto i = toSend.begin(), e = toSend.end(); i != e; ++i) { for (const auto &[requestId, request] : toSend) {
containerSize += i.value().messageSize(); containerSize += request.messageSize();
if (needsLayer && i.value()->needsLayer) { if (needsLayer && request->needsLayer) {
containerSize += initSizeInInts; containerSize += initSizeInInts;
willNeedInit = true; willNeedInit = true;
} }
@ -799,7 +802,7 @@ void ConnectionPrivate::tryToSend() {
initWrapper.write<mtpBuffer>(initSerialized); initWrapper.write<mtpBuffer>(initSerialized);
} }
// prepare container + each in invoke after // prepare container + each in invoke after
toSendRequest = SecureRequest::Prepare( toSendRequest = SerializedRequest::Prepare(
containerSize, containerSize,
containerSize + 3 * toSend.size()); containerSize + 3 * toSend.size());
toSendRequest->push_back(mtpc_msg_container); toSendRequest->push_back(mtpc_msg_container);
@ -813,9 +816,8 @@ void ConnectionPrivate::tryToSend() {
auto &haveSent = _sessionData->haveSentMap(); auto &haveSent = _sessionData->haveSentMap();
// prepare "request-like" wrap for msgId vector // prepare "request-like" wrap for msgId vector
auto haveSentIdsWrap = SecureRequest::Prepare(idsWrapSize); auto haveSentIdsWrap = SerializedRequest::Prepare(idsWrapSize);
haveSentIdsWrap->msDate = 0; // Container: msDate = 0, seqNo = 0. haveSentIdsWrap->isContainerIdsWrap = true;
haveSentIdsWrap->requestId = 0;
haveSentIdsWrap->resize(haveSentIdsWrap->size() + idsWrapSize); haveSentIdsWrap->resize(haveSentIdsWrap->size() + idsWrapSize);
auto haveSentArr = (mtpMsgId*)(haveSentIdsWrap->data() + 8); auto haveSentArr = (mtpMsgId*)(haveSentIdsWrap->data() + 8);
@ -840,10 +842,9 @@ void ConnectionPrivate::tryToSend() {
if (resendRequest || stateRequest) { if (resendRequest || stateRequest) {
needAnyResponse = true; needAnyResponse = true;
} }
for (auto i = toSend.begin(), e = toSend.end(); i != e; ++i) { for (auto &[requestId, request] : toSend) {
auto &req = i.value();
const auto msgId = prepareToSend( const auto msgId = prepareToSend(
req, request,
bigMsgId, bigMsgId,
forceNewMsgId); forceNewMsgId);
if (msgId >= bigMsgId) { if (msgId >= bigMsgId) {
@ -851,44 +852,43 @@ void ConnectionPrivate::tryToSend() {
} }
*(haveSentArr++) = msgId; *(haveSentArr++) = msgId;
bool added = false; bool added = false;
if (req->requestId) { if (request->requestId) {
if (req.needAck()) { if (request.needAck()) {
req->msDate = req.isStateRequest() ? 0 : crl::now(); request->lastSentTime = crl::now();
int32 reqNeedsLayer = (needsLayer && req->needsLayer) ? toSendRequest->size() : 0; int32 reqNeedsLayer = (needsLayer && request->needsLayer) ? toSendRequest->size() : 0;
if (req->after) { if (request->after) {
wrapInvokeAfter(toSendRequest, req, haveSent, reqNeedsLayer ? initSizeInInts : 0); WrapInvokeAfter(toSendRequest, request, haveSent, reqNeedsLayer ? initSizeInInts : 0);
if (reqNeedsLayer) { if (reqNeedsLayer) {
memcpy(toSendRequest->data() + reqNeedsLayer + 4, initSerialized.constData(), initSize); memcpy(toSendRequest->data() + reqNeedsLayer + 4, initSerialized.constData(), initSize);
*(toSendRequest->data() + reqNeedsLayer + 3) += initSize; *(toSendRequest->data() + reqNeedsLayer + 3) += initSize;
} }
added = true; added = true;
} else if (reqNeedsLayer) { } else if (reqNeedsLayer) {
toSendRequest->resize(reqNeedsLayer + initSizeInInts + req.messageSize()); toSendRequest->resize(reqNeedsLayer + initSizeInInts + request.messageSize());
memcpy(toSendRequest->data() + reqNeedsLayer, req->constData() + 4, 4 * sizeof(mtpPrime)); memcpy(toSendRequest->data() + reqNeedsLayer, request->constData() + 4, 4 * sizeof(mtpPrime));
memcpy(toSendRequest->data() + reqNeedsLayer + 4, initSerialized.constData(), initSize); memcpy(toSendRequest->data() + reqNeedsLayer + 4, initSerialized.constData(), initSize);
memcpy(toSendRequest->data() + reqNeedsLayer + 4 + initSizeInInts, req->constData() + 8, tl::count_length(req)); memcpy(toSendRequest->data() + reqNeedsLayer + 4 + initSizeInInts, request->constData() + 8, tl::count_length(request));
*(toSendRequest->data() + reqNeedsLayer + 3) += initSize; *(toSendRequest->data() + reqNeedsLayer + 3) += initSize;
added = true; added = true;
} }
Assert(!haveSent.contains(msgId)); Assert(!haveSent.contains(msgId));
haveSent.insert(msgId, req); haveSent.emplace(msgId, request);
needAnyResponse = true; needAnyResponse = true;
} else { } else {
_ackedIds.emplace(msgId, req->requestId); _ackedIds.emplace(msgId, request->requestId);
} }
} }
if (!added) { if (!added) {
uint32 from = toSendRequest->size(), len = req.messageSize(); uint32 from = toSendRequest->size(), len = request.messageSize();
toSendRequest->resize(from + len); toSendRequest->resize(from + len);
memcpy(toSendRequest->data() + from, req->constData() + 4, len * sizeof(mtpPrime)); memcpy(toSendRequest->data() + from, request->constData() + 4, len * sizeof(mtpPrime));
} }
} }
if (stateRequest) { if (stateRequest) {
mtpMsgId msgId = placeToContainer(toSendRequest, bigMsgId, forceNewMsgId, haveSentArr, stateRequest); const auto msgId = placeToContainer(toSendRequest, bigMsgId, forceNewMsgId, haveSentArr, stateRequest);
stateRequest->msDate = 0; // 0 for state request, do not request state of it
Assert(!haveSent.contains(msgId)); Assert(!haveSent.contains(msgId));
haveSent.insert(msgId, stateRequest); haveSent.emplace(msgId, stateRequest);
} }
if (resendRequest) placeToContainer(toSendRequest, bigMsgId, forceNewMsgId, haveSentArr, resendRequest); if (resendRequest) placeToContainer(toSendRequest, bigMsgId, forceNewMsgId, haveSentArr, resendRequest);
if (ackRequest) placeToContainer(toSendRequest, bigMsgId, forceNewMsgId, haveSentArr, ackRequest); if (ackRequest) placeToContainer(toSendRequest, bigMsgId, forceNewMsgId, haveSentArr, ackRequest);
@ -899,9 +899,8 @@ void ConnectionPrivate::tryToSend() {
bigMsgId, bigMsgId,
forceNewMsgId); forceNewMsgId);
*(mtpMsgId*)(haveSentIdsWrap->data() + 4) = containerMsgId; *(mtpMsgId*)(haveSentIdsWrap->data() + 4) = containerMsgId;
(*haveSentIdsWrap)[6] = 0; // for container, msDate = 0, seqNo = 0
Assert(!haveSent.contains(containerMsgId)); Assert(!haveSent.contains(containerMsgId));
haveSent.insert(containerMsgId, haveSentIdsWrap); haveSent.emplace(containerMsgId, haveSentIdsWrap);
toSend.clear(); toSend.clear();
} }
} }
@ -1370,7 +1369,8 @@ void ConnectionPrivate::handleReceived() {
} }
auto lock = QReadLocker(_sessionData->haveReceivedMutex()); auto lock = QReadLocker(_sessionData->haveReceivedMutex());
const auto tryToReceive = !_sessionData->haveReceivedResponses().isEmpty() || !_sessionData->haveReceivedUpdates().isEmpty(); const auto tryToReceive = !_sessionData->haveReceivedResponses().empty()
|| !_sessionData->haveReceivedUpdates().empty();
lock.unlock(); lock.unlock();
if (tryToReceive) { if (tryToReceive) {
@ -1521,16 +1521,16 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(
|| (errorCode == 64); // bad container || (errorCode == 64); // bad container
if (errorCode == 64) { // bad container! if (errorCode == 64) { // bad container!
if (Logs::DebugEnabled()) { if (Logs::DebugEnabled()) {
SecureRequest request; SerializedRequest request;
{ {
QWriteLocker locker(_sessionData->haveSentMutex()); QWriteLocker locker(_sessionData->haveSentMutex());
auto &haveSent = _sessionData->haveSentMap(); auto &haveSent = _sessionData->haveSentMap();
const auto i = haveSent.constFind(resendId); const auto i = haveSent.find(resendId);
if (i == haveSent.cend()) { if (i == haveSent.end()) {
LOG(("Message Error: Container not found!")); LOG(("Message Error: Container not found!"));
} else { } else {
request = i.value(); request = i->second;
} }
} }
if (request) { if (request) {
@ -1626,53 +1626,6 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(
resend(resendId); resend(resendId);
} return HandleResult::Success; } return HandleResult::Success;
case mtpc_msgs_state_req: {
if (badTime) {
DEBUG_LOG(("Message Info: skipping with bad time..."));
return HandleResult::Ignored;
}
MTPMsgsStateReq msg;
if (!msg.read(from, end)) {
return HandleResult::ParseError;
}
auto &ids = msg.c_msgs_state_req().vmsg_ids().v;
auto idsCount = ids.size();
DEBUG_LOG(("Message Info: msgs_state_req received, ids: %1").arg(LogIdsVector(ids)));
if (!idsCount) return HandleResult::Success;
QByteArray info(idsCount, Qt::Uninitialized);
{
const auto minRecv = _receivedMessageIds.min();
const auto maxRecv = _receivedMessageIds.max();
for (uint32 i = 0, l = idsCount; i < l; ++i) {
char state = 0;
uint64 reqMsgId = ids[i].v;
if (reqMsgId < minRecv) {
state |= 0x01;
} else if (reqMsgId > maxRecv) {
state |= 0x03;
} else {
auto msgIdState = _receivedMessageIds.lookup(reqMsgId);
if (msgIdState == ReceivedIdsManager::State::NotFound) {
state |= 0x02;
} else {
state |= 0x04;
if (_ackedIds.contains(reqMsgId)) {
state |= 0x80; // we know, that server knows, that we received request
}
if (msgIdState == ReceivedIdsManager::State::NeedsAck) { // need ack, so we sent ack
state |= 0x08;
} else {
state |= 0x10;
}
}
}
info[i] = state;
}
}
_sessionData->queueSendMsgsStateInfo(msgId, info);
} return HandleResult::Success;
case mtpc_msgs_state_info: { case mtpc_msgs_state_info: {
MTPMsgsStateInfo msg; MTPMsgsStateInfo msg;
if (!msg.read(from, end)) { if (!msg.read(from, end)) {
@ -1684,12 +1637,12 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(
auto &states = data.vinfo().v; 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())); 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()));
SecureRequest requestBuffer; SerializedRequest requestBuffer;
{ // find this request in session-shared sent requests map { // find this request in session-shared sent requests map
QReadLocker locker(_sessionData->haveSentMutex()); QReadLocker locker(_sessionData->haveSentMutex());
const auto &haveSent = _sessionData->haveSentMap(); const auto &haveSent = _sessionData->haveSentMap();
const auto replyTo = haveSent.constFind(reqMsgId); const auto replyTo = haveSent.find(reqMsgId);
if (replyTo == haveSent.cend()) { // do not look in toResend, because we do not resend msgs_state_req requests if (replyTo == haveSent.end()) { // 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)); DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(reqMsgId));
return (badTime ? HandleResult::Ignored : HandleResult::Success); return (badTime ? HandleResult::Ignored : HandleResult::Success);
} }
@ -1703,7 +1656,7 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(
badTime = false; badTime = false;
} }
requestBuffer = replyTo.value(); requestBuffer = replyTo->second;
} }
QVector<MTPlong> toAckReq(1, MTP_long(reqMsgId)), toAck; QVector<MTPlong> toAckReq(1, MTP_long(reqMsgId)), toAck;
requestsAcked(toAck, true); requestsAcked(toAck, true);
@ -1809,7 +1762,7 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(
if (from + 3 > end) { if (from + 3 > end) {
return HandleResult::ParseError; return HandleResult::ParseError;
} }
auto response = SerializedMessage(); auto response = mtpBuffer();
MTPlong reqMsgId; MTPlong reqMsgId;
if (!reqMsgId.read(++from, end)) { if (!reqMsgId.read(++from, end)) {
@ -1861,7 +1814,7 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(
if (requestId && requestId != mtpRequestId(0xFFFFFFFF)) { if (requestId && requestId != mtpRequestId(0xFFFFFFFF)) {
// Save rpc_result for processing in the main thread. // Save rpc_result for processing in the main thread.
QWriteLocker locker(_sessionData->haveReceivedMutex()); QWriteLocker locker(_sessionData->haveReceivedMutex());
_sessionData->haveReceivedResponses().insert(requestId, response); _sessionData->haveReceivedResponses().emplace(requestId, response);
} else { } else {
DEBUG_LOG(("RPC Info: requestId not found for msgId %1").arg(requestMsgId)); DEBUG_LOG(("RPC Info: requestId not found for msgId %1").arg(requestMsgId));
} }
@ -1893,11 +1846,11 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(
QReadLocker locker(_sessionData->haveSentMutex()); QReadLocker locker(_sessionData->haveSentMutex());
const auto &haveSent = _sessionData->haveSentMap(); const auto &haveSent = _sessionData->haveSentMap();
toResend.reserve(haveSent.size()); toResend.reserve(haveSent.size());
for (auto i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { for (const auto &[msgId, request] : haveSent) {
if (i.key() >= firstMsgId) { if (msgId >= firstMsgId) {
break; break;
} else if (i.value()->requestId) { } else if (request->requestId) {
toResend.push_back(i.key()); toResend.push_back(msgId);
} }
} }
} }
@ -1910,7 +1863,7 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(
// Notify main process about new session - need to get difference. // Notify main process about new session - need to get difference.
QWriteLocker locker(_sessionData->haveReceivedMutex()); QWriteLocker locker(_sessionData->haveReceivedMutex());
_sessionData->haveReceivedUpdates().push_back(SerializedMessage(update)); _sessionData->haveReceivedUpdates().push_back(mtpBuffer(update));
} return HandleResult::Success; } return HandleResult::Success;
case mtpc_pong: { case mtpc_pong: {
@ -1957,7 +1910,7 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(
// Notify main process about the new updates. // Notify main process about the new updates.
QWriteLocker locker(_sessionData->haveReceivedMutex()); QWriteLocker locker(_sessionData->haveReceivedMutex());
_sessionData->haveReceivedUpdates().push_back(SerializedMessage(update)); _sessionData->haveReceivedUpdates().push_back(mtpBuffer(update));
} else { } else {
LOG(("Message Error: unexpected updates in dcType: %1" LOG(("Message Error: unexpected updates in dcType: %1"
).arg(static_cast<int>(_currentDcType))); ).arg(static_cast<int>(_currentDcType)));
@ -2075,27 +2028,27 @@ void ConnectionPrivate::requestsAcked(const QVector<MTPlong> &ids, bool byRespon
for (uint32 i = 0; i < idsCount; ++i) { for (uint32 i = 0; i < idsCount; ++i) {
mtpMsgId msgId = ids[i].v; mtpMsgId msgId = ids[i].v;
const auto req = haveSent.find(msgId); const auto req = haveSent.find(msgId);
if (req != haveSent.cend()) { if (req != haveSent.end()) {
if (!req.value()->msDate) { if (req->second.isSentContainer()) {
DEBUG_LOG(("Message Info: container ack received, msgId %1").arg(ids[i].v)); DEBUG_LOG(("Message Info: container ack received, msgId %1").arg(ids[i].v));
uint32 inContCount = ((*req)->size() - 8) / 2; uint32 inContCount = (req->second->size() - 8) / 2;
const mtpMsgId *inContId = (const mtpMsgId *)(req.value()->constData() + 8); const mtpMsgId *inContId = (const mtpMsgId *)(req->second->constData() + 8);
toAckMore.reserve(toAckMore.size() + inContCount); toAckMore.reserve(toAckMore.size() + inContCount);
for (uint32 j = 0; j < inContCount; ++j) { for (uint32 j = 0; j < inContCount; ++j) {
toAckMore.push_back(MTP_long(*(inContId++))); toAckMore.push_back(MTP_long(*(inContId++)));
} }
haveSent.erase(req); haveSent.erase(req);
} else { } else {
mtpRequestId reqId = req.value()->requestId; const auto requestId = req->second->requestId;
bool moveToAcked = byResponse; bool moveToAcked = byResponse;
if (!moveToAcked) { // ignore ACK, if we need a response (if we have a handler) if (!moveToAcked) { // ignore ACK, if we need a response (if we have a handler)
moveToAcked = !_instance->hasCallbacks(reqId); moveToAcked = !_instance->hasCallbacks(requestId);
} }
if (moveToAcked) { if (moveToAcked) {
_ackedIds.emplace(msgId, reqId); _ackedIds.emplace(msgId, requestId);
haveSent.erase(req); haveSent.erase(req);
} else { } else {
DEBUG_LOG(("Message Info: ignoring ACK for msgId %1 because request %2 requires a response").arg(msgId).arg(reqId)); DEBUG_LOG(("Message Info: ignoring ACK for msgId %1 because request %2 requires a response").arg(msgId).arg(requestId));
} }
} }
} else { } else {
@ -2112,9 +2065,9 @@ void ConnectionPrivate::requestsAcked(const QVector<MTPlong> &ids, bool byRespon
auto &toSend = _sessionData->toSendMap(); auto &toSend = _sessionData->toSendMap();
const auto req = toSend.find(reqId); const auto req = toSend.find(reqId);
if (req != toSend.cend()) { if (req != toSend.cend()) {
_ackedIds.emplace(msgId, req.value()->requestId); _ackedIds.emplace(msgId, req->second->requestId);
if (req.value()->requestId != reqId) { if (req->second->requestId != reqId) {
DEBUG_LOG(("Message Error: for msgId %1 found resent request, requestId %2, contains requestId %3").arg(msgId).arg(reqId).arg(req.value()->requestId)); DEBUG_LOG(("Message Error: for msgId %1 found resent request, requestId %2, contains requestId %3").arg(msgId).arg(reqId).arg(req->second->requestId));
} else { } else {
DEBUG_LOG(("Message Info: acked msgId %1 that was prepared to resend, requestId %2").arg(msgId).arg(reqId)); DEBUG_LOG(("Message Info: acked msgId %1 that was prepared to resend, requestId %2").arg(msgId).arg(reqId));
} }
@ -2172,9 +2125,7 @@ void ConnectionPrivate::handleMsgsStates(const QVector<MTPlong> &ids, const QByt
uint64 requestMsgId = ids[i].v; uint64 requestMsgId = ids[i].v;
{ {
QReadLocker locker(_sessionData->haveSentMutex()); QReadLocker locker(_sessionData->haveSentMutex());
const auto &haveSent = _sessionData->haveSentMap(); if (!_sessionData->haveSentMap().contains(requestMsgId)) {
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)); DEBUG_LOG(("Message Info: state was received for msgId %1, but request is not found, looking in resent requests...").arg(requestMsgId));
const auto reqIt = _resendingIds.find(requestMsgId); const auto reqIt = _resendingIds.find(requestMsgId);
if (reqIt != _resendingIds.cend()) { if (reqIt != _resendingIds.cend()) {
@ -2226,7 +2177,7 @@ void ConnectionPrivate::resend(
if (i == haveSent.end()) { if (i == haveSent.end()) {
return; return;
} }
auto request = i.value(); auto request = i->second;
haveSent.erase(i); haveSent.erase(i);
lock.unlock(); lock.unlock();
@ -2238,11 +2189,12 @@ void ConnectionPrivate::resend(
resend(ids[i], -1, true); resend(ids[i], -1, true);
} }
} else if (!request.isStateRequest()) { } else if (!request.isStateRequest()) {
request->msDate = forceContainer ? 0 : crl::now(); request->lastSentTime = crl::now();
request->forceSendInContainer = forceContainer;
_resendingIds.emplace(msgId, request->requestId); _resendingIds.emplace(msgId, request->requestId);
{ {
QWriteLocker locker(_sessionData->toSendMutex()); QWriteLocker locker(_sessionData->toSendMutex());
_sessionData->toSendMap().insert(request->requestId, request); _sessionData->toSendMap().emplace(request->requestId, request);
} }
} }
} }
@ -2253,9 +2205,9 @@ void ConnectionPrivate::resendAll() {
auto lock = QReadLocker(_sessionData->haveSentMutex()); auto lock = QReadLocker(_sessionData->haveSentMutex());
const auto &haveSent = _sessionData->haveSentMap(); const auto &haveSent = _sessionData->haveSentMap();
toResend.reserve(haveSent.size()); toResend.reserve(haveSent.size());
for (auto i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { for (const auto &[msgId, request] : haveSent) {
if (!i.value().isSentContainer()) { if (!request.isSentContainer() && !request.isStateRequest()) {
toResend.push_back(i.key()); toResend.push_back(msgId);
} }
} }
lock.unlock(); lock.unlock();
@ -2581,7 +2533,7 @@ void ConnectionPrivate::destroyTemporaryKey() {
} }
bool ConnectionPrivate::sendSecureRequest( bool ConnectionPrivate::sendSecureRequest(
SecureRequest &&request, SerializedRequest &&request,
bool needAnyResponse) { bool needAnyResponse) {
#ifdef TDESKTOP_MTPROTO_OLD #ifdef TDESKTOP_MTPROTO_OLD
const auto oldPadding = true; const auto oldPadding = true;
@ -2671,10 +2623,10 @@ mtpRequestId ConnectionPrivate::wasSent(mtpMsgId msgId) const {
{ {
QReadLocker locker(_sessionData->haveSentMutex()); QReadLocker locker(_sessionData->haveSentMutex());
const auto &haveSent = _sessionData->haveSentMap(); const auto &haveSent = _sessionData->haveSentMap();
const auto i = haveSent.constFind(msgId); const auto i = haveSent.find(msgId);
if (i != haveSent.cend()) { if (i != haveSent.end()) {
return i.value()->requestId return i->second->requestId
? i.value()->requestId ? i->second->requestId
: mtpRequestId(0xFFFFFFFF); : mtpRequestId(0xFFFFFFFF);
} }
} }

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once #pragma once
#include "mtproto/details/mtproto_received_ids_manager.h" #include "mtproto/details/mtproto_received_ids_manager.h"
#include "mtproto/details/mtproto_serialized_request.h"
#include "mtproto/mtproto_auth_key.h" #include "mtproto/mtproto_auth_key.h"
#include "mtproto/dc_options.h" #include "mtproto/dc_options.h"
#include "mtproto/connection_abstract.h" #include "mtproto/connection_abstract.h"
@ -139,18 +140,22 @@ private:
void checkSentRequests(); void checkSentRequests();
mtpMsgId placeToContainer( mtpMsgId placeToContainer(
SecureRequest &toSendRequest, details::SerializedRequest &toSendRequest,
mtpMsgId &bigMsgId, mtpMsgId &bigMsgId,
bool forceNewMsgId, bool forceNewMsgId,
mtpMsgId *&haveSentArr, mtpMsgId *&haveSentArr,
SecureRequest &req); details::SerializedRequest &req);
mtpMsgId prepareToSend( mtpMsgId prepareToSend(
SecureRequest &request, details::SerializedRequest &request,
mtpMsgId currentLastId, mtpMsgId currentLastId,
bool forceNewMsgId); bool forceNewMsgId);
mtpMsgId replaceMsgId(SecureRequest &request, mtpMsgId newId); mtpMsgId replaceMsgId(
details::SerializedRequest &request,
mtpMsgId newId);
bool sendSecureRequest(SecureRequest &&request, bool needAnyResponse); bool sendSecureRequest(
details::SerializedRequest &&request,
bool needAnyResponse);
mtpRequestId wasSent(mtpMsgId msgId) const; mtpRequestId wasSent(mtpMsgId msgId) const;
[[nodiscard]] HandleResult handleOneReceived(const mtpPrime *from, const mtpPrime *end, uint64 msgId, int32 serverTime, uint64 serverSalt, bool badTime); [[nodiscard]] HandleResult handleOneReceived(const mtpPrime *from, const mtpPrime *end, uint64 msgId, int32 serverTime, uint64 serverSalt, bool badTime);

View File

@ -122,102 +122,6 @@ static const mtpTypeId mtpLayers[] = {
}; };
static const uint32 mtpLayerMaxSingle = sizeof(mtpLayers) / sizeof(mtpLayers[0]); static const uint32 mtpLayerMaxSingle = sizeof(mtpLayers) / sizeof(mtpLayers[0]);
namespace MTP {
namespace details {
struct SecureRequestCreateTag {
};
} // namespace details
class SecureRequestData;
class SecureRequest {
public:
SecureRequest() = default;
static constexpr auto kSaltInts = 2;
static constexpr auto kSessionIdInts = 2;
static constexpr auto kMessageIdPosition = kSaltInts + kSessionIdInts;
static constexpr auto kMessageIdInts = 2;
static constexpr auto kSeqNoPosition = kMessageIdPosition
+ 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<tl::is_boxed_v<Request>>>
static SecureRequest Serialize(const Request &request);
// For template MTP requests and MTPBoxed instanciation.
template <typename Accumulator>
void write(Accumulator &to) const {
if (const auto size = sizeInBytes()) {
tl::Writer<Accumulator>::PutBytes(to, dataInBytes(), size);
}
}
SecureRequestData *operator->() const;
SecureRequestData &operator*() const;
explicit operator bool() const;
void setMsgId(mtpMsgId msgId);
[[nodiscard]] mtpMsgId getMsgId() const;
void setSeqNo(uint32 seqNo);
[[nodiscard]] uint32 getSeqNo() const;
void addPadding(bool extended, bool old);
[[nodiscard]] uint32 messageSize() const;
// "request-like" wrap for msgIds vector
[[nodiscard]] bool isSentContainer() const;
[[nodiscard]] bool isStateRequest() const;
[[nodiscard]] bool needAck() const;
using ResponseType = void; // don't know real response type =(
private:
explicit SecureRequest(const details::SecureRequestCreateTag &);
[[nodiscard]] size_t sizeInBytes() const;
[[nodiscard]] const void *dataInBytes() const;
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 = tl::count_length(request) >> 2;
auto serialized = Prepare(requestSize);
request.template write<mtpBuffer>(*serialized);
return serialized;
}
} // namespace MTP
using MTPint = tl::int_type; using MTPint = tl::int_type;
inline MTPint MTP_int(int32 v) { inline MTPint MTP_int(int32 v) {

View File

@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "mtproto/details/mtproto_bound_key_creator.h" #include "mtproto/details/mtproto_bound_key_creator.h"
#include "mtproto/details/mtproto_serialized_request.h"
namespace MTP::details { namespace MTP::details {
BoundKeyCreator::BoundKeyCreator(DcKeyRequest request, Delegate delegate) BoundKeyCreator::BoundKeyCreator(DcKeyRequest request, Delegate delegate)
@ -54,7 +56,7 @@ bool BoundKeyCreator::readyToBind() const {
return _binder.has_value(); return _binder.has_value();
} }
SecureRequest BoundKeyCreator::prepareBindRequest( SerializedRequest BoundKeyCreator::prepareBindRequest(
const AuthKeyPtr &temporaryKey, const AuthKeyPtr &temporaryKey,
uint64 sessionId) { uint64 sessionId) {
Expects(_binder.has_value()); Expects(_binder.has_value());

View File

@ -12,6 +12,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace MTP::details { namespace MTP::details {
class SerializedRequest;
class BoundKeyCreator final { class BoundKeyCreator final {
public: public:
struct Delegate { struct Delegate {
@ -32,7 +34,7 @@ public:
void bind(AuthKeyPtr &&persistentKey); void bind(AuthKeyPtr &&persistentKey);
void restartBinder(); void restartBinder();
[[nodiscard]] bool readyToBind() const; [[nodiscard]] bool readyToBind() const;
[[nodiscard]] SecureRequest prepareBindRequest( [[nodiscard]] SerializedRequest prepareBindRequest(
const AuthKeyPtr &temporaryKey, const AuthKeyPtr &temporaryKey,
uint64 sessionId); uint64 sessionId);
[[nodiscard]] DcKeyBindState handleBindResponse( [[nodiscard]] DcKeyBindState handleBindResponse(

View File

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "mtproto/details/mtproto_dc_key_binder.h" #include "mtproto/details/mtproto_dc_key_binder.h"
#include "mtproto/details/mtproto_serialized_request.h"
#include "mtproto/mtp_instance.h" #include "mtproto/mtp_instance.h"
#include "base/unixtime.h" #include "base/unixtime.h"
#include "base/openssl_help.h" #include "base/openssl_help.h"
@ -21,12 +22,12 @@ namespace {
const AuthKeyPtr &persistentKey, const AuthKeyPtr &persistentKey,
mtpMsgId realMsgId, mtpMsgId realMsgId,
const MTPBindAuthKeyInner &data) { const MTPBindAuthKeyInner &data) {
auto serialized = SecureRequest::Serialize(data); auto serialized = SerializedRequest::Serialize(data);
serialized.setMsgId(realMsgId); serialized.setMsgId(realMsgId);
serialized.setSeqNo(0); serialized.setSeqNo(0);
serialized.addPadding(false, true); serialized.addPadding(false, true);
constexpr auto kMsgIdPosition = SecureRequest::kMessageIdPosition; constexpr auto kMsgIdPosition = SerializedRequest::kMessageIdPosition;
constexpr auto kMinMessageSize = 5; constexpr auto kMinMessageSize = 5;
const auto sizeInPrimes = serialized->size(); const auto sizeInPrimes = serialized->size();
@ -77,7 +78,7 @@ DcKeyBinder::DcKeyBinder(AuthKeyPtr &&persistentKey)
Expects(_persistentKey != nullptr); Expects(_persistentKey != nullptr);
} }
SecureRequest DcKeyBinder::prepareRequest( SerializedRequest DcKeyBinder::prepareRequest(
const AuthKeyPtr &temporaryKey, const AuthKeyPtr &temporaryKey,
uint64 sessionId) { uint64 sessionId) {
Expects(temporaryKey != nullptr); Expects(temporaryKey != nullptr);
@ -85,7 +86,7 @@ SecureRequest DcKeyBinder::prepareRequest(
const auto nonce = openssl::RandomValue<uint64>(); const auto nonce = openssl::RandomValue<uint64>();
const auto msgId = base::unixtime::mtproto_msg_id(); const auto msgId = base::unixtime::mtproto_msg_id();
auto result = SecureRequest::Serialize(MTPauth_BindTempAuthKey( auto result = SerializedRequest::Serialize(MTPauth_BindTempAuthKey(
MTP_long(_persistentKey->keyId()), MTP_long(_persistentKey->keyId()),
MTP_long(nonce), MTP_long(nonce),
MTP_int(temporaryKey->expiresAt()), MTP_int(temporaryKey->expiresAt()),

View File

@ -16,6 +16,8 @@ class Instance;
namespace MTP::details { namespace MTP::details {
class SerializedRequest;
enum class DcKeyBindState { enum class DcKeyBindState {
Success, Success,
Failed, Failed,
@ -26,7 +28,7 @@ class DcKeyBinder final {
public: public:
explicit DcKeyBinder(AuthKeyPtr &&persistentKey); explicit DcKeyBinder(AuthKeyPtr &&persistentKey);
[[nodiscard]] SecureRequest prepareRequest( [[nodiscard]] SerializedRequest prepareRequest(
const AuthKeyPtr &temporaryKey, const AuthKeyPtr &temporaryKey,
uint64 sessionId); uint64 sessionId);
[[nodiscard]] DcKeyBindState handleResponse(const mtpBuffer &response); [[nodiscard]] DcKeyBindState handleResponse(const mtpBuffer &response);

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once #pragma once
#include "mtproto/core_types.h" #include "mtproto/core_types.h"
#include "mtproto/details/mtproto_serialized_request.h"
namespace MTP::details { namespace MTP::details {

View File

@ -5,9 +5,11 @@ the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link: For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "mtproto/core_types.h" #include "mtproto/details/mtproto_serialized_request.h"
namespace MTP { #include "base/openssl_help.h"
namespace MTP::details {
namespace { namespace {
uint32 CountPaddingPrimesCount(uint32 requestSize, bool extended, bool old) { uint32 CountPaddingPrimesCount(uint32 requestSize, bool extended, bool old) {
@ -27,7 +29,7 @@ uint32 CountPaddingPrimesCount(uint32 requestSize, bool extended, bool old) {
if (extended) { if (extended) {
// Some more random padding. // Some more random padding.
result += ((rand_value<uchar>() & 0x0F) << 2); result += ((openssl::RandomValue<uchar>() & 0x0F) << 2);
} }
return result; return result;
@ -35,67 +37,72 @@ uint32 CountPaddingPrimesCount(uint32 requestSize, bool extended, bool old) {
} // namespace } // namespace
SecureRequest::SecureRequest(const details::SecureRequestCreateTag &tag) SerializedRequest::SerializedRequest(const RequestConstructHider::Tag &tag)
: _data(std::make_shared<SecureRequestData>(tag)) { : _data(std::make_shared<RequestData>(tag)) {
} }
SecureRequest SecureRequest::Prepare(uint32 size, uint32 reserveSize) { SerializedRequest SerializedRequest::Prepare(
uint32 size,
uint32 reserveSize) {
Expects(size > 0);
const auto finalSize = std::max(size, reserveSize); const auto finalSize = std::max(size, reserveSize);
auto result = SecureRequest(details::SecureRequestCreateTag{}); auto result = SerializedRequest(RequestConstructHider::Tag{});
result->reserve(kMessageBodyPosition + finalSize); result->reserve(kMessageBodyPosition + finalSize);
result->resize(kMessageBodyPosition); result->resize(kMessageBodyPosition);
result->back() = (size << 2); result->back() = (size << 2);
result->msDate = crl::now(); // > 0 - can send without container result->lastSentTime = crl::now();
return result; return result;
} }
SecureRequestData *SecureRequest::operator->() const { RequestData *SerializedRequest::operator->() const {
Expects(_data != nullptr); Expects(_data != nullptr);
return _data.get(); return _data.get();
} }
SecureRequestData &SecureRequest::operator*() const { RequestData &SerializedRequest::operator*() const {
Expects(_data != nullptr); Expects(_data != nullptr);
return *_data; return *_data;
} }
SecureRequest::operator bool() const { SerializedRequest::operator bool() const {
return (_data != nullptr); return (_data != nullptr);
} }
void SecureRequest::setMsgId(mtpMsgId msgId) { void SerializedRequest::setMsgId(mtpMsgId msgId) {
Expects(_data != nullptr); Expects(_data != nullptr);
Expects(_data->size() > kMessageBodyPosition);
memcpy(_data->data() + kMessageIdPosition, &msgId, sizeof(mtpMsgId)); memcpy(_data->data() + kMessageIdPosition, &msgId, sizeof(mtpMsgId));
} }
mtpMsgId SecureRequest::getMsgId() const { mtpMsgId SerializedRequest::getMsgId() const {
Expects(_data != nullptr); Expects(_data != nullptr);
Expects(_data->size() > kMessageBodyPosition);
return *(mtpMsgId*)(_data->constData() + kMessageIdPosition); return *(mtpMsgId*)(_data->constData() + kMessageIdPosition);
} }
void SecureRequest::setSeqNo(uint32 seqNo) { void SerializedRequest::setSeqNo(uint32 seqNo) {
Expects(_data != nullptr); Expects(_data != nullptr);
Expects(_data->size() > kMessageBodyPosition);
(*_data)[kSeqNoPosition] = mtpPrime(seqNo); (*_data)[kSeqNoPosition] = mtpPrime(seqNo);
} }
uint32 SecureRequest::getSeqNo() const { uint32 SerializedRequest::getSeqNo() const {
Expects(_data != nullptr); Expects(_data != nullptr);
Expects(_data->size() > kMessageBodyPosition);
return uint32((*_data)[kSeqNoPosition]); return uint32((*_data)[kSeqNoPosition]);
} }
void SecureRequest::addPadding(bool extended, bool old) { void SerializedRequest::addPadding(bool extended, bool old) {
Expects(_data != nullptr); Expects(_data != nullptr);
Expects(_data->size() > kMessageBodyPosition);
if (_data->size() <= kMessageBodyPosition) {
return;
}
const auto requestSize = (tl::count_length(*this) >> 2); const auto requestSize = (tl::count_length(*this) >> 2);
const auto padding = CountPaddingPrimesCount(requestSize, extended, old); const auto padding = CountPaddingPrimesCount(requestSize, extended, old);
@ -103,48 +110,38 @@ void SecureRequest::addPadding(bool extended, bool old) {
if (uint32(_data->size()) != fullSize) { if (uint32(_data->size()) != fullSize) {
_data->resize(fullSize); _data->resize(fullSize);
if (padding > 0) { if (padding > 0) {
memset_rand( bytes::set_random(bytes::make_span(*_data).subspan(
_data->data() + (fullSize - padding), (fullSize - padding) * sizeof(mtpPrime)));
padding * sizeof(mtpPrime));
} }
} }
} }
uint32 SecureRequest::messageSize() const { uint32 SerializedRequest::messageSize() const {
Expects(_data != nullptr); Expects(_data != nullptr);
Expects(_data->size() > kMessageBodyPosition);
if (_data->size() <= kMessageBodyPosition) {
return 0;
}
const auto ints = (tl::count_length(*this) >> 2); const auto ints = (tl::count_length(*this) >> 2);
return kMessageIdInts + kSeqNoInts + kMessageLengthInts + ints; return kMessageIdInts + kSeqNoInts + kMessageLengthInts + ints;
} }
bool SecureRequest::isSentContainer() const { bool SerializedRequest::isSentContainer() const {
Expects(_data != nullptr); Expects(_data != nullptr);
if (_data->size() <= kMessageBodyPosition) { return _data->isContainerIdsWrap;
return false;
}
return (!_data->msDate && !getSeqNo()); // msDate = 0, seqNo = 0
} }
bool SecureRequest::isStateRequest() const { bool SerializedRequest::isStateRequest() const {
Expects(_data != nullptr); Expects(_data != nullptr);
Expects(_data->size() > kMessageBodyPosition);
if (_data->size() <= kMessageBodyPosition) {
return false;
}
const auto type = mtpTypeId((*_data)[kMessageBodyPosition]); const auto type = mtpTypeId((*_data)[kMessageBodyPosition]);
return (type == mtpc_msgs_state_req); return (type == mtpc_msgs_state_req);
} }
bool SecureRequest::needAck() const { bool SerializedRequest::needAck() const {
Expects(_data != nullptr); Expects(_data != nullptr);
Expects(_data->size() > kMessageBodyPosition);
if (_data->size() <= kMessageBodyPosition) {
return false;
}
const auto type = mtpTypeId((*_data)[kMessageBodyPosition]); const auto type = mtpTypeId((*_data)[kMessageBodyPosition]);
switch (type) { switch (type) {
case mtpc_msg_container: case mtpc_msg_container:
@ -160,16 +157,14 @@ bool SecureRequest::needAck() const {
return true; return true;
} }
size_t SecureRequest::sizeInBytes() const { size_t SerializedRequest::sizeInBytes() const {
return (_data && _data->size() > kMessageBodyPosition) Expects(!_data || _data->size() > kMessageBodyPosition);
? (*_data)[kMessageLengthPosition] return _data ? (*_data)[kMessageLengthPosition] : 0;
: 0;
} }
const void *SecureRequest::dataInBytes() const { const void *SerializedRequest::dataInBytes() const {
return (_data && _data->size() > kMessageBodyPosition) Expects(!_data || _data->size() > kMessageBodyPosition);
? (_data->constData() + kMessageBodyPosition) return _data ? (_data->constData() + kMessageBodyPosition) : nullptr;
: nullptr;
} }
} // namespace MTP } // namespace MTP

View File

@ -0,0 +1,109 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "mtproto/core_types.h"
#include <crl/crl_time.h>
namespace MTP::details {
class RequestData;
class SerializedRequest;
class RequestConstructHider {
struct Tag {};
friend class RequestData;
friend class SerializedRequest;
};
class SerializedRequest {
public:
SerializedRequest() = default;
static constexpr auto kSaltInts = 2;
static constexpr auto kSessionIdInts = 2;
static constexpr auto kMessageIdPosition = kSaltInts + kSessionIdInts;
static constexpr auto kMessageIdInts = 2;
static constexpr auto kSeqNoPosition = kMessageIdPosition
+ kMessageIdInts;
static constexpr auto kSeqNoInts = 1;
static constexpr auto kMessageLengthPosition = kSeqNoPosition
+ kSeqNoInts;
static constexpr auto kMessageLengthInts = 1;
static constexpr auto kMessageBodyPosition = kMessageLengthPosition
+ kMessageLengthInts;
static SerializedRequest Prepare(uint32 size, uint32 reserveSize = 0);
template <
typename Request,
typename = std::enable_if_t<tl::is_boxed_v<Request>>>
static SerializedRequest Serialize(const Request &request);
// For template MTP requests and MTPBoxed instantiation.
template <typename Accumulator>
void write(Accumulator &to) const {
if (const auto size = sizeInBytes()) {
tl::Writer<Accumulator>::PutBytes(to, dataInBytes(), size);
}
}
RequestData *operator->() const;
RequestData &operator*() const;
explicit operator bool() const;
void setMsgId(mtpMsgId msgId);
[[nodiscard]] mtpMsgId getMsgId() const;
void setSeqNo(uint32 seqNo);
[[nodiscard]] uint32 getSeqNo() const;
void addPadding(bool extended, bool old);
[[nodiscard]] uint32 messageSize() const;
// "request-like" wrap for msgIds vector
[[nodiscard]] bool isSentContainer() const;
[[nodiscard]] bool isStateRequest() const;
[[nodiscard]] bool needAck() const;
using ResponseType = void; // don't know real response type =(
private:
explicit SerializedRequest(const RequestConstructHider::Tag &);
[[nodiscard]] size_t sizeInBytes() const;
[[nodiscard]] const void *dataInBytes() const;
std::shared_ptr<RequestData> _data;
};
class RequestData : public mtpBuffer {
public:
explicit RequestData(const RequestConstructHider::Tag &) {
}
SerializedRequest after;
crl::time lastSentTime = 0;
mtpRequestId requestId = 0;
bool needsLayer = false;
bool forceSendInContainer = false;
bool isContainerIdsWrap = false;
};
template <typename Request, typename>
SerializedRequest SerializedRequest::Serialize(const Request &request) {
const auto requestSize = tl::count_length(request) >> 2;
auto serialized = Prepare(requestSize);
request.template write<mtpBuffer>(*serialized);
return serialized;
}
} // namespace MTP::details

View File

@ -36,6 +36,7 @@ constexpr auto kConfigBecomesOldForBlockedIn = 8 * crl::time(1000);
constexpr auto kCheckKeyEach = 60 * crl::time(1000); constexpr auto kCheckKeyEach = 60 * crl::time(1000);
using namespace internal; using namespace internal;
using namespace details;
std::atomic<int> GlobalAtomicRequestId = 0; std::atomic<int> GlobalAtomicRequestId = 0;
@ -111,7 +112,7 @@ public:
void sendRequest( void sendRequest(
mtpRequestId requestId, mtpRequestId requestId,
SecureRequest &&request, SerializedRequest &&request,
RPCResponseHandler &&callbacks, RPCResponseHandler &&callbacks,
ShiftedDcId shiftedDcId, ShiftedDcId shiftedDcId,
crl::time msCanWait, crl::time msCanWait,
@ -121,9 +122,9 @@ public:
void unregisterRequest(mtpRequestId requestId); void unregisterRequest(mtpRequestId requestId);
void storeRequest( void storeRequest(
mtpRequestId requestId, mtpRequestId requestId,
const SecureRequest &request, const SerializedRequest &request,
RPCResponseHandler &&callbacks); RPCResponseHandler &&callbacks);
SecureRequest getRequest(mtpRequestId requestId); SerializedRequest getRequest(mtpRequestId requestId);
void clearCallbacksDelayed(std::vector<RPCCallbackClear> &&ids); void clearCallbacksDelayed(std::vector<RPCCallbackClear> &&ids);
void execCallback(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end); void execCallback(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end);
bool hasCallbacks(mtpRequestId requestId); bool hasCallbacks(mtpRequestId requestId);
@ -238,7 +239,7 @@ private:
std::map<mtpRequestId, RPCResponseHandler> _parserMap; std::map<mtpRequestId, RPCResponseHandler> _parserMap;
QMutex _parserMapLock; QMutex _parserMapLock;
std::map<mtpRequestId, SecureRequest> _requestMap; std::map<mtpRequestId, SerializedRequest> _requestMap;
QReadWriteLock _requestMapLock; QReadWriteLock _requestMapLock;
std::deque<std::pair<mtpRequestId, crl::time>> _delayedRequests; std::deque<std::pair<mtpRequestId, crl::time>> _delayedRequests;
@ -911,7 +912,7 @@ void Instance::Private::checkDelayedRequests() {
continue; continue;
} }
auto request = SecureRequest(); auto request = SerializedRequest();
{ {
QReadLocker locker(&_requestMapLock); QReadLocker locker(&_requestMapLock);
auto it = _requestMap.find(requestId); auto it = _requestMap.find(requestId);
@ -932,7 +933,7 @@ void Instance::Private::checkDelayedRequests() {
void Instance::Private::sendRequest( void Instance::Private::sendRequest(
mtpRequestId requestId, mtpRequestId requestId,
SecureRequest &&request, SerializedRequest &&request,
RPCResponseHandler &&callbacks, RPCResponseHandler &&callbacks,
ShiftedDcId shiftedDcId, ShiftedDcId shiftedDcId,
crl::time msCanWait, crl::time msCanWait,
@ -951,7 +952,7 @@ void Instance::Private::sendRequest(
if (afterRequestId) { if (afterRequestId) {
request->after = getRequest(afterRequestId); request->after = getRequest(afterRequestId);
} }
request->msDate = crl::now(); // > 0 - can send without container request->lastSentTime = crl::now();
request->needsLayer = needsLayer; request->needsLayer = needsLayer;
session->sendPrepared(request, msCanWait); session->sendPrepared(request, msCanWait);
@ -980,7 +981,7 @@ void Instance::Private::unregisterRequest(mtpRequestId requestId) {
void Instance::Private::storeRequest( void Instance::Private::storeRequest(
mtpRequestId requestId, mtpRequestId requestId,
const SecureRequest &request, const SerializedRequest &request,
RPCResponseHandler &&callbacks) { RPCResponseHandler &&callbacks) {
if (callbacks.onDone || callbacks.onFail) { if (callbacks.onDone || callbacks.onFail) {
QMutexLocker locker(&_parserMapLock); QMutexLocker locker(&_parserMapLock);
@ -992,8 +993,8 @@ void Instance::Private::storeRequest(
} }
} }
SecureRequest Instance::Private::getRequest(mtpRequestId requestId) { SerializedRequest Instance::Private::getRequest(mtpRequestId requestId) {
auto result = SecureRequest(); auto result = SerializedRequest();
{ {
QReadLocker locker(&_requestMapLock); QReadLocker locker(&_requestMapLock);
auto it = _requestMap.find(requestId); auto it = _requestMap.find(requestId);
@ -1319,7 +1320,7 @@ bool Instance::Private::onErrorDefault(mtpRequestId requestId, const RPCError &e
newdcWithShift = ShiftDcId(newdcWithShift, GetDcIdShift(dcWithShift)); newdcWithShift = ShiftDcId(newdcWithShift, GetDcIdShift(dcWithShift));
} }
auto request = SecureRequest(); auto request = SerializedRequest();
{ {
QReadLocker locker(&_requestMapLock); QReadLocker locker(&_requestMapLock);
auto it = _requestMap.find(requestId); auto it = _requestMap.find(requestId);
@ -1391,7 +1392,7 @@ bool Instance::Private::onErrorDefault(mtpRequestId requestId, const RPCError &e
if (badGuestDc) _badGuestDcRequests.insert(requestId); if (badGuestDc) _badGuestDcRequests.insert(requestId);
return true; return true;
} else if (err == qstr("CONNECTION_NOT_INITED") || err == qstr("CONNECTION_LAYER_INVALID")) { } else if (err == qstr("CONNECTION_NOT_INITED") || err == qstr("CONNECTION_LAYER_INVALID")) {
SecureRequest request; SerializedRequest request;
{ {
QReadLocker locker(&_requestMapLock); QReadLocker locker(&_requestMapLock);
auto it = _requestMap.find(requestId); auto it = _requestMap.find(requestId);
@ -1416,7 +1417,7 @@ bool Instance::Private::onErrorDefault(mtpRequestId requestId, const RPCError &e
} else if (err == qstr("CONNECTION_LANG_CODE_INVALID")) { } else if (err == qstr("CONNECTION_LANG_CODE_INVALID")) {
Lang::CurrentCloudManager().resetToDefault(); Lang::CurrentCloudManager().resetToDefault();
} else if (err == qstr("MSG_WAIT_FAILED")) { } else if (err == qstr("MSG_WAIT_FAILED")) {
SecureRequest request; SerializedRequest request;
{ {
QReadLocker locker(&_requestMapLock); QReadLocker locker(&_requestMapLock);
auto it = _requestMap.find(requestId); auto it = _requestMap.find(requestId);
@ -1435,7 +1436,7 @@ bool Instance::Private::onErrorDefault(mtpRequestId requestId, const RPCError &e
if (const auto afterDcId = queryRequestByDc(request->after->requestId)) { if (const auto afterDcId = queryRequestByDc(request->after->requestId)) {
dcWithShift = *shiftedDcId; dcWithShift = *shiftedDcId;
if (*shiftedDcId != *afterDcId) { if (*shiftedDcId != *afterDcId) {
request->after = SecureRequest(); request->after = SerializedRequest();
} }
} else { } else {
LOG(("MTP Error: could not find dependent request %1 by dc").arg(request->after->requestId)); LOG(("MTP Error: could not find dependent request %1 by dc").arg(request->after->requestId));
@ -1852,7 +1853,7 @@ void Instance::keyDestroyedOnServer(ShiftedDcId shiftedDcId, uint64 keyId) {
void Instance::sendRequest( void Instance::sendRequest(
mtpRequestId requestId, mtpRequestId requestId,
SecureRequest &&request, SerializedRequest &&request,
RPCResponseHandler &&callbacks, RPCResponseHandler &&callbacks,
ShiftedDcId shiftedDcId, ShiftedDcId shiftedDcId,
crl::time msCanWait, crl::time msCanWait,

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once #pragma once
#include "mtproto/mtproto_rpc_sender.h" #include "mtproto/mtproto_rpc_sender.h"
#include "mtproto/details/mtproto_serialized_request.h"
namespace MTP { namespace MTP {
namespace internal { namespace internal {
@ -139,7 +140,7 @@ public:
const auto requestId = internal::GetNextRequestId(); const auto requestId = internal::GetNextRequestId();
sendSerialized( sendSerialized(
requestId, requestId,
SecureRequest::Serialize(request), details::SerializedRequest::Serialize(request),
std::move(callbacks), std::move(callbacks),
shiftedDcId, shiftedDcId,
msCanWait, msCanWait,
@ -170,7 +171,7 @@ public:
const auto requestId = internal::GetNextRequestId(); const auto requestId = internal::GetNextRequestId();
sendRequest( sendRequest(
requestId, requestId,
SecureRequest::Serialize(request), details::SerializedRequest::Serialize(request),
{}, {},
shiftedDcId, shiftedDcId,
0, 0,
@ -181,7 +182,7 @@ public:
void sendSerialized( void sendSerialized(
mtpRequestId requestId, mtpRequestId requestId,
SecureRequest &&request, details::SerializedRequest &&request,
RPCResponseHandler &&callbacks, RPCResponseHandler &&callbacks,
ShiftedDcId shiftedDcId, ShiftedDcId shiftedDcId,
crl::time msCanWait, crl::time msCanWait,
@ -209,7 +210,7 @@ signals:
private: private:
void sendRequest( void sendRequest(
mtpRequestId requestId, mtpRequestId requestId,
SecureRequest &&request, details::SerializedRequest &&request,
RPCResponseHandler &&callbacks, RPCResponseHandler &&callbacks,
ShiftedDcId shiftedDcId, ShiftedDcId shiftedDcId,
crl::time msCanWait, crl::time msCanWait,

View File

@ -94,12 +94,6 @@ void SessionData::queueSendAnything(crl::time msCanWait) {
}); });
} }
void SessionData::queueSendMsgsStateInfo(quint64 msgId, QByteArray data) {
withSession([=](not_null<Session*> session) {
session->sendMsgsStateInfo(msgId, data);
});
}
bool SessionData::connectionInited() const { bool SessionData::connectionInited() const {
QMutexLocker lock(&_ownerMutex); QMutexLocker lock(&_ownerMutex);
return _owner ? _owner->connectionInited() : false; return _owner ? _owner->connectionInited() : false;
@ -300,18 +294,6 @@ void Session::needToResumeAndSend() {
} }
} }
void Session::sendMsgsStateInfo(quint64 msgId, QByteArray data) {
auto info = bytes::vector();
if (!data.isEmpty()) {
info.resize(data.size());
bytes::copy(info, bytes::make_span(data));
}
_instance->sendProtocolMessage(
_shiftedDcId,
MTPMsgsStateInfo(
MTP_msgs_state_info(MTP_long(msgId), MTP_bytes(data))));
}
void Session::connectionStateChange(int newState) { void Session::connectionStateChange(int newState) {
_instance->onStateChange(_shiftedDcId, newState); _instance->onStateChange(_shiftedDcId, newState);
} }
@ -356,17 +338,14 @@ int32 Session::requestState(mtpRequestId requestId) const {
} }
if (!connected) { if (!connected) {
return result; return result;
} } else if (!requestId) {
if (!requestId) return MTP::RequestSent;
QWriteLocker locker(_data->toSendMutex());
const auto &toSend = _data->toSendMap();
const auto i = toSend.constFind(requestId);
if (i != toSend.cend()) {
return MTP::RequestSending;
} else {
return MTP::RequestSent; return MTP::RequestSent;
} }
QWriteLocker locker(_data->toSendMutex());
return _data->toSendMap().contains(requestId)
? MTP::RequestSending
: MTP::RequestSent;
} }
int32 Session::getState() const { int32 Session::getState() const {
@ -397,13 +376,13 @@ QString Session::transport() const {
} }
void Session::sendPrepared( void Session::sendPrepared(
const SecureRequest &request, const details::SerializedRequest &request,
crl::time msCanWait) { crl::time msCanWait) {
DEBUG_LOG(("MTP Info: adding request to toSendMap, msCanWait %1" DEBUG_LOG(("MTP Info: adding request to toSendMap, msCanWait %1"
).arg(msCanWait)); ).arg(msCanWait));
{ {
QWriteLocker locker(_data->toSendMutex()); QWriteLocker locker(_data->toSendMutex());
_data->toSendMap().insert(request->requestId, request); _data->toSendMap().emplace(request->requestId, request);
*(mtpMsgId*)(request->data() + 4) = 0; *(mtpMsgId*)(request->data() + 4) = 0;
*(request->data() + 6) = 0; *(request->data() + 6) = 0;
} }
@ -510,35 +489,27 @@ void Session::tryToReceive() {
return; return;
} }
while (true) { while (true) {
auto requestId = mtpRequestId(0); auto lock = QWriteLocker(_data->haveReceivedMutex());
auto isUpdate = false; const auto responses = base::take(_data->haveReceivedResponses());
auto message = SerializedMessage(); const auto updates = base::take(_data->haveReceivedUpdates());
{ lock.unlock();
QWriteLocker locker(_data->haveReceivedMutex()); if (responses.empty() && updates.empty()) {
auto &responses = _data->haveReceivedResponses(); break;
auto response = responses.begin();
if (response == responses.cend()) {
auto &updates = _data->haveReceivedUpdates();
auto update = updates.begin();
if (update == updates.cend()) {
return;
} else {
message = std::move(*update);
isUpdate = true;
updates.pop_front();
}
} else {
requestId = response.key();
message = std::move(response.value());
responses.erase(response);
}
} }
if (isUpdate) { for (const auto &[requestId, response] : responses) {
if (_shiftedDcId == BareDcId(_shiftedDcId)) { // call globalCallback only in main session _instance->execCallback(
_instance->globalCallback(message.constData(), message.constData() + message.size()); requestId,
response.constData(),
response.constData() + response.size());
}
// Call globalCallback only in main session.
if (_shiftedDcId == BareDcId(_shiftedDcId)) {
for (const auto &update : updates) {
_instance->globalCallback(
update.constData(),
update.constData() + update.size());
} }
} else {
_instance->execCallback(requestId, message.constData(), message.constData() + message.size());
} }
} }
} }

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer.h" #include "base/timer.h"
#include "mtproto/mtproto_rpc_sender.h" #include "mtproto/mtproto_rpc_sender.h"
#include "mtproto/mtproto_proxy_data.h" #include "mtproto/mtproto_proxy_data.h"
#include "mtproto/details/mtproto_serialized_request.h"
#include <QtCore/QTimer> #include <QtCore/QTimer>
@ -27,18 +28,6 @@ class Connection;
enum class TemporaryKeyType; enum class TemporaryKeyType;
enum class CreatingKeyType; enum class CreatingKeyType;
using PreRequestMap = QMap<mtpRequestId, SecureRequest>;
using RequestMap = QMap<mtpMsgId, SecureRequest>;
using SerializedMessage = mtpBuffer;
inline bool ResponseNeedsAck(const SerializedMessage &response) {
if (response.size() < 8) {
return false;
}
auto seqNo = *(uint32*)(response.constData() + 6);
return (seqNo & 0x01) ? true : false;
}
struct ConnectionOptions { struct ConnectionOptions {
ConnectionOptions() = default; ConnectionOptions() = default;
ConnectionOptions( ConnectionOptions(
@ -80,38 +69,26 @@ public:
return _options; return _options;
} }
not_null<QReadWriteLock*> toSendMutex() const { not_null<QReadWriteLock*> toSendMutex() {
return &_toSendLock; return &_toSendLock;
} }
not_null<QReadWriteLock*> haveSentMutex() const { not_null<QReadWriteLock*> haveSentMutex() {
return &_haveSentLock; return &_haveSentLock;
} }
not_null<QReadWriteLock*> haveReceivedMutex() const { not_null<QReadWriteLock*> haveReceivedMutex() {
return &_haveReceivedLock; return &_haveReceivedLock;
} }
PreRequestMap &toSendMap() { base::flat_map<mtpRequestId, details::SerializedRequest> &toSendMap() {
return _toSend; return _toSend;
} }
const PreRequestMap &toSendMap() const { base::flat_map<mtpMsgId, details::SerializedRequest> &haveSentMap() {
return _toSend;
}
RequestMap &haveSentMap() {
return _haveSent; return _haveSent;
} }
const RequestMap &haveSentMap() const { base::flat_map<mtpRequestId, mtpBuffer> &haveReceivedResponses() {
return _haveSent;
}
QMap<mtpRequestId, SerializedMessage> &haveReceivedResponses() {
return _receivedResponses; return _receivedResponses;
} }
const QMap<mtpRequestId, SerializedMessage> &haveReceivedResponses() const { std::vector<mtpBuffer> &haveReceivedUpdates() {
return _receivedResponses;
}
QList<SerializedMessage> &haveReceivedUpdates() {
return _receivedUpdates;
}
const QList<SerializedMessage> &haveReceivedUpdates() const {
return _receivedUpdates; return _receivedUpdates;
} }
@ -126,7 +103,6 @@ public:
void queueConnectionStateChange(int newState); void queueConnectionStateChange(int newState);
void queueResetDone(); void queueResetDone();
void queueSendAnything(crl::time msCanWait = 0); void queueSendAnything(crl::time msCanWait = 0);
void queueSendMsgsStateInfo(quint64 msgId, QByteArray data);
[[nodiscard]] bool connectionInited() const; [[nodiscard]] bool connectionInited() const;
[[nodiscard]] AuthKeyPtr getPersistentKey() const; [[nodiscard]] AuthKeyPtr getPersistentKey() const;
@ -148,18 +124,17 @@ private:
mutable QMutex _ownerMutex; mutable QMutex _ownerMutex;
ConnectionOptions _options; ConnectionOptions _options;
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
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
// mutexes
mutable QReadWriteLock _optionsLock; mutable QReadWriteLock _optionsLock;
mutable QReadWriteLock _toSendLock;
mutable QReadWriteLock _haveSentLock; base::flat_map<mtpRequestId, details::SerializedRequest> _toSend; // map of request_id -> request, that is waiting to be sent
mutable QReadWriteLock _haveReceivedLock; QReadWriteLock _toSendLock;
base::flat_map<mtpMsgId, details::SerializedRequest> _haveSent; // map of msg_id -> request, that was sent
QReadWriteLock _haveSentLock;
base::flat_map<mtpRequestId, mtpBuffer> _receivedResponses; // map of request_id -> response that should be processed in the main thread
std::vector<mtpBuffer> _receivedUpdates; // list of updates that should be processed in the main thread
QReadWriteLock _haveReceivedLock;
}; };
@ -189,7 +164,9 @@ public:
[[nodiscard]] AuthKeyPtr getPersistentKey() const; [[nodiscard]] AuthKeyPtr getPersistentKey() const;
[[nodiscard]] AuthKeyPtr getTemporaryKey(TemporaryKeyType type) const; [[nodiscard]] AuthKeyPtr getTemporaryKey(TemporaryKeyType type) const;
[[nodiscard]] bool connectionInited() const; [[nodiscard]] bool connectionInited() const;
void sendPrepared(const SecureRequest &request, crl::time msCanWait = 0); void sendPrepared(
const details::SerializedRequest &request,
crl::time msCanWait = 0);
// Connection thread. // Connection thread.
[[nodiscard]] CreatingKeyType acquireKeyCreation(TemporaryKeyType type); [[nodiscard]] CreatingKeyType acquireKeyCreation(TemporaryKeyType type);
@ -212,7 +189,6 @@ public:
void connectionStateChange(int newState); void connectionStateChange(int newState);
void resetDone(); void resetDone();
void sendAnything(crl::time msCanWait = 0); void sendAnything(crl::time msCanWait = 0);
void sendMsgsStateInfo(quint64 msgId, QByteArray data);
signals: signals:
void authKeyChanged(); void authKeyChanged();

View File

@ -44,6 +44,8 @@
'<(src_loc)/mtproto/details/mtproto_dump_to_text.h', '<(src_loc)/mtproto/details/mtproto_dump_to_text.h',
'<(src_loc)/mtproto/details/mtproto_received_ids_manager.cpp', '<(src_loc)/mtproto/details/mtproto_received_ids_manager.cpp',
'<(src_loc)/mtproto/details/mtproto_received_ids_manager.h', '<(src_loc)/mtproto/details/mtproto_received_ids_manager.h',
'<(src_loc)/mtproto/details/mtproto_serialized_request.cpp',
'<(src_loc)/mtproto/details/mtproto_serialized_request.h',
'<(src_loc)/mtproto/mtproto_abstract_socket.cpp', '<(src_loc)/mtproto/mtproto_abstract_socket.cpp',
'<(src_loc)/mtproto/mtproto_abstract_socket.h', '<(src_loc)/mtproto/mtproto_abstract_socket.h',
'<(src_loc)/mtproto/mtproto_auth_key.cpp', '<(src_loc)/mtproto/mtproto_auth_key.cpp',

View File

@ -547,7 +547,6 @@
<(src_loc)/mtproto/connection_resolving.h <(src_loc)/mtproto/connection_resolving.h
<(src_loc)/mtproto/connection_tcp.cpp <(src_loc)/mtproto/connection_tcp.cpp
<(src_loc)/mtproto/connection_tcp.h <(src_loc)/mtproto/connection_tcp.h
<(src_loc)/mtproto/core_types.cpp
<(src_loc)/mtproto/core_types.h <(src_loc)/mtproto/core_types.h
<(src_loc)/mtproto/dcenter.cpp <(src_loc)/mtproto/dcenter.cpp
<(src_loc)/mtproto/dcenter.h <(src_loc)/mtproto/dcenter.h

@ -1 +1 @@
Subproject commit 2bf101114f0a54c868a2703a9a80c06c0f2d2c41 Subproject commit 13918d5b5c4611ef1563a13ac1daf4d2c77c5f49