blob: 2c15b005e88885a7e11df49276f7821c9f0c6b1f [file] [log] [blame]
James Kuszmaul4a42b182021-01-17 11:32:46 -08001#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 */
18bool 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 */
42bool 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 */
66bool 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 */
83enum 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 */
147enum 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 */
176enum 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 */
205enum 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 */
229enum 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 */
248enum 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
268static 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 */
288void 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 */
311void 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(&parameters, 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 */
362void 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}