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);
}
示例#3
0
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);
}
示例#8
0
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);
    }
}
示例#10
0
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;
    }
}
示例#14
0
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);
}