init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
This commit is contained in:
213
Telegram/SourceFiles/mtproto/connection_abstract.h
Normal file
213
Telegram/SourceFiles/mtproto/connection_abstract.h
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
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/mtproto_dc_options.h"
|
||||
#include "mtproto/mtproto_proxy_data.h"
|
||||
#include "base/bytes.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include <deque>
|
||||
|
||||
namespace MTP {
|
||||
|
||||
class Instance;
|
||||
|
||||
namespace details {
|
||||
|
||||
struct ConnectionOptions;
|
||||
|
||||
class AbstractConnection;
|
||||
|
||||
inline constexpr auto kTestModeDcIdShift = 10000;
|
||||
|
||||
class ConnectionPointer {
|
||||
public:
|
||||
ConnectionPointer();
|
||||
ConnectionPointer(std::nullptr_t);
|
||||
ConnectionPointer(ConnectionPointer &&other);
|
||||
ConnectionPointer &operator=(ConnectionPointer &&other);
|
||||
|
||||
template <typename ConnectionType, typename ...Args>
|
||||
static ConnectionPointer New(Args &&...args) {
|
||||
return ConnectionPointer(new ConnectionType(
|
||||
std::forward<Args>(args)...
|
||||
));
|
||||
}
|
||||
|
||||
AbstractConnection *get() const;
|
||||
void reset(AbstractConnection *value = nullptr);
|
||||
operator AbstractConnection*() const;
|
||||
AbstractConnection *operator->() const;
|
||||
AbstractConnection &operator*() const;
|
||||
explicit operator bool() const;
|
||||
|
||||
~ConnectionPointer();
|
||||
|
||||
private:
|
||||
explicit ConnectionPointer(AbstractConnection *value);
|
||||
|
||||
AbstractConnection *_value = nullptr;
|
||||
|
||||
};
|
||||
|
||||
class AbstractConnection : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AbstractConnection(QThread *thread, const ProxyData &proxy);
|
||||
AbstractConnection(const AbstractConnection &other) = delete;
|
||||
AbstractConnection &operator=(const AbstractConnection &other) = delete;
|
||||
virtual ~AbstractConnection() = default;
|
||||
|
||||
// virtual constructor
|
||||
[[nodiscard]] static ConnectionPointer Create(
|
||||
not_null<Instance*> instance,
|
||||
DcOptions::Variants::Protocol protocol,
|
||||
QThread *thread,
|
||||
const bytes::vector &secret,
|
||||
const ProxyData &proxy);
|
||||
|
||||
[[nodiscard]] virtual ConnectionPointer clone(const ProxyData &proxy) = 0;
|
||||
|
||||
[[nodiscard]] virtual crl::time pingTime() const = 0;
|
||||
[[nodiscard]] virtual crl::time fullConnectTimeout() const = 0;
|
||||
virtual void sendData(mtpBuffer &&buffer) = 0;
|
||||
virtual void disconnectFromServer() = 0;
|
||||
virtual void connectToServer(
|
||||
const QString &ip,
|
||||
int port,
|
||||
const bytes::vector &protocolSecret,
|
||||
int16 protocolDcId,
|
||||
bool protocolForFiles) = 0;
|
||||
virtual void timedOut() {
|
||||
}
|
||||
[[nodiscard]] virtual bool isConnected() const = 0;
|
||||
[[nodiscard]] virtual bool usingHttpWait() {
|
||||
return false;
|
||||
}
|
||||
[[nodiscard]] virtual bool needHttpWait() {
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual int32 debugState() const = 0;
|
||||
|
||||
[[nodiscard]] virtual QString transport() const = 0;
|
||||
[[nodiscard]] virtual QString tag() const = 0;
|
||||
|
||||
void setSentEncryptedWithKeyId(uint64 keyId) {
|
||||
_sentEncryptedWithKeyId = keyId;
|
||||
}
|
||||
[[nodiscard]] uint64 sentEncryptedWithKeyId() const {
|
||||
return _sentEncryptedWithKeyId;
|
||||
}
|
||||
|
||||
using BuffersQueue = std::deque<mtpBuffer>;
|
||||
[[nodiscard]] BuffersQueue &received() {
|
||||
return _receivedQueue;
|
||||
}
|
||||
|
||||
template <typename Request>
|
||||
[[nodiscard]] mtpBuffer prepareNotSecurePacket(
|
||||
const Request &request,
|
||||
mtpMsgId newId) const;
|
||||
[[nodiscard]] mtpBuffer prepareSecurePacket(
|
||||
uint64 keyId,
|
||||
MTPint128 msgKey,
|
||||
uint32 size) const;
|
||||
|
||||
[[nodiscard]] gsl::span<const mtpPrime> parseNotSecureResponse(
|
||||
const mtpBuffer &buffer) const;
|
||||
|
||||
[[nodiscard]] static QString ProtocolDcDebugId(int16 protocolDcId);
|
||||
[[nodiscard]] QString debugId() const {
|
||||
return _debugId;
|
||||
}
|
||||
void logInfo(const QString &message);
|
||||
void logError(const QString &message);
|
||||
|
||||
// Used to emit error(...) with no real code from the server.
|
||||
static constexpr auto kErrorCodeOther = -499;
|
||||
|
||||
Q_SIGNALS:
|
||||
void receivedData();
|
||||
void receivedSome(); // to stop restart timer
|
||||
|
||||
void error(qint32 errorCodebool);
|
||||
|
||||
void connected();
|
||||
void disconnected();
|
||||
|
||||
void syncTimeRequest();
|
||||
|
||||
protected:
|
||||
BuffersQueue _receivedQueue; // list of received packets, not processed yet
|
||||
int _pingTime = 0;
|
||||
ProxyData _proxy;
|
||||
|
||||
QString _debugId;
|
||||
|
||||
// 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
|
||||
[[nodiscard]] mtpBuffer preparePQFake(const MTPint128 &nonce) const;
|
||||
[[nodiscard]] std::optional<MTPResPQ> readPQFakeReply(
|
||||
const mtpBuffer &buffer) const;
|
||||
|
||||
private:
|
||||
[[nodiscard]] uint32 extendedNotSecurePadding() const;
|
||||
|
||||
uint64 _sentEncryptedWithKeyId = 0;
|
||||
|
||||
};
|
||||
|
||||
template <typename Request>
|
||||
mtpBuffer AbstractConnection::prepareNotSecurePacket(
|
||||
const Request &request,
|
||||
mtpMsgId newId) const {
|
||||
const auto intsSize = tl::count_length(request) >> 2;
|
||||
const auto intsPadding = extendedNotSecurePadding();
|
||||
|
||||
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) = newId;
|
||||
|
||||
request.write(result);
|
||||
|
||||
const auto messageLength = messageId + kMessageIdInts;
|
||||
*messageLength = (result.size() - kPrefixInts + intsPadding) << 2;
|
||||
|
||||
if (intsPadding > 0) {
|
||||
const auto skipPrimes = result.size();
|
||||
result.resize(skipPrimes + intsPadding);
|
||||
const auto skipBytes = skipPrimes * sizeof(mtpPrime);
|
||||
bytes::set_random(bytes::make_span(result).subspan(skipBytes));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define CONNECTION_LOG_INFO(x) if (Logs::DebugEnabled()) { logInfo(x); }
|
||||
#define CONNECTION_LOG_ERROR(x) if (Logs::DebugEnabled()) { logError(x); }
|
||||
|
||||
} // namespace details
|
||||
} // namespace MTP
|
||||
Reference in New Issue
Block a user