void Session::workNewSessionCreated(InboundPkt &inboundPkt, qint64 msgId) { qCDebug(TG_CORE_SESSION) << "workNewSessionCreated: msgId =" << QString::number(msgId, 16); mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_NewSessionCreated); inboundPkt.fetchLong(); // first_msg_id; //XXX set is as m_clientLastMsgId?? inboundPkt.fetchLong (); // unique_id m_dc->setServerSalt(inboundPkt.fetchLong()); // server_salt }
void Session::workUpdateShort(InboundPkt &inboundPkt, qint64 msgId) { qCDebug(TG_CORE_SESSION) << "workUpdateShort: msgId =" << QString::number(msgId, 16); mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_UpdateShort); Update update = inboundPkt.fetchUpdate(); qint32 date = inboundPkt.fetchInt(); Q_EMIT updateShort(update, date); }
void Session::workBadMsgNotification(InboundPkt &inboundPkt, qint64 msgId) { mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_BadMsgNotification); qint64 badMsgId = inboundPkt.fetchLong(); qint32 badMsgSeqNo = inboundPkt.fetchInt(); qint32 errorCode = inboundPkt.fetchInt(); qCWarning(TG_CORE_SESSION) << "workBadMsgNotification: badMsgId =" << QString::number(badMsgId, 16) << ", badMsgSeqNo =" << badMsgSeqNo << ", errorCode =" << errorCode; switch (errorCode) { case 16: case 17: case 19: case 32: case 33: case 64: // update time sync difference and reset msgIds counter qint32 serverTime = msgId >> 32LL; mTimeDifference = QDateTime::currentDateTime().toTime_t() - serverTime; qint64 nextId = generatePlainNextMsgId(); if (!m_pendingQueries.contains(nextId)) { m_clientLastMsgId = 0; } // read removing from pending queries, recompose and send the last query Query *q = m_pendingQueries.take(badMsgId); qint64 newMsgId = recomposeAndSendQuery(q); if (newMsgId != 0) { Q_EMIT updateMessageId(badMsgId, newMsgId); } break; } }
void Session::workNewDetailedInfo(InboundPkt &inboundPkt, qint64 msgId) { qCDebug(TG_CORE_SESSION) << "workNewDetailedInfo: msgId =" << QString::number(msgId, 16); mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_MsgNewDetailedInfo); inboundPkt.fetchLong(); // answer_msg_id inboundPkt.fetchInt(); // bytes inboundPkt.fetchInt(); // status }
void Session::rpcExecuteAnswer(InboundPkt &inboundPkt, qint64 msgId) { qint32 op = inboundPkt.prefetchInt(); qCDebug(TG_CORE_SESSION) << "rpcExecuteAnswer(), op =" << QString::number(op, 16); switch (op) { case TL_MsgContainer: workContainer(inboundPkt, msgId); return; case TL_NewSessionCreated: workNewSessionCreated(inboundPkt, msgId); return; case TL_MsgsAck: workMsgsAck(inboundPkt, msgId); return; case TL_RpcResult: workRpcResult(inboundPkt, msgId); return; case TL_UpdateShort: workUpdateShort(inboundPkt, msgId); return; case TL_UpdatesCombined: workUpdatesCombined(inboundPkt, msgId); case TL_Updates: workUpdates(inboundPkt, msgId); return; case TL_UpdateShortMessage: workUpdateShortMessage(inboundPkt, msgId); return; case TL_UpdateShortChatMessage: workUpdateShortChatMessage(inboundPkt, msgId); return; case TL_GZipPacked: workPacked(inboundPkt, msgId); return; case TL_BadServerSalt: workBadServerSalt(inboundPkt, msgId); return; case TL_Pong: workPong(inboundPkt, msgId); return; case TL_MsgDetailedInfo: workDetailedInfo(inboundPkt, msgId); return; case TL_MsgNewDetailedInfo: workNewDetailedInfo(inboundPkt, msgId); return; case TL_UpdatesTooLong: workUpdatesTooLong(inboundPkt, msgId); return; case TL_BadMsgNotification: workBadMsgNotification(inboundPkt, msgId); return; } qCWarning(TG_CORE_SESSION) << "Unknown rpc response message"; inboundPkt.setInPtr(inboundPkt.inEnd()); }
void Session::workRpcResult(InboundPkt &inboundPkt, qint64 msgId) { qCDebug(TG_CORE_SESSION) << "workRpcResult: msgId =" << QString::number(msgId, 16); mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_RpcResult); qint64 id = inboundPkt.fetchLong(); qint32 op = inboundPkt.prefetchInt(); if (op == (qint32)TL_RpcError) { queryOnError(inboundPkt, id); } else { queryOnResult(inboundPkt, id); } }
void Session::workBadServerSalt(InboundPkt &inboundPkt, qint64 msgId) { qCDebug(TG_CORE_SESSION) << "workBadServerSalt: msgId =" << QString::number(msgId, 16); mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_BadServerSalt); qint64 badMsgId = inboundPkt.fetchLong(); inboundPkt.fetchInt(); // badMsgSeqNo inboundPkt.fetchInt(); // errorCode m_dc->setServerSalt(inboundPkt.fetchLong()); // new server_salt // resend the last query Query *q = m_pendingQueries.value(badMsgId); if(q) resendQuery(q); }
void Session::queryOnError(InboundPkt &inboundPkt, qint64 msgId) { mAsserter.check(inboundPkt.fetchInt() == TL_RpcError); qint32 errorCode = inboundPkt.fetchInt(); QString errorText = inboundPkt.fetchQString(); qCDebug(TG_CORE_SESSION) << "error for query" << QString::number(msgId, 16) << " :" << errorCode << " :" << errorText; Query *q = m_pendingQueries.take(msgId); if (!q) { qCWarning(TG_CORE_SESSION) << "No such query"; } else { q->setAcked(true); Q_EMIT errorReceived(q, errorCode, errorText); } }
void Session::workMsgsAck(InboundPkt &inboundPkt, qint64 msgId) { qCDebug(TG_CORE_SESSION) << "workMsgsAck: msgId =" << QString::number(msgId, 16); mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_MsgsAck); mAsserter.check(inboundPkt.fetchInt () == (qint32)TL_Vector); qint32 n = inboundPkt.fetchInt(); for (qint32 i = 0; i < n; i++) { qint64 id = inboundPkt.fetchLong (); Query *q = m_pendingQueries.value(id); if(!q) return; Q_ASSERT(q); q->setAcked(true); } }
void Session::workBadServerSalt(InboundPkt &inboundPkt, qint64 msgId) { Q_UNUSED(msgId) mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_BadServerSalt); qint64 badMsgId = inboundPkt.fetchLong(); qint32 badMsgSeqNo = inboundPkt.fetchInt(); qint32 errorCode = inboundPkt.fetchInt(); qCDebug(TG_CORE_SESSION) << "workBadServerSalt: badMsgId =" << QString::number(badMsgId, 16) << ", badMsgSeqNo =" << badMsgSeqNo << ", errorCode =" << errorCode; m_dc->setServerSalt(inboundPkt.fetchLong()); // new server_salt Query *q = m_pendingQueries.take(badMsgId); qint64 newMsgId = recomposeAndSendQuery(q); if (newMsgId != 0) { Q_EMIT updateMessageId(badMsgId, newMsgId); } }
void Session::workPacked(InboundPkt &inboundPkt, qint64 msgId) { qCDebug(TG_CORE_SESSION) << "workPacked: msgId =" << QString::number(msgId, 16); mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_GZipPacked); static qint32 buf[MAX_PACKED_SIZE >> 2]; qint32 l = inboundPkt.prefetchStrlen(); char *s = inboundPkt.fetchStr(l); qint32 totalOut = Utils::tinflate(s, l, buf, MAX_PACKED_SIZE); qint32 *inPtr = inboundPkt.inPtr(); qint32 *inEnd = inboundPkt.inEnd(); inboundPkt.setInPtr(buf); inboundPkt.setInEnd(inboundPkt.inPtr() + totalOut / 4); qCDebug(TG_CORE_SESSION) << "Unzipped data"; rpcExecuteAnswer(inboundPkt, msgId); inboundPkt.setInPtr(inPtr); //TODO Not sure about this operations of setting inPtr and inEnd after execute answer completion inboundPkt.setInEnd(inEnd); }
void Session::processRpcMessage(InboundPkt &inboundPkt) { EncryptedMsg *enc = (EncryptedMsg *)inboundPkt.buffer(); qint32 len = inboundPkt.length(); const qint32 MINSZ = offsetof (EncryptedMsg, message); const qint32 UNENCSZ = offsetof (EncryptedMsg, serverSalt); qCDebug(TG_CORE_SESSION) << "processRpcMessage(), len=" << len; if(len < MINSZ || (len & 15) != (UNENCSZ & 15)) return; Q_ASSERT(m_dc->authKeyId()); mAsserter.check(enc->authKeyId == m_dc->authKeyId()); //msg_key is used to compute AES key and to decrypt the received message mCrypto->initAESAuth(m_dc->authKey() + 8, enc->msgKey, AES_DECRYPT); qint32 l = mCrypto->padAESDecrypt((char *)&enc->serverSalt, len - UNENCSZ, (char *)&enc->serverSalt, len - UNENCSZ); Q_UNUSED(l); Q_ASSERT(l == len - UNENCSZ); if( !(!(enc->msgLen & 3) && enc->msgLen > 0 && enc->msgLen <= len - MINSZ && len - MINSZ - enc->msgLen <= 12) ) return; //check msg_key is indeed equal to SHA1 of the plaintext obtained after decription (without final padding bytes). static uchar sha1Buffer[20]; SHA1((uchar *)&enc->serverSalt, enc->msgLen + (MINSZ - UNENCSZ), sha1Buffer); Q_ASSERT(!memcmp (&enc->msgKey, sha1Buffer + 4, 16)); if (m_dc->serverSalt() != enc->serverSalt) { m_dc->setServerSalt(enc->serverSalt); } // check time synchronization qint32 serverTime = enc->msgId >> 32LL; qint32 clientTime = QDateTime::currentDateTime().toTime_t() - mTimeDifference; if (clientTime <= serverTime - 30 || clientTime >= serverTime + 300) { qCDebug(TG_CORE_SESSION) << "salt =" << enc->serverSalt << ", sessionId =" << QString::number(enc->sessionId, 16) << ", msgId =" << QString::number(enc->msgId, 16) << ", seqNo =" << enc->seqNo << ", serverTime =" << serverTime << ", clientTime =" << clientTime; QString alert("Received message has too large difference between client and server dates - "); if (clientTime <= serverTime -30) { alert.append("the message has a date at least 30 seconds later in time than current date"); } else { alert.append("the message was sent at least 300 seconds ago"); } qCWarning(TG_CORE_SESSION) << alert; } inboundPkt.setInPtr(enc->message); inboundPkt.setInEnd(inboundPkt.inPtr() + (enc->msgLen / 4)); qCDebug(TG_CORE_SESSION) << "received message id" << QString::number(enc->msgId, 16); Q_ASSERT(l >= (MINSZ - UNENCSZ) + 8); if (enc->msgId & 1) { addToPendingAcks(enc->msgId); } mAsserter.check(m_sessionId == enc->sessionId); rpcExecuteAnswer(inboundPkt, enc->msgId); mAsserter.check(inboundPkt.inPtr() == inboundPkt.inEnd()); }
void Session::workBadMsgNotification(InboundPkt &inboundPkt, qint64 msgId) { mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_BadMsgNotification); qint64 badMsgId = inboundPkt.fetchLong(); qint32 badMsgSeqNo = inboundPkt.fetchInt(); qint32 errorCode = inboundPkt.fetchInt(); qCWarning(TG_CORE_SESSION) << "workBadMsgNotification: msgId =" << badMsgId << ", seqNo =" << badMsgSeqNo << ", errorCode =" << errorCode; switch (errorCode) { case 16: case 17: // update time sync difference and reset msgIds counter qint32 serverTime = msgId >> 32LL; mTimeDifference = QDateTime::currentDateTime().toTime_t() - serverTime; m_clientLastMsgId = 0; // read removing from pending queries, recompose and send the last query Query *q = m_pendingQueries.take(badMsgId); recomposeAndSendQuery(q); break; } }
void Session::queryOnResult(InboundPkt &inboundPkt, qint64 msgId) { qCDebug(TG_CORE_SESSION) << "result for query" << QString::number(msgId, 16); qint32 op = inboundPkt.prefetchInt(); qint32 *inPtr = 0; qint32 *inEnd = 0; if (op == (qint32)TL_GZipPacked) { inboundPkt.fetchInt(); qint32 l = inboundPkt.prefetchStrlen(); char *s = inboundPkt.fetchStr(l); static qint32 packedBuffer[MAX_PACKED_SIZE / 4]; qint32 totalOut = Utils::tinflate (s, l, packedBuffer, MAX_PACKED_SIZE); inPtr = inboundPkt.inPtr(); inEnd = inboundPkt.inEnd(); inboundPkt.setInPtr(packedBuffer); inboundPkt.setInEnd(inboundPkt.inPtr() + totalOut / 4); qCDebug(TG_CORE_SESSION) << "unzipped data"; } Query *q = m_pendingQueries.take(msgId); if (!q) { qCWarning(TG_CORE_SESSION) << "No such query"; inboundPkt.setInPtr(inboundPkt.inEnd()); } else { qCDebug(TG_CORE_SESSION) << "acked query with msgId" << QString::number(msgId, 16) << ",pendingQueries:" << m_pendingQueries.size(); q->setAcked(true); Q_EMIT resultReceived(q, inboundPkt); } if (inPtr) { inboundPkt.setInPtr(inPtr); inboundPkt.setInEnd(inEnd); } }
void Session::workUpdatesTooLong(InboundPkt &inboundPkt, qint64 msgId) { qCDebug(TG_CORE_SESSION) << "workUpdatesTooLong: msgId =" << QString::number(msgId, 16); mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_UpdatesTooLong); Q_EMIT updatesTooLong(); }
void Session::workContainer (InboundPkt &inboundPkt, qint64 msgId) { qCDebug(TG_CORE_SESSION) << "workContainer: msgId =" << QString::number(msgId, 16); mAsserter.check(inboundPkt.fetchInt() == TL_MsgContainer); qint32 n = inboundPkt.fetchInt(); for (qint32 i = 0; i < n; i++) { // message qint64 id = inboundPkt.fetchLong (); // msg_id if (id & 1) { addToPendingAcks(id); } inboundPkt.fetchInt (); // seq_no qint32 bytes = inboundPkt.fetchInt (); qint32 *t = inboundPkt.inEnd(); inboundPkt.setInEnd(inboundPkt.inPtr() + (bytes / 4)); rpcExecuteAnswer(inboundPkt, id); Q_ASSERT (inboundPkt.inPtr() == inboundPkt.inEnd()); inboundPkt.setInEnd(t); } }
void Session::workPong(InboundPkt &inboundPkt, qint64 msgId) { qCDebug(TG_CORE_SESSION) << "workPong: msgId =" << QString::number(msgId, 16); mAsserter.check (inboundPkt.fetchInt() == (qint32)TL_Pong); inboundPkt.fetchLong(); // msg_id inboundPkt.fetchLong(); // ping_id }
void Session::workUpdates(InboundPkt &inboundPkt, qint64 msgId) { qCDebug(TG_CORE_SESSION) << "workUpdates: msgId =" << QString::number(msgId, 16); mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_Updates); //updates mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_Vector); qint32 n = inboundPkt.fetchInt(); QList<Update> updatesList; for (qint32 i = 0; i < n; i++) { updatesList.append(inboundPkt.fetchUpdate()); } //users mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_Vector); n = inboundPkt.fetchInt(); QList<User> users; for (qint32 i = 0; i < n; i++) { users.append(inboundPkt.fetchUser()); } //chats mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_Vector); n = inboundPkt.fetchInt(); QList<Chat> chats; for (qint32 i = 0; i < n; i++) { chats.append(inboundPkt.fetchChat()); } qint32 date = inboundPkt.fetchInt(); qint32 seq = inboundPkt.fetchInt(); Q_EMIT updates(updatesList, users, chats, date, seq); }
void Session::workUpdateShortChatMessage(InboundPkt &inboundPkt, qint64 msgId) { qCDebug(TG_CORE_SESSION) << "workUpdateShortChatMessage: msgId =" << QString::number(msgId, 16); mAsserter.check(inboundPkt.fetchInt() == (qint32)TL_UpdateShortChatMessage); qint32 flags = inboundPkt.fetchInt(); qint32 id = inboundPkt.fetchInt(); qint32 fromId = inboundPkt.fetchInt(); qint32 chatId = inboundPkt.fetchInt(); QString message = inboundPkt.fetchQString(); qint32 pts = inboundPkt.fetchInt(); qint32 pts_count = inboundPkt.fetchInt(); qint32 date = inboundPkt.fetchInt(); qint32 fwd_from_id = 0; qint32 fwd_date = 0; qint32 reply_to_msg_id = 0; bool unread = (flags & 1<<0); bool out = (flags & 1<<1); if(flags & (1<<2)) { fwd_from_id = inboundPkt.fetchInt(); fwd_date = inboundPkt.fetchInt(); } if(flags & (1<<3)) { reply_to_msg_id = inboundPkt.fetchInt(); } Q_EMIT updateShortChatMessage(id, fromId, chatId, message, pts, pts_count, date, fwd_from_id, fwd_date, reply_to_msg_id, unread, out); }