| 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 *mdns_addr); |
| 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 *mdns_addr) |
| 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,&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 | if (mdns_addr) { |
| 196 | cand->mdns_addr = strdup(mdns_addr); |
| 197 | if (!cand->mdns_addr) { |
| 198 | ABORT(R_NO_MEMORY)do { int _r=1; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | /* Not the fastest way to find a component, but it's what we got */ |
| 203 | j=1; |
| 204 | for(comp=STAILQ_FIRST(&pstream->components)((&pstream->components)->stqh_first);comp;comp=STAILQ_NEXT(comp,entry)((comp)->entry.stqe_next)){ |
| 205 | if(j==cand->component_id) |
| 206 | break; |
| 207 | |
| 208 | j++; |
| 209 | } |
| 210 | |
| 211 | if(!comp){ |
| 212 | /* Very common for the answerer when it uses rtcp-mux */ |
| 213 | r_log(LOG_ICE,LOG_INFO6,"ICE(%s): peer (%s) no such component for candidate %s",pctx->ctx->label,pctx->label, candidate); |
| 214 | ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while (0); |
| 215 | } |
| 216 | |
| 217 | if (comp->state == NR_ICE_COMPONENT_DISABLED4) { |
| 218 | r_log(LOG_ICE,LOG_WARNING4,"Peer offered candidate for disabled remote component: %s", candidate); |
| 219 | ABORT(R_BAD_DATA)do { int _r=7; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 220 | } |
| 221 | if (comp->local_component->state == NR_ICE_COMPONENT_DISABLED4) { |
| 222 | r_log(LOG_ICE,LOG_WARNING4,"Peer offered candidate for disabled local component: %s", candidate); |
| 223 | ABORT(R_BAD_DATA)do { int _r=7; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 224 | } |
| 225 | |
| 226 | cand->component=comp; |
| 227 | |
| 228 | 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); |
| 229 | |
| 230 | r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s)/CAND(%s): creating peer candidate", |
| 231 | pctx->label,cand->label); |
| 232 | |
| 233 | _status=0; |
| 234 | abort: |
| 235 | if (_status) { |
| 236 | nr_ice_candidate_destroy(&cand); |
| 237 | } |
| 238 | return(_status); |
| 239 | } |
| 240 | |
| 241 | int nr_ice_peer_ctx_find_pstream(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream **pstreamp) |
| 242 | { |
| 243 | int _status; |
| 244 | nr_ice_media_stream *pstream; |
| 245 | |
| 246 | /* Because we don't have forward pointers, iterate through all the |
| 247 | peer streams to find one that matches us */ |
| 248 | pstream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 249 | |
| 250 | if(!pstream) { |
| 251 | /* No peer streams at all, presumably because they do not exist yet. |
| 252 | * Don't log a warning here. */ |
| 253 | ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 254 | } |
| 255 | |
| 256 | while(pstream) { |
| 257 | if (pstream->local_stream == stream) |
| 258 | break; |
| 259 | |
| 260 | pstream = STAILQ_NEXT(pstream, entry)((pstream)->entry.stqe_next); |
| 261 | } |
| 262 | |
| 263 | if (!pstream) { |
| 264 | r_log(LOG_ICE,LOG_WARNING4,"ICE(%s): peer (%s) has no stream matching stream %s",pctx->ctx->label,pctx->label,stream->label); |
| 265 | ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 266 | } |
| 267 | |
| 268 | *pstreamp = pstream; |
| 269 | |
| 270 | _status=0; |
| 271 | abort: |
| 272 | return(_status); |
| 273 | } |
| 274 | |
| 275 | int nr_ice_peer_ctx_remove_pstream(nr_ice_peer_ctx *pctx, nr_ice_media_stream **pstreamp) |
| 276 | { |
| 277 | int r,_status; |
| 278 | |
| 279 | 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); |
| 280 | |
| 281 | if(r=nr_ice_media_stream_destroy(pstreamp)) { |
| 282 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 283 | } |
| 284 | |
| 285 | _status=0; |
| 286 | abort: |
| 287 | return(_status); |
| 288 | } |
| 289 | |
| 290 | int nr_ice_peer_ctx_parse_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *candidate, const char *mdns_addr) |
| 291 | { |
| 292 | nr_ice_media_stream *pstream; |
| 293 | int r,_status; |
| 294 | int needs_pairing = 0; |
| 295 | |
| 296 | if (stream->obsolete) { |
| 297 | return 0; |
| 298 | } |
| 299 | |
| 300 | r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s): peer (%s) parsing trickle ICE candidate %s",pctx->ctx->label,pctx->label,candidate); |
| 301 | r = nr_ice_peer_ctx_find_pstream(pctx, stream, &pstream); |
| 302 | if (r) |
| 303 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 304 | |
| 305 | switch(pstream->ice_state) { |
| 306 | case NR_ICE_MEDIA_STREAM_UNPAIRED1: |
| 307 | break; |
| 308 | case NR_ICE_MEDIA_STREAM_CHECKS_FROZEN2: |
| 309 | case NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE3: |
| 310 | needs_pairing = 1; |
| 311 | break; |
| 312 | default: |
| 313 | 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); |
| 314 | ABORT(R_ALREADY)do { int _r=4; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 315 | break; |
| 316 | } |
| 317 | |
| 318 | if(r=nr_ice_ctx_parse_candidate(pctx,pstream,candidate,1,mdns_addr)){ |
| 319 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 320 | } |
| 321 | |
| 322 | /* If ICE is running (i.e., we are in FROZEN or ACTIVE states) |
| 323 | then we need to pair this new candidate. For now we |
| 324 | just re-pair the stream which is inefficient but still |
| 325 | fine because we suppress duplicate pairing */ |
| 326 | if (needs_pairing) { |
| 327 | /* Start the remote trickle grace timeout if it hasn't been started by |
| 328 | another trickled candidate or from the SDP. */ |
| 329 | if (!pctx->trickle_grace_period_timer) { |
| 330 | nr_ice_peer_ctx_start_trickle_timer(pctx); |
| 331 | } |
| 332 | |
| 333 | if(r=nr_ice_media_stream_pair_candidates(pctx, stream, pstream)) { |
| 334 | 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); |
| 335 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 336 | } |
| 337 | |
| 338 | /* Start checks if this stream is not checking yet or if it has checked |
| 339 | all the available candidates but not had a completed check for all |
| 340 | components. |
| 341 | |
| 342 | Note that this is not compliant with RFC 5245, but consistent with |
| 343 | the libjingle trickle ICE behavior. Note that we will not restart |
| 344 | checks if either (a) the stream has failed or (b) all components |
| 345 | have a successful pair because the switch statement above jumps |
| 346 | will in both states. |
| 347 | |
| 348 | TODO(ekr@rtfm.com): restart checks. |
| 349 | TODO(ekr@rtfm.com): update when the trickle ICE RFC is published |
| 350 | */ |
| 351 | if (!pstream->timer) { |
| 352 | if(r=nr_ice_media_stream_start_checks(pctx, pstream)) { |
| 353 | r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s), stream(%s) failed to start checks",pctx->ctx->label,pctx->label,stream->label); |
| 354 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 355 | } |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | _status=0; |
| 360 | abort: |
| 361 | return(_status); |
| 362 | |
| 363 | } |
| 364 | |
| 365 | |
| 366 | static void nr_ice_peer_ctx_trickle_wait_cb(NR_SOCKET s, int how, void *cb_arg) |
| 367 | { |
| 368 | nr_ice_peer_ctx *pctx=(nr_ice_peer_ctx*)cb_arg; |
| 369 | nr_ice_media_stream *stream; |
| 370 | nr_ice_component *comp; |
| 371 | |
| 372 | pctx->trickle_grace_period_timer=0; |
| 373 | |
| 374 | 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); |
| 375 | |
| 376 | stream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 377 | while(stream){ |
| 378 | comp=STAILQ_FIRST(&stream->components)((&stream->components)->stqh_first); |
| 379 | while(comp){ |
| 380 | nr_ice_component_check_if_failed(comp); |
| 381 | comp=STAILQ_NEXT(comp,entry)((comp)->entry.stqe_next); |
| 382 | } |
| 383 | stream=STAILQ_NEXT(stream,entry)((stream)->entry.stqe_next); |
| 384 | } |
| 385 | } |
| 386 | |
| 387 | static void nr_ice_peer_ctx_start_trickle_timer(nr_ice_peer_ctx *pctx) |
| 388 | { |
| 389 | UINT4 grace_period_timeout=0; |
| 390 | |
| 391 | if(pctx->trickle_grace_period_timer) { |
| 392 | NR_async_timer_cancel(pctx->trickle_grace_period_timer); |
| 393 | pctx->trickle_grace_period_timer=0; |
| 394 | } |
| 395 | |
| 396 | NR_reg_get_uint4(NR_ICE_REG_TRICKLE_GRACE_PERIOD"ice.trickle_grace_period",&grace_period_timeout); |
| 397 | |
| 398 | if (grace_period_timeout) { |
| 399 | 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); |
| 400 | /* If we're doing trickle, we need to allow a grace period for new |
| 401 | * trickle candidates to arrive in case the pairs we have fail quickly. */ |
| 402 | 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__,402,&pctx->trickle_grace_period_timer ); |
| 403 | } |
| 404 | } |
| 405 | |
| 406 | int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx) |
| 407 | { |
| 408 | nr_ice_media_stream *stream; |
| 409 | int r,_status; |
| 410 | |
| 411 | if(pctx->peer_lite && !pctx->controlling) { |
| 412 | if(pctx->ctx->flags & NR_ICE_CTX_FLAGS_LITE(1<<1)){ |
| 413 | r_log(LOG_ICE,LOG_ERR3,"Both sides are ICE-Lite"); |
| 414 | ABORT(R_BAD_DATA)do { int _r=7; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 415 | } |
| 416 | nr_ice_peer_ctx_switch_controlling_role(pctx); |
| 417 | } |
| 418 | |
| 419 | r_log(LOG_ICE,LOG_DEBUG7,"ICE(%s): peer (%s) pairing candidates",pctx->ctx->label,pctx->label); |
| 420 | |
| 421 | if(STAILQ_EMPTY(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first == __null)) { |
| 422 | r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s) received no media stream attributes",pctx->ctx->label,pctx->label); |
| 423 | ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while (0); |
| 424 | } |
| 425 | |
| 426 | /* Set this first; if we fail partway through, we do not want to end |
| 427 | * up in UNPAIRED after creating some pairs. */ |
| 428 | pctx->state = NR_ICE_PEER_STATE_PAIRED2; |
| 429 | |
| 430 | stream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 431 | while(stream){ |
| 432 | if(!stream->local_stream->obsolete) { |
| 433 | if(r=nr_ice_media_stream_pair_candidates(pctx, stream->local_stream, |
| 434 | stream)) |
| 435 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 436 | } |
| 437 | |
| 438 | stream=STAILQ_NEXT(stream,entry)((stream)->entry.stqe_next); |
| 439 | } |
| 440 | |
| 441 | |
| 442 | _status=0; |
| 443 | abort: |
| 444 | return(_status); |
| 445 | } |
| 446 | |
| 447 | |
| 448 | int nr_ice_peer_ctx_pair_new_trickle_candidate(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx, nr_ice_candidate *cand) |
| 449 | { |
| 450 | int r, _status; |
| 451 | nr_ice_media_stream *pstream; |
| 452 | |
| 453 | r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s) pairing local trickle ICE candidate %s",pctx->ctx->label,pctx->label,cand->label); |
| 454 | if ((r = nr_ice_peer_ctx_find_pstream(pctx, cand->stream, &pstream))) |
| 455 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 456 | |
| 457 | /* Start the remote trickle grace timeout if it hasn't been started |
| 458 | already. */ |
| 459 | if (!pctx->trickle_grace_period_timer) { |
| 460 | nr_ice_peer_ctx_start_trickle_timer(pctx); |
| 461 | } |
| 462 | |
| 463 | if ((r = nr_ice_media_stream_pair_new_trickle_candidate(pctx, pstream, cand))) |
| 464 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 465 | |
| 466 | _status=0; |
| 467 | abort: |
| 468 | return _status; |
| 469 | } |
| 470 | |
| 471 | void nr_ice_peer_ctx_destroy(nr_ice_peer_ctx** pctxp) { |
| 472 | if (!pctxp || !*pctxp) return; |
| 473 | |
| 474 | nr_ice_peer_ctx* pctx = *pctxp; |
| 475 | nr_ice_media_stream *str1,*str2; |
| 476 | |
| 477 | /* Stop calling the handler */ |
| 478 | pctx->handler = 0; |
| 479 | |
| 480 | NR_async_timer_cancel(pctx->connected_cb_timer); |
| 481 | free(pctx->label); |
| 482 | |
| 483 | 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)){ |
| 484 | 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); |
| 485 | nr_ice_media_stream_destroy(&str1); |
| 486 | } |
| 487 | assert(pctx->ctx)(static_cast <bool> (pctx->ctx) ? void (0) : __assert_fail ("pctx->ctx", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); |
| 488 | if (pctx->ctx) |
| 489 | 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); |
| 490 | |
| 491 | if(pctx->trickle_grace_period_timer) { |
| 492 | NR_async_timer_cancel(pctx->trickle_grace_period_timer); |
| 493 | pctx->trickle_grace_period_timer=0; |
| 494 | } |
| 495 | |
| 496 | free(pctx); |
| 497 | |
| 498 | *pctxp=0; |
| 499 | } |
| 500 | |
| 501 | /* Start the checks for the first media stream (S 5.7) |
| 502 | The rest remain FROZEN */ |
| 503 | int nr_ice_peer_ctx_start_checks(nr_ice_peer_ctx *pctx) |
| 504 | { |
| 505 | return nr_ice_peer_ctx_start_checks2(pctx, 0); |
| 506 | } |
| 507 | |
| 508 | /* Start checks for some media stream. |
| 509 | |
| 510 | If allow_non_first == 0, then we only look at the first stream, |
| 511 | which is 5245-complaint. |
| 512 | |
| 513 | If allow_non_first == 1 then we find the first non-empty stream |
| 514 | This is not compliant with RFC 5245 but is necessary to make trickle ICE |
| 515 | work plausibly |
| 516 | */ |
| 517 | int nr_ice_peer_ctx_start_checks2(nr_ice_peer_ctx *pctx, int allow_non_first) |
| 518 | { |
| 519 | int r,_status; |
| 520 | nr_ice_media_stream *stream; |
| 521 | int started = 0; |
| 522 | |
| 523 | /* Ensure that grace period timer is running. We might cancel this if we |
| 524 | * didn't actually start any pairs. */ |
| 525 | nr_ice_peer_ctx_start_trickle_timer(pctx); |
| 526 | |
| 527 | /* Might have added some streams */ |
| 528 | pctx->reported_connected = 0; |
| 529 | NR_async_timer_cancel(pctx->connected_cb_timer); |
| 530 | pctx->connected_cb_timer = 0; |
| 531 | pctx->checks_started = 0; |
| 532 | |
| 533 | nr_ice_peer_ctx_check_if_connected(pctx); |
| 534 | |
| 535 | if (pctx->reported_connected) { |
| 536 | r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s) in %s all streams were done",pctx->ctx->label,pctx->label,__FUNCTION__); |
| 537 | return (0); |
| 538 | } |
| 539 | |
| 540 | stream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 541 | if(!stream) |
| 542 | ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while (0); |
| 543 | |
| 544 | while (stream) { |
| 545 | if(!stream->local_stream->obsolete) { |
| 546 | assert(stream->ice_state != NR_ICE_MEDIA_STREAM_UNPAIRED)(static_cast <bool> (stream->ice_state != 1) ? void ( 0) : __assert_fail ("stream->ice_state != NR_ICE_MEDIA_STREAM_UNPAIRED" , __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__ )); |
| 547 | |
| 548 | if (stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN2) { |
| 549 | if(!TAILQ_EMPTY(&stream->check_list)((&stream->check_list)->tqh_first == __null)) |
| 550 | break; |
| 551 | |
| 552 | if(!allow_non_first){ |
| 553 | /* This test applies if: |
| 554 | |
| 555 | 1. allow_non_first is 0 (i.e., non-trickle ICE) |
| 556 | 2. the first stream has an empty check list. |
| 557 | |
| 558 | But in the non-trickle ICE case, the other side should have provided |
| 559 | some candidates or ICE is pretty much not going to work and we're |
| 560 | just going to fail. Hence R_FAILED as opposed to R_NOT_FOUND and |
| 561 | immediate termination here. |
| 562 | */ |
| 563 | r_log(LOG_ICE,LOG_ERR3,"ICE(%s): peer (%s) first stream has empty check list",pctx->ctx->label,pctx->label); |
| 564 | ABORT(R_FAILED)do { int _r=10; if(!_r) _r=-1; _status=_r; goto abort;} while (0); |
| 565 | } |
| 566 | } |
| 567 | } |
| 568 | |
| 569 | stream=STAILQ_NEXT(stream, entry)((stream)->entry.stqe_next); |
| 570 | } |
| 571 | |
| 572 | if (!stream) { |
| 573 | /* |
| 574 | We fail above if we aren't doing trickle, and this is not all that |
| 575 | unusual in the trickle case. |
| 576 | */ |
| 577 | r_log(LOG_ICE,LOG_NOTICE5,"ICE(%s): peer (%s) no streams with non-empty check lists",pctx->ctx->label,pctx->label); |
| 578 | } |
| 579 | else if (stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN2) { |
| 580 | if(r=nr_ice_media_stream_unfreeze_pairs(pctx,stream)) |
| 581 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 582 | if(r=nr_ice_media_stream_start_checks(pctx,stream)) |
| 583 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 584 | ++started; |
| 585 | } |
| 586 | |
| 587 | stream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 588 | while (stream) { |
| 589 | int serviced = 0; |
| 590 | if (r=nr_ice_media_stream_service_pre_answer_requests(pctx, stream->local_stream, stream, &serviced)) |
| 591 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 592 | |
| 593 | if (serviced) { |
| 594 | ++started; |
| 595 | } |
| 596 | else { |
| 597 | r_log(LOG_ICE,LOG_NOTICE5,"ICE(%s): peer (%s) no streams with pre-answer requests",pctx->ctx->label,pctx->label); |
| 598 | } |
| 599 | |
| 600 | |
| 601 | stream=STAILQ_NEXT(stream, entry)((stream)->entry.stqe_next); |
| 602 | } |
| 603 | |
| 604 | if (!started && pctx->ctx->uninitialized_candidates) { |
| 605 | 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); |
| 606 | /* Never mind on the grace period timer */ |
| 607 | NR_async_timer_cancel(pctx->trickle_grace_period_timer); |
| 608 | pctx->trickle_grace_period_timer=0; |
| 609 | ABORT(R_NOT_FOUND)do { int _r=2; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 610 | } |
| 611 | |
| 612 | _status=0; |
| 613 | abort: |
| 614 | return(_status); |
| 615 | } |
| 616 | |
| 617 | void nr_ice_peer_ctx_stream_started_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream) |
| 618 | { |
| 619 | if (!pctx->checks_started) { |
| 620 | r_log(LOG_ICE,LOG_NOTICE5,"ICE(%s): peer (%s) is now checking",pctx->ctx->label,pctx->label); |
| 621 | pctx->checks_started = 1; |
| 622 | if (pctx->handler && pctx->handler->vtbl->ice_checking) { |
| 623 | pctx->handler->vtbl->ice_checking(pctx->handler->obj, pctx); |
| 624 | } |
| 625 | } |
| 626 | } |
| 627 | |
| 628 | void nr_ice_peer_ctx_refresh_consent_all_streams(nr_ice_peer_ctx *pctx) |
| 629 | { |
| 630 | nr_ice_media_stream *str; |
| 631 | |
| 632 | r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): refreshing consent on all streams",pctx->label); |
| 633 | |
| 634 | str=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 635 | while(str) { |
| 636 | nr_ice_media_stream_refresh_consent_all(str); |
| 637 | str=STAILQ_NEXT(str,entry)((str)->entry.stqe_next); |
| 638 | } |
| 639 | } |
| 640 | |
| 641 | void nr_ice_peer_ctx_disconnected(nr_ice_peer_ctx *pctx) |
| 642 | { |
| 643 | if (pctx->connected_cb_timer) { |
| 644 | /* Whoops, never mind */ |
| 645 | NR_async_timer_cancel(pctx->connected_cb_timer); |
| 646 | pctx->connected_cb_timer = 0; |
| 647 | } |
| 648 | |
| 649 | if (pctx->reported_connected && |
| 650 | pctx->handler && |
| 651 | pctx->handler->vtbl->ice_disconnected) { |
| 652 | pctx->handler->vtbl->ice_disconnected(pctx->handler->obj, pctx); |
| 653 | |
| 654 | pctx->reported_connected = 0; |
| 655 | } |
| 656 | } |
| 657 | |
| 658 | void nr_ice_peer_ctx_disconnect_all_streams(nr_ice_peer_ctx *pctx) |
| 659 | { |
| 660 | nr_ice_media_stream *str; |
| 661 | |
| 662 | r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): disconnecting all streams",pctx->label); |
| 663 | |
| 664 | str=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 665 | while(str) { |
| 666 | nr_ice_media_stream_disconnect_all_components(str); |
| 667 | |
| 668 | /* The first stream to be disconnected will cause the peer ctx to signal |
| 669 | the disconnect up. */ |
| 670 | nr_ice_media_stream_set_disconnected(str, NR_ICE_MEDIA_STREAM_DISCONNECTED1); |
| 671 | |
| 672 | str=STAILQ_NEXT(str,entry)((str)->entry.stqe_next); |
| 673 | } |
| 674 | } |
| 675 | |
| 676 | void nr_ice_peer_ctx_connected(nr_ice_peer_ctx *pctx) |
| 677 | { |
| 678 | /* Fire the handler callback to say we're done */ |
| 679 | if (pctx->reported_connected && |
| 680 | pctx->handler && |
| 681 | pctx->handler->vtbl->ice_connected) { |
| 682 | pctx->handler->vtbl->ice_connected(pctx->handler->obj, pctx); |
| 683 | } |
| 684 | } |
| 685 | |
| 686 | static void nr_ice_peer_ctx_fire_connected(NR_SOCKET s, int how, void *cb_arg) |
| 687 | { |
| 688 | nr_ice_peer_ctx *pctx=(nr_ice_peer_ctx*)cb_arg; |
| 689 | |
| 690 | pctx->connected_cb_timer=0; |
| 691 | |
| 692 | nr_ice_peer_ctx_connected(pctx); |
| 693 | } |
| 694 | |
| 695 | /* Examine all the streams to see if we're |
| 696 | maybe miraculously connected */ |
| 697 | void nr_ice_peer_ctx_check_if_connected(nr_ice_peer_ctx *pctx) |
| 698 | { |
| 699 | nr_ice_media_stream *str; |
| 700 | int failed=0; |
| 701 | int succeeded=0; |
| 702 | |
| 703 | str=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 704 | while(str){ |
| 705 | if (!str->local_stream->obsolete){ |
| 706 | if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED4){ |
| 707 | succeeded++; |
| 708 | } |
| 709 | else if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_FAILED5){ |
| 710 | failed++; |
| 711 | } |
| 712 | else{ |
| 713 | break; |
| 714 | } |
| 715 | } |
| 716 | str=STAILQ_NEXT(str,entry)((str)->entry.stqe_next); |
| 717 | } |
| 718 | |
| 719 | if(str) |
| 720 | return; /* Something isn't done */ |
| 721 | |
| 722 | /* OK, we're finished, one way or another */ |
| 723 | r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): all checks completed success=%d fail=%d",pctx->label,succeeded,failed); |
| 724 | |
| 725 | /* Make sure grace period timer is cancelled */ |
| 726 | if(pctx->trickle_grace_period_timer) { |
| 727 | r_log(LOG_ICE,LOG_INFO6,"ICE(%s): peer (%s) cancelling grace period timer",pctx->ctx->label,pctx->label); |
| 728 | NR_async_timer_cancel(pctx->trickle_grace_period_timer); |
| 729 | pctx->trickle_grace_period_timer=0; |
| 730 | } |
| 731 | |
| 732 | /* Schedule a connected notification for the first connected event. |
| 733 | IMPORTANT: This is done in a callback because we expect destructors |
| 734 | of various kinds to be fired from here */ |
| 735 | if (!pctx->reported_connected) { |
| 736 | pctx->reported_connected = 1; |
| 737 | 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__)); |
| 738 | 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__,738,&pctx->connected_cb_timer); |
| 739 | } |
| 740 | } |
| 741 | |
| 742 | |
| 743 | /* Given a component in the main ICE ctx, find the relevant component in |
| 744 | the peer_ctx */ |
| 745 | int nr_ice_peer_ctx_find_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component_id, nr_ice_component **compp) |
| 746 | { |
| 747 | nr_ice_media_stream *pstr; |
| 748 | int r,_status; |
| 749 | |
| 750 | pstr=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 751 | while(pstr){ |
| 752 | if(pstr->local_stream==str) |
| 753 | break; |
| 754 | |
| 755 | pstr=STAILQ_NEXT(pstr,entry)((pstr)->entry.stqe_next); |
| 756 | } |
| 757 | if(!pstr) |
| 758 | ABORT(R_BAD_ARGS)do { int _r=6; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 759 | |
| 760 | if(r=nr_ice_media_stream_find_component(pstr,component_id,compp)) |
| 761 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 762 | |
| 763 | _status=0; |
| 764 | abort: |
| 765 | return(_status); |
| 766 | } |
| 767 | |
| 768 | /* |
| 769 | This packet may be for us. |
| 770 | |
| 771 | 1. Find the matching peer component |
| 772 | 2. Examine the packet source address to see if it matches |
| 773 | one of the peer candidates. |
| 774 | 3. Fire the relevant callback handler if there is a match |
| 775 | |
| 776 | Return 0 if match, R_REJECTED if no match, other errors |
| 777 | if we can't even find the component or something like that. |
| 778 | */ |
| 779 | |
| 780 | 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) |
| 781 | { |
| 782 | nr_ice_component *peer_comp; |
| 783 | nr_ice_candidate *cand; |
| 784 | int r,_status; |
| 785 | |
| 786 | if(r=nr_ice_peer_ctx_find_component(pctx, comp->stream, comp->component_id, |
| 787 | &peer_comp)) |
| 788 | ABORT(r)do { int _r=r; if(!_r) _r=-1; _status=_r; goto abort;} while( 0); |
| 789 | |
| 790 | /* OK, we've found the component, now look for matches */ |
| 791 | cand=TAILQ_FIRST(&peer_comp->candidates)((&peer_comp->candidates)->tqh_first); |
| 792 | while(cand){ |
| 793 | if(!nr_transport_addr_cmp(source_addr,&cand->addr, |
| 794 | NR_TRANSPORT_ADDR_CMP_MODE_ALL4)) |
| 795 | break; |
| 796 | |
| 797 | cand=TAILQ_NEXT(cand,entry_comp)((cand)->entry_comp.tqe_next); |
| 798 | } |
| 799 | |
| 800 | if(!cand) |
| 801 | ABORT(R_REJECTED)do { int _r=11; if(!_r) _r=-1; _status=_r; goto abort;} while (0); |
| 802 | |
| 803 | // accumulate the received bytes and packets for the active candidate pair |
| 804 | if (peer_comp->active) { |
| 805 | peer_comp->active->bytes_recvd += len; |
| 806 | peer_comp->active->packets_recvd += 1; |
| 807 | gettimeofday(&peer_comp->active->last_recvd, 0); |
| 808 | } |
| 809 | |
| 810 | /* OK, there's a match. Call the handler */ |
| 811 | |
| 812 | if (pctx->handler) { |
| 813 | r_log(LOG_ICE,LOG_DEBUG7,"ICE-PEER(%s): Delivering data", pctx->label); |
| 814 | |
| 815 | pctx->handler->vtbl->msg_recvd(pctx->handler->obj, |
| 816 | pctx,comp->stream,comp->component_id,data,len); |
| 817 | } |
| 818 | |
| 819 | _status=0; |
| 820 | abort: |
| 821 | return(_status); |
| 822 | } |
| 823 | |
| 824 | void nr_ice_peer_ctx_switch_controlling_role(nr_ice_peer_ctx *pctx) |
| 825 | { |
| 826 | int controlling = !(pctx->controlling); |
| 827 | if(pctx->controlling_conflict_resolved) { |
| 828 | r_log(LOG_ICE,LOG_WARNING4,"ICE(%s): peer (%s) %s called more than once; " |
| 829 | "this probably means the peer is confused. Not switching roles.", |
| 830 | pctx->ctx->label,pctx->label,__FUNCTION__); |
| 831 | return; |
| 832 | } |
| 833 | |
| 834 | r_log(LOG_ICE,LOG_INFO6,"ICE-PEER(%s): detected " |
| 835 | "role conflict. Switching to %s", |
| 836 | pctx->label, |
| 837 | controlling ? "controlling" : "controlled"); |
| 838 | |
| 839 | pctx->controlling = controlling; |
| 840 | pctx->controlling_conflict_resolved = 1; |
| 841 | |
| 842 | if(pctx->state == NR_ICE_PEER_STATE_PAIRED2) { |
| 843 | /* We have formed candidate pairs. We need to inform them. */ |
| 844 | nr_ice_media_stream *pstream=STAILQ_FIRST(&pctx->peer_streams)((&pctx->peer_streams)->stqh_first); |
| 845 | while(pstream) { |
| 846 | nr_ice_media_stream_role_change(pstream); |
| 847 | pstream = STAILQ_NEXT(pstream, entry)((pstream)->entry.stqe_next); |
| 848 | } |
| 849 | } |
| 850 | } |
| 851 |