mirror of https://github.com/procxx/kepka.git
added connection implementations to git, protocol improved
This commit is contained in:
parent
ad53185645
commit
7c99f947eb
|
@ -19,6 +19,7 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
|
|
||||||
#include <AL/al.h>
|
#include <AL/al.h>
|
||||||
|
@ -27,10 +28,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#define AL_ALEXT_PROTOTYPES
|
#define AL_ALEXT_PROTOTYPES
|
||||||
#include <AL/alext.h>
|
#include <AL/alext.h>
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
#include <libswresample/swresample.h>
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
#include <iconv.h>
|
#include <iconv.h>
|
||||||
|
|
||||||
#undef iconv_open
|
#undef iconv_open
|
||||||
|
@ -46,10 +50,9 @@ size_t iconv (iconv_t cd, char* * inbuf, size_t *inbytesleft, char* * outbuf, s
|
||||||
int iconv_close (iconv_t cd) {
|
int iconv_close (iconv_t cd) {
|
||||||
return libiconv_close(cd);
|
return libiconv_close(cd);
|
||||||
}
|
}
|
||||||
|
#endif // Q_OS_MAC
|
||||||
|
|
||||||
}
|
} // extern "C"
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
ALCdevice *audioDevice = 0;
|
ALCdevice *audioDevice = 0;
|
||||||
|
|
|
@ -28,6 +28,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include <openssl/bio.h>
|
#include <openssl/bio.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN // use Lzma SDK for win
|
||||||
|
#include <LzmaLib.h>
|
||||||
|
#else // Q_OS_WIN
|
||||||
|
#include <lzma.h>
|
||||||
|
#endif // else of Q_OS_WIN
|
||||||
|
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "pspecific.h"
|
#include "pspecific.h"
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "animation.h"
|
#include "animation.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
#include <libswscale/swscale.h>
|
||||||
|
}
|
||||||
|
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
|
|
||||||
|
|
|
@ -160,8 +160,8 @@ namespace {
|
||||||
|
|
||||||
QByteArray _settingsSalt, _passKeySalt, _passKeyEncrypted;
|
QByteArray _settingsSalt, _passKeySalt, _passKeyEncrypted;
|
||||||
|
|
||||||
mtpAuthKey _oldKey, _settingsKey, _passKey, _localKey;
|
MTP::AuthKey _oldKey, _settingsKey, _passKey, _localKey;
|
||||||
void createLocalKey(const QByteArray &pass, QByteArray *salt, mtpAuthKey *result) {
|
void createLocalKey(const QByteArray &pass, QByteArray *salt, MTP::AuthKey *result) {
|
||||||
uchar key[LocalEncryptKeySize] = { 0 };
|
uchar key[LocalEncryptKeySize] = { 0 };
|
||||||
int32 iterCount = pass.size() ? LocalEncryptIterCount : LocalEncryptNoPwdIterCount; // dont slow down for no password
|
int32 iterCount = pass.size() ? LocalEncryptIterCount : LocalEncryptNoPwdIterCount; // dont slow down for no password
|
||||||
QByteArray newSalt;
|
QByteArray newSalt;
|
||||||
|
@ -282,7 +282,7 @@ namespace {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
static QByteArray prepareEncrypted(EncryptedDescriptor &data, const mtpAuthKey &key = _localKey) {
|
static QByteArray prepareEncrypted(EncryptedDescriptor &data, const MTP::AuthKey &key = _localKey) {
|
||||||
data.finish();
|
data.finish();
|
||||||
QByteArray &toEncrypt(data.data);
|
QByteArray &toEncrypt(data.data);
|
||||||
|
|
||||||
|
@ -296,11 +296,11 @@ namespace {
|
||||||
*(uint32*)toEncrypt.data() = size;
|
*(uint32*)toEncrypt.data() = size;
|
||||||
QByteArray encrypted(0x10 + fullSize, Qt::Uninitialized); // 128bit of sha1 - key128, sizeof(data), data
|
QByteArray encrypted(0x10 + fullSize, Qt::Uninitialized); // 128bit of sha1 - key128, sizeof(data), data
|
||||||
hashSha1(toEncrypt.constData(), toEncrypt.size(), encrypted.data());
|
hashSha1(toEncrypt.constData(), toEncrypt.size(), encrypted.data());
|
||||||
aesEncryptLocal(toEncrypt.constData(), encrypted.data() + 0x10, fullSize, &key, encrypted.constData());
|
MTP::aesEncryptLocal(toEncrypt.constData(), encrypted.data() + 0x10, fullSize, &key, encrypted.constData());
|
||||||
|
|
||||||
return encrypted;
|
return encrypted;
|
||||||
}
|
}
|
||||||
bool writeEncrypted(EncryptedDescriptor &data, const mtpAuthKey &key = _localKey) {
|
bool writeEncrypted(EncryptedDescriptor &data, const MTP::AuthKey &key = _localKey) {
|
||||||
return writeData(prepareEncrypted(data, key));
|
return writeData(prepareEncrypted(data, key));
|
||||||
}
|
}
|
||||||
void finish() {
|
void finish() {
|
||||||
|
@ -468,7 +468,7 @@ namespace {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool decryptLocal(EncryptedDescriptor &result, const QByteArray &encrypted, const mtpAuthKey &key = _localKey) {
|
bool decryptLocal(EncryptedDescriptor &result, const QByteArray &encrypted, const MTP::AuthKey &key = _localKey) {
|
||||||
if (encrypted.size() <= 16 || (encrypted.size() & 0x0F)) {
|
if (encrypted.size() <= 16 || (encrypted.size() & 0x0F)) {
|
||||||
LOG(("App Error: bad encrypted part size: %1").arg(encrypted.size()));
|
LOG(("App Error: bad encrypted part size: %1").arg(encrypted.size()));
|
||||||
return false;
|
return false;
|
||||||
|
@ -504,7 +504,7 @@ namespace {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readEncryptedFile(FileReadDescriptor &result, const QString &name, int options = UserPath | SafePath, const mtpAuthKey &key = _localKey) {
|
bool readEncryptedFile(FileReadDescriptor &result, const QString &name, int options = UserPath | SafePath, const MTP::AuthKey &key = _localKey) {
|
||||||
if (!readFile(result, name, options)) {
|
if (!readFile(result, name, options)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -534,7 +534,7 @@ namespace {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readEncryptedFile(FileReadDescriptor &result, const FileKey &fkey, int options = UserPath | SafePath, const mtpAuthKey &key = _localKey) {
|
bool readEncryptedFile(FileReadDescriptor &result, const FileKey &fkey, int options = UserPath | SafePath, const MTP::AuthKey &key = _localKey) {
|
||||||
return readEncryptedFile(result, toFilePart(fkey), options, key);
|
return readEncryptedFile(result, toFilePart(fkey), options, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -932,7 +932,7 @@ namespace {
|
||||||
|
|
||||||
DEBUG_LOG(("MTP Info: key found, dc %1, key: %2").arg(dcId).arg(Logs::mb(key, 256).str()));
|
DEBUG_LOG(("MTP Info: key found, dc %1, key: %2").arg(dcId).arg(Logs::mb(key, 256).str()));
|
||||||
dcId = MTP::bareDcId(dcId);
|
dcId = MTP::bareDcId(dcId);
|
||||||
mtpAuthKeyPtr keyPtr(new mtpAuthKey());
|
MTP::AuthKeyPtr keyPtr(new MTP::AuthKey());
|
||||||
keyPtr->setKey(key);
|
keyPtr->setKey(key);
|
||||||
keyPtr->setDC(dcId);
|
keyPtr->setDC(dcId);
|
||||||
|
|
||||||
|
@ -1668,16 +1668,16 @@ namespace {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mtpKeysMap keys = MTP::getKeys();
|
MTP::AuthKeysMap keys = MTP::getKeys();
|
||||||
|
|
||||||
quint32 size = sizeof(quint32) + sizeof(qint32) + sizeof(quint32);
|
quint32 size = sizeof(quint32) + sizeof(qint32) + sizeof(quint32);
|
||||||
size += keys.size() * (sizeof(quint32) + sizeof(quint32) + 256);
|
size += keys.size() * (sizeof(quint32) + sizeof(quint32) + 256);
|
||||||
|
|
||||||
EncryptedDescriptor data(size);
|
EncryptedDescriptor data(size);
|
||||||
data.stream << quint32(dbiUser) << qint32(MTP::authedId()) << quint32(MTP::maindc());
|
data.stream << quint32(dbiUser) << qint32(MTP::authedId()) << quint32(MTP::maindc());
|
||||||
for (mtpKeysMap::const_iterator i = keys.cbegin(), e = keys.cend(); i != e; ++i) {
|
for_const (const MTP::AuthKeyPtr &key, keys) {
|
||||||
data.stream << quint32(dbiKey) << quint32((*i)->getDC());
|
data.stream << quint32(dbiKey) << quint32(key->getDC());
|
||||||
(*i)->write(data.stream);
|
key->write(data.stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
mtp.writeEncrypted(data, _localKey);
|
mtp.writeEncrypted(data, _localKey);
|
||||||
|
@ -2291,7 +2291,7 @@ namespace Local {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkPasscode(const QByteArray &passcode) {
|
bool checkPasscode(const QByteArray &passcode) {
|
||||||
mtpAuthKey tmp;
|
MTP::AuthKey tmp;
|
||||||
createLocalKey(passcode, &_passKeySalt, &tmp);
|
createLocalKey(passcode, &_passKeySalt, &tmp);
|
||||||
return (tmp == _passKey);
|
return (tmp == _passKey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,22 +24,36 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include <openssl/aes.h>
|
#include <openssl/aes.h>
|
||||||
|
|
||||||
void aesEncrypt(const void *src, void *dst, uint32 len, void *key, void *iv) {
|
namespace MTP {
|
||||||
|
|
||||||
|
void aesIgeEncrypt(const void *src, void *dst, uint32 len, const void *key, const void *iv) {
|
||||||
uchar aes_key[32], aes_iv[32];
|
uchar aes_key[32], aes_iv[32];
|
||||||
memcpy(aes_key, key, 32);
|
memcpy(aes_key, key, 32);
|
||||||
memcpy(aes_iv, iv, 32);
|
memcpy(aes_iv, iv, 32);
|
||||||
|
|
||||||
AES_KEY aes;
|
AES_KEY aes;
|
||||||
AES_set_encrypt_key(aes_key, 256, &aes);
|
AES_set_encrypt_key(aes_key, 256, &aes);
|
||||||
AES_ige_encrypt((const uchar*)src, (uchar*)dst, len, &aes, aes_iv, AES_ENCRYPT);
|
AES_ige_encrypt(static_cast<const uchar*>(src), static_cast<uchar*>(dst), len, &aes, aes_iv, AES_ENCRYPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void aesDecrypt(const void *src, void *dst, uint32 len, void *key, void *iv) {
|
void aesIgeDecrypt(const void *src, void *dst, uint32 len, const void *key, const void *iv) {
|
||||||
uchar aes_key[32], aes_iv[32];
|
uchar aes_key[32], aes_iv[32];
|
||||||
memcpy(aes_key, key, 32);
|
memcpy(aes_key, key, 32);
|
||||||
memcpy(aes_iv, iv, 32);
|
memcpy(aes_iv, iv, 32);
|
||||||
|
|
||||||
AES_KEY aes;
|
AES_KEY aes;
|
||||||
AES_set_decrypt_key(aes_key, 256, &aes);
|
AES_set_decrypt_key(aes_key, 256, &aes);
|
||||||
AES_ige_encrypt((const uchar*)src, (uchar*)dst, len, &aes, aes_iv, AES_DECRYPT);
|
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) {
|
||||||
|
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!");
|
||||||
|
|
||||||
|
AES_ctr128_encrypt(static_cast<const uchar*>(data), static_cast<uchar*>(data), len, &aes, state->ivec, state->ecount, &state->num);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace MTP
|
||||||
|
|
|
@ -20,10 +20,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
class mtpAuthKey {
|
namespace MTP {
|
||||||
|
|
||||||
|
class AuthKey {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
mtpAuthKey() : _isset(false), _dc(0) {
|
AuthKey() : _isset(false), _dc(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool created() const {
|
bool created() const {
|
||||||
|
@ -94,7 +96,7 @@ public:
|
||||||
|
|
||||||
static const uint64 RecreateKeyId = 0xFFFFFFFFFFFFFFFFL;
|
static const uint64 RecreateKeyId = 0xFFFFFFFFFFFFFFFFL;
|
||||||
|
|
||||||
friend bool operator==(const mtpAuthKey &a, const mtpAuthKey &b);
|
friend bool operator==(const AuthKey &a, const AuthKey &b);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -105,40 +107,54 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool operator==(const mtpAuthKey &a, const mtpAuthKey &b) {
|
inline bool operator==(const AuthKey &a, const AuthKey &b) {
|
||||||
return !memcmp(a._key, b._key, 256);
|
return !memcmp(a._key, b._key, 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef QSharedPointer<mtpAuthKey> mtpAuthKeyPtr;
|
typedef QSharedPointer<AuthKey> AuthKeyPtr;
|
||||||
typedef QVector<mtpAuthKeyPtr> mtpKeysMap;
|
typedef QVector<AuthKeyPtr> AuthKeysMap;
|
||||||
|
|
||||||
void aesEncrypt(const void *src, void *dst, uint32 len, void *key, void *iv);
|
void aesIgeEncrypt(const void *src, void *dst, uint32 len, const void *key, const void *iv);
|
||||||
void aesDecrypt(const void *src, void *dst, uint32 len, void *key, void *iv);
|
void aesIgeDecrypt(const void *src, void *dst, uint32 len, const void *key, const void *iv);
|
||||||
|
|
||||||
inline void aesEncrypt(const void *src, void *dst, uint32 len, const mtpAuthKeyPtr &authKey, const MTPint128 &msgKey) {
|
inline void aesIgeEncrypt(const void *src, void *dst, uint32 len, const AuthKeyPtr &authKey, const MTPint128 &msgKey) {
|
||||||
MTPint256 aesKey, aesIV;
|
MTPint256 aesKey, aesIV;
|
||||||
authKey->prepareAES(msgKey, aesKey, aesIV);
|
authKey->prepareAES(msgKey, aesKey, aesIV);
|
||||||
|
|
||||||
return aesEncrypt(src, dst, len, &aesKey, &aesIV);
|
return aesIgeEncrypt(src, dst, len, static_cast<const void*>(&aesKey), static_cast<const void*>(&aesIV));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void aesEncryptLocal(const void *src, void *dst, uint32 len, const mtpAuthKey *authKey, const void *key128) {
|
inline void aesEncryptLocal(const void *src, void *dst, uint32 len, const AuthKey *authKey, const void *key128) {
|
||||||
MTPint256 aesKey, aesIV;
|
MTPint256 aesKey, aesIV;
|
||||||
authKey->prepareAES(*(const MTPint128*)key128, aesKey, aesIV, false);
|
authKey->prepareAES(*(const MTPint128*)key128, aesKey, aesIV, false);
|
||||||
|
|
||||||
return aesEncrypt(src, dst, len, &aesKey, &aesIV);
|
return aesIgeEncrypt(src, dst, len, static_cast<const void*>(&aesKey), static_cast<const void*>(&aesIV));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void aesDecrypt(const void *src, void *dst, uint32 len, const mtpAuthKeyPtr &authKey, const MTPint128 &msgKey) {
|
inline void aesIgeDecrypt(const void *src, void *dst, uint32 len, const AuthKeyPtr &authKey, const MTPint128 &msgKey) {
|
||||||
MTPint256 aesKey, aesIV;
|
MTPint256 aesKey, aesIV;
|
||||||
authKey->prepareAES(msgKey, aesKey, aesIV, false);
|
authKey->prepareAES(msgKey, aesKey, aesIV, false);
|
||||||
|
|
||||||
return aesDecrypt(src, dst, len, &aesKey, &aesIV);
|
return aesIgeDecrypt(src, dst, len, static_cast<const void*>(&aesKey), static_cast<const void*>(&aesIV));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void aesDecryptLocal(const void *src, void *dst, uint32 len, const mtpAuthKey *authKey, const void *key128) {
|
inline void aesDecryptLocal(const void *src, void *dst, uint32 len, const AuthKey *authKey, const void *key128) {
|
||||||
MTPint256 aesKey, aesIV;
|
MTPint256 aesKey, aesIV;
|
||||||
authKey->prepareAES(*(const MTPint128*)key128, aesKey, aesIV, false);
|
authKey->prepareAES(*(const MTPint128*)key128, aesKey, aesIV, false);
|
||||||
|
|
||||||
return aesDecrypt(src, dst, len, &aesKey, &aesIV);
|
return aesIgeDecrypt(src, dst, len, static_cast<const void*>(&aesKey), static_cast<const void*>(&aesIV));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ctr used inplace, encrypt the data and leave it at the same place
|
||||||
|
struct CTRState {
|
||||||
|
static constexpr int KeySize = 32;
|
||||||
|
static constexpr int IvecSize = 16;
|
||||||
|
static constexpr int EcountSize = 16;
|
||||||
|
|
||||||
|
uchar ivec[IvecSize] = { 0 };
|
||||||
|
uint32 num = 0;
|
||||||
|
uchar ecount[EcountSize] = { 0 };
|
||||||
|
};
|
||||||
|
void aesCtrEncrypt(void *data, uint32 len, const void *key, CTRState *state);
|
||||||
|
|
||||||
|
} // namespace MTP
|
||||||
|
|
|
@ -28,6 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
#include <openssl/md5.h>
|
#include <openssl/md5.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
|
#include "zlib.h"
|
||||||
|
|
||||||
#include "mtproto/rsa_public_key.h"
|
#include "mtproto/rsa_public_key.h"
|
||||||
|
|
||||||
|
@ -438,7 +439,7 @@ ConnectionPrivate::ConnectionPrivate(QThread *thread, Connection *owner, Session
|
||||||
moveToThread(thread);
|
moveToThread(thread);
|
||||||
|
|
||||||
if (!dc) {
|
if (!dc) {
|
||||||
QReadLocker lock(mtpDcOptionsMutex());
|
QReadLocker lock(dcOptionsMutex());
|
||||||
const MTP::DcOptions &options(Global::DcOptions());
|
const MTP::DcOptions &options(Global::DcOptions());
|
||||||
if (options.isEmpty()) {
|
if (options.isEmpty()) {
|
||||||
LOG(("MTP Error: connect failed, no DCs"));
|
LOG(("MTP Error: connect failed, no DCs"));
|
||||||
|
@ -1042,7 +1043,7 @@ void ConnectionPrivate::retryByTimer() {
|
||||||
} else if (retryTimeout < 64000) {
|
} else if (retryTimeout < 64000) {
|
||||||
retryTimeout *= 2;
|
retryTimeout *= 2;
|
||||||
}
|
}
|
||||||
if (keyId == mtpAuthKey::RecreateKeyId) {
|
if (keyId == AuthKey::RecreateKeyId) {
|
||||||
if (sessionData->getKey()) {
|
if (sessionData->getKey()) {
|
||||||
unlockKey();
|
unlockKey();
|
||||||
|
|
||||||
|
@ -1083,7 +1084,7 @@ void ConnectionPrivate::socketStart(bool afterConfig) {
|
||||||
string ip[2][2];
|
string ip[2][2];
|
||||||
uint32 port[2][2] = { { 0 } };
|
uint32 port[2][2] = { { 0 } };
|
||||||
{
|
{
|
||||||
QReadLocker lock(mtpDcOptionsMutex());
|
QReadLocker lock(dcOptionsMutex());
|
||||||
const MTP::DcOptions &options(Global::DcOptions());
|
const MTP::DcOptions &options(Global::DcOptions());
|
||||||
int32 shifts[2][2][4] = {
|
int32 shifts[2][2][4] = {
|
||||||
{ // IPv4
|
{ // IPv4
|
||||||
|
@ -1138,8 +1139,8 @@ void ConnectionPrivate::socketStart(bool afterConfig) {
|
||||||
}
|
}
|
||||||
if (noIPv4) DEBUG_LOG(("MTP Info: DC %1 options for IPv4 over HTTP not found, waiting for config").arg(dc));
|
if (noIPv4) DEBUG_LOG(("MTP Info: DC %1 options for IPv4 over HTTP not found, waiting for config").arg(dc));
|
||||||
if (cTryIPv6() && noIPv6) DEBUG_LOG(("MTP Info: DC %1 options for IPv6 over HTTP not found, waiting for config").arg(dc));
|
if (cTryIPv6() && noIPv6) DEBUG_LOG(("MTP Info: DC %1 options for IPv6 over HTTP not found, waiting for config").arg(dc));
|
||||||
connect(mtpConfigLoader(), SIGNAL(loaded()), this, SLOT(onConfigLoaded()));
|
connect(configLoader(), SIGNAL(loaded()), this, SLOT(onConfigLoaded()));
|
||||||
mtpConfigLoader()->load();
|
configLoader()->load();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1180,12 +1181,12 @@ void ConnectionPrivate::restart(bool mayBeBadKey) {
|
||||||
_waitForReceivedTimer.stop();
|
_waitForReceivedTimer.stop();
|
||||||
_waitForConnectedTimer.stop();
|
_waitForConnectedTimer.stop();
|
||||||
|
|
||||||
mtpAuthKeyPtr key(sessionData->getKey());
|
AuthKeyPtr key(sessionData->getKey());
|
||||||
if (key) {
|
if (key) {
|
||||||
if (!sessionData->isCheckedKey()) {
|
if (!sessionData->isCheckedKey()) {
|
||||||
if (mayBeBadKey) {
|
if (mayBeBadKey) {
|
||||||
clearMessages();
|
clearMessages();
|
||||||
keyId = mtpAuthKey::RecreateKeyId;
|
keyId = AuthKey::RecreateKeyId;
|
||||||
// retryTimeout = 1; // no ddos please
|
// retryTimeout = 1; // no ddos please
|
||||||
LOG(("MTP Info: key may be bad and was not checked - but won't be destroyed, no log outs because of bad server right now.."));
|
LOG(("MTP Info: key may be bad and was not checked - but won't be destroyed, no log outs because of bad server right now.."));
|
||||||
}
|
}
|
||||||
|
@ -1351,7 +1352,7 @@ void ConnectionPrivate::handleReceived() {
|
||||||
return restart();
|
return restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
mtpAuthKeyPtr key(sessionData->getKey());
|
AuthKeyPtr key(sessionData->getKey());
|
||||||
if (!key || key->keyId() != keyId) {
|
if (!key || key->keyId() != keyId) {
|
||||||
DEBUG_LOG(("MTP Error: auth_key id for dc %1 changed").arg(dc));
|
DEBUG_LOG(("MTP Error: auth_key id for dc %1 changed").arg(dc));
|
||||||
|
|
||||||
|
@ -1383,7 +1384,7 @@ void ConnectionPrivate::handleReceived() {
|
||||||
const mtpPrime *from(msg), *end;
|
const mtpPrime *from(msg), *end;
|
||||||
MTPint128 msgKey(*(MTPint128*)(encrypted + 2));
|
MTPint128 msgKey(*(MTPint128*)(encrypted + 2));
|
||||||
|
|
||||||
aesDecrypt(encrypted + 6, data, dataBuffer.size(), key, msgKey);
|
aesIgeDecrypt(encrypted + 6, data, dataBuffer.size(), key, msgKey);
|
||||||
|
|
||||||
uint64 serverSalt = *(uint64*)&data[0], session = *(uint64*)&data[2], msgId = *(uint64*)&data[4];
|
uint64 serverSalt = *(uint64*)&data[0], session = *(uint64*)&data[2], msgId = *(uint64*)&data[4];
|
||||||
uint32 seqNo = *(uint32*)&data[6], msgLen = *(uint32*)&data[7];
|
uint32 seqNo = *(uint32*)&data[6], msgLen = *(uint32*)&data[7];
|
||||||
|
@ -2351,7 +2352,7 @@ void ConnectionPrivate::updateAuthKey() {
|
||||||
keyId = newKeyId;
|
keyId = newKeyId;
|
||||||
return; // some other connection is getting key
|
return; // some other connection is getting key
|
||||||
}
|
}
|
||||||
const mtpAuthKeyPtr &key(sessionData->getKey());
|
const AuthKeyPtr &key(sessionData->getKey());
|
||||||
newKeyId = key ? key->keyId() : 0;
|
newKeyId = key ? key->keyId() : 0;
|
||||||
}
|
}
|
||||||
if (keyId != newKeyId) {
|
if (keyId != newKeyId) {
|
||||||
|
@ -2366,7 +2367,7 @@ void ConnectionPrivate::updateAuthKey() {
|
||||||
DEBUG_LOG(("AuthKey Info: No key in updateAuthKey(), will be creating auth_key"));
|
DEBUG_LOG(("AuthKey Info: No key in updateAuthKey(), will be creating auth_key"));
|
||||||
lockKey();
|
lockKey();
|
||||||
|
|
||||||
const mtpAuthKeyPtr &key(sessionData->getKey());
|
const AuthKeyPtr &key(sessionData->getKey());
|
||||||
if (key) {
|
if (key) {
|
||||||
if (keyId != key->keyId()) clearMessages();
|
if (keyId != key->keyId()) clearMessages();
|
||||||
keyId = key->keyId();
|
keyId = key->keyId();
|
||||||
|
@ -2390,7 +2391,7 @@ void ConnectionPrivate::updateAuthKey() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionPrivate::clearMessages() {
|
void ConnectionPrivate::clearMessages() {
|
||||||
if (keyId && keyId != mtpAuthKey::RecreateKeyId && _conn) {
|
if (keyId && keyId != AuthKey::RecreateKeyId && _conn) {
|
||||||
_conn->received().clear();
|
_conn->received().clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2543,7 +2544,7 @@ void ConnectionPrivate::dhParamsAnswered() {
|
||||||
memcpy(authKeyData->aesIV + 8, sha1nn, 20);
|
memcpy(authKeyData->aesIV + 8, sha1nn, 20);
|
||||||
memcpy(authKeyData->aesIV + 28, &authKeyData->new_nonce, 4);
|
memcpy(authKeyData->aesIV + 28, &authKeyData->new_nonce, 4);
|
||||||
|
|
||||||
aesDecrypt(&encDHStr[0], &decBuffer[0], encDHLen, authKeyData->aesKey, authKeyData->aesIV);
|
aesIgeDecrypt(&encDHStr[0], &decBuffer[0], encDHLen, authKeyData->aesKey, authKeyData->aesIV);
|
||||||
|
|
||||||
const mtpPrime *from(&decBuffer[5]), *to(from), *end(from + (encDHBufLen - 5));
|
const mtpPrime *from(&decBuffer[5]), *to(from), *end(from + (encDHBufLen - 5));
|
||||||
MTPServer_DH_inner_data dh_inner(to, end);
|
MTPServer_DH_inner_data dh_inner(to, end);
|
||||||
|
@ -2667,7 +2668,7 @@ void ConnectionPrivate::dhClientParamsSend() {
|
||||||
|
|
||||||
sdhEncString.resize(encFullSize * 4);
|
sdhEncString.resize(encFullSize * 4);
|
||||||
|
|
||||||
aesEncrypt(&encBuffer[0], &sdhEncString[0], encFullSize * sizeof(mtpPrime), authKeyData->aesKey, authKeyData->aesIV);
|
aesIgeEncrypt(&encBuffer[0], &sdhEncString[0], encFullSize * sizeof(mtpPrime), authKeyData->aesKey, authKeyData->aesIV);
|
||||||
|
|
||||||
connect(_conn, SIGNAL(receivedData()), this, SLOT(dhClientParamsAnswered()));
|
connect(_conn, SIGNAL(receivedData()), this, SLOT(dhClientParamsAnswered()));
|
||||||
|
|
||||||
|
@ -2718,7 +2719,7 @@ void ConnectionPrivate::dhClientParamsAnswered() {
|
||||||
uint64 salt1 = authKeyData->new_nonce.l.l, salt2 = authKeyData->server_nonce.l, serverSalt = salt1 ^ salt2;
|
uint64 salt1 = authKeyData->new_nonce.l.l, salt2 = authKeyData->server_nonce.l, serverSalt = salt1 ^ salt2;
|
||||||
sessionData->setSalt(serverSalt);
|
sessionData->setSalt(serverSalt);
|
||||||
|
|
||||||
mtpAuthKeyPtr authKey(new mtpAuthKey());
|
AuthKeyPtr authKey(new AuthKey());
|
||||||
authKey->setKey(authKeyData->auth_key);
|
authKey->setKey(authKeyData->auth_key);
|
||||||
authKey->setDC(bareDcId(dc));
|
authKey->setDC(bareDcId(dc));
|
||||||
|
|
||||||
|
@ -2946,7 +2947,7 @@ bool ConnectionPrivate::sendRequest(mtpRequest &request, bool needAnyResponse, Q
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mtpAuthKeyPtr key(sessionData->getKey());
|
AuthKeyPtr key(sessionData->getKey());
|
||||||
if (!key || key->keyId() != keyId) {
|
if (!key || key->keyId() != keyId) {
|
||||||
DEBUG_LOG(("MTP Error: auth_key id for dc %1 changed").arg(dc));
|
DEBUG_LOG(("MTP Error: auth_key id for dc %1 changed").arg(dc));
|
||||||
|
|
||||||
|
@ -2973,7 +2974,7 @@ bool ConnectionPrivate::sendRequest(mtpRequest &request, bool needAnyResponse, Q
|
||||||
*((uint64*)&result[2]) = keyId;
|
*((uint64*)&result[2]) = keyId;
|
||||||
*((MTPint128*)&result[4]) = msgKey;
|
*((MTPint128*)&result[4]) = msgKey;
|
||||||
|
|
||||||
aesEncrypt(request->constData(), &result[8], fullSize * sizeof(mtpPrime), key, msgKey);
|
aesIgeEncrypt(request->constData(), &result[8], fullSize * sizeof(mtpPrime), key, msgKey);
|
||||||
|
|
||||||
DEBUG_LOG(("MTP Info: sending request, size: %1, num: %2, time: %3").arg(fullSize + 6).arg((*request)[4]).arg((*request)[5]));
|
DEBUG_LOG(("MTP Info: sending request, size: %1, num: %2, time: %3").arg(fullSize + 6).arg((*request)[4]).arg((*request)[5]));
|
||||||
|
|
||||||
|
@ -3031,7 +3032,7 @@ void ConnectionPrivate::stop() {
|
||||||
QWriteLocker lockFinished(&sessionDataMutex);
|
QWriteLocker lockFinished(&sessionDataMutex);
|
||||||
if (sessionData) {
|
if (sessionData) {
|
||||||
if (myKeyLock) {
|
if (myKeyLock) {
|
||||||
sessionData->owner()->notifyKeyCreated(mtpAuthKeyPtr()); // release key lock, let someone else create it
|
sessionData->owner()->notifyKeyCreated(AuthKeyPtr()); // release key lock, let someone else create it
|
||||||
sessionData->keyMutex()->unlock();
|
sessionData->keyMutex()->unlock();
|
||||||
myKeyLock = false;
|
myKeyLock = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
#include "mtproto/connection_abstract.h"
|
||||||
|
|
||||||
|
#include "mtproto/connection_tcp.h"
|
||||||
|
#include "mtproto/connection_http.h"
|
||||||
|
#include "mtproto/connection_auto.h"
|
||||||
|
|
||||||
|
namespace MTP {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
MTPResPQ AbstractConnection::readPQFakeReply(const mtpBuffer &buffer) {
|
||||||
|
const mtpPrime *answer(buffer.constData());
|
||||||
|
uint32 len = buffer.size();
|
||||||
|
if (len < 5) {
|
||||||
|
LOG(("Fake PQ Error: bad request answer, len = %1").arg(len * sizeof(mtpPrime)));
|
||||||
|
DEBUG_LOG(("Fake PQ Error: answer bytes %1").arg(Logs::mb(answer, len * sizeof(mtpPrime)).str()));
|
||||||
|
throw Exception("bad pq reply");
|
||||||
|
}
|
||||||
|
if (answer[0] != 0 || answer[1] != 0 || (((uint32)answer[2]) & 0x03) != 1/* || (unixtime() - answer[3] > 300) || (answer[3] - unixtime() > 60)*/) { // didnt sync time yet
|
||||||
|
LOG(("Fake PQ Error: bad request answer start (%1 %2 %3)").arg(answer[0]).arg(answer[1]).arg(answer[2]));
|
||||||
|
DEBUG_LOG(("Fake PQ Error: answer bytes %1").arg(Logs::mb(answer, len * sizeof(mtpPrime)).str()));
|
||||||
|
throw Exception("bad pq reply");
|
||||||
|
}
|
||||||
|
uint32 answerLen = (uint32)answer[4];
|
||||||
|
if (answerLen != (len - 5) * sizeof(mtpPrime)) {
|
||||||
|
LOG(("Fake PQ Error: bad request answer %1 <> %2").arg(answerLen).arg((len - 5) * sizeof(mtpPrime)));
|
||||||
|
DEBUG_LOG(("Fake PQ Error: answer bytes %1").arg(Logs::mb(answer, len * sizeof(mtpPrime)).str()));
|
||||||
|
throw Exception("bad pq reply");
|
||||||
|
}
|
||||||
|
const mtpPrime *from(answer + 5), *end(from + len - 5);
|
||||||
|
MTPResPQ response;
|
||||||
|
response.read(from, end);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractConnection *AbstractConnection::create(QThread *thread) {
|
||||||
|
if (cConnectionType() == dbictHttpProxy) {
|
||||||
|
return new HTTPConnection(thread);
|
||||||
|
} else if (cConnectionType() == dbictTcpProxy) {
|
||||||
|
return new TCPConnection(thread);
|
||||||
|
}
|
||||||
|
return new AutoConnection(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace MTP
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "mtproto/core_types.h"
|
||||||
|
|
||||||
|
namespace MTP {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class AbstractConnection : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
AbstractConnection(QThread *thread) : _sentEncrypted(false) {
|
||||||
|
moveToThread(thread);
|
||||||
|
}
|
||||||
|
AbstractConnection(const AbstractConnection &other) = delete;
|
||||||
|
AbstractConnection &operator=(const AbstractConnection &other) = delete;
|
||||||
|
virtual ~AbstractConnection() = 0 {
|
||||||
|
}
|
||||||
|
|
||||||
|
// virtual constructor
|
||||||
|
static AbstractConnection *create(QThread *thread);
|
||||||
|
|
||||||
|
void setSentEncrypted() {
|
||||||
|
_sentEncrypted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void sendData(mtpBuffer &buffer) = 0; // has size + 3, buffer[0] = len, buffer[1] = packetnum, buffer[last] = crc32
|
||||||
|
virtual void disconnectFromServer() = 0;
|
||||||
|
virtual void connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) = 0;
|
||||||
|
virtual void connectHttp(const QString &addr, int32 port, MTPDdcOption::Flags flags) = 0;
|
||||||
|
virtual bool isConnected() const = 0;
|
||||||
|
virtual bool usingHttpWait() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
virtual bool needHttpWait() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int32 debugState() const = 0;
|
||||||
|
|
||||||
|
virtual QString transport() const = 0;
|
||||||
|
|
||||||
|
typedef QList<mtpBuffer> BuffersQueue;
|
||||||
|
BuffersQueue &received() {
|
||||||
|
return receivedQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void receivedData();
|
||||||
|
void receivedSome(); // to stop restart timer
|
||||||
|
|
||||||
|
void error(bool mayBeBadKey = false);
|
||||||
|
|
||||||
|
void connected();
|
||||||
|
void disconnected();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
BuffersQueue receivedQueue; // list of received packets, not processed yet
|
||||||
|
bool _sentEncrypted;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace MTP
|
|
@ -0,0 +1,344 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
#include "mtproto/connection_auto.h"
|
||||||
|
|
||||||
|
#include "mtproto/connection_http.h"
|
||||||
|
|
||||||
|
namespace MTP {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
AutoConnection::AutoConnection(QThread *thread) : AbstractTCPConnection(thread)
|
||||||
|
, status(WaitingBoth)
|
||||||
|
, tcpNonce(rand_value<MTPint128>())
|
||||||
|
, httpNonce(rand_value<MTPint128>())
|
||||||
|
, _flagsTcp(0)
|
||||||
|
, _flagsHttp(0)
|
||||||
|
, _tcpTimeout(MTPMinReceiveDelay) {
|
||||||
|
manager.moveToThread(thread);
|
||||||
|
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
|
||||||
|
manager.setProxy(QNetworkProxy(QNetworkProxy::DefaultProxy));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
httpStartTimer.moveToThread(thread);
|
||||||
|
httpStartTimer.setSingleShot(true);
|
||||||
|
connect(&httpStartTimer, SIGNAL(timeout()), this, SLOT(onHttpStart()));
|
||||||
|
|
||||||
|
tcpTimeoutTimer.moveToThread(thread);
|
||||||
|
tcpTimeoutTimer.setSingleShot(true);
|
||||||
|
connect(&tcpTimeoutTimer, SIGNAL(timeout()), this, SLOT(onTcpTimeoutTimer()));
|
||||||
|
|
||||||
|
sock.moveToThread(thread);
|
||||||
|
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
|
||||||
|
sock.setProxy(QNetworkProxy(QNetworkProxy::NoProxy));
|
||||||
|
#endif
|
||||||
|
connect(&sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
|
||||||
|
connect(&sock, SIGNAL(connected()), this, SLOT(onSocketConnected()));
|
||||||
|
connect(&sock, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoConnection::onHttpStart() {
|
||||||
|
if (status == HttpReady) {
|
||||||
|
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by timer").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
||||||
|
status = UsingHttp;
|
||||||
|
sock.disconnectFromHost();
|
||||||
|
emit connected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoConnection::onSocketConnected() {
|
||||||
|
if (status == HttpReady || status == WaitingBoth || status == WaitingTcp) {
|
||||||
|
mtpBuffer buffer(preparePQFake(tcpNonce));
|
||||||
|
|
||||||
|
DEBUG_LOG(("Connection Info: sending fake req_pq through TCP/%1 transport").arg((_flagsTcp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
||||||
|
|
||||||
|
if (_tcpTimeout < 0) _tcpTimeout = -_tcpTimeout;
|
||||||
|
tcpTimeoutTimer.start(_tcpTimeout);
|
||||||
|
|
||||||
|
tcpSend(buffer);
|
||||||
|
} else if (status == WaitingHttp || status == UsingHttp) {
|
||||||
|
sock.disconnectFromHost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoConnection::onTcpTimeoutTimer() {
|
||||||
|
if (status == HttpReady || status == WaitingBoth || status == WaitingTcp) {
|
||||||
|
if (_tcpTimeout < MTPMaxReceiveDelay) _tcpTimeout *= 2;
|
||||||
|
_tcpTimeout = -_tcpTimeout;
|
||||||
|
|
||||||
|
QAbstractSocket::SocketState state = sock.state();
|
||||||
|
if (state == QAbstractSocket::ConnectedState || state == QAbstractSocket::ConnectingState || state == QAbstractSocket::HostLookupState) {
|
||||||
|
sock.disconnectFromHost();
|
||||||
|
} else if (state != QAbstractSocket::ClosingState) {
|
||||||
|
sock.connectToHost(QHostAddress(_addrTcp), _portTcp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoConnection::onSocketDisconnected() {
|
||||||
|
if (_tcpTimeout < 0) {
|
||||||
|
_tcpTimeout = -_tcpTimeout;
|
||||||
|
if (status == HttpReady || status == WaitingBoth || status == WaitingTcp) {
|
||||||
|
sock.connectToHost(QHostAddress(_addrTcp), _portTcp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (status == WaitingBoth) {
|
||||||
|
status = WaitingHttp;
|
||||||
|
} else if (status == WaitingTcp || status == UsingTcp) {
|
||||||
|
emit disconnected();
|
||||||
|
} else if (status == HttpReady) {
|
||||||
|
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by socket disconnect").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
||||||
|
status = UsingHttp;
|
||||||
|
emit connected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoConnection::sendData(mtpBuffer &buffer) {
|
||||||
|
if (status == FinishedWork) return;
|
||||||
|
|
||||||
|
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();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == UsingTcp) {
|
||||||
|
tcpSend(buffer);
|
||||||
|
} else {
|
||||||
|
httpSend(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoConnection::httpSend(mtpBuffer &buffer) {
|
||||||
|
int32 requestSize = (buffer.size() - 3) * sizeof(mtpPrime);
|
||||||
|
|
||||||
|
QNetworkRequest request(address);
|
||||||
|
request.setHeader(QNetworkRequest::ContentLengthHeader, QVariant(requestSize));
|
||||||
|
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(qsl("application/x-www-form-urlencoded")));
|
||||||
|
|
||||||
|
TCP_LOG(("HTTP Info: sending %1 len request").arg(requestSize));
|
||||||
|
requests.insert(manager.post(request, QByteArray((const char*)(&buffer[2]), requestSize)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoConnection::disconnectFromServer() {
|
||||||
|
if (status == FinishedWork) return;
|
||||||
|
status = FinishedWork;
|
||||||
|
|
||||||
|
Requests copy = requests;
|
||||||
|
requests.clear();
|
||||||
|
for (Requests::const_iterator i = copy.cbegin(), e = copy.cend(); i != e; ++i) {
|
||||||
|
(*i)->abort();
|
||||||
|
(*i)->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
||||||
|
|
||||||
|
address = QUrl();
|
||||||
|
|
||||||
|
disconnect(&sock, SIGNAL(readyRead()), 0, 0);
|
||||||
|
sock.close();
|
||||||
|
|
||||||
|
httpStartTimer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoConnection::connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) {
|
||||||
|
_addrTcp = addr;
|
||||||
|
_portTcp = port;
|
||||||
|
_flagsTcp = flags;
|
||||||
|
|
||||||
|
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
|
||||||
|
sock.connectToHost(QHostAddress(_addrTcp), _portTcp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoConnection::connectHttp(const QString &addr, int32 port, MTPDdcOption::Flags flags) {
|
||||||
|
address = QUrl(((flags & MTPDdcOption::Flag::f_ipv6) ? qsl("http://[%1]:%2/api") : qsl("http://%1:%2/api")).arg(addr).arg(80));//not p - always 80 port for http transport
|
||||||
|
TCP_LOG(("HTTP Info: address is %1").arg(address.toDisplayString()));
|
||||||
|
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
||||||
|
|
||||||
|
_addrHttp = addr;
|
||||||
|
_portHttp = port;
|
||||||
|
_flagsHttp = flags;
|
||||||
|
|
||||||
|
mtpBuffer buffer(preparePQFake(httpNonce));
|
||||||
|
|
||||||
|
DEBUG_LOG(("Connection Info: sending fake req_pq through HTTP/%1 transport").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
||||||
|
|
||||||
|
httpSend(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AutoConnection::isConnected() const {
|
||||||
|
return (status == UsingTcp) || (status == UsingHttp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoConnection::requestFinished(QNetworkReply *reply) {
|
||||||
|
if (status == FinishedWork) return;
|
||||||
|
|
||||||
|
reply->deleteLater();
|
||||||
|
if (reply->error() == QNetworkReply::NoError) {
|
||||||
|
requests.remove(reply);
|
||||||
|
|
||||||
|
mtpBuffer data = HTTPConnection::handleResponse(reply);
|
||||||
|
if (data.size() == 1) {
|
||||||
|
if (status == WaitingBoth) {
|
||||||
|
status = WaitingTcp;
|
||||||
|
} else {
|
||||||
|
emit error();
|
||||||
|
}
|
||||||
|
} else if (!data.isEmpty()) {
|
||||||
|
if (status == UsingHttp) {
|
||||||
|
receivedQueue.push_back(data);
|
||||||
|
emit receivedData();
|
||||||
|
} else if (status == WaitingBoth || status == WaitingHttp) {
|
||||||
|
try {
|
||||||
|
MTPResPQ res_pq = readPQFakeReply(data);
|
||||||
|
const MTPDresPQ &res_pq_data(res_pq.c_resPQ());
|
||||||
|
if (res_pq_data.vnonce == httpNonce) {
|
||||||
|
if (status == WaitingBoth) {
|
||||||
|
status = HttpReady;
|
||||||
|
httpStartTimer.start(MTPTcpConnectionWaitTimeout);
|
||||||
|
} else {
|
||||||
|
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by pq-response, awaited").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
||||||
|
status = UsingHttp;
|
||||||
|
sock.disconnectFromHost();
|
||||||
|
emit connected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception &e) {
|
||||||
|
DEBUG_LOG(("Connection Error: exception in parsing HTTP fake pq-responce, %1").arg(e.what()));
|
||||||
|
if (status == WaitingBoth) {
|
||||||
|
status = WaitingTcp;
|
||||||
|
} else {
|
||||||
|
emit error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (status == UsingTcp) {
|
||||||
|
DEBUG_LOG(("Connection Info: already using tcp, ignoring http response"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!requests.remove(reply)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mayBeBadKey = HTTPConnection::handleError(reply) && _sentEncrypted;
|
||||||
|
if (status == WaitingBoth) {
|
||||||
|
status = WaitingTcp;
|
||||||
|
} else if (status == WaitingHttp || status == UsingHttp) {
|
||||||
|
emit error(mayBeBadKey);
|
||||||
|
} else {
|
||||||
|
LOG(("Strange Http Error: status %1").arg(status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoConnection::socketPacket(const char *packet, uint32 length) {
|
||||||
|
if (status == FinishedWork) return;
|
||||||
|
|
||||||
|
mtpBuffer data = TCPConnection::handleResponse(packet, length);
|
||||||
|
if (data.size() == 1) {
|
||||||
|
if (status == WaitingBoth) {
|
||||||
|
status = WaitingHttp;
|
||||||
|
sock.disconnectFromHost();
|
||||||
|
} else if (status == HttpReady) {
|
||||||
|
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by bad tcp response, ready").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
||||||
|
status = UsingHttp;
|
||||||
|
sock.disconnectFromHost();
|
||||||
|
emit connected();
|
||||||
|
} else if (status == WaitingTcp || status == UsingTcp) {
|
||||||
|
bool mayBeBadKey = (data[0] == -410) && _sentEncrypted;
|
||||||
|
emit error(mayBeBadKey);
|
||||||
|
} else {
|
||||||
|
LOG(("Strange Tcp Error; status %1").arg(status));
|
||||||
|
}
|
||||||
|
} else if (status == UsingTcp) {
|
||||||
|
receivedQueue.push_back(data);
|
||||||
|
emit receivedData();
|
||||||
|
} else if (status == WaitingBoth || status == WaitingTcp || status == HttpReady) {
|
||||||
|
tcpTimeoutTimer.stop();
|
||||||
|
try {
|
||||||
|
MTPResPQ res_pq = readPQFakeReply(data);
|
||||||
|
const MTPDresPQ &res_pq_data(res_pq.c_resPQ());
|
||||||
|
if (res_pq_data.vnonce == tcpNonce) {
|
||||||
|
DEBUG_LOG(("Connection Info: TCP/%1-transport chosen by pq-response").arg((_flagsTcp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
||||||
|
status = UsingTcp;
|
||||||
|
emit connected();
|
||||||
|
}
|
||||||
|
} catch (Exception &e) {
|
||||||
|
DEBUG_LOG(("Connection Error: exception in parsing TCP fake pq-responce, %1").arg(e.what()));
|
||||||
|
if (status == WaitingBoth) {
|
||||||
|
status = WaitingHttp;
|
||||||
|
sock.disconnectFromHost();
|
||||||
|
} else if (status == HttpReady) {
|
||||||
|
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by bad tcp response, awaited").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
||||||
|
status = UsingHttp;
|
||||||
|
sock.disconnectFromHost();
|
||||||
|
emit connected();
|
||||||
|
} else {
|
||||||
|
emit error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AutoConnection::usingHttpWait() {
|
||||||
|
return (status == UsingHttp);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AutoConnection::needHttpWait() {
|
||||||
|
return (status == UsingHttp) ? requests.isEmpty() : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 AutoConnection::debugState() const {
|
||||||
|
return (status == UsingHttp) ? -1 : (UsingTcp ? sock.state() : -777);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString AutoConnection::transport() const {
|
||||||
|
if (status == UsingTcp) {
|
||||||
|
return qsl("TCP");
|
||||||
|
} else if (status == UsingHttp) {
|
||||||
|
return qsl("HTTP");
|
||||||
|
} else {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoConnection::socketError(QAbstractSocket::SocketError e) {
|
||||||
|
if (status == FinishedWork) return;
|
||||||
|
|
||||||
|
TCPConnection::handleError(e, sock);
|
||||||
|
if (status == WaitingBoth) {
|
||||||
|
status = WaitingHttp;
|
||||||
|
} else if (status == HttpReady) {
|
||||||
|
DEBUG_LOG(("Connection Info: HTTP/%1-transport chosen by tcp error, ready").arg((_flagsHttp & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
||||||
|
status = UsingHttp;
|
||||||
|
emit connected();
|
||||||
|
} else if (status == WaitingTcp || status == UsingTcp) {
|
||||||
|
emit error();
|
||||||
|
} else {
|
||||||
|
LOG(("Strange Tcp Error: status %1").arg(status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace MTP
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "mtproto/core_types.h"
|
||||||
|
#include "mtproto/connection_tcp.h"
|
||||||
|
|
||||||
|
namespace MTP {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class AutoConnection : public AbstractTCPConnection {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
AutoConnection(QThread *thread);
|
||||||
|
|
||||||
|
void sendData(mtpBuffer &buffer) override;
|
||||||
|
void disconnectFromServer() override;
|
||||||
|
void connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override;
|
||||||
|
void connectHttp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override;
|
||||||
|
bool isConnected() const override;
|
||||||
|
bool usingHttpWait() override;
|
||||||
|
bool needHttpWait() override;
|
||||||
|
|
||||||
|
int32 debugState() const override;
|
||||||
|
|
||||||
|
QString transport() const override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void socketError(QAbstractSocket::SocketError e);
|
||||||
|
void requestFinished(QNetworkReply *reply);
|
||||||
|
|
||||||
|
void onSocketConnected();
|
||||||
|
void onSocketDisconnected();
|
||||||
|
void onHttpStart();
|
||||||
|
|
||||||
|
void onTcpTimeoutTimer();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void socketPacket(const char *packet, uint32 length) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void httpSend(mtpBuffer &buffer);
|
||||||
|
enum Status {
|
||||||
|
WaitingBoth = 0,
|
||||||
|
WaitingHttp,
|
||||||
|
WaitingTcp,
|
||||||
|
HttpReady,
|
||||||
|
UsingHttp,
|
||||||
|
UsingTcp,
|
||||||
|
FinishedWork
|
||||||
|
};
|
||||||
|
Status status;
|
||||||
|
MTPint128 tcpNonce, httpNonce;
|
||||||
|
QTimer httpStartTimer;
|
||||||
|
|
||||||
|
QNetworkAccessManager manager;
|
||||||
|
QUrl address;
|
||||||
|
|
||||||
|
typedef QSet<QNetworkReply*> Requests;
|
||||||
|
Requests requests;
|
||||||
|
|
||||||
|
QString _addrTcp, _addrHttp;
|
||||||
|
int32 _portTcp, _portHttp;
|
||||||
|
MTPDdcOption::Flags _flagsTcp, _flagsHttp;
|
||||||
|
int32 _tcpTimeout;
|
||||||
|
QTimer tcpTimeoutTimer;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace MTP
|
|
@ -0,0 +1,218 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
#include "mtproto/connection_http.h"
|
||||||
|
|
||||||
|
namespace MTP {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
mtpBuffer HTTPConnection::handleResponse(QNetworkReply *reply) {
|
||||||
|
QByteArray response = reply->readAll();
|
||||||
|
TCP_LOG(("HTTP Info: read %1 bytes").arg(response.size()));
|
||||||
|
|
||||||
|
if (response.isEmpty()) return mtpBuffer();
|
||||||
|
|
||||||
|
if (response.size() & 0x03 || response.size() < 8) {
|
||||||
|
LOG(("HTTP Error: bad response size %1").arg(response.size()));
|
||||||
|
return mtpBuffer(1, -500);
|
||||||
|
}
|
||||||
|
|
||||||
|
mtpBuffer data(response.size() >> 2);
|
||||||
|
memcpy(data.data(), response.constData(), response.size());
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HTTPConnection::handleError(QNetworkReply *reply) { // returnes "maybe bad key"
|
||||||
|
bool mayBeBadKey = false;
|
||||||
|
|
||||||
|
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||||
|
if (statusCode.isValid()) {
|
||||||
|
int status = statusCode.toInt();
|
||||||
|
mayBeBadKey = (status == 410);
|
||||||
|
if (status == 429) {
|
||||||
|
LOG(("Protocol Error: 429 flood code returned!"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (reply->error()) {
|
||||||
|
case QNetworkReply::ConnectionRefusedError: LOG(("HTTP Error: connection refused - %1").arg(reply->errorString())); break;
|
||||||
|
case QNetworkReply::RemoteHostClosedError: LOG(("HTTP Error: remote host closed - %1").arg(reply->errorString())); break;
|
||||||
|
case QNetworkReply::HostNotFoundError: LOG(("HTTP Error: host not found - %2").arg(reply->error()).arg(reply->errorString())); break;
|
||||||
|
case QNetworkReply::TimeoutError: LOG(("HTTP Error: timeout - %2").arg(reply->error()).arg(reply->errorString())); break;
|
||||||
|
case QNetworkReply::OperationCanceledError: LOG(("HTTP Error: cancelled - %2").arg(reply->error()).arg(reply->errorString())); break;
|
||||||
|
case QNetworkReply::SslHandshakeFailedError:
|
||||||
|
case QNetworkReply::TemporaryNetworkFailureError:
|
||||||
|
case QNetworkReply::NetworkSessionFailedError:
|
||||||
|
case QNetworkReply::BackgroundRequestNotAllowedError:
|
||||||
|
case QNetworkReply::UnknownNetworkError: LOG(("HTTP Error: network error %1 - %2").arg(reply->error()).arg(reply->errorString())); break;
|
||||||
|
|
||||||
|
// proxy errors (101-199):
|
||||||
|
case QNetworkReply::ProxyConnectionRefusedError:
|
||||||
|
case QNetworkReply::ProxyConnectionClosedError:
|
||||||
|
case QNetworkReply::ProxyNotFoundError:
|
||||||
|
case QNetworkReply::ProxyTimeoutError:
|
||||||
|
case QNetworkReply::ProxyAuthenticationRequiredError:
|
||||||
|
case QNetworkReply::UnknownProxyError:LOG(("HTTP Error: proxy error %1 - %2").arg(reply->error()).arg(reply->errorString())); break;
|
||||||
|
|
||||||
|
// content errors (201-299):
|
||||||
|
case QNetworkReply::ContentAccessDenied:
|
||||||
|
case QNetworkReply::ContentOperationNotPermittedError:
|
||||||
|
case QNetworkReply::ContentNotFoundError:
|
||||||
|
case QNetworkReply::AuthenticationRequiredError:
|
||||||
|
case QNetworkReply::ContentReSendError:
|
||||||
|
case QNetworkReply::UnknownContentError: LOG(("HTTP Error: content error %1 - %2").arg(reply->error()).arg(reply->errorString())); break;
|
||||||
|
|
||||||
|
// protocol errors
|
||||||
|
case QNetworkReply::ProtocolUnknownError:
|
||||||
|
case QNetworkReply::ProtocolInvalidOperationError:
|
||||||
|
case QNetworkReply::ProtocolFailure: LOG(("HTTP Error: protocol error %1 - %2").arg(reply->error()).arg(reply->errorString())); break;
|
||||||
|
};
|
||||||
|
TCP_LOG(("HTTP Error %1, restarting! - %2").arg(reply->error()).arg(reply->errorString()));
|
||||||
|
|
||||||
|
return mayBeBadKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
HTTPConnection::HTTPConnection(QThread *thread) : AbstractConnection(thread)
|
||||||
|
, status(WaitingHttp)
|
||||||
|
, httpNonce(rand_value<MTPint128>())
|
||||||
|
, _flags(0) {
|
||||||
|
manager.moveToThread(thread);
|
||||||
|
App::setProxySettings(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPConnection::sendData(mtpBuffer &buffer) {
|
||||||
|
if (status == FinishedWork) return;
|
||||||
|
|
||||||
|
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();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 requestSize = (buffer.size() - 3) * sizeof(mtpPrime);
|
||||||
|
|
||||||
|
QNetworkRequest request(address);
|
||||||
|
request.setHeader(QNetworkRequest::ContentLengthHeader, QVariant(requestSize));
|
||||||
|
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(qsl("application/x-www-form-urlencoded")));
|
||||||
|
|
||||||
|
TCP_LOG(("HTTP Info: sending %1 len request %2").arg(requestSize).arg(Logs::mb(&buffer[2], requestSize).str()));
|
||||||
|
requests.insert(manager.post(request, QByteArray((const char*)(&buffer[2]), requestSize)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPConnection::disconnectFromServer() {
|
||||||
|
if (status == FinishedWork) return;
|
||||||
|
status = FinishedWork;
|
||||||
|
|
||||||
|
Requests copy = requests;
|
||||||
|
requests.clear();
|
||||||
|
for (Requests::const_iterator i = copy.cbegin(), e = copy.cend(); i != e; ++i) {
|
||||||
|
(*i)->abort();
|
||||||
|
(*i)->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
||||||
|
|
||||||
|
address = QUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPConnection::connectHttp(const QString &addr, int32 p, MTPDdcOption::Flags flags) {
|
||||||
|
address = QUrl(((flags & MTPDdcOption::Flag::f_ipv6) ? qsl("http://[%1]:%2/api") : qsl("http://%1:%2/api")).arg(addr).arg(80));//not p - always 80 port for http transport
|
||||||
|
TCP_LOG(("HTTP Info: address is %1").arg(address.toDisplayString()));
|
||||||
|
connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
|
||||||
|
|
||||||
|
_flags = flags;
|
||||||
|
|
||||||
|
mtpBuffer buffer(preparePQFake(httpNonce));
|
||||||
|
|
||||||
|
DEBUG_LOG(("Connection Info: sending fake req_pq through HTTP/%1 transport").arg((flags & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
||||||
|
|
||||||
|
sendData(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HTTPConnection::isConnected() const {
|
||||||
|
return (status == UsingHttp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPConnection::requestFinished(QNetworkReply *reply) {
|
||||||
|
if (status == FinishedWork) return;
|
||||||
|
|
||||||
|
reply->deleteLater();
|
||||||
|
if (reply->error() == QNetworkReply::NoError) {
|
||||||
|
requests.remove(reply);
|
||||||
|
|
||||||
|
mtpBuffer data = handleResponse(reply);
|
||||||
|
if (data.size() == 1) {
|
||||||
|
emit error();
|
||||||
|
} else if (!data.isEmpty()) {
|
||||||
|
if (status == UsingHttp) {
|
||||||
|
receivedQueue.push_back(data);
|
||||||
|
emit receivedData();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
MTPResPQ res_pq = readPQFakeReply(data);
|
||||||
|
const MTPDresPQ &res_pq_data(res_pq.c_resPQ());
|
||||||
|
if (res_pq_data.vnonce == httpNonce) {
|
||||||
|
DEBUG_LOG(("Connection Info: HTTP/%1-transport connected by pq-response").arg((_flags & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
||||||
|
status = UsingHttp;
|
||||||
|
emit connected();
|
||||||
|
}
|
||||||
|
} catch (Exception &e) {
|
||||||
|
DEBUG_LOG(("Connection Error: exception in parsing HTTP fake pq-responce, %1").arg(e.what()));
|
||||||
|
emit error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!requests.remove(reply)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mayBeBadKey = handleError(reply) && _sentEncrypted;
|
||||||
|
|
||||||
|
emit error(mayBeBadKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HTTPConnection::usingHttpWait() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HTTPConnection::needHttpWait() {
|
||||||
|
return requests.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 HTTPConnection::debugState() const {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString HTTPConnection::transport() const {
|
||||||
|
if (status == UsingHttp) {
|
||||||
|
return qsl("HTTP");
|
||||||
|
} else {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace MTP
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "mtproto/core_types.h"
|
||||||
|
#include "mtproto/connection_abstract.h"
|
||||||
|
|
||||||
|
namespace MTP {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class HTTPConnection : public AbstractConnection {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
HTTPConnection(QThread *thread);
|
||||||
|
|
||||||
|
void sendData(mtpBuffer &buffer) override;
|
||||||
|
void disconnectFromServer() override;
|
||||||
|
void connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override { // not supported
|
||||||
|
}
|
||||||
|
void connectHttp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override;
|
||||||
|
bool isConnected() const override;
|
||||||
|
bool usingHttpWait() override;
|
||||||
|
bool needHttpWait() override;
|
||||||
|
|
||||||
|
int32 debugState() const override;
|
||||||
|
|
||||||
|
QString transport() const override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void requestFinished(QNetworkReply *reply);
|
||||||
|
|
||||||
|
static mtpBuffer handleResponse(QNetworkReply *reply);
|
||||||
|
static bool handleError(QNetworkReply *reply); // returnes "maybe bad key"
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum Status {
|
||||||
|
WaitingHttp = 0,
|
||||||
|
UsingHttp,
|
||||||
|
FinishedWork
|
||||||
|
};
|
||||||
|
Status status;
|
||||||
|
MTPint128 httpNonce;
|
||||||
|
MTPDdcOption::Flags _flags;
|
||||||
|
|
||||||
|
QNetworkAccessManager manager;
|
||||||
|
QUrl address;
|
||||||
|
|
||||||
|
typedef QSet<QNetworkReply*> Requests;
|
||||||
|
Requests requests;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace MTP
|
|
@ -0,0 +1,395 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
#include "mtproto/connection_tcp.h"
|
||||||
|
|
||||||
|
#include <openssl/aes.h>
|
||||||
|
|
||||||
|
namespace MTP {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
uint32 tcpPacketSize(const char *packet) { // must have at least 4 bytes readable
|
||||||
|
uint32 result = (packet[0] > 0) ? packet[0] : 0;
|
||||||
|
if (result == 0x7f) {
|
||||||
|
const uchar *bytes = reinterpret_cast<const uchar*>(packet);
|
||||||
|
result = (((uint32(bytes[3]) << 8) | uint32(bytes[2])) << 8) | uint32(bytes[1]);
|
||||||
|
return (result << 2) + 4;
|
||||||
|
}
|
||||||
|
return (result << 2) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
AbstractTCPConnection::AbstractTCPConnection(QThread *thread) : AbstractConnection(thread)
|
||||||
|
, packetNum(0)
|
||||||
|
, packetRead(0)
|
||||||
|
, packetLeft(0)
|
||||||
|
, readingToShort(true)
|
||||||
|
, currentPos((char*)shortBuffer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractTCPConnection::socketRead() {
|
||||||
|
if (sock.state() != QAbstractSocket::ConnectedState) {
|
||||||
|
LOG(("MTP error: socket not connected in socketRead(), state: %1").arg(sock.state()));
|
||||||
|
emit error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
uint32 toRead = packetLeft ? packetLeft : (readingToShort ? (MTPShortBufferSize * sizeof(mtpPrime) - packetRead) : 4);
|
||||||
|
if (readingToShort) {
|
||||||
|
if (currentPos + toRead > ((char*)shortBuffer) + MTPShortBufferSize * sizeof(mtpPrime)) {
|
||||||
|
longBuffer.resize(((packetRead + toRead) >> 2) + 1);
|
||||||
|
memcpy(&longBuffer[0], shortBuffer, packetRead);
|
||||||
|
currentPos = ((char*)&longBuffer[0]) + packetRead;
|
||||||
|
readingToShort = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (longBuffer.size() * sizeof(mtpPrime) < packetRead + toRead) {
|
||||||
|
longBuffer.resize(((packetRead + toRead) >> 2) + 1);
|
||||||
|
currentPos = ((char*)&longBuffer[0]) + packetRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int32 bytes = (int32)sock.read(currentPos, toRead);
|
||||||
|
if (bytes > 0) {
|
||||||
|
aesCtrEncrypt(currentPos, bytes, _receiveKey, &_receiveState);
|
||||||
|
TCP_LOG(("TCP Info: read %1 bytes").arg(bytes));
|
||||||
|
|
||||||
|
packetRead += bytes;
|
||||||
|
currentPos += bytes;
|
||||||
|
if (packetLeft) {
|
||||||
|
packetLeft -= bytes;
|
||||||
|
if (!packetLeft) {
|
||||||
|
socketPacket(currentPos - packetRead, packetRead);
|
||||||
|
currentPos = (char*)shortBuffer;
|
||||||
|
packetRead = packetLeft = 0;
|
||||||
|
readingToShort = true;
|
||||||
|
longBuffer.clear();
|
||||||
|
} else {
|
||||||
|
TCP_LOG(("TCP Info: not enough %1 for packet! read %2").arg(packetLeft).arg(packetRead));
|
||||||
|
emit receivedSome();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bool move = false;
|
||||||
|
while (packetRead >= 4) {
|
||||||
|
uint32 packetSize = tcpPacketSize(currentPos - packetRead);
|
||||||
|
if (packetSize < 5 || packetSize > MTPPacketSizeMax) {
|
||||||
|
LOG(("TCP Error: packet size = %1").arg(packetSize));
|
||||||
|
emit error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (packetRead >= packetSize) {
|
||||||
|
socketPacket(currentPos - packetRead, packetSize);
|
||||||
|
packetRead -= packetSize;
|
||||||
|
packetLeft = 0;
|
||||||
|
move = true;
|
||||||
|
} else {
|
||||||
|
packetLeft = packetSize - packetRead;
|
||||||
|
TCP_LOG(("TCP Info: not enough %1 for packet! size %2 read %3").arg(packetLeft).arg(packetSize).arg(packetRead));
|
||||||
|
emit receivedSome();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (move) {
|
||||||
|
if (!packetRead) {
|
||||||
|
currentPos = (char*)shortBuffer;
|
||||||
|
readingToShort = true;
|
||||||
|
longBuffer.clear();
|
||||||
|
} else if (!readingToShort && packetRead < MTPShortBufferSize * sizeof(mtpPrime)) {
|
||||||
|
memcpy(shortBuffer, currentPos - packetRead, packetRead);
|
||||||
|
currentPos = (char*)shortBuffer + packetRead;
|
||||||
|
readingToShort = true;
|
||||||
|
longBuffer.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (bytes < 0) {
|
||||||
|
LOG(("TCP Error: socket read return -1"));
|
||||||
|
emit error();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
TCP_LOG(("TCP Info: no bytes read, but bytes available was true.."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (sock.state() == QAbstractSocket::ConnectedState && sock.bytesAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
mtpBuffer AbstractTCPConnection::handleResponse(const char *packet, uint32 length) {
|
||||||
|
if (length < 5 || length > MTPPacketSizeMax) {
|
||||||
|
LOG(("TCP Error: bad packet size %1").arg(length));
|
||||||
|
return mtpBuffer(1, -500);
|
||||||
|
}
|
||||||
|
int32 size = packet[0], len = length - 1;
|
||||||
|
if (size == 0x7f) {
|
||||||
|
const uchar *bytes = reinterpret_cast<const uchar*>(packet);
|
||||||
|
size = (((uint32(bytes[3]) << 8) | uint32(bytes[2])) << 8) | uint32(bytes[1]);
|
||||||
|
len -= 3;
|
||||||
|
}
|
||||||
|
if (size * int32(sizeof(mtpPrime)) != len) {
|
||||||
|
LOG(("TCP Error: bad packet header"));
|
||||||
|
TCP_LOG(("TCP Error: bad packet header, packet: %1").arg(Logs::mb(packet, length).str()));
|
||||||
|
return mtpBuffer(1, -500);
|
||||||
|
}
|
||||||
|
const mtpPrime *packetdata = reinterpret_cast<const mtpPrime*>(packet + (length - len));
|
||||||
|
TCP_LOG(("TCP Info: packet received, size = %1").arg(size * sizeof(mtpPrime)));
|
||||||
|
if (size == 1) {
|
||||||
|
if (*packetdata == -429) {
|
||||||
|
LOG(("Protocol Error: -429 flood code returned!"));
|
||||||
|
} else {
|
||||||
|
LOG(("TCP Error: error packet received, code = %1").arg(*packetdata));
|
||||||
|
}
|
||||||
|
return mtpBuffer(1, *packetdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
mtpBuffer data(size);
|
||||||
|
memcpy(data.data(), packetdata, size * sizeof(mtpPrime));
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractTCPConnection::handleError(QAbstractSocket::SocketError e, QTcpSocket &sock) {
|
||||||
|
switch (e) {
|
||||||
|
case QAbstractSocket::ConnectionRefusedError:
|
||||||
|
LOG(("TCP Error: socket connection refused - %1").arg(sock.errorString()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QAbstractSocket::RemoteHostClosedError:
|
||||||
|
TCP_LOG(("TCP Info: remote host closed socket connection - %1").arg(sock.errorString()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QAbstractSocket::HostNotFoundError:
|
||||||
|
LOG(("TCP Error: host not found - %1").arg(sock.errorString()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QAbstractSocket::SocketTimeoutError:
|
||||||
|
LOG(("TCP Error: socket timeout - %1").arg(sock.errorString()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QAbstractSocket::NetworkError:
|
||||||
|
LOG(("TCP Error: network - %1").arg(sock.errorString()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QAbstractSocket::ProxyAuthenticationRequiredError:
|
||||||
|
case QAbstractSocket::ProxyConnectionRefusedError:
|
||||||
|
case QAbstractSocket::ProxyConnectionClosedError:
|
||||||
|
case QAbstractSocket::ProxyConnectionTimeoutError:
|
||||||
|
case QAbstractSocket::ProxyNotFoundError:
|
||||||
|
case QAbstractSocket::ProxyProtocolError:
|
||||||
|
LOG(("TCP Error: proxy (%1) - %2").arg(e).arg(sock.errorString()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG(("TCP Error: other (%1) - %2").arg(e).arg(sock.errorString()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TCP_LOG(("TCP Error %1, restarting! - %2").arg(e).arg(sock.errorString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TCPConnection::TCPConnection(QThread *thread) : AbstractTCPConnection(thread)
|
||||||
|
, status(WaitingTcp)
|
||||||
|
, tcpNonce(rand_value<MTPint128>())
|
||||||
|
, _tcpTimeout(MTPMinReceiveDelay)
|
||||||
|
, _flags(0) {
|
||||||
|
tcpTimeoutTimer.moveToThread(thread);
|
||||||
|
tcpTimeoutTimer.setSingleShot(true);
|
||||||
|
connect(&tcpTimeoutTimer, SIGNAL(timeout()), this, SLOT(onTcpTimeoutTimer()));
|
||||||
|
|
||||||
|
sock.moveToThread(thread);
|
||||||
|
App::setProxySettings(sock);
|
||||||
|
connect(&sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
|
||||||
|
connect(&sock, SIGNAL(connected()), this, SLOT(onSocketConnected()));
|
||||||
|
connect(&sock, SIGNAL(disconnected()), this, SLOT(onSocketDisconnected()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPConnection::onSocketConnected() {
|
||||||
|
if (status == WaitingTcp) {
|
||||||
|
mtpBuffer buffer(preparePQFake(tcpNonce));
|
||||||
|
|
||||||
|
DEBUG_LOG(("Connection Info: sending fake req_pq through TCP/%1 transport").arg((_flags & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
||||||
|
|
||||||
|
if (_tcpTimeout < 0) _tcpTimeout = -_tcpTimeout;
|
||||||
|
tcpTimeoutTimer.start(_tcpTimeout);
|
||||||
|
|
||||||
|
sendData(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPConnection::onTcpTimeoutTimer() {
|
||||||
|
if (status == WaitingTcp) {
|
||||||
|
if (_tcpTimeout < MTPMaxReceiveDelay) _tcpTimeout *= 2;
|
||||||
|
_tcpTimeout = -_tcpTimeout;
|
||||||
|
|
||||||
|
QAbstractSocket::SocketState state = sock.state();
|
||||||
|
if (state == QAbstractSocket::ConnectedState || state == QAbstractSocket::ConnectingState || state == QAbstractSocket::HostLookupState) {
|
||||||
|
sock.disconnectFromHost();
|
||||||
|
} else if (state != QAbstractSocket::ClosingState) {
|
||||||
|
sock.connectToHost(QHostAddress(_addr), _port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPConnection::onSocketDisconnected() {
|
||||||
|
if (_tcpTimeout < 0) {
|
||||||
|
_tcpTimeout = -_tcpTimeout;
|
||||||
|
if (status == WaitingTcp) {
|
||||||
|
sock.connectToHost(QHostAddress(_addr), _port);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (status == WaitingTcp || status == UsingTcp) {
|
||||||
|
emit disconnected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPConnection::sendData(mtpBuffer &buffer) {
|
||||||
|
if (status == FinishedWork) return;
|
||||||
|
|
||||||
|
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();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcpSend(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractTCPConnection::tcpSend(mtpBuffer &buffer) {
|
||||||
|
if (!packetNum) {
|
||||||
|
// prepare random part
|
||||||
|
char nonce[64];
|
||||||
|
uint32 *first = reinterpret_cast<uint32*>(nonce), *second = first + 1;
|
||||||
|
uint32 first1 = 0x44414548U, first2 = 0x54534f50U, first3 = 0x20544547U, first4 = 0x20544547U, first5 = 0xeeeeeeeeU;
|
||||||
|
uint32 second1 = 0;
|
||||||
|
do {
|
||||||
|
memset_rand(nonce, sizeof(nonce));
|
||||||
|
} while (*first == first1 || *first == first2 || *first == first3 || *first == first4 || *first == first5 || *second == second1 || *reinterpret_cast<uchar*>(nonce) == 0xef);
|
||||||
|
//sock.write(nonce, 64);
|
||||||
|
|
||||||
|
// prepare encryption key/iv
|
||||||
|
memcpy(_sendKey, nonce + 8, CTRState::KeySize);
|
||||||
|
memcpy(_sendState.ivec, nonce + 8 + CTRState::KeySize, CTRState::IvecSize);
|
||||||
|
|
||||||
|
// prepare decryption key/iv
|
||||||
|
char reversed[48];
|
||||||
|
memcpy(reversed, nonce + 8, sizeof(reversed));
|
||||||
|
std::reverse(reversed, reversed + arraysize(reversed));
|
||||||
|
memcpy(_receiveKey, reversed, CTRState::KeySize);
|
||||||
|
memcpy(_receiveState.ivec, reversed + CTRState::KeySize, CTRState::IvecSize);
|
||||||
|
|
||||||
|
// write protocol identifier
|
||||||
|
*reinterpret_cast<uint32*>(nonce + 56) = 0xefefefefU;
|
||||||
|
|
||||||
|
sock.write(nonce, 56);
|
||||||
|
aesCtrEncrypt(nonce, 64, _sendKey, &_sendState);
|
||||||
|
sock.write(nonce + 56, 8);
|
||||||
|
}
|
||||||
|
++packetNum;
|
||||||
|
|
||||||
|
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(packetNum).arg(len + 1));
|
||||||
|
|
||||||
|
aesCtrEncrypt(data + 7, len + 1, _sendKey, &_sendState);
|
||||||
|
sock.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(packetNum).arg(len + 4));
|
||||||
|
|
||||||
|
aesCtrEncrypt(data + 4, len + 4, _sendKey, &_sendState);
|
||||||
|
sock.write(data + 4, len + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPConnection::disconnectFromServer() {
|
||||||
|
if (status == FinishedWork) return;
|
||||||
|
status = FinishedWork;
|
||||||
|
|
||||||
|
disconnect(&sock, SIGNAL(readyRead()), 0, 0);
|
||||||
|
sock.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPConnection::connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) {
|
||||||
|
_addr = addr;
|
||||||
|
_port = port;
|
||||||
|
_flags = flags;
|
||||||
|
|
||||||
|
connect(&sock, SIGNAL(readyRead()), this, SLOT(socketRead()));
|
||||||
|
sock.connectToHost(QHostAddress(_addr), _port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPConnection::socketPacket(const char *packet, uint32 length) {
|
||||||
|
if (status == FinishedWork) return;
|
||||||
|
|
||||||
|
mtpBuffer data = handleResponse(packet, length);
|
||||||
|
if (data.size() == 1) {
|
||||||
|
bool mayBeBadKey = (data[0] == -410) && _sentEncrypted;
|
||||||
|
emit error(mayBeBadKey);
|
||||||
|
} else if (status == UsingTcp) {
|
||||||
|
receivedQueue.push_back(data);
|
||||||
|
emit receivedData();
|
||||||
|
} else if (status == WaitingTcp) {
|
||||||
|
tcpTimeoutTimer.stop();
|
||||||
|
try {
|
||||||
|
MTPResPQ res_pq = readPQFakeReply(data);
|
||||||
|
const MTPDresPQ &res_pq_data(res_pq.c_resPQ());
|
||||||
|
if (res_pq_data.vnonce == tcpNonce) {
|
||||||
|
DEBUG_LOG(("Connection Info: TCP/%1-transport chosen by pq-response").arg((_flags & MTPDdcOption::Flag::f_ipv6) ? "IPv6" : "IPv4"));
|
||||||
|
status = UsingTcp;
|
||||||
|
emit connected();
|
||||||
|
}
|
||||||
|
} catch (Exception &e) {
|
||||||
|
DEBUG_LOG(("Connection Error: exception in parsing TCP fake pq-responce, %1").arg(e.what()));
|
||||||
|
emit error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TCPConnection::isConnected() const {
|
||||||
|
return (status == UsingTcp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 TCPConnection::debugState() const {
|
||||||
|
return sock.state();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TCPConnection::transport() const {
|
||||||
|
return isConnected() ? qsl("TCP") : QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCPConnection::socketError(QAbstractSocket::SocketError e) {
|
||||||
|
if (status == FinishedWork) return;
|
||||||
|
|
||||||
|
handleError(e, sock);
|
||||||
|
emit error();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace MTP
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "mtproto/core_types.h"
|
||||||
|
#include "mtproto/auth_key.h"
|
||||||
|
#include "mtproto/connection_abstract.h"
|
||||||
|
|
||||||
|
namespace MTP {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class AbstractTCPConnection : public AbstractConnection {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
AbstractTCPConnection(QThread *thread);
|
||||||
|
virtual ~AbstractTCPConnection() = 0 {
|
||||||
|
}
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void socketRead();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
QTcpSocket sock;
|
||||||
|
uint32 packetNum; // sent packet number
|
||||||
|
|
||||||
|
uint32 packetRead, packetLeft; // reading from socket
|
||||||
|
bool readingToShort;
|
||||||
|
char *currentPos;
|
||||||
|
mtpBuffer longBuffer;
|
||||||
|
mtpPrime shortBuffer[MTPShortBufferSize];
|
||||||
|
virtual void socketPacket(const char *packet, uint32 length) = 0;
|
||||||
|
|
||||||
|
static mtpBuffer handleResponse(const char *packet, uint32 length);
|
||||||
|
static void handleError(QAbstractSocket::SocketError e, QTcpSocket &sock);
|
||||||
|
static uint32 fourCharsToUInt(char ch1, char ch2, char ch3, char ch4) {
|
||||||
|
char ch[4] = { ch1, ch2, ch3, ch4 };
|
||||||
|
return *reinterpret_cast<uint32*>(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcpSend(mtpBuffer &buffer);
|
||||||
|
uchar _sendKey[CTRState::KeySize];
|
||||||
|
CTRState _sendState;
|
||||||
|
uchar _receiveKey[CTRState::KeySize];
|
||||||
|
CTRState _receiveState;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class TCPConnection : public AbstractTCPConnection {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
TCPConnection(QThread *thread);
|
||||||
|
|
||||||
|
void sendData(mtpBuffer &buffer) override;
|
||||||
|
void disconnectFromServer() override;
|
||||||
|
void connectTcp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override;
|
||||||
|
void connectHttp(const QString &addr, int32 port, MTPDdcOption::Flags flags) override { // not supported
|
||||||
|
}
|
||||||
|
bool isConnected() const override;
|
||||||
|
|
||||||
|
int32 debugState() const override;
|
||||||
|
|
||||||
|
QString transport() const override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void socketError(QAbstractSocket::SocketError e);
|
||||||
|
|
||||||
|
void onSocketConnected();
|
||||||
|
void onSocketDisconnected();
|
||||||
|
|
||||||
|
void onTcpTimeoutTimer();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void socketPacket(const char *packet, uint32 length) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum Status {
|
||||||
|
WaitingTcp = 0,
|
||||||
|
UsingTcp,
|
||||||
|
FinishedWork
|
||||||
|
};
|
||||||
|
Status status;
|
||||||
|
MTPint128 tcpNonce;
|
||||||
|
|
||||||
|
QString _addr;
|
||||||
|
int32 _port, _tcpTimeout;
|
||||||
|
MTPDdcOption::Flags _flags;
|
||||||
|
QTimer tcpTimeoutTimer;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace MTP
|
|
@ -22,6 +22,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "mtproto/core_types.h"
|
#include "mtproto/core_types.h"
|
||||||
|
|
||||||
|
#include "zlib.h"
|
||||||
|
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
|
|
||||||
QString mtpWrapNumber(float64 number) {
|
QString mtpWrapNumber(float64 number) {
|
||||||
|
|
|
@ -25,39 +25,41 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "mtproto/facade.h"
|
#include "mtproto/facade.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
|
|
||||||
namespace {
|
namespace MTP {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
MTProtoDCMap gDCs;
|
namespace {
|
||||||
|
DcenterMap gDCs;
|
||||||
bool configLoadedOnce = false;
|
bool configLoadedOnce = false;
|
||||||
bool mainDCChanged = false;
|
bool mainDCChanged = false;
|
||||||
int32 mainDC = 2;
|
int32 _mainDC = 2;
|
||||||
int32 userId = 0;
|
int32 userId = 0;
|
||||||
|
|
||||||
typedef QMap<int32, mtpAuthKeyPtr> _KeysMapForWrite;
|
typedef QMap<int32, AuthKeyPtr> _KeysMapForWrite;
|
||||||
_KeysMapForWrite _keysMapForWrite;
|
_KeysMapForWrite _keysMapForWrite;
|
||||||
QMutex _keysMapForWriteMutex;
|
QMutex _keysMapForWriteMutex;
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
int32 mtpAuthed() {
|
int32 authed() {
|
||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mtpAuthed(int32 uid) {
|
void authed(int32 uid) {
|
||||||
if (userId != uid) {
|
if (userId != uid) {
|
||||||
userId = uid;
|
userId = uid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MTProtoDCMap &mtpDCMap() {
|
DcenterMap &DCMap() {
|
||||||
return gDCs;
|
return gDCs;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mtpNeedConfig() {
|
bool configNeeded() {
|
||||||
return !configLoadedOnce;
|
return !configLoadedOnce;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 mtpMainDC() {
|
int32 mainDC() {
|
||||||
return mainDC;
|
return _mainDC;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -74,7 +76,7 @@ namespace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mtpLogoutOtherDCs() {
|
void logoutOtherDCs() {
|
||||||
QList<int32> dcs;
|
QList<int32> dcs;
|
||||||
{
|
{
|
||||||
QMutexLocker lock(&_keysMapForWriteMutex);
|
QMutexLocker lock(&_keysMapForWriteMutex);
|
||||||
|
@ -87,15 +89,15 @@ void mtpLogoutOtherDCs() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mtpSetDC(int32 dc, bool firstOnly) {
|
void setDC(int32 dc, bool firstOnly) {
|
||||||
if (!dc || (firstOnly && mainDCChanged)) return;
|
if (!dc || (firstOnly && mainDCChanged)) return;
|
||||||
mainDCChanged = true;
|
mainDCChanged = true;
|
||||||
if (dc != mainDC) {
|
if (dc != _mainDC) {
|
||||||
mainDC = dc;
|
_mainDC = dc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MTProtoDC::MTProtoDC(int32 id, const mtpAuthKeyPtr &key) : _id(id), _key(key), _connectionInited(false) {
|
Dcenter::Dcenter(int32 id, const AuthKeyPtr &key) : _id(id), _key(key), _connectionInited(false) {
|
||||||
connect(this, SIGNAL(authKeyCreated()), this, SLOT(authKeyWrite()), Qt::QueuedConnection);
|
connect(this, SIGNAL(authKeyCreated()), this, SLOT(authKeyWrite()), Qt::QueuedConnection);
|
||||||
|
|
||||||
QMutexLocker lock(&_keysMapForWriteMutex);
|
QMutexLocker lock(&_keysMapForWriteMutex);
|
||||||
|
@ -106,14 +108,14 @@ MTProtoDC::MTProtoDC(int32 id, const mtpAuthKeyPtr &key) : _id(id), _key(key), _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MTProtoDC::authKeyWrite() {
|
void Dcenter::authKeyWrite() {
|
||||||
DEBUG_LOG(("AuthKey Info: MTProtoDC::authKeyWrite() slot, dc %1").arg(_id));
|
DEBUG_LOG(("AuthKey Info: MTProtoDC::authKeyWrite() slot, dc %1").arg(_id));
|
||||||
if (_key) {
|
if (_key) {
|
||||||
Local::writeMtpData();
|
Local::writeMtpData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MTProtoDC::setKey(const mtpAuthKeyPtr &key) {
|
void Dcenter::setKey(const AuthKeyPtr &key) {
|
||||||
DEBUG_LOG(("AuthKey Info: MTProtoDC::setKey(%1), emitting authKeyCreated, dc %2").arg(key ? key->keyId() : 0).arg(_id));
|
DEBUG_LOG(("AuthKey Info: MTProtoDC::setKey(%1), emitting authKeyCreated, dc %2").arg(key ? key->keyId() : 0).arg(_id));
|
||||||
_key = key;
|
_key = key;
|
||||||
_connectionInited = false;
|
_connectionInited = false;
|
||||||
|
@ -127,23 +129,23 @@ void MTProtoDC::setKey(const mtpAuthKeyPtr &key) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QReadWriteLock *MTProtoDC::keyMutex() const {
|
QReadWriteLock *Dcenter::keyMutex() const {
|
||||||
return &keyLock;
|
return &keyLock;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mtpAuthKeyPtr &MTProtoDC::getKey() const {
|
const AuthKeyPtr &Dcenter::getKey() const {
|
||||||
return _key;
|
return _key;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MTProtoDC::destroyKey() {
|
void Dcenter::destroyKey() {
|
||||||
setKey(mtpAuthKeyPtr());
|
setKey(AuthKeyPtr());
|
||||||
|
|
||||||
QMutexLocker lock(&_keysMapForWriteMutex);
|
QMutexLocker lock(&_keysMapForWriteMutex);
|
||||||
_keysMapForWrite.remove(_id);
|
_keysMapForWrite.remove(_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
MTProtoConfigLoader *configLoader = 0;
|
ConfigLoader *_configLoader = nullptr;
|
||||||
bool loadingConfig = false;
|
bool loadingConfig = false;
|
||||||
void configLoaded(const MTPConfig &result) {
|
void configLoaded(const MTPConfig &result) {
|
||||||
loadingConfig = false;
|
loadingConfig = false;
|
||||||
|
@ -152,7 +154,7 @@ namespace {
|
||||||
|
|
||||||
DEBUG_LOG(("MTP Info: got config, chat_size_max: %1, date: %2, test_mode: %3, this_dc: %4, dc_options.length: %5").arg(data.vchat_size_max.v).arg(data.vdate.v).arg(mtpIsTrue(data.vtest_mode)).arg(data.vthis_dc.v).arg(data.vdc_options.c_vector().v.size()));
|
DEBUG_LOG(("MTP Info: got config, chat_size_max: %1, date: %2, test_mode: %3, this_dc: %4, dc_options.length: %5").arg(data.vchat_size_max.v).arg(data.vdate.v).arg(mtpIsTrue(data.vtest_mode)).arg(data.vthis_dc.v).arg(data.vdc_options.c_vector().v.size()));
|
||||||
|
|
||||||
mtpUpdateDcOptions(data.vdc_options.c_vector().v);
|
updateDcOptions(data.vdc_options.c_vector().v);
|
||||||
|
|
||||||
Global::SetChatSizeMax(data.vchat_size_max.v);
|
Global::SetChatSizeMax(data.vchat_size_max.v);
|
||||||
Global::SetMegagroupSizeMax(data.vmegagroup_size_max.v);
|
Global::SetMegagroupSizeMax(data.vmegagroup_size_max.v);
|
||||||
|
@ -172,7 +174,7 @@ namespace {
|
||||||
configLoadedOnce = true;
|
configLoadedOnce = true;
|
||||||
Local::writeSettings();
|
Local::writeSettings();
|
||||||
|
|
||||||
mtpConfigLoader()->done();
|
configLoader()->done();
|
||||||
}
|
}
|
||||||
bool configFailed(const RPCError &error) {
|
bool configFailed(const RPCError &error) {
|
||||||
if (mtpIsFlood(error)) return false;
|
if (mtpIsFlood(error)) return false;
|
||||||
|
@ -183,12 +185,12 @@ namespace {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void mtpUpdateDcOptions(const QVector<MTPDcOption> &options) {
|
void updateDcOptions(const QVector<MTPDcOption> &options) {
|
||||||
QSet<int32> already, restart;
|
QSet<int32> already, restart;
|
||||||
{
|
{
|
||||||
MTP::DcOptions opts;
|
MTP::DcOptions opts;
|
||||||
{
|
{
|
||||||
QReadLocker lock(mtpDcOptionsMutex());
|
QReadLocker lock(dcOptionsMutex());
|
||||||
opts = Global::DcOptions();
|
opts = Global::DcOptions();
|
||||||
}
|
}
|
||||||
for (QVector<MTPDcOption>::const_iterator i = options.cbegin(), e = options.cend(); i != e; ++i) {
|
for (QVector<MTPDcOption>::const_iterator i = options.cbegin(), e = options.cend(); i != e; ++i) {
|
||||||
|
@ -206,7 +208,7 @@ void mtpUpdateDcOptions(const QVector<MTPDcOption> &options) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
QWriteLocker lock(mtpDcOptionsMutex());
|
QWriteLocker lock(dcOptionsMutex());
|
||||||
Global::SetDcOptions(opts);
|
Global::SetDcOptions(opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,15 +221,15 @@ namespace {
|
||||||
QReadWriteLock _dcOptionsMutex;
|
QReadWriteLock _dcOptionsMutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
QReadWriteLock *mtpDcOptionsMutex() {
|
QReadWriteLock *dcOptionsMutex() {
|
||||||
return &_dcOptionsMutex;
|
return &_dcOptionsMutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
MTProtoConfigLoader::MTProtoConfigLoader() : _enumCurrent(0), _enumRequest(0) {
|
ConfigLoader::ConfigLoader() : _enumCurrent(0), _enumRequest(0) {
|
||||||
connect(&_enumDCTimer, SIGNAL(timeout()), this, SLOT(enumDC()));
|
connect(&_enumDCTimer, SIGNAL(timeout()), this, SLOT(enumDC()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MTProtoConfigLoader::load() {
|
void ConfigLoader::load() {
|
||||||
if (loadingConfig) return;
|
if (loadingConfig) return;
|
||||||
loadingConfig = true;
|
loadingConfig = true;
|
||||||
|
|
||||||
|
@ -236,7 +238,7 @@ void MTProtoConfigLoader::load() {
|
||||||
_enumDCTimer.start(MTPEnumDCTimeout);
|
_enumDCTimer.start(MTPEnumDCTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MTProtoConfigLoader::done() {
|
void ConfigLoader::done() {
|
||||||
_enumDCTimer.stop();
|
_enumDCTimer.stop();
|
||||||
if (_enumRequest) {
|
if (_enumRequest) {
|
||||||
MTP::cancel(_enumRequest);
|
MTP::cancel(_enumRequest);
|
||||||
|
@ -249,19 +251,19 @@ void MTProtoConfigLoader::done() {
|
||||||
emit loaded();
|
emit loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MTProtoConfigLoader::enumDC() {
|
void ConfigLoader::enumDC() {
|
||||||
if (!loadingConfig) return;
|
if (!loadingConfig) return;
|
||||||
|
|
||||||
if (_enumRequest) MTP::cancel(_enumRequest);
|
if (_enumRequest) MTP::cancel(_enumRequest);
|
||||||
|
|
||||||
if (!_enumCurrent) {
|
if (!_enumCurrent) {
|
||||||
_enumCurrent = mainDC;
|
_enumCurrent = _mainDC;
|
||||||
} else {
|
} else {
|
||||||
MTP::killSession(MTP::cfgDcId(_enumCurrent));
|
MTP::killSession(MTP::cfgDcId(_enumCurrent));
|
||||||
}
|
}
|
||||||
OrderedSet<int32> dcs;
|
OrderedSet<int32> dcs;
|
||||||
{
|
{
|
||||||
QReadLocker lock(mtpDcOptionsMutex());
|
QReadLocker lock(dcOptionsMutex());
|
||||||
const MTP::DcOptions &options(Global::DcOptions());
|
const MTP::DcOptions &options(Global::DcOptions());
|
||||||
for (auto i = options.cbegin(), e = options.cend(); i != e; ++i) {
|
for (auto i = options.cbegin(), e = options.cend(); i != e; ++i) {
|
||||||
dcs.insert(MTP::bareDcId(i.key()));
|
dcs.insert(MTP::bareDcId(i.key()));
|
||||||
|
@ -278,26 +280,29 @@ void MTProtoConfigLoader::enumDC() {
|
||||||
_enumDCTimer.start(MTPEnumDCTimeout);
|
_enumDCTimer.start(MTPEnumDCTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
MTProtoConfigLoader *mtpConfigLoader() {
|
ConfigLoader *configLoader() {
|
||||||
if (!configLoader) configLoader = new MTProtoConfigLoader();
|
if (!_configLoader) _configLoader = new ConfigLoader();
|
||||||
return configLoader;
|
return _configLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mtpDestroyConfigLoader() {
|
void destroyConfigLoader() {
|
||||||
delete configLoader;
|
delete _configLoader;
|
||||||
configLoader = 0;
|
_configLoader = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
mtpKeysMap mtpGetKeys() {
|
AuthKeysMap getAuthKeys() {
|
||||||
mtpKeysMap result;
|
AuthKeysMap result;
|
||||||
QMutexLocker lock(&_keysMapForWriteMutex);
|
QMutexLocker lock(&_keysMapForWriteMutex);
|
||||||
for (_KeysMapForWrite::const_iterator i = _keysMapForWrite.cbegin(), e = _keysMapForWrite.cend(); i != e; ++i) {
|
for_const (const AuthKeyPtr &key, _keysMapForWrite) {
|
||||||
result.push_back(i.value());
|
result.push_back(key);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mtpSetKey(int32 dcId, mtpAuthKeyPtr key) {
|
void setAuthKey(int32 dcId, AuthKeyPtr key) {
|
||||||
MTProtoDCPtr dc(new MTProtoDC(dcId, key));
|
DcenterPtr dc(new Dcenter(dcId, key));
|
||||||
gDCs.insert(dcId, dc);
|
gDCs.insert(dcId, dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace MTP
|
||||||
|
|
|
@ -20,16 +20,19 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
class MTProtoDC : public QObject {
|
namespace MTP {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class Dcenter : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MTProtoDC(int32 id, const mtpAuthKeyPtr &key);
|
Dcenter(int32 id, const AuthKeyPtr &key);
|
||||||
|
|
||||||
QReadWriteLock *keyMutex() const;
|
QReadWriteLock *keyMutex() const;
|
||||||
const mtpAuthKeyPtr &getKey() const;
|
const AuthKeyPtr &getKey() const;
|
||||||
void setKey(const mtpAuthKeyPtr &key);
|
void setKey(const AuthKeyPtr &key);
|
||||||
void destroyKey();
|
void destroyKey();
|
||||||
|
|
||||||
bool connectionInited() const {
|
bool connectionInited() const {
|
||||||
|
@ -56,19 +59,19 @@ private:
|
||||||
mutable QReadWriteLock keyLock;
|
mutable QReadWriteLock keyLock;
|
||||||
mutable QMutex initLock;
|
mutable QMutex initLock;
|
||||||
int32 _id;
|
int32 _id;
|
||||||
mtpAuthKeyPtr _key;
|
AuthKeyPtr _key;
|
||||||
bool _connectionInited;
|
bool _connectionInited;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef QSharedPointer<MTProtoDC> MTProtoDCPtr;
|
typedef QSharedPointer<Dcenter> DcenterPtr;
|
||||||
typedef QMap<uint32, MTProtoDCPtr> MTProtoDCMap;
|
typedef QMap<uint32, DcenterPtr> DcenterMap;
|
||||||
|
|
||||||
class MTProtoConfigLoader : public QObject {
|
class ConfigLoader : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MTProtoConfigLoader();
|
ConfigLoader();
|
||||||
void load();
|
void load();
|
||||||
void done();
|
void done();
|
||||||
|
|
||||||
|
@ -88,21 +91,23 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MTProtoConfigLoader *mtpConfigLoader();
|
ConfigLoader *configLoader();
|
||||||
void mtpDestroyConfigLoader();
|
void destroyConfigLoader();
|
||||||
|
|
||||||
MTProtoDCMap &mtpDCMap();
|
DcenterMap &DCMap();
|
||||||
bool mtpNeedConfig();
|
bool configNeeded();
|
||||||
int32 mtpMainDC();
|
int32 mainDC();
|
||||||
void mtpLogoutOtherDCs();
|
void logoutOtherDCs();
|
||||||
void mtpSetDC(int32 dc, bool firstOnly = false);
|
void setDC(int32 dc, bool firstOnly = false);
|
||||||
uint32 mtpMaxChatSize();
|
|
||||||
|
|
||||||
int32 mtpAuthed();
|
int32 authed();
|
||||||
void mtpAuthed(int32 uid);
|
void authed(int32 uid);
|
||||||
|
|
||||||
mtpKeysMap mtpGetKeys();
|
AuthKeysMap getAuthKeys();
|
||||||
void mtpSetKey(int32 dc, mtpAuthKeyPtr key);
|
void setAuthKey(int32 dc, AuthKeyPtr key);
|
||||||
|
|
||||||
void mtpUpdateDcOptions(const QVector<MTPDcOption> &options);
|
void updateDcOptions(const QVector<MTPDcOption> &options);
|
||||||
QReadWriteLock *mtpDcOptionsMutex();
|
QReadWriteLock *dcOptionsMutex();
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace MTP
|
||||||
|
|
|
@ -249,7 +249,7 @@ namespace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int32 newdc = bareDcId(qAbs(dcWithShift));
|
int32 newdc = bareDcId(qAbs(dcWithShift));
|
||||||
if (!newdc || newdc == mtpMainDC() || !authedId()) {
|
if (!newdc || newdc == internal::mainDC() || !authedId()) {
|
||||||
if (!badGuestDC && globalHandler.onFail) (*globalHandler.onFail)(requestId, error); // auth failed in main dc
|
if (!badGuestDC && globalHandler.onFail) (*globalHandler.onFail)(requestId, error); // auth failed in main dc
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -649,17 +649,17 @@ void start() {
|
||||||
|
|
||||||
unixtimeInit();
|
unixtimeInit();
|
||||||
|
|
||||||
MTProtoDCMap &dcs(mtpDCMap());
|
internal::DcenterMap &dcs(internal::DCMap());
|
||||||
|
|
||||||
_globalSlotCarrier = new internal::GlobalSlotCarrier();
|
_globalSlotCarrier = new internal::GlobalSlotCarrier();
|
||||||
|
|
||||||
mainSession = new internal::Session(mtpMainDC());
|
mainSession = new internal::Session(internal::mainDC());
|
||||||
sessions.insert(mainSession->getDcWithShift(), mainSession);
|
sessions.insert(mainSession->getDcWithShift(), mainSession);
|
||||||
|
|
||||||
_started = true;
|
_started = true;
|
||||||
|
|
||||||
if (mtpNeedConfig()) {
|
if (internal::configNeeded()) {
|
||||||
mtpConfigLoader()->load();
|
internal::configLoader()->load();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,13 +701,13 @@ void unpause() {
|
||||||
|
|
||||||
void configure(int32 dc, int32 user) {
|
void configure(int32 dc, int32 user) {
|
||||||
if (_started) return;
|
if (_started) return;
|
||||||
mtpSetDC(dc);
|
internal::setDC(dc);
|
||||||
mtpAuthed(user);
|
internal::authed(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setdc(int32 dc, bool fromZeroOnly) {
|
void setdc(int32 dc, bool fromZeroOnly) {
|
||||||
if (!dc || !_started) return;
|
if (!dc || !_started) return;
|
||||||
mtpSetDC(dc, fromZeroOnly);
|
internal::setDC(dc, fromZeroOnly);
|
||||||
int32 oldMainDc = mainSession->getDcWithShift();
|
int32 oldMainDc = mainSession->getDcWithShift();
|
||||||
if (maindc() != oldMainDc) {
|
if (maindc() != oldMainDc) {
|
||||||
killSession(oldMainDc);
|
killSession(oldMainDc);
|
||||||
|
@ -716,7 +716,7 @@ void setdc(int32 dc, bool fromZeroOnly) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 maindc() {
|
int32 maindc() {
|
||||||
return mtpMainDC();
|
return internal::mainDC();
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 dcstate(int32 dc) {
|
int32 dcstate(int32 dc) {
|
||||||
|
@ -789,7 +789,7 @@ void killSession(int32 dc) {
|
||||||
sessions.erase(i);
|
sessions.erase(i);
|
||||||
|
|
||||||
if (wasMain) {
|
if (wasMain) {
|
||||||
mainSession = new internal::Session(mtpMainDC());
|
mainSession = new internal::Session(internal::mainDC());
|
||||||
int32 newdc = mainSession->getDcWithShift();
|
int32 newdc = mainSession->getDcWithShift();
|
||||||
i = sessions.find(newdc);
|
i = sessions.find(newdc);
|
||||||
if (i != sessions.cend()) {
|
if (i != sessions.cend()) {
|
||||||
|
@ -846,22 +846,22 @@ void finish() {
|
||||||
delete _globalSlotCarrier;
|
delete _globalSlotCarrier;
|
||||||
_globalSlotCarrier = nullptr;
|
_globalSlotCarrier = nullptr;
|
||||||
|
|
||||||
mtpDestroyConfigLoader();
|
internal::destroyConfigLoader();
|
||||||
|
|
||||||
_started = false;
|
_started = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void authed(int32 uid) {
|
void authed(int32 uid) {
|
||||||
mtpAuthed(uid);
|
internal::authed(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 authedId() {
|
int32 authedId() {
|
||||||
return mtpAuthed();
|
return internal::authed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void logoutKeys(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail) {
|
void logoutKeys(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail) {
|
||||||
mtpRequestId req = MTP::send(MTPauth_LogOut(), onDone, onFail);
|
mtpRequestId req = MTP::send(MTPauth_LogOut(), onDone, onFail);
|
||||||
mtpLogoutOtherDCs();
|
internal::logoutOtherDCs();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setGlobalDoneHandler(RPCDoneHandlerPtr handler) {
|
void setGlobalDoneHandler(RPCDoneHandlerPtr handler) {
|
||||||
|
@ -888,20 +888,20 @@ void clearGlobalHandlers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateDcOptions(const QVector<MTPDcOption> &options) {
|
void updateDcOptions(const QVector<MTPDcOption> &options) {
|
||||||
mtpUpdateDcOptions(options);
|
internal::updateDcOptions(options);
|
||||||
Local::writeSettings();
|
Local::writeSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
mtpKeysMap getKeys() {
|
AuthKeysMap getKeys() {
|
||||||
return mtpGetKeys();
|
return internal::getAuthKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setKey(int32 dc, mtpAuthKeyPtr key) {
|
void setKey(int32 dc, AuthKeyPtr key) {
|
||||||
return mtpSetKey(dc, key);
|
return internal::setAuthKey(dc, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
QReadWriteLock *dcOptionsMutex() {
|
QReadWriteLock *dcOptionsMutex() {
|
||||||
return mtpDcOptionsMutex();
|
return internal::dcOptionsMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace MTP
|
} // namespace MTP
|
||||||
|
|
|
@ -192,8 +192,8 @@ void clearGlobalHandlers();
|
||||||
|
|
||||||
void updateDcOptions(const QVector<MTPDcOption> &options);
|
void updateDcOptions(const QVector<MTPDcOption> &options);
|
||||||
|
|
||||||
mtpKeysMap getKeys();
|
AuthKeysMap getKeys();
|
||||||
void setKey(int32 dc, mtpAuthKeyPtr key);
|
void setKey(int32 dc, AuthKeyPtr key);
|
||||||
|
|
||||||
QReadWriteLock *dcOptionsMutex();
|
QReadWriteLock *dcOptionsMutex();
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ Session::Session(int32 dcenter) : QObject()
|
||||||
|
|
||||||
connect(&sender, SIGNAL(timeout()), this, SLOT(needToResumeAndSend()));
|
connect(&sender, SIGNAL(timeout()), this, SLOT(needToResumeAndSend()));
|
||||||
|
|
||||||
MTProtoDCMap &dcs(mtpDCMap());
|
DcenterMap &dcs(DCMap());
|
||||||
|
|
||||||
_connection = new Connection();
|
_connection = new Connection();
|
||||||
dcWithShift = _connection->start(&data, dcenter);
|
dcWithShift = _connection->start(&data, dcenter);
|
||||||
|
@ -109,16 +109,16 @@ Session::Session(int32 dcenter) : QObject()
|
||||||
if (!dc) {
|
if (!dc) {
|
||||||
dcenter = dcWithShift;
|
dcenter = dcWithShift;
|
||||||
int32 dcId = bareDcId(dcWithShift);
|
int32 dcId = bareDcId(dcWithShift);
|
||||||
MTProtoDCMap::const_iterator dcIndex = dcs.constFind(dcId);
|
auto dcIndex = dcs.constFind(dcId);
|
||||||
if (dcIndex == dcs.cend()) {
|
if (dcIndex == dcs.cend()) {
|
||||||
dc = MTProtoDCPtr(new MTProtoDC(dcId, mtpAuthKeyPtr()));
|
dc = DcenterPtr(new Dcenter(dcId, AuthKeyPtr()));
|
||||||
dcs.insert(dcId, dc);
|
dcs.insert(dcId, dc);
|
||||||
} else {
|
} else {
|
||||||
dc = dcIndex.value();
|
dc = dcIndex.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadLockerAttempt lock(keyMutex());
|
ReadLockerAttempt lock(keyMutex());
|
||||||
data.setKey(lock ? dc->getKey() : mtpAuthKeyPtr(0));
|
data.setKey(lock ? dc->getKey() : AuthKeyPtr());
|
||||||
if (lock && dc->connectionInited()) {
|
if (lock && dc->connectionInited()) {
|
||||||
data.setLayerWasInited(true);
|
data.setLayerWasInited(true);
|
||||||
}
|
}
|
||||||
|
@ -197,7 +197,7 @@ void Session::needToResumeAndSend() {
|
||||||
}
|
}
|
||||||
if (!_connection) {
|
if (!_connection) {
|
||||||
DEBUG_LOG(("Session Info: resuming session dcWithShift %1").arg(dcWithShift));
|
DEBUG_LOG(("Session Info: resuming session dcWithShift %1").arg(dcWithShift));
|
||||||
MTProtoDCMap &dcs(mtpDCMap());
|
DcenterMap &dcs(DCMap());
|
||||||
|
|
||||||
_connection = new Connection();
|
_connection = new Connection();
|
||||||
if (!_connection->start(&data, dcWithShift)) {
|
if (!_connection->start(&data, dcWithShift)) {
|
||||||
|
@ -466,7 +466,7 @@ void Session::authKeyCreatedForDC() {
|
||||||
emit authKeyCreated();
|
emit authKeyCreated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::notifyKeyCreated(const mtpAuthKeyPtr &key) {
|
void Session::notifyKeyCreated(const AuthKeyPtr &key) {
|
||||||
DEBUG_LOG(("AuthKey Info: MTProtoSession::keyCreated(), setting, dcWithShift %1").arg(dcWithShift));
|
DEBUG_LOG(("AuthKey Info: MTProtoSession::keyCreated(), setting, dcWithShift %1").arg(dcWithShift));
|
||||||
dc->setKey(key);
|
dc->setKey(key);
|
||||||
}
|
}
|
||||||
|
@ -490,7 +490,7 @@ void Session::destroyKey() {
|
||||||
if (data.getKey() == dc->getKey()) {
|
if (data.getKey() == dc->getKey()) {
|
||||||
dc->destroyKey();
|
dc->destroyKey();
|
||||||
}
|
}
|
||||||
data.setKey(mtpAuthKeyPtr(0));
|
data.setKey(AuthKeyPtr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,10 +73,10 @@ public:
|
||||||
return _salt;
|
return _salt;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mtpAuthKeyPtr &getKey() const {
|
const AuthKeyPtr &getKey() const {
|
||||||
return _authKey;
|
return _authKey;
|
||||||
}
|
}
|
||||||
void setKey(const mtpAuthKeyPtr &key) {
|
void setKey(const AuthKeyPtr &key) {
|
||||||
if (_authKey != key) {
|
if (_authKey != key) {
|
||||||
uint64 session = rand_value<uint64>();
|
uint64 session = rand_value<uint64>();
|
||||||
_authKey = key;
|
_authKey = key;
|
||||||
|
@ -200,7 +200,7 @@ private:
|
||||||
|
|
||||||
Session *_owner;
|
Session *_owner;
|
||||||
|
|
||||||
mtpAuthKeyPtr _authKey;
|
AuthKeyPtr _authKey;
|
||||||
bool _keyChecked, _layerInited;
|
bool _keyChecked, _layerInited;
|
||||||
|
|
||||||
mtpPreRequestMap toSend; // map of request_id -> request, that is waiting to be sent
|
mtpPreRequestMap toSend; // map of request_id -> request, that is waiting to be sent
|
||||||
|
@ -240,7 +240,7 @@ public:
|
||||||
~Session();
|
~Session();
|
||||||
|
|
||||||
QReadWriteLock *keyMutex() const;
|
QReadWriteLock *keyMutex() const;
|
||||||
void notifyKeyCreated(const mtpAuthKeyPtr &key);
|
void notifyKeyCreated(const AuthKeyPtr &key);
|
||||||
void destroyKey();
|
void destroyKey();
|
||||||
void notifyLayerInited(bool wasInited);
|
void notifyLayerInited(bool wasInited);
|
||||||
|
|
||||||
|
@ -292,7 +292,7 @@ private:
|
||||||
SessionData data;
|
SessionData data;
|
||||||
|
|
||||||
int32 dcWithShift;
|
int32 dcWithShift;
|
||||||
MTProtoDCPtr dc;
|
DcenterPtr dc;
|
||||||
|
|
||||||
uint64 msSendCall, msWait;
|
uint64 msSendCall, msWait;
|
||||||
|
|
||||||
|
|
|
@ -33,12 +33,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#undef signals
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <libappindicator/app-indicator.h>
|
#undef signals
|
||||||
#include <gtk/gtk.h>
|
#include <libappindicator/app-indicator.h>
|
||||||
}
|
#include <gtk/gtk.h>
|
||||||
#define signals public
|
#define signals public
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
#include <unity/unity/unity.h>
|
#include <unity/unity/unity.h>
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
inline QString psServerPrefix() {
|
inline QString psServerPrefix() {
|
||||||
return qsl("Global\\");
|
return qsl("Global\\");
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,51 +20,15 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define NOMINMAX // no min() and max() macro declarations
|
#define NOMINMAX // no min() and max() macro declarations
|
||||||
|
|
||||||
#ifdef TDESKTOP_WINRT
|
|
||||||
|
|
||||||
#include <wrl.h>
|
|
||||||
#include <wrl/client.h>
|
|
||||||
|
|
||||||
#else // TDESKTOP_WINRT
|
|
||||||
|
|
||||||
#define __HUGE
|
#define __HUGE
|
||||||
#define PSAPI_VERSION 1 // fix WinXP
|
|
||||||
|
|
||||||
#define __STDC_FORMAT_MACROS // fix breakpad for mac
|
#define __STDC_FORMAT_MACROS // fix breakpad for mac
|
||||||
|
|
||||||
#endif // else of TDESKTOP_WINRT
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
#include <numeric>
|
|
||||||
|
|
||||||
#include <QtCore/QtCore>
|
#include <QtCore/QtCore>
|
||||||
#include <QtWidgets/QtWidgets>
|
#include <QtWidgets/QtWidgets>
|
||||||
#include <QtNetwork/QtNetwork>
|
#include <QtNetwork/QtNetwork>
|
||||||
|
|
||||||
#ifdef Q_OS_WIN // use Lzma SDK for win
|
|
||||||
#include <LzmaLib.h>
|
|
||||||
#else // Q_OS_WIN
|
|
||||||
#include <lzma.h>
|
|
||||||
#endif // else of Q_OS_WIN
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "zip.h"
|
|
||||||
|
|
||||||
#include <libavcodec/avcodec.h>
|
|
||||||
#include <libavformat/avformat.h>
|
|
||||||
#include <libavutil/opt.h>
|
|
||||||
#include <libswresample/swresample.h>
|
|
||||||
#include <libswscale/swscale.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
@ -85,4 +49,4 @@ extern "C" {
|
||||||
|
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
|
|
||||||
#endif
|
#endif // __cplusplus
|
||||||
|
|
|
@ -25,6 +25,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
}
|
||||||
|
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
|
|
||||||
uint64 _SharedMemoryLocation[4] = { 0x00, 0x01, 0x02, 0x03 };
|
uint64 _SharedMemoryLocation[4] = { 0x00, 0x01, 0x02, 0x03 };
|
||||||
|
|
|
@ -19,14 +19,15 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "style.h"
|
|
||||||
#include "lang.h"
|
|
||||||
|
|
||||||
#include "shortcuts.h"
|
|
||||||
|
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "application.h"
|
|
||||||
|
|
||||||
|
#include "zip.h"
|
||||||
|
|
||||||
|
#include "style.h"
|
||||||
|
#include "lang.h"
|
||||||
|
#include "shortcuts.h"
|
||||||
|
#include "application.h"
|
||||||
#include "pspecific.h"
|
#include "pspecific.h"
|
||||||
#include "title.h"
|
#include "title.h"
|
||||||
#include "passcodewidget.h"
|
#include "passcodewidget.h"
|
||||||
|
@ -37,9 +38,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "boxes/contactsbox.h"
|
#include "boxes/contactsbox.h"
|
||||||
#include "boxes/addcontactbox.h"
|
#include "boxes/addcontactbox.h"
|
||||||
|
|
||||||
#include "autoupdater.h"
|
#include "autoupdater.h"
|
||||||
|
|
||||||
#include "mediaview.h"
|
#include "mediaview.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue