LCOV - code coverage report
Current view: top level - src/app - dc_session.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 80.5 % 41 33
Test Date: 2026-04-20 19:54:22 Functions: 100.0 % 3 3

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-3.0-or-later */
       2              : /* Copyright 2026 Peter Csaszar */
       3              : 
       4              : /**
       5              :  * @file app/dc_session.c
       6              :  * @brief Implementation of per-DC session bring-up.
       7              :  */
       8              : 
       9              : #include "app/dc_session.h"
      10              : 
      11              : #include "app/auth_flow.h"
      12              : #include "app/dc_config.h"
      13              : #include "app/session_store.h"
      14              : #include "infrastructure/auth_transfer.h"
      15              : #include "logger.h"
      16              : 
      17              : #include <string.h>
      18              : 
      19           30 : int dc_session_open(int dc_id, DcSession *out) {
      20           30 :     if (!out) return -1;
      21           29 :     memset(out, 0, sizeof(*out));
      22           29 :     out->dc_id = dc_id;
      23           29 :     transport_init(&out->transport);
      24           29 :     mtproto_session_init(&out->session);
      25              : 
      26              :     /* Fast path: reuse a previously persisted auth_key. A cached auth_key
      27              :      * on the server has whatever authorization state was bound to it at
      28              :      * last import, so we treat it as authorized here. A later
      29              :      * AUTH_KEY_UNREGISTERED would force a re-handshake. */
      30           29 :     if (session_store_load_dc(dc_id, &out->session) == 0) {
      31           26 :         const DcEndpoint *ep = dc_lookup(dc_id);
      32           26 :         if (ep && transport_connect(&out->transport, ep->host, ep->port) == 0) {
      33           25 :             out->transport.dc_id = dc_id;
      34           25 :             out->authorized      = 1;
      35           25 :             logger_log(LOG_INFO, "dc_session: reused cached key on DC%d", dc_id);
      36           25 :             return 0;
      37              :         }
      38            1 :         logger_log(LOG_WARN,
      39              :                    "dc_session: cached DC%d unusable, re-handshaking", dc_id);
      40            1 :         transport_close(&out->transport);
      41            1 :         mtproto_session_init(&out->session);
      42              :     }
      43              : 
      44              :     /* Slow path: fresh DH handshake. The new auth_key has no user binding
      45              :      * yet; the caller must run auth.importAuthorization before any
      46              :      * authorized RPC on @p out. */
      47            4 :     if (auth_flow_connect_dc(dc_id, &out->transport, &out->session) != 0) {
      48            4 :         logger_log(LOG_ERROR, "dc_session: handshake failed on DC%d", dc_id);
      49            4 :         return -1;
      50              :     }
      51            0 :     out->authorized = 0;
      52              : 
      53            0 :     if (session_store_save_dc(dc_id, &out->session) != 0) {
      54            0 :         logger_log(LOG_WARN,
      55              :                    "dc_session: could not persist DC%d (non-fatal)", dc_id);
      56              :     }
      57            0 :     return 0;
      58              : }
      59              : 
      60           12 : int dc_session_ensure_authorized(DcSession *sess,
      61              :                                   const ApiConfig *cfg,
      62              :                                   MtProtoSession *home_s,
      63              :                                   Transport *home_t) {
      64           12 :     if (!sess || !cfg || !home_s || !home_t) return -1;
      65           12 :     if (sess->authorized) return 0;
      66              : 
      67            2 :     AuthExported tok = {0};
      68            2 :     RpcError err = {0};
      69            2 :     if (auth_transfer_export(cfg, home_s, home_t,
      70              :                                sess->dc_id, &tok, &err) != 0) {
      71            0 :         logger_log(LOG_ERROR,
      72              :                    "dc_session: export for DC%d failed (%d: %s)",
      73              :                    sess->dc_id, err.error_code, err.error_msg);
      74            0 :         return -1;
      75              :     }
      76            2 :     RpcError ierr = {0};
      77            2 :     if (auth_transfer_import(cfg, &sess->session, &sess->transport,
      78              :                                &tok, &ierr) != 0) {
      79            0 :         logger_log(LOG_ERROR,
      80              :                    "dc_session: import on DC%d failed (%d: %s)",
      81              :                    sess->dc_id, ierr.error_code, ierr.error_msg);
      82            0 :         return -1;
      83              :     }
      84            2 :     sess->authorized = 1;
      85              : 
      86              :     /* Persist the now-authorized auth_key. The server-side binding is
      87              :      * tied to the auth_key itself; on next run we skip the import. */
      88            2 :     (void)session_store_save_dc(sess->dc_id, &sess->session);
      89            2 :     return 0;
      90              : }
      91              : 
      92           26 : void dc_session_close(DcSession *s) {
      93           26 :     if (!s) return;
      94           25 :     transport_close(&s->transport);
      95              : }
        

Generated by: LCOV version 2.0-1