blob: 46ae22b850423364edc36c8c43301a00a5a97078 [file] [log] [blame]
#include "parameters.h"
#include "common.h"
#include "utils.h"
#include <rawrtc.h>
#include <rawrtcc.h>
#include <rawrtcdc.h>
#include <re.h>
#define DEBUG_MODULE "helper-parameters"
#define DEBUG_LEVEL 7
#include <re_dbg.h>
/*
* Set ICE parameters in dictionary.
*/
void set_ice_parameters(struct rawrtc_ice_parameters* const parameters, struct odict* const dict) {
char* username_fragment;
char* password;
bool ice_lite;
// Get values
EOE(rawrtc_ice_parameters_get_username_fragment(&username_fragment, parameters));
EOE(rawrtc_ice_parameters_get_password(&password, parameters));
EOE(rawrtc_ice_parameters_get_ice_lite(&ice_lite, parameters));
// Set ICE parameters
EOR(odict_entry_add(dict, "usernameFragment", ODICT_STRING, username_fragment));
EOR(odict_entry_add(dict, "password", ODICT_STRING, password));
EOR(odict_entry_add(dict, "iceLite", ODICT_BOOL, ice_lite));
// Un-reference values
mem_deref(password);
mem_deref(username_fragment);
}
/*
* Set ICE candidates in dictionary.
*/
void set_ice_candidates(struct rawrtc_ice_candidates* const parameters, struct odict* const array) {
size_t i;
struct odict* node;
// Set ICE candidates
for (i = 0; i < parameters->n_candidates; ++i) {
enum rawrtc_code error;
struct rawrtc_ice_candidate* const candidate = parameters->candidates[i];
char* foundation;
uint32_t priority;
char* ip;
enum rawrtc_ice_protocol protocol;
uint16_t port;
enum rawrtc_ice_candidate_type type;
enum rawrtc_ice_tcp_candidate_type tcp_type = RAWRTC_ICE_TCP_CANDIDATE_TYPE_ACTIVE;
char* related_address = NULL;
uint16_t related_port = 0;
char* key;
// Create object
EOR(odict_alloc(&node, 16));
// Get values
EOE(rawrtc_ice_candidate_get_foundation(&foundation, candidate));
EOE(rawrtc_ice_candidate_get_priority(&priority, candidate));
EOE(rawrtc_ice_candidate_get_ip(&ip, candidate));
EOE(rawrtc_ice_candidate_get_protocol(&protocol, candidate));
EOE(rawrtc_ice_candidate_get_port(&port, candidate));
EOE(rawrtc_ice_candidate_get_type(&type, candidate));
error = rawrtc_ice_candidate_get_tcp_type(&tcp_type, candidate);
EOE(error == RAWRTC_CODE_NO_VALUE ? RAWRTC_CODE_SUCCESS : error);
error = rawrtc_ice_candidate_get_related_address(&related_address, candidate);
EOE(error == RAWRTC_CODE_NO_VALUE ? RAWRTC_CODE_SUCCESS : error);
error = rawrtc_ice_candidate_get_related_port(&related_port, candidate);
EOE(error == RAWRTC_CODE_NO_VALUE ? RAWRTC_CODE_SUCCESS : error);
// Set ICE candidate values
EOR(odict_entry_add(node, "foundation", ODICT_STRING, foundation));
EOR(odict_entry_add(node, "priority", ODICT_INT, (int64_t) priority));
EOR(odict_entry_add(node, "ip", ODICT_STRING, ip));
EOR(odict_entry_add(node, "protocol", ODICT_STRING, rawrtc_ice_protocol_to_str(protocol)));
EOR(odict_entry_add(node, "port", ODICT_INT, (int64_t) port));
EOR(odict_entry_add(node, "type", ODICT_STRING, rawrtc_ice_candidate_type_to_str(type)));
if (protocol == RAWRTC_ICE_PROTOCOL_TCP) {
EOR(odict_entry_add(
node, "tcpType", ODICT_STRING, rawrtc_ice_tcp_candidate_type_to_str(tcp_type)));
}
if (related_address) {
EOR(odict_entry_add(node, "relatedAddress", ODICT_STRING, related_address));
}
if (related_port > 0) {
EOR(odict_entry_add(node, "relatedPort", (int64_t) ODICT_INT, related_port));
}
// Add to array
EOE(rawrtc_sdprintf(&key, "%zu", i));
EOR(odict_entry_add(array, key, ODICT_OBJECT, node));
// Un-reference values
mem_deref(key);
mem_deref(related_address);
mem_deref(ip);
mem_deref(foundation);
mem_deref(node);
}
}
/*
* Set DTLS parameters in dictionary.
*/
void set_dtls_parameters(
struct rawrtc_dtls_parameters* const parameters, struct odict* const dict) {
enum rawrtc_dtls_role role;
struct odict* array;
struct odict* node;
struct rawrtc_dtls_fingerprints* fingerprints;
size_t i;
// Get and set DTLS role
EOE(rawrtc_dtls_parameters_get_role(&role, parameters));
EOR(odict_entry_add(dict, "role", ODICT_STRING, rawrtc_dtls_role_to_str(role)));
// Create array
EOR(odict_alloc(&array, 16));
// Get and set fingerprints
EOE(rawrtc_dtls_parameters_get_fingerprints(&fingerprints, parameters));
for (i = 0; i < fingerprints->n_fingerprints; ++i) {
struct rawrtc_dtls_fingerprint* const fingerprint = fingerprints->fingerprints[i];
enum rawrtc_certificate_sign_algorithm sign_algorithm;
char* value;
char* key;
// Create object
EOR(odict_alloc(&node, 16));
// Get values
EOE(rawrtc_dtls_fingerprint_get_sign_algorithm(&sign_algorithm, fingerprint));
EOE(rawrtc_dtls_fingerprint_get_value(&value, fingerprint));
// Set fingerprint values
EOR(odict_entry_add(
node, "algorithm", ODICT_STRING,
rawrtc_certificate_sign_algorithm_to_str(sign_algorithm)));
EOR(odict_entry_add(node, "value", ODICT_STRING, value));
// Add to array
EOE(rawrtc_sdprintf(&key, "%zu", i));
EOR(odict_entry_add(array, key, ODICT_OBJECT, node));
// Un-reference values
mem_deref(key);
mem_deref(value);
mem_deref(node);
}
// Un-reference fingerprints
mem_deref(fingerprints);
// Add array to object
EOR(odict_entry_add(dict, "fingerprints", ODICT_ARRAY, array));
mem_deref(array);
}
/*
* Set SCTP parameters in dictionary.
*/
void set_sctp_parameters(
struct rawrtc_sctp_transport* const transport,
struct sctp_parameters* const parameters,
struct odict* const dict) {
uint64_t max_message_size;
uint16_t port;
// Get values
EOE(rawrtc_sctp_capabilities_get_max_message_size(&max_message_size, parameters->capabilities));
EOE(rawrtc_sctp_transport_get_port(&port, transport));
// Ensure maximum message size fits into int64
if (max_message_size > INT64_MAX) {
EOE(RAWRTC_CODE_INSUFFICIENT_SPACE);
}
// Set ICE parameters
EOR(odict_entry_add(dict, "maxMessageSize", ODICT_INT, (int64_t) max_message_size));
EOR(odict_entry_add(dict, "port", ODICT_INT, (int64_t) port));
}
#if RAWRTC_HAVE_SCTP_REDIRECT_TRANSPORT
/*
* Set SCTP redirect parameters in dictionary.
*/
void set_sctp_redirect_parameters(
struct rawrtc_sctp_redirect_transport* const transport,
struct sctp_parameters* const parameters,
struct odict* const dict) {
uint64_t max_message_size;
uint16_t port;
// Get values
EOE(rawrtc_sctp_capabilities_get_max_message_size(&max_message_size, parameters->capabilities));
EOE(rawrtc_sctp_redirect_transport_get_port(&port, transport));
// Ensure maximum message size fits into int64
if (max_message_size > INT64_MAX) {
EOE(RAWRTC_CODE_INSUFFICIENT_SPACE);
}
// Set ICE parameters
EOR(odict_entry_add(dict, "maxMessageSize", ODICT_INT, (int64_t) max_message_size));
EOR(odict_entry_add(dict, "port", ODICT_INT, (int64_t) port));
}
#endif
/*
* Get ICE parameters from dictionary.
*/
enum rawrtc_code get_ice_parameters(
struct rawrtc_ice_parameters** const parametersp, struct odict* const dict) {
enum rawrtc_code error = RAWRTC_CODE_SUCCESS;
char* username_fragment;
char* password;
bool ice_lite;
// Get ICE parameters
error |= dict_get_entry(&username_fragment, dict, "usernameFragment", ODICT_STRING, true);
error |= dict_get_entry(&password, dict, "password", ODICT_STRING, true);
error |= dict_get_entry(&ice_lite, dict, "iceLite", ODICT_BOOL, true);
if (error) {
return error;
}
// Create ICE parameters instance
return rawrtc_ice_parameters_create(parametersp, username_fragment, password, ice_lite);
}
static void ice_candidates_destroy(void* arg) {
struct rawrtc_ice_candidates* const candidates = arg;
size_t i;
// Un-reference each item
for (i = 0; i < candidates->n_candidates; ++i) {
mem_deref(candidates->candidates[i]);
}
}
/*
* Get ICE candidates from dictionary.
* Filter by enabled ICE candidate types if `client` argument is set to
* non-NULL.
*/
enum rawrtc_code get_ice_candidates(
struct rawrtc_ice_candidates** const candidatesp,
struct odict* const dict,
struct client* const client) {
size_t n;
struct rawrtc_ice_candidates* candidates;
enum rawrtc_code error = RAWRTC_CODE_SUCCESS;
struct le* le;
// Get length
n = list_count(&dict->lst) + 1;
// Allocate & set length immediately
// Note: We allocate more than we need in case ICE candidate types are being filtered but... meh
candidates = mem_zalloc(
sizeof(*candidates) + (sizeof(struct rawrtc_ice_candidate*) * n), ice_candidates_destroy);
if (!candidates) {
EWE("No memory to allocate ICE candidates array");
}
candidates->n_candidates = 0;
// Get ICE candidates
for (le = list_head(&dict->lst); le != NULL; le = le->next) {
struct odict* const node = ((struct odict_entry*) le->data)->u.odict;
char const* type_str = NULL;
enum rawrtc_ice_candidate_type type;
char* foundation;
uint32_t priority;
char* ip;
char const* protocol_str = NULL;
enum rawrtc_ice_protocol protocol;
uint16_t port;
char const* tcp_type_str = NULL;
enum rawrtc_ice_tcp_candidate_type tcp_type = RAWRTC_ICE_TCP_CANDIDATE_TYPE_ACTIVE;
char* related_address = NULL;
uint16_t related_port = 0;
struct rawrtc_ice_candidate* candidate;
// Get ICE candidate
error |= dict_get_entry(&type_str, node, "type", ODICT_STRING, true);
error |= rawrtc_str_to_ice_candidate_type(&type, type_str);
error |= dict_get_entry(&foundation, node, "foundation", ODICT_STRING, true);
error |= dict_get_uint32(&priority, node, "priority", true);
error |= dict_get_entry(&ip, node, "ip", ODICT_STRING, true);
error |= dict_get_entry(&protocol_str, node, "protocol", ODICT_STRING, true);
error |= rawrtc_str_to_ice_protocol(&protocol, protocol_str);
error |= dict_get_uint16(&port, node, "port", true);
if (protocol == RAWRTC_ICE_PROTOCOL_TCP) {
error |= dict_get_entry(&tcp_type_str, node, "tcpType", ODICT_STRING, true);
error |= rawrtc_str_to_ice_tcp_candidate_type(&tcp_type, tcp_type_str);
}
dict_get_entry(&related_address, node, "relatedAddress", ODICT_STRING, false);
dict_get_uint16(&related_port, node, "relatedPort", false);
if (error) {
goto out;
}
// Create and add ICE candidate
error = rawrtc_ice_candidate_create(
&candidate, foundation, priority, ip, protocol, port, type, tcp_type, related_address,
related_port);
if (error) {
goto out;
}
// Print ICE candidate
print_ice_candidate(candidate, NULL, NULL, client);
// Store if ICE candidate type enabled
if (ice_candidate_type_enabled(client, type)) {
candidates->candidates[candidates->n_candidates++] = candidate;
} else {
mem_deref(candidate);
}
}
// End-of-candidates
candidates->candidates[candidates->n_candidates++] = NULL;
out:
if (error) {
mem_deref(candidates);
} else {
// Set pointer
*candidatesp = candidates;
}
return error;
}
static void dtls_fingerprints_destroy(void* arg) {
struct rawrtc_dtls_fingerprints* const fingerprints = arg;
size_t i;
// Un-reference each item
for (i = 0; i < fingerprints->n_fingerprints; ++i) {
mem_deref(fingerprints->fingerprints[i]);
}
}
/*
* Get DTLS parameters from dictionary.
*/
enum rawrtc_code get_dtls_parameters(
struct rawrtc_dtls_parameters** const parametersp, struct odict* const dict) {
size_t n;
struct rawrtc_dtls_parameters* parameters = NULL;
struct rawrtc_dtls_fingerprints* fingerprints;
enum rawrtc_code error;
char const* role_str = NULL;
enum rawrtc_dtls_role role;
struct odict* node;
struct le* le;
size_t i;
// Get fingerprints array and length
error = dict_get_entry(&node, dict, "fingerprints", ODICT_ARRAY, true);
if (error) {
return error;
}
n = list_count(&node->lst);
// Allocate & set length immediately
fingerprints = mem_zalloc(
sizeof(*fingerprints) + (sizeof(struct rawrtc_dtls_fingerprints*) * n),
dtls_fingerprints_destroy);
if (!fingerprints) {
EWE("No memory to allocate DTLS fingerprint array");
}
fingerprints->n_fingerprints = n;
// Get role
error |= dict_get_entry(&role_str, dict, "role", ODICT_STRING, true);
error |= rawrtc_str_to_dtls_role(&role, role_str);
if (error) {
role = RAWRTC_DTLS_ROLE_AUTO;
}
// Get fingerprints
for (le = list_head(&node->lst), i = 0; le != NULL; le = le->next, ++i) {
char* algorithm_str = NULL;
enum rawrtc_certificate_sign_algorithm algorithm;
char* value;
node = ((struct odict_entry*) le->data)->u.odict;
// Get fingerprint
error |= dict_get_entry(&algorithm_str, node, "algorithm", ODICT_STRING, true);
error |= rawrtc_str_to_certificate_sign_algorithm(&algorithm, algorithm_str);
error |= dict_get_entry(&value, node, "value", ODICT_STRING, true);
if (error) {
goto out;
}
// Create and add fingerprint
error = rawrtc_dtls_fingerprint_create(&fingerprints->fingerprints[i], algorithm, value);
if (error) {
goto out;
}
}
// Create DTLS parameters
error = rawrtc_dtls_parameters_create(
&parameters, role, fingerprints->fingerprints, fingerprints->n_fingerprints);
out:
mem_deref(fingerprints);
if (error) {
mem_deref(parameters);
} else {
// Set pointer
*parametersp = parameters;
}
return error;
}
/*
* Get SCTP parameters from dictionary.
*/
enum rawrtc_code get_sctp_parameters(
struct sctp_parameters* const parameters, struct odict* const dict) {
enum rawrtc_code error;
uint64_t max_message_size;
// Get maximum message size
error = dict_get_entry(&max_message_size, dict, "maxMessageSize", ODICT_INT, true);
if (error) {
return error;
}
// Get port
error = dict_get_uint16(&parameters->port, dict, "port", false);
if (error && error != RAWRTC_CODE_NO_VALUE) {
// Note: Nothing to do in NO VALUE case as port has been set to 0 by default
return error;
}
// Create SCTP capabilities instance
return rawrtc_sctp_capabilities_create(&parameters->capabilities, max_message_size);
}