| #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( |
| ¶meters, 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(¶meters->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(¶meters->capabilities, max_message_size); |
| } |