LCOV - code coverage report
Current view: top level - src/core - mtproto_session.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 43 43
Test Date: 2026-04-20 19:54:22 Functions: 100.0 % 7 7

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-3.0-or-later */
       2              : /* Copyright 2026 Peter Csaszar */
       3              : 
       4              : /**
       5              :  * @file mtproto_session.c
       6              :  * @brief MTProto session state management.
       7              :  */
       8              : 
       9              : #include "mtproto_session.h"
      10              : #include "crypto.h"
      11              : #include "raii.h"
      12              : #include "fs_util.h"
      13              : 
      14              : #include <stdio.h>
      15              : #include <stdlib.h>
      16              : #include <string.h>
      17              : #include <time.h>
      18              : 
      19              : /**
      20              :  * @brief Initialize a new MTProto session with a random session_id.
      21              :  * @param s Session to initialize.
      22              :  */
      23         1311 : void mtproto_session_init(MtProtoSession *s) {
      24         1311 :     if (!s) return;
      25         1311 :     memset(s, 0, sizeof(*s));
      26              : 
      27              :     /* Random session_id */
      28         1311 :     crypto_rand_bytes((unsigned char *)&s->session_id, sizeof(s->session_id));
      29              :     /* Ensure non-zero */
      30         1311 :     if (s->session_id == 0) s->session_id = 1;
      31              : }
      32              : 
      33              : /**
      34              :  * @brief Generate the next monotonically increasing message ID.
      35              :  *
      36              :  * Message IDs are approximately unix_time * 2^32, must be divisible by 4
      37              :  * (client→server), and strictly increasing.
      38              :  *
      39              :  * @param s Session.
      40              :  * @return Next message ID, or 0 if s is NULL.
      41              :  */
      42          815 : uint64_t mtproto_session_next_msg_id(MtProtoSession *s) {
      43          815 :     if (!s) return 0;
      44              : 
      45              :     /* msg_id ≈ unix_time * 2^32 with cryptographic randomness in the
      46              :      * lower 32 bits. Must be monotonically increasing and divisible by
      47              :      * 4 for client→server. */
      48          815 :     uint64_t now = (uint64_t)time(NULL);
      49          815 :     uint32_t low = 0;
      50          815 :     crypto_rand_bytes((unsigned char *)&low, sizeof(low));
      51          815 :     uint64_t msg_id = (now << 32) | ((uint64_t)low & 0xFFFFFFFC);
      52              : 
      53              :     /* Ensure monotonic increase */
      54          815 :     if (msg_id <= s->last_msg_id) {
      55          175 :         msg_id = s->last_msg_id + 4;
      56              :     }
      57              : 
      58              :     /* Client→server: msg_id mod 4 == 0 */
      59          815 :     msg_id &= ~(uint64_t)3;
      60              : 
      61          815 :     s->last_msg_id = msg_id;
      62          815 :     return msg_id;
      63              : }
      64              : 
      65              : /**
      66              :  * @brief Get the next sequence number.
      67              :  *
      68              :  * For content-related messages, increments the internal counter.
      69              :  *
      70              :  * @param s Session.
      71              :  * @param content_related 1 for RPC calls, 0 for acks/pings.
      72              :  * @return Next sequence number, or 0 if s is NULL.
      73              :  */
      74          767 : uint32_t mtproto_session_next_seq_no(MtProtoSession *s, int content_related) {
      75          767 :     if (!s) return 0;
      76          767 :     uint32_t result = s->seq_no * 2 + (content_related ? 1 : 0);
      77          767 :     if (content_related) s->seq_no++;
      78          767 :     return result;
      79              : }
      80              : 
      81              : /**
      82              :  * @brief Set the 256-byte authorization key on the session.
      83              :  * @param s   Session.
      84              :  * @param key 256-byte key to copy.
      85              :  */
      86          634 : void mtproto_session_set_auth_key(MtProtoSession *s, const uint8_t key[256]) {
      87          634 :     if (!s || !key) return;
      88          634 :     memcpy(s->auth_key, key, 256);
      89          634 :     s->has_auth_key = 1;
      90              : }
      91              : 
      92              : /**
      93              :  * @brief Set the server salt.
      94              :  * @param s    Session.
      95              :  * @param salt Server salt value.
      96              :  */
      97          629 : void mtproto_session_set_salt(MtProtoSession *s, uint64_t salt) {
      98          629 :     if (!s) return;
      99          629 :     s->server_salt = salt;
     100              : }
     101              : 
     102              : /**
     103              :  * @brief Save the auth key to a file with mode 0600.
     104              :  *
     105              :  * @param s    Session (must have auth_key).
     106              :  * @param path File path to write.
     107              :  * @return 0 on success, -1 on error.
     108              :  */
     109            5 : int mtproto_session_save_auth_key(const MtProtoSession *s, const char *path) {
     110            5 :     if (!s || !path || !s->has_auth_key) return -1;
     111            4 :     RAII_FILE FILE *f = fopen(path, "wb");
     112            2 :     if (!f) return -1;
     113              : 
     114              :     /* Set restrictive permissions (auth key is sensitive) */
     115            1 :     if (fs_ensure_permissions(path, 0600) != 0) {
     116              :         /* Non-fatal but log-worthy — file was already created */
     117              :     }
     118              : 
     119            1 :     size_t written = fwrite(s->auth_key, 1, 256, f);
     120            1 :     return (written == 256) ? 0 : -1;
     121              : }
     122              : 
     123              : /**
     124              :  * @brief Load an auth key from a file.
     125              :  *
     126              :  * @param s    Session (auth_key and has_auth_key will be set on success).
     127              :  * @param path File path to read.
     128              :  * @return 0 on success, -1 on error (file not found, too short, etc.).
     129              :  */
     130            5 : int mtproto_session_load_auth_key(MtProtoSession *s, const char *path) {
     131            5 :     if (!s || !path) return -1;
     132            6 :     RAII_FILE FILE *f = fopen(path, "rb");
     133            3 :     if (!f) return -1;
     134            2 :     size_t nread = fread(s->auth_key, 1, 256, f);
     135            2 :     if (nread != 256) return -1;
     136            1 :     s->has_auth_key = 1;
     137            1 :     return 0;
     138              : }
        

Generated by: LCOV version 2.0-1