mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-27 04:35:34 +08:00
Use sourcecode for libjuice
This commit is contained in:
45
thirdparty/libjuice/test/base64.c
vendored
Normal file
45
thirdparty/libjuice/test/base64.c
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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 "base64.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
int test_base64(void) {
|
||||
const char *str = "Man is distinguished, not only by his reason, but by this singular passion "
|
||||
"from other animals, which is a lust of the mind, that by a perseverance of "
|
||||
"delight in the continued and indefatigable generation of knowledge, exceeds "
|
||||
"the short vehemence of any carnal pleasure.";
|
||||
const char *expected =
|
||||
"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIH"
|
||||
"Bhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBw"
|
||||
"ZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb2"
|
||||
"4gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4"
|
||||
"=";
|
||||
|
||||
char buffer1[BUFFER_SIZE];
|
||||
if (BASE64_ENCODE(str, strlen(str), buffer1, BUFFER_SIZE) <= 0)
|
||||
return -1;
|
||||
|
||||
if (strcmp(buffer1, expected) != 0)
|
||||
return -1;
|
||||
|
||||
char buffer2[BUFFER_SIZE];
|
||||
int len = BASE64_DECODE(buffer1, buffer2, BUFFER_SIZE);
|
||||
if (len <= 0)
|
||||
return -1;
|
||||
|
||||
buffer2[len] = '\0';
|
||||
if (strcmp(buffer2, str) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
225
thirdparty/libjuice/test/bind.c
vendored
Normal file
225
thirdparty/libjuice/test/bind.c
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* 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
|
||||
#define BIND_ADDRESS "127.0.0.1"
|
||||
|
||||
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_bind() {
|
||||
juice_set_log_level(JUICE_LOG_LEVEL_DEBUG);
|
||||
|
||||
// Agent 1: Create agent
|
||||
juice_config_t config1;
|
||||
memset(&config1, 0, sizeof(config1));
|
||||
|
||||
config1.bind_address = BIND_ADDRESS;
|
||||
|
||||
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;
|
||||
|
||||
agent1 = juice_create(&config1);
|
||||
|
||||
// Agent 2: Create agent
|
||||
juice_config_t config2;
|
||||
memset(&config2, 0, sizeof(config2));
|
||||
|
||||
config2.bind_address = BIND_ADDRESS;
|
||||
|
||||
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;
|
||||
|
||||
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 --
|
||||
bool success = true;
|
||||
/*
|
||||
// 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 (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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// Filter host candidates for the bind address
|
||||
if(!strstr(sdp, "host") || !strstr(sdp, BIND_ADDRESS))
|
||||
return;
|
||||
|
||||
// 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);
|
||||
|
||||
// Filter host candidates for the bind address
|
||||
if(!strstr(sdp, "host") || !strstr(sdp, BIND_ADDRESS))
|
||||
return;
|
||||
|
||||
// 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);
|
||||
}
|
||||
203
thirdparty/libjuice/test/conflict.c
vendored
Normal file
203
thirdparty/libjuice/test/conflict.c
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
/**
|
||||
* 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_conflict() {
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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: 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);
|
||||
|
||||
// Setting the remote description now on both agents will hint them both into controlling mode,
|
||||
// creating an ICE role conflict
|
||||
|
||||
// Agent 1: Receive description from agent 2
|
||||
juice_set_remote_description(agent1, sdp2);
|
||||
|
||||
// Agent 2: Receive description from agent 1
|
||||
juice_set_remote_description(agent2, sdp1);
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
228
thirdparty/libjuice/test/connectivity.c
vendored
Normal file
228
thirdparty/libjuice/test/connectivity.c
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* 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_connectivity() {
|
||||
juice_set_log_level(JUICE_LOG_LEVEL_DEBUG);
|
||||
|
||||
// Agent 1: Create agent
|
||||
juice_config_t config1;
|
||||
memset(&config1, 0, sizeof(config1));
|
||||
|
||||
// STUN server example
|
||||
config1.stun_server_host = "stun.l.google.com";
|
||||
config1.stun_server_port = 19302;
|
||||
|
||||
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;
|
||||
|
||||
agent1 = juice_create(&config1);
|
||||
|
||||
// Agent 2: Create agent
|
||||
juice_config_t config2;
|
||||
memset(&config2, 0, sizeof(config2));
|
||||
|
||||
// STUN server example
|
||||
config2.stun_server_host = "stun.l.google.com";
|
||||
config2.stun_server_port = 19302;
|
||||
|
||||
// Port range example
|
||||
config2.local_port_range_begin = 60000;
|
||||
config2.local_port_range_end = 61000;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
22
thirdparty/libjuice/test/crc32.c
vendored
Normal file
22
thirdparty/libjuice/test/crc32.c
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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 "crc32.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
int test_crc32(void) {
|
||||
const char *str = "The quick brown fox jumps over the lazy dog";
|
||||
uint32_t expected = 0x414fa339;
|
||||
|
||||
if (CRC32(str, strlen(str)) != expected)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
95
thirdparty/libjuice/test/gathering.c
vendored
Normal file
95
thirdparty/libjuice/test/gathering.c
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* 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 *agent;
|
||||
static bool success = false;
|
||||
static bool done = false;
|
||||
|
||||
static void on_state_changed(juice_agent_t *agent, juice_state_t state, void *user_ptr);
|
||||
static void on_candidate(juice_agent_t *agent, const char *sdp, void *user_ptr);
|
||||
static void on_gathering_done(juice_agent_t *agent, void *user_ptr);
|
||||
|
||||
int test_gathering() {
|
||||
juice_set_log_level(JUICE_LOG_LEVEL_DEBUG);
|
||||
|
||||
// Create agent
|
||||
juice_config_t config;
|
||||
memset(&config, 0, sizeof(config));
|
||||
|
||||
// STUN server example
|
||||
config.stun_server_host = "stun.l.google.com";
|
||||
config.stun_server_port = 19302;
|
||||
|
||||
config.cb_state_changed = on_state_changed;
|
||||
config.cb_candidate = on_candidate;
|
||||
config.cb_gathering_done = on_gathering_done;
|
||||
config.user_ptr = NULL;
|
||||
|
||||
agent = juice_create(&config);
|
||||
|
||||
// Generate local description
|
||||
char sdp[JUICE_MAX_SDP_STRING_LEN];
|
||||
juice_get_local_description(agent, sdp, JUICE_MAX_SDP_STRING_LEN);
|
||||
printf("Local description:\n%s\n", sdp);
|
||||
|
||||
// Gather candidates
|
||||
juice_gather_candidates(agent);
|
||||
|
||||
// Wait until gathering done
|
||||
int secs = 10;
|
||||
while (secs-- && !done && !success)
|
||||
sleep(1);
|
||||
|
||||
// Destroy
|
||||
juice_destroy(agent);
|
||||
|
||||
if (success) {
|
||||
printf("Success\n");
|
||||
return 0;
|
||||
} else {
|
||||
printf("Failure\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// On state changed
|
||||
static void on_state_changed(juice_agent_t *agent, juice_state_t state, void *user_ptr) {
|
||||
printf("State: %s\n", juice_state_to_string(state));
|
||||
}
|
||||
|
||||
// On local candidate gathered
|
||||
static void on_candidate(juice_agent_t *agent, const char *sdp, void *user_ptr) {
|
||||
printf("Candidate: %s\n", sdp);
|
||||
|
||||
// Success if a valid srflx candidate is emitted
|
||||
if (strstr(sdp, " typ srflx raddr 0.0.0.0 rport 0"))
|
||||
success = true;
|
||||
}
|
||||
|
||||
// On local candidates gathering done
|
||||
static void on_gathering_done(juice_agent_t *agent, void *user_ptr) {
|
||||
printf("Gathering done\n");
|
||||
|
||||
done = true;
|
||||
}
|
||||
110
thirdparty/libjuice/test/main.c
vendored
Normal file
110
thirdparty/libjuice/test/main.c
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* 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 <stdio.h>
|
||||
|
||||
int test_crc32(void);
|
||||
int test_base64(void);
|
||||
int test_stun(void);
|
||||
int test_connectivity(void);
|
||||
int test_thread(void);
|
||||
int test_mux(void);
|
||||
int test_notrickle(void);
|
||||
int test_gathering(void);
|
||||
int test_turn(void);
|
||||
int test_conflict(void);
|
||||
int test_bind(void);
|
||||
|
||||
#ifndef NO_SERVER
|
||||
int test_server(void);
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
juice_set_log_level(JUICE_LOG_LEVEL_WARN);
|
||||
|
||||
printf("\nRunning CRC32 implementation test...\n");
|
||||
if (test_crc32()) {
|
||||
fprintf(stderr, "CRC32 implementation test failed\n");
|
||||
return -2;
|
||||
}
|
||||
|
||||
printf("\nRunning base64 implementation test...\n");
|
||||
if (test_base64()) {
|
||||
fprintf(stderr, "base64 implementation test failed\n");
|
||||
return -2;
|
||||
}
|
||||
|
||||
printf("\nRunning STUN parsing implementation test...\n");
|
||||
if (test_stun()) {
|
||||
fprintf(stderr, "STUN parsing implementation test failed\n");
|
||||
return -3;
|
||||
}
|
||||
|
||||
printf("\nRunning candidates gathering test...\n");
|
||||
if (test_gathering()) {
|
||||
fprintf(stderr, "Candidates gathering test failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("\nRunning connectivity test...\n");
|
||||
if (test_connectivity()) {
|
||||
fprintf(stderr, "Connectivity test failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Disabled as the Open Relay TURN server is unreliable
|
||||
/*
|
||||
printf("\nRunning TURN connectivity test...\n");
|
||||
if (test_turn()) {
|
||||
fprintf(stderr, "TURN connectivity test failed\n");
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
printf("\nRunning thread-mode connectivity test...\n");
|
||||
if (test_thread()) {
|
||||
fprintf(stderr, "Thread-mode connectivity test failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("\nRunning mux-mode connectivity test...\n");
|
||||
if (test_mux()) {
|
||||
fprintf(stderr, "Mux-mode connectivity test failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("\nRunning non-trickled connectivity test...\n");
|
||||
if (test_notrickle()) {
|
||||
fprintf(stderr, "Non-trickled connectivity test failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("\nRunning connectivity test with role conflict...\n");
|
||||
if (test_conflict()) {
|
||||
fprintf(stderr, "Connectivity test with role conflict failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("\nRunning connectivity test with bind address...\n");
|
||||
if (test_bind()) {
|
||||
fprintf(stderr, "Connectivity test with bind address failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifndef NO_SERVER
|
||||
printf("\nRunning server test...\n");
|
||||
if (test_server()) {
|
||||
fprintf(stderr, "Server test failed\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
226
thirdparty/libjuice/test/mux.c
vendored
Normal file
226
thirdparty/libjuice/test/mux.c
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
* Copyright (c) 2022 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);
|
||||
|
||||
bool endswith(const char *str, const char *suffix) {
|
||||
size_t str_len = strlen(str);
|
||||
size_t suffix_len = strlen(suffix);
|
||||
return str_len >= suffix_len && memcmp(str + str_len - suffix_len, suffix, suffix_len) == 0;
|
||||
}
|
||||
|
||||
int test_mux() {
|
||||
juice_set_log_level(JUICE_LOG_LEVEL_DEBUG);
|
||||
|
||||
// Agent 1: Create agent
|
||||
juice_config_t config1;
|
||||
memset(&config1, 0, sizeof(config1));
|
||||
config1.stun_server_host = "stun.l.google.com";
|
||||
config1.stun_server_port = 19302;
|
||||
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;
|
||||
agent1 = juice_create(&config1);
|
||||
|
||||
// Agent 2: Create agent in mux mode on port 60000
|
||||
juice_config_t config2;
|
||||
memset(&config2, 0, sizeof(config2));
|
||||
config2.concurrency_mode = JUICE_CONCURRENCY_MODE_MUX;
|
||||
config2.local_port_range_begin = 60000;
|
||||
config2.local_port_range_end = 60000;
|
||||
config2.cb_state_changed = on_state_changed1;
|
||||
config2.cb_candidate = on_candidate1;
|
||||
config2.cb_gathering_done = on_gathering_done1;
|
||||
config2.cb_recv = on_recv1;
|
||||
config2.user_ptr = NULL;
|
||||
|
||||
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);
|
||||
success &= endswith(remoteAddr, ":60000");
|
||||
}
|
||||
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);
|
||||
success &= endswith(localAddr, ":60000");
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
201
thirdparty/libjuice/test/notrickle.c
vendored
Normal file
201
thirdparty/libjuice/test/notrickle.c
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* 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_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_notrickle() {
|
||||
juice_set_log_level(JUICE_LOG_LEVEL_DEBUG);
|
||||
|
||||
// Agent 1: Create agent
|
||||
juice_config_t config1;
|
||||
memset(&config1, 0, sizeof(config1));
|
||||
|
||||
// STUN server example
|
||||
config1.stun_server_host = "stun.l.google.com";
|
||||
config1.stun_server_port = 19302;
|
||||
|
||||
config1.cb_state_changed = on_state_changed1;
|
||||
config1.cb_gathering_done = on_gathering_done1;
|
||||
config1.cb_recv = on_recv1;
|
||||
config1.user_ptr = NULL;
|
||||
|
||||
agent1 = juice_create(&config1);
|
||||
|
||||
// Agent 2: Create agent
|
||||
juice_config_t config2;
|
||||
memset(&config2, 0, sizeof(config2));
|
||||
|
||||
// STUN server example
|
||||
config2.stun_server_host = "stun.l.google.com";
|
||||
config2.stun_server_port = 19302;
|
||||
|
||||
config2.cb_state_changed = on_state_changed2;
|
||||
config2.cb_gathering_done = on_gathering_done2;
|
||||
config2.cb_recv = on_recv2;
|
||||
config2.user_ptr = NULL;
|
||||
|
||||
agent2 = juice_create(&config2);
|
||||
|
||||
// Agent 1: Gather candidates
|
||||
juice_gather_candidates(agent1);
|
||||
|
||||
sleep(4);
|
||||
|
||||
// -- 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 (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);
|
||||
}
|
||||
|
||||
// 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 ((!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_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);
|
||||
if ((!strstr(local, "typ host") && !strstr(local, "typ prflx")) ||
|
||||
(!strstr(remote, "typ host") && !strstr(remote, "typ prflx")))
|
||||
success = false; // local connection should be possible
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 candidates gathering done
|
||||
static void on_gathering_done1(juice_agent_t *agent, void *user_ptr) {
|
||||
printf("Gathering done 1\n");
|
||||
|
||||
// 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: Gather candidates
|
||||
juice_gather_candidates(agent2);
|
||||
}
|
||||
|
||||
// Agent 2: on local candidates gathering done
|
||||
static void on_gathering_done2(juice_agent_t *agent, void *user_ptr) {
|
||||
printf("Gathering done 2\n");
|
||||
|
||||
// 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: 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);
|
||||
}
|
||||
274
thirdparty/libjuice/test/server.c
vendored
Normal file
274
thirdparty/libjuice/test/server.c
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
#ifndef NO_SERVER
|
||||
|
||||
#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
|
||||
|
||||
#define TURN_USERNAME1 "server_test1"
|
||||
#define TURN_PASSWORD1 "79874638521694"
|
||||
|
||||
#define TURN_USERNAME2 "server_test2"
|
||||
#define TURN_PASSWORD2 "36512189907731"
|
||||
|
||||
static juice_server_t *server;
|
||||
static juice_agent_t *agent1;
|
||||
static juice_agent_t *agent2;
|
||||
static bool srflx_success = false;
|
||||
static bool relay_success = false;
|
||||
static bool success = false;
|
||||
|
||||
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_server() {
|
||||
juice_set_log_level(JUICE_LOG_LEVEL_DEBUG);
|
||||
|
||||
// Create server
|
||||
juice_server_credentials_t credentials[1];
|
||||
memset(&credentials, 0, sizeof(credentials));
|
||||
credentials[0].username = TURN_USERNAME1;
|
||||
credentials[0].password = TURN_PASSWORD1;
|
||||
|
||||
juice_server_config_t server_config;
|
||||
memset(&server_config, 0, sizeof(server_config));
|
||||
server_config.port = 3478;
|
||||
server_config.credentials = credentials;
|
||||
server_config.credentials_count = 1;
|
||||
server_config.max_allocations = 100;
|
||||
server_config.realm = "Juice test server";
|
||||
server = juice_server_create(&server_config);
|
||||
|
||||
if(juice_server_get_port(server) != 3478) {
|
||||
printf("juice_server_get_port failed\n");
|
||||
juice_server_destroy(server);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Added credentials example
|
||||
juice_server_credentials_t added_credentials[1];
|
||||
memset(&added_credentials, 0, sizeof(added_credentials));
|
||||
added_credentials[0].username = TURN_USERNAME2;
|
||||
added_credentials[0].password = TURN_PASSWORD2;
|
||||
juice_server_add_credentials(server, added_credentials, 60000); // 60s
|
||||
|
||||
// Agent 1: Create agent
|
||||
juice_config_t config1;
|
||||
memset(&config1, 0, sizeof(config1));
|
||||
|
||||
// Set STUN server
|
||||
config1.stun_server_host = "localhost";
|
||||
config1.stun_server_port = 3478;
|
||||
|
||||
// Set TURN server
|
||||
juice_turn_server_t turn_server1;
|
||||
memset(&turn_server1, 0, sizeof(turn_server1));
|
||||
turn_server1.host = "localhost";
|
||||
turn_server1.port = 3478;
|
||||
turn_server1.username = TURN_USERNAME1;
|
||||
turn_server1.password = TURN_PASSWORD1;
|
||||
config1.turn_servers = &turn_server1;
|
||||
config1.turn_servers_count = 1;
|
||||
|
||||
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;
|
||||
|
||||
agent1 = juice_create(&config1);
|
||||
|
||||
// Agent 2: Create agent
|
||||
juice_config_t config2;
|
||||
memset(&config2, 0, sizeof(config2));
|
||||
|
||||
// Set STUN server
|
||||
config2.stun_server_host = "localhost";
|
||||
config2.stun_server_port = 3478;
|
||||
|
||||
// Set TURN server
|
||||
juice_turn_server_t turn_server2;
|
||||
memset(&turn_server2, 0, sizeof(turn_server2));
|
||||
turn_server2.host = "localhost";
|
||||
turn_server2.port = 3478;
|
||||
turn_server2.username = TURN_USERNAME2;
|
||||
turn_server2.password = TURN_PASSWORD2;
|
||||
config2.turn_servers = &turn_server2;
|
||||
config2.turn_servers_count = 1;
|
||||
|
||||
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;
|
||||
|
||||
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 --
|
||||
|
||||
// Agent 1: destroy
|
||||
juice_destroy(agent1);
|
||||
|
||||
// Agent 2: destroy
|
||||
juice_destroy(agent2);
|
||||
|
||||
// Destroy server
|
||||
juice_server_destroy(server);
|
||||
|
||||
if (srflx_success && relay_success && success) {
|
||||
printf("Success\n");
|
||||
return 0;
|
||||
} else {
|
||||
printf("Failure\n");
|
||||
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);
|
||||
|
||||
// Success if a valid srflx candidate is emitted
|
||||
if (strstr(sdp, " typ srflx raddr 0.0.0.0 rport 0"))
|
||||
srflx_success = true;
|
||||
|
||||
// Success if a valid relay candidate is emitted
|
||||
if (strstr(sdp, " typ relay raddr 0.0.0.0 rport 0"))
|
||||
relay_success = true;
|
||||
|
||||
// Filter relayed candidates
|
||||
if (!strstr(sdp, "relay"))
|
||||
return;
|
||||
|
||||
// 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);
|
||||
|
||||
// Success if a valid srflx candidate is emitted
|
||||
if (strstr(sdp, " typ srflx raddr 0.0.0.0 rport 0"))
|
||||
srflx_success = true;
|
||||
|
||||
// Success if a valid relay candidate is emitted
|
||||
if (strstr(sdp, " typ relay raddr 0.0.0.0 rport 0"))
|
||||
relay_success = true;
|
||||
|
||||
// Filter relayed candidates
|
||||
if (!strstr(sdp, "relay"))
|
||||
return;
|
||||
|
||||
// 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);
|
||||
success = true;
|
||||
}
|
||||
|
||||
// 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);
|
||||
success = true;
|
||||
}
|
||||
|
||||
#endif // ifndef NO_SERVER
|
||||
155
thirdparty/libjuice/test/stun.c
vendored
Normal file
155
thirdparty/libjuice/test/stun.c
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* 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 "stun.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
int test_stun(void) {
|
||||
stun_message_t msg;
|
||||
|
||||
uint8_t message1[] = {
|
||||
0x00, 0x01, 0x00, 0x58, // Request type and message length
|
||||
0x21, 0x12, 0xa4, 0x42, // Magic cookie
|
||||
0xb7, 0xe7, 0xa7, 0x01, // Transaction ID
|
||||
0xbc, 0x34, 0xd6, 0x86, //
|
||||
0xfa, 0x87, 0xdf, 0xae, //
|
||||
0x80, 0x22, 0x00, 0x10, // SOFTWARE attribute header
|
||||
0x53, 0x54, 0x55, 0x4e, //
|
||||
0x20, 0x74, 0x65, 0x73, //
|
||||
0x74, 0x20, 0x63, 0x6c, //
|
||||
0x69, 0x65, 0x6e, 0x74, //
|
||||
0x00, 0x24, 0x00, 0x04, // PRIORITY attribute header
|
||||
0x6e, 0x00, 0x01, 0xff, //
|
||||
0x80, 0x29, 0x00, 0x08, // ICE-CONTROLLED attribute header
|
||||
0x93, 0x2f, 0xf9, 0xb1, //
|
||||
0x51, 0x26, 0x3b, 0x36, //
|
||||
0x00, 0x06, 0x00, 0x09, // USERNAME attribute header
|
||||
0x65, 0x76, 0x74, 0x6a, //
|
||||
0x3a, 0x68, 0x36, 0x76, //
|
||||
0x59, 0x20, 0x20, 0x20, //
|
||||
0x00, 0x08, 0x00, 0x14, // MESSAGE-INTEGRITY attribute header
|
||||
0x9a, 0xea, 0xa7, 0x0c, //
|
||||
0xbf, 0xd8, 0xcb, 0x56, //
|
||||
0x78, 0x1e, 0xf2, 0xb5, //
|
||||
0xb2, 0xd3, 0xf2, 0x49, //
|
||||
0xc1, 0xb5, 0x71, 0xa2, //
|
||||
0x80, 0x28, 0x00, 0x04, // FINGERPRINT attribute header
|
||||
0xe5, 0x7a, 0x3b, 0xcf, //
|
||||
};
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
if (_juice_stun_read(message1, sizeof(message1), &msg) <= 0)
|
||||
return -1;
|
||||
|
||||
if(msg.msg_class != STUN_CLASS_REQUEST || msg.msg_method != STUN_METHOD_BINDING)
|
||||
return -1;
|
||||
|
||||
if (memcmp(msg.transaction_id, message1 + 8, 12) != 0)
|
||||
return -1;
|
||||
|
||||
if (msg.priority != 0x6e0001ff)
|
||||
return -1;
|
||||
|
||||
if (msg.ice_controlled != 0x932ff9b151263b36LL)
|
||||
return -1;
|
||||
|
||||
if (!msg.has_integrity)
|
||||
return -1;
|
||||
|
||||
if (!_juice_stun_check_integrity(message1, sizeof(message1), &msg, "VOkJxbRl1RmTxUk/WvJxBt"))
|
||||
return -1;
|
||||
|
||||
if(msg.error_code != 0)
|
||||
return -1;
|
||||
|
||||
// The test vector in RFC 8489 is completely wrong
|
||||
// See https://www.rfc-editor.org/errata_search.php?rfc=8489
|
||||
uint8_t message2[] = {
|
||||
0x00, 0x01, 0x00, 0x90, // Request type and message length
|
||||
0x21, 0x12, 0xa4, 0x42, // Magic cookie
|
||||
0x78, 0xad, 0x34, 0x33, // Transaction ID
|
||||
0xc6, 0xad, 0x72, 0xc0, //
|
||||
0x29, 0xda, 0x41, 0x2e, //
|
||||
0x00, 0x1e, 0x00, 0x20, // USERHASH attribute header
|
||||
0x4a, 0x3c, 0xf3, 0x8f, // Userhash value (32 bytes)
|
||||
0xef, 0x69, 0x92, 0xbd, //
|
||||
0xa9, 0x52, 0xc6, 0x78, //
|
||||
0x04, 0x17, 0xda, 0x0f, //
|
||||
0x24, 0x81, 0x94, 0x15, //
|
||||
0x56, 0x9e, 0x60, 0xb2, //
|
||||
0x05, 0xc4, 0x6e, 0x41, //
|
||||
0x40, 0x7f, 0x17, 0x04, //
|
||||
0x00, 0x15, 0x00, 0x29, // NONCE attribute header
|
||||
0x6f, 0x62, 0x4d, 0x61, // Nonce value and padding (3 bytes)
|
||||
0x74, 0x4a, 0x6f, 0x73, //
|
||||
0x32, 0x41, 0x41, 0x41, //
|
||||
0x43, 0x66, 0x2f, 0x2f, //
|
||||
0x34, 0x39, 0x39, 0x6b, //
|
||||
0x39, 0x35, 0x34, 0x64, //
|
||||
0x36, 0x4f, 0x4c, 0x33, //
|
||||
0x34, 0x6f, 0x4c, 0x39, //
|
||||
0x46, 0x53, 0x54, 0x76, //
|
||||
0x79, 0x36, 0x34, 0x73, //
|
||||
0x41, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x14, 0x00, 0x0b, // REALM attribute header
|
||||
0x65, 0x78, 0x61, 0x6d, // Realm value (11 bytes) and padding (1 byte)
|
||||
0x70, 0x6c, 0x65, 0x2e, //
|
||||
0x6f, 0x72, 0x67, 0x00, //
|
||||
0x00, 0x1d, 0x00, 0x04, // PASSWORD-ALGORITHM attribute header
|
||||
0x00, 0x02, 0x00, 0x00, // PASSWORD-ALGORITHM value (4 bytes)
|
||||
0x00, 0x1c, 0x00, 0x20, // MESSAGE-INTEGRITY-SHA256 attribute header
|
||||
0xb5, 0xc7, 0xbf, 0x00, // HMAC-SHA256 value
|
||||
0x5b, 0x6c, 0x52, 0xa2, //
|
||||
0x1c, 0x51, 0xc5, 0xe8, //
|
||||
0x92, 0xf8, 0x19, 0x24, //
|
||||
0x13, 0x62, 0x96, 0xcb, //
|
||||
0x92, 0x7c, 0x43, 0x14, //
|
||||
0x93, 0x09, 0x27, 0x8c, //
|
||||
0xc6, 0x51, 0x8e, 0x65, //
|
||||
};
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
if (_juice_stun_read(message2, sizeof(message2), &msg) <= 0)
|
||||
return -1;
|
||||
|
||||
if(msg.msg_class != STUN_CLASS_REQUEST || msg.msg_method != STUN_METHOD_BINDING)
|
||||
return -1;
|
||||
|
||||
if (memcmp(msg.transaction_id, message2 + 8, 12) != 0)
|
||||
return -1;
|
||||
|
||||
if (!msg.credentials.enable_userhash)
|
||||
return -1;
|
||||
|
||||
if (memcmp(msg.credentials.userhash, message2 + 24, 32) != 0)
|
||||
return -1;
|
||||
|
||||
if (strcmp(msg.credentials.realm, "example.org") != 0)
|
||||
return -1;
|
||||
|
||||
if (strcmp(msg.credentials.nonce, "obMatJos2AAACf//499k954d6OL34oL9FSTvy64sA") != 0)
|
||||
return -1;
|
||||
|
||||
if (!msg.has_integrity)
|
||||
return -1;
|
||||
|
||||
// Username is "<U+30DE><U+30C8><U+30EA><U+30C3><U+30AF><U+30B9>" or "マトリックス"
|
||||
// aka "The Matrix" in Japanese
|
||||
strcpy(msg.credentials.username, "マトリックス");
|
||||
if (!_juice_stun_check_integrity(message2, sizeof(message2), &msg, "TheMatrIX"))
|
||||
return -1;
|
||||
|
||||
if(msg.error_code != STUN_ERROR_INTERNAL_VALIDATION_FAILED)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
220
thirdparty/libjuice/test/thread.c
vendored
Normal file
220
thirdparty/libjuice/test/thread.c
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* Copyright (c) 2022 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_thread() {
|
||||
juice_set_log_level(JUICE_LOG_LEVEL_DEBUG);
|
||||
|
||||
// Agent 1: Create agent in thread concurrency mode
|
||||
juice_config_t config1;
|
||||
memset(&config1, 0, sizeof(config1));
|
||||
config1.concurrency_mode = JUICE_CONCURRENCY_MODE_THREAD;
|
||||
config1.stun_server_host = "stun.l.google.com";
|
||||
config1.stun_server_port = 19302;
|
||||
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;
|
||||
|
||||
agent1 = juice_create(&config1);
|
||||
|
||||
// Agent 2: Create agent in thread concurrency mode
|
||||
juice_config_t config2;
|
||||
memset(&config2, 0, sizeof(config2));
|
||||
config2.concurrency_mode = JUICE_CONCURRENCY_MODE_THREAD;
|
||||
config2.stun_server_host = "stun.l.google.com";
|
||||
config2.stun_server_port = 19302;
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
241
thirdparty/libjuice/test/turn.c
vendored
Normal file
241
thirdparty/libjuice/test/turn.c
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
/**
|
||||
* 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_turn() {
|
||||
juice_set_log_level(JUICE_LOG_LEVEL_DEBUG);
|
||||
|
||||
// Agent 1: Create agent
|
||||
juice_config_t config1;
|
||||
memset(&config1, 0, sizeof(config1));
|
||||
|
||||
// STUN server example (use your own server in production)
|
||||
config1.stun_server_host = "openrelay.metered.ca";
|
||||
config1.stun_server_port = 80;
|
||||
|
||||
// TURN server example (use your own server in production)
|
||||
juice_turn_server_t turn_server;
|
||||
memset(&turn_server, 0, sizeof(turn_server));
|
||||
turn_server.host = "openrelay.metered.ca";
|
||||
turn_server.port = 80;
|
||||
turn_server.username = "openrelayproject";
|
||||
turn_server.password = "openrelayproject";
|
||||
config1.turn_servers = &turn_server;
|
||||
config1.turn_servers_count = 1;
|
||||
|
||||
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;
|
||||
|
||||
agent1 = juice_create(&config1);
|
||||
|
||||
// Agent 2: Create agent
|
||||
juice_config_t config2;
|
||||
memset(&config2, 0, sizeof(config2));
|
||||
|
||||
// STUN server example (use your own server in production)
|
||||
config2.stun_server_host = "openrelay.metered.ca";
|
||||
config2.stun_server_port = 80;
|
||||
|
||||
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;
|
||||
|
||||
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 || state1 == JUICE_STATE_CONNECTED) &&
|
||||
(state2 == JUICE_STATE_CONNECTED || 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);
|
||||
|
||||
success &= (strstr(local, "relay") != NULL);
|
||||
}
|
||||
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);
|
||||
|
||||
success &= (strstr(remote, "relay") != NULL);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// Filter relayed candidates
|
||||
if (!strstr(sdp, "relay"))
|
||||
return;
|
||||
|
||||
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) {
|
||||
// Filter server reflexive candidates
|
||||
if (!strstr(sdp, "srflx"))
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user