| File: | root/firefox-clang/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_peer_ctx.cpp |
| Warning: | line 169, column 12 Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 | #include <string.h> |
| 34 | #include <assert.h> |
| 35 | #include <registry.h> |
| 36 | #include <nr_api.h> |
| 37 | #include "ice_ctx.h" |
| 38 | #include "ice_peer_ctx.h" |
| 39 | #include "ice_media_stream.h" |
| 40 | #include "ice_util.h" |
| 41 | #include "nr_crypto.h" |
| 42 | #include "async_timer.h" |
| 43 | #include "ice_reg.h" |
| 44 | |
| 45 | static void nr_ice_peer_ctx_parse_stream_attributes_int(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream *pstream, char **attrs, int attr_ct); |
| 46 | static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, char *candidate, int trickled, const char *resolved_address); |
| 47 | static void nr_ice_peer_ctx_start_trickle_timer(nr_ice_peer_ctx *pctx); |
| 48 | |
| 49 | int nr_ice_peer_ctx_create(nr_ice_ctx *ctx, nr_ice_handler *handler,char *label, nr_ice_peer_ctx **pctxp) |
| 50 | { |
| 51 | int r,_status; |
| 52 | nr_ice_peer_ctx *pctx=0; |
| 53 | |
| 54 | if(!(pctx=R_NEW(nr_ice_peer_ctx)(nr_ice_peer_ctx*)calloc(1,sizeof(nr_ice_peer_ctx)))) |
| 55 | ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 56 | |
| 57 | pctx->state = NR_ICE_PEER_STATE_UNPAIRED1; |
| 58 | |
| 59 | if(!(pctx->label=strdup(label))) |
| 60 | ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 61 | |
| 62 | pctx->ctx=ctx; |
| 63 | pctx->handler=handler; |
| 64 | |
| 65 | /* Decide controlling vs. controlled */ |
| 66 | if(ctx->flags & NR_ICE_CTX_FLAGS_LITE(1<<1)){ |
| 67 | pctx->controlling=0; |
| 68 | } else { |
| 69 | pctx->controlling=1; |
| 70 | } |
| 71 | if(r=nr_crypto_random_bytes((UCHAR *)&pctx->tiebreaker,8)nr_crypto_vtbl->random_bytes((UCHAR *)&pctx->tiebreaker ,8)) |
| 72 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 73 | |
| 74 | STAILQ_INIT(&pctx->peer_streams)do { (((&pctx->peer_streams))->stqh_first) = __null ; (&pctx->peer_streams)->stqh_last = &(((&pctx ->peer_streams))->stqh_first); } while (0); |
| 75 | |
| 76 | STAILQ_INSERT_TAIL(&ctx->peers,pctx,entry)do { (((pctx))->entry.stqe_next) = __null; *(&ctx-> peers)->stqh_last = (pctx); (&ctx->peers)->stqh_last = &(((pctx))->entry.stqe_next); } while (0); |
| 77 | |
| 78 | *pctxp=pctx; |
| 79 | |
| 80 | _status = 0; |
| 81 | abort: |
| 82 | if(_status){ |
| 83 | nr_ice_peer_ctx_destroy(&pctx); |
| 84 | } |
| 85 | return(_status); |
| 86 | } |
| 87 | |
| 88 | int nr_ice_peer_ctx_aggressive_nomination(nr_ice_peer_ctx *pctx) |
| 89 | { |
| 90 | return (pctx->ctx->flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION(1)) && |
| 91 | !pctx->peer_lite; |
| 92 | } |
| 93 | |
| 94 | |
| 95 | |
| 96 | int nr_ice_peer_ctx_parse_stream_attributes(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char **attrs, int attr_ct) |
| 97 | { |
| 98 | nr_ice_media_stream *pstream=0; |
| 99 | nr_ice_component *comp,*comp2; |
| 100 | char *lufrag,*rufrag; |
| 101 | char *lpwd,*rpwd; |
| 102 | int r,_status; |
| 103 | |
| 104 | /* |
| 105 | Note: use component_ct from our own stream since components other |
| 106 | than this offered by the other side are unusable */ |
| 107 | if(r=nr_ice_media_stream_create(pctx->ctx,stream->label,"","",stream->component_ct,&pstream)) |
| 108 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 109 | |
| 110 | /* Match up the local and remote components */ |
| 111 | comp=STAILQ_FIRST(&stream->components)((&stream->components)->stqh_first); |
| 112 | comp2=STAILQ_FIRST(&pstream->components)((&pstream->components)->stqh_first); |
| 113 | while(comp){ |
| 114 | comp2->local_component=comp; |
| 115 | |
| 116 | comp=STAILQ_NEXT(comp,entry)((comp)->entry.stqe_next); |
| 117 | comp2=STAILQ_NEXT(comp2,entry)((comp2)->entry.stqe_next); |
| 118 | } |
| 119 | |
| 120 | pstream->local_stream=stream; |
| 121 | pstream->pctx=pctx; |
| 122 | |
| 123 | nr_ice_peer_ctx_parse_stream_attributes_int(pctx,stream,pstream,attrs,attr_ct); |
| 124 | |
| 125 | /* Now that we have the ufrag and password, compute all the username/password |
| 126 | pairs */ |
| 127 | lufrag=stream->ufrag; |
| 128 | lpwd=stream->pwd; |
| 129 | assert(lufrag)(static_cast <bool> (lufrag) ? void (0) : __assert_fail ("lufrag", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); |
| 130 | assert(lpwd)(static_cast <bool> (lpwd) ? void (0) : __assert_fail ( "lpwd", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__ )); |
| 131 | rufrag=pstream->ufrag; |
| 132 | rpwd=pstream->pwd; |
| 133 | if (!rufrag || !rpwd) |
| 134 | ABORT(R_BAD_DATA)do { int _r=7; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 135 | |
| 136 | if(r=nr_concat_strings(&pstream->r2l_user,lufrag,":",rufrag,NULL__null)) |
| 137 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 138 | if(r=nr_concat_strings(&pstream->l2r_user,rufrag,":",lufrag,NULL__null)) |
| 139 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 140 | if(r=r_data_make(&pstream->r2l_pass, (UCHAR *)lpwd, strlen(lpwd))) |
| 141 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 142 | if(r=r_data_make(&pstream->l2r_pass, (UCHAR *)rpwd, strlen(rpwd))) |
| 143 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 144 | |
| 145 | STAILQ_INSERT_TAIL(&pctx->peer_streams,pstream,entry)do { (((pstream))->entry.stqe_next) = __null; *(&pctx-> peer_streams)->stqh_last = (pstream); (&pctx->peer_streams )->stqh_last = &(((pstream))->entry.stqe_next); } while (0); |
| 146 | pstream=0; |
| 147 | |
| 148 | _status=0; |
| 149 | abort: |
| 150 | if (_status) { |
| 151 | nr_ice_media_stream_destroy(&pstream); |
| 152 | } |
| 153 | return(_status); |
| 154 | } |
| 155 | |
| 156 | static void nr_ice_peer_ctx_parse_stream_attributes_int(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream *pstream, char **attrs, int attr_ct) |
| 157 | { |
| 158 | int r; |
| 159 | int i; |
| 160 | |
| 161 | for(i=0;i<attr_ct;i++){ |
| 162 | if(!strncmp(attrs[i],"ice-",4)){ |
| 163 | if(r=nr_ice_peer_ctx_parse_media_stream_attribute(pctx,pstream,attrs[i])) { |
| 164 | r_log(LOG_ICE,LOG_WARNING4,"ICE(%s): peer (%s) specified bogus ICE attribute",pctx->ctx->label,pctx->label); |
| 165 | continue; |
| 166 | } |
| 167 | } |
| 168 | else if (!strncmp(attrs[i],"candidate",9)){ |
| 169 | if(r=nr_ice_ctx_parse_candidate(pctx,pstream,attrs[i],0,0)) { |
Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r' | |
| 170 | r_log(LOG_ICE,LOG_WARNING4,"ICE(%s): peer (%s) specified bogus candidate",pctx->ctx->label,pctx->label); |
| 171 | continue; |
| 172 | } |
| 173 | } |
| 174 | else { |
| 175 | r_log(LOG_ICE,LOG_WARNING4,"ICE(%s): peer (%s) specified bogus attribute: %s",pctx->ctx->label,pctx->label,attrs[i]); |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | /* Doesn't fail because we just skip errors */ |
| 180 | } |
| 181 | |
| 182 | static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, char *candidate, int trickled, const char *resolved_address) |
| 183 | { |
| 184 | nr_ice_candidate *cand=0; |
| 185 | nr_ice_component *comp; |
| 186 | int j; |
| 187 | int r, _status; |
| 188 | |
| 189 | if(r=nr_ice_peer_candidate_from_attribute(pctx->ctx,candidate,pstream,resolved_address,&cand)) |
| 190 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 191 | |
| 192 | /* set the trickled flag on the candidate */ |
| 193 | cand->trickled = trickled; |
| 194 | |
| 195 | /* Not the fastest way to find a component, but it's what we got */ |
| 196 | j=1; |
| 197 | for(comp=STAILQ_FIRST(&pstream->components)((&pstream->components)->stqh_first);comp;comp=STAILQ_NEXT(comp,entry)((comp)->entry.stqe_next)){ |
| 198 | if(j==cand->component_id) |
| 199 | break; |
| 200 | |
| 201 | j++; |
| 202 | } |
| 203 | |
| 204 | if(!comp){ |
| 205 | /* Very common for the answerer when it uses rtcp-mux */ |
| 206 | r_log(LOG_ICE,LOG_INFO6,"ICE(%s): peer (%s) no such component for candidate %s",pctx->ctx->label,pctx->label, candidate); |
| 207 | ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while (0); |
| 208 | } |
| 209 | |
| 210 | if (comp->state == NR_ICE_COMPONENT_DISABLED4) { |
| 211 | r_log(LOG_ICE,LOG_WARNING4,"Peer offered candidate for disabled remote component: %s", candidate); |
| 212 | ABORT(R_BAD_DATA)do { int _r=7; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 213 | } |
| 214 | if (comp->local_component->state == NR_ICE_COMPONENT_DISABLED4) { |
| 215 | r_log(LOG_ICE,LOG_WARNING4,"Peer offered candidate for disabled local component: %s", candidate); |
| 216 | ABORT(R_BAD_DATA)do { int _r=7; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 217 | } |
| 218 | |
| 219 | cand->component=comp; |
| 220 | |
| 221 | TAILQ_INSERT_TAIL(&comp->candidates,cand,entry_comp)do { (((cand))->entry_comp.tqe_next) = __null; (cand)-> entry_comp.tqe_prev = (&comp->candidates)->tqh_last ; *(&comp->candidates)->tqh_last = (cand); (&comp ->candidates)->tqh_last = &(((cand))->entry_comp .tqe_next); ; ; } while (0); |
| 222 | |
| 223 | r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s)/CAND(%s): creating peer candidate", |
| 224 | pctx->label,cand->label); |
| 225 | |
| 226 | _status=0; |
| 227 | abort: |
| 228 | if (_status) { |
| 229 | nr_ice_candidate_destroy(&cand); |
| 230 | } |
| 231 | return(_status); |
| 232 | } |
| 233 | |
| 234 | int nr_ice_peer_ctx_find_pstream(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream **pstreamp) |
| 235 | { |
| 236 | int _status; |
| 237 | nr_ice_media_stream *pstream; |
| 238 | |
| 239 | /* Because we don't have forward pointers, iterate through all the |
| 240 | peer streams to find one that matches us */ |
| 241 | pstream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 242 | |
| 243 | if(!pstream) { |
| 244 | /* No peer streams at all, presumably because they do not exist yet. |
| 245 | * Don't log a warning here. */ |
| 246 | ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 247 | } |
| 248 | |
| 249 | while(pstream) { |
| 250 | if (pstream->local_stream == stream) |
| 251 | break; |
| 252 | |
| 253 | pstream = STAILQ_NEXT(pstream, entry)((pstream)->entry.stqe_next); |
| 254 | } |
| 255 | |
| 256 | if (!pstream) { |
| 257 | r_log(LOG_ICE,LOG_WARNING4,"ICE(%s): peer (%s) has no stream matching stream %s",pctx->ctx->label,pctx->label,stream->label); |
| 258 | ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 259 | } |
| 260 | |
| 261 | *pstreamp = pstream; |
| 262 | |
| 263 | _status=0; |
| 264 | abort: |
| 265 | return(_status); |
| 266 | } |
| 267 | |
| 268 | int nr_ice_peer_ctx_remove_pstream(nr_ice_peer_ctx *pctx, nr_ice_media_stream **pstreamp) |
| 269 | { |
| 270 | int r,_status; |
| 271 | |
| 272 | /* Update pctx->active_streams, which paces the check timers. Not |
| 273 | done through nr_ice_media_stream_set_state(), since there is no state |
| 274 | that means "gone". */ |
| 275 | if((*pstreamp)->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE3) { |
| 276 | pctx->active_streams--; |
| 277 | r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s): removing stream %s while it is checking; %d active streams",pctx->label,(*pstreamp)->label,pctx->active_streams); |
| 278 | } |
| 279 | |
| 280 | STAILQ_REMOVE(&pctx->peer_streams,*pstreamp,nr_ice_media_stream_,entry)do { if ((((&pctx->peer_streams))->stqh_first) == ( *pstreamp)) { do { if ((((((&pctx->peer_streams)))-> stqh_first) = ((((((&pctx->peer_streams)))->stqh_first ))->entry.stqe_next)) == __null) ((&pctx->peer_streams ))->stqh_last = &((((&pctx->peer_streams)))-> stqh_first); } while (0); } else { struct nr_ice_media_stream_ *curelm = (((&pctx->peer_streams))->stqh_first); while (((curelm)->entry.stqe_next) != (*pstreamp)) curelm = ((curelm )->entry.stqe_next); if ((((curelm)->entry.stqe_next) = ((((curelm)->entry.stqe_next))->entry.stqe_next)) == __null ) (&pctx->peer_streams)->stqh_last = &(((curelm ))->entry.stqe_next); } } while (0); |
| 281 | |
| 282 | if(r=nr_ice_media_stream_destroy(pstreamp)) { |
| 283 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 284 | } |
| 285 | |
| 286 | /* The removed stream may have been the one the others were frozen |
| 287 | behind, or the last one holding up completion. */ |
| 288 | nr_ice_peer_ctx_react_to_stream_change(pctx); |
| 289 | |
| 290 | _status=0; |
| 291 | abort: |
| 292 | return(_status); |
| 293 | } |
| 294 | |
| 295 | int nr_ice_peer_ctx_parse_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *candidate, const char *resolved_address) |
| 296 | { |
| 297 | nr_ice_media_stream *pstream; |
| 298 | int r,_status; |
| 299 | int needs_pairing = 0; |
| 300 | |
| 301 | if (stream->obsolete) { |
| 302 | return 0; |
| 303 | } |
| 304 | |
| 305 | r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s): peer (%s) parsing trickle ICE candidate %s",pctx->ctx->label,pctx->label,candidate); |
| 306 | r = nr_ice_peer_ctx_find_pstream(pctx, stream, &pstream); |
| 307 | if (r) |
| 308 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 309 | |
| 310 | switch(pstream->ice_state) { |
| 311 | case NR_ICE_MEDIA_STREAM_UNPAIRED1: |
| 312 | break; |
| 313 | case NR_ICE_MEDIA_STREAM_CHECKS_FROZEN2: |
| 314 | case NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE3: |
| 315 | needs_pairing = 1; |
| 316 | break; |
| 317 | default: |
| 318 | r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s), stream(%s) tried to trickle ICE in inappropriate state %d",pctx->ctx->label,pctx->label,stream->label,pstream->ice_state); |
| 319 | ABORT(R_ALREADY)do { int _r=4; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 320 | break; |
| 321 | } |
| 322 | |
| 323 | if(r=nr_ice_ctx_parse_candidate(pctx,pstream,candidate,1,resolved_address)){ |
| 324 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 325 | } |
| 326 | |
| 327 | /* If ICE is running (i.e., we are in FROZEN or ACTIVE states) |
| 328 | then we need to pair this new candidate. For now we |
| 329 | just re-pair the stream which is inefficient but still |
| 330 | fine because we suppress duplicate pairing */ |
| 331 | if (needs_pairing) { |
| 332 | /* Start the remote trickle grace timeout if it hasn't been started by |
| 333 | another trickled candidate or from the SDP. */ |
| 334 | if (!pctx->trickle_grace_period_timer) { |
| 335 | nr_ice_peer_ctx_start_trickle_timer(pctx); |
| 336 | } |
| 337 | |
| 338 | if(r=nr_ice_media_stream_pair_candidates(pctx, stream, pstream)) { |
| 339 | r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s), stream(%s) failed to pair trickle ICE candidates",pctx->ctx->label,pctx->label,stream->label); |
| 340 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 341 | } |
| 342 | |
| 343 | /* Start checks if this stream is not checking yet or if it has checked |
| 344 | all the available candidates but not had a completed check for all |
| 345 | components. |
| 346 | |
| 347 | Note that this is not compliant with RFC 5245, but consistent with |
| 348 | the libjingle trickle ICE behavior. Note that we will not restart |
| 349 | checks if either (a) the stream has failed or (b) all components |
| 350 | have a successful pair because the switch statement above jumps |
| 351 | will in both states. |
| 352 | |
| 353 | TODO(ekr@rtfm.com): restart checks. |
| 354 | TODO(ekr@rtfm.com): update when the trickle ICE RFC is published |
| 355 | */ |
| 356 | if (!pstream->timer) { |
| 357 | if(r=nr_ice_media_stream_start_checks(pctx, pstream)) { |
| 358 | r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s), stream(%s) failed to start checks",pctx->ctx->label,pctx->label,stream->label); |
| 359 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 360 | } |
| 361 | } |
| 362 | } |
| 363 | |
| 364 | _status=0; |
| 365 | abort: |
| 366 | return(_status); |
| 367 | |
| 368 | } |
| 369 | |
| 370 | |
| 371 | static void nr_ice_peer_ctx_trickle_wait_cb(NR_SOCKET s, int how, void *cb_arg) |
| 372 | { |
| 373 | nr_ice_peer_ctx *pctx=(nr_ice_peer_ctx*)cb_arg; |
| 374 | nr_ice_media_stream *stream; |
| 375 | nr_ice_component *comp; |
| 376 | |
| 377 | pctx->trickle_grace_period_timer=0; |
| 378 | |
| 379 | r_log(LOG_ICE,LOG_INFO6,"ICE(%s): peer (%s) Trickle grace period is over; marking every component with only failed pairs as failed.",pctx->ctx->label,pctx->label); |
| 380 | |
| 381 | stream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 382 | while(stream){ |
| 383 | comp=STAILQ_FIRST(&stream->components)((&stream->components)->stqh_first); |
| 384 | while(comp){ |
| 385 | nr_ice_component_check_if_failed(comp); |
| 386 | comp=STAILQ_NEXT(comp,entry)((comp)->entry.stqe_next); |
| 387 | } |
| 388 | stream=STAILQ_NEXT(stream,entry)((stream)->entry.stqe_next); |
| 389 | } |
| 390 | } |
| 391 | |
| 392 | static void nr_ice_peer_ctx_start_trickle_timer(nr_ice_peer_ctx *pctx) |
| 393 | { |
| 394 | UINT4 grace_period_timeout=0; |
| 395 | |
| 396 | if(pctx->trickle_grace_period_timer) { |
| 397 | NR_async_timer_cancel(pctx->trickle_grace_period_timer); |
| 398 | pctx->trickle_grace_period_timer=0; |
| 399 | } |
| 400 | |
| 401 | NR_reg_get_uint4(NR_ICE_REG_TRICKLE_GRACE_PERIOD"ice.trickle_grace_period",&grace_period_timeout); |
| 402 | |
| 403 | if (grace_period_timeout) { |
| 404 | r_log(LOG_ICE,LOG_INFO6,"ICE(%s): peer (%s) starting grace period timer for %u ms",pctx->ctx->label,pctx->label, grace_period_timeout); |
| 405 | /* If we're doing trickle, we need to allow a grace period for new |
| 406 | * trickle candidates to arrive in case the pairs we have fail quickly. */ |
| 407 | NR_ASYNC_TIMER_SET(grace_period_timeout,nr_ice_peer_ctx_trickle_wait_cb,pctx,&pctx->trickle_grace_period_timer)NR_async_timer_set(grace_period_timeout,nr_ice_peer_ctx_trickle_wait_cb ,pctx,(char *)__FUNCTION__,407,&pctx->trickle_grace_period_timer ); |
| 408 | } |
| 409 | } |
| 410 | |
| 411 | int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx) |
| 412 | { |
| 413 | nr_ice_media_stream *stream; |
| 414 | int r,_status; |
| 415 | |
| 416 | if(pctx->peer_lite && !pctx->controlling) { |
| 417 | if(pctx->ctx->flags & NR_ICE_CTX_FLAGS_LITE(1<<1)){ |
| 418 | r_log(LOG_ICE,LOG_ERR3,"Both sides are ICE-Lite"); |
| 419 | ABORT(R_BAD_DATA)do { int _r=7; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 420 | } |
| 421 | nr_ice_peer_ctx_switch_controlling_role(pctx); |
| 422 | } |
| 423 | |
| 424 | r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s): peer (%s) pairing candidates",pctx->ctx->label,pctx->label); |
| 425 | |
| 426 | if(STAILQ_EMPTY(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first == __null)) { |
| 427 | r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s) received no media stream attributes",pctx->ctx->label,pctx->label); |
| 428 | ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while (0); |
| 429 | } |
| 430 | |
| 431 | /* Set this first; if we fail partway through, we do not want to end |
| 432 | * up in UNPAIRED after creating some pairs. */ |
| 433 | pctx->state = NR_ICE_PEER_STATE_PAIRED2; |
| 434 | |
| 435 | stream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 436 | while(stream){ |
| 437 | if(!stream->local_stream->obsolete) { |
| 438 | if(r=nr_ice_media_stream_pair_candidates(pctx, stream->local_stream, |
| 439 | stream)) |
| 440 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 441 | } |
| 442 | |
| 443 | stream=STAILQ_NEXT(stream,entry)((stream)->entry.stqe_next); |
| 444 | } |
| 445 | |
| 446 | |
| 447 | _status=0; |
| 448 | abort: |
| 449 | return(_status); |
| 450 | } |
| 451 | |
| 452 | |
| 453 | int nr_ice_peer_ctx_pair_new_trickle_candidate(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx, nr_ice_candidate *cand) |
| 454 | { |
| 455 | int r, _status; |
| 456 | nr_ice_media_stream *pstream; |
| 457 | |
| 458 | r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s) pairing local trickle ICE candidate %s",pctx->ctx->label,pctx->label,cand->label); |
| 459 | if ((r = nr_ice_peer_ctx_find_pstream(pctx, cand->stream, &pstream))) |
| 460 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 461 | |
| 462 | /* Start the remote trickle grace timeout if it hasn't been started |
| 463 | already. */ |
| 464 | if (!pctx->trickle_grace_period_timer) { |
| 465 | nr_ice_peer_ctx_start_trickle_timer(pctx); |
| 466 | } |
| 467 | |
| 468 | if ((r = nr_ice_media_stream_pair_new_trickle_candidate(pctx, pstream, cand))) |
| 469 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 470 | |
| 471 | _status=0; |
| 472 | abort: |
| 473 | return _status; |
| 474 | } |
| 475 | |
| 476 | void nr_ice_peer_ctx_destroy(nr_ice_peer_ctx** pctxp) { |
| 477 | if (!pctxp || !*pctxp) return; |
| 478 | |
| 479 | nr_ice_peer_ctx* pctx = *pctxp; |
| 480 | nr_ice_media_stream *str1,*str2; |
| 481 | |
| 482 | /* Stop calling the handler */ |
| 483 | pctx->handler = 0; |
| 484 | |
| 485 | NR_async_timer_cancel(pctx->connected_cb_timer); |
| 486 | free(pctx->label); |
| 487 | |
| 488 | STAILQ_FOREACH_SAFE(str1, &pctx->peer_streams, entry, str2)for ((str1) = (((&pctx->peer_streams))->stqh_first) ; (str1) && ((str2) = (((str1))->entry.stqe_next), 1); (str1) = (str2)){ |
| 489 | STAILQ_REMOVE(&pctx->peer_streams,str1,nr_ice_media_stream_,entry)do { if ((((&pctx->peer_streams))->stqh_first) == ( str1)) { do { if ((((((&pctx->peer_streams)))->stqh_first ) = ((((((&pctx->peer_streams)))->stqh_first))-> entry.stqe_next)) == __null) ((&pctx->peer_streams))-> stqh_last = &((((&pctx->peer_streams)))->stqh_first ); } while (0); } else { struct nr_ice_media_stream_ *curelm = (((&pctx->peer_streams))->stqh_first); while (((curelm )->entry.stqe_next) != (str1)) curelm = ((curelm)->entry .stqe_next); if ((((curelm)->entry.stqe_next) = ((((curelm )->entry.stqe_next))->entry.stqe_next)) == __null) (& pctx->peer_streams)->stqh_last = &(((curelm))->entry .stqe_next); } } while (0); |
| 490 | nr_ice_media_stream_destroy(&str1); |
| 491 | } |
| 492 | assert(pctx->ctx)(static_cast <bool> (pctx->ctx) ? void (0) : __assert_fail ("pctx->ctx", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); |
| 493 | if (pctx->ctx) |
| 494 | STAILQ_REMOVE(&pctx->ctx->peers, pctx, nr_ice_peer_ctx_, entry)do { if ((((&pctx->ctx->peers))->stqh_first) == ( pctx)) { do { if ((((((&pctx->ctx->peers)))->stqh_first ) = ((((((&pctx->ctx->peers)))->stqh_first))-> entry.stqe_next)) == __null) ((&pctx->ctx->peers))-> stqh_last = &((((&pctx->ctx->peers)))->stqh_first ); } while (0); } else { struct nr_ice_peer_ctx_ *curelm = (( (&pctx->ctx->peers))->stqh_first); while (((curelm )->entry.stqe_next) != (pctx)) curelm = ((curelm)->entry .stqe_next); if ((((curelm)->entry.stqe_next) = ((((curelm )->entry.stqe_next))->entry.stqe_next)) == __null) (& pctx->ctx->peers)->stqh_last = &(((curelm))-> entry.stqe_next); } } while (0); |
| 495 | |
| 496 | if(pctx->trickle_grace_period_timer) { |
| 497 | NR_async_timer_cancel(pctx->trickle_grace_period_timer); |
| 498 | pctx->trickle_grace_period_timer=0; |
| 499 | } |
| 500 | |
| 501 | free(pctx); |
| 502 | |
| 503 | *pctxp=0; |
| 504 | } |
| 505 | |
| 506 | /* Unless some stream is already checking, unfreeze and start the first |
| 507 | frozen stream that has a check list (RFC 5245 S 5.7, S 7.1.3.2.3). |
| 508 | Returns R_NOT_FOUND if there was nothing to start. |
| 509 | |
| 510 | RFC 5245 only does this at startup, and unfreezes the rest by foundation |
| 511 | as checks succeed. Here it also runs whenever a stream reaches a final |
| 512 | state (see nr_ice_peer_ctx_react_to_stream_change), so that a stream that fails or |
| 513 | is removed before any of its pairs succeed does not strand the streams |
| 514 | frozen behind it. RFC 8445 avoids the problem differently, by running |
| 515 | every checklist from the start (S 6.1.4.2). */ |
| 516 | static int nr_ice_peer_ctx_start_next_stream(nr_ice_peer_ctx *pctx) |
| 517 | { |
| 518 | int r; |
| 519 | nr_ice_media_stream *str; |
| 520 | nr_ice_media_stream *first_frozen = nullptr; |
| 521 | |
| 522 | str=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 523 | while(str){ |
| 524 | if(!str->local_stream->obsolete){ |
| 525 | if(str->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE3) |
| 526 | return R_NOT_FOUND2; |
| 527 | |
| 528 | if(!first_frozen && |
| 529 | str->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN2 && |
| 530 | !TAILQ_EMPTY(&str->check_list)((&str->check_list)->tqh_first == __null)) { |
| 531 | first_frozen = str; |
| 532 | } |
| 533 | } |
| 534 | str=STAILQ_NEXT(str,entry)((str)->entry.stqe_next); |
| 535 | } |
| 536 | |
| 537 | if(!first_frozen) |
| 538 | return R_NOT_FOUND2; |
| 539 | |
| 540 | r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): starting checks for stream %s",pctx->label,first_frozen->label); |
| 541 | if(r=nr_ice_media_stream_unfreeze_pairs(pctx,first_frozen)) |
| 542 | return r; |
| 543 | if(r=nr_ice_media_stream_start_checks(pctx,first_frozen)) |
| 544 | return r; |
| 545 | |
| 546 | return 0; |
| 547 | } |
| 548 | |
| 549 | /* Start checks. Only the first frozen stream with a check list is started; |
| 550 | the rest are unfrozen as checks succeed, or as streams reach a final |
| 551 | state. In the trickle case there may be nothing to start yet, in which |
| 552 | case this returns R_NOT_FOUND; streams are then started as their |
| 553 | candidates arrive. */ |
| 554 | int nr_ice_peer_ctx_start_checks(nr_ice_peer_ctx *pctx) |
| 555 | { |
| 556 | int r,_status; |
| 557 | nr_ice_media_stream *stream; |
| 558 | int started = 0; |
| 559 | |
| 560 | /* Ensure that grace period timer is running. We might cancel this if we |
| 561 | * didn't actually start any pairs. */ |
| 562 | nr_ice_peer_ctx_start_trickle_timer(pctx); |
| 563 | |
| 564 | /* Might have added some streams */ |
| 565 | pctx->reported_connected = 0; |
| 566 | NR_async_timer_cancel(pctx->connected_cb_timer); |
| 567 | pctx->connected_cb_timer = 0; |
| 568 | pctx->checks_started = 0; |
| 569 | |
| 570 | if(nr_ice_peer_ctx_react_to_stream_change(pctx)){ |
| 571 | ++started; |
| 572 | } |
| 573 | else if(pctx->reported_connected){ |
| 574 | r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s) in %s all streams were done",pctx->ctx->label,pctx->label,__FUNCTION__); |
| 575 | return (0); |
| 576 | } |
| 577 | else{ |
| 578 | /* Not all that unusual in the trickle case. */ |
| 579 | r_log(LOG_ICE,LOG_NOTICE5,"ICE(%s): peer (%s) no streams with non-empty check lists",pctx->ctx->label,pctx->label); |
| 580 | } |
| 581 | |
| 582 | if(STAILQ_EMPTY(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first == __null)) |
| 583 | ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while (0); |
| 584 | |
| 585 | stream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 586 | while (stream) { |
| 587 | int serviced = 0; |
| 588 | if (r=nr_ice_media_stream_service_pre_answer_requests(pctx, stream->local_stream, stream, &serviced)) |
| 589 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 590 | |
| 591 | if (serviced) { |
| 592 | ++started; |
| 593 | } |
| 594 | else { |
| 595 | r_log(LOG_ICE,LOG_NOTICE5,"ICE(%s): peer (%s) no streams with pre-answer requests",pctx->ctx->label,pctx->label); |
| 596 | } |
| 597 | |
| 598 | |
| 599 | stream=STAILQ_NEXT(stream, entry)((stream)->entry.stqe_next); |
| 600 | } |
| 601 | |
| 602 | if (!started && pctx->ctx->uninitialized_candidates) { |
| 603 | r_log(LOG_ICE,LOG_INFO6,"ICE(%s): peer (%s) no checks to start, but gathering is not done yet, cancelling grace period timer",pctx->ctx->label,pctx->label); |
| 604 | /* Never mind on the grace period timer */ |
| 605 | NR_async_timer_cancel(pctx->trickle_grace_period_timer); |
| 606 | pctx->trickle_grace_period_timer=0; |
| 607 | ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 608 | } |
| 609 | |
| 610 | _status=0; |
| 611 | abort: |
| 612 | return(_status); |
| 613 | } |
| 614 | |
| 615 | void nr_ice_peer_ctx_stream_started_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream) |
| 616 | { |
| 617 | if (!pctx->checks_started) { |
| 618 | r_log(LOG_ICE,LOG_NOTICE5,"ICE(%s): peer (%s) is now checking",pctx->ctx->label,pctx->label); |
| 619 | pctx->checks_started = 1; |
| 620 | if (pctx->handler && pctx->handler->vtbl->ice_checking) { |
| 621 | pctx->handler->vtbl->ice_checking(pctx->handler->obj, pctx); |
| 622 | } |
| 623 | } |
| 624 | } |
| 625 | |
| 626 | void nr_ice_peer_ctx_refresh_consent_all_streams(nr_ice_peer_ctx *pctx) |
| 627 | { |
| 628 | nr_ice_media_stream *str; |
| 629 | |
| 630 | r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): refreshing consent on all streams",pctx->label); |
| 631 | |
| 632 | str=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 633 | while(str) { |
| 634 | nr_ice_media_stream_refresh_consent_all(str); |
| 635 | str=STAILQ_NEXT(str,entry)((str)->entry.stqe_next); |
| 636 | } |
| 637 | } |
| 638 | |
| 639 | void nr_ice_peer_ctx_disconnected(nr_ice_peer_ctx *pctx) |
| 640 | { |
| 641 | if (pctx->connected_cb_timer) { |
| 642 | /* Whoops, never mind */ |
| 643 | NR_async_timer_cancel(pctx->connected_cb_timer); |
| 644 | pctx->connected_cb_timer = 0; |
| 645 | } |
| 646 | |
| 647 | if (pctx->reported_connected && |
| 648 | pctx->handler && |
| 649 | pctx->handler->vtbl->ice_disconnected) { |
| 650 | pctx->handler->vtbl->ice_disconnected(pctx->handler->obj, pctx); |
| 651 | |
| 652 | pctx->reported_connected = 0; |
| 653 | } |
| 654 | } |
| 655 | |
| 656 | void nr_ice_peer_ctx_disconnect_all_streams(nr_ice_peer_ctx *pctx) |
| 657 | { |
| 658 | nr_ice_media_stream *str; |
| 659 | |
| 660 | r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): disconnecting all streams",pctx->label); |
| 661 | |
| 662 | str=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 663 | while(str) { |
| 664 | nr_ice_media_stream_disconnect_all_components(str); |
| 665 | |
| 666 | /* The first stream to be disconnected will cause the peer ctx to signal |
| 667 | the disconnect up. */ |
| 668 | nr_ice_media_stream_set_disconnected(str, NR_ICE_MEDIA_STREAM_DISCONNECTED1); |
| 669 | |
| 670 | str=STAILQ_NEXT(str,entry)((str)->entry.stqe_next); |
| 671 | } |
| 672 | } |
| 673 | |
| 674 | void nr_ice_peer_ctx_connected(nr_ice_peer_ctx *pctx) |
| 675 | { |
| 676 | /* Fire the handler callback to say we're done */ |
| 677 | if (pctx->reported_connected && |
| 678 | pctx->handler && |
| 679 | pctx->handler->vtbl->ice_connected) { |
| 680 | pctx->handler->vtbl->ice_connected(pctx->handler->obj, pctx); |
| 681 | } |
| 682 | } |
| 683 | |
| 684 | static void nr_ice_peer_ctx_fire_connected(NR_SOCKET s, int how, void *cb_arg) |
| 685 | { |
| 686 | nr_ice_peer_ctx *pctx=(nr_ice_peer_ctx*)cb_arg; |
| 687 | |
| 688 | pctx->connected_cb_timer=0; |
| 689 | |
| 690 | nr_ice_peer_ctx_connected(pctx); |
| 691 | } |
| 692 | |
| 693 | /* A stream reached a final state (connected, failed, or removed), or a stream |
| 694 | * has been added and needs to start checks. If every stream is done, report |
| 695 | * it; otherwise make sure some stream is still checking. Returns 1 if it |
| 696 | * started checks on a stream. */ |
| 697 | int nr_ice_peer_ctx_react_to_stream_change(nr_ice_peer_ctx *pctx) |
| 698 | { |
| 699 | int r; |
| 700 | nr_ice_media_stream *str; |
| 701 | int failed=0; |
| 702 | int succeeded=0; |
| 703 | |
| 704 | str=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 705 | while(str){ |
| 706 | if (!str->local_stream->obsolete){ |
| 707 | if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED4){ |
| 708 | succeeded++; |
| 709 | } |
| 710 | else if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_FAILED5){ |
| 711 | failed++; |
| 712 | } |
| 713 | else{ |
| 714 | break; |
| 715 | } |
| 716 | } |
| 717 | str=STAILQ_NEXT(str,entry)((str)->entry.stqe_next); |
| 718 | } |
| 719 | |
| 720 | if (!str) { |
| 721 | /* OK, we're finished, one way or another */ |
| 722 | r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): all checks completed success=%d fail=%d",pctx->label,succeeded,failed); |
| 723 | |
| 724 | /* Make sure grace period timer is cancelled */ |
| 725 | if(pctx->trickle_grace_period_timer) { |
| 726 | r_log(LOG_ICE,LOG_INFO6,"ICE(%s): peer (%s) cancelling grace period timer",pctx->ctx->label,pctx->label); |
| 727 | NR_async_timer_cancel(pctx->trickle_grace_period_timer); |
| 728 | pctx->trickle_grace_period_timer=0; |
| 729 | } |
| 730 | |
| 731 | /* Schedule a connected notification for the first connected event. |
| 732 | IMPORTANT: This is done in a callback because we expect destructors |
| 733 | of various kinds to be fired from here */ |
| 734 | if (!pctx->reported_connected && !failed) { |
| 735 | pctx->reported_connected = 1; |
| 736 | assert(!pctx->connected_cb_timer)(static_cast <bool> (!pctx->connected_cb_timer) ? void (0) : __assert_fail ("!pctx->connected_cb_timer", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); |
| 737 | NR_ASYNC_TIMER_SET(0,nr_ice_peer_ctx_fire_connected,pctx,&pctx->connected_cb_timer)NR_async_timer_set(0,nr_ice_peer_ctx_fire_connected,pctx,(char *)__FUNCTION__,737,&pctx->connected_cb_timer); |
| 738 | } |
| 739 | } else { |
| 740 | /* Something isn't done. Whatever was checking may just have finished, |
| 741 | failed, or been removed; don't leave the rest frozen behind it. |
| 742 | (Before checks are first started nothing is FROZEN yet, so this is a |
| 743 | no-op then.) */ |
| 744 | r=nr_ice_peer_ctx_start_next_stream(pctx); |
| 745 | if(!r) |
| 746 | return 1; |
| 747 | if(r!=R_NOT_FOUND2){ |
| 748 | r_log(LOG_ICE,LOG_ERR3,"ICE-PEER(%s): couldn't start checks for next stream, error=%d",pctx->label,r); |
| 749 | } |
| 750 | } |
| 751 | |
| 752 | return 0; |
| 753 | } |
| 754 | |
| 755 | |
| 756 | /* Given a component in the main ICE ctx, find the relevant component in |
| 757 | the peer_ctx */ |
| 758 | int nr_ice_peer_ctx_find_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component_id, nr_ice_component **compp) |
| 759 | { |
| 760 | nr_ice_media_stream *pstr; |
| 761 | int r,_status; |
| 762 | |
| 763 | pstr=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 764 | while(pstr){ |
| 765 | if(pstr->local_stream==str) |
| 766 | break; |
| 767 | |
| 768 | pstr=STAILQ_NEXT(pstr,entry)((pstr)->entry.stqe_next); |
| 769 | } |
| 770 | if(!pstr) |
| 771 | ABORT(R_BAD_ARGS)do { int _r=6; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 772 | |
| 773 | if(r=nr_ice_media_stream_find_component(pstr,component_id,compp)) |
| 774 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 775 | |
| 776 | _status=0; |
| 777 | abort: |
| 778 | return(_status); |
| 779 | } |
| 780 | |
| 781 | /* |
| 782 | This packet may be for us. |
| 783 | |
| 784 | 1. Find the matching peer component |
| 785 | 2. Examine the packet source address to see if it matches |
| 786 | one of the peer candidates. |
| 787 | 3. Fire the relevant callback handler if there is a match |
| 788 | |
| 789 | Return 0 if match, R_REJECTED if no match, other errors |
| 790 | if we can't even find the component or something like that. |
| 791 | */ |
| 792 | |
| 793 | int nr_ice_peer_ctx_deliver_packet_maybe(nr_ice_peer_ctx *pctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len) |
| 794 | { |
| 795 | nr_ice_component *peer_comp; |
| 796 | nr_ice_candidate *cand; |
| 797 | int r,_status; |
| 798 | |
| 799 | if(r=nr_ice_peer_ctx_find_component(pctx, comp->stream, comp->component_id, |
| 800 | &peer_comp)) |
| 801 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 802 | |
| 803 | /* OK, we've found the component, now look for matches */ |
| 804 | cand=TAILQ_FIRST(&peer_comp->candidates)((&peer_comp->candidates)->tqh_first); |
| 805 | while(cand){ |
| 806 | if(!nr_transport_addr_cmp(source_addr,&cand->addr, |
| 807 | NR_TRANSPORT_ADDR_CMP_MODE_ALL4)) |
| 808 | break; |
| 809 | |
| 810 | cand=TAILQ_NEXT(cand,entry_comp)((cand)->entry_comp.tqe_next); |
| 811 | } |
| 812 | |
| 813 | if(!cand) |
| 814 | ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while (0); |
| 815 | |
| 816 | // accumulate the received bytes and packets for the active candidate pair |
| 817 | if (peer_comp->active) { |
| 818 | peer_comp->active->bytes_recvd += len; |
| 819 | peer_comp->active->packets_recvd += 1; |
| 820 | gettimeofday(&peer_comp->active->last_recvd, 0); |
| 821 | } |
| 822 | |
| 823 | /* OK, there's a match. Call the handler */ |
| 824 | |
| 825 | if (pctx->handler) { |
| 826 | r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s): Delivering data", pctx->label); |
| 827 | |
| 828 | pctx->handler->vtbl->msg_recvd(pctx->handler->obj, |
| 829 | pctx,comp->stream,comp->component_id,data,len); |
| 830 | } |
| 831 | |
| 832 | _status=0; |
| 833 | abort: |
| 834 | return(_status); |
| 835 | } |
| 836 | |
| 837 | void nr_ice_peer_ctx_switch_controlling_role(nr_ice_peer_ctx *pctx) |
| 838 | { |
| 839 | int controlling = !(pctx->controlling); |
| 840 | if(pctx->controlling_conflict_resolved) { |
| 841 | r_log(LOG_ICE,LOG_WARNING4,"ICE(%s): peer (%s) %s called more than once; " |
| 842 | "this probably means the peer is confused. Not switching roles.", |
| 843 | pctx->ctx->label,pctx->label,__FUNCTION__); |
| 844 | return; |
| 845 | } |
| 846 | |
| 847 | r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): detected " |
| 848 | "role conflict. Switching to %s", |
| 849 | pctx->label, |
| 850 | controlling ? "controlling" : "controlled"); |
| 851 | |
| 852 | pctx->controlling = controlling; |
| 853 | pctx->controlling_conflict_resolved = 1; |
| 854 | |
| 855 | if(pctx->state == NR_ICE_PEER_STATE_PAIRED2) { |
| 856 | /* We have formed candidate pairs. We need to inform them. */ |
| 857 | nr_ice_media_stream *pstream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 858 | while(pstream) { |
| 859 | nr_ice_media_stream_role_change(pstream); |
| 860 | pstream = STAILQ_NEXT(pstream, entry)((pstream)->entry.stqe_next); |
| 861 | } |
| 862 | } |
| 863 | } |
| 864 |