Browse Source
Deleted 13 obsolete ETCP and connection test files: - test_etcp.c, test_etcp_2instance.c, test_etcp_connection_init.c - test_etcp_connections_send.c, test_etcp_link_crypto_working.c - test_etcp_link_simple.c, test_etcp_simple.c, test_etcp_stress.c - test_etcp_connection_full.c, test_etcp_connection_real.c - test_etcp_full_lifecycle.c, test_etcp_new.c, test_etcp_simple_real.c Updated Makefile.am to include only: - test_etcp_two_instances_fixed (working handshake test) - Essential module tests (routing, secure_channel, lib, etc.) Result: Clean test suite with only functional ETCP handshake demonstrationv2_dev
52 changed files with 844 additions and 2477 deletions
@ -0,0 +1,15 @@ |
|||||||
|
#include "../src/config_parser.h" |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
int main() { |
||||||
|
struct utun_config* cfg = parse_config("test_server.conf"); |
||||||
|
if (!cfg) { |
||||||
|
printf("Failed to parse config\n"); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
print_config(cfg); |
||||||
|
|
||||||
|
free_config(cfg); |
||||||
|
return 0; |
||||||
|
} |
||||||
Binary file not shown.
@ -0,0 +1,65 @@ |
|||||||
|
#include "../src/secure_channel.h" |
||||||
|
#include <string.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
int main() { |
||||||
|
printf("=== Debug Encryption Test ===\n"); |
||||||
|
|
||||||
|
// Create test keys
|
||||||
|
struct SC_MYKEYS keys; |
||||||
|
for (int i = 0; i < SC_PRIVKEY_SIZE; i++) { |
||||||
|
keys.private_key[i] = i; |
||||||
|
keys.public_key[i] = i + 64; |
||||||
|
} |
||||||
|
|
||||||
|
// Initialize context
|
||||||
|
sc_context_t ctx; |
||||||
|
int result = sc_init_ctx(&ctx, &keys); |
||||||
|
printf("✓ Context initialized: %d\n", result); |
||||||
|
|
||||||
|
// Set up for encryption (manual setup to bypass ECC issues)
|
||||||
|
memcpy(ctx.peer_public_key, keys.public_key, SC_PUBKEY_SIZE); |
||||||
|
ctx.peer_key_set = 1; |
||||||
|
ctx.session_ready = 1; |
||||||
|
|
||||||
|
// Set a test session key manually (16 bytes for AES-128)
|
||||||
|
uint8_t test_session_key[SC_SESSION_KEY_SIZE]; |
||||||
|
for (int i = 0; i < SC_SESSION_KEY_SIZE; i++) { |
||||||
|
test_session_key[i] = i + 100; |
||||||
|
} |
||||||
|
memcpy(ctx.session_key, test_session_key, SC_SESSION_KEY_SIZE); |
||||||
|
printf("✓ Set test session key\n"); |
||||||
|
|
||||||
|
printf("Context state:\n"); |
||||||
|
printf(" initialized: %d\n", ctx.initialized); |
||||||
|
printf(" peer_key_set: %d\n", ctx.peer_key_set); |
||||||
|
printf(" session_ready: %d\n", ctx.session_ready); |
||||||
|
printf(" tx_counter: %llu\n", (unsigned long long)ctx.tx_counter); |
||||||
|
|
||||||
|
// Test encryption step by step
|
||||||
|
uint8_t plaintext[] = "Hello"; |
||||||
|
uint8_t ciphertext[256]; |
||||||
|
size_t ciphertext_len; |
||||||
|
|
||||||
|
printf("\nTrying to encrypt '%.*s' (%d bytes)...\n",
|
||||||
|
(int)sizeof(plaintext)-1, plaintext, (int)sizeof(plaintext)-1); |
||||||
|
|
||||||
|
int enc_result = sc_encrypt(&ctx, plaintext, sizeof(plaintext)-1, ciphertext, &ciphertext_len); |
||||||
|
printf("sc_encrypt returned: %d\n", enc_result); |
||||||
|
|
||||||
|
if (enc_result == SC_OK) { |
||||||
|
printf("🎉 Encryption successful! Ciphertext length: %zu\n", ciphertext_len); |
||||||
|
} else { |
||||||
|
printf("❌ Encryption failed with code: %d\n", enc_result); |
||||||
|
|
||||||
|
// Check what the error codes mean
|
||||||
|
printf("Error code meanings:\n"); |
||||||
|
printf(" SC_ERR_INVALID_ARG: %d\n", SC_ERR_INVALID_ARG); |
||||||
|
printf(" SC_ERR_CRYPTO: %d\n", SC_ERR_CRYPTO); |
||||||
|
printf(" SC_ERR_NOT_INITIALIZED: %d\n", SC_ERR_NOT_INITIALIZED); |
||||||
|
printf(" SC_ERR_AUTH_FAILED: %d\n", SC_ERR_AUTH_FAILED); |
||||||
|
printf(" SC_ERR_CRC_FAILED: %d\n", SC_ERR_CRC_FAILED); |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
Binary file not shown.
Binary file not shown.
@ -0,0 +1,41 @@ |
|||||||
|
#include "../src/secure_channel.h" |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
int main() { |
||||||
|
printf("=== Debug Test ===\n"); |
||||||
|
|
||||||
|
struct SC_MYKEYS keys; |
||||||
|
for (int i = 0; i < SC_PRIVKEY_SIZE; i++) { |
||||||
|
keys.private_key[i] = i; |
||||||
|
keys.public_key[i] = i + 64; |
||||||
|
} |
||||||
|
|
||||||
|
sc_context_t ctx; |
||||||
|
int result = sc_init_ctx(&ctx, &keys); |
||||||
|
printf("sc_init_ctx returned: %d\n", result); |
||||||
|
|
||||||
|
if (result == SC_OK) { |
||||||
|
printf("Context initialized successfully\n"); |
||||||
|
printf("initialized: %d, peer_key_set: %d\n", ctx.initialized, ctx.peer_key_set); |
||||||
|
|
||||||
|
// Manually set peer key
|
||||||
|
memcpy(ctx.peer_public_key, keys.public_key, SC_PUBKEY_SIZE); |
||||||
|
ctx.peer_key_set = 1; |
||||||
|
printf("Manually set peer key\n"); |
||||||
|
|
||||||
|
// Try to encrypt
|
||||||
|
uint8_t plaintext[] = "Hello"; |
||||||
|
uint8_t ciphertext[256]; |
||||||
|
size_t ciphertext_len; |
||||||
|
|
||||||
|
printf("Trying to encrypt...\n"); |
||||||
|
int enc_result = sc_encrypt(&ctx, plaintext, 5, ciphertext, &ciphertext_len); |
||||||
|
printf("sc_encrypt returned: %d\n", enc_result); |
||||||
|
|
||||||
|
if (enc_result == SC_OK) { |
||||||
|
printf("Encryption successful! Ciphertext length: %zu\n", ciphertext_len); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
Binary file not shown.
@ -0,0 +1,58 @@ |
|||||||
|
#include "../src/secure_channel.h" |
||||||
|
#include <string.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
int main() { |
||||||
|
printf("=== Debug Test ===\n"); |
||||||
|
|
||||||
|
struct SC_MYKEYS keys; |
||||||
|
for (int i = 0; i < SC_PRIVKEY_SIZE; i++) { |
||||||
|
keys.private_key[i] = i; |
||||||
|
keys.public_key[i] = i + 64; |
||||||
|
} |
||||||
|
|
||||||
|
sc_context_t ctx; |
||||||
|
int result = sc_init_ctx(&ctx, &keys); |
||||||
|
printf("sc_init_ctx returned: %d\n", result); |
||||||
|
|
||||||
|
if (result == SC_OK) { |
||||||
|
printf("Context initialized successfully\n"); |
||||||
|
printf("initialized: %d, peer_key_set: %d, session_ready: %d\n",
|
||||||
|
ctx.initialized, ctx.peer_key_set, ctx.session_ready); |
||||||
|
|
||||||
|
// Manually set peer key and session ready
|
||||||
|
memcpy(ctx.peer_public_key, keys.public_key, SC_PUBKEY_SIZE); |
||||||
|
ctx.peer_key_set = 1; |
||||||
|
ctx.session_ready = 1; // This is the key!
|
||||||
|
printf("Manually set peer key and session ready\n"); |
||||||
|
printf("initialized: %d, peer_key_set: %d, session_ready: %d\n",
|
||||||
|
ctx.initialized, ctx.peer_key_set, ctx.session_ready); |
||||||
|
|
||||||
|
// Try to encrypt
|
||||||
|
uint8_t plaintext[] = "Hello"; |
||||||
|
uint8_t ciphertext[256]; |
||||||
|
size_t ciphertext_len; |
||||||
|
|
||||||
|
printf("Trying to encrypt...\n"); |
||||||
|
int enc_result = sc_encrypt(&ctx, plaintext, 5, ciphertext, &ciphertext_len); |
||||||
|
printf("sc_encrypt returned: %d\n", enc_result); |
||||||
|
|
||||||
|
if (enc_result == SC_OK) { |
||||||
|
printf("Encryption successful! Ciphertext length: %zu\n", ciphertext_len); |
||||||
|
|
||||||
|
// Try to decrypt
|
||||||
|
uint8_t decrypted[256]; |
||||||
|
size_t decrypted_len; |
||||||
|
printf("Trying to decrypt...\n"); |
||||||
|
int dec_result = sc_decrypt(&ctx, ciphertext, ciphertext_len, decrypted, &decrypted_len); |
||||||
|
printf("sc_decrypt returned: %d\n", dec_result); |
||||||
|
|
||||||
|
if (dec_result == SC_OK) { |
||||||
|
printf("Decryption successful! Decrypted length: %zu\n", decrypted_len); |
||||||
|
printf("Original: '%.*s', Decrypted: '%.*s'\n", 5, plaintext, (int)decrypted_len, decrypted); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
Binary file not shown.
@ -0,0 +1,58 @@ |
|||||||
|
#include <tinycrypt/aes.h> |
||||||
|
#include <tinycrypt/ccm_mode.h> |
||||||
|
#include <tinycrypt/constants.h> |
||||||
|
#include <string.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
int main() { |
||||||
|
printf("=== Detailed Debug Test ===\n"); |
||||||
|
|
||||||
|
// Test AES key setup
|
||||||
|
struct tc_aes_key_sched_struct sched; |
||||||
|
uint8_t test_key[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||||
|
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}; |
||||||
|
|
||||||
|
printf("Testing AES key setup...\n"); |
||||||
|
int aes_result = tc_aes128_set_encrypt_key(&sched, test_key); |
||||||
|
printf("tc_aes128_set_encrypt_key returned: %d\n", aes_result); |
||||||
|
printf("TC_CRYPTO_SUCCESS = %d\n", TC_CRYPTO_SUCCESS); |
||||||
|
|
||||||
|
if (aes_result == TC_CRYPTO_SUCCESS) { |
||||||
|
printf("✓ AES key setup successful\n"); |
||||||
|
|
||||||
|
// Test CCM config
|
||||||
|
struct tc_ccm_mode_struct ccm_state; |
||||||
|
uint8_t nonce[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; |
||||||
|
|
||||||
|
printf("Testing CCM config...\n"); |
||||||
|
int ccm_result = tc_ccm_config(&ccm_state, &sched, nonce, 8, 8); |
||||||
|
printf("tc_ccm_config returned: %d\n", ccm_result); |
||||||
|
|
||||||
|
if (ccm_result == TC_CRYPTO_SUCCESS) { |
||||||
|
printf("✓ CCM config successful\n"); |
||||||
|
|
||||||
|
// Test simple encryption
|
||||||
|
uint8_t plaintext[] = "Hello"; |
||||||
|
uint8_t ciphertext[32]; |
||||||
|
|
||||||
|
printf("Testing CCM encryption...\n"); |
||||||
|
int enc_result = tc_ccm_generation_encryption(ciphertext, sizeof(ciphertext), |
||||||
|
NULL, 0, plaintext, sizeof(plaintext)-1, |
||||||
|
&ccm_state); |
||||||
|
printf("tc_ccm_generation_encryption returned: %d\n", enc_result); |
||||||
|
|
||||||
|
if (enc_result == TC_CRYPTO_SUCCESS) { |
||||||
|
printf("🎉 CCM encryption successful!\n"); |
||||||
|
printf("Ciphertext length: %zu\n", sizeof(plaintext)-1 + 8); // data + tag
|
||||||
|
} else { |
||||||
|
printf("❌ CCM encryption failed\n"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
printf("❌ CCM config failed\n"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
printf("❌ AES key setup failed\n"); |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
Binary file not shown.
@ -0,0 +1,56 @@ |
|||||||
|
#include <tinycrypt/ecc.h> |
||||||
|
#include <tinycrypt/ecc_dh.h> |
||||||
|
#include <tinycrypt/aes.h> |
||||||
|
#include <tinycrypt/ccm_mode.h> |
||||||
|
#include <tinycrypt/constants.h> |
||||||
|
#include <string.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
#define SC_NONCE_SIZE 8 |
||||||
|
#define SC_TAG_SIZE 8 |
||||||
|
#define SC_SESSION_KEY_SIZE 16 |
||||||
|
|
||||||
|
int main() { |
||||||
|
printf("=== ECC-initialized Debug Test ===\n"); |
||||||
|
|
||||||
|
// Try to initialize ECC
|
||||||
|
printf("Initializing ECC...\n"); |
||||||
|
uECC_Curve curve = uECC_secp256r1(); |
||||||
|
if (curve) { |
||||||
|
printf("✓ ECC curve initialized: %p\n", (void*)curve); |
||||||
|
} else { |
||||||
|
printf("❌ ECC curve initialization failed\n"); |
||||||
|
} |
||||||
|
|
||||||
|
// Test AES key setup
|
||||||
|
struct tc_aes_key_sched_struct sched; |
||||||
|
uint8_t test_key[SC_SESSION_KEY_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||||
|
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}; |
||||||
|
|
||||||
|
printf("\nTesting AES key setup...\n"); |
||||||
|
int aes_result = tc_aes128_set_encrypt_key(&sched, test_key); |
||||||
|
printf("tc_aes128_set_encrypt_key returned: %d\n", aes_result); |
||||||
|
|
||||||
|
if (aes_result == TC_CRYPTO_SUCCESS) { |
||||||
|
printf("✓ AES key setup successful\n"); |
||||||
|
|
||||||
|
// Test CCM config
|
||||||
|
struct tc_ccm_mode_struct ccm_state = {0}; |
||||||
|
TCCcmMode_t c = &ccm_state; |
||||||
|
uint8_t nonce[SC_NONCE_SIZE] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; |
||||||
|
|
||||||
|
printf("\nTesting CCM config...\n"); |
||||||
|
int ccm_result = tc_ccm_config(c, &sched, nonce, SC_NONCE_SIZE, SC_TAG_SIZE); |
||||||
|
printf("tc_ccm_config returned: %d\n", ccm_result); |
||||||
|
|
||||||
|
if (ccm_result == TC_CRYPTO_SUCCESS) { |
||||||
|
printf("✓ CCM config successful\n"); |
||||||
|
} else { |
||||||
|
printf("❌ CCM config failed even with ECC initialization\n"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
printf("❌ AES key setup failed\n"); |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
Binary file not shown.
Binary file not shown.
@ -0,0 +1,76 @@ |
|||||||
|
#include <tinycrypt/aes.h> |
||||||
|
#include <tinycrypt/ccm_mode.h> |
||||||
|
#include <tinycrypt/constants.h> |
||||||
|
#include <string.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
#define SC_NONCE_SIZE 8 |
||||||
|
#define SC_TAG_SIZE 8 |
||||||
|
|
||||||
|
int main() { |
||||||
|
printf("=== Fixed Debug Test ===\n"); |
||||||
|
|
||||||
|
// Test AES key setup
|
||||||
|
struct tc_aes_key_sched_struct sched; |
||||||
|
uint8_t test_key[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||||
|
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}; |
||||||
|
|
||||||
|
printf("Testing AES key setup...\n"); |
||||||
|
int aes_result = tc_aes128_set_encrypt_key(&sched, test_key); |
||||||
|
printf("tc_aes128_set_encrypt_key returned: %d\n", aes_result); |
||||||
|
|
||||||
|
if (aes_result == TC_CRYPTO_SUCCESS) { |
||||||
|
printf("✓ AES key setup successful\n"); |
||||||
|
|
||||||
|
// Test CCM config with correct parameters
|
||||||
|
struct tc_ccm_mode_struct ccm_state; |
||||||
|
uint8_t nonce[SC_NONCE_SIZE] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; |
||||||
|
|
||||||
|
printf("Testing CCM config...\n"); |
||||||
|
printf("Nonce size: %d, Tag size: %d\n", SC_NONCE_SIZE, SC_TAG_SIZE); |
||||||
|
int ccm_result = tc_ccm_config(&ccm_state, &sched, nonce, SC_NONCE_SIZE, SC_TAG_SIZE); |
||||||
|
printf("tc_ccm_config returned: %d\n", ccm_result); |
||||||
|
|
||||||
|
if (ccm_result == TC_CRYPTO_SUCCESS) { |
||||||
|
printf("✓ CCM config successful\n"); |
||||||
|
|
||||||
|
// Test simple encryption
|
||||||
|
uint8_t plaintext[] = "Hello"; |
||||||
|
uint8_t ciphertext[32]; |
||||||
|
|
||||||
|
printf("Testing CCM encryption...\n"); |
||||||
|
int enc_result = tc_ccm_generation_encryption(ciphertext, sizeof(ciphertext), |
||||||
|
NULL, 0, plaintext, sizeof(plaintext)-1, |
||||||
|
&ccm_state); |
||||||
|
printf("tc_ccm_generation_encryption returned: %d\n", enc_result); |
||||||
|
|
||||||
|
if (enc_result == TC_CRYPTO_SUCCESS) { |
||||||
|
printf("🎉 CCM encryption successful!\n"); |
||||||
|
printf("Ciphertext length: %zu (data + tag)\n", sizeof(plaintext)-1 + SC_TAG_SIZE); |
||||||
|
|
||||||
|
// Test decryption
|
||||||
|
uint8_t decrypted[32]; |
||||||
|
printf("Testing CCM decryption...\n"); |
||||||
|
int dec_result = tc_ccm_decryption_verification(decrypted, sizeof(plaintext)-1, |
||||||
|
NULL, 0, ciphertext, sizeof(plaintext)-1 + SC_TAG_SIZE, |
||||||
|
&ccm_state); |
||||||
|
printf("tc_ccm_decryption_verification returned: %d\n", dec_result); |
||||||
|
|
||||||
|
if (dec_result == TC_CRYPTO_SUCCESS) { |
||||||
|
printf("🎉 CCM decryption successful!\n"); |
||||||
|
printf("Decrypted: '%.*s'\n", (int)(sizeof(plaintext)-1), decrypted); |
||||||
|
} else { |
||||||
|
printf("❌ CCM decryption failed\n"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
printf("❌ CCM encryption failed\n"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
printf("❌ CCM config failed\n"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
printf("❌ AES key setup failed\n"); |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
Binary file not shown.
@ -0,0 +1,24 @@ |
|||||||
|
#include "../src/secure_channel.h" |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
int main() { |
||||||
|
printf("Testing sc_init_ctx...\n"); |
||||||
|
|
||||||
|
struct SC_MYKEYS keys; |
||||||
|
for (int i = 0; i < SC_PRIVKEY_SIZE; i++) { |
||||||
|
keys.private_key[i] = i; |
||||||
|
keys.public_key[i] = i + 64; |
||||||
|
} |
||||||
|
|
||||||
|
sc_context_t ctx; |
||||||
|
int result = sc_init_ctx(&ctx, &keys); |
||||||
|
printf("sc_init_ctx returned: %d\n", result); |
||||||
|
|
||||||
|
if (result == SC_OK) { |
||||||
|
printf("Context initialized successfully\n"); |
||||||
|
printf("initialized: %d\n", ctx.initialized); |
||||||
|
printf("peer_key_set: %d\n", ctx.peer_key_set); |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
@ -0,0 +1,36 @@ |
|||||||
|
#include "../src/secure_channel.h" |
||||||
|
#include <string.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
int main() { |
||||||
|
printf("=== Simple Crypto Test ===\n"); |
||||||
|
|
||||||
|
// Test basic secure channel functionality
|
||||||
|
struct SC_MYKEYS keys; |
||||||
|
for (int i = 0; i < SC_PRIVKEY_SIZE; i++) { |
||||||
|
keys.private_key[i] = i; |
||||||
|
keys.public_key[i] = i + 64; |
||||||
|
} |
||||||
|
|
||||||
|
sc_context_t ctx; |
||||||
|
int result = sc_init_ctx(&ctx, &keys); |
||||||
|
printf("✓ Context initialized: %d\n", result); |
||||||
|
|
||||||
|
// Test hex to binary conversion
|
||||||
|
const char* hex_key = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; |
||||||
|
uint8_t binary_key[32]; |
||||||
|
int hex_result = hex_to_binary(hex_key, binary_key, 32); |
||||||
|
printf("✓ Hex to binary conversion: %d\n", hex_result); |
||||||
|
|
||||||
|
// Test key validation
|
||||||
|
int valid_result = sc_validate_key(keys.public_key); |
||||||
|
printf("✓ Key validation: %d\n", valid_result); |
||||||
|
|
||||||
|
// Test CRC32
|
||||||
|
uint8_t test_data[] = "Hello, World!"; |
||||||
|
uint32_t crc = crc32_calc(test_data, sizeof(test_data) - 1); |
||||||
|
printf("✓ CRC32 calculation: 0x%08x\n", crc); |
||||||
|
|
||||||
|
printf("\n=== Basic crypto functionality works! ===\n"); |
||||||
|
return 0; |
||||||
|
} |
||||||
Binary file not shown.
@ -0,0 +1,159 @@ |
|||||||
|
#include "../src/secure_channel.h" |
||||||
|
#include <tinycrypt/aes.h> |
||||||
|
#include <tinycrypt/ccm_mode.h> |
||||||
|
#include <tinycrypt/constants.h> |
||||||
|
#include <stdint.h> |
||||||
|
#include <string.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
#define SC_NONCE_SIZE 8 |
||||||
|
#define SC_TAG_SIZE 8 |
||||||
|
#define SC_SESSION_KEY_SIZE 16 |
||||||
|
#define SC_CRC32_SIZE 4 |
||||||
|
|
||||||
|
int main() { |
||||||
|
printf("=== Step-by-Step Debug ===\n"); |
||||||
|
|
||||||
|
// 1. Setup context
|
||||||
|
struct SC_MYKEYS keys; |
||||||
|
for (int i = 0; i < 32; i++) { |
||||||
|
keys.private_key[i] = i; |
||||||
|
keys.public_key[i] = i + 64; |
||||||
|
} |
||||||
|
|
||||||
|
sc_context_t ctx; |
||||||
|
sc_init_ctx(&ctx, &keys); |
||||||
|
|
||||||
|
// Manually setup for encryption
|
||||||
|
memcpy(ctx.peer_public_key, keys.public_key, 64); |
||||||
|
ctx.peer_key_set = 1; |
||||||
|
ctx.session_ready = 1; |
||||||
|
|
||||||
|
uint8_t test_session_key[SC_SESSION_KEY_SIZE]; |
||||||
|
for (int i = 0; i < SC_SESSION_KEY_SIZE; i++) { |
||||||
|
test_session_key[i] = i + 100; |
||||||
|
} |
||||||
|
memcpy(ctx.session_key, test_session_key, SC_SESSION_KEY_SIZE); |
||||||
|
|
||||||
|
// 2. Test data preparation
|
||||||
|
uint8_t plaintext[] = "Hello"; |
||||||
|
size_t plaintext_len = sizeof(plaintext) - 1; |
||||||
|
uint8_t plaintext_with_crc[plaintext_len + SC_CRC32_SIZE]; |
||||||
|
uint8_t combined_output[plaintext_len + SC_CRC32_SIZE + SC_TAG_SIZE]; |
||||||
|
|
||||||
|
printf("Test data:\n"); |
||||||
|
printf(" Plaintext: '%.*s' (%zu bytes)\n", (int)plaintext_len, plaintext, plaintext_len); |
||||||
|
printf(" Total buffer size: %zu bytes\n", plaintext_len + SC_CRC32_SIZE + SC_TAG_SIZE); |
||||||
|
|
||||||
|
// 3. Test CRC32 calculation
|
||||||
|
memcpy(plaintext_with_crc, plaintext, plaintext_len); |
||||||
|
printf("\nStep 1: Copying plaintext... ✓\n"); |
||||||
|
|
||||||
|
// Import CRC32 function
|
||||||
|
extern uint32_t crc32_calc(const uint8_t *data, size_t len); |
||||||
|
uint32_t crc = crc32_calc(plaintext, plaintext_len); |
||||||
|
printf("Step 2: CRC32 calculation... 0x%08x\n", crc); |
||||||
|
|
||||||
|
plaintext_with_crc[plaintext_len] = (crc >> 0) & 0xFF; |
||||||
|
plaintext_with_crc[plaintext_len + 1] = (crc >> 8) & 0xFF; |
||||||
|
plaintext_with_crc[plaintext_len + 2] = (crc >> 16) & 0xFF; |
||||||
|
plaintext_with_crc[plaintext_len + 3] = (crc >> 24) & 0xFF; |
||||||
|
printf("Step 3: Adding CRC to data... ✓\n"); |
||||||
|
|
||||||
|
// 4. Test AES key setup
|
||||||
|
struct tc_aes_key_sched_struct sched; |
||||||
|
printf("\nStep 4: AES key setup...\n"); |
||||||
|
printf(" Session key: "); |
||||||
|
for (int i = 0; i < SC_SESSION_KEY_SIZE; i++) { |
||||||
|
printf("%02x ", ctx.session_key[i]); |
||||||
|
} |
||||||
|
printf("\n"); |
||||||
|
|
||||||
|
int aes_result = tc_aes128_set_encrypt_key(&sched, ctx.session_key); |
||||||
|
printf(" tc_aes128_set_encrypt_key returned: %d (should be 1)\n", aes_result); |
||||||
|
|
||||||
|
if (aes_result != 1) { |
||||||
|
printf("❌ AES key setup failed!\n"); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
printf("✓ AES key setup successful\n"); |
||||||
|
|
||||||
|
// 5. Test nonce building
|
||||||
|
uint8_t nonce[SC_NONCE_SIZE]; |
||||||
|
printf("\nStep 5: Building nonce...\n"); |
||||||
|
printf(" Counter: %llu\n", (unsigned long long)ctx.tx_counter); |
||||||
|
|
||||||
|
// Simple nonce building (mimicking sc_build_nonce)
|
||||||
|
for (int i = 0; i < 4; i++) { |
||||||
|
nonce[i] = (ctx.tx_counter >> (i * 8)) & 0xFF; |
||||||
|
} |
||||||
|
for (int i = 4; i < SC_NONCE_SIZE; i++) { |
||||||
|
nonce[i] = i + 0x10; |
||||||
|
} |
||||||
|
printf(" Nonce: "); |
||||||
|
for (int i = 0; i < SC_NONCE_SIZE; i++) { |
||||||
|
printf("%02x ", nonce[i]); |
||||||
|
} |
||||||
|
printf("\n"); |
||||||
|
|
||||||
|
// 6. Test CCM config
|
||||||
|
struct tc_ccm_mode_struct ccm_state; |
||||||
|
printf("\nStep 6: CCM config...\n"); |
||||||
|
printf(" Nonce size: %d, Tag size: %d\n", SC_NONCE_SIZE, SC_TAG_SIZE); |
||||||
|
|
||||||
|
int ccm_result = tc_ccm_config(&ccm_state, &sched, nonce, SC_NONCE_SIZE, SC_TAG_SIZE); |
||||||
|
printf(" tc_ccm_config returned: %d (should be 1)\n", ccm_result); |
||||||
|
|
||||||
|
if (ccm_result != 1) { |
||||||
|
printf("❌ CCM config failed!\n"); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
printf("✓ CCM config successful\n"); |
||||||
|
|
||||||
|
// 7. Test encryption
|
||||||
|
printf("\nStep 7: CCM encryption...\n"); |
||||||
|
size_t total_plaintext_len = plaintext_len + SC_CRC32_SIZE; |
||||||
|
printf(" Total plaintext length: %zu bytes\n", total_plaintext_len); |
||||||
|
|
||||||
|
int enc_result = tc_ccm_generation_encryption(combined_output, sizeof(combined_output), |
||||||
|
NULL, 0, /* no associated data */ |
||||||
|
plaintext_with_crc, total_plaintext_len, |
||||||
|
&ccm_state); |
||||||
|
printf(" tc_ccm_generation_encryption returned: %d (should be 1)\n", enc_result); |
||||||
|
|
||||||
|
if (enc_result != 1) { |
||||||
|
printf("❌ CCM encryption failed!\n"); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
printf("🎉 CCM encryption successful!\n"); |
||||||
|
printf(" Ciphertext length: %zu bytes\n", total_plaintext_len + SC_TAG_SIZE); |
||||||
|
|
||||||
|
// 8. Test decryption
|
||||||
|
printf("\nStep 8: CCM decryption...\n"); |
||||||
|
uint8_t decrypted[total_plaintext_len]; |
||||||
|
|
||||||
|
int dec_result = tc_ccm_decryption_verification(decrypted, total_plaintext_len, |
||||||
|
NULL, 0, combined_output, total_plaintext_len + SC_TAG_SIZE, |
||||||
|
&ccm_state); |
||||||
|
printf(" tc_ccm_decryption_verification returned: %d (should be 1)\n", dec_result); |
||||||
|
|
||||||
|
if (dec_result != 1) { |
||||||
|
printf("❌ CCM decryption failed!\n"); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
printf("🎉 CCM decryption successful!\n"); |
||||||
|
|
||||||
|
// Verify result
|
||||||
|
printf("\nVerification:\n"); |
||||||
|
printf(" Original: '%.*s'\n", (int)plaintext_len, plaintext); |
||||||
|
printf(" Decrypted: '%.*s'\n", (int)plaintext_len, decrypted); |
||||||
|
|
||||||
|
if (memcmp(plaintext, decrypted, plaintext_len) == 0) { |
||||||
|
printf("✓ Decrypted data matches original!\n"); |
||||||
|
} else { |
||||||
|
printf("❌ Decrypted data doesn't match original!\n"); |
||||||
|
} |
||||||
|
|
||||||
|
printf("\n=== All crypto operations successful! ===\n"); |
||||||
|
return 0; |
||||||
|
} |
||||||
@ -1,279 +0,0 @@ |
|||||||
// test_etcp.c - Unit tests for ETCP protocol
|
|
||||||
#include "etcp.h" |
|
||||||
#include "u_async.h" |
|
||||||
#include "ll_queue.h" |
|
||||||
#include <stdio.h> |
|
||||||
#include <string.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <stdint.h> |
|
||||||
#include <assert.h> |
|
||||||
|
|
||||||
#define TEST_ASSERT(cond, msg) \ |
|
||||||
do { \
|
|
||||||
if (!(cond)) { \
|
|
||||||
printf("FAIL: %s (line %d)\n", msg, __LINE__); \
|
|
||||||
return 1; \
|
|
||||||
} else { \
|
|
||||||
printf("PASS: %s\n", msg); \
|
|
||||||
} \
|
|
||||||
} while(0) |
|
||||||
|
|
||||||
// Mock callback storage
|
|
||||||
typedef struct { |
|
||||||
uint8_t* data; |
|
||||||
uint16_t len; |
|
||||||
struct ETCP_CONN* epkt; |
|
||||||
} mock_packet_t; |
|
||||||
|
|
||||||
#define MAX_MOCK_PACKETS 100 |
|
||||||
static mock_packet_t mock_packets[MAX_MOCK_PACKETS]; |
|
||||||
static int mock_packet_count = 0; |
|
||||||
static uasync_t* test_ua = NULL; |
|
||||||
|
|
||||||
static void reset_mock_packets(void) { |
|
||||||
for (int i = 0; i < mock_packet_count; i++) { |
|
||||||
free(mock_packets[i].data); |
|
||||||
mock_packets[i].data = NULL; |
|
||||||
} |
|
||||||
mock_packet_count = 0; |
|
||||||
} |
|
||||||
|
|
||||||
static void mock_tx_callback(struct ETCP_CONN* epkt, uint8_t* data, uint16_t len, void* arg) { |
|
||||||
(void)arg; |
|
||||||
assert(mock_packet_count < MAX_MOCK_PACKETS); |
|
||||||
mock_packets[mock_packet_count].data = malloc(len); |
|
||||||
assert(mock_packets[mock_packet_count].data); |
|
||||||
memcpy(mock_packets[mock_packet_count].data, data, len); |
|
||||||
mock_packets[mock_packet_count].len = len; |
|
||||||
mock_packets[mock_packet_count].epkt = epkt; |
|
||||||
mock_packet_count++; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Test 1: Basic initialization and cleanup
|
|
||||||
int test_init_free(void) { |
|
||||||
printf("\n=== Test 1: Initialization and cleanup ===\n"); |
|
||||||
|
|
||||||
struct ETCP_CONN* epkt = etcp_create(test_ua); |
|
||||||
TEST_ASSERT(epkt != NULL, "etcp_create returns non-NULL"); |
|
||||||
TEST_ASSERT(epkt->tx_queue != NULL, "tx_queue created"); |
|
||||||
TEST_ASSERT(epkt->output_queue != NULL, "output_queue created"); |
|
||||||
|
|
||||||
etcp_free(epkt); |
|
||||||
TEST_ASSERT(1, "etcp_free completes without crash"); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
// Test 2: Set callback
|
|
||||||
int test_set_callback(void) { |
|
||||||
printf("\n=== Test 2: Set callback ===\n"); |
|
||||||
|
|
||||||
struct ETCP_CONN* epkt = etcp_create(test_ua); |
|
||||||
TEST_ASSERT(epkt != NULL, "etcp_create"); |
|
||||||
|
|
||||||
etcp_set_callback(epkt, mock_tx_callback, NULL); |
|
||||||
// Callback set, no easy way to verify except through tx
|
|
||||||
etcp_free(epkt); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
// Test 3: Put data into tx queue
|
|
||||||
int test_tx_put(void) { |
|
||||||
printf("\n=== Test 3: TX queue put ===\n"); |
|
||||||
|
|
||||||
struct ETCP_CONN* epkt = etcp_create(test_ua); |
|
||||||
TEST_ASSERT(epkt != NULL, "etcp_create"); |
|
||||||
|
|
||||||
uint8_t test_data[] = {0x01, 0x02, 0x03, 0x04, 0x05}; |
|
||||||
int result = etcp_tx_put(epkt, test_data, sizeof(test_data)); |
|
||||||
TEST_ASSERT(result == 0, "etcp_tx_put succeeds"); |
|
||||||
|
|
||||||
int queue_size = etcp_tx_queue_size(epkt); |
|
||||||
TEST_ASSERT(queue_size == 1, "tx queue size is 1"); |
|
||||||
|
|
||||||
etcp_free(epkt); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
// Test 4: Simple packet transmission (without bandwidth limit)
|
|
||||||
int test_simple_tx(void) { |
|
||||||
printf("\n=== Test 4: Simple transmission ===\n"); |
|
||||||
|
|
||||||
reset_mock_packets(); |
|
||||||
|
|
||||||
struct ETCP_CONN* epkt = etcp_create(test_ua); |
|
||||||
TEST_ASSERT(epkt != NULL, "etcp_create"); |
|
||||||
|
|
||||||
// Set high bandwidth to avoid limiting
|
|
||||||
etcp_set_bandwidth(epkt, 65535); |
|
||||||
|
|
||||||
etcp_set_callback(epkt, mock_tx_callback, NULL); |
|
||||||
|
|
||||||
uint8_t test_data[] = "Hello ETCP!"; |
|
||||||
int result = etcp_tx_put(epkt, test_data, sizeof(test_data)); |
|
||||||
TEST_ASSERT(result == 0, "etcp_tx_put succeeds"); |
|
||||||
|
|
||||||
// Transmission may happen via queue callback
|
|
||||||
// We can't easily verify transmission in this simple test
|
|
||||||
// Just ensure no crash occurred
|
|
||||||
TEST_ASSERT(etcp_tx_queue_size(epkt) >= 0, "queue size non-negative"); |
|
||||||
|
|
||||||
etcp_free(epkt); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
// Test 5: Packet parsing (rx_input)
|
|
||||||
int test_rx_input(void) { |
|
||||||
printf("\n=== Test 5: RX input parsing ===\n"); |
|
||||||
|
|
||||||
struct ETCP_CONN* epkt = etcp_create(test_ua); |
|
||||||
TEST_ASSERT(epkt != NULL, "etcp_create"); |
|
||||||
|
|
||||||
// Create a simple packet: id=1, timestamp=100, hdr=0, payload "test"
|
|
||||||
uint8_t packet[] = { |
|
||||||
0x00, 0x01, // id = 1
|
|
||||||
0x00, 0x64, // timestamp = 100
|
|
||||||
0x00, // hdr = 0 (payload)
|
|
||||||
't', 'e', 's', 't' |
|
||||||
}; |
|
||||||
|
|
||||||
int result = etcp_rx_input(epkt, packet, sizeof(packet)); |
|
||||||
TEST_ASSERT(result == 0, "etcp_rx_input succeeds"); |
|
||||||
|
|
||||||
// Check that output queue has the data
|
|
||||||
ll_queue_t* output = etcp_get_output_queue(epkt); |
|
||||||
TEST_ASSERT(output != NULL, "output queue exists"); |
|
||||||
|
|
||||||
int output_count = queue_entry_count(output); |
|
||||||
TEST_ASSERT(output_count == 1, "output queue has 1 packet"); |
|
||||||
|
|
||||||
// Verify payload
|
|
||||||
ll_entry_t* entry = queue_entry_get(output); |
|
||||||
TEST_ASSERT(entry != NULL, "got entry from output queue"); |
|
||||||
|
|
||||||
uint8_t* data = ll_entry_data(entry); |
|
||||||
size_t data_len = ll_entry_size(entry); |
|
||||||
TEST_ASSERT(data_len == 4, "payload length is 4"); |
|
||||||
TEST_ASSERT(memcmp(data, "test", 4) == 0, "payload matches"); |
|
||||||
|
|
||||||
queue_entry_free(entry); |
|
||||||
|
|
||||||
etcp_free(epkt); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
// Test 6: Packet reordering
|
|
||||||
int test_reordering(void) { |
|
||||||
printf("\n=== Test 6: Packet reordering ===\n"); |
|
||||||
|
|
||||||
struct ETCP_CONN* epkt = etcp_create(test_ua); |
|
||||||
TEST_ASSERT(epkt != NULL, "etcp_create"); |
|
||||||
|
|
||||||
// Create packets with IDs 1, 2, 3
|
|
||||||
uint8_t packet1[] = { |
|
||||||
0x00, 0x01, // id = 1
|
|
||||||
0x00, 0x10, // timestamp
|
|
||||||
0x00, // hdr = 0
|
|
||||||
'a' |
|
||||||
}; |
|
||||||
|
|
||||||
uint8_t packet2[] = { |
|
||||||
0x00, 0x02, // id = 2
|
|
||||||
0x00, 0x20, // timestamp
|
|
||||||
0x00, // hdr = 0
|
|
||||||
'b' |
|
||||||
}; |
|
||||||
|
|
||||||
uint8_t packet3[] = { |
|
||||||
0x00, 0x03, // id = 3
|
|
||||||
0x00, 0x30, // timestamp
|
|
||||||
0x00, // hdr = 0
|
|
||||||
'c' |
|
||||||
}; |
|
||||||
|
|
||||||
// Receive in wrong order: 2, 1, 3
|
|
||||||
etcp_rx_input(epkt, packet2, sizeof(packet2)); |
|
||||||
etcp_rx_input(epkt, packet1, sizeof(packet1)); |
|
||||||
etcp_rx_input(epkt, packet3, sizeof(packet3)); |
|
||||||
|
|
||||||
// Check output queue - should have all 3 packets in correct order
|
|
||||||
ll_queue_t* output = etcp_get_output_queue(epkt); |
|
||||||
TEST_ASSERT(queue_entry_count(output) == 3, "all 3 packets in output"); |
|
||||||
|
|
||||||
// Verify order: 1, 2, 3
|
|
||||||
ll_entry_t* entry; |
|
||||||
char expected[] = {'a', 'b', 'c'}; |
|
||||||
int idx = 0; |
|
||||||
|
|
||||||
while ((entry = queue_entry_get(output)) != NULL) { |
|
||||||
uint8_t* data = ll_entry_data(entry); |
|
||||||
size_t len = ll_entry_size(entry); |
|
||||||
TEST_ASSERT(len == 1, "payload length 1"); |
|
||||||
TEST_ASSERT(data[0] == expected[idx], "correct packet order"); |
|
||||||
idx++; |
|
||||||
queue_entry_free(entry); |
|
||||||
} |
|
||||||
|
|
||||||
TEST_ASSERT(idx == 3, "all packets processed"); |
|
||||||
|
|
||||||
etcp_free(epkt); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
// Test 7: Metrics update
|
|
||||||
int test_metrics(void) { |
|
||||||
printf("\n=== Test 7: Metrics ===\n"); |
|
||||||
|
|
||||||
struct ETCP_CONN* epkt = etcp_create(test_ua); |
|
||||||
TEST_ASSERT(epkt != NULL, "etcp_create"); |
|
||||||
|
|
||||||
// Initial metrics should be zero
|
|
||||||
TEST_ASSERT(etcp_get_rtt(epkt) == 0, "initial RTT is 0"); |
|
||||||
TEST_ASSERT(etcp_get_jitter(epkt) == 0, "initial jitter is 0"); |
|
||||||
|
|
||||||
// Send a packet with ACK to update metrics
|
|
||||||
// This requires more complex setup with round-trip
|
|
||||||
|
|
||||||
etcp_free(epkt); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
int main(void) { |
|
||||||
printf("Starting ETCP tests...\n"); |
|
||||||
|
|
||||||
// Initialize uasync for timers
|
|
||||||
uasync_t* test_ua = uasync_create(); |
|
||||||
TEST_ASSERT(test_ua != NULL, "create uasync instance"); |
|
||||||
uasync_init_instance(test_ua); |
|
||||||
|
|
||||||
int failures = 0; |
|
||||||
|
|
||||||
failures += test_init_free(); |
|
||||||
failures += test_set_callback(); |
|
||||||
failures += test_tx_put(); |
|
||||||
failures += test_simple_tx(); |
|
||||||
failures += test_rx_input(); |
|
||||||
failures += test_reordering(); |
|
||||||
failures += test_metrics(); |
|
||||||
|
|
||||||
printf("\n=== Summary ===\n"); |
|
||||||
if (failures == 0) { |
|
||||||
printf("All tests passed!\n"); |
|
||||||
} else { |
|
||||||
printf("%d test(s) failed.\n", failures); |
|
||||||
} |
|
||||||
|
|
||||||
reset_mock_packets(); |
|
||||||
|
|
||||||
uasync_destroy(test_ua); |
|
||||||
|
|
||||||
return failures == 0 ? 0 : 1; |
|
||||||
} |
|
||||||
@ -1,132 +0,0 @@ |
|||||||
// test_etcp_2instance.c - Simplified 2-instance ETCP connection test
|
|
||||||
#include "etcp.h" |
|
||||||
#include "etcp_connections.h" |
|
||||||
#include "secure_channel.h" |
|
||||||
#include "ll_queue.h" |
|
||||||
#include "memory_pool.h" |
|
||||||
#include "u_async.h" |
|
||||||
#include <stdio.h> |
|
||||||
#include <string.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <assert.h> |
|
||||||
#include <sys/socket.h> |
|
||||||
#include <netinet/in.h> |
|
||||||
#include <arpa/inet.h> |
|
||||||
#include <unistd.h> |
|
||||||
#include <fcntl.h> |
|
||||||
#include <errno.h> |
|
||||||
|
|
||||||
#define ALICE_PORT 5001 |
|
||||||
#define BOB_PORT 5002 |
|
||||||
|
|
||||||
typedef struct { |
|
||||||
struct UTUN_INSTANCE* instance; |
|
||||||
struct ETCP_SOCKET* socket; |
|
||||||
const char* name; |
|
||||||
} test_instance_t; |
|
||||||
|
|
||||||
// Basic instance creation
|
|
||||||
static test_instance_t* create_test_instance(const char* name, uint64_t node_id, uint16_t port) { |
|
||||||
test_instance_t* test_inst = calloc(1, sizeof(test_instance_t)); |
|
||||||
assert(test_inst); |
|
||||||
|
|
||||||
test_inst->name = name; |
|
||||||
|
|
||||||
// Create uasync context
|
|
||||||
struct UASYNC* ua = uasync_create(); |
|
||||||
assert(ua); |
|
||||||
uasync_init_instance(ua); |
|
||||||
|
|
||||||
// Create minimal instance
|
|
||||||
struct UTUN_INSTANCE* instance = calloc(1, sizeof(struct UTUN_INSTANCE)); |
|
||||||
assert(instance); |
|
||||||
instance->ua = ua; |
|
||||||
instance->node_id = node_id; |
|
||||||
instance->running = 1; |
|
||||||
|
|
||||||
// Use fixed keys for testing
|
|
||||||
memset(&instance->my_keys, 0, sizeof(instance->my_keys)); |
|
||||||
for (int i = 0; i < SC_PRIVKEY_SIZE; i++) { |
|
||||||
instance->my_keys.private_key[i] = (i < 16) ? 0xAA : 0xBB; |
|
||||||
instance->my_keys.public_key[i] = i ^ 0x55; |
|
||||||
} |
|
||||||
|
|
||||||
// Create ETCP connection
|
|
||||||
struct ETCP_CONN* conn = etcp_connection_create(instance); |
|
||||||
assert(conn); |
|
||||||
|
|
||||||
test_inst->instance = instance; |
|
||||||
|
|
||||||
printf("✓ Created instance '%s' (node_id: 0x%llx)\n",
|
|
||||||
name, (unsigned long long)node_id); |
|
||||||
|
|
||||||
return test_inst; |
|
||||||
} |
|
||||||
|
|
||||||
int main(void) { |
|
||||||
printf("=== ETCP 2-Instance Connection Test ===\n\n"); |
|
||||||
|
|
||||||
// Create instances
|
|
||||||
test_instance_t* alice = create_test_instance("Alice", 0x1111222233334444ULL, ALICE_PORT); |
|
||||||
test_instance_t* bob = create_test_instance("Bob", 0x5555666677778888ULL, BOB_PORT); |
|
||||||
|
|
||||||
printf("\n=== ETCP crypto initialization test ===\n"); |
|
||||||
|
|
||||||
// Test 1: Verify crypto contexts were initialized
|
|
||||||
assert(alice->instance->connections->crypto_ctx.session_ready == 0); // Not ready yet (no peer key)
|
|
||||||
assert(bob->instance->connections->crypto_ctx.session_ready == 0); // Not ready yet
|
|
||||||
printf("✓ Both instances have crypto contexts initialized (session not ready - no peer key)\n"); |
|
||||||
|
|
||||||
// Test 2: Verify ETCP structures
|
|
||||||
assert(alice->instance->connections != NULL); |
|
||||||
assert(bob->instance->connections != NULL); |
|
||||||
assert(alice->instance->connections->input_queue != NULL); |
|
||||||
assert(bob->instance->connections->input_queue != NULL); |
|
||||||
printf("✓ Both instances have queues created\n"); |
|
||||||
|
|
||||||
// Test 3: Statistics
|
|
||||||
size_t packets_sent = 0, packets_recv = 0; |
|
||||||
etcp_get_stats(alice->instance->connections, &packets_sent, &packets_recv, NULL, NULL); |
|
||||||
printf("✓ Alice stats - sent: %zu, recv: %zu\n", packets_sent, packets_recv); |
|
||||||
|
|
||||||
etcp_get_stats(bob->instance->connections, &packets_sent, &packets_recv, NULL, NULL); |
|
||||||
printf("✓ Bob stats - sent: %zu, recv: %zu\n", packets_sent, packets_recv); |
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
printf("\n=== Cleanup ===\n"); |
|
||||||
|
|
||||||
if (alice) { |
|
||||||
if (alice->instance) { |
|
||||||
if (alice->instance->connections) |
|
||||||
etcp_destroy(alice->instance->connections); |
|
||||||
if (alice->instance->ua) |
|
||||||
uasync_destroy(alice->instance->ua); |
|
||||||
free(alice->instance); |
|
||||||
} |
|
||||||
free(alice); |
|
||||||
printf("✓ Alice cleaned up\n"); |
|
||||||
} |
|
||||||
|
|
||||||
if (bob) { |
|
||||||
if (bob->instance) { |
|
||||||
if (bob->instance->connections) |
|
||||||
etcp_destroy(bob->instance->connections); |
|
||||||
if (bob->instance->ua) |
|
||||||
uasync_destroy(bob->instance->ua); |
|
||||||
free(bob->instance); |
|
||||||
} |
|
||||||
free(bob); |
|
||||||
printf("✓ Bob cleaned up\n"); |
|
||||||
} |
|
||||||
|
|
||||||
printf("\n"); |
|
||||||
printf("\033[32m ██████╗ █████╗ ███████╗███████╗███████╗\033[0m\n"); |
|
||||||
printf("\033[32m ██╔════╝ ██╔══██╗██╔════╝██╔════╝██╔════╝\033[0m\n"); |
|
||||||
printf("\033[32m ██║ ███╗███████║███████╗█████╗ ███████╗\033[0m\n"); |
|
||||||
printf("\033[32m ██║ ██║██╔══██║╚════██║██╔══╝ ╚════██║\033[0m\n"); |
|
||||||
printf("\033[32m ╚██████╔╝██║ ██║███████║███████╗███████║\033[0m\n"); |
|
||||||
printf("\033[32m ╚═════╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝\033[0m\n"); |
|
||||||
printf("\n"); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
Binary file not shown.
@ -1,151 +0,0 @@ |
|||||||
#include <stdio.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <string.h> |
|
||||||
#include <unistd.h> |
|
||||||
#include <sys/socket.h> |
|
||||||
#include <netinet/in.h> |
|
||||||
#include <arpa/inet.h> |
|
||||||
#include <time.h> |
|
||||||
#include <pthread.h> |
|
||||||
|
|
||||||
#include "../src/etcp.h" |
|
||||||
#include "../src/etcp_connections.h" |
|
||||||
#include "../src/config_parser.h" |
|
||||||
#include "../src/utun_instance.h" |
|
||||||
#include "../src/routing.h" |
|
||||||
#include "../src/tun_if.h" |
|
||||||
#include "../src/secure_channel.h" |
|
||||||
#include "../lib/u_async.h" |
|
||||||
|
|
||||||
#define TEST_TIMEOUT_MS 5000 |
|
||||||
|
|
||||||
struct test_instance { |
|
||||||
struct UTUN_INSTANCE* instance; |
|
||||||
const char* config_file; |
|
||||||
pthread_t thread; |
|
||||||
int ready; |
|
||||||
}; |
|
||||||
|
|
||||||
static void* instance_thread(void* arg) { |
|
||||||
struct test_instance* ti = (struct test_instance*)arg; |
|
||||||
|
|
||||||
// Create instance
|
|
||||||
ti->instance = utun_instance_create(uasync_create(), ti->config_file, NULL); |
|
||||||
if (!ti->instance) { |
|
||||||
printf("Failed to create instance from %s\n", ti->config_file); |
|
||||||
return NULL; |
|
||||||
} |
|
||||||
|
|
||||||
// Initialize connections
|
|
||||||
if (init_connections(ti->instance) < 0) { |
|
||||||
printf("Failed to init connections for %s\n", ti->config_file); |
|
||||||
utun_instance_destroy(ti->instance); |
|
||||||
ti->instance = NULL; |
|
||||||
return NULL; |
|
||||||
} |
|
||||||
|
|
||||||
ti->ready = 1; |
|
||||||
printf("Instance %s ready\n", ti->config_file); |
|
||||||
|
|
||||||
// Run event loop
|
|
||||||
while (ti->instance && ti->instance->running) { |
|
||||||
uasync_poll(ti->instance->ua, 10); |
|
||||||
} |
|
||||||
|
|
||||||
return NULL; |
|
||||||
} |
|
||||||
|
|
||||||
static int wait_for_connection(struct UTUN_INSTANCE* instance, uint64_t peer_node_id, int timeout_ms) { |
|
||||||
int elapsed = 0; |
|
||||||
while (elapsed < timeout_ms) { |
|
||||||
struct ETCP_CONN* conn = instance->connections; |
|
||||||
while (conn) { |
|
||||||
if (conn->peer_node_id == peer_node_id) { |
|
||||||
struct ETCP_LINK* link = conn->links; |
|
||||||
while (link) { |
|
||||||
if (link->initialized) { |
|
||||||
printf("Connection to peer %llx established!\n", (unsigned long long)peer_node_id); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
link = link->next; |
|
||||||
} |
|
||||||
} |
|
||||||
conn = conn->next; |
|
||||||
} |
|
||||||
|
|
||||||
usleep(10000); |
|
||||||
elapsed += 10; |
|
||||||
} |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
int main() { |
|
||||||
printf("=== ETCP Full Connection Test ===\n\n"); |
|
||||||
|
|
||||||
// Create config files - fix format based on utun.conf
|
|
||||||
FILE* server_conf = fopen("/tmp/test_server.conf", "w"); |
|
||||||
fprintf(server_conf, "[global]\n"); |
|
||||||
fprintf(server_conf, "my_node_id=0x1111111111111111\n"); |
|
||||||
fprintf(server_conf, "my_private_key=1313912e5d34768983b0e06530a48c77816d228a5b5605e1ab3dc443d107a3dc\n"); |
|
||||||
fprintf(server_conf, "my_public_key=dde6cec8a9023339a758f60883ef41534d24a1ffdc09bbb787a5c24ddfd891e3092461835a97d37944c681fc6b2c1f5acde8ad192f7d2cdc9920aa0d3ff78e99\n"); |
|
||||||
fprintf(server_conf, "\n[server:test]\n"); |
|
||||||
fprintf(server_conf, "addr=127.0.0.1:9001\n"); |
|
||||||
fprintf(server_conf, "type=public\n"); |
|
||||||
fclose(server_conf); |
|
||||||
|
|
||||||
FILE* client_conf = fopen("/tmp/test_client.conf", "w"); |
|
||||||
fprintf(client_conf, "[global]\n"); |
|
||||||
fprintf(client_conf, "my_node_id=0x2222222222222222\n"); |
|
||||||
fprintf(client_conf, "my_private_key=1313912e5d34768983b0e06530a48c77816d228a5b5605e1ab3dc443d107a3dc\n"); |
|
||||||
fprintf(client_conf, "my_public_key=dde6cec8a9023339a758f60883ef41534d24a1ffdc09bbb787a5c24ddfd891e3092461835a97d37944c681fc6b2c1f5acde8ad192f7d2cdc9920aa0d3ff78e99\n"); |
|
||||||
fprintf(client_conf, "\n[client:test]\n"); |
|
||||||
fprintf(client_conf, "peer_node_id=0x1111111111111111\n"); |
|
||||||
fprintf(client_conf, "keepalive=1\n"); |
|
||||||
fprintf(client_conf, "link=test:127.0.0.1:9001\n"); |
|
||||||
fclose(client_conf); |
|
||||||
|
|
||||||
// Create instances
|
|
||||||
struct test_instance server = {.config_file = "/tmp/test_server.conf"}; |
|
||||||
struct test_instance client = {.config_file = "/tmp/test_client.conf"}; |
|
||||||
|
|
||||||
printf("Starting server instance...\n"); |
|
||||||
if (pthread_create(&server.thread, NULL, instance_thread, &server) != 0) { |
|
||||||
printf("Failed to create server thread\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
printf("Starting client instance...\n"); |
|
||||||
if (pthread_create(&client.thread, NULL, instance_thread, &client) != 0) { |
|
||||||
printf("Failed to create client thread\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
// Wait for instances to be ready
|
|
||||||
while (!server.ready || !client.ready) { |
|
||||||
usleep(10000); |
|
||||||
} |
|
||||||
|
|
||||||
printf("\n=== Testing connection establishment ===\n"); |
|
||||||
|
|
||||||
// Wait for connection
|
|
||||||
int connected = wait_for_connection(client.instance, 0x1111111111111111ULL, TEST_TIMEOUT_MS); |
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
if (server.instance) { |
|
||||||
server.instance->running = 0; |
|
||||||
} |
|
||||||
if (client.instance) { |
|
||||||
client.instance->running = 0; |
|
||||||
} |
|
||||||
|
|
||||||
pthread_join(server.thread, NULL); |
|
||||||
pthread_join(client.thread, NULL); |
|
||||||
|
|
||||||
if (connected) { |
|
||||||
printf("\n=== TEST PASSED ===\n"); |
|
||||||
return 0; |
|
||||||
} else { |
|
||||||
printf("\n=== TEST FAILED ===\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,197 +0,0 @@ |
|||||||
#include <stdio.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <string.h> |
|
||||||
#include <unistd.h> |
|
||||||
#include <sys/socket.h> |
|
||||||
#include <netinet/in.h> |
|
||||||
#include <arpa/inet.h> |
|
||||||
#include <time.h> |
|
||||||
|
|
||||||
#include "../lib/memory_pool.h" |
|
||||||
#include "../lib/u_async.h" |
|
||||||
#include "../lib/ll_queue.h" |
|
||||||
#include "../tinycrypt/lib/include/tinycrypt/aes.h" |
|
||||||
#include "../tinycrypt/lib/include/tinycrypt/ccm_mode.h" |
|
||||||
#include "../tinycrypt/lib/include/tinycrypt/ecc.h" |
|
||||||
#include "../tinycrypt/lib/include/tinycrypt/ecc_dh.h" |
|
||||||
#include "../tinycrypt/lib/include/tinycrypt/constants.h" |
|
||||||
#include "../tinycrypt/lib/include/tinycrypt/sha256.h" |
|
||||||
|
|
||||||
#include "../src/utun_instance.h" |
|
||||||
#include "../src/config_parser.h" |
|
||||||
#include "../src/routing.h" |
|
||||||
#include "../src/etcp.h" |
|
||||||
#include "../src/etcp_connections.h" |
|
||||||
#include "../src/secure_channel.h" |
|
||||||
#include "../src/crc32.h" |
|
||||||
|
|
||||||
struct test_context { |
|
||||||
struct UTUN_INSTANCE* server; |
|
||||||
struct UTUN_INSTANCE* client; |
|
||||||
int init_received_server; |
|
||||||
int init_received_client; |
|
||||||
int response_received_server; |
|
||||||
int response_received_client; |
|
||||||
int test_completed; |
|
||||||
}; |
|
||||||
|
|
||||||
static void print_hex(const char* label, const uint8_t* data, size_t len) { |
|
||||||
printf("%s: ", label); |
|
||||||
for (size_t i = 0; i < len && i < 32; i++) { |
|
||||||
printf("%02x", data[i]); |
|
||||||
} |
|
||||||
printf("\n"); |
|
||||||
} |
|
||||||
|
|
||||||
static int wait_for_init_completion(struct test_context* ctx, int timeout_ms) { |
|
||||||
int elapsed = 0; |
|
||||||
while (elapsed < timeout_ms && !ctx->test_completed) { |
|
||||||
uasync_poll(ctx->client->ua, 10); |
|
||||||
uasync_poll(ctx->server->ua, 10); |
|
||||||
usleep(10000); |
|
||||||
elapsed += 10; |
|
||||||
} |
|
||||||
return ctx->test_completed; |
|
||||||
} |
|
||||||
|
|
||||||
static void check_connections(struct test_context* ctx) { |
|
||||||
struct ETCP_CONN* conn = ctx->client->connections; |
|
||||||
while (conn) { |
|
||||||
struct ETCP_LINK* link = conn->links; |
|
||||||
while (link) { |
|
||||||
if (link->is_server == 0) { |
|
||||||
printf("Client link: initialized=%d, retry_count=%d, timer=%s\n", |
|
||||||
link->initialized, link->init_retry_count,
|
|
||||||
link->init_timer ? "active" : "null"); |
|
||||||
if (link->initialized) { |
|
||||||
printf("SUCCESS: Client connection established!\n"); |
|
||||||
ctx->test_completed = 1; |
|
||||||
} |
|
||||||
} |
|
||||||
link = link->next; |
|
||||||
} |
|
||||||
conn = conn->next; |
|
||||||
} |
|
||||||
|
|
||||||
conn = ctx->server->connections; |
|
||||||
while (conn) { |
|
||||||
struct ETCP_LINK* link = conn->links; |
|
||||||
while (link) { |
|
||||||
if (link->is_server == 1) { |
|
||||||
printf("Server link: initialized=%d\n", link->initialized); |
|
||||||
} |
|
||||||
link = link->next; |
|
||||||
} |
|
||||||
conn = conn->next; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
int main() { |
|
||||||
printf("=== ETCP Connection Establishment Test ===\n\n"); |
|
||||||
|
|
||||||
struct test_context ctx = {0}; |
|
||||||
|
|
||||||
ctx.server = calloc(1, sizeof(struct UTUN_INSTANCE)); |
|
||||||
ctx.client = calloc(1, sizeof(struct UTUN_INSTANCE)); |
|
||||||
|
|
||||||
if (!ctx.server || !ctx.client) { |
|
||||||
printf("Failed to allocate instances\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
ctx.server->ua = uasync_create(); |
|
||||||
ctx.client->ua = uasync_create(); |
|
||||||
|
|
||||||
if (!ctx.server->ua || !ctx.client->ua) { |
|
||||||
printf("Failed to create uasync instances\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
ctx.server->node_id = 0x1111111111111111ULL; |
|
||||||
ctx.client->node_id = 0x2222222222222222ULL; |
|
||||||
|
|
||||||
// Generate keypairs
|
|
||||||
sc_generate_keypair(&ctx.server->my_keys); |
|
||||||
sc_generate_keypair(&ctx.client->my_keys); |
|
||||||
|
|
||||||
printf("Server node_id: 0x%llx\n", (unsigned long long)ctx.server->node_id); |
|
||||||
printf("Client node_id: 0x%llx\n", (unsigned long long)ctx.client->node_id); |
|
||||||
print_hex("Server public key", ctx.server->my_keys.public_key, SC_PUBKEY_SIZE); |
|
||||||
print_hex("Client public key", ctx.client->my_keys.public_key, SC_PUBKEY_SIZE); |
|
||||||
|
|
||||||
// Configure server socket (listen on localhost:9001)
|
|
||||||
struct ETCP_SOCKET* server_sock = etcp_socket_add(ctx.server, NULL, 0, 0, 0); |
|
||||||
if (!server_sock) { |
|
||||||
printf("Failed to create server socket\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
struct sockaddr_in server_addr = {0}; |
|
||||||
server_addr.sin_family = AF_INET; |
|
||||||
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); |
|
||||||
server_addr.sin_port = htons(9001); |
|
||||||
|
|
||||||
if (bind(server_sock->fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { |
|
||||||
printf("Failed to bind server socket\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
// Create server ETCP connection
|
|
||||||
struct ETCP_CONN* server_conn = etcp_connection_create(ctx.server); |
|
||||||
if (!server_conn) { |
|
||||||
printf("Failed to create server ETCP connection\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
sc_init_ctx(&server_conn->crypto_ctx, &ctx.server->my_keys); |
|
||||||
|
|
||||||
printf("\n=== Starting connection test ===\n"); |
|
||||||
|
|
||||||
// Create client socket
|
|
||||||
struct ETCP_SOCKET* client_sock = etcp_socket_add(ctx.client, NULL, 0, 0, 0); |
|
||||||
if (!client_sock) { |
|
||||||
printf("Failed to create client socket\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
// Create client ETCP connection
|
|
||||||
struct ETCP_CONN* client_conn = etcp_connection_create(ctx.client); |
|
||||||
if (!client_conn) { |
|
||||||
printf("Failed to create client ETCP connection\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
sc_init_ctx(&client_conn->crypto_ctx, &ctx.client->my_keys); |
|
||||||
|
|
||||||
// Set peer public key for both sides
|
|
||||||
sc_set_peer_public_key(&server_conn->crypto_ctx, ctx.server->my_keys.public_key, 0); |
|
||||||
sc_set_peer_public_key(&client_conn->crypto_ctx, ctx.client->my_keys.public_key, 0); |
|
||||||
|
|
||||||
// Create client link (this will auto-start init)
|
|
||||||
struct sockaddr_storage server_remote_addr = {0}; |
|
||||||
memcpy(&server_remote_addr, &server_addr, sizeof(server_addr)); |
|
||||||
server_remote_addr.ss_family = AF_INET; |
|
||||||
|
|
||||||
struct ETCP_LINK* client_link = etcp_link_new(client_conn, client_sock, &server_remote_addr, 0); |
|
||||||
if (!client_link) { |
|
||||||
printf("Failed to create client link\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
printf("\nClient link created, is_server=%d, init_timer=%s\n",
|
|
||||||
client_link->is_server, client_link->init_timer ? "active" : "null"); |
|
||||||
|
|
||||||
// Poll for 5 seconds to allow handshake
|
|
||||||
printf("\nWaiting for connection establishment (5 seconds)...\n"); |
|
||||||
int completed = wait_for_init_completion(&ctx, 5000); |
|
||||||
|
|
||||||
check_connections(&ctx); |
|
||||||
|
|
||||||
if (completed) { |
|
||||||
printf("\n=== TEST PASSED ===\n"); |
|
||||||
printf("Connection established successfully!\n"); |
|
||||||
return 0; |
|
||||||
} else { |
|
||||||
printf("\n=== TEST FAILED ===\n"); |
|
||||||
printf("Connection not established within timeout\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
} |
|
||||||
Binary file not shown.
@ -1,235 +0,0 @@ |
|||||||
#include <stdio.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <string.h> |
|
||||||
#include <unistd.h> |
|
||||||
#include <sys/socket.h> |
|
||||||
#include <netinet/in.h> |
|
||||||
#include <arpa/inet.h> |
|
||||||
#include <time.h> |
|
||||||
#include <pthread.h> |
|
||||||
|
|
||||||
#include "../src/etcp.h" |
|
||||||
#include "../src/etcp_connections.h" |
|
||||||
#include "../src/config_parser.h" |
|
||||||
#include "../src/utun_instance.h" |
|
||||||
#include "../src/routing.h" |
|
||||||
#include "../src/tun_if.h" |
|
||||||
#include "../src/secure_channel.h" |
|
||||||
#include "../lib/u_async.h" |
|
||||||
|
|
||||||
#define TEST_TIMEOUT_MS 5000 |
|
||||||
|
|
||||||
struct test_instance { |
|
||||||
struct UTUN_INSTANCE* instance; |
|
||||||
const char* config_file; |
|
||||||
pthread_t thread; |
|
||||||
int ready; |
|
||||||
}; |
|
||||||
|
|
||||||
static void* instance_thread(void* arg) { |
|
||||||
struct test_instance* ti = (struct test_instance*)arg; |
|
||||||
|
|
||||||
// Create instance
|
|
||||||
ti->instance = utun_instance_create(uasync_create(), ti->config_file, NULL); |
|
||||||
if (!ti->instance) { |
|
||||||
printf("Failed to create instance from %s\n", ti->config_file); |
|
||||||
return NULL; |
|
||||||
} |
|
||||||
|
|
||||||
printf("Instance %s created successfully\n", ti->config_file); |
|
||||||
|
|
||||||
// Debug: print config servers
|
|
||||||
if (ti->instance->config) { |
|
||||||
printf("Config for %s has servers:\n", ti->config_file); |
|
||||||
struct CFG_SERVER* srv = ti->instance->config->servers; |
|
||||||
while (srv) { |
|
||||||
printf(" Server '%s'\n", srv->name); |
|
||||||
srv = srv->next; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Initialize instance (TUN, routing, etc)
|
|
||||||
if (utun_instance_init(ti->instance) < 0) { |
|
||||||
printf("Failed to initialize instance %s\n", ti->config_file); |
|
||||||
utun_instance_destroy(ti->instance); |
|
||||||
ti->instance = NULL; |
|
||||||
return NULL; |
|
||||||
} |
|
||||||
|
|
||||||
// Register sockets with uasync
|
|
||||||
if (utun_instance_register_sockets(ti->instance) < 0) { |
|
||||||
printf("Failed to register sockets for %s\n", ti->config_file); |
|
||||||
utun_instance_destroy(ti->instance); |
|
||||||
ti->instance = NULL; |
|
||||||
return NULL; |
|
||||||
} |
|
||||||
|
|
||||||
// Initialize connections (this will start handshake for clients)
|
|
||||||
if (init_connections(ti->instance) < 0) { |
|
||||||
printf("Failed to init connections for %s\n", ti->config_file); |
|
||||||
utun_instance_destroy(ti->instance); |
|
||||||
ti->instance = NULL; |
|
||||||
return NULL; |
|
||||||
} |
|
||||||
|
|
||||||
ti->ready = 1; |
|
||||||
printf("Instance %s ready (node_id=%llx)\n", ti->config_file, (unsigned long long)ti->instance->node_id); |
|
||||||
|
|
||||||
// Run event loop
|
|
||||||
while (ti->instance && ti->instance->running) { |
|
||||||
uasync_poll(ti->instance->ua, 10); |
|
||||||
} |
|
||||||
|
|
||||||
return NULL; |
|
||||||
} |
|
||||||
|
|
||||||
static void dump_connections(struct UTUN_INSTANCE* instance, const char* name) { |
|
||||||
printf("\n=== %s connections state ===\n", name); |
|
||||||
|
|
||||||
if (!instance->connections) { |
|
||||||
printf("No connections\n"); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
struct ETCP_CONN* conn = instance->connections; |
|
||||||
int conn_idx = 0; |
|
||||||
while (conn) { |
|
||||||
printf("Connection %d: peer_node_id=%llx\n", conn_idx, (unsigned long long)conn->peer_node_id); |
|
||||||
|
|
||||||
struct ETCP_LINK* link = conn->links; |
|
||||||
int link_idx = 0; |
|
||||||
while (link) { |
|
||||||
printf(" Link %d: initialized=%d, is_server=%d, init_timer=%s, timeout=%dms, retry=%d\n", |
|
||||||
link_idx, |
|
||||||
link->initialized, |
|
||||||
link->is_server, |
|
||||||
link->init_timer ? "active" : "null", |
|
||||||
link->init_timeout, |
|
||||||
link->init_retry_count); |
|
||||||
|
|
||||||
link = link->next; |
|
||||||
link_idx++; |
|
||||||
} |
|
||||||
|
|
||||||
conn = conn->next; |
|
||||||
conn_idx++; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
int main() { |
|
||||||
printf("=== ETCP Full Connection Test with Real Instances ===\n\n"); |
|
||||||
|
|
||||||
// Create config files in test directory
|
|
||||||
FILE* server_conf = fopen("test_server.conf", "w"); |
|
||||||
fprintf(server_conf, "[global]\n"); |
|
||||||
fprintf(server_conf, "my_node_id=0x1111111111111111\n"); |
|
||||||
fprintf(server_conf, "my_private_key=1313912e5d34768983b0e06530a48c77816d228a5b5605e1ab3dc443d107a3dc\n"); |
|
||||||
fprintf(server_conf, "my_public_key=dde6cec8a9023339a758f60883ef41534d24a1ffdc09bbb787a5c24ddfd891e3092461835a97d37944c681fc6b2c1f5acde8ad192f7d2cdc9920aa0d3ff78e99\n"); |
|
||||||
fprintf(server_conf, "tun_ip=10.99.0.1/24\n"); |
|
||||||
fprintf(server_conf, "tun_ifname=tun99\n"); |
|
||||||
fprintf(server_conf, "\n[server:test]\n"); |
|
||||||
fprintf(server_conf, "addr=127.0.0.1:9001\n"); |
|
||||||
fprintf(server_conf, "type=public\n"); |
|
||||||
fclose(server_conf); |
|
||||||
|
|
||||||
FILE* client_conf = fopen("test_client.conf", "w"); |
|
||||||
fprintf(client_conf, "[global]\n"); |
|
||||||
fprintf(client_conf, "my_node_id=0x2222222222222222\n"); |
|
||||||
fprintf(client_conf, "my_private_key=1313912e5d34768983b0e06530a48c77816d228a5b5605e1ab3dc443d107a3dc\n"); |
|
||||||
fprintf(client_conf, "my_public_key=dde6cec8a9023339a758f60883ef41534d24a1ffdc09bbb787a5c24ddfd891e3092461835a97d37944c681fc6b2c1f5acde8ad192f7d2cdc9920aa0d3ff78e99\n"); |
|
||||||
fprintf(client_conf, "tun_ip=10.99.0.2/24\n"); |
|
||||||
fprintf(client_conf, "tun_ifname=tun98\n"); |
|
||||||
fprintf(client_conf, "\n[client:test_client]\n"); |
|
||||||
fprintf(client_conf, "peer_node_id=0x1111111111111111\n"); |
|
||||||
fprintf(client_conf, "keepalive=1\n"); |
|
||||||
fprintf(client_conf, "link=127.0.0.1:9001\n"); |
|
||||||
fclose(client_conf); |
|
||||||
|
|
||||||
// Create test instances
|
|
||||||
struct test_instance server = {.config_file = "test_server.conf"}; |
|
||||||
struct test_instance client = {.config_file = "test_client.conf"}; |
|
||||||
|
|
||||||
printf("Starting server instance...\n"); |
|
||||||
if (pthread_create(&server.thread, NULL, instance_thread, &server) != 0) { |
|
||||||
printf("Failed to create server thread\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
printf("Starting client instance...\n"); |
|
||||||
if (pthread_create(&client.thread, NULL, instance_thread, &client) != 0) { |
|
||||||
printf("Failed to create client thread\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
// Wait for instances to be ready
|
|
||||||
int wait_count = 0; |
|
||||||
while ((!server.ready || !client.ready) && wait_count < 100) { |
|
||||||
usleep(50000); |
|
||||||
wait_count++; |
|
||||||
} |
|
||||||
|
|
||||||
if (!server.ready || !client.ready) { |
|
||||||
printf("Instances failed to initialize\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
printf("\n=== Monitoring connection state ===\n"); |
|
||||||
|
|
||||||
// Monitor connection state for 5 seconds
|
|
||||||
int established = 0; |
|
||||||
int elapsed = 0; |
|
||||||
while (elapsed < TEST_TIMEOUT_MS) { |
|
||||||
// Check client connection to server
|
|
||||||
struct ETCP_CONN* client_conn = client.instance->connections; |
|
||||||
while (client_conn) { |
|
||||||
if (client_conn->peer_node_id == 0x1111111111111111ULL) { |
|
||||||
struct ETCP_LINK* link = client_conn->links; |
|
||||||
while (link) { |
|
||||||
if (link->initialized && link->is_server == 0) { |
|
||||||
printf("SUCCESS: Client connection established!\n"); |
|
||||||
established = 1; |
|
||||||
break; |
|
||||||
} |
|
||||||
link = link->next; |
|
||||||
} |
|
||||||
} |
|
||||||
if (established) break; |
|
||||||
client_conn = client_conn->next; |
|
||||||
} |
|
||||||
|
|
||||||
if (established) break; |
|
||||||
|
|
||||||
// Dump state every second
|
|
||||||
if (elapsed % 1000 == 0) { |
|
||||||
dump_connections(server.instance, "Server"); |
|
||||||
dump_connections(client.instance, "Client"); |
|
||||||
} |
|
||||||
|
|
||||||
usleep(100000); |
|
||||||
elapsed += 100; |
|
||||||
} |
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
printf("\n=== Cleaning up ===\n"); |
|
||||||
if (server.instance) { |
|
||||||
server.instance->running = 0; |
|
||||||
} |
|
||||||
if (client.instance) { |
|
||||||
client.instance->running = 0; |
|
||||||
} |
|
||||||
|
|
||||||
pthread_join(server.thread, NULL); |
|
||||||
pthread_join(client.thread, NULL); |
|
||||||
|
|
||||||
// Cleanup config files
|
|
||||||
unlink("test_server.conf"); |
|
||||||
unlink("test_client.conf"); |
|
||||||
|
|
||||||
if (established) { |
|
||||||
printf("\n=== TEST PASSED ===\n"); |
|
||||||
return 0; |
|
||||||
} else { |
|
||||||
printf("\n=== TEST FAILED ===\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,381 +0,0 @@ |
|||||||
// tests/test_etcp_connections_send.c - Test ETCP connections send/encrypt functions
|
|
||||||
#include "etcp_connections.h" |
|
||||||
#include "etcp.h" |
|
||||||
#include "secure_channel.h" |
|
||||||
#include "memory_pool.h" |
|
||||||
#include "ll_queue.h" |
|
||||||
#include "crc32.h" |
|
||||||
#include <stdio.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <string.h> |
|
||||||
#include <assert.h> |
|
||||||
#include <sys/socket.h> |
|
||||||
|
|
||||||
|
|
||||||
void packet_pool_free(struct memory_pool* pool, void* ptr); |
|
||||||
// Forward declarations
|
|
||||||
#include <netinet/in.h> |
|
||||||
#include <arpa/inet.h> |
|
||||||
#include <unistd.h> |
|
||||||
#include <fcntl.h> |
|
||||||
#include <errno.h> |
|
||||||
|
|
||||||
#define TEST_PORT 6001 |
|
||||||
#define TEST_MESSAGE "Hello ETCP Connection!" |
|
||||||
|
|
||||||
typedef struct { |
|
||||||
struct UTUN_INSTANCE* instance; |
|
||||||
struct ETCP_SOCKET* socket; |
|
||||||
struct ETCP_CONN* conn; |
|
||||||
int udp_fd; |
|
||||||
} test_context_t; |
|
||||||
|
|
||||||
// Helper: Create minimal UTUN instance
|
|
||||||
test_context_t* create_test_context(void) { |
|
||||||
test_context_t* ctx = calloc(1, sizeof(test_context_t)); |
|
||||||
assert(ctx); |
|
||||||
|
|
||||||
// Create instance
|
|
||||||
ctx->instance = calloc(1, sizeof(struct UTUN_INSTANCE)); |
|
||||||
assert(ctx->instance); |
|
||||||
|
|
||||||
// Create ETCP connection
|
|
||||||
ctx->conn = etcp_connection_create(ctx->instance); |
|
||||||
assert(ctx->conn); |
|
||||||
|
|
||||||
// Create UDP socket
|
|
||||||
ctx->udp_fd = socket(AF_INET, SOCK_DGRAM, 0); |
|
||||||
assert(ctx->udp_fd >= 0); |
|
||||||
|
|
||||||
// Bind to test port
|
|
||||||
struct sockaddr_in addr; |
|
||||||
memset(&addr, 0, sizeof(addr)); |
|
||||||
addr.sin_family = AF_INET; |
|
||||||
addr.sin_port = htons(TEST_PORT); |
|
||||||
addr.sin_addr.s_addr = INADDR_ANY; |
|
||||||
|
|
||||||
int ret = bind(ctx->udp_fd, (struct sockaddr*)&addr, sizeof(addr)); |
|
||||||
assert(ret == 0); |
|
||||||
|
|
||||||
// Create ETCP socket wrapper
|
|
||||||
ctx->socket = calloc(1, sizeof(struct ETCP_SOCKET)); |
|
||||||
assert(ctx->socket); |
|
||||||
|
|
||||||
ctx->socket->instance = ctx->instance; |
|
||||||
ctx->socket->fd = ctx->udp_fd; |
|
||||||
memcpy(&ctx->socket->local_addr, &addr, sizeof(addr)); |
|
||||||
ctx->socket->max_channels = 8; |
|
||||||
ctx->socket->links = calloc(ctx->socket->max_channels, sizeof(struct ETCP_LINK*)); |
|
||||||
assert(ctx->socket->links); |
|
||||||
|
|
||||||
// Add to instance
|
|
||||||
ctx->socket->next = ctx->instance->etcp_sockets; |
|
||||||
ctx->instance->etcp_sockets = ctx->socket; |
|
||||||
|
|
||||||
printf(" ✓ Test context created\n"); |
|
||||||
return ctx; |
|
||||||
} |
|
||||||
|
|
||||||
// Helper: Cleanup context
|
|
||||||
void destroy_test_context(test_context_t* ctx) { |
|
||||||
if (!ctx) return; |
|
||||||
|
|
||||||
close(ctx->udp_fd); |
|
||||||
etcp_destroy(ctx->conn); |
|
||||||
free(ctx->socket->links); |
|
||||||
free(ctx->socket); |
|
||||||
free(ctx->instance); |
|
||||||
free(ctx); |
|
||||||
|
|
||||||
printf(" ✓ Test context destroyed\n"); |
|
||||||
} |
|
||||||
|
|
||||||
// Test 1: etcp_socket_add
|
|
||||||
static int test_socket_add(void) { |
|
||||||
printf("\n=== Test 1: Socket Add ===\n"); |
|
||||||
|
|
||||||
struct UTUN_INSTANCE* instance = calloc(1, sizeof(struct UTUN_INSTANCE)); |
|
||||||
assert(instance); |
|
||||||
|
|
||||||
// Create test IP
|
|
||||||
struct sockaddr_storage ip_addr; |
|
||||||
struct sockaddr_in* sin = (struct sockaddr_in*)&ip_addr; |
|
||||||
sin->sin_family = AF_INET; |
|
||||||
sin->sin_port = htons(7000); |
|
||||||
sin->sin_addr.s_addr = INADDR_ANY; |
|
||||||
|
|
||||||
// Add socket
|
|
||||||
struct ETCP_SOCKET* sock = etcp_socket_add(instance, &ip_addr, 0, 0, 0); |
|
||||||
assert(sock != NULL); |
|
||||||
assert(sock->fd >= 0); |
|
||||||
assert(sock->instance == instance); |
|
||||||
printf(" ✓ Test PASSED\n")("Socket added successfully"); |
|
||||||
|
|
||||||
// Find in list
|
|
||||||
struct ETCP_SOCKET* found = instance->etcp_sockets; |
|
||||||
assert(found == sock); |
|
||||||
printf(" ✓ Test PASSED\n")("Socket found in instance list"); |
|
||||||
|
|
||||||
etcp_socket_remove(sock); |
|
||||||
free(instance); |
|
||||||
printf(" ✓ Test PASSED\n")("Cleanup successful"); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
// Test 2: etcp_socket_remove with active links
|
|
||||||
static int test_socket_remove_with_links(void) { |
|
||||||
printf("\n=== Test 2: Socket Remove with Links ===\n"); |
|
||||||
|
|
||||||
test_context_t* ctx = create_test_context(); |
|
||||||
|
|
||||||
// Create a link
|
|
||||||
struct sockaddr_storage remote_addr; |
|
||||||
struct sockaddr_in* sin = (struct sockaddr_in*)&remote_addr; |
|
||||||
sin->sin_family = AF_INET; |
|
||||||
sin->sin_port = htons(7001); |
|
||||||
inet_pton(AF_INET, "127.0.0.1", &sin->sin_addr); |
|
||||||
|
|
||||||
struct ETCP_LINK* link = etcp_link_new(ctx->conn, ctx->socket, &remote_addr, 0); |
|
||||||
assert(link != NULL); |
|
||||||
printf(" ✓ Test PASSED\n")("Link created"); |
|
||||||
|
|
||||||
// Remove socket (should close links)
|
|
||||||
etcp_socket_remove(ctx->socket); |
|
||||||
|
|
||||||
// Verify socket removed from instance
|
|
||||||
assert(ctx->instance->etcp_sockets == NULL); |
|
||||||
printf(" ✓ Test PASSED\n")("Socket removed from instance"); |
|
||||||
|
|
||||||
free(ctx->instance); |
|
||||||
free(ctx); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
// Test 3: etcp_link_new basic
|
|
||||||
static int test_link_new_basic(void) { |
|
||||||
printf("\n=== Test 3: Link New Basic ===\n"); |
|
||||||
|
|
||||||
test_context_t* ctx = create_test_context(); |
|
||||||
|
|
||||||
// Create remote address
|
|
||||||
struct sockaddr_storage remote_addr; |
|
||||||
struct sockaddr_in* sin = (struct sockaddr_in*)&remote_addr; |
|
||||||
sin->sin_family = AF_INET; |
|
||||||
sin->sin_port = htons(7002); |
|
||||||
inet_pton(AF_INET, "127.0.0.1", &sin->sin_addr); |
|
||||||
|
|
||||||
// Create link
|
|
||||||
struct ETCP_LINK* link = etcp_link_new(ctx->conn, ctx->socket, &remote_addr, 0); |
|
||||||
assert(link != NULL); |
|
||||||
assert(link->conn == ctx->socket); |
|
||||||
assert(link->etcp == ctx->conn); |
|
||||||
printf(" ✓ Test PASSED\n")("Link created with correct associations"); |
|
||||||
|
|
||||||
// Verify remote address copied
|
|
||||||
struct sockaddr_in* remote_sin = (struct sockaddr_in*)&link->remote_addr; |
|
||||||
assert(remote_sin->sin_port == htons(7002)); |
|
||||||
printf(" ✓ Test PASSED\n")("Remote address copied correctly"); |
|
||||||
|
|
||||||
destroy_test_context(ctx); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
// Test 4: etcp_link_find_by_addr
|
|
||||||
static int test_link_find_by_addr(void) { |
|
||||||
printf("\n=== Test 4: Link Find by Address ===\n"); |
|
||||||
|
|
||||||
test_context_t* ctx = create_test_context(); |
|
||||||
|
|
||||||
// Create multiple links
|
|
||||||
for (int i = 0; i < 5; i++) { |
|
||||||
struct sockaddr_storage addr; |
|
||||||
struct sockaddr_in* sin = (struct sockaddr_in*)&addr; |
|
||||||
sin->sin_family = AF_INET; |
|
||||||
sin->sin_port = htons(8000 + i); |
|
||||||
inet_pton(AF_INET, "127.0.0.1", &sin->sin_addr); |
|
||||||
|
|
||||||
struct ETCP_LINK* link = etcp_link_new(ctx->conn, ctx->socket, &addr, 0); |
|
||||||
assert(link != NULL); |
|
||||||
} |
|
||||||
printf(" ✓ Test PASSED\n")("5 links created"); |
|
||||||
|
|
||||||
// Find specific link
|
|
||||||
struct sockaddr_storage search_addr; |
|
||||||
struct sockaddr_in* search_sin = (struct sockaddr_in*)&search_addr; |
|
||||||
search_sin->sin_family = AF_INET; |
|
||||||
search_sin->sin_port = htons(8002); |
|
||||||
inet_pton(AF_INET, "127.0.0.1", &search_sin->sin_addr); |
|
||||||
|
|
||||||
struct ETCP_LINK* found = etcp_link_find_by_addr(ctx->socket, &search_addr); |
|
||||||
assert(found != NULL); |
|
||||||
assert(((struct sockaddr_in*)&found->remote_addr)->sin_port == htons(8002)); |
|
||||||
printf(" ✓ Test PASSED\n")("Link found by address"); |
|
||||||
|
|
||||||
// Search for non-existent
|
|
||||||
search_sin->sin_port = htons(9999); |
|
||||||
found = etcp_link_find_by_addr(ctx->socket, &search_addr); |
|
||||||
assert(found == NULL); |
|
||||||
printf(" ✓ Test PASSED\n")("Non-existent link returns NULL"); |
|
||||||
|
|
||||||
destroy_test_context(ctx); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
// Test 5: etcp_encrypt_send basic
|
|
||||||
static int test_encrypt_send_basic(void) { |
|
||||||
printf("\n=== Test 5: Encrypt Send Basic ===\n"); |
|
||||||
|
|
||||||
test_context_t* ctx = create_test_context(); |
|
||||||
|
|
||||||
// Create peer
|
|
||||||
struct sockaddr_storage peer_addr; |
|
||||||
struct sockaddr_in* sin = (struct sockaddr_in*)&peer_addr; |
|
||||||
sin->sin_family = AF_INET; |
|
||||||
sin->sin_port = htons(9001); |
|
||||||
inet_pton(AF_INET, "127.0.0.1", &sin->sin_addr); |
|
||||||
|
|
||||||
struct ETCP_LINK* link = etcp_link_new(ctx->conn, ctx->socket, &peer_addr, 0); |
|
||||||
assert(link != NULL); |
|
||||||
printf(" ✓ Test PASSED\n")("Link to peer created"); |
|
||||||
|
|
||||||
// Set peer public key for encryption
|
|
||||||
// Using dummy key for test
|
|
||||||
uint8_t dummy_key[SC_PUBKEY_SIZE]; |
|
||||||
memset(dummy_key, 0xAA, SC_PUBKEY_SIZE); |
|
||||||
int ret = sc_set_peer_public_key(&ctx->conn->crypto_ctx, (const char*)dummy_key, 0); |
|
||||||
if (ret != SC_OK) { |
|
||||||
printf(" ⚠ Warning: sc_set_peer_public_key failed (expected for dummy key)\n"); |
|
||||||
} |
|
||||||
|
|
||||||
// Create datagram
|
|
||||||
uint8_t buffer[1600]; |
|
||||||
struct ETCP_DGRAM* dgram = (struct ETCP_DGRAM*)buffer; |
|
||||||
dgram->link = link; |
|
||||||
dgram->noencrypt_len = 0; |
|
||||||
dgram->data_len = strlen(TEST_MESSAGE); |
|
||||||
memcpy(dgram->data, TEST_MESSAGE, dgram->data_len); |
|
||||||
|
|
||||||
// Send (will fail due to invalid key, but tests the path)
|
|
||||||
int sent = etcp_encrypt_send(dgram); |
|
||||||
if (sent < 0) { |
|
||||||
printf(" ✓ Send path executed (encryption failed as expected with dummy key)\n"); |
|
||||||
} else { |
|
||||||
printf(" ✓ Send successful\n"); |
|
||||||
} |
|
||||||
|
|
||||||
destroy_test_context(ctx); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
// Test 6: etcp_link_close basic
|
|
||||||
static int test_link_close_basic(void) { |
|
||||||
printf("\n=== Test 6: Link Close Basic ===\n"); |
|
||||||
|
|
||||||
test_context_t* ctx = create_test_context(); |
|
||||||
|
|
||||||
// Create link
|
|
||||||
struct sockaddr_storage addr1, addr2; |
|
||||||
struct sockaddr_in* sin1 = (struct sockaddr_in*)&addr1; |
|
||||||
sin1->sin_family = AF_INET; |
|
||||||
sin1->sin_port = htons(7001); |
|
||||||
inet_pton(AF_INET, "127.0.0.1", &sin1->sin_addr); |
|
||||||
|
|
||||||
struct sockaddr_in* sin2 = (struct sockaddr_in*)&addr2; |
|
||||||
sin2->sin_family = AF_INET; |
|
||||||
sin2->sin_port = htons(7002); |
|
||||||
inet_pton(AF_INET, "127.0.0.1", &sin2->sin_addr); |
|
||||||
|
|
||||||
struct ETCP_LINK* link1 = etcp_link_new(ctx->conn, ctx->socket, &addr1, 0); |
|
||||||
struct ETCP_LINK* link2 = etcp_link_new(ctx->conn, ctx->socket, &addr2, 0); |
|
||||||
assert(link1 != NULL && link2 != NULL); |
|
||||||
printf(" ✓ Test PASSED\n")("2 links created"); |
|
||||||
|
|
||||||
// Close one link
|
|
||||||
etcp_link_close(link1); |
|
||||||
printf(" ✓ Test PASSED\n")("Link closed"); |
|
||||||
|
|
||||||
// Verify socket still has one link
|
|
||||||
int count = 0; |
|
||||||
for (size_t i = 0; i < ctx->socket->num_channels; i++) { |
|
||||||
if (ctx->socket->links[i] != NULL) count++; |
|
||||||
} |
|
||||||
printf(" ℹ Socket has %d links after closing\n", count); |
|
||||||
|
|
||||||
destroy_test_context(ctx); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
// Test 7: Memory pool free
|
|
||||||
static int test_packet_pool_free(void) { |
|
||||||
printf("\n=== Test 7: Packet Pool Free ===\n"); |
|
||||||
|
|
||||||
// Create a memory pool
|
|
||||||
struct memory_pool* pool = memory_pool_init(1600); |
|
||||||
assert(pool != NULL); |
|
||||||
printf(" ✓ Test PASSED\n")("Memory pool created"); |
|
||||||
|
|
||||||
// Allocate a packet
|
|
||||||
struct ETCP_DGRAM* pkt = memory_pool_alloc(pool); |
|
||||||
assert(pkt != NULL); |
|
||||||
printf(" ✓ Test PASSED\n")("Packet allocated"); |
|
||||||
|
|
||||||
// Fill with test data
|
|
||||||
pkt->link = NULL; |
|
||||||
pkt->data_len = 100; |
|
||||||
memcpy(pkt->data, "test data", 10); |
|
||||||
|
|
||||||
// Free the packet
|
|
||||||
packet_pool_free(pool, pkt); |
|
||||||
printf(" ✓ Test PASSED\n")("Packet freed"); |
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
// Note: memory_pool_destroy not exposed, assuming cleanup via etcp_destroy
|
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
// Main test runner
|
|
||||||
int main(void) { |
|
||||||
printf("╔═══════════════════════════════════════════════════════════════╗\n"); |
|
||||||
printf("║ ETCP Connections Send Operations Tests ║\n"); |
|
||||||
printf("╚═══════════════════════════════════════════════════════════════╝\n"); |
|
||||||
|
|
||||||
int tests_passed = 0; |
|
||||||
int total_tests = 0; |
|
||||||
|
|
||||||
struct test_case { |
|
||||||
const char* name; |
|
||||||
int (*func)(void); |
|
||||||
} test_cases[] = { |
|
||||||
{"Socket Add", test_socket_add}, |
|
||||||
{"Socket Remove with Links", test_socket_remove_with_links}, |
|
||||||
{"Link New Basic", test_link_new_basic}, |
|
||||||
{"Link Find by Address", test_link_find_by_addr}, |
|
||||||
{"Encrypt Send Basic", test_encrypt_send_basic}, |
|
||||||
{"Link Close Basic", test_link_close_basic}, |
|
||||||
{"Packet Pool Free", test_packet_pool_free}, |
|
||||||
{NULL, NULL} |
|
||||||
}; |
|
||||||
|
|
||||||
for (int i = 0; test_cases[i].func != NULL; i++) { |
|
||||||
total_tests++; |
|
||||||
printf("\n[TEST %d/%d] Running: %s\n", i + 1, 7, test_cases[i].name); |
|
||||||
|
|
||||||
if (test_cases[i].func() == 0) { |
|
||||||
tests_passed++; |
|
||||||
printf("[TEST %d/%d] ✓ PASSED\n", i + 1, 7); |
|
||||||
} else { |
|
||||||
printf("[TEST %d/%d] ✗ FAILED\n", i + 1, 7); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
printf("\n╔═══════════════════════════════════════════════════════════════╗\n"); |
|
||||||
printf("║ TEST SUMMARY ║\n"); |
|
||||||
printf("╠═══════════════════════════════════════════════════════════════╣\n"); |
|
||||||
printf("║ Tests Passed: %d / %d ║\n", tests_passed, total_tests); |
|
||||||
printf("║ Coverage: ETCP Connections Send Operations ║\n"); |
|
||||||
printf("╚═══════════════════════════════════════════════════════════════╝\n"); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
Binary file not shown.
Binary file not shown.
@ -1,94 +0,0 @@ |
|||||||
// tests/test_etcp_full_lifecycle.c - Integration test for Routing + ETCP
|
|
||||||
#include "routing.h" |
|
||||||
#include "secure_channel.h" |
|
||||||
#include <stdio.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <string.h> |
|
||||||
#include <assert.h> |
|
||||||
#include <arpa/inet.h> |
|
||||||
|
|
||||||
#define TEST_PASS(msg) do { printf(" ✓ %s\n", (msg)); } while(0) |
|
||||||
|
|
||||||
int main(void) { |
|
||||||
printf("ETCP Full Lifecycle Integration Test\n"); |
|
||||||
printf("Testing: Routing Table + Secure Channel\n"); |
|
||||||
printf("════════════════════════════════════════\n\n"); |
|
||||||
|
|
||||||
int tests_passed = 0; |
|
||||||
int total_tests = 0; |
|
||||||
|
|
||||||
// Test 1: Routing table creation
|
|
||||||
total_tests++; |
|
||||||
printf("Test %d/%d: Routing table creation\n", total_tests, 3); |
|
||||||
|
|
||||||
struct routing_table* rt = routing_table_create(); |
|
||||||
if (rt == NULL) { |
|
||||||
printf(" ✗ FAILED: routing_table_create returned NULL\n"); |
|
||||||
} else { |
|
||||||
TEST_PASS("Routing table created successfully"); |
|
||||||
tests_passed++; |
|
||||||
} |
|
||||||
|
|
||||||
// Test 2: Insert and lookup route
|
|
||||||
total_tests++; |
|
||||||
printf("\nTest %d/%d: Insert and lookup route\n", total_tests, 3); |
|
||||||
|
|
||||||
struct route_entry route = { |
|
||||||
.network = 0x0A000100, // 10.0.1.0 (network byte order)
|
|
||||||
.prefix_length = 24, |
|
||||||
.next_hop_ip = 0xC0A80101, // 192.168.1.1
|
|
||||||
.type = ROUTE_TYPE_STATIC, |
|
||||||
.flags = ROUTE_FLAG_ACTIVE |
|
||||||
}; |
|
||||||
|
|
||||||
bool result = routing_table_insert(rt, &route); |
|
||||||
if (result == false) { |
|
||||||
printf(" ✗ FAILED: routing_table_insert returned false\n"); |
|
||||||
} else if (rt->count != 1) { |
|
||||||
printf(" ✗ FAILED: table count is %zu, expected 1\n", rt->count); |
|
||||||
} else { |
|
||||||
TEST_PASS("Route inserted (10.0.1.0/24)"); |
|
||||||
tests_passed++; |
|
||||||
} |
|
||||||
|
|
||||||
struct route_entry found; |
|
||||||
uint32_t test_ip = 0x0A000164; // 10.0.1.100
|
|
||||||
result = routing_table_lookup(rt, test_ip, &found); |
|
||||||
|
|
||||||
if (result == false) { |
|
||||||
printf(" ✗ FAILED: routing_table_lookup returned false\n"); |
|
||||||
} else if (found.network != route.network) { |
|
||||||
printf(" ✗ FAILED: wrong route found\n"); |
|
||||||
} else { |
|
||||||
TEST_PASS("Route lookup successful"); |
|
||||||
tests_passed++; |
|
||||||
} |
|
||||||
|
|
||||||
// Test 3: Secure channel basic
|
|
||||||
total_tests++; |
|
||||||
printf("\nTest %d/%d: Secure channel initialization\n", total_tests, 3); |
|
||||||
|
|
||||||
struct SC_MYKEYS keys; |
|
||||||
sc_status_t status = sc_generate_keypair(&keys); |
|
||||||
if (status != SC_OK) { |
|
||||||
printf(" ⚠ WARNING: sc_generate_keypair returned %d (may need entropy)\n", status); |
|
||||||
// Not a failure, just a warning
|
|
||||||
} |
|
||||||
TEST_PASS("Key generation attempted"); |
|
||||||
tests_passed++; |
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
printf("\nCleaning up...\n"); |
|
||||||
routing_table_destroy(rt); |
|
||||||
TEST_PASS("Routing table destroyed"); |
|
||||||
|
|
||||||
// Summary
|
|
||||||
printf("\n╔═══════════════════════════════════════════════════════════════╗\n"); |
|
||||||
printf("║ TEST SUMMARY ║\n"); |
|
||||||
printf("╠═══════════════════════════════════════════════════════════════╣\n"); |
|
||||||
printf("║ Tests Passed: %d / %d ║\n", tests_passed, total_tests); |
|
||||||
printf("║ Coverage: Routing Table + Secure Channel Integration ║\n"); |
|
||||||
printf("╚═══════════════════════════════════════════════════════════════╝\n"); |
|
||||||
|
|
||||||
return (tests_passed == total_tests) ? 0 : 1; |
|
||||||
} |
|
||||||
@ -1,145 +0,0 @@ |
|||||||
// test_etcp_link_simple.c - Simple test with two ETCP_LINKs via UDP sockets
|
|
||||||
#include <stdio.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <string.h> |
|
||||||
#include <unistd.h> |
|
||||||
#include <arpa/inet.h> |
|
||||||
#include <sys/socket.h> |
|
||||||
#include <fcntl.h> |
|
||||||
#include <errno.h> |
|
||||||
#include <time.h> |
|
||||||
|
|
||||||
#define TEST_PORT 22345 |
|
||||||
|
|
||||||
typedef struct { |
|
||||||
int fd; |
|
||||||
struct sockaddr_in addr; |
|
||||||
} socket_t; |
|
||||||
|
|
||||||
// Create UDP socket
|
|
||||||
static socket_t* create_socket(int port) { |
|
||||||
socket_t* sock = calloc(1, sizeof(socket_t)); |
|
||||||
if (!sock) return NULL; |
|
||||||
|
|
||||||
sock->fd = socket(AF_INET, SOCK_DGRAM, 0); |
|
||||||
if (sock->fd < 0) { |
|
||||||
free(sock); |
|
||||||
return NULL; |
|
||||||
} |
|
||||||
|
|
||||||
int flags = fcntl(sock->fd, F_GETFL, 0); |
|
||||||
fcntl(sock->fd, F_SETFL, flags | O_NONBLOCK); |
|
||||||
|
|
||||||
memset(&sock->addr, 0, sizeof(sock->addr)); |
|
||||||
sock->addr.sin_family = AF_INET; |
|
||||||
sock->addr.sin_addr.s_addr = INADDR_ANY; |
|
||||||
sock->addr.sin_port = htons(port); |
|
||||||
|
|
||||||
if (bind(sock->fd, (struct sockaddr*)&sock->addr, sizeof(sock->addr)) < 0) { |
|
||||||
perror("bind"); |
|
||||||
close(sock->fd); |
|
||||||
free(sock); |
|
||||||
return NULL; |
|
||||||
} |
|
||||||
|
|
||||||
printf("Socket created on port %d (fd=%d)\n", port, sock->fd); |
|
||||||
return sock; |
|
||||||
} |
|
||||||
|
|
||||||
// Send data
|
|
||||||
static int send_data(socket_t* sock, const char* data, size_t len, int dst_port) { |
|
||||||
struct sockaddr_in dst; |
|
||||||
memset(&dst, 0, sizeof(dst)); |
|
||||||
dst.sin_family = AF_INET; |
|
||||||
dst.sin_addr.s_addr = inet_addr("127.0.0.1"); |
|
||||||
dst.sin_port = htons(dst_port); |
|
||||||
|
|
||||||
ssize_t sent = sendto(sock->fd, data, len, 0, (struct sockaddr*)&dst, sizeof(dst)); |
|
||||||
printf("[SEND] Sent %zd/%zu bytes to port %d\n", sent, len, dst_port); |
|
||||||
return (sent == len) ? 0 : -1; |
|
||||||
} |
|
||||||
|
|
||||||
// Receive data
|
|
||||||
static int recv_data(socket_t* sock, char* buffer, size_t max_len) { |
|
||||||
struct sockaddr_in from; |
|
||||||
socklen_t from_len = sizeof(from); |
|
||||||
|
|
||||||
ssize_t received = recvfrom(sock->fd, buffer, max_len, 0, (struct sockaddr*)&from, &from_len); |
|
||||||
if (received < 0) { |
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) { |
|
||||||
printf("[RECV] No data available\n"); |
|
||||||
} else { |
|
||||||
perror("[RECV] recvfrom"); |
|
||||||
} |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
printf("[RECV] Received %zd bytes from port %d\n", received, ntohs(from.sin_port)); |
|
||||||
return received; |
|
||||||
} |
|
||||||
|
|
||||||
int main(void) { |
|
||||||
printf("=== Simple Socket Test ===\n"); |
|
||||||
|
|
||||||
// Create sockets
|
|
||||||
socket_t* server = create_socket(TEST_PORT); |
|
||||||
socket_t* client = create_socket(TEST_PORT + 1); |
|
||||||
|
|
||||||
if (!server || !client) { |
|
||||||
fprintf(stderr, "Failed to create sockets\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
float start_time = (float)clock() / CLOCKS_PER_SEC; |
|
||||||
|
|
||||||
// Send from client to server
|
|
||||||
const char* test_data = "Hello, world!"; |
|
||||||
printf("\n[SEND] Client sending: '%s'\n", test_data); |
|
||||||
if (send_data(client, test_data, strlen(test_data), TEST_PORT) < 0) { |
|
||||||
fprintf(stderr, "Send failed\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
// Receive on server
|
|
||||||
usleep(50000); |
|
||||||
char buffer[2048]; |
|
||||||
int received = recv_data(server, buffer, sizeof(buffer)); |
|
||||||
if (received > 0) { |
|
||||||
buffer[received] = '\0'; |
|
||||||
printf("[RECV] Server got: '%s'\n", buffer); |
|
||||||
|
|
||||||
if (strcmp(buffer, test_data) == 0) { |
|
||||||
printf("✅ SUCCESS: Data matches!\n"); |
|
||||||
} else { |
|
||||||
printf("❌ FAIL: Data mismatch\n"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Send response from server to client
|
|
||||||
const char* reply = "Reply from server"; |
|
||||||
printf("\n[SEND] Server sending reply: '%s'\n", reply); |
|
||||||
if (send_data(server, reply, strlen(reply), TEST_PORT + 1) < 0) { |
|
||||||
fprintf(stderr, "Send failed\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
// Receive on client
|
|
||||||
usleep(50000); |
|
||||||
received = recv_data(client, buffer, sizeof(buffer)); |
|
||||||
if (received > 0) { |
|
||||||
buffer[received] = '\0'; |
|
||||||
printf("[RECV] Client got: '%s'\n", buffer); |
|
||||||
} |
|
||||||
|
|
||||||
float end_time = (float)clock() / CLOCKS_PER_SEC; |
|
||||||
printf("\nTiming: %.3f ms\n", (end_time - start_time) * 1000); |
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
close(server->fd); |
|
||||||
close(client->fd); |
|
||||||
free(server); |
|
||||||
free(client); |
|
||||||
|
|
||||||
printf("\n=== Test completed ===\n"); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
@ -1,137 +0,0 @@ |
|||||||
/**
|
|
||||||
* Integration test for ETCP protocol with packet pool |
|
||||||
* Tests: etcp_create, add_socket, packet processing, channel creation |
|
||||||
*/ |
|
||||||
|
|
||||||
#include <stdio.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <string.h> |
|
||||||
#include <assert.h> |
|
||||||
#include <unistd.h> |
|
||||||
#include <arpa/inet.h> |
|
||||||
#include <sys/socket.h> |
|
||||||
|
|
||||||
#include "../src/etcp.h" |
|
||||||
#include "../src/packet_buffer.h" |
|
||||||
#include "../src/packet_pool.h" |
|
||||||
|
|
||||||
static int g_data_ready_called = 0; |
|
||||||
static etcp_channel_t* g_last_channel = NULL; |
|
||||||
static packet_buffer_t* g_last_packet = NULL; |
|
||||||
|
|
||||||
static void test_data_ready_cb(struct ETCP_CONN* etcp, etcp_channel_t* channel, |
|
||||||
packet_buffer_t* pkt, void* user_data) { |
|
||||||
(void)etcp; |
|
||||||
(void)user_data; |
|
||||||
|
|
||||||
g_data_ready_called++; |
|
||||||
g_last_channel = channel; |
|
||||||
g_last_packet = pkt; |
|
||||||
|
|
||||||
printf(" Data ready: channel=%p, packet=%p, len=%zu\n", |
|
||||||
channel, pkt, packet_data_len(pkt)); |
|
||||||
} |
|
||||||
|
|
||||||
int main() { |
|
||||||
printf("=== ETCP Integration Test ===\n"); |
|
||||||
|
|
||||||
// Test 1: Create ETCP instance
|
|
||||||
printf("Test 1: Creating ETCP instance..."); |
|
||||||
uint64_t node_id = 0x123456789ABCDEF0; |
|
||||||
struct ETCP_CONN* etcp = etcp_create(node_id, 1500); |
|
||||||
assert(etcp != NULL); |
|
||||||
assert(etcp->node_id == node_id); |
|
||||||
printf(" PASS (node_id=0x%llx)\n", (unsigned long long)node_id); |
|
||||||
|
|
||||||
// Test 2: Add socket
|
|
||||||
printf("Test 2: Adding UDP socket..."); |
|
||||||
int ret = etcp_add_socket(etcp, "127.0.0.1", 0); // 0 = any port
|
|
||||||
assert(ret == 0); |
|
||||||
assert(etcp->socket_count == 1); |
|
||||||
printf(" PASS (socket_count=%d)\n", etcp->socket_count); |
|
||||||
|
|
||||||
// Test 3: Set data ready callback
|
|
||||||
printf("Test 3: Setting data ready callback..."); |
|
||||||
etcp_set_data_ready_callback(etcp, test_data_ready_cb, NULL); |
|
||||||
assert(etcp->data_ready_cb != NULL); |
|
||||||
printf(" PASS\n"); |
|
||||||
|
|
||||||
// Test 4: Create a test packet (simulating incoming packet)
|
|
||||||
printf("Test 4: Processing incoming INIT packet..."); |
|
||||||
packet_buffer_t* pkt = packet_pool_get(&etcp->packet_pool); |
|
||||||
assert(pkt != NULL); |
|
||||||
|
|
||||||
// Fill packet as if it came from socket
|
|
||||||
pkt->metadata.socket = etcp->sockets[0]; |
|
||||||
pkt->metadata.timestamp_us = 1000; |
|
||||||
pkt->metadata.flags = 0; |
|
||||||
pkt->metadata.stage = PACKET_STAGE_RX_SOCKET; |
|
||||||
|
|
||||||
// Set source address
|
|
||||||
struct sockaddr_in src_addr; |
|
||||||
src_addr.sin_family = AF_INET; |
|
||||||
src_addr.sin_port = htons(50001); |
|
||||||
inet_pton(AF_INET, "127.0.0.1", &src_addr.sin_addr); |
|
||||||
memcpy(&pkt->metadata.src_addr, &src_addr, sizeof(src_addr)); |
|
||||||
|
|
||||||
// Set packet data (INIT packet)
|
|
||||||
memcpy(packet_data(pkt), "INIT", 4); |
|
||||||
packet_set_data_len(pkt, 4); |
|
||||||
|
|
||||||
g_data_ready_called = 0; |
|
||||||
etcp_packet_input(etcp, pkt); |
|
||||||
|
|
||||||
// Check that callback was called and channel was created
|
|
||||||
assert(g_data_ready_called == 1); |
|
||||||
assert(g_last_channel != NULL); |
|
||||||
assert(g_last_packet == pkt); |
|
||||||
assert(etcp->channel_count == 1); |
|
||||||
printf(" PASS (channel_count=%d, callback called)\n", etcp->channel_count); |
|
||||||
|
|
||||||
// Test 5: Get pool statistics
|
|
||||||
printf("Test 5: Getting pool statistics..."); |
|
||||||
size_t allocs, reuse, overflow; |
|
||||||
packet_pool_get_stats(&etcp->packet_pool, &allocs, &reuse, &overflow); |
|
||||||
printf(" PASS (allocs=%zu, reuse=%zu, overflow=%zu)\n", allocs, reuse, overflow); |
|
||||||
|
|
||||||
// Test 6: Send data through channel
|
|
||||||
printf("Test 6: Sending data through channel..."); |
|
||||||
const char* test_data = "Hello, ETCP!"; |
|
||||||
ret = etcp_send(etcp, g_last_channel, (const uint8_t*)test_data, strlen(test_data)); |
|
||||||
assert(ret == 0); |
|
||||||
printf(" PASS\n"); |
|
||||||
|
|
||||||
// Test 7: Get ETCP statistics
|
|
||||||
printf("Test 7: Getting ETCP statistics..."); |
|
||||||
etcp_get_stats(etcp, &allocs, &reuse, NULL, NULL); |
|
||||||
printf(" PASS\n"); |
|
||||||
|
|
||||||
// Test 8: Destroy ETCP instance
|
|
||||||
printf("Test 8: Destroying ETCP instance..."); |
|
||||||
etcp_destroy(etcp); |
|
||||||
printf(" PASS\n"); |
|
||||||
|
|
||||||
// Test 9: Test packet buffer operations
|
|
||||||
printf("Test 9: Testing packet buffer operations..."); |
|
||||||
packet_buffer_t test_pkt; |
|
||||||
packet_init(&test_pkt); |
|
||||||
|
|
||||||
// Test metadata
|
|
||||||
packet_set_encrypted(&test_pkt, 1); |
|
||||||
assert(packet_is_encrypted(&test_pkt) != 0); |
|
||||||
|
|
||||||
packet_set_fragmented(&test_pkt, 1); |
|
||||||
assert(packet_is_fragmented(&test_pkt) != 0); |
|
||||||
|
|
||||||
packet_set_stage(&test_pkt, PACKET_STAGE_RX_DECRYPTED); |
|
||||||
assert(packet_stage(&test_pkt) == PACKET_STAGE_RX_DECRYPTED); |
|
||||||
|
|
||||||
// Test addresses
|
|
||||||
memcpy(packet_src_addr(&test_pkt), &src_addr, sizeof(src_addr)); |
|
||||||
assert(packet_src_port(&test_pkt) == src_addr.sin_port); |
|
||||||
|
|
||||||
printf(" PASS\n"); |
|
||||||
|
|
||||||
printf("\n=== All ETCP Integration Tests Passed ===\n"); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
@ -1,123 +0,0 @@ |
|||||||
// test_etcp_simple.c - Simple test to verify ETCP sender-receiver communication
|
|
||||||
#define ETCP_DEBUG 1 |
|
||||||
#include "etcp.h" |
|
||||||
#include "u_async.h" |
|
||||||
#include "ll_queue.h" |
|
||||||
#include "simple_uasync.h" |
|
||||||
#include <stdio.h> |
|
||||||
#include <string.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <stdint.h> |
|
||||||
|
|
||||||
// Sender's TX callback - just forward to receiver
|
|
||||||
static void sender_tx_callback(struct ETCP_CONN* epkt, uint8_t* data, uint16_t len, void* arg) { |
|
||||||
(void)epkt; |
|
||||||
struct ETCP_CONN* receiver = (struct ETCP_CONN*)arg; |
|
||||||
printf("Sender TX callback: sending %u bytes to receiver\n", len); |
|
||||||
|
|
||||||
// Forward directly to receiver (no loss, no delay)
|
|
||||||
etcp_rx_input(receiver, data, len); |
|
||||||
} |
|
||||||
|
|
||||||
// Receiver's TX callback - would send ACKs back to sender in real scenario
|
|
||||||
static void receiver_tx_callback(struct ETCP_CONN* epkt, uint8_t* data, uint16_t len, void* arg) { |
|
||||||
(void)epkt; |
|
||||||
(void)data; |
|
||||||
(void)len; |
|
||||||
(void)arg; |
|
||||||
printf("Receiver TX callback: ACK sent back\n"); |
|
||||||
} |
|
||||||
|
|
||||||
int main(void) { |
|
||||||
printf("Simple ETCP sender-receiver test\n"); |
|
||||||
|
|
||||||
// Initialize uasync instance
|
|
||||||
uasync_t* ua = uasync_create(); |
|
||||||
if (!ua) { |
|
||||||
fprintf(stderr, "Failed to create uasync instance\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
uasync_init_instance(ua); |
|
||||||
|
|
||||||
// Create ETCP instances
|
|
||||||
struct ETCP_CONN* sender = etcp_create(ua); |
|
||||||
struct ETCP_CONN* receiver = etcp_create(ua); |
|
||||||
|
|
||||||
if (!sender || !receiver) { |
|
||||||
printf("ERROR: Failed to create ETCP instances\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
// Set up callbacks
|
|
||||||
etcp_set_callback(sender, sender_tx_callback, receiver); |
|
||||||
etcp_set_callback(receiver, receiver_tx_callback, sender); |
|
||||||
|
|
||||||
// Send a simple packet
|
|
||||||
const char* test_data = "Hello, ETCP!"; |
|
||||||
uint16_t data_len = strlen(test_data); |
|
||||||
uint8_t* data = malloc(data_len); |
|
||||||
memcpy(data, test_data, data_len); |
|
||||||
|
|
||||||
printf("Sending test packet: %s\n", test_data); |
|
||||||
|
|
||||||
if (etcp_tx_put(sender, data, data_len) != 0) { |
|
||||||
printf("ERROR: Failed to queue packet\n"); |
|
||||||
free(data); |
|
||||||
etcp_free(sender); |
|
||||||
etcp_free(receiver); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
free(data); // etcp_tx_put makes its own copy
|
|
||||||
|
|
||||||
// Advance time to allow transmission
|
|
||||||
printf("Advancing time...\n"); |
|
||||||
for (int i = 0; i < 10; i++) { |
|
||||||
simple_uasync_advance_time(10); // 1ms each
|
|
||||||
// Process any timers (retransmissions, etc.)
|
|
||||||
} |
|
||||||
|
|
||||||
// Check receiver's output queue
|
|
||||||
ll_queue_t* output_queue = etcp_get_output_queue(receiver); |
|
||||||
if (!output_queue) { |
|
||||||
printf("ERROR: Receiver output queue is NULL\n"); |
|
||||||
etcp_free(sender); |
|
||||||
etcp_free(receiver); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
ll_entry_t* entry = queue_entry_get(output_queue); |
|
||||||
if (!entry) { |
|
||||||
printf("FAIL: No packet in receiver output queue\n"); |
|
||||||
|
|
||||||
// Debug: check queue size
|
|
||||||
printf("Queue size check: %d\n", queue_entry_count(output_queue)); |
|
||||||
|
|
||||||
etcp_free(sender); |
|
||||||
etcp_free(receiver); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
uint8_t* received_data = ll_entry_data(entry); |
|
||||||
uint16_t received_len = ll_entry_size(entry); |
|
||||||
|
|
||||||
printf("SUCCESS: Received packet of length %u\n", received_len); |
|
||||||
printf("Data: "); |
|
||||||
for (uint16_t i = 0; i < received_len; i++) { |
|
||||||
printf("%c", received_data[i]); |
|
||||||
} |
|
||||||
printf("\n"); |
|
||||||
|
|
||||||
if (received_len == data_len && memcmp(received_data, test_data, data_len) == 0) { |
|
||||||
printf("PASS: Data matches!\n"); |
|
||||||
} else { |
|
||||||
printf("FAIL: Data doesn't match\n"); |
|
||||||
} |
|
||||||
|
|
||||||
queue_entry_free(entry); |
|
||||||
etcp_free(sender); |
|
||||||
etcp_free(receiver); |
|
||||||
uasync_destroy(ua); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
Binary file not shown.
@ -1,107 +0,0 @@ |
|||||||
#include <stdio.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <string.h> |
|
||||||
#include <unistd.h> |
|
||||||
#include <sys/socket.h> |
|
||||||
#include <netinet/in.h> |
|
||||||
#include <arpa/inet.h> |
|
||||||
#include <time.h> |
|
||||||
|
|
||||||
#include "../src/etcp.h" |
|
||||||
#include "../src/etcp_connections.h" |
|
||||||
#include "../src/config_parser.h" |
|
||||||
#include "../src/utun_instance.h" |
|
||||||
#include "../src/routing.h" |
|
||||||
#include "../src/tun_if.h" |
|
||||||
#include "../src/secure_channel.h" |
|
||||||
#include "../lib/u_async.h" |
|
||||||
|
|
||||||
#define TEST_TIMEOUT_MS 5000 |
|
||||||
|
|
||||||
int main() { |
|
||||||
printf("=== ETCP Real Instance Test ===\n\n"); |
|
||||||
|
|
||||||
// Create config file
|
|
||||||
FILE* conf = fopen("test_real.conf", "w"); |
|
||||||
fprintf(conf, "[global]\n"); |
|
||||||
fprintf(conf, "my_node_id=0x1111111111111111\n"); |
|
||||||
fprintf(conf, "my_private_key=1313912e5d34768983b0e06530a48c77816d228a5b5605e1ab3dc443d107a3dc\n"); |
|
||||||
fprintf(conf, "my_public_key=dde6cec8a9023339a758f60883ef41534d24a1ffdc09bbb787a5c24ddfd891e3092461835a97d37944c681fc6b2c1f5acde8ad192f7d2cdc9920aa0d3ff78e99\n"); |
|
||||||
fprintf(conf, "tun_ip=10.99.0.1/24\n"); |
|
||||||
fprintf(conf, "tun_ifname=tun99\n"); |
|
||||||
fprintf(conf, "\n[server: test]\n"); |
|
||||||
fprintf(conf, "addr=127.0.0.1:9001\n"); |
|
||||||
fprintf(conf, "type=public\n"); |
|
||||||
fclose(conf); |
|
||||||
|
|
||||||
// Create instance
|
|
||||||
printf("Creating UTUN instance...\n"); |
|
||||||
struct UASYNC* ua = uasync_create(); |
|
||||||
struct UTUN_INSTANCE* instance = utun_instance_create(ua, "test_real.conf", NULL); |
|
||||||
if (!instance) { |
|
||||||
printf("Failed to create instance\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
printf("Instance created (node_id=%llx)\n", (unsigned long long)instance->node_id); |
|
||||||
|
|
||||||
// Initialize
|
|
||||||
printf("Initializing instance...\n"); |
|
||||||
if (utun_instance_init(instance) < 0) { |
|
||||||
printf("Failed to initialize instance\n"); |
|
||||||
utun_instance_destroy(instance); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
// Register sockets
|
|
||||||
printf("Registering sockets...\n"); |
|
||||||
if (utun_instance_register_sockets(instance) < 0) { |
|
||||||
printf("Failed to register sockets\n"); |
|
||||||
utun_instance_destroy(instance); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
// Initialize connections
|
|
||||||
printf("Initializing connections...\n"); |
|
||||||
if (init_connections(instance) < 0) { |
|
||||||
printf("Failed to initialize connections\n"); |
|
||||||
utun_instance_destroy(instance); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
printf("Instance ready\n"); |
|
||||||
|
|
||||||
// Monitor for 5 seconds
|
|
||||||
printf("\nMonitoring connections for %d seconds...\n", TEST_TIMEOUT_MS/1000); |
|
||||||
|
|
||||||
int elapsed = 0; |
|
||||||
while (elapsed < TEST_TIMEOUT_MS) { |
|
||||||
// Dump connection state
|
|
||||||
struct ETCP_CONN* conn = instance->connections; |
|
||||||
while (conn) { |
|
||||||
printf("Connection to node %llx:\n", (unsigned long long)conn->peer_node_id); |
|
||||||
|
|
||||||
struct ETCP_LINK* link = conn->links; |
|
||||||
while (link) { |
|
||||||
printf(" Link: initialized=%d, is_server=%d, init_timer=%s, timeout=%dms, retry=%d\n", |
|
||||||
link->initialized, link->is_server, |
|
||||||
link->init_timer ? "active" : "null", |
|
||||||
link->init_timeout, link->init_retry_count); |
|
||||||
link = link->next; |
|
||||||
} |
|
||||||
conn = conn->next; |
|
||||||
} |
|
||||||
|
|
||||||
uasync_poll(ua, 100); |
|
||||||
elapsed += 100; |
|
||||||
} |
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
printf("Cleaning up...\n"); |
|
||||||
unlink("test_real.conf"); |
|
||||||
instance->running = 0; |
|
||||||
utun_instance_destroy(instance); |
|
||||||
|
|
||||||
printf("\n=== Test completed ===\n"); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
@ -1,55 +0,0 @@ |
|||||||
// tests/test_etcp_stress.c - Minimal stress routing test
|
|
||||||
#include "routing.h" |
|
||||||
#include <stdio.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <time.h> |
|
||||||
|
|
||||||
#define NUM_ROUTES 500 |
|
||||||
#define NUM_LOOKUPS 5000 |
|
||||||
|
|
||||||
int main(void) { |
|
||||||
printf("ETCP Stress Test: Routing Table Performance\n"); |
|
||||||
printf("═════════════════════════════════════════════\n\n"); |
|
||||||
|
|
||||||
struct routing_table* rt = routing_table_create(); |
|
||||||
if (!rt) { |
|
||||||
printf("Error: Failed to create routing table\n"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
clock_t start = clock(); |
|
||||||
|
|
||||||
// Insert routes
|
|
||||||
for (int i = 0; i < NUM_ROUTES; i++) { |
|
||||||
struct route_entry route = { |
|
||||||
.network = (10 << 24) | (i << 8), |
|
||||||
.prefix_length = 24, |
|
||||||
.type = 0, |
|
||||||
.flags = 1 |
|
||||||
}; |
|
||||||
routing_table_insert(rt, &route); |
|
||||||
} |
|
||||||
|
|
||||||
clock_t insert_done = clock(); |
|
||||||
double insert_time = ((double)(insert_done - start)) / CLOCKS_PER_SEC; |
|
||||||
printf("✓ Inserted %d routes in %.3f seconds\n", NUM_ROUTES, insert_time); |
|
||||||
|
|
||||||
// Perform lookups
|
|
||||||
for (int i = 0; i < NUM_LOOKUPS; i++) { |
|
||||||
struct route_entry found; |
|
||||||
uint32_t ip = (10 << 24) | ((i % NUM_ROUTES) << 8) | 100; |
|
||||||
routing_table_lookup(rt, ip, &found); |
|
||||||
} |
|
||||||
|
|
||||||
clock_t lookup_done = clock(); |
|
||||||
double lookup_time = ((double)(lookup_done - insert_done)) / CLOCKS_PER_SEC; |
|
||||||
printf("✓ Performed %d lookups in %.3f seconds\n", NUM_LOOKUPS, lookup_time); |
|
||||||
|
|
||||||
routing_table_destroy(rt); |
|
||||||
|
|
||||||
printf("\n╔═══════════════════════════════════════════════════════════════╗\n"); |
|
||||||
printf("║ PERFORMANCE TEST PASSED ║\n"); |
|
||||||
printf("╚═══════════════════════════════════════════════════════════════╝\n"); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,16 @@ |
|||||||
|
#include <stdio.h> |
||||||
|
#include "../src/secure_channel.h" |
||||||
|
|
||||||
|
int main() { |
||||||
|
struct SC_MYKEYS keys; |
||||||
|
sc_generate_keypair(&keys); |
||||||
|
|
||||||
|
printf("Public key generated: "); |
||||||
|
for(int i=0; i<8; i++) printf("%02x ", keys.public_key[i]); |
||||||
|
printf("...\n"); |
||||||
|
|
||||||
|
int valid = uECC_valid_public_key(keys.public_key, uECC_secp256r1()); |
||||||
|
printf("Key valid: %d\n", valid); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
@ -0,0 +1,37 @@ |
|||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <unistd.h> |
||||||
|
|
||||||
|
#include "../src/etcp_connections.h" |
||||||
|
#include "../src/utun_instance.h" |
||||||
|
#include "../lib/u_async.h" |
||||||
|
|
||||||
|
int main() { |
||||||
|
printf("=== Minimal Test ===\n"); |
||||||
|
|
||||||
|
struct UASYNC* ua = uasync_create(); |
||||||
|
struct UTUN_INSTANCE* instance = utun_instance_create(ua, "../utun.conf", NULL); |
||||||
|
|
||||||
|
if (!instance) { |
||||||
|
printf("Failed to create instance\n"); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
printf("Instance created\n"); |
||||||
|
|
||||||
|
// Add a socket manually
|
||||||
|
struct sockaddr_storage addr; |
||||||
|
struct sockaddr_in* sin = (struct sockaddr_in*)&addr; |
||||||
|
sin->sin_family = AF_INET; |
||||||
|
sin->sin_addr.s_addr = inet_addr("127.0.0.1"); |
||||||
|
sin->sin_port = htons(9001); |
||||||
|
|
||||||
|
struct ETCP_SOCKET* sock = etcp_socket_add(instance, &addr, 0, 0, 0); |
||||||
|
|
||||||
|
if (sock) { |
||||||
|
printf("Socket created: fd=%d\n", sock->fd); |
||||||
|
printf("Socket has socket_id: %p\n", sock->socket_id); |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,97 @@ |
|||||||
|
#include <tinycrypt/aes.h> |
||||||
|
#include <tinycrypt/ccm_mode.h> |
||||||
|
#include <tinycrypt/constants.h> |
||||||
|
#include <string.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
#define SC_TAG_SIZE 8 // This is valid: 8 bytes
|
||||||
|
#define SC_SESSION_KEY_SIZE 16 |
||||||
|
|
||||||
|
int main() { |
||||||
|
printf("=== Working Crypto Test ===\n"); |
||||||
|
|
||||||
|
// Test AES key setup
|
||||||
|
struct tc_aes_key_sched_struct sched; |
||||||
|
uint8_t test_key[SC_SESSION_KEY_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||||
|
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}; |
||||||
|
|
||||||
|
printf("Testing AES key setup...\n"); |
||||||
|
int aes_result = tc_aes128_set_encrypt_key(&sched, test_key); |
||||||
|
printf("tc_aes128_set_encrypt_key returned: %d\n", aes_result); |
||||||
|
|
||||||
|
if (aes_result == TC_CRYPTO_SUCCESS) { |
||||||
|
printf("✓ AES key setup successful\n"); |
||||||
|
|
||||||
|
// Test CCM config with CORRECT parameters
|
||||||
|
struct tc_ccm_mode_struct ccm_state = {0}; |
||||||
|
TCCcmMode_t c = &ccm_state; |
||||||
|
|
||||||
|
// CRITICAL: nonce MUST be exactly 13 bytes for CCM!
|
||||||
|
uint8_t nonce[13] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
|
||||||
|
0x99, 0xAA, 0xBB, 0xCC, 0xDD}; |
||||||
|
|
||||||
|
printf("\nTesting CCM config with CORRECT parameters...\n"); |
||||||
|
printf("Nonce size: 13 (required by CCM standard)\n"); |
||||||
|
printf("Tag size: %d (valid: 4,6,8,10,12,14,16)\n", SC_TAG_SIZE); |
||||||
|
printf("Using TCCcmMode_t pointer: %p\n", (void*)c); |
||||||
|
|
||||||
|
int ccm_result = tc_ccm_config(c, &sched, nonce, 13, SC_TAG_SIZE); |
||||||
|
printf("tc_ccm_config returned: %d\n", ccm_result); |
||||||
|
|
||||||
|
if (ccm_result == TC_CRYPTO_SUCCESS) { |
||||||
|
printf("✓ CCM config successful!\n"); |
||||||
|
|
||||||
|
// Test simple encryption
|
||||||
|
uint8_t plaintext[] = "Hello, World!"; |
||||||
|
uint8_t ciphertext[64]; |
||||||
|
size_t plaintext_len = sizeof(plaintext) - 1; |
||||||
|
size_t ciphertext_len = plaintext_len + SC_TAG_SIZE; |
||||||
|
|
||||||
|
printf("\nTesting CCM encryption...\n"); |
||||||
|
printf("Plaintext: '%s' (%zu bytes)\n", plaintext, plaintext_len); |
||||||
|
printf("Expected ciphertext: %zu bytes (data + tag)\n", ciphertext_len); |
||||||
|
|
||||||
|
int enc_result = tc_ccm_generation_encryption(ciphertext, sizeof(ciphertext), |
||||||
|
NULL, 0, /* no associated data */ |
||||||
|
plaintext, plaintext_len, |
||||||
|
c); |
||||||
|
printf("tc_ccm_generation_encryption returned: %d\n", enc_result); |
||||||
|
|
||||||
|
if (enc_result == TC_CRYPTO_SUCCESS) { |
||||||
|
printf("🎉 CCM encryption successful!\n"); |
||||||
|
printf("Ciphertext length: %zu bytes\n", plaintext_len + SC_TAG_SIZE); |
||||||
|
|
||||||
|
// Test decryption
|
||||||
|
uint8_t decrypted[64]; |
||||||
|
printf("\nTesting CCM decryption...\n"); |
||||||
|
int dec_result = tc_ccm_decryption_verification(decrypted, plaintext_len, |
||||||
|
NULL, 0, ciphertext, ciphertext_len, |
||||||
|
c); |
||||||
|
printf("tc_ccm_decryption_verification returned: %d\n", dec_result); |
||||||
|
|
||||||
|
if (dec_result == TC_CRYPTO_SUCCESS) { |
||||||
|
printf("🎉 CCM decryption successful!\n"); |
||||||
|
printf("Decrypted: '%.*s'\n", (int)plaintext_len, decrypted); |
||||||
|
|
||||||
|
// Verify result
|
||||||
|
if (memcmp(plaintext, decrypted, plaintext_len) == 0) { |
||||||
|
printf("✓ Decrypted data matches original!\n"); |
||||||
|
printf("\n🎉 CRYPTO WORKS! AES-CCM encryption/decryption successful!\n"); |
||||||
|
} else { |
||||||
|
printf("❌ Decrypted data doesn't match original!\n"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
printf("❌ CCM decryption failed\n"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
printf("❌ CCM encryption failed\n"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
printf("❌ CCM config failed even with correct parameters!\n"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
printf("❌ AES key setup failed\n"); |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
Binary file not shown.
@ -0,0 +1,63 @@ |
|||||||
|
#include <tinycrypt/aes.h> |
||||||
|
#include <tinycrypt/ccm_mode.h> |
||||||
|
#include <tinycrypt/constants.h> |
||||||
|
#include <string.h> |
||||||
|
#include <stdio.h> |
||||||
|
|
||||||
|
#define SC_NONCE_SIZE 8 |
||||||
|
#define SC_TAG_SIZE 8 |
||||||
|
#define SC_SESSION_KEY_SIZE 16 |
||||||
|
|
||||||
|
int main() { |
||||||
|
printf("=== Zero-initialized Debug Test ===\n"); |
||||||
|
|
||||||
|
// Test AES key setup
|
||||||
|
struct tc_aes_key_sched_struct sched; |
||||||
|
uint8_t test_key[SC_SESSION_KEY_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||||
|
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}; |
||||||
|
|
||||||
|
printf("Testing AES key setup...\n"); |
||||||
|
int aes_result = tc_aes128_set_encrypt_key(&sched, test_key); |
||||||
|
printf("tc_aes128_set_encrypt_key returned: %d\n", aes_result); |
||||||
|
|
||||||
|
if (aes_result == TC_CRYPTO_SUCCESS) { |
||||||
|
printf("✓ AES key setup successful\n"); |
||||||
|
|
||||||
|
// Test CCM config with zero-initialized structure
|
||||||
|
struct tc_ccm_mode_struct ccm_state = {0}; // Zero initialize
|
||||||
|
TCCcmMode_t c = &ccm_state; |
||||||
|
uint8_t nonce[SC_NONCE_SIZE] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; |
||||||
|
|
||||||
|
printf("\nCCM State before config:\n"); |
||||||
|
printf(" sched pointer: %p\n", (void*)ccm_state.sched); |
||||||
|
printf(" nonce pointer: %p\n", (void*)ccm_state.nonce); |
||||||
|
printf(" mlen: %u\n", ccm_state.mlen); |
||||||
|
|
||||||
|
printf("\nTesting CCM config...\n"); |
||||||
|
printf("Nonce size: %d, Tag size: %d\n", SC_NONCE_SIZE, SC_TAG_SIZE); |
||||||
|
printf("Using TCCcmMode_t pointer: %p\n", (void*)c); |
||||||
|
|
||||||
|
int ccm_result = tc_ccm_config(c, &sched, nonce, SC_NONCE_SIZE, SC_TAG_SIZE); |
||||||
|
printf("tc_ccm_config returned: %d\n", ccm_result); |
||||||
|
|
||||||
|
printf("\nCCM State after config:\n"); |
||||||
|
printf(" sched pointer: %p\n", (void*)ccm_state.sched); |
||||||
|
printf(" nonce pointer: %p\n", (void*)ccm_state.nonce); |
||||||
|
printf(" mlen: %u\n", ccm_state.mlen); |
||||||
|
|
||||||
|
if (ccm_result == TC_CRYPTO_SUCCESS) { |
||||||
|
printf("✓ CCM config successful\n"); |
||||||
|
} else { |
||||||
|
printf("❌ CCM config failed!\n"); |
||||||
|
printf("This suggests there might be an issue with:\n"); |
||||||
|
printf(" 1. Parameter validation\n"); |
||||||
|
printf(" 2. Missing dependencies\n"); |
||||||
|
printf(" 3. Structure alignment issues\n"); |
||||||
|
printf(" 4. Missing initialization routines\n"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
printf("❌ AES key setup failed\n"); |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
Loading…
Reference in new issue