LCOV - code coverage report
Current view: top level - tests/unit - test_rpc.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 284 284
Test Date: 2026-04-20 19:54:22 Functions: 100.0 % 22 22

            Line data    Source code
       1              : /**
       2              :  * @file test_rpc.c
       3              :  * @brief Unit tests for MTProto RPC framework.
       4              :  *
       5              :  * Uses mock socket + mock crypto to verify message framing.
       6              :  */
       7              : 
       8              : #include "test_helpers.h"
       9              : #include "mtproto_rpc.h"
      10              : #include "mtproto_session.h"
      11              : #include "tl_serial.h"
      12              : #include "mock_socket.h"
      13              : #include "mock_crypto.h"
      14              : #include "transport.h"
      15              : 
      16              : #include <stdlib.h>
      17              : #include <string.h>
      18              : #include <stdio.h>
      19              : 
      20            1 : void test_rpc_send_unencrypted_framing(void) {
      21            1 :     mock_socket_reset();
      22            1 :     mock_crypto_reset();
      23              :     MtProtoSession s;
      24            1 :     mtproto_session_init(&s);
      25              : 
      26              :     Transport t;
      27            1 :     transport_init(&t);
      28            1 :     transport_connect(&t, "localhost", 443);
      29              : 
      30              :     /* Send a 4-byte payload */
      31            1 :     uint8_t payload[4] = {0x01, 0x02, 0x03, 0x04};
      32            1 :     int rc = rpc_send_unencrypted(&s, &t, payload, 4);
      33            1 :     ASSERT(rc == 0, "send_unencrypted should succeed");
      34              : 
      35              :     /* Verify sent data */
      36            1 :     size_t sent_len = 0;
      37            1 :     (void)mock_socket_get_sent(&sent_len);
      38              :     /* sent_len includes the 0xEF abridged marker (1) + abridged prefix + payload */
      39              :     /* The abridged encoding wraps the RPC frame */
      40            1 :     ASSERT(sent_len > 20, "should have sent more than 20 bytes");
      41              : 
      42            1 :     transport_close(&t);
      43              : }
      44              : 
      45            1 : void test_rpc_recv_unencrypted(void) {
      46            1 :     mock_socket_reset();
      47            1 :     mock_crypto_reset();
      48              :     MtProtoSession s;
      49            1 :     mtproto_session_init(&s);
      50              : 
      51              :     Transport t;
      52            1 :     transport_init(&t);
      53            1 :     transport_connect(&t, "localhost", 443);
      54              : 
      55              :     /* Build a response: auth_key_id(8)=0 + msg_id(8)=99 + len(4)=4 + data(4) */
      56              :     uint8_t response[24];
      57            1 :     memset(response, 0, sizeof(response));
      58              :     /* auth_key_id = 0 (bytes 0-7) */
      59              :     /* msg_id = 99 at byte 8 */
      60            1 :     uint64_t msg_id = 99;
      61            1 :     memcpy(response + 8, &msg_id, 8);
      62              :     /* len = 4 at byte 16 */
      63            1 :     uint32_t data_len = 4;
      64            1 :     memcpy(response + 16, &data_len, 4);
      65              :     /* data at byte 20 */
      66            1 :     response[20] = 0xAA;
      67            1 :     response[21] = 0xBB;
      68            1 :     response[22] = 0xCC;
      69            1 :     response[23] = 0xDD;
      70              : 
      71              :     /* Abridged encode: length in 4-byte units = 24/4 = 6, fits in 1 byte */
      72              :     uint8_t wire[25];
      73            1 :     wire[0] = 6; /* abridged length prefix */
      74            1 :     memcpy(wire + 1, response, 24);
      75            1 :     mock_socket_set_response(wire, 25);
      76              : 
      77              :     /* Clear sent data (abridged marker) */
      78            1 :     mock_socket_clear_sent();
      79              : 
      80              :     /* Now receive */
      81              :     uint8_t out[64];
      82            1 :     size_t out_len = 0;
      83            1 :     int rc = rpc_recv_unencrypted(&s, &t, out, sizeof(out), &out_len);
      84            1 :     ASSERT(rc == 0, "recv_unencrypted should succeed");
      85            1 :     ASSERT(out_len == 4, "payload length should be 4");
      86            1 :     ASSERT(out[0] == 0xAA, "payload byte 0");
      87            1 :     ASSERT(out[1] == 0xBB, "payload byte 1");
      88              : 
      89            1 :     transport_close(&t);
      90              : }
      91              : 
      92            1 : void test_rpc_send_unencrypted_null_checks(void) {
      93              :     MtProtoSession s;
      94            1 :     mtproto_session_init(&s);
      95            1 :     uint8_t data[4] = {0};
      96              : 
      97            1 :     ASSERT(rpc_send_unencrypted(NULL, NULL, data, 4) == -1,
      98              :            "NULL session should fail");
      99            1 :     ASSERT(rpc_send_unencrypted(&s, NULL, data, 4) == -1,
     100              :            "NULL transport should fail");
     101            1 :     ASSERT(rpc_send_unencrypted(&s, (Transport*)(intptr_t)1, NULL, 4) == -1,
     102              :            "NULL data should fail");
     103              : }
     104              : 
     105            1 : void test_rpc_recv_unencrypted_short_packet(void) {
     106            1 :     mock_socket_reset();
     107            1 :     mock_crypto_reset();
     108              :     MtProtoSession s;
     109            1 :     mtproto_session_init(&s);
     110              : 
     111              :     Transport t;
     112            1 :     transport_init(&t);
     113            1 :     transport_connect(&t, "localhost", 443);
     114            1 :     mock_socket_clear_sent();
     115              : 
     116              :     /* Too-short packet (10 bytes) */
     117              :     uint8_t wire[11];
     118            1 :     wire[0] = 3; /* abridged: 3*4=12 bytes, but we only provide 10 */
     119            1 :     uint8_t short_data[10] = {0};
     120            1 :     memcpy(wire + 1, short_data, 10);
     121            1 :     mock_socket_set_response(wire, 11);
     122              : 
     123              :     uint8_t out[64];
     124            1 :     size_t out_len = 0;
     125            1 :     int rc = rpc_recv_unencrypted(&s, &t, out, sizeof(out), &out_len);
     126            1 :     ASSERT(rc == -1, "short packet should fail");
     127              : 
     128            1 :     transport_close(&t);
     129              : }
     130              : 
     131              : /* ---- msg_container tests ---- */
     132              : 
     133            1 : void test_container_not_container(void) {
     134              :     /* Non-container data → single message */
     135            1 :     uint8_t data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
     136              :     RpcContainerMsg msgs[4];
     137            1 :     size_t count = 0;
     138              : 
     139            1 :     int rc = rpc_parse_container(data, sizeof(data), msgs, 4, &count);
     140            1 :     ASSERT(rc == 0, "non-container should succeed");
     141            1 :     ASSERT(count == 1, "count should be 1");
     142            1 :     ASSERT(msgs[0].body_len == sizeof(data), "body_len should match");
     143            1 :     ASSERT(msgs[0].body == data, "body should point to original data");
     144              : }
     145              : 
     146            1 : void test_container_single_msg(void) {
     147              :     /* Container with 1 message */
     148              :     TlWriter w;
     149            1 :     tl_writer_init(&w);
     150            1 :     tl_write_uint32(&w, 0x73f1f8dc); /* msg_container */
     151            1 :     tl_write_uint32(&w, 1);          /* count = 1 */
     152              :     /* msg: msg_id(8) + seqno(4) + body_len(4) + body */
     153            1 :     tl_write_uint64(&w, 12345);      /* msg_id */
     154            1 :     tl_write_uint32(&w, 1);          /* seqno */
     155            1 :     tl_write_uint32(&w, 4);          /* body_len */
     156            1 :     uint8_t body[] = { 0xAA, 0xBB, 0xCC, 0xDD };
     157            1 :     tl_write_raw(&w, body, 4);
     158              : 
     159              :     RpcContainerMsg msgs[4];
     160            1 :     size_t count = 0;
     161            1 :     int rc = rpc_parse_container(w.data, w.len, msgs, 4, &count);
     162            1 :     ASSERT(rc == 0, "single-msg container should succeed");
     163            1 :     ASSERT(count == 1, "count should be 1");
     164            1 :     ASSERT(msgs[0].msg_id == 12345, "msg_id should be 12345");
     165            1 :     ASSERT(msgs[0].seqno == 1, "seqno should be 1");
     166            1 :     ASSERT(msgs[0].body_len == 4, "body_len should be 4");
     167            1 :     ASSERT(memcmp(msgs[0].body, body, 4) == 0, "body should match");
     168              : 
     169            1 :     tl_writer_free(&w);
     170              : }
     171              : 
     172            1 : void test_container_multiple_msgs(void) {
     173              :     /* Container with 3 messages */
     174              :     TlWriter w;
     175            1 :     tl_writer_init(&w);
     176            1 :     tl_write_uint32(&w, 0x73f1f8dc);
     177            1 :     tl_write_uint32(&w, 3);
     178              : 
     179            4 :     for (int i = 0; i < 3; i++) {
     180            3 :         tl_write_uint64(&w, (uint64_t)(100 + i)); /* msg_id */
     181            3 :         tl_write_uint32(&w, (uint32_t)(i * 2));    /* seqno */
     182            3 :         tl_write_uint32(&w, 4);                    /* body_len */
     183            3 :         uint8_t body[4] = { (uint8_t)i, 0, 0, 0 };
     184            3 :         tl_write_raw(&w, body, 4);
     185              :     }
     186              : 
     187              :     RpcContainerMsg msgs[8];
     188            1 :     size_t count = 0;
     189            1 :     int rc = rpc_parse_container(w.data, w.len, msgs, 8, &count);
     190            1 :     ASSERT(rc == 0, "multi-msg container should succeed");
     191            1 :     ASSERT(count == 3, "count should be 3");
     192            1 :     ASSERT(msgs[0].msg_id == 100, "msg 0 id");
     193            1 :     ASSERT(msgs[1].msg_id == 101, "msg 1 id");
     194            1 :     ASSERT(msgs[2].msg_id == 102, "msg 2 id");
     195            1 :     ASSERT(msgs[0].body[0] == 0, "msg 0 body");
     196            1 :     ASSERT(msgs[1].body[0] == 1, "msg 1 body");
     197            1 :     ASSERT(msgs[2].body[0] == 2, "msg 2 body");
     198              : 
     199            1 :     tl_writer_free(&w);
     200              : }
     201              : 
     202            1 : void test_container_too_many_msgs(void) {
     203              :     /* Container with more messages than buffer can hold */
     204              :     TlWriter w;
     205            1 :     tl_writer_init(&w);
     206            1 :     tl_write_uint32(&w, 0x73f1f8dc);
     207            1 :     tl_write_uint32(&w, 5); /* 5 messages */
     208            6 :     for (int i = 0; i < 5; i++) {
     209            5 :         tl_write_uint64(&w, (uint64_t)i);
     210            5 :         tl_write_uint32(&w, 0);
     211            5 :         tl_write_uint32(&w, 4);
     212            5 :         uint8_t body[4] = {0};
     213            5 :         tl_write_raw(&w, body, 4);
     214              :     }
     215              : 
     216              :     RpcContainerMsg msgs[2]; /* only room for 2 */
     217            1 :     size_t count = 0;
     218            1 :     int rc = rpc_parse_container(w.data, w.len, msgs, 2, &count);
     219            1 :     ASSERT(rc == -1, "should fail when too many messages for buffer");
     220            1 :     tl_writer_free(&w);
     221              : }
     222              : 
     223            1 : void test_container_null_args(void) {
     224            1 :     uint8_t data[8] = {0};
     225              :     RpcContainerMsg msgs[2];
     226            1 :     size_t count = 0;
     227            1 :     ASSERT(rpc_parse_container(NULL, 8, msgs, 2, &count) == -1, "NULL data");
     228            1 :     ASSERT(rpc_parse_container(data, 8, NULL, 2, &count) == -1, "NULL msgs");
     229            1 :     ASSERT(rpc_parse_container(data, 8, msgs, 2, NULL) == -1, "NULL count");
     230              : }
     231              : 
     232            1 : void test_container_unaligned_body_len(void) {
     233              :     /* Regression: QA-20 — a container with body_len that is not a multiple
     234              :      * of 4 must be rejected to prevent silent misalignment of subsequent
     235              :      * message reads. */
     236              :     TlWriter w;
     237            1 :     tl_writer_init(&w);
     238            1 :     tl_write_uint32(&w, 0x73f1f8dc); /* msg_container */
     239            1 :     tl_write_uint32(&w, 1);          /* count = 1 */
     240            1 :     tl_write_uint64(&w, 12345);      /* msg_id */
     241            1 :     tl_write_uint32(&w, 1);          /* seqno */
     242            1 :     tl_write_uint32(&w, 3);          /* body_len = 3 (odd, not 4-aligned) */
     243            1 :     uint8_t body[4] = { 0xAA, 0xBB, 0xCC, 0x00 };
     244            1 :     tl_write_raw(&w, body, 4);
     245              : 
     246              :     RpcContainerMsg msgs[4];
     247            1 :     size_t count = 0;
     248            1 :     int rc = rpc_parse_container(w.data, w.len, msgs, 4, &count);
     249            1 :     ASSERT(rc == -1, "container with unaligned body_len must be rejected");
     250              : 
     251            1 :     tl_writer_free(&w);
     252              : }
     253              : 
     254              : /* ---- rpc_result / rpc_error tests ---- */
     255              : 
     256            1 : void test_rpc_unwrap_result(void) {
     257              :     TlWriter w;
     258            1 :     tl_writer_init(&w);
     259            1 :     tl_write_uint32(&w, 0xf35c6d01); /* rpc_result */
     260            1 :     tl_write_uint64(&w, 99887766ULL); /* req_msg_id */
     261            1 :     tl_write_uint32(&w, 0xDEADBEEF); /* inner data (some constructor) */
     262            1 :     tl_write_int32(&w, 42);
     263              : 
     264            1 :     uint64_t req_id = 0;
     265            1 :     const uint8_t *inner = NULL;
     266            1 :     size_t inner_len = 0;
     267            1 :     int rc = rpc_unwrap_result(w.data, w.len, &req_id, &inner, &inner_len);
     268            1 :     ASSERT(rc == 0, "unwrap rpc_result should succeed");
     269            1 :     ASSERT(req_id == 99887766ULL, "req_msg_id should match");
     270            1 :     ASSERT(inner_len == 8, "inner should be 8 bytes (constructor + int32)");
     271              : 
     272              :     uint32_t inner_crc;
     273            1 :     memcpy(&inner_crc, inner, 4);
     274            1 :     ASSERT(inner_crc == 0xDEADBEEF, "inner constructor should match");
     275              : 
     276            1 :     tl_writer_free(&w);
     277              : }
     278              : 
     279            1 : void test_rpc_unwrap_result_not_result(void) {
     280              :     TlWriter w;
     281            1 :     tl_writer_init(&w);
     282            1 :     tl_write_uint32(&w, 0x12345678); /* not rpc_result */
     283            1 :     tl_write_int32(&w, 42);
     284              : 
     285              :     uint64_t req_id;
     286              :     const uint8_t *inner;
     287              :     size_t inner_len;
     288            1 :     int rc = rpc_unwrap_result(w.data, w.len, &req_id, &inner, &inner_len);
     289            1 :     ASSERT(rc == -1, "non-rpc_result should return -1");
     290            1 :     tl_writer_free(&w);
     291              : }
     292              : 
     293            1 : void test_rpc_parse_error_flood_wait(void) {
     294              :     TlWriter w;
     295            1 :     tl_writer_init(&w);
     296            1 :     tl_write_uint32(&w, 0x2144ca19); /* rpc_error */
     297            1 :     tl_write_int32(&w, 420);         /* error_code */
     298            1 :     tl_write_string(&w, "FLOOD_WAIT_30");
     299              : 
     300              :     RpcError err;
     301            1 :     int rc = rpc_parse_error(w.data, w.len, &err);
     302            1 :     ASSERT(rc == 0, "parse flood_wait should succeed");
     303            1 :     ASSERT(err.error_code == 420, "error_code should be 420");
     304            1 :     ASSERT(strcmp(err.error_msg, "FLOOD_WAIT_30") == 0, "error_msg should match");
     305            1 :     ASSERT(err.flood_wait_secs == 30, "flood_wait should be 30 seconds");
     306            1 :     ASSERT(err.migrate_dc == -1, "no migration");
     307              : 
     308            1 :     tl_writer_free(&w);
     309              : }
     310              : 
     311            1 : void test_rpc_parse_error_phone_migrate(void) {
     312              :     TlWriter w;
     313            1 :     tl_writer_init(&w);
     314            1 :     tl_write_uint32(&w, 0x2144ca19);
     315            1 :     tl_write_int32(&w, 303);
     316            1 :     tl_write_string(&w, "PHONE_MIGRATE_4");
     317              : 
     318              :     RpcError err;
     319            1 :     int rc = rpc_parse_error(w.data, w.len, &err);
     320            1 :     ASSERT(rc == 0, "parse phone_migrate should succeed");
     321            1 :     ASSERT(err.error_code == 303, "error_code should be 303");
     322            1 :     ASSERT(err.migrate_dc == 4, "should migrate to DC 4");
     323            1 :     ASSERT(err.flood_wait_secs == 0, "no flood wait");
     324              : 
     325            1 :     tl_writer_free(&w);
     326              : }
     327              : 
     328            1 : void test_rpc_parse_error_file_migrate(void) {
     329              :     TlWriter w;
     330            1 :     tl_writer_init(&w);
     331            1 :     tl_write_uint32(&w, 0x2144ca19);
     332            1 :     tl_write_int32(&w, 303);
     333            1 :     tl_write_string(&w, "FILE_MIGRATE_2");
     334              : 
     335              :     RpcError err;
     336            1 :     int rc = rpc_parse_error(w.data, w.len, &err);
     337            1 :     ASSERT(rc == 0, "parse file_migrate should succeed");
     338            1 :     ASSERT(err.migrate_dc == 2, "should migrate to DC 2");
     339              : 
     340            1 :     tl_writer_free(&w);
     341              : }
     342              : 
     343            1 : void test_rpc_parse_error_session_password(void) {
     344              :     TlWriter w;
     345            1 :     tl_writer_init(&w);
     346            1 :     tl_write_uint32(&w, 0x2144ca19);
     347            1 :     tl_write_int32(&w, 401);
     348            1 :     tl_write_string(&w, "SESSION_PASSWORD_NEEDED");
     349              : 
     350              :     RpcError err;
     351            1 :     int rc = rpc_parse_error(w.data, w.len, &err);
     352            1 :     ASSERT(rc == 0, "parse session_password should succeed");
     353            1 :     ASSERT(err.error_code == 401, "error_code should be 401");
     354            1 :     ASSERT(strcmp(err.error_msg, "SESSION_PASSWORD_NEEDED") == 0, "msg");
     355            1 :     ASSERT(err.migrate_dc == -1, "no migration");
     356            1 :     ASSERT(err.flood_wait_secs == 0, "no flood wait");
     357              : 
     358            1 :     tl_writer_free(&w);
     359              : }
     360              : 
     361            1 : void test_rpc_parse_error_not_error(void) {
     362              :     TlWriter w;
     363            1 :     tl_writer_init(&w);
     364            1 :     tl_write_uint32(&w, 0x12345678); /* not rpc_error */
     365            1 :     tl_write_int32(&w, 200);
     366              : 
     367              :     RpcError err;
     368            1 :     int rc = rpc_parse_error(w.data, w.len, &err);
     369            1 :     ASSERT(rc == -1, "non-rpc_error should return -1");
     370              : 
     371            1 :     tl_writer_free(&w);
     372              : }
     373              : 
     374            1 : void test_rpc_parse_error_null_args(void) {
     375            1 :     uint8_t data[16] = {0};
     376              :     RpcError err;
     377            1 :     ASSERT(rpc_parse_error(NULL, 16, &err) == -1, "NULL data");
     378            1 :     ASSERT(rpc_parse_error(data, 16, NULL) == -1, "NULL err");
     379              : }
     380              : 
     381              : /* ---- rpc_recv_encrypted validation tests ---- */
     382              : 
     383              : /**
     384              :  * Build a minimal valid encrypted wire frame and put it in the mock socket.
     385              :  *
     386              :  * With mock crypto:
     387              :  *  - SHA256 always returns 32 zero bytes, so auth_key_id = 0 and msg_key = 0.
     388              :  *  - AES decrypt is an identity transform, so decrypted == ciphertext.
     389              :  *  - msg_key verification inside mtproto_decrypt passes when msg_key == 0.
     390              :  *
     391              :  * The plaintext layout:
     392              :  *   salt(8) | session_id(8) | msg_id(8) | seq_no(4) | data_len(4) | data(4) | pad(16)
     393              :  *   = 52 bytes total → round to 64 (multiple of 16 for AES).
     394              :  *
     395              :  * @param session_id_override  Value to write into the session_id field of the frame.
     396              :  * @param auth_key_id_override Value to write into the outer auth_key_id field.
     397              :  * @param local_session_id     Session's actual session_id.
     398              :  */
     399            2 : static void build_encrypted_frame(uint64_t auth_key_id_override,
     400              :                                   uint64_t session_id_in_frame,
     401              :                                   Transport *t) {
     402              :     /* Plaintext: must be multiple of 16. We use 64 bytes. */
     403              :     uint8_t plain[64];
     404            2 :     memset(plain, 0, sizeof(plain));
     405              : 
     406            2 :     uint64_t salt = 0;
     407            2 :     memcpy(plain + 0,  &salt,                 8); /* salt */
     408            2 :     memcpy(plain + 8,  &session_id_in_frame,  8); /* session_id */
     409              :     /* msg_id, seq_no, data_len, data, padding stay zero */
     410              : 
     411              :     /* With mock crypto, AES-IGE decrypt is identity: cipher == plain. */
     412              :     uint8_t cipher[64];
     413            2 :     memcpy(cipher, plain, 64);
     414              : 
     415              :     /* Wire frame: auth_key_id(8) + msg_key(16, zeros) + cipher(64) = 88 bytes */
     416              :     uint8_t frame[88];
     417            2 :     memcpy(frame + 0,  &auth_key_id_override, 8);  /* auth_key_id */
     418            2 :     memset(frame + 8,  0, 16);                      /* msg_key = zeros */
     419            2 :     memcpy(frame + 24, cipher, 64);
     420              : 
     421              :     /* Abridged encoding: length in 4-byte units = 88/4 = 22 → fits in 1 byte */
     422              :     uint8_t wire[89];
     423            2 :     wire[0] = 22;
     424            2 :     memcpy(wire + 1, frame, 88);
     425            2 :     mock_socket_set_response(wire, 89);
     426              : 
     427              :     (void)t;
     428            2 : }
     429              : 
     430            1 : void test_recv_encrypted_wrong_auth_key_id(void) {
     431            1 :     mock_socket_reset();
     432            1 :     mock_crypto_reset();
     433              : 
     434              :     MtProtoSession s;
     435            1 :     mtproto_session_init(&s);
     436            1 :     s.has_auth_key = 1;
     437            1 :     memset(s.auth_key, 0, 256);
     438              :     /* With mock SHA256 = zeros, the expected auth_key_id is 0.
     439              :      * We deliberately use a non-zero auth_key_id to trigger rejection. */
     440            1 :     uint64_t wrong_id = 0xDEADBEEFCAFEBABEULL;
     441              : 
     442              :     Transport t;
     443            1 :     transport_init(&t);
     444            1 :     transport_connect(&t, "localhost", 443);
     445            1 :     mock_socket_clear_sent();
     446              : 
     447            1 :     build_encrypted_frame(wrong_id, s.session_id, &t);
     448              : 
     449              :     uint8_t out[256];
     450            1 :     size_t out_len = 0;
     451            1 :     int rc = rpc_recv_encrypted(&s, &t, out, sizeof(out), &out_len);
     452            1 :     ASSERT(rc == -1, "wrong auth_key_id must be rejected");
     453              : 
     454            1 :     transport_close(&t);
     455              : }
     456              : 
     457            1 : void test_recv_encrypted_wrong_session_id(void) {
     458            1 :     mock_socket_reset();
     459            1 :     mock_crypto_reset();
     460              : 
     461              :     MtProtoSession s;
     462            1 :     mtproto_session_init(&s);
     463            1 :     s.has_auth_key = 1;
     464            1 :     memset(s.auth_key, 0, 256);
     465              :     /* Correct auth_key_id = 0 (mock SHA256 zeros); wrong session_id in frame. */
     466            1 :     uint64_t correct_auth_key_id = 0ULL;
     467            1 :     uint64_t wrong_session_id    = s.session_id ^ 0xFFFFFFFFFFFFFFFFULL;
     468              : 
     469              :     Transport t;
     470            1 :     transport_init(&t);
     471            1 :     transport_connect(&t, "localhost", 443);
     472            1 :     mock_socket_clear_sent();
     473              : 
     474            1 :     build_encrypted_frame(correct_auth_key_id, wrong_session_id, &t);
     475              : 
     476              :     uint8_t out[256];
     477            1 :     size_t out_len = 0;
     478            1 :     int rc = rpc_recv_encrypted(&s, &t, out, sizeof(out), &out_len);
     479            1 :     ASSERT(rc == -1, "wrong session_id must be rejected");
     480              : 
     481            1 :     transport_close(&t);
     482              : }
     483              : 
     484            1 : void test_rpc(void) {
     485            1 :     RUN_TEST(test_rpc_send_unencrypted_framing);
     486            1 :     RUN_TEST(test_rpc_recv_unencrypted);
     487            1 :     RUN_TEST(test_rpc_send_unencrypted_null_checks);
     488            1 :     RUN_TEST(test_rpc_recv_unencrypted_short_packet);
     489              : 
     490              :     /* msg_container */
     491            1 :     RUN_TEST(test_container_not_container);
     492            1 :     RUN_TEST(test_container_single_msg);
     493            1 :     RUN_TEST(test_container_multiple_msgs);
     494            1 :     RUN_TEST(test_container_too_many_msgs);
     495            1 :     RUN_TEST(test_container_null_args);
     496            1 :     RUN_TEST(test_container_unaligned_body_len);
     497              : 
     498              :     /* rpc_recv_encrypted validation */
     499            1 :     RUN_TEST(test_recv_encrypted_wrong_auth_key_id);
     500            1 :     RUN_TEST(test_recv_encrypted_wrong_session_id);
     501              : 
     502              :     /* rpc_result / rpc_error */
     503            1 :     RUN_TEST(test_rpc_unwrap_result);
     504            1 :     RUN_TEST(test_rpc_unwrap_result_not_result);
     505            1 :     RUN_TEST(test_rpc_parse_error_flood_wait);
     506            1 :     RUN_TEST(test_rpc_parse_error_phone_migrate);
     507            1 :     RUN_TEST(test_rpc_parse_error_file_migrate);
     508            1 :     RUN_TEST(test_rpc_parse_error_session_password);
     509            1 :     RUN_TEST(test_rpc_parse_error_not_error);
     510            1 :     RUN_TEST(test_rpc_parse_error_null_args);
     511            1 : }
        

Generated by: LCOV version 2.0-1