James Kuszmaul | 4a42b18 | 2021-01-17 11:32:46 -0800 | [diff] [blame^] | 1 | #include "parameters.h" |
| 2 | #include "common.h" |
| 3 | #include "utils.h" |
| 4 | #include <rawrtc.h> |
| 5 | #include <rawrtcc.h> |
| 6 | #include <rawrtcdc.h> |
| 7 | #include <re.h> |
| 8 | |
| 9 | #define DEBUG_MODULE "helper-parameters" |
| 10 | #define DEBUG_LEVEL 7 |
| 11 | #include <re_dbg.h> |
| 12 | |
| 13 | /* |
| 14 | * Set ICE parameters in dictionary. |
| 15 | */ |
| 16 | void set_ice_parameters(struct rawrtc_ice_parameters* const parameters, struct odict* const dict) { |
| 17 | char* username_fragment; |
| 18 | char* password; |
| 19 | bool ice_lite; |
| 20 | |
| 21 | // Get values |
| 22 | EOE(rawrtc_ice_parameters_get_username_fragment(&username_fragment, parameters)); |
| 23 | EOE(rawrtc_ice_parameters_get_password(&password, parameters)); |
| 24 | EOE(rawrtc_ice_parameters_get_ice_lite(&ice_lite, parameters)); |
| 25 | |
| 26 | // Set ICE parameters |
| 27 | EOR(odict_entry_add(dict, "usernameFragment", ODICT_STRING, username_fragment)); |
| 28 | EOR(odict_entry_add(dict, "password", ODICT_STRING, password)); |
| 29 | EOR(odict_entry_add(dict, "iceLite", ODICT_BOOL, ice_lite)); |
| 30 | |
| 31 | // Un-reference values |
| 32 | mem_deref(password); |
| 33 | mem_deref(username_fragment); |
| 34 | } |
| 35 | |
| 36 | /* |
| 37 | * Set ICE candidates in dictionary. |
| 38 | */ |
| 39 | void set_ice_candidates(struct rawrtc_ice_candidates* const parameters, struct odict* const array) { |
| 40 | size_t i; |
| 41 | struct odict* node; |
| 42 | |
| 43 | // Set ICE candidates |
| 44 | for (i = 0; i < parameters->n_candidates; ++i) { |
| 45 | enum rawrtc_code error; |
| 46 | struct rawrtc_ice_candidate* const candidate = parameters->candidates[i]; |
| 47 | char* foundation; |
| 48 | uint32_t priority; |
| 49 | char* ip; |
| 50 | enum rawrtc_ice_protocol protocol; |
| 51 | uint16_t port; |
| 52 | enum rawrtc_ice_candidate_type type; |
| 53 | enum rawrtc_ice_tcp_candidate_type tcp_type = RAWRTC_ICE_TCP_CANDIDATE_TYPE_ACTIVE; |
| 54 | char* related_address = NULL; |
| 55 | uint16_t related_port = 0; |
| 56 | char* key; |
| 57 | |
| 58 | // Create object |
| 59 | EOR(odict_alloc(&node, 16)); |
| 60 | |
| 61 | // Get values |
| 62 | EOE(rawrtc_ice_candidate_get_foundation(&foundation, candidate)); |
| 63 | EOE(rawrtc_ice_candidate_get_priority(&priority, candidate)); |
| 64 | EOE(rawrtc_ice_candidate_get_ip(&ip, candidate)); |
| 65 | EOE(rawrtc_ice_candidate_get_protocol(&protocol, candidate)); |
| 66 | EOE(rawrtc_ice_candidate_get_port(&port, candidate)); |
| 67 | EOE(rawrtc_ice_candidate_get_type(&type, candidate)); |
| 68 | error = rawrtc_ice_candidate_get_tcp_type(&tcp_type, candidate); |
| 69 | EOE(error == RAWRTC_CODE_NO_VALUE ? RAWRTC_CODE_SUCCESS : error); |
| 70 | error = rawrtc_ice_candidate_get_related_address(&related_address, candidate); |
| 71 | EOE(error == RAWRTC_CODE_NO_VALUE ? RAWRTC_CODE_SUCCESS : error); |
| 72 | error = rawrtc_ice_candidate_get_related_port(&related_port, candidate); |
| 73 | EOE(error == RAWRTC_CODE_NO_VALUE ? RAWRTC_CODE_SUCCESS : error); |
| 74 | |
| 75 | // Set ICE candidate values |
| 76 | EOR(odict_entry_add(node, "foundation", ODICT_STRING, foundation)); |
| 77 | EOR(odict_entry_add(node, "priority", ODICT_INT, (int64_t) priority)); |
| 78 | EOR(odict_entry_add(node, "ip", ODICT_STRING, ip)); |
| 79 | EOR(odict_entry_add(node, "protocol", ODICT_STRING, rawrtc_ice_protocol_to_str(protocol))); |
| 80 | EOR(odict_entry_add(node, "port", ODICT_INT, (int64_t) port)); |
| 81 | EOR(odict_entry_add(node, "type", ODICT_STRING, rawrtc_ice_candidate_type_to_str(type))); |
| 82 | if (protocol == RAWRTC_ICE_PROTOCOL_TCP) { |
| 83 | EOR(odict_entry_add( |
| 84 | node, "tcpType", ODICT_STRING, rawrtc_ice_tcp_candidate_type_to_str(tcp_type))); |
| 85 | } |
| 86 | if (related_address) { |
| 87 | EOR(odict_entry_add(node, "relatedAddress", ODICT_STRING, related_address)); |
| 88 | } |
| 89 | if (related_port > 0) { |
| 90 | EOR(odict_entry_add(node, "relatedPort", (int64_t) ODICT_INT, related_port)); |
| 91 | } |
| 92 | |
| 93 | // Add to array |
| 94 | EOE(rawrtc_sdprintf(&key, "%zu", i)); |
| 95 | EOR(odict_entry_add(array, key, ODICT_OBJECT, node)); |
| 96 | |
| 97 | // Un-reference values |
| 98 | mem_deref(key); |
| 99 | mem_deref(related_address); |
| 100 | mem_deref(ip); |
| 101 | mem_deref(foundation); |
| 102 | mem_deref(node); |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | /* |
| 107 | * Set DTLS parameters in dictionary. |
| 108 | */ |
| 109 | void set_dtls_parameters( |
| 110 | struct rawrtc_dtls_parameters* const parameters, struct odict* const dict) { |
| 111 | enum rawrtc_dtls_role role; |
| 112 | struct odict* array; |
| 113 | struct odict* node; |
| 114 | struct rawrtc_dtls_fingerprints* fingerprints; |
| 115 | size_t i; |
| 116 | |
| 117 | // Get and set DTLS role |
| 118 | EOE(rawrtc_dtls_parameters_get_role(&role, parameters)); |
| 119 | EOR(odict_entry_add(dict, "role", ODICT_STRING, rawrtc_dtls_role_to_str(role))); |
| 120 | |
| 121 | // Create array |
| 122 | EOR(odict_alloc(&array, 16)); |
| 123 | |
| 124 | // Get and set fingerprints |
| 125 | EOE(rawrtc_dtls_parameters_get_fingerprints(&fingerprints, parameters)); |
| 126 | for (i = 0; i < fingerprints->n_fingerprints; ++i) { |
| 127 | struct rawrtc_dtls_fingerprint* const fingerprint = fingerprints->fingerprints[i]; |
| 128 | enum rawrtc_certificate_sign_algorithm sign_algorithm; |
| 129 | char* value; |
| 130 | char* key; |
| 131 | |
| 132 | // Create object |
| 133 | EOR(odict_alloc(&node, 16)); |
| 134 | |
| 135 | // Get values |
| 136 | EOE(rawrtc_dtls_fingerprint_get_sign_algorithm(&sign_algorithm, fingerprint)); |
| 137 | EOE(rawrtc_dtls_fingerprint_get_value(&value, fingerprint)); |
| 138 | |
| 139 | // Set fingerprint values |
| 140 | EOR(odict_entry_add( |
| 141 | node, "algorithm", ODICT_STRING, |
| 142 | rawrtc_certificate_sign_algorithm_to_str(sign_algorithm))); |
| 143 | EOR(odict_entry_add(node, "value", ODICT_STRING, value)); |
| 144 | |
| 145 | // Add to array |
| 146 | EOE(rawrtc_sdprintf(&key, "%zu", i)); |
| 147 | EOR(odict_entry_add(array, key, ODICT_OBJECT, node)); |
| 148 | |
| 149 | // Un-reference values |
| 150 | mem_deref(key); |
| 151 | mem_deref(value); |
| 152 | mem_deref(node); |
| 153 | } |
| 154 | |
| 155 | // Un-reference fingerprints |
| 156 | mem_deref(fingerprints); |
| 157 | |
| 158 | // Add array to object |
| 159 | EOR(odict_entry_add(dict, "fingerprints", ODICT_ARRAY, array)); |
| 160 | mem_deref(array); |
| 161 | } |
| 162 | |
| 163 | /* |
| 164 | * Set SCTP parameters in dictionary. |
| 165 | */ |
| 166 | void set_sctp_parameters( |
| 167 | struct rawrtc_sctp_transport* const transport, |
| 168 | struct sctp_parameters* const parameters, |
| 169 | struct odict* const dict) { |
| 170 | uint64_t max_message_size; |
| 171 | uint16_t port; |
| 172 | |
| 173 | // Get values |
| 174 | EOE(rawrtc_sctp_capabilities_get_max_message_size(&max_message_size, parameters->capabilities)); |
| 175 | EOE(rawrtc_sctp_transport_get_port(&port, transport)); |
| 176 | |
| 177 | // Ensure maximum message size fits into int64 |
| 178 | if (max_message_size > INT64_MAX) { |
| 179 | EOE(RAWRTC_CODE_INSUFFICIENT_SPACE); |
| 180 | } |
| 181 | |
| 182 | // Set ICE parameters |
| 183 | EOR(odict_entry_add(dict, "maxMessageSize", ODICT_INT, (int64_t) max_message_size)); |
| 184 | EOR(odict_entry_add(dict, "port", ODICT_INT, (int64_t) port)); |
| 185 | } |
| 186 | |
| 187 | #if RAWRTC_HAVE_SCTP_REDIRECT_TRANSPORT |
| 188 | /* |
| 189 | * Set SCTP redirect parameters in dictionary. |
| 190 | */ |
| 191 | void set_sctp_redirect_parameters( |
| 192 | struct rawrtc_sctp_redirect_transport* const transport, |
| 193 | struct sctp_parameters* const parameters, |
| 194 | struct odict* const dict) { |
| 195 | uint64_t max_message_size; |
| 196 | uint16_t port; |
| 197 | |
| 198 | // Get values |
| 199 | EOE(rawrtc_sctp_capabilities_get_max_message_size(&max_message_size, parameters->capabilities)); |
| 200 | EOE(rawrtc_sctp_redirect_transport_get_port(&port, transport)); |
| 201 | |
| 202 | // Ensure maximum message size fits into int64 |
| 203 | if (max_message_size > INT64_MAX) { |
| 204 | EOE(RAWRTC_CODE_INSUFFICIENT_SPACE); |
| 205 | } |
| 206 | |
| 207 | // Set ICE parameters |
| 208 | EOR(odict_entry_add(dict, "maxMessageSize", ODICT_INT, (int64_t) max_message_size)); |
| 209 | EOR(odict_entry_add(dict, "port", ODICT_INT, (int64_t) port)); |
| 210 | } |
| 211 | #endif |
| 212 | |
| 213 | /* |
| 214 | * Get ICE parameters from dictionary. |
| 215 | */ |
| 216 | enum rawrtc_code get_ice_parameters( |
| 217 | struct rawrtc_ice_parameters** const parametersp, struct odict* const dict) { |
| 218 | enum rawrtc_code error = RAWRTC_CODE_SUCCESS; |
| 219 | char* username_fragment; |
| 220 | char* password; |
| 221 | bool ice_lite; |
| 222 | |
| 223 | // Get ICE parameters |
| 224 | error |= dict_get_entry(&username_fragment, dict, "usernameFragment", ODICT_STRING, true); |
| 225 | error |= dict_get_entry(&password, dict, "password", ODICT_STRING, true); |
| 226 | error |= dict_get_entry(&ice_lite, dict, "iceLite", ODICT_BOOL, true); |
| 227 | if (error) { |
| 228 | return error; |
| 229 | } |
| 230 | |
| 231 | // Create ICE parameters instance |
| 232 | return rawrtc_ice_parameters_create(parametersp, username_fragment, password, ice_lite); |
| 233 | } |
| 234 | |
| 235 | static void ice_candidates_destroy(void* arg) { |
| 236 | struct rawrtc_ice_candidates* const candidates = arg; |
| 237 | size_t i; |
| 238 | |
| 239 | // Un-reference each item |
| 240 | for (i = 0; i < candidates->n_candidates; ++i) { |
| 241 | mem_deref(candidates->candidates[i]); |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | /* |
| 246 | * Get ICE candidates from dictionary. |
| 247 | * Filter by enabled ICE candidate types if `client` argument is set to |
| 248 | * non-NULL. |
| 249 | */ |
| 250 | enum rawrtc_code get_ice_candidates( |
| 251 | struct rawrtc_ice_candidates** const candidatesp, |
| 252 | struct odict* const dict, |
| 253 | struct client* const client) { |
| 254 | size_t n; |
| 255 | struct rawrtc_ice_candidates* candidates; |
| 256 | enum rawrtc_code error = RAWRTC_CODE_SUCCESS; |
| 257 | struct le* le; |
| 258 | |
| 259 | // Get length |
| 260 | n = list_count(&dict->lst) + 1; |
| 261 | |
| 262 | // Allocate & set length immediately |
| 263 | // Note: We allocate more than we need in case ICE candidate types are being filtered but... meh |
| 264 | candidates = mem_zalloc( |
| 265 | sizeof(*candidates) + (sizeof(struct rawrtc_ice_candidate*) * n), ice_candidates_destroy); |
| 266 | if (!candidates) { |
| 267 | EWE("No memory to allocate ICE candidates array"); |
| 268 | } |
| 269 | candidates->n_candidates = 0; |
| 270 | |
| 271 | // Get ICE candidates |
| 272 | for (le = list_head(&dict->lst); le != NULL; le = le->next) { |
| 273 | struct odict* const node = ((struct odict_entry*) le->data)->u.odict; |
| 274 | char const* type_str = NULL; |
| 275 | enum rawrtc_ice_candidate_type type; |
| 276 | char* foundation; |
| 277 | uint32_t priority; |
| 278 | char* ip; |
| 279 | char const* protocol_str = NULL; |
| 280 | enum rawrtc_ice_protocol protocol; |
| 281 | uint16_t port; |
| 282 | char const* tcp_type_str = NULL; |
| 283 | enum rawrtc_ice_tcp_candidate_type tcp_type = RAWRTC_ICE_TCP_CANDIDATE_TYPE_ACTIVE; |
| 284 | char* related_address = NULL; |
| 285 | uint16_t related_port = 0; |
| 286 | struct rawrtc_ice_candidate* candidate; |
| 287 | |
| 288 | // Get ICE candidate |
| 289 | error |= dict_get_entry(&type_str, node, "type", ODICT_STRING, true); |
| 290 | error |= rawrtc_str_to_ice_candidate_type(&type, type_str); |
| 291 | error |= dict_get_entry(&foundation, node, "foundation", ODICT_STRING, true); |
| 292 | error |= dict_get_uint32(&priority, node, "priority", true); |
| 293 | error |= dict_get_entry(&ip, node, "ip", ODICT_STRING, true); |
| 294 | error |= dict_get_entry(&protocol_str, node, "protocol", ODICT_STRING, true); |
| 295 | error |= rawrtc_str_to_ice_protocol(&protocol, protocol_str); |
| 296 | error |= dict_get_uint16(&port, node, "port", true); |
| 297 | if (protocol == RAWRTC_ICE_PROTOCOL_TCP) { |
| 298 | error |= dict_get_entry(&tcp_type_str, node, "tcpType", ODICT_STRING, true); |
| 299 | error |= rawrtc_str_to_ice_tcp_candidate_type(&tcp_type, tcp_type_str); |
| 300 | } |
| 301 | dict_get_entry(&related_address, node, "relatedAddress", ODICT_STRING, false); |
| 302 | dict_get_uint16(&related_port, node, "relatedPort", false); |
| 303 | if (error) { |
| 304 | goto out; |
| 305 | } |
| 306 | |
| 307 | // Create and add ICE candidate |
| 308 | error = rawrtc_ice_candidate_create( |
| 309 | &candidate, foundation, priority, ip, protocol, port, type, tcp_type, related_address, |
| 310 | related_port); |
| 311 | if (error) { |
| 312 | goto out; |
| 313 | } |
| 314 | |
| 315 | // Print ICE candidate |
| 316 | print_ice_candidate(candidate, NULL, NULL, client); |
| 317 | |
| 318 | // Store if ICE candidate type enabled |
| 319 | if (ice_candidate_type_enabled(client, type)) { |
| 320 | candidates->candidates[candidates->n_candidates++] = candidate; |
| 321 | } else { |
| 322 | mem_deref(candidate); |
| 323 | } |
| 324 | } |
| 325 | |
| 326 | // End-of-candidates |
| 327 | candidates->candidates[candidates->n_candidates++] = NULL; |
| 328 | |
| 329 | out: |
| 330 | if (error) { |
| 331 | mem_deref(candidates); |
| 332 | } else { |
| 333 | // Set pointer |
| 334 | *candidatesp = candidates; |
| 335 | } |
| 336 | return error; |
| 337 | } |
| 338 | |
| 339 | static void dtls_fingerprints_destroy(void* arg) { |
| 340 | struct rawrtc_dtls_fingerprints* const fingerprints = arg; |
| 341 | size_t i; |
| 342 | |
| 343 | // Un-reference each item |
| 344 | for (i = 0; i < fingerprints->n_fingerprints; ++i) { |
| 345 | mem_deref(fingerprints->fingerprints[i]); |
| 346 | } |
| 347 | } |
| 348 | |
| 349 | /* |
| 350 | * Get DTLS parameters from dictionary. |
| 351 | */ |
| 352 | enum rawrtc_code get_dtls_parameters( |
| 353 | struct rawrtc_dtls_parameters** const parametersp, struct odict* const dict) { |
| 354 | size_t n; |
| 355 | struct rawrtc_dtls_parameters* parameters = NULL; |
| 356 | struct rawrtc_dtls_fingerprints* fingerprints; |
| 357 | enum rawrtc_code error; |
| 358 | char const* role_str = NULL; |
| 359 | enum rawrtc_dtls_role role; |
| 360 | struct odict* node; |
| 361 | struct le* le; |
| 362 | size_t i; |
| 363 | |
| 364 | // Get fingerprints array and length |
| 365 | error = dict_get_entry(&node, dict, "fingerprints", ODICT_ARRAY, true); |
| 366 | if (error) { |
| 367 | return error; |
| 368 | } |
| 369 | n = list_count(&node->lst); |
| 370 | |
| 371 | // Allocate & set length immediately |
| 372 | fingerprints = mem_zalloc( |
| 373 | sizeof(*fingerprints) + (sizeof(struct rawrtc_dtls_fingerprints*) * n), |
| 374 | dtls_fingerprints_destroy); |
| 375 | if (!fingerprints) { |
| 376 | EWE("No memory to allocate DTLS fingerprint array"); |
| 377 | } |
| 378 | fingerprints->n_fingerprints = n; |
| 379 | |
| 380 | // Get role |
| 381 | error |= dict_get_entry(&role_str, dict, "role", ODICT_STRING, true); |
| 382 | error |= rawrtc_str_to_dtls_role(&role, role_str); |
| 383 | if (error) { |
| 384 | role = RAWRTC_DTLS_ROLE_AUTO; |
| 385 | } |
| 386 | |
| 387 | // Get fingerprints |
| 388 | for (le = list_head(&node->lst), i = 0; le != NULL; le = le->next, ++i) { |
| 389 | char* algorithm_str = NULL; |
| 390 | enum rawrtc_certificate_sign_algorithm algorithm; |
| 391 | char* value; |
| 392 | node = ((struct odict_entry*) le->data)->u.odict; |
| 393 | |
| 394 | // Get fingerprint |
| 395 | error |= dict_get_entry(&algorithm_str, node, "algorithm", ODICT_STRING, true); |
| 396 | error |= rawrtc_str_to_certificate_sign_algorithm(&algorithm, algorithm_str); |
| 397 | error |= dict_get_entry(&value, node, "value", ODICT_STRING, true); |
| 398 | if (error) { |
| 399 | goto out; |
| 400 | } |
| 401 | |
| 402 | // Create and add fingerprint |
| 403 | error = rawrtc_dtls_fingerprint_create(&fingerprints->fingerprints[i], algorithm, value); |
| 404 | if (error) { |
| 405 | goto out; |
| 406 | } |
| 407 | } |
| 408 | |
| 409 | // Create DTLS parameters |
| 410 | error = rawrtc_dtls_parameters_create( |
| 411 | ¶meters, role, fingerprints->fingerprints, fingerprints->n_fingerprints); |
| 412 | |
| 413 | out: |
| 414 | mem_deref(fingerprints); |
| 415 | |
| 416 | if (error) { |
| 417 | mem_deref(parameters); |
| 418 | } else { |
| 419 | // Set pointer |
| 420 | *parametersp = parameters; |
| 421 | } |
| 422 | return error; |
| 423 | } |
| 424 | |
| 425 | /* |
| 426 | * Get SCTP parameters from dictionary. |
| 427 | */ |
| 428 | enum rawrtc_code get_sctp_parameters( |
| 429 | struct sctp_parameters* const parameters, struct odict* const dict) { |
| 430 | enum rawrtc_code error; |
| 431 | uint64_t max_message_size; |
| 432 | |
| 433 | // Get maximum message size |
| 434 | error = dict_get_entry(&max_message_size, dict, "maxMessageSize", ODICT_INT, true); |
| 435 | if (error) { |
| 436 | return error; |
| 437 | } |
| 438 | |
| 439 | // Get port |
| 440 | error = dict_get_uint16(¶meters->port, dict, "port", false); |
| 441 | if (error && error != RAWRTC_CODE_NO_VALUE) { |
| 442 | // Note: Nothing to do in NO VALUE case as port has been set to 0 by default |
| 443 | return error; |
| 444 | } |
| 445 | |
| 446 | // Create SCTP capabilities instance |
| 447 | return rawrtc_sctp_capabilities_create(¶meters->capabilities, max_message_size); |
| 448 | } |