mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-04-01 14:50:24 +00:00
improved bad_msg_notification handle and local time shifts
This commit is contained in:
parent
22e1a7b730
commit
0e031f042d
@ -95,7 +95,7 @@ namespace App {
|
||||
return w ? w->mainWidget() : 0;
|
||||
}
|
||||
|
||||
Settings *settings() {
|
||||
SettingsWidget *settings() {
|
||||
Window *w(wnd());
|
||||
return w ? w->settingsWidget() : 0;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
class Application;
|
||||
class Window;
|
||||
class MainWidget;
|
||||
class Settings;
|
||||
class SettingsWidget;
|
||||
class Font;
|
||||
class Color;
|
||||
class FileUploader;
|
||||
@ -38,7 +38,7 @@ namespace App {
|
||||
Application *app();
|
||||
Window *wnd();
|
||||
MainWidget *main();
|
||||
Settings *settings();
|
||||
SettingsWidget *settings();
|
||||
FileUploader *uploader();
|
||||
|
||||
void showSettings();
|
||||
|
@ -230,6 +230,7 @@ bool StorageImage::check() const {
|
||||
h = data.height();
|
||||
invalidateSizeCache();
|
||||
loader->deleteLater();
|
||||
loader->rpcInvalidate();
|
||||
loader = 0;
|
||||
|
||||
saved = bytes;
|
||||
@ -256,6 +257,7 @@ void StorageImage::setData(QByteArray &bytes, const QByteArray &format) {
|
||||
invalidateSizeCache();
|
||||
if (loader) {
|
||||
loader->deleteLater();
|
||||
loader->rpcInvalidate();
|
||||
loader = 0;
|
||||
}
|
||||
this->saved = bytes;
|
||||
@ -269,6 +271,7 @@ StorageImage::~StorageImage() {
|
||||
}
|
||||
if (loader) {
|
||||
loader->deleteLater();
|
||||
loader->rpcInvalidate();
|
||||
loader = 0;
|
||||
}
|
||||
}
|
||||
|
@ -227,6 +227,7 @@ struct VideoData {
|
||||
if (l) {
|
||||
l->cancel();
|
||||
l->deleteLater();
|
||||
l->rpcInvalidate();
|
||||
}
|
||||
fileName = QString();
|
||||
modDate = QDateTime();
|
||||
@ -241,6 +242,7 @@ struct VideoData {
|
||||
modDate = fileName.isEmpty() ? QDateTime() : QFileInfo(fileName).lastModified();
|
||||
}
|
||||
loader->deleteLater();
|
||||
loader->rpcInvalidate();
|
||||
loader = 0;
|
||||
}
|
||||
|
||||
@ -328,6 +330,7 @@ struct AudioData {
|
||||
if (l) {
|
||||
l->cancel();
|
||||
l->deleteLater();
|
||||
l->rpcInvalidate();
|
||||
}
|
||||
fileName = QString();
|
||||
modDate = QDateTime();
|
||||
@ -342,6 +345,7 @@ struct AudioData {
|
||||
modDate = fileName.isEmpty() ? QDateTime() : QFileInfo(fileName).lastModified();
|
||||
}
|
||||
loader->deleteLater();
|
||||
loader->rpcInvalidate();
|
||||
loader = 0;
|
||||
}
|
||||
|
||||
@ -427,6 +431,7 @@ struct DocumentData {
|
||||
if (l) {
|
||||
l->cancel();
|
||||
l->deleteLater();
|
||||
l->rpcInvalidate();
|
||||
}
|
||||
fileName = QString();
|
||||
modDate = QDateTime();
|
||||
@ -441,6 +446,7 @@ struct DocumentData {
|
||||
modDate = fileName.isEmpty() ? QDateTime() : QFileInfo(fileName).lastModified();
|
||||
}
|
||||
loader->deleteLater();
|
||||
loader->rpcInvalidate();
|
||||
loader = 0;
|
||||
}
|
||||
|
||||
|
@ -288,6 +288,12 @@ void IntroWidget::keyPressEvent(QKeyEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
void IntroWidget::rpcInvalidate() {
|
||||
if (phone) phone->rpcInvalidate();
|
||||
if (code) code->rpcInvalidate();
|
||||
if (signup) signup->rpcInvalidate();
|
||||
}
|
||||
|
||||
IntroWidget::~IntroWidget() {
|
||||
delete steps;
|
||||
delete phone;
|
||||
|
@ -57,6 +57,8 @@ public:
|
||||
|
||||
void finish(const MTPUser &user, const QImage &photo = QImage());
|
||||
|
||||
void rpcInvalidate();
|
||||
|
||||
~IntroWidget();
|
||||
|
||||
public slots:
|
||||
|
@ -756,7 +756,10 @@ void MainWidget::showPeer(const PeerId &peerId, MsgId msgId, bool back, bool for
|
||||
history.showPeer(peerId, msgId, force);
|
||||
if (force || !selectingPeer()) {
|
||||
if (profile) {
|
||||
if (profile) profile->deleteLater();
|
||||
if (profile) {
|
||||
profile->deleteLater();
|
||||
profile->rpcInvalidate();
|
||||
}
|
||||
profile = 0;
|
||||
profileStack.clear();
|
||||
if (!history.peer() || !history.peer()->id) {
|
||||
@ -811,7 +814,10 @@ void MainWidget::showPeerProfile(const PeerData *peer, bool back) {
|
||||
profileStack.push_back(history.peer());
|
||||
}
|
||||
}
|
||||
if (profile) profile->deleteLater();
|
||||
if (profile) {
|
||||
profile->deleteLater();
|
||||
profile->rpcInvalidate();
|
||||
}
|
||||
profile = new ProfileWidget(this, peer);
|
||||
_topBar.show();
|
||||
resizeEvent(0);
|
||||
|
@ -1034,7 +1034,8 @@ void MTProtoConnectionPrivate::createConn() {
|
||||
MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConnection *owner, MTPSessionData *data, uint32 _dc)
|
||||
: QObject(0)
|
||||
, _state(MTProtoConnection::Disconnected)
|
||||
, dc(_dc)
|
||||
, _needSessionReset(false)
|
||||
, dc(_dc)
|
||||
, _owner(owner)
|
||||
, conn(0)
|
||||
, retryTimeout(1)
|
||||
@ -1137,7 +1138,118 @@ bool MTProtoConnectionPrivate::setState(int32 state, int32 ifState) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mtpMsgId MTProtoConnectionPrivate::prepareToSend(mtpRequest &request) {
|
||||
void MTProtoConnectionPrivate::resetSession() { // recreate all msg_id and msg_seqno
|
||||
_needSessionReset = false;
|
||||
|
||||
QWriteLocker locker1(sessionData->haveSentMutex());
|
||||
QWriteLocker locker2(sessionData->toResendMutex());
|
||||
QWriteLocker locker3(sessionData->toSendMutex());
|
||||
QWriteLocker locker4(sessionData->wereAckedMutex());
|
||||
mtpRequestMap &haveSent(sessionData->haveSentMap());
|
||||
mtpRequestIdsMap &toResend(sessionData->toResendMap());
|
||||
mtpPreRequestMap &toSend(sessionData->toSendMap());
|
||||
mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap());
|
||||
|
||||
mtpMsgId newId = msgid();
|
||||
mtpRequestMap setSeqNumbers;
|
||||
typedef QMap<mtpMsgId, mtpMsgId> Replaces;
|
||||
Replaces replaces;
|
||||
for (mtpRequestMap::const_iterator i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) {
|
||||
if (!mtpRequestData::isSentContainer(i.value())) {
|
||||
if (!*(mtpMsgId*)(i.value()->constData() + 4)) continue;
|
||||
|
||||
mtpMsgId id = i.key();
|
||||
if (id > newId) {
|
||||
while (true) {
|
||||
if (toResend.constFind(newId) == toResend.cend() && wereAcked.constFind(newId) == wereAcked.cend() && haveSent.constFind(newId) == haveSent.cend()) {
|
||||
break;
|
||||
}
|
||||
mtpMsgId m = msgid();
|
||||
if (m <= newId) break; // wtf
|
||||
|
||||
newId = m;
|
||||
}
|
||||
|
||||
MTP_LOG(dc, ("Replacing msgId %1 to %2!").arg(id).arg(newId));
|
||||
replaces.insert(id, newId);
|
||||
id = newId;
|
||||
*(mtpMsgId*)(i.value()->data() + 4) = id;
|
||||
}
|
||||
setSeqNumbers.insert(id, i.value());
|
||||
}
|
||||
}
|
||||
for (mtpRequestIdsMap::const_iterator i = toResend.cbegin(), e = toResend.cend(); i != e; ++i) { // collect all non-container requests
|
||||
mtpPreRequestMap::const_iterator j = toSend.constFind(i.value());
|
||||
if (j == toSend.cend()) continue;
|
||||
|
||||
if (!mtpRequestData::isSentContainer(j.value())) {
|
||||
if (!*(mtpMsgId*)(j.value()->constData() + 4)) continue;
|
||||
|
||||
mtpMsgId id = i.key();
|
||||
if (id > newId) {
|
||||
while (true) {
|
||||
if (toResend.constFind(newId) == toResend.cend() && wereAcked.constFind(newId) == wereAcked.cend() && haveSent.constFind(newId) == haveSent.cend()) {
|
||||
break;
|
||||
}
|
||||
mtpMsgId m = msgid();
|
||||
if (m <= newId) break; // wtf
|
||||
|
||||
newId = m;
|
||||
}
|
||||
|
||||
MTP_LOG(dc, ("Replacing msgId %1 to %2!").arg(id).arg(newId));
|
||||
replaces.insert(id, newId);
|
||||
id = newId;
|
||||
*(mtpMsgId*)(j.value()->data() + 4) = id;
|
||||
}
|
||||
setSeqNumbers.insert(id, j.value());
|
||||
}
|
||||
}
|
||||
|
||||
uint64 session = MTP::nonce<uint64>();
|
||||
DEBUG_LOG(("MTP Info: creating new session after bad_msg_notification, setting random server_session %1").arg(session));
|
||||
sessionData->setSession(session);
|
||||
|
||||
for (mtpRequestMap::const_iterator i = setSeqNumbers.cbegin(), e = setSeqNumbers.cend(); i != e; ++i) { // generate new seq_numbers
|
||||
bool wasNeedAck = (*(i.value()->data() + 6) & 1);
|
||||
*(i.value()->data() + 6) = sessionData->nextRequestSeqNumber(wasNeedAck);
|
||||
}
|
||||
if (!replaces.isEmpty()) {
|
||||
for (Replaces::const_iterator i = replaces.cbegin(), e = replaces.cend(); i != e; ++i) { // replace msgIds keys in all data structs
|
||||
mtpRequestMap::iterator j = haveSent.find(i.key());
|
||||
if (j != haveSent.cend()) {
|
||||
mtpRequest req = j.value();
|
||||
haveSent.erase(j);
|
||||
haveSent.insert(i.value(), req);
|
||||
}
|
||||
mtpRequestIdsMap::iterator k = toResend.find(i.key());
|
||||
if (k != toResend.cend()) {
|
||||
mtpRequestId req = k.value();
|
||||
toResend.erase(k);
|
||||
toResend.insert(i.value(), req);
|
||||
}
|
||||
k = wereAcked.find(i.key());
|
||||
if (k != wereAcked.cend()) {
|
||||
mtpRequestId req = k.value();
|
||||
wereAcked.erase(k);
|
||||
wereAcked.insert(i.value(), req);
|
||||
}
|
||||
}
|
||||
for (mtpRequestMap::const_iterator i = haveSent.cbegin(), e = haveSent.cend(); i != e; ++i) { // replace msgIds in saved containers
|
||||
if (mtpRequestData::isSentContainer(i.value())) {
|
||||
mtpMsgId *ids = (mtpMsgId *)(i.value()->data() + 8);
|
||||
for (uint32 j = 0, l = (i.value()->size() - 8) >> 1; j < l; ++j) {
|
||||
Replaces::const_iterator k = replaces.constFind(ids[j]);
|
||||
if (k != replaces.cend()) {
|
||||
ids[j] = k.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mtpMsgId MTProtoConnectionPrivate::prepareToSend(mtpRequest &request, mtpMsgId currentLastId) {
|
||||
if (request->size() < 9) return 0;
|
||||
mtpMsgId msgId = *(mtpMsgId*)(request->constData() + 4);
|
||||
if (msgId) { // resending this request
|
||||
@ -1148,12 +1260,75 @@ mtpMsgId MTProtoConnectionPrivate::prepareToSend(mtpRequest &request) {
|
||||
toResend.erase(i);
|
||||
}
|
||||
} else {
|
||||
msgId = *(mtpMsgId*)(request->data() + 4) = msgid();
|
||||
msgId = *(mtpMsgId*)(request->data() + 4) = currentLastId;
|
||||
*(request->data() + 6) = sessionData->nextRequestSeqNumber(mtpRequestData::needAck(request));
|
||||
}
|
||||
return msgId;
|
||||
}
|
||||
|
||||
mtpMsgId MTProtoConnectionPrivate::replaceMsgId(mtpRequest &request, mtpMsgId newId) {
|
||||
if (request->size() < 9) return 0;
|
||||
|
||||
mtpMsgId oldMsgId = *(mtpMsgId*)(request->constData() + 4);
|
||||
if (oldMsgId != newId) {
|
||||
if (oldMsgId) {
|
||||
QWriteLocker locker(sessionData->toResendMutex());
|
||||
// haveSentMutex() and wereAckedMutex() were locked in tryToSend()
|
||||
|
||||
mtpRequestIdsMap &toResend(sessionData->toResendMap());
|
||||
mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap());
|
||||
mtpRequestMap &haveSent(sessionData->haveSentMap());
|
||||
|
||||
while (true) {
|
||||
if (toResend.constFind(newId) == toResend.cend() && wereAcked.constFind(newId) == wereAcked.cend() && haveSent.constFind(newId) == haveSent.cend()) {
|
||||
break;
|
||||
}
|
||||
mtpMsgId m = msgid();
|
||||
if (m <= newId) break; // wtf
|
||||
|
||||
newId = m;
|
||||
}
|
||||
|
||||
mtpRequestIdsMap::iterator i = toResend.find(oldMsgId);
|
||||
if (i != toResend.cend()) {
|
||||
mtpRequestId req = i.value();
|
||||
toResend.erase(i);
|
||||
toResend.insert(newId, req);
|
||||
}
|
||||
|
||||
mtpRequestIdsMap::iterator j = wereAcked.find(oldMsgId);
|
||||
if (j != wereAcked.cend()) {
|
||||
mtpRequestId req = j.value();
|
||||
wereAcked.erase(j);
|
||||
wereAcked.insert(newId, req);
|
||||
}
|
||||
|
||||
mtpRequestMap::iterator k = haveSent.find(oldMsgId);
|
||||
if (k != haveSent.cend()) {
|
||||
mtpRequest req = k.value();
|
||||
haveSent.erase(k);
|
||||
haveSent.insert(newId, req);
|
||||
}
|
||||
|
||||
for (k = haveSent.begin(); k != haveSent.cend(); ++k) {
|
||||
mtpRequest req(k.value());
|
||||
if (mtpRequestData::isSentContainer(req)) {
|
||||
mtpMsgId *ids = (mtpMsgId *)(req->data() + 8);
|
||||
for (uint32 i = 0, l = (req->size() - 8) >> 1; i < l; ++i) {
|
||||
if (ids[i] == oldMsgId) {
|
||||
ids[i] = newId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*(request->data() + 6) = sessionData->nextRequestSeqNumber(mtpRequestData::needAck(request));
|
||||
}
|
||||
*(mtpMsgId*)(request->data() + 4) = newId;
|
||||
}
|
||||
return newId;
|
||||
}
|
||||
|
||||
void MTProtoConnectionPrivate::tryToSend() {
|
||||
if (!conn) return;
|
||||
|
||||
@ -1211,7 +1386,7 @@ void MTProtoConnectionPrivate::tryToSend() {
|
||||
locker1.unlock();
|
||||
}
|
||||
|
||||
mtpMsgId msgId = prepareToSend(toSendRequest);
|
||||
mtpMsgId msgId = prepareToSend(toSendRequest, msgid());
|
||||
if (havePrepend) pingMsgId = msgId;
|
||||
|
||||
if (toSendRequest->requestId) {
|
||||
@ -1237,10 +1412,12 @@ void MTProtoConnectionPrivate::tryToSend() {
|
||||
toSendRequest->push_back(mtpc_msg_container);
|
||||
toSendRequest->push_back(toSendCount);
|
||||
|
||||
QWriteLocker locker2(sessionData->haveSentMutex());
|
||||
mtpMsgId bigMsgId = msgid(); // check for a valid container
|
||||
|
||||
QWriteLocker locker2(sessionData->haveSentMutex()); // the fact of this lock is used in replaceMsgId()
|
||||
mtpRequestMap &haveSent(sessionData->haveSentMap());
|
||||
|
||||
QWriteLocker locker3(sessionData->wereAckedMutex());
|
||||
QWriteLocker locker3(sessionData->wereAckedMutex()); // the fact of this lock is used in replaceMsgId()
|
||||
mtpRequestIdsMap &wereAcked(sessionData->wereAckedMap());
|
||||
|
||||
mtpRequest haveSentIdsWrap(mtpRequestData::prepare(idsWrapSize)); // prepare "request-like" wrap for msgId vector
|
||||
@ -1249,7 +1426,9 @@ void MTProtoConnectionPrivate::tryToSend() {
|
||||
mtpMsgId *haveSentArr = (mtpMsgId*)(haveSentIdsWrap->data() + 8);
|
||||
|
||||
if (havePrepend) {
|
||||
mtpMsgId msgId = prepareToSend(prepend);
|
||||
mtpMsgId msgId = prepareToSend(prepend, bigMsgId);
|
||||
if (msgId > bigMsgId) msgId = replaceMsgId(prepend, bigMsgId);
|
||||
if (msgId >= bigMsgId) bigMsgId = msgid();
|
||||
*(haveSentArr++) = msgId;
|
||||
if (havePrepend) pingMsgId = msgId;
|
||||
|
||||
@ -1261,8 +1440,10 @@ void MTProtoConnectionPrivate::tryToSend() {
|
||||
}
|
||||
for (mtpPreRequestMap::iterator i = toSend.begin(), e = toSend.end(); i != e; ++i) {
|
||||
mtpRequest &req(i.value());
|
||||
mtpMsgId msgId = prepareToSend(req);
|
||||
*(haveSentArr++) = msgId;
|
||||
mtpMsgId msgId = prepareToSend(req, bigMsgId);
|
||||
if (msgId > bigMsgId) msgId = replaceMsgId(req, bigMsgId);
|
||||
if (msgId >= bigMsgId) bigMsgId = msgid();
|
||||
*(haveSentArr++) = msgId;
|
||||
|
||||
if (req->requestId) {
|
||||
if (mtpRequestData::needAck(req)) {
|
||||
@ -1279,7 +1460,7 @@ void MTProtoConnectionPrivate::tryToSend() {
|
||||
memcpy(toSendRequest->data() + from, req->constData() + 4, len * sizeof(mtpPrime));
|
||||
}
|
||||
|
||||
mtpMsgId contMsgId = prepareToSend(toSendRequest);
|
||||
mtpMsgId contMsgId = prepareToSend(toSendRequest, bigMsgId);
|
||||
*(mtpMsgId*)(haveSentIdsWrap->data() + 4) = contMsgId;
|
||||
(*haveSentIdsWrap)[6] = 0; // for container, msDate = 0, seqNo = 0
|
||||
haveSent.insert(contMsgId, haveSentIdsWrap);
|
||||
@ -1372,6 +1553,9 @@ void MTProtoConnectionPrivate::restart(bool maybeBadKey) {
|
||||
}
|
||||
|
||||
doDisconnect();
|
||||
if (_needSessionReset) {
|
||||
resetSession();
|
||||
}
|
||||
restarted = true;
|
||||
if (retryTimer.isActive()) return;
|
||||
|
||||
@ -1564,7 +1748,9 @@ void MTProtoConnectionPrivate::handleReceived() {
|
||||
int32 res = 1; // if no need to handle, then succeed
|
||||
end = data + 8 + (msgLen >> 2);
|
||||
const mtpPrime *sfrom(data + 4);
|
||||
MTP_LOG(dc, ("Recv: ") + mtpTextSerialize(sfrom, end, mtpc_core_message));
|
||||
if (cDebug()) {
|
||||
MTP_LOG(dc, ("Recv: ") + mtpTextSerialize(sfrom, end, mtpc_core_message));
|
||||
}
|
||||
|
||||
bool needToHandle = false;
|
||||
{
|
||||
@ -1606,6 +1792,7 @@ void MTProtoConnectionPrivate::handleReceived() {
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
_needSessionReset = (res < -1);
|
||||
return restart();
|
||||
}
|
||||
|
||||
@ -1714,29 +1901,71 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
|
||||
const MTPDbad_msg_notification &data(msg.c_bad_msg_notification());
|
||||
LOG(("Message Info: bad message notification received (error_code %3) for msg_id = %1, seq_no = %2").arg(data.vbad_msg_id.v).arg(data.vbad_msg_seqno.v).arg(data.verror_code.v));
|
||||
|
||||
bool needResend = (data.verror_code.v == 16 || data.verror_code.v == 17); // bad msg_id
|
||||
|
||||
mtpMsgId resendId = data.vbad_msg_id.v;
|
||||
if (!wasSent(resendId)) {
|
||||
DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(resendId));
|
||||
return (badTime ? 0 : 1);
|
||||
}
|
||||
int32 errorCode = data.verror_code.v;
|
||||
if (errorCode == 16 || errorCode == 17 || errorCode == 32 || errorCode == 33 || errorCode == 64) { // can handle
|
||||
bool needResend = (errorCode == 16 || errorCode == 17); // bad msg_id
|
||||
if (errorCode == 64) { // bad container!
|
||||
needResend = true;
|
||||
if (cDebug()) {
|
||||
mtpRequest request;
|
||||
{
|
||||
QWriteLocker locker(sessionData->haveSentMutex());
|
||||
mtpRequestMap &haveSent(sessionData->haveSentMap());
|
||||
|
||||
if (needResend) { // bad msg_id
|
||||
if (serverSalt) sessionData->setSalt(serverSalt);
|
||||
unixtimeSet(serverTime, true);
|
||||
mtpRequestMap::iterator i = haveSent.find(msgId);
|
||||
if (i == haveSent.end()) {
|
||||
LOG(("Message Error: Container not found!"));
|
||||
}
|
||||
|
||||
DEBUG_LOG(("Message Info: unixtime updated, now %1, resending in container..").arg(serverTime));
|
||||
|
||||
resend(resendId, 0, true);
|
||||
} else {
|
||||
if (badTime) {
|
||||
if (serverSalt) sessionData->setSalt(serverSalt);
|
||||
unixtimeSet(serverTime);
|
||||
badTime = false;
|
||||
request = i.value();
|
||||
}
|
||||
if (request) {
|
||||
if (mtpRequestData::isSentContainer(request)) {
|
||||
QStringList lst;
|
||||
const mtpMsgId *ids = (const mtpMsgId *)(request->constData() + 8);
|
||||
for (uint32 i = 0, l = (request->size() - 8) >> 1; i < l; ++i) {
|
||||
lst.push_back(QString::number(ids[i]));
|
||||
}
|
||||
LOG(("Message Info: bad container received! messages: %1").arg(lst.join(',')));
|
||||
} else {
|
||||
LOG(("Message Error: bad container received, but request is not a container!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG(("Message Error: bad message notification received, msgId %1, error_code %2").arg(data.vbad_msg_id.v).arg(data.verror_code.v));
|
||||
return -1;
|
||||
|
||||
mtpMsgId resendId = data.vbad_msg_id.v;
|
||||
if (!wasSent(resendId)) {
|
||||
DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(resendId));
|
||||
return (badTime ? 0 : 1);
|
||||
}
|
||||
|
||||
if (needResend) { // bad msg_id
|
||||
if (serverSalt) sessionData->setSalt(serverSalt);
|
||||
unixtimeSet(serverTime, true);
|
||||
|
||||
DEBUG_LOG(("Message Info: unixtime updated, now %1, resending in container..").arg(serverTime));
|
||||
|
||||
resend(resendId, 0, true);
|
||||
} else { // must create new session, because msg_id and msg_seqno are inconsistent
|
||||
if (badTime) {
|
||||
if (serverSalt) sessionData->setSalt(serverSalt);
|
||||
unixtimeSet(serverTime);
|
||||
badTime = false;
|
||||
}
|
||||
LOG(("Message Info: bad message notification received, msgId %1, error_code %2").arg(data.vbad_msg_id.v).arg(errorCode));
|
||||
return -2;
|
||||
}
|
||||
} else { // fatal (except 48, but it must not get here)
|
||||
mtpMsgId resendId = data.vbad_msg_id.v;
|
||||
mtpRequestId requestId = wasSent(resendId);
|
||||
if (requestId) {
|
||||
LOG(("Message Error: bad message notification received, msgId %1, error_code %2, fatal: clearing callbacks").arg(data.vbad_msg_id.v).arg(errorCode));
|
||||
_mtp_internal::clearCallbacksDelayed(RPCCallbackClears(1, RPCCallbackClear(requestId, -errorCode)));
|
||||
} else {
|
||||
DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(resendId));
|
||||
}
|
||||
return (badTime ? 0 : 1);
|
||||
}
|
||||
} return 1;
|
||||
|
||||
@ -1855,8 +2084,13 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
|
||||
}
|
||||
try {
|
||||
const mtpPrime *rFrom = requestBuffer->constData() + 8, *rEnd = requestBuffer->constData() + requestBuffer->size();
|
||||
MTPMsgsStateReq request(rFrom, rEnd);
|
||||
handleMsgsStates(request.c_msgs_state_req().vmsg_ids.c_vector().v, states, toAck);
|
||||
if (*rFrom == mtpc_msgs_state_req) {
|
||||
MTPMsgsStateReq request(rFrom, rEnd);
|
||||
handleMsgsStates(request.c_msgs_state_req().vmsg_ids.c_vector().v, states, toAck);
|
||||
} else {
|
||||
MTPMsgResendReq request(rFrom, rEnd);
|
||||
handleMsgsStates(request.c_msg_resend_req().vmsg_ids.c_vector().v, states, toAck);
|
||||
}
|
||||
} catch(Exception &e) {
|
||||
LOG(("Message Error: could not parse sent msgs_state_req"));
|
||||
throw;
|
||||
@ -2280,7 +2514,6 @@ mtpRequestId MTProtoConnectionPrivate::resend(mtpMsgId msgId, uint64 msCanWait,
|
||||
return sessionData->owner()->resend(msgId, msCanWait, forceContainer, sendMsgStateInfo);
|
||||
}
|
||||
|
||||
|
||||
void MTProtoConnectionPrivate::onConnected() {
|
||||
disconnect(conn, SIGNAL(connected()), this, SLOT(onConnected()));
|
||||
if (!conn->isConnected()) {
|
||||
@ -2874,7 +3107,9 @@ bool MTProtoConnectionPrivate::sendRequest(mtpRequest &request, bool needAnyResp
|
||||
memcpy(request->data() + 2, &session, 2 * sizeof(mtpPrime));
|
||||
|
||||
const mtpPrime *from = request->constData() + 4;
|
||||
MTP_LOG(dc, ("Send: ") + mtpTextSerialize(from, from + messageSize, mtpc_core_message));
|
||||
if (cDebug()) {
|
||||
MTP_LOG(dc, ("Send: ") + mtpTextSerialize(from, from + messageSize, mtpc_core_message));
|
||||
}
|
||||
|
||||
uchar encryptedSHA[20];
|
||||
MTPint128 &msgKey(*(MTPint128*)(encryptedSHA + 4));
|
||||
|
@ -332,7 +332,8 @@ private:
|
||||
|
||||
void createConn();
|
||||
|
||||
mtpMsgId prepareToSend(mtpRequest &request);
|
||||
mtpMsgId prepareToSend(mtpRequest &request, mtpMsgId currentLastId);
|
||||
mtpMsgId replaceMsgId(mtpRequest &request, mtpMsgId newId);
|
||||
|
||||
bool sendRequest(mtpRequest &request, bool needAnyResponse);
|
||||
mtpRequestId wasSent(mtpMsgId msgId) const;
|
||||
@ -347,6 +348,9 @@ private:
|
||||
mutable QReadWriteLock stateMutex;
|
||||
int32 _state;
|
||||
|
||||
bool _needSessionReset;
|
||||
void resetSession();
|
||||
|
||||
uint32 dc;
|
||||
MTProtoConnection *_owner;
|
||||
MTPabstractConnection *conn;
|
||||
|
@ -19,17 +19,17 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
#include "mtproto/mtpRPC.h"
|
||||
|
||||
RPCOwnedDoneHandler::RPCOwnedDoneHandler(RPCSender *owner) : _owner(owner) {
|
||||
_owner->regHandler(this);
|
||||
_owner->_rpcRegHandler(this);
|
||||
}
|
||||
|
||||
RPCOwnedDoneHandler::~RPCOwnedDoneHandler() {
|
||||
if (_owner) _owner->unregHandler(this);
|
||||
if (_owner) _owner->_rpcUnregHandler(this);
|
||||
}
|
||||
|
||||
RPCOwnedFailHandler::RPCOwnedFailHandler(RPCSender *owner) : _owner(owner) {
|
||||
_owner->regHandler(this);
|
||||
_owner->_rpcRegHandler(this);
|
||||
}
|
||||
|
||||
RPCOwnedFailHandler::~RPCOwnedFailHandler() {
|
||||
if (_owner) _owner->unregHandler(this);
|
||||
if (_owner) _owner->_rpcUnregHandler(this);
|
||||
}
|
||||
|
@ -654,9 +654,28 @@ private:
|
||||
|
||||
class RPCSender {
|
||||
typedef QSet<RPCOwnedDoneHandler*> DoneHandlers;
|
||||
DoneHandlers doneHandlers;
|
||||
DoneHandlers _rpcDoneHandlers;
|
||||
typedef QSet<RPCOwnedFailHandler*> FailHandlers;
|
||||
FailHandlers failHandlers;
|
||||
FailHandlers _rpcFailHandlers;
|
||||
|
||||
void _rpcRegHandler(RPCOwnedDoneHandler *handler) {
|
||||
_rpcDoneHandlers.insert(handler);
|
||||
}
|
||||
|
||||
void _rpcUnregHandler(RPCOwnedDoneHandler *handler) {
|
||||
_rpcDoneHandlers.remove(handler);
|
||||
}
|
||||
|
||||
void _rpcRegHandler(RPCOwnedFailHandler *handler) {
|
||||
_rpcFailHandlers.insert(handler);
|
||||
}
|
||||
|
||||
void _rpcUnregHandler(RPCOwnedFailHandler *handler) {
|
||||
_rpcFailHandlers.remove(handler);
|
||||
}
|
||||
|
||||
friend class RPCOwnedDoneHandler;
|
||||
friend class RPCOwnedFailHandler;
|
||||
|
||||
public:
|
||||
|
||||
@ -760,29 +779,19 @@ public:
|
||||
return RPCFailHandlerPtr(new RPCBindedFailHandlerOwnedNo<T, TReceiver>(b, static_cast<TReceiver*>(this), onFail));
|
||||
}
|
||||
|
||||
void regHandler(RPCOwnedDoneHandler *handler) {
|
||||
doneHandlers.insert(handler);
|
||||
}
|
||||
|
||||
void unregHandler(RPCOwnedDoneHandler *handler) {
|
||||
doneHandlers.remove(handler);
|
||||
}
|
||||
|
||||
void regHandler(RPCOwnedFailHandler *handler) {
|
||||
failHandlers.insert(handler);
|
||||
}
|
||||
|
||||
void unregHandler(RPCOwnedFailHandler *handler) {
|
||||
failHandlers.remove(handler);
|
||||
void rpcInvalidate() {
|
||||
for (DoneHandlers::iterator i = _rpcDoneHandlers.begin(), e = _rpcDoneHandlers.end(); i != e; ++i) {
|
||||
(*i)->invalidate();
|
||||
}
|
||||
_rpcDoneHandlers.clear();
|
||||
for (FailHandlers::iterator i = _rpcFailHandlers.begin(), e = _rpcFailHandlers.end(); i != e; ++i) {
|
||||
(*i)->invalidate();
|
||||
}
|
||||
_rpcFailHandlers.clear();
|
||||
}
|
||||
|
||||
~RPCSender() {
|
||||
for (DoneHandlers::iterator i = doneHandlers.begin(), e = doneHandlers.end(); i != e; ++i) {
|
||||
(*i)->invalidate();
|
||||
}
|
||||
for (FailHandlers::iterator i = failHandlers.begin(), e = failHandlers.end(); i != e; ++i) {
|
||||
(*i)->invalidate();
|
||||
}
|
||||
rpcInvalidate();
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -61,8 +61,7 @@ public:
|
||||
void setKey(const mtpAuthKeyPtr &key) {
|
||||
if (authKey != key) {
|
||||
uint64 session;
|
||||
memset_rand(&session, sizeof(uint64));
|
||||
|
||||
memsetrnd(session);
|
||||
authKey = key;
|
||||
|
||||
DEBUG_LOG(("MTP Info: new auth key set in SessionData, id %1, setting random server_session %2").arg(key ? key->keyId() : 0).arg(session));
|
||||
|
@ -95,7 +95,7 @@ bool scaleIs(DBIScale scale) {
|
||||
return cRealScale() == scale || (cRealScale() == dbisAuto && cScreenScale() == scale);
|
||||
}
|
||||
|
||||
SettingsInner::SettingsInner(Settings *parent) : QWidget(parent),
|
||||
SettingsInner::SettingsInner(SettingsWidget *parent) : QWidget(parent),
|
||||
_self(App::self()),
|
||||
|
||||
// profile
|
||||
@ -1126,7 +1126,7 @@ void SettingsInner::onPhotoUpdateDone(PeerId peer) {
|
||||
update();
|
||||
}
|
||||
|
||||
Settings::Settings(Window *parent) : QWidget(parent),
|
||||
SettingsWidget::SettingsWidget(Window *parent) : QWidget(parent),
|
||||
_scroll(this, st::setScroll), _inner(this), _close(this, st::setClose) {
|
||||
_scroll.setWidget(&_inner);
|
||||
|
||||
@ -1138,11 +1138,11 @@ Settings::Settings(Window *parent) : QWidget(parent),
|
||||
showAll();
|
||||
}
|
||||
|
||||
void Settings::onParentResize(const QSize &newSize) {
|
||||
void SettingsWidget::onParentResize(const QSize &newSize) {
|
||||
resize(newSize);
|
||||
}
|
||||
|
||||
void Settings::animShow(const QPixmap &bgAnimCache, bool back) {
|
||||
void SettingsWidget::animShow(const QPixmap &bgAnimCache, bool back) {
|
||||
_bgAnimCache = bgAnimCache;
|
||||
|
||||
anim::stop(this);
|
||||
@ -1159,7 +1159,7 @@ void Settings::animShow(const QPixmap &bgAnimCache, bool back) {
|
||||
show();
|
||||
}
|
||||
|
||||
bool Settings::animStep(float64 ms) {
|
||||
bool SettingsWidget::animStep(float64 ms) {
|
||||
float64 fullDuration = st::introSlideDelta + st::introSlideDuration, dt = ms / fullDuration;
|
||||
float64 dt1 = (ms > st::introSlideDuration) ? 1 : (ms / st::introSlideDuration), dt2 = (ms > st::introSlideDelta) ? (ms - st::introSlideDelta) / (st::introSlideDuration) : 0;
|
||||
bool res = true;
|
||||
@ -1184,7 +1184,7 @@ bool Settings::animStep(float64 ms) {
|
||||
return res;
|
||||
}
|
||||
|
||||
void Settings::paintEvent(QPaintEvent *e) {
|
||||
void SettingsWidget::paintEvent(QPaintEvent *e) {
|
||||
QRect r(e->rect());
|
||||
bool trivial = (rect() == r);
|
||||
|
||||
@ -1202,32 +1202,32 @@ void Settings::paintEvent(QPaintEvent *e) {
|
||||
}
|
||||
}
|
||||
|
||||
void Settings::showAll() {
|
||||
void SettingsWidget::showAll() {
|
||||
_scroll.show();
|
||||
_inner.show();
|
||||
_inner.showAll();
|
||||
_close.show();
|
||||
}
|
||||
|
||||
void Settings::hideAll() {
|
||||
void SettingsWidget::hideAll() {
|
||||
_scroll.hide();
|
||||
_close.hide();
|
||||
}
|
||||
|
||||
void Settings::resizeEvent(QResizeEvent *e) {
|
||||
void SettingsWidget::resizeEvent(QResizeEvent *e) {
|
||||
_scroll.resize(size());
|
||||
_inner.updateSize(width());
|
||||
_close.move(st::setClosePos.x(), st::setClosePos.y());
|
||||
}
|
||||
|
||||
void Settings::dragEnterEvent(QDragEnterEvent *e) {
|
||||
void SettingsWidget::dragEnterEvent(QDragEnterEvent *e) {
|
||||
|
||||
}
|
||||
|
||||
void Settings::dropEvent(QDropEvent *e) {
|
||||
void SettingsWidget::dropEvent(QDropEvent *e) {
|
||||
}
|
||||
|
||||
bool Settings::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const {
|
||||
bool SettingsWidget::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const {
|
||||
if (_inner.getPhotoCoords(photo, x, y, w)) {
|
||||
x += _inner.x();
|
||||
y += _inner.y();
|
||||
@ -1236,14 +1236,18 @@ bool Settings::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) co
|
||||
return false;
|
||||
}
|
||||
|
||||
void Settings::updateOnlineDisplay() {
|
||||
void SettingsWidget::updateOnlineDisplay() {
|
||||
_inner.updateOnlineDisplay();
|
||||
}
|
||||
|
||||
void Settings::updateConnectionType() {
|
||||
void SettingsWidget::updateConnectionType() {
|
||||
_inner.updateConnectionType();
|
||||
}
|
||||
|
||||
Settings::~Settings() {
|
||||
void SettingsWidget::rpcInvalidate() {
|
||||
_inner.rpcInvalidate();
|
||||
}
|
||||
|
||||
SettingsWidget::~SettingsWidget() {
|
||||
if (App::wnd()) App::wnd()->noSettings(this);
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ class SettingsInner : public QWidget, public RPCSender, public Animated {
|
||||
|
||||
public:
|
||||
|
||||
SettingsInner(Settings *parent);
|
||||
SettingsInner(SettingsWidget *parent);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
@ -218,12 +218,12 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class Settings : public QWidget, public Animated {
|
||||
class SettingsWidget : public QWidget, public Animated {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Settings(Window *parent);
|
||||
SettingsWidget(Window *parent);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
@ -238,7 +238,9 @@ public:
|
||||
void updateOnlineDisplay();
|
||||
void updateConnectionType();
|
||||
|
||||
~Settings();
|
||||
void rpcInvalidate();
|
||||
|
||||
~SettingsWidget();
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -129,6 +129,11 @@ inline char *hashMd5Hex(const void *data, uint32 len, void *dest) { // dest = pt
|
||||
|
||||
void memset_rand(void *data, uint32 len);
|
||||
|
||||
template <typename T>
|
||||
inline void memsetrnd(T &value) {
|
||||
memset_rand(&value, sizeof(value));
|
||||
}
|
||||
|
||||
class ReadLockerAttempt {
|
||||
public:
|
||||
|
||||
|
@ -395,18 +395,21 @@ void Window::clearWidgets() {
|
||||
anim::stop(settings);
|
||||
settings->hide();
|
||||
settings->deleteLater();
|
||||
settings->rpcInvalidate();
|
||||
settings = 0;
|
||||
}
|
||||
if (main) {
|
||||
anim::stop(main);
|
||||
main->hide();
|
||||
main->deleteLater();
|
||||
main->rpcInvalidate();
|
||||
main = 0;
|
||||
}
|
||||
if (intro) {
|
||||
anim::stop(intro);
|
||||
intro->hide();
|
||||
intro->deleteLater();
|
||||
intro->rpcInvalidate();
|
||||
intro = 0;
|
||||
}
|
||||
}
|
||||
@ -463,7 +466,7 @@ void Window::showSettings() {
|
||||
anim::stop(main);
|
||||
main->hide();
|
||||
}
|
||||
settings = new Settings(this);
|
||||
settings = new SettingsWidget(this);
|
||||
settings->animShow(bg);
|
||||
|
||||
fixOrder();
|
||||
@ -476,6 +479,7 @@ void Window::hideSettings(bool fast) {
|
||||
anim::stop(settings);
|
||||
settings->hide();
|
||||
settings->deleteLater();
|
||||
settings->rpcInvalidate();
|
||||
settings = 0;
|
||||
if (intro) {
|
||||
intro->show();
|
||||
@ -488,6 +492,7 @@ void Window::hideSettings(bool fast) {
|
||||
anim::stop(settings);
|
||||
settings->hide();
|
||||
settings->deleteLater();
|
||||
settings->rpcInvalidate();
|
||||
settings = 0;
|
||||
if (intro) {
|
||||
intro->animShow(bg, true);
|
||||
@ -533,7 +538,7 @@ MainWidget *Window::mainWidget() {
|
||||
return main;
|
||||
}
|
||||
|
||||
Settings *Window::settingsWidget() {
|
||||
SettingsWidget *Window::settingsWidget() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
@ -798,7 +803,7 @@ void Window::noIntro(IntroWidget *was) {
|
||||
}
|
||||
}
|
||||
|
||||
void Window::noSettings(Settings *was) {
|
||||
void Window::noSettings(SettingsWidget *was) {
|
||||
if (was == settings) {
|
||||
settings = 0;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
|
||||
class TitleWidget;
|
||||
class IntroWidget;
|
||||
class MainWidget;
|
||||
class Settings;
|
||||
class SettingsWidget;
|
||||
class LayerWidget;
|
||||
class BackgroundWidget;
|
||||
class LayeredWidget;
|
||||
@ -165,7 +165,7 @@ public:
|
||||
|
||||
IntroWidget *introWidget();
|
||||
MainWidget *mainWidget();
|
||||
Settings *settingsWidget();
|
||||
SettingsWidget *settingsWidget();
|
||||
|
||||
void showConnecting(const QString &text, const QString &reconnect = QString());
|
||||
void hideConnecting();
|
||||
@ -191,7 +191,7 @@ public:
|
||||
void activate();
|
||||
|
||||
void noIntro(IntroWidget *was);
|
||||
void noSettings(Settings *was);
|
||||
void noSettings(SettingsWidget *was);
|
||||
void noMain(MainWidget *was);
|
||||
void noLayer(LayerWidget *was);
|
||||
void noBox(BackgroundWidget *was);
|
||||
@ -259,7 +259,7 @@ private:
|
||||
TitleWidget *title;
|
||||
IntroWidget *intro;
|
||||
MainWidget *main;
|
||||
Settings *settings;
|
||||
SettingsWidget *settings;
|
||||
LayerWidget *layer;
|
||||
BackgroundWidget *layerBG;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user