James Kuszmaul | 4a42b18 | 2021-01-17 11:32:46 -0800 | [diff] [blame^] | 1 | #include "utils.h" |
| 2 | #include "common.h" |
| 3 | #include <rawrtc.h> |
| 4 | #include <rawrtcc.h> |
| 5 | #include <rawrtcdc.h> |
| 6 | #include <re.h> |
| 7 | #include <limits.h> // ULONG_MAX |
| 8 | #include <stdlib.h> // strto* |
| 9 | #include <string.h> // strlen |
| 10 | |
| 11 | #define DEBUG_MODULE "helper-utils" |
| 12 | #define DEBUG_LEVEL 7 |
| 13 | #include <re_dbg.h> |
| 14 | |
| 15 | /* |
| 16 | * Convert string to uint16. |
| 17 | */ |
| 18 | bool str_to_uint16(uint16_t* const numberp, char* const str) { |
| 19 | char* end; |
| 20 | unsigned long number = strtoul(str, &end, 10); |
| 21 | |
| 22 | // Check result (this function is insane, srsly...) |
| 23 | if (*end != '\0' || (number == ULONG_MAX && errno == ERANGE)) { |
| 24 | return false; |
| 25 | } |
| 26 | |
| 27 | // Check bounds |
| 28 | #if (ULONG_MAX > UINT16_MAX) |
| 29 | if (number > UINT16_MAX) { |
| 30 | return false; |
| 31 | } |
| 32 | #endif |
| 33 | |
| 34 | // Done |
| 35 | *numberp = (uint16_t) number; |
| 36 | return true; |
| 37 | } |
| 38 | |
| 39 | /* |
| 40 | * Convert string to uint64. |
| 41 | */ |
| 42 | bool str_to_uint64(uint64_t* const numberp, char* const str) { |
| 43 | char* end; |
| 44 | unsigned long long number = strtoull(str, &end, 10); |
| 45 | |
| 46 | // Check result (this function is insane, srsly...) |
| 47 | if (*end != '\0' || (number == ULONG_MAX && errno == ERANGE)) { |
| 48 | return false; |
| 49 | } |
| 50 | |
| 51 | // Check bounds |
| 52 | #if (ULONG_MAX > UINT64_MAX) |
| 53 | if (number > UINT64_MAX) { |
| 54 | return false; |
| 55 | } |
| 56 | #endif |
| 57 | |
| 58 | // Done |
| 59 | *numberp = (uint64_t) number; |
| 60 | return true; |
| 61 | } |
| 62 | |
| 63 | /* |
| 64 | * Convert string to uint32. |
| 65 | */ |
| 66 | bool str_to_uint32(uint32_t* const numberp, char* const str) { |
| 67 | uint64_t number; |
| 68 | bool success = str_to_uint64(&number, str); |
| 69 | |
| 70 | // Validate |
| 71 | if (!success || number > UINT32_MAX) { |
| 72 | return false; |
| 73 | } |
| 74 | |
| 75 | // Done |
| 76 | *numberp = (uint32_t) number; |
| 77 | return true; |
| 78 | } |
| 79 | |
| 80 | /* |
| 81 | * Get a dictionary entry and store it in `*valuep`. |
| 82 | */ |
| 83 | enum rawrtc_code dict_get_entry( |
| 84 | void* const valuep, |
| 85 | struct odict* const parent, |
| 86 | char* const key, |
| 87 | enum odict_type const type, |
| 88 | bool required) { |
| 89 | struct odict_entry const* entry; |
| 90 | |
| 91 | // Check arguments |
| 92 | if (!valuep || !parent || !key) { |
| 93 | return RAWRTC_CODE_INVALID_ARGUMENT; |
| 94 | } |
| 95 | |
| 96 | // Do lookup |
| 97 | entry = odict_lookup(parent, key); |
| 98 | |
| 99 | // Check for entry |
| 100 | if (!entry) { |
| 101 | if (required) { |
| 102 | DEBUG_WARNING("'%s' missing\n", key); |
| 103 | return RAWRTC_CODE_INVALID_ARGUMENT; |
| 104 | } else { |
| 105 | return RAWRTC_CODE_NO_VALUE; |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | // Check for type |
| 110 | if (entry->type != type) { |
| 111 | DEBUG_WARNING("'%s' is of different type than expected\n", key); |
| 112 | return RAWRTC_CODE_INVALID_ARGUMENT; |
| 113 | } |
| 114 | |
| 115 | // Set value according to type |
| 116 | switch (type) { |
| 117 | case ODICT_OBJECT: |
| 118 | case ODICT_ARRAY: |
| 119 | *((struct odict * * const) valuep) = entry->u.odict; |
| 120 | break; |
| 121 | case ODICT_STRING: |
| 122 | *((char** const) valuep) = entry->u.str; |
| 123 | break; |
| 124 | case ODICT_INT: |
| 125 | *((int64_t* const) valuep) = entry->u.integer; |
| 126 | break; |
| 127 | case ODICT_DOUBLE: |
| 128 | *((double* const) valuep) = entry->u.dbl; |
| 129 | break; |
| 130 | case ODICT_BOOL: |
| 131 | *((bool* const) valuep) = entry->u.boolean; |
| 132 | break; |
| 133 | case ODICT_NULL: |
| 134 | *((char** const) valuep) = NULL; // meh! |
| 135 | break; |
| 136 | default: |
| 137 | return RAWRTC_CODE_INVALID_ARGUMENT; |
| 138 | } |
| 139 | |
| 140 | // Done |
| 141 | return RAWRTC_CODE_SUCCESS; |
| 142 | } |
| 143 | |
| 144 | /* |
| 145 | * Get a uint32 entry and store it in `*valuep`. |
| 146 | */ |
| 147 | enum rawrtc_code dict_get_uint32( |
| 148 | uint32_t* const valuep, struct odict* const parent, char* const key, bool required) { |
| 149 | enum rawrtc_code error; |
| 150 | int64_t value; |
| 151 | |
| 152 | // Check arguments |
| 153 | if (!valuep || !parent || !key) { |
| 154 | return RAWRTC_CODE_INVALID_ARGUMENT; |
| 155 | } |
| 156 | |
| 157 | // Get int64_t |
| 158 | error = dict_get_entry(&value, parent, key, ODICT_INT, required); |
| 159 | if (error) { |
| 160 | return error; |
| 161 | } |
| 162 | |
| 163 | // Check bounds |
| 164 | if (value < 0 || value > UINT32_MAX) { |
| 165 | return RAWRTC_CODE_INVALID_ARGUMENT; |
| 166 | } |
| 167 | |
| 168 | // Set value & done |
| 169 | *valuep = (uint32_t) value; |
| 170 | return RAWRTC_CODE_SUCCESS; |
| 171 | } |
| 172 | |
| 173 | /* |
| 174 | * Get a uint16 entry and store it in `*valuep`. |
| 175 | */ |
| 176 | enum rawrtc_code dict_get_uint16( |
| 177 | uint16_t* const valuep, struct odict* const parent, char* const key, bool required) { |
| 178 | enum rawrtc_code error; |
| 179 | int64_t value; |
| 180 | |
| 181 | // Check arguments |
| 182 | if (!valuep || !parent || !key) { |
| 183 | return RAWRTC_CODE_INVALID_ARGUMENT; |
| 184 | } |
| 185 | |
| 186 | // Get int64_t |
| 187 | error = dict_get_entry(&value, parent, key, ODICT_INT, required); |
| 188 | if (error) { |
| 189 | return error; |
| 190 | } |
| 191 | |
| 192 | // Check bounds |
| 193 | if (value < 0 || value > UINT16_MAX) { |
| 194 | return RAWRTC_CODE_INVALID_ARGUMENT; |
| 195 | } |
| 196 | |
| 197 | // Set value & done |
| 198 | *valuep = (uint16_t) value; |
| 199 | return RAWRTC_CODE_SUCCESS; |
| 200 | } |
| 201 | |
| 202 | /* |
| 203 | * Get JSON from stdin and parse it to a dictionary. |
| 204 | */ |
| 205 | enum rawrtc_code get_json_stdin(struct odict** const dictp // de-referenced |
| 206 | ) { |
| 207 | char buffer[PARAMETERS_MAX_LENGTH]; |
| 208 | size_t length; |
| 209 | |
| 210 | // Get message from stdin |
| 211 | if (!fgets((char*) buffer, PARAMETERS_MAX_LENGTH, stdin)) { |
| 212 | EWE("Error polling stdin"); |
| 213 | } |
| 214 | length = strlen(buffer); |
| 215 | |
| 216 | // Exit? |
| 217 | if (length == 1 && buffer[0] == '\n') { |
| 218 | return RAWRTC_CODE_NO_VALUE; |
| 219 | } |
| 220 | |
| 221 | // Decode JSON |
| 222 | EOR(json_decode_odict(dictp, 16, buffer, length, 3)); |
| 223 | return RAWRTC_CODE_SUCCESS; |
| 224 | } |
| 225 | |
| 226 | /* |
| 227 | * Get the ICE role from a string. |
| 228 | */ |
| 229 | enum rawrtc_code get_ice_role( |
| 230 | enum rawrtc_ice_role* const rolep, // de-referenced |
| 231 | char const* const str) { |
| 232 | // Get ICE role |
| 233 | switch (str[0]) { |
| 234 | case '0': |
| 235 | *rolep = RAWRTC_ICE_ROLE_CONTROLLED; |
| 236 | return RAWRTC_CODE_SUCCESS; |
| 237 | case '1': |
| 238 | *rolep = RAWRTC_ICE_ROLE_CONTROLLING; |
| 239 | return RAWRTC_CODE_SUCCESS; |
| 240 | default: |
| 241 | return RAWRTC_CODE_INVALID_ARGUMENT; |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | /* |
| 246 | * Get the congestion control algorithm from a string. |
| 247 | */ |
| 248 | enum rawrtc_code get_congestion_control_algorithm( |
| 249 | enum rawrtc_sctp_transport_congestion_ctrl* const algorithmp, // de-referenced |
| 250 | char const* const str) { |
| 251 | if (str_casecmp(str, "RFC2581") == 0) { |
| 252 | *algorithmp = RAWRTC_SCTP_TRANSPORT_CONGESTION_CTRL_RFC2581; |
| 253 | return RAWRTC_CODE_SUCCESS; |
| 254 | } else if (str_casecmp(str, "HSTCP") == 0) { |
| 255 | *algorithmp = RAWRTC_SCTP_TRANSPORT_CONGESTION_CTRL_HSTCP; |
| 256 | return RAWRTC_CODE_SUCCESS; |
| 257 | } else if (str_casecmp(str, "HTCP") == 0) { |
| 258 | *algorithmp = RAWRTC_SCTP_TRANSPORT_CONGESTION_CTRL_HTCP; |
| 259 | return RAWRTC_CODE_SUCCESS; |
| 260 | } else if (str_casecmp(str, "RTCC") == 0) { |
| 261 | *algorithmp = RAWRTC_SCTP_TRANSPORT_CONGESTION_CTRL_RTCC; |
| 262 | return RAWRTC_CODE_SUCCESS; |
| 263 | } else { |
| 264 | return RAWRTC_CODE_INVALID_ARGUMENT; |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | static void data_channel_helper_destroy(void* arg) { |
| 269 | struct data_channel_helper* const channel = arg; |
| 270 | |
| 271 | // Unset handler argument & handlers of the channel |
| 272 | if (channel->channel) { |
| 273 | EOE(rawrtc_data_channel_unset_handlers(channel->channel)); |
| 274 | } |
| 275 | |
| 276 | // Remove from list |
| 277 | list_unlink(&channel->le); |
| 278 | |
| 279 | // Un-reference |
| 280 | mem_deref(channel->arg); |
| 281 | mem_deref(channel->label); |
| 282 | mem_deref(channel->channel); |
| 283 | } |
| 284 | |
| 285 | /* |
| 286 | * Create a data channel helper instance. |
| 287 | */ |
| 288 | void data_channel_helper_create( |
| 289 | struct data_channel_helper** const channel_helperp, // de-referenced |
| 290 | struct client* const client, |
| 291 | char* const label) { |
| 292 | // Allocate |
| 293 | struct data_channel_helper* const channel = |
| 294 | mem_zalloc(sizeof(*channel), data_channel_helper_destroy); |
| 295 | if (!channel) { |
| 296 | EOE(RAWRTC_CODE_NO_MEMORY); |
| 297 | return; |
| 298 | } |
| 299 | |
| 300 | // Set fields |
| 301 | channel->client = client; |
| 302 | EOE(rawrtc_strdup(&channel->label, label)); |
| 303 | |
| 304 | // Set pointer & done |
| 305 | *channel_helperp = channel; |
| 306 | } |
| 307 | |
| 308 | /* |
| 309 | * Create a data channel helper instance from parameters. |
| 310 | */ |
| 311 | void data_channel_helper_create_from_channel( |
| 312 | struct data_channel_helper** const channel_helperp, // de-referenced |
| 313 | struct rawrtc_data_channel* channel, |
| 314 | struct client* const client, |
| 315 | void* const arg // nullable |
| 316 | ) { |
| 317 | enum rawrtc_code error; |
| 318 | struct rawrtc_data_channel_parameters* parameters; |
| 319 | char* label; |
| 320 | |
| 321 | // Allocate |
| 322 | struct data_channel_helper* const channel_helper = |
| 323 | mem_zalloc(sizeof(*channel_helper), data_channel_helper_destroy); |
| 324 | if (!channel_helper) { |
| 325 | EOE(RAWRTC_CODE_NO_MEMORY); |
| 326 | return; |
| 327 | } |
| 328 | |
| 329 | // Get parameters |
| 330 | EOE(rawrtc_data_channel_get_parameters(¶meters, channel)); |
| 331 | |
| 332 | // Get & set label |
| 333 | error = rawrtc_data_channel_parameters_get_label(&label, parameters); |
| 334 | switch (error) { |
| 335 | case RAWRTC_CODE_SUCCESS: |
| 336 | EOE(rawrtc_strdup(&channel_helper->label, label)); |
| 337 | mem_deref(label); |
| 338 | break; |
| 339 | case RAWRTC_CODE_NO_VALUE: |
| 340 | EOE(rawrtc_strdup(&channel_helper->label, "n/a")); |
| 341 | break; |
| 342 | default: |
| 343 | EOE(error); |
| 344 | } |
| 345 | |
| 346 | // Set fields |
| 347 | channel_helper->client = client; |
| 348 | channel_helper->channel = channel; |
| 349 | channel_helper->arg = mem_ref(arg); |
| 350 | |
| 351 | // Set pointer |
| 352 | *channel_helperp = channel_helper; |
| 353 | |
| 354 | // Un-reference & done |
| 355 | mem_deref(parameters); |
| 356 | } |
| 357 | |
| 358 | /* |
| 359 | * Add the ICE candidate to the remote ICE transport if the ICE |
| 360 | * candidate type is enabled. |
| 361 | */ |
| 362 | void add_to_other_if_ice_candidate_type_enabled( |
| 363 | struct client* const client, |
| 364 | struct rawrtc_ice_candidate* const candidate, |
| 365 | struct rawrtc_ice_transport* const transport) { |
| 366 | if (candidate) { |
| 367 | enum rawrtc_ice_candidate_type type; |
| 368 | |
| 369 | // Get ICE candidate type |
| 370 | EOE(rawrtc_ice_candidate_get_type(&type, candidate)); |
| 371 | |
| 372 | // Add to other client as remote candidate (if type enabled) |
| 373 | if (ice_candidate_type_enabled(client, type)) { |
| 374 | EOE(rawrtc_ice_transport_add_remote_candidate(transport, candidate)); |
| 375 | } |
| 376 | } else { |
| 377 | // Last candidate is always being added |
| 378 | EOE(rawrtc_ice_transport_add_remote_candidate(transport, candidate)); |
| 379 | } |
| 380 | } |