Skip to content

Commit

Permalink
Implement ICE-TCP
Browse files Browse the repository at this point in the history
  • Loading branch information
seaduboi-openai committed Jan 22, 2025
1 parent 2fb91a3 commit 54b3133
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ set(TESTS_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/test/conflict.c
${CMAKE_CURRENT_SOURCE_DIR}/test/bind.c
${CMAKE_CURRENT_SOURCE_DIR}/test/ufrag.c
${CMAKE_CURRENT_SOURCE_DIR}/test/tcp.c
)
source_group("Test Files" FILES "${TESTS_SOURCES}")

Expand Down
8 changes: 8 additions & 0 deletions include/juice/juice.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ typedef enum juice_concurrency_mode {
JUICE_CONCURRENCY_MODE_THREAD, // Each connection runs in its own thread
} juice_concurrency_mode_t;

typedef enum juice_ice_tcp_mode {
JUICE_ICE_TCP_MODE_NONE = 0, // ICE-TCP is disabled
JUICE_ICE_TCP_MODE_ACTIVE, // ICE-TCP will operate as a client
JUICE_ICE_TCP_MODE_PASSIVE, // ICE-TCP will operate as a server
} juice_ice_tcp_mode;

typedef struct juice_config {
juice_concurrency_mode_t concurrency_mode;

Expand All @@ -104,6 +110,8 @@ typedef struct juice_config {
uint16_t local_port_range_begin;
uint16_t local_port_range_end;

juice_ice_tcp_mode_t ice_tcp_mode;

juice_cb_state_changed_t cb_state_changed;
juice_cb_candidate_t cb_candidate;
juice_cb_gathering_done_t cb_gathering_done;
Expand Down
7 changes: 7 additions & 0 deletions test/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ int test_turn(void);
int test_conflict(void);
int test_bind(void);
int test_ufrag(void);
int test_tcp(void);

#ifndef NO_SERVER
int test_server(void);
Expand All @@ -30,6 +31,12 @@ int test_server(void);
int main(int argc, char **argv) {
juice_set_log_level(JUICE_LOG_LEVEL_WARN);

printf("\nRunning TCP test...\n");
if (test_tcp()) {
fprintf(stderr, "TCP test failed\n");
return -2;
}

printf("\nRunning CRC32 implementation test...\n");
if (test_crc32()) {
fprintf(stderr, "CRC32 implementation test failed\n");
Expand Down
220 changes: 220 additions & 0 deletions test/tcp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/**
* Copyright (c) 2020 Paul-Louis Ageneau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

#include "juice/juice.h"

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#ifdef _WIN32
#include <windows.h>
static void sleep(unsigned int secs) { Sleep(secs * 1000); }
#else
#include <unistd.h> // for sleep
#endif

#define BUFFER_SIZE 4096

static juice_agent_t *agent1;
static juice_agent_t *agent2;

static void on_state_changed1(juice_agent_t *agent, juice_state_t state, void *user_ptr);
static void on_state_changed2(juice_agent_t *agent, juice_state_t state, void *user_ptr);

static void on_candidate1(juice_agent_t *agent, const char *sdp, void *user_ptr);
static void on_candidate2(juice_agent_t *agent, const char *sdp, void *user_ptr);

static void on_gathering_done1(juice_agent_t *agent, void *user_ptr);
static void on_gathering_done2(juice_agent_t *agent, void *user_ptr);

static void on_recv1(juice_agent_t *agent, const char *data, size_t size, void *user_ptr);
static void on_recv2(juice_agent_t *agent, const char *data, size_t size, void *user_ptr);

int test_tcp() {
juice_set_log_level(JUICE_LOG_LEVEL_DEBUG);

// Agent 1: Create agent
juice_config_t config1;
memset(&config1, 0, sizeof(config1));

config1.cb_state_changed = on_state_changed1;
config1.cb_candidate = on_candidate1;
config1.cb_gathering_done = on_gathering_done1;
config1.cb_recv = on_recv1;
config1.user_ptr = NULL;
config1.enable_ice_tcp_passive = true;

agent1 = juice_create(&config1);

// Agent 2: Create agent
juice_config_t config2;
memset(&config2, 0, sizeof(config2));

config2.cb_state_changed = on_state_changed2;
config2.cb_candidate = on_candidate2;
config2.cb_gathering_done = on_gathering_done2;
config2.cb_recv = on_recv2;
config2.user_ptr = NULL;
config1.enable_ice_tcp_active = true;

// agent2 = juice_create(&config2);

// Agent 1: Generate local description
char sdp1[JUICE_MAX_SDP_STRING_LEN];
juice_get_local_description(agent1, sdp1, JUICE_MAX_SDP_STRING_LEN);
printf("Local description 1:\n%s\n", sdp1);

// // Agent 2: Receive description from agent 1
// juice_set_remote_description(agent2, sdp1);

// // Agent 2: Generate local description
// char sdp2[JUICE_MAX_SDP_STRING_LEN];
// juice_get_local_description(agent2, sdp2, JUICE_MAX_SDP_STRING_LEN);
// printf("Local description 2:\n%s\n", sdp2);

// // Agent 1: Receive description from agent 2
// juice_set_remote_description(agent1, sdp2);

// Agent 1: Gather candidates (and send them to agent 2)
juice_gather_candidates(agent1);
sleep(2);

// // Agent 2: Gather candidates (and send them to agent 1)
// juice_gather_candidates(agent2);
// sleep(2);

// -- Connection should be finished --

// // Check states
// juice_state_t state1 = juice_get_state(agent1);
// juice_state_t state2 = juice_get_state(agent2);
// bool success = (state1 == JUICE_STATE_COMPLETED && state2 == JUICE_STATE_COMPLETED);

// // Retrieve candidates
// char local[JUICE_MAX_CANDIDATE_SDP_STRING_LEN];
// char remote[JUICE_MAX_CANDIDATE_SDP_STRING_LEN];
// if (success &=
// (juice_get_selected_candidates(agent1, local, JUICE_MAX_CANDIDATE_SDP_STRING_LEN, remote,
// JUICE_MAX_CANDIDATE_SDP_STRING_LEN) == 0)) {
// printf("Local candidate 1: %s\n", local);
// printf("Remote candidate 1: %s\n", remote);
// if ((!strstr(local, "typ host") && !strstr(local, "typ prflx")) ||
// (!strstr(remote, "typ host") && !strstr(remote, "typ prflx")))
// success = false; // local connection should be possible
// }
// if (success &=
// (juice_get_selected_candidates(agent2, local, JUICE_MAX_CANDIDATE_SDP_STRING_LEN, remote,
// JUICE_MAX_CANDIDATE_SDP_STRING_LEN) == 0)) {
// printf("Local candidate 2: %s\n", local);
// printf("Remote candidate 2: %s\n", remote);
// if ((!strstr(local, "typ host") && !strstr(local, "typ prflx")) ||
// (!strstr(remote, "typ host") && !strstr(remote, "typ prflx")))
// success = false; // local connection should be possible
// }

// // Retrieve addresses
// char localAddr[JUICE_MAX_ADDRESS_STRING_LEN];
// char remoteAddr[JUICE_MAX_ADDRESS_STRING_LEN];
// if (success &= (juice_get_selected_addresses(agent1, localAddr, JUICE_MAX_ADDRESS_STRING_LEN,
// remoteAddr, JUICE_MAX_ADDRESS_STRING_LEN) == 0)) {
// printf("Local address 1: %s\n", localAddr);
// printf("Remote address 1: %s\n", remoteAddr);
// }
// if (success &= (juice_get_selected_addresses(agent2, localAddr, JUICE_MAX_ADDRESS_STRING_LEN,
// remoteAddr, JUICE_MAX_ADDRESS_STRING_LEN) == 0)) {
// printf("Local address 2: %s\n", localAddr);
// printf("Remote address 2: %s\n", remoteAddr);
// }

// // Agent 1: destroy
// juice_destroy(agent1);

// // Agent 2: destroy
// juice_destroy(agent2);

// if (success) {
// printf("Success\n");
// return 0;
// } else {
// printf("Failure\n");
// return -1;
// }
//
return -1;
}

// Agent 1: on state changed
static void on_state_changed1(juice_agent_t *agent, juice_state_t state, void *user_ptr) {
// printf("State 1: %s\n", juice_state_to_string(state));
//
// if (state == JUICE_STATE_CONNECTED) {
// // Agent 1: on connected, send a message
// const char *message = "Hello from 1";
// juice_send(agent, message, strlen(message));
// }
}
//
// Agent 2: on state changed
static void on_state_changed2(juice_agent_t *agent, juice_state_t state, void *user_ptr) {
// printf("State 2: %s\n", juice_state_to_string(state));
// if (state == JUICE_STATE_CONNECTED) {
// // Agent 2: on connected, send a message
// const char *message = "Hello from 2";
// juice_send(agent, message, strlen(message));
// }
}

// Agent 1: on local candidate gathered
static void on_candidate1(juice_agent_t *agent, const char *sdp, void *user_ptr) {
// printf("Candidate 1: %s\n", sdp);
//
// // Agent 2: Receive it from agent 1
// juice_add_remote_candidate(agent2, sdp);
}
//
// Agent 2: on local candidate gathered
static void on_candidate2(juice_agent_t *agent, const char *sdp, void *user_ptr) {
// printf("Candidate 2: %s\n", sdp);
//
// // Agent 1: Receive it from agent 2
// juice_add_remote_candidate(agent1, sdp);
}

// Agent 1: on local candidates gathering done
static void on_gathering_done1(juice_agent_t *agent, void *user_ptr) {
// printf("Gathering done 1\n");
// juice_set_remote_gathering_done(agent2); // optional
}

// Agent 2: on local candidates gathering done
static void on_gathering_done2(juice_agent_t *agent, void *user_ptr) {
// printf("Gathering done 2\n");
// juice_set_remote_gathering_done(agent1); // optional
}

// Agent 1: on message received
static void on_recv1(juice_agent_t *agent, const char *data, size_t size, void *user_ptr) {
// char buffer[BUFFER_SIZE];
// if (size > BUFFER_SIZE - 1)
// size = BUFFER_SIZE - 1;
// memcpy(buffer, data, size);
// buffer[size] = '\0';
// printf("Received 1: %s\n", buffer);
}
//
// Agent 2: on message received
static void on_recv2(juice_agent_t *agent, const char *data, size_t size, void *user_ptr) {
// char buffer[BUFFER_SIZE];
// if (size > BUFFER_SIZE - 1)
// size = BUFFER_SIZE - 1;
// memcpy(buffer, data, size);
// buffer[size] = '\0';
// printf("Received 2: %s\n", buffer);
}

0 comments on commit 54b3133

Please sign in to comment.