|
1 /* |
|
2 Copyright (c) 2007, Adobe Systems, Incorporated |
|
3 All rights reserved. |
|
4 |
|
5 Redistribution and use in source and binary forms, with or without |
|
6 modification, are permitted provided that the following conditions are |
|
7 met: |
|
8 |
|
9 * Redistributions of source code must retain the above copyright |
|
10 notice, this list of conditions and the following disclaimer. |
|
11 |
|
12 * Redistributions in binary form must reproduce the above copyright |
|
13 notice, this list of conditions and the following disclaimer in the |
|
14 documentation and/or other materials provided with the distribution. |
|
15 |
|
16 * Neither the name of Adobe Systems, Network Resonance nor the names of its |
|
17 contributors may be used to endorse or promote products derived from |
|
18 this software without specific prior written permission. |
|
19 |
|
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
31 */ |
|
32 |
|
33 |
|
34 |
|
35 static char *RCSSTRING __UNUSED__="$Id: ice_ctx.c,v 1.2 2008/04/28 17:59:01 ekr Exp $"; |
|
36 |
|
37 #include <csi_platform.h> |
|
38 #include <assert.h> |
|
39 #include <sys/types.h> |
|
40 #ifdef WIN32 |
|
41 #include <winsock2.h> |
|
42 #else |
|
43 #include <sys/socket.h> |
|
44 #include <netinet/in.h> |
|
45 #include <arpa/inet.h> |
|
46 #endif |
|
47 #include <sys/queue.h> |
|
48 #include <string.h> |
|
49 #include <nr_api.h> |
|
50 #include <registry.h> |
|
51 #include "stun.h" |
|
52 #include "ice_ctx.h" |
|
53 #include "ice_reg.h" |
|
54 #include "nr_crypto.h" |
|
55 #include "async_timer.h" |
|
56 #include "util.h" |
|
57 |
|
58 |
|
59 int LOG_ICE = 0; |
|
60 |
|
61 static int nr_ice_random_string(char *str, int len); |
|
62 static int nr_ice_fetch_stun_servers(int ct, nr_ice_stun_server **out); |
|
63 #ifdef USE_TURN |
|
64 static int nr_ice_fetch_turn_servers(int ct, nr_ice_turn_server **out); |
|
65 #endif /* USE_TURN */ |
|
66 static void nr_ice_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg); |
|
67 static int nr_ice_ctx_pair_new_trickle_candidates(nr_ice_ctx *ctx, nr_ice_candidate *cand); |
|
68 |
|
69 int nr_ice_fetch_stun_servers(int ct, nr_ice_stun_server **out) |
|
70 { |
|
71 int r,_status; |
|
72 nr_ice_stun_server *servers = 0; |
|
73 int i; |
|
74 NR_registry child; |
|
75 char *addr=0; |
|
76 UINT2 port; |
|
77 in_addr_t addr_int; |
|
78 |
|
79 if(!(servers=RCALLOC(sizeof(nr_ice_stun_server)*ct))) |
|
80 ABORT(R_NO_MEMORY); |
|
81 |
|
82 for(i=0;i<ct;i++){ |
|
83 if(r=NR_reg_get_child_registry(NR_ICE_REG_STUN_SRV_PRFX,i,child)) |
|
84 ABORT(r); |
|
85 /* Assume we have a v4 addr for now */ |
|
86 if(r=NR_reg_alloc2_string(child,"addr",&addr)) |
|
87 ABORT(r); |
|
88 addr_int=inet_addr(addr); |
|
89 if(addr_int==INADDR_NONE){ |
|
90 r_log(LOG_ICE,LOG_ERR,"Invalid address %s;",addr); |
|
91 ABORT(R_BAD_ARGS); |
|
92 } |
|
93 if(r=NR_reg_get2_uint2(child,"port",&port)) { |
|
94 if (r != R_NOT_FOUND) |
|
95 ABORT(r); |
|
96 port = 3478; |
|
97 } |
|
98 if(r=nr_ip4_port_to_transport_addr(ntohl(addr_int), port, IPPROTO_UDP, |
|
99 &servers[i].u.addr)) |
|
100 ABORT(r); |
|
101 servers[i].index=i; |
|
102 servers[i].type = NR_ICE_STUN_SERVER_TYPE_ADDR; |
|
103 RFREE(addr); |
|
104 addr=0; |
|
105 } |
|
106 |
|
107 *out = servers; |
|
108 |
|
109 _status=0; |
|
110 abort: |
|
111 RFREE(addr); |
|
112 if (_status) RFREE(servers); |
|
113 return(_status); |
|
114 } |
|
115 |
|
116 int nr_ice_ctx_set_stun_servers(nr_ice_ctx *ctx,nr_ice_stun_server *servers,int ct) |
|
117 { |
|
118 int _status; |
|
119 |
|
120 if(ctx->stun_servers){ |
|
121 RFREE(ctx->stun_servers); |
|
122 ctx->stun_server_ct=0; |
|
123 } |
|
124 |
|
125 if (ct) { |
|
126 if(!(ctx->stun_servers=RCALLOC(sizeof(nr_ice_stun_server)*ct))) |
|
127 ABORT(R_NO_MEMORY); |
|
128 |
|
129 memcpy(ctx->stun_servers,servers,sizeof(nr_ice_stun_server)*ct); |
|
130 ctx->stun_server_ct = ct; |
|
131 } |
|
132 |
|
133 _status=0; |
|
134 abort: |
|
135 return(_status); |
|
136 } |
|
137 |
|
138 int nr_ice_ctx_set_turn_servers(nr_ice_ctx *ctx,nr_ice_turn_server *servers,int ct) |
|
139 { |
|
140 int _status; |
|
141 |
|
142 if(ctx->turn_servers){ |
|
143 RFREE(ctx->turn_servers); |
|
144 ctx->turn_server_ct=0; |
|
145 } |
|
146 |
|
147 if(ct) { |
|
148 if(!(ctx->turn_servers=RCALLOC(sizeof(nr_ice_turn_server)*ct))) |
|
149 ABORT(R_NO_MEMORY); |
|
150 |
|
151 memcpy(ctx->turn_servers,servers,sizeof(nr_ice_turn_server)*ct); |
|
152 ctx->turn_server_ct = ct; |
|
153 } |
|
154 |
|
155 _status=0; |
|
156 abort: |
|
157 return(_status); |
|
158 } |
|
159 |
|
160 int nr_ice_ctx_set_local_addrs(nr_ice_ctx *ctx,nr_local_addr *addrs,int ct) |
|
161 { |
|
162 int _status,i,r; |
|
163 |
|
164 if(ctx->local_addrs) { |
|
165 RFREE(ctx->local_addrs); |
|
166 ctx->local_addr_ct=0; |
|
167 ctx->local_addrs=0; |
|
168 } |
|
169 |
|
170 if (ct) { |
|
171 if(!(ctx->local_addrs=RCALLOC(sizeof(nr_local_addr)*ct))) |
|
172 ABORT(R_NO_MEMORY); |
|
173 |
|
174 for (i=0;i<ct;++i) { |
|
175 if (r=nr_local_addr_copy(ctx->local_addrs+i,addrs+i)) { |
|
176 ABORT(r); |
|
177 } |
|
178 } |
|
179 ctx->local_addr_ct = ct; |
|
180 } |
|
181 |
|
182 _status=0; |
|
183 abort: |
|
184 return(_status); |
|
185 } |
|
186 |
|
187 int nr_ice_ctx_set_resolver(nr_ice_ctx *ctx, nr_resolver *resolver) |
|
188 { |
|
189 int _status; |
|
190 |
|
191 if (ctx->resolver) { |
|
192 ABORT(R_ALREADY); |
|
193 } |
|
194 |
|
195 ctx->resolver = resolver; |
|
196 |
|
197 _status=0; |
|
198 abort: |
|
199 return(_status); |
|
200 } |
|
201 |
|
202 int nr_ice_ctx_set_interface_prioritizer(nr_ice_ctx *ctx, nr_interface_prioritizer *ip) |
|
203 { |
|
204 int _status; |
|
205 |
|
206 if (ctx->interface_prioritizer) { |
|
207 ABORT(R_ALREADY); |
|
208 } |
|
209 |
|
210 ctx->interface_prioritizer = ip; |
|
211 |
|
212 _status=0; |
|
213 abort: |
|
214 return(_status); |
|
215 } |
|
216 |
|
217 #ifdef USE_TURN |
|
218 int nr_ice_fetch_turn_servers(int ct, nr_ice_turn_server **out) |
|
219 { |
|
220 int r,_status; |
|
221 nr_ice_turn_server *servers = 0; |
|
222 int i; |
|
223 NR_registry child; |
|
224 char *addr=0; |
|
225 UINT2 port; |
|
226 in_addr_t addr_int; |
|
227 Data data={0}; |
|
228 |
|
229 if(!(servers=RCALLOC(sizeof(nr_ice_turn_server)*ct))) |
|
230 ABORT(R_NO_MEMORY); |
|
231 |
|
232 for(i=0;i<ct;i++){ |
|
233 if(r=NR_reg_get_child_registry(NR_ICE_REG_TURN_SRV_PRFX,i,child)) |
|
234 ABORT(r); |
|
235 /* Assume we have a v4 addr for now */ |
|
236 if(r=NR_reg_alloc2_string(child,"addr",&addr)) |
|
237 ABORT(r); |
|
238 addr_int=inet_addr(addr); |
|
239 if(addr_int==INADDR_NONE){ |
|
240 r_log(LOG_ICE,LOG_ERR,"Invalid address %s",addr); |
|
241 ABORT(R_BAD_ARGS); |
|
242 } |
|
243 if(r=NR_reg_get2_uint2(child,"port",&port)) { |
|
244 if (r != R_NOT_FOUND) |
|
245 ABORT(r); |
|
246 port = 3478; |
|
247 } |
|
248 if(r=nr_ip4_port_to_transport_addr(ntohl(addr_int), port, IPPROTO_UDP, |
|
249 &servers[i].turn_server.u.addr)) |
|
250 ABORT(r); |
|
251 |
|
252 |
|
253 if(r=NR_reg_alloc2_string(child,NR_ICE_REG_TURN_SRV_USERNAME,&servers[i].username)){ |
|
254 if(r!=R_NOT_FOUND) |
|
255 ABORT(r); |
|
256 } |
|
257 |
|
258 if(r=NR_reg_alloc2_data(child,NR_ICE_REG_TURN_SRV_PASSWORD,&data)){ |
|
259 if(r!=R_NOT_FOUND) |
|
260 ABORT(r); |
|
261 } |
|
262 else { |
|
263 servers[i].password=RCALLOC(sizeof(*servers[i].password)); |
|
264 if(!servers[i].password) |
|
265 ABORT(R_NO_MEMORY); |
|
266 servers[i].password->data = data.data; |
|
267 servers[i].password->len = data.len; |
|
268 data.data=0; |
|
269 } |
|
270 |
|
271 servers[i].turn_server.index=i; |
|
272 |
|
273 RFREE(addr); |
|
274 addr=0; |
|
275 } |
|
276 |
|
277 *out = servers; |
|
278 |
|
279 _status=0; |
|
280 abort: |
|
281 RFREE(data.data); |
|
282 RFREE(addr); |
|
283 if (_status) RFREE(servers); |
|
284 return(_status); |
|
285 } |
|
286 #endif /* USE_TURN */ |
|
287 |
|
288 int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp) |
|
289 { |
|
290 nr_ice_ctx *ctx=0; |
|
291 int r,_status; |
|
292 char buf[100]; |
|
293 |
|
294 if(r=r_log_register("ice", &LOG_ICE)) |
|
295 ABORT(r); |
|
296 |
|
297 if(!(ctx=RCALLOC(sizeof(nr_ice_ctx)))) |
|
298 ABORT(R_NO_MEMORY); |
|
299 |
|
300 ctx->flags=flags; |
|
301 |
|
302 if(!(ctx->label=r_strdup(label))) |
|
303 ABORT(R_NO_MEMORY); |
|
304 |
|
305 if(r=nr_ice_random_string(buf,8)) |
|
306 ABORT(r); |
|
307 if(!(ctx->ufrag=r_strdup(buf))) |
|
308 ABORT(r); |
|
309 if(r=nr_ice_random_string(buf,32)) |
|
310 ABORT(r); |
|
311 if(!(ctx->pwd=r_strdup(buf))) |
|
312 ABORT(r); |
|
313 |
|
314 /* Get the STUN servers */ |
|
315 if(r=NR_reg_get_child_count(NR_ICE_REG_STUN_SRV_PRFX, |
|
316 (unsigned int *)&ctx->stun_server_ct)||ctx->stun_server_ct==0) { |
|
317 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): No STUN servers specified", ctx->label); |
|
318 ctx->stun_server_ct=0; |
|
319 } |
|
320 |
|
321 /* 255 is the max for our priority algorithm */ |
|
322 if(ctx->stun_server_ct>255){ |
|
323 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Too many STUN servers specified: max=255", ctx->label); |
|
324 ctx->stun_server_ct=255; |
|
325 } |
|
326 |
|
327 if(ctx->stun_server_ct>0){ |
|
328 if(r=nr_ice_fetch_stun_servers(ctx->stun_server_ct,&ctx->stun_servers)){ |
|
329 r_log(LOG_ICE,LOG_ERR,"ICE(%s): Couldn't load STUN servers from registry", ctx->label); |
|
330 ctx->stun_server_ct=0; |
|
331 ABORT(r); |
|
332 } |
|
333 } |
|
334 |
|
335 #ifdef USE_TURN |
|
336 /* Get the TURN servers */ |
|
337 if(r=NR_reg_get_child_count(NR_ICE_REG_TURN_SRV_PRFX, |
|
338 (unsigned int *)&ctx->turn_server_ct)||ctx->turn_server_ct==0) { |
|
339 r_log(LOG_ICE,LOG_NOTICE,"ICE(%s): No TURN servers specified", ctx->label); |
|
340 ctx->turn_server_ct=0; |
|
341 } |
|
342 #else |
|
343 ctx->turn_server_ct=0; |
|
344 #endif /* USE_TURN */ |
|
345 |
|
346 ctx->local_addrs=0; |
|
347 ctx->local_addr_ct=0; |
|
348 |
|
349 /* 255 is the max for our priority algorithm */ |
|
350 if((ctx->stun_server_ct+ctx->turn_server_ct)>255){ |
|
351 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Too many STUN/TURN servers specified: max=255", ctx->label); |
|
352 ctx->turn_server_ct=255-ctx->stun_server_ct; |
|
353 } |
|
354 |
|
355 #ifdef USE_TURN |
|
356 if(ctx->turn_server_ct>0){ |
|
357 if(r=nr_ice_fetch_turn_servers(ctx->turn_server_ct,&ctx->turn_servers)){ |
|
358 ctx->turn_server_ct=0; |
|
359 r_log(LOG_ICE,LOG_ERR,"ICE(%s): Couldn't load TURN servers from registry", ctx->label); |
|
360 ABORT(r); |
|
361 } |
|
362 } |
|
363 #endif /* USE_TURN */ |
|
364 |
|
365 |
|
366 ctx->Ta = 20; |
|
367 |
|
368 STAILQ_INIT(&ctx->streams); |
|
369 STAILQ_INIT(&ctx->sockets); |
|
370 STAILQ_INIT(&ctx->foundations); |
|
371 STAILQ_INIT(&ctx->peers); |
|
372 STAILQ_INIT(&ctx->ids); |
|
373 |
|
374 *ctxp=ctx; |
|
375 |
|
376 _status=0; |
|
377 abort: |
|
378 if(_status) |
|
379 nr_ice_ctx_destroy_cb(0,0,ctx); |
|
380 |
|
381 return(_status); |
|
382 } |
|
383 |
|
384 static void nr_ice_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg) |
|
385 { |
|
386 nr_ice_ctx *ctx=cb_arg; |
|
387 nr_ice_foundation *f1,*f2; |
|
388 nr_ice_media_stream *s1,*s2; |
|
389 int i; |
|
390 nr_ice_stun_id *id1,*id2; |
|
391 |
|
392 RFREE(ctx->label); |
|
393 |
|
394 RFREE(ctx->stun_servers); |
|
395 |
|
396 RFREE(ctx->local_addrs); |
|
397 |
|
398 for (i = 0; i < ctx->turn_server_ct; i++) { |
|
399 RFREE(ctx->turn_servers[i].username); |
|
400 r_data_destroy(&ctx->turn_servers[i].password); |
|
401 } |
|
402 RFREE(ctx->turn_servers); |
|
403 |
|
404 f1=STAILQ_FIRST(&ctx->foundations); |
|
405 while(f1){ |
|
406 f2=STAILQ_NEXT(f1,entry); |
|
407 RFREE(f1); |
|
408 f1=f2; |
|
409 } |
|
410 RFREE(ctx->pwd); |
|
411 RFREE(ctx->ufrag); |
|
412 |
|
413 STAILQ_FOREACH_SAFE(s1, &ctx->streams, entry, s2){ |
|
414 STAILQ_REMOVE(&ctx->streams,s1,nr_ice_media_stream_,entry); |
|
415 nr_ice_media_stream_destroy(&s1); |
|
416 } |
|
417 |
|
418 STAILQ_FOREACH_SAFE(id1, &ctx->ids, entry, id2){ |
|
419 STAILQ_REMOVE(&ctx->ids,id1,nr_ice_stun_id_,entry); |
|
420 RFREE(id1); |
|
421 } |
|
422 |
|
423 nr_resolver_destroy(&ctx->resolver); |
|
424 nr_interface_prioritizer_destroy(&ctx->interface_prioritizer); |
|
425 |
|
426 RFREE(ctx); |
|
427 } |
|
428 |
|
429 int nr_ice_ctx_destroy(nr_ice_ctx **ctxp) |
|
430 { |
|
431 if(!ctxp || !*ctxp) |
|
432 return(0); |
|
433 |
|
434 (*ctxp)->done_cb=0; |
|
435 (*ctxp)->trickle_cb=0; |
|
436 |
|
437 NR_ASYNC_SCHEDULE(nr_ice_ctx_destroy_cb,*ctxp); |
|
438 |
|
439 *ctxp=0; |
|
440 |
|
441 return(0); |
|
442 } |
|
443 |
|
444 void nr_ice_initialize_finished_cb(NR_SOCKET s, int h, void *cb_arg) |
|
445 { |
|
446 int r,_status; |
|
447 nr_ice_candidate *cand=cb_arg; |
|
448 nr_ice_ctx *ctx; |
|
449 |
|
450 |
|
451 assert(cb_arg); |
|
452 if (!cb_arg) |
|
453 return; |
|
454 ctx = cand->ctx; |
|
455 |
|
456 ctx->uninitialized_candidates--; |
|
457 |
|
458 if (cand->state == NR_ICE_CAND_STATE_INITIALIZED) { |
|
459 int was_pruned = 0; |
|
460 |
|
461 if (r=nr_ice_component_maybe_prune_candidate(ctx, cand->component, |
|
462 cand, &was_pruned)) { |
|
463 r_log(LOG_ICE, LOG_NOTICE, "ICE(%s): Problem pruning candidates",ctx->label); |
|
464 } |
|
465 |
|
466 /* If we are initialized, the candidate wasn't pruned, |
|
467 and we have a trickle ICE callback fire the callback */ |
|
468 if (ctx->trickle_cb && !was_pruned) { |
|
469 ctx->trickle_cb(ctx->trickle_cb_arg, ctx, cand->stream, cand->component_id, cand); |
|
470 |
|
471 if (r=nr_ice_ctx_pair_new_trickle_candidates(ctx, cand)) { |
|
472 r_log(LOG_ICE,LOG_ERR, "ICE(%s): All could not pair new trickle candidate",ctx->label); |
|
473 /* But continue */ |
|
474 } |
|
475 } |
|
476 } |
|
477 |
|
478 if(ctx->uninitialized_candidates==0){ |
|
479 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): All candidates initialized",ctx->label); |
|
480 ctx->state=NR_ICE_STATE_INITIALIZED; |
|
481 if (ctx->done_cb) { |
|
482 ctx->done_cb(0,0,ctx->cb_arg); |
|
483 } |
|
484 else { |
|
485 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): No done_cb. We were probably destroyed.",ctx->label); |
|
486 } |
|
487 } |
|
488 else { |
|
489 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Waiting for %d candidates to be initialized",ctx->label, ctx->uninitialized_candidates); |
|
490 } |
|
491 } |
|
492 |
|
493 static int nr_ice_ctx_pair_new_trickle_candidates(nr_ice_ctx *ctx, nr_ice_candidate *cand) |
|
494 { |
|
495 int r,_status; |
|
496 nr_ice_peer_ctx *pctx; |
|
497 |
|
498 pctx=STAILQ_FIRST(&ctx->peers); |
|
499 while(pctx){ |
|
500 if (pctx->state == NR_ICE_PEER_STATE_PAIRED) { |
|
501 r = nr_ice_peer_ctx_pair_new_trickle_candidate(ctx, pctx, cand); |
|
502 if (r) |
|
503 ABORT(r); |
|
504 } |
|
505 |
|
506 pctx=STAILQ_NEXT(pctx,entry); |
|
507 } |
|
508 |
|
509 _status=0; |
|
510 abort: |
|
511 return(_status); |
|
512 } |
|
513 |
|
514 |
|
515 #define MAXADDRS 100 // Ridiculously high |
|
516 int nr_ice_initialize(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg) |
|
517 { |
|
518 int r,_status; |
|
519 nr_ice_media_stream *stream; |
|
520 nr_local_addr addrs[MAXADDRS]; |
|
521 int i,addr_ct; |
|
522 |
|
523 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Initializing candidates",ctx->label); |
|
524 ctx->state=NR_ICE_STATE_INITIALIZING; |
|
525 ctx->done_cb=done_cb; |
|
526 ctx->cb_arg=cb_arg; |
|
527 |
|
528 if(STAILQ_EMPTY(&ctx->streams)) { |
|
529 r_log(LOG_ICE,LOG_ERR,"ICE(%s): Missing streams to initialize",ctx->label); |
|
530 ABORT(R_BAD_ARGS); |
|
531 } |
|
532 |
|
533 /* First, gather all the local addresses we have */ |
|
534 if(r=nr_stun_find_local_addresses(addrs,MAXADDRS,&addr_ct)) { |
|
535 r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to find local addresses",ctx->label); |
|
536 ABORT(r); |
|
537 } |
|
538 |
|
539 /* Sort interfaces by preference */ |
|
540 if(ctx->interface_prioritizer) { |
|
541 for(i=0;i<addr_ct;i++){ |
|
542 if(r=nr_interface_prioritizer_add_interface(ctx->interface_prioritizer,addrs+i)) { |
|
543 r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to add interface ",ctx->label); |
|
544 ABORT(r); |
|
545 } |
|
546 } |
|
547 if(r=nr_interface_prioritizer_sort_preference(ctx->interface_prioritizer)) { |
|
548 r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to sort interface by preference",ctx->label); |
|
549 ABORT(r); |
|
550 } |
|
551 } |
|
552 |
|
553 if (r=nr_ice_ctx_set_local_addrs(ctx,addrs,addr_ct)) { |
|
554 ABORT(r); |
|
555 } |
|
556 |
|
557 /* Initialize all the media stream/component pairs */ |
|
558 stream=STAILQ_FIRST(&ctx->streams); |
|
559 while(stream){ |
|
560 if(r=nr_ice_media_stream_initialize(ctx,stream)) |
|
561 ABORT(r); |
|
562 |
|
563 stream=STAILQ_NEXT(stream,entry); |
|
564 } |
|
565 |
|
566 if(ctx->uninitialized_candidates) |
|
567 ABORT(R_WOULDBLOCK); |
|
568 |
|
569 |
|
570 _status=0; |
|
571 abort: |
|
572 return(_status); |
|
573 } |
|
574 |
|
575 int nr_ice_add_media_stream(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp) |
|
576 { |
|
577 int r,_status; |
|
578 |
|
579 if(r=nr_ice_media_stream_create(ctx,label,components,streamp)) |
|
580 ABORT(r); |
|
581 |
|
582 STAILQ_INSERT_TAIL(&ctx->streams,*streamp,entry); |
|
583 |
|
584 _status=0; |
|
585 abort: |
|
586 return(_status); |
|
587 } |
|
588 |
|
589 int nr_ice_get_global_attributes(nr_ice_ctx *ctx,char ***attrsp, int *attrctp) |
|
590 { |
|
591 char **attrs=0; |
|
592 int _status; |
|
593 char *tmp=0; |
|
594 |
|
595 if(!(attrs=RCALLOC(sizeof(char *)*2))) |
|
596 ABORT(R_NO_MEMORY); |
|
597 |
|
598 if(!(tmp=RMALLOC(100))) |
|
599 ABORT(R_NO_MEMORY); |
|
600 snprintf(tmp,100,"ice-ufrag:%s",ctx->ufrag); |
|
601 attrs[0]=tmp; |
|
602 |
|
603 if(!(tmp=RMALLOC(100))) |
|
604 ABORT(R_NO_MEMORY); |
|
605 snprintf(tmp,100,"ice-pwd:%s",ctx->pwd); |
|
606 attrs[1]=tmp; |
|
607 |
|
608 *attrctp=2; |
|
609 *attrsp=attrs; |
|
610 |
|
611 _status=0; |
|
612 abort: |
|
613 if (_status){ |
|
614 if (attrs){ |
|
615 RFREE(attrs[0]); |
|
616 RFREE(attrs[1]); |
|
617 } |
|
618 RFREE(attrs); |
|
619 } |
|
620 return(_status); |
|
621 } |
|
622 |
|
623 static int nr_ice_random_string(char *str, int len) |
|
624 { |
|
625 unsigned char bytes[100]; |
|
626 int needed; |
|
627 int r,_status; |
|
628 |
|
629 if(len%2) ABORT(R_BAD_ARGS); |
|
630 needed=len/2; |
|
631 |
|
632 if(needed>sizeof(bytes)) ABORT(R_BAD_ARGS); |
|
633 |
|
634 //memset(bytes,0,needed); |
|
635 |
|
636 if(r=nr_crypto_random_bytes(bytes,needed)) |
|
637 ABORT(r); |
|
638 |
|
639 if(r=nr_bin2hex(bytes,needed,(unsigned char *)str)) |
|
640 ABORT(r); |
|
641 |
|
642 _status=0; |
|
643 abort: |
|
644 return(_status); |
|
645 } |
|
646 |
|
647 /* This is incredibly annoying: we now have a datagram but we don't |
|
648 know which peer it's from, and we need to be able to tell the |
|
649 API user. So, offer it to each peer and if one bites, assume |
|
650 the others don't want it |
|
651 */ |
|
652 int nr_ice_ctx_deliver_packet(nr_ice_ctx *ctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len) |
|
653 { |
|
654 nr_ice_peer_ctx *pctx; |
|
655 int r; |
|
656 |
|
657 pctx=STAILQ_FIRST(&ctx->peers); |
|
658 while(pctx){ |
|
659 r=nr_ice_peer_ctx_deliver_packet_maybe(pctx, comp, source_addr, data, len); |
|
660 if(!r) |
|
661 break; |
|
662 |
|
663 pctx=STAILQ_NEXT(pctx,entry); |
|
664 } |
|
665 |
|
666 if(!pctx) |
|
667 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Packet received from %s which doesn't match any known peer",ctx->label,source_addr->as_string); |
|
668 |
|
669 return(0); |
|
670 } |
|
671 |
|
672 int nr_ice_ctx_is_known_id(nr_ice_ctx *ctx, UCHAR id[12]) |
|
673 { |
|
674 nr_ice_stun_id *xid; |
|
675 |
|
676 xid=STAILQ_FIRST(&ctx->ids); |
|
677 while(xid){ |
|
678 if (!memcmp(xid->id, id, 12)) |
|
679 return 1; |
|
680 |
|
681 xid=STAILQ_NEXT(xid,entry); |
|
682 } |
|
683 |
|
684 return 0; |
|
685 } |
|
686 |
|
687 int nr_ice_ctx_remember_id(nr_ice_ctx *ctx, nr_stun_message *msg) |
|
688 { |
|
689 int _status; |
|
690 nr_ice_stun_id *xid; |
|
691 |
|
692 xid = RCALLOC(sizeof(*xid)); |
|
693 if (!xid) |
|
694 ABORT(R_NO_MEMORY); |
|
695 |
|
696 assert(sizeof(xid->id) == sizeof(msg->header.id)); |
|
697 #if __STDC_VERSION__ >= 201112L |
|
698 _Static_assert(sizeof(xid->id) == sizeof(msg->header.id),"Message ID Size Mismatch"); |
|
699 #endif |
|
700 memcpy(xid->id, &msg->header.id, sizeof(xid->id)); |
|
701 |
|
702 STAILQ_INSERT_TAIL(&ctx->ids,xid,entry); |
|
703 |
|
704 _status=0; |
|
705 abort: |
|
706 return(_status); |
|
707 } |
|
708 |
|
709 |
|
710 /* Clean up some of the resources (mostly file descriptors) used |
|
711 by candidates we didn't choose. Note that this still leaves |
|
712 a fair amount of non-system stuff floating around. This gets |
|
713 cleaned up when you destroy the ICE ctx */ |
|
714 int nr_ice_ctx_finalize(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx) |
|
715 { |
|
716 nr_ice_media_stream *lstr,*rstr; |
|
717 |
|
718 r_log(LOG_ICE,LOG_DEBUG,"Finalizing ICE ctx %s, peer=%s",ctx->label,pctx->label); |
|
719 /* |
|
720 First find the peer stream, if any |
|
721 */ |
|
722 lstr=STAILQ_FIRST(&ctx->streams); |
|
723 while(lstr){ |
|
724 rstr=STAILQ_FIRST(&pctx->peer_streams); |
|
725 |
|
726 while(rstr){ |
|
727 if(rstr->local_stream==lstr) |
|
728 break; |
|
729 |
|
730 rstr=STAILQ_NEXT(rstr,entry); |
|
731 } |
|
732 |
|
733 nr_ice_media_stream_finalize(lstr,rstr); |
|
734 |
|
735 lstr=STAILQ_NEXT(lstr,entry); |
|
736 } |
|
737 |
|
738 return(0); |
|
739 } |
|
740 |
|
741 |
|
742 int nr_ice_ctx_set_trickle_cb(nr_ice_ctx *ctx, nr_ice_trickle_candidate_cb cb, void *cb_arg) |
|
743 { |
|
744 ctx->trickle_cb = cb; |
|
745 ctx->trickle_cb_arg = cb_arg; |
|
746 |
|
747 return 0; |
|
748 } |