Changeset 1988 for pjproject/trunk/pjnath/src/pjnath/ice_strans.c
- Timestamp:
- Jun 6, 2008 2:47:10 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjnath/src/pjnath/ice_strans.c
r1913 r1988 20 20 #include <pjnath/errno.h> 21 21 #include <pj/addr_resolv.h> 22 #include <pj/array.h> 22 23 #include <pj/assert.h> 23 24 #include <pj/ip_helper.h> 24 25 #include <pj/log.h> 26 #include <pj/os.h> 25 27 #include <pj/pool.h> 26 28 #include <pj/rand.h> … … 36 38 37 39 40 /* Transport IDs */ 41 enum tp_type 42 { 43 TP_NONE, 44 TP_STUN, 45 TP_TURN 46 }; 47 48 /* Candidate preference default values */ 49 #define SRFLX_PREF 65535 50 #define HOST_PREF 65530 51 #define RELAY_PREF 65525 52 38 53 39 54 /* ICE callbacks */ … … 41 56 static pj_status_t ice_tx_pkt(pj_ice_sess *ice, 42 57 unsigned comp_id, 58 unsigned transport_id, 43 59 const void *pkt, pj_size_t size, 44 60 const pj_sockaddr_t *dst_addr, 45 61 unsigned dst_addr_len); 46 62 static void ice_rx_data(pj_ice_sess *ice, 47 unsigned comp_id, 48 void *pkt, pj_size_t size, 49 const pj_sockaddr_t *src_addr, 50 unsigned src_addr_len); 51 52 /* Ioqueue callback */ 53 static void on_read_complete(pj_ioqueue_key_t *key, 54 pj_ioqueue_op_key_t *op_key, 55 pj_ssize_t bytes_read); 56 57 static void destroy_component(pj_ice_strans_comp *comp); 58 static void destroy_ice_st(pj_ice_strans *ice_st, pj_status_t reason); 59 60 61 /* STUN session callback */ 62 static pj_status_t stun_on_send_msg(pj_stun_session *sess, 63 void *token, 64 const void *pkt, 65 pj_size_t pkt_size, 66 const pj_sockaddr_t *dst_addr, 67 unsigned addr_len); 68 static void stun_on_request_complete(pj_stun_session *sess, 69 pj_status_t status, 70 void *token, 71 pj_stun_tx_data *tdata, 72 const pj_stun_msg *response, 73 const pj_sockaddr_t *src_addr, 74 unsigned src_addr_len); 75 76 /* Keep-alive timer */ 77 static void start_ka_timer(pj_ice_strans *ice_st); 78 static void stop_ka_timer(pj_ice_strans *ice_st); 79 80 /* Utility: print error */ 63 unsigned comp_id, 64 unsigned transport_id, 65 void *pkt, pj_size_t size, 66 const pj_sockaddr_t *src_addr, 67 unsigned src_addr_len); 68 69 70 /* STUN socket callbacks */ 71 /* Notification when incoming packet has been received. */ 72 static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock, 73 void *pkt, 74 unsigned pkt_len, 75 const pj_sockaddr_t *src_addr, 76 unsigned addr_len); 77 /* Notifification when asynchronous send operation has completed. */ 78 static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock, 79 pj_ioqueue_op_key_t *send_key, 80 pj_ssize_t sent); 81 /* Notification when the status of the STUN transport has changed. */ 82 static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, 83 pj_stun_sock_op op, 84 pj_status_t status); 85 86 87 /* TURN callbacks */ 88 static void turn_on_rx_data(pj_turn_sock *turn_sock, 89 void *pkt, 90 unsigned pkt_len, 91 const pj_sockaddr_t *peer_addr, 92 unsigned addr_len); 93 static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state, 94 pj_turn_state_t new_state); 95 96 97 98 /* Forward decls */ 99 static void destroy_ice_st(pj_ice_strans *ice_st); 81 100 #define ice_st_perror(ice_st,msg,rc) pjnath_perror(ice_st->obj_name,msg,rc) 101 static void sess_init_update(pj_ice_strans *ice_st); 102 103 static void sess_add_ref(pj_ice_strans *ice_st); 104 static pj_bool_t sess_dec_ref(pj_ice_strans *ice_st); 105 106 /** 107 * This structure describes an ICE stream transport component. A component 108 * in ICE stream transport typically corresponds to a single socket created 109 * for this component, and bound to a specific transport address. This 110 * component may have multiple alias addresses, for example one alias 111 * address for each interfaces in multi-homed host, another for server 112 * reflexive alias, and another for relayed alias. For each transport 113 * address alias, an ICE stream transport candidate (#pj_ice_sess_cand) will 114 * be created, and these candidates will eventually registered to the ICE 115 * session. 116 */ 117 typedef struct pj_ice_strans_comp 118 { 119 pj_ice_strans *ice_st; /**< ICE stream transport. */ 120 unsigned comp_id; /**< Component ID. */ 121 122 pj_stun_sock *stun_sock; /**< STUN transport. */ 123 pj_turn_sock *turn_sock; /**< TURN relay transport. */ 124 125 unsigned cand_cnt; /**< # of candidates/aliaes. */ 126 pj_ice_sess_cand cand_list[PJ_ICE_ST_MAX_CAND]; /**< Cand array */ 127 128 unsigned default_cand; /**< Default candidate. */ 129 130 } pj_ice_strans_comp; 131 132 133 /** 134 * This structure represents the ICE stream transport. 135 */ 136 struct pj_ice_strans 137 { 138 char *obj_name; /**< Log ID. */ 139 pj_pool_t *pool; /**< Pool used by this object. */ 140 void *user_data; /**< Application data. */ 141 pj_ice_strans_cfg cfg; /**< Configuration. */ 142 pj_ice_strans_cb cb; /**< Application callback. */ 143 144 pj_ice_sess *ice; /**< ICE session. */ 145 pj_time_val start_time;/**< Time when ICE was started */ 146 147 unsigned comp_cnt; /**< Number of components. */ 148 pj_ice_strans_comp **comp; /**< Components array. */ 149 150 pj_timer_entry ka_timer; /**< STUN keep-alive timer. */ 151 152 pj_atomic_t *busy_cnt; /**< To prevent destroy */ 153 pj_bool_t destroy_req;/**< Destroy has been called? */ 154 pj_bool_t cb_called; /**< Init error callback called?*/ 155 }; 156 157 158 /* Validate configuration */ 159 static pj_status_t pj_ice_strans_cfg_check_valid(const pj_ice_strans_cfg *cfg) 160 { 161 pj_status_t status; 162 163 status = pj_stun_config_check_valid(&cfg->stun_cfg); 164 if (!status) 165 return status; 166 167 return PJ_SUCCESS; 168 } 169 170 171 /* 172 * Initialize ICE transport configuration with default values. 173 */ 174 PJ_DEF(void) pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg) 175 { 176 pj_bzero(cfg, sizeof(*cfg)); 177 178 pj_stun_config_init(&cfg->stun_cfg, NULL, 0, NULL, NULL); 179 pj_stun_sock_cfg_default(&cfg->stun.cfg); 180 pj_turn_alloc_param_default(&cfg->turn.alloc_param); 181 182 cfg->af = pj_AF_INET(); 183 cfg->stun.port = PJ_STUN_PORT; 184 cfg->turn.conn_type = PJ_TURN_TP_UDP; 185 } 186 187 188 /* 189 * Copy configuration. 190 */ 191 PJ_DEF(void) pj_ice_strans_cfg_copy( pj_pool_t *pool, 192 pj_ice_strans_cfg *dst, 193 const pj_ice_strans_cfg *src) 194 { 195 pj_memcpy(dst, src, sizeof(*src)); 196 197 if (src->stun.server.slen) 198 pj_strdup(pool, &dst->stun.server, &src->stun.server); 199 if (src->turn.server.slen) 200 pj_strdup(pool, &dst->turn.server, &src->turn.server); 201 pj_stun_auth_cred_dup(pool, &dst->turn.auth_cred, 202 &src->turn.auth_cred); 203 } 204 205 /* 206 * Create the component. 207 */ 208 static pj_status_t create_comp(pj_ice_strans *ice_st, unsigned comp_id) 209 { 210 pj_ice_strans_comp *comp = NULL; 211 pj_status_t status; 212 213 /* Verify arguments */ 214 PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL); 215 216 /* Check that component ID present */ 217 PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID); 218 219 /* Create component */ 220 comp = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_strans_comp); 221 comp->ice_st = ice_st; 222 comp->comp_id = comp_id; 223 224 ice_st->comp[comp_id-1] = comp; 225 226 /* Initialize default candidate */ 227 comp->default_cand = 0; 228 229 /* Create STUN transport if configured */ 230 if (ice_st->cfg.stun.server.slen || !ice_st->cfg.stun.no_host_cands) { 231 pj_stun_sock_cb stun_sock_cb; 232 pj_ice_sess_cand *cand; 233 234 pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb)); 235 stun_sock_cb.on_rx_data = &stun_on_rx_data; 236 stun_sock_cb.on_status = &stun_on_status; 237 stun_sock_cb.on_data_sent = &stun_on_data_sent; 238 239 /* Create the STUN transport */ 240 status = pj_stun_sock_create(&ice_st->cfg.stun_cfg, NULL, 241 ice_st->cfg.af, &stun_sock_cb, 242 &ice_st->cfg.stun.cfg, 243 comp, &comp->stun_sock); 244 if (status != PJ_SUCCESS) 245 return status; 246 247 /* Start STUN Binding resolution and add srflx candidate 248 * only if server is set 249 */ 250 if (ice_st->cfg.stun.server.slen) { 251 pj_stun_sock_info stun_sock_info; 252 253 /* Add pending job */ 254 ///sess_add_ref(ice_st); 255 256 /* Start Binding resolution */ 257 status = pj_stun_sock_start(comp->stun_sock, 258 &ice_st->cfg.stun.server, 259 ice_st->cfg.stun.port, 260 ice_st->cfg.resolver); 261 if (status != PJ_SUCCESS) { 262 ///sess_dec_ref(ice_st); 263 return status; 264 } 265 266 /* Enumerate addresses */ 267 status = pj_stun_sock_get_info(comp->stun_sock, &stun_sock_info); 268 if (status != PJ_SUCCESS) { 269 ///sess_dec_ref(ice_st); 270 return status; 271 } 272 273 /* Add srflx candidate with pending status */ 274 cand = &comp->cand_list[comp->cand_cnt++]; 275 cand->type = PJ_ICE_CAND_TYPE_SRFLX; 276 cand->status = PJ_EPENDING; 277 cand->local_pref = SRFLX_PREF; 278 cand->transport_id = TP_STUN; 279 cand->comp_id = (pj_uint8_t) comp_id; 280 pj_sockaddr_cp(&cand->base_addr, &stun_sock_info.aliases[0]); 281 pj_sockaddr_cp(&cand->rel_addr, &cand->base_addr); 282 pj_ice_calc_foundation(ice_st->pool, &cand->foundation, 283 cand->type, &cand->base_addr); 284 PJ_LOG(4,(ice_st->obj_name, 285 "Comp %d: srflx candidate starts Binding discovery", 286 comp_id)); 287 288 /* Set default candidate to srflx */ 289 comp->default_cand = cand - comp->cand_list; 290 } 291 292 /* Add local addresses to host candidates, unless no_host_cands 293 * flag is set. 294 */ 295 if (ice_st->cfg.stun.no_host_cands == PJ_FALSE) { 296 pj_stun_sock_info stun_sock_info; 297 unsigned i; 298 299 /* Enumerate addresses */ 300 status = pj_stun_sock_get_info(comp->stun_sock, &stun_sock_info); 301 if (status != PJ_SUCCESS) 302 return status; 303 304 for (i=0; i<stun_sock_info.alias_cnt; ++i) { 305 char addrinfo[PJ_INET6_ADDRSTRLEN+10]; 306 const pj_sockaddr *addr = &stun_sock_info.aliases[i]; 307 308 /* Leave one candidate for relay */ 309 if (comp->cand_cnt >= PJ_ICE_ST_MAX_CAND-1) { 310 PJ_LOG(4,(ice_st->obj_name, "Too many host candidates")); 311 break; 312 } 313 314 /* Ignore loopback addresses unless cfg->stun.loop_addr 315 * is set 316 */ 317 if ((pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127) { 318 if (ice_st->cfg.stun.loop_addr==PJ_FALSE) 319 continue; 320 } 321 322 cand = &comp->cand_list[comp->cand_cnt++]; 323 324 cand->type = PJ_ICE_CAND_TYPE_HOST; 325 cand->status = PJ_SUCCESS; 326 cand->local_pref = HOST_PREF; 327 cand->transport_id = TP_STUN; 328 cand->comp_id = (pj_uint8_t) comp_id; 329 pj_sockaddr_cp(&cand->addr, addr); 330 pj_sockaddr_cp(&cand->base_addr, addr); 331 pj_bzero(&cand->rel_addr, sizeof(cand->rel_addr)); 332 pj_ice_calc_foundation(ice_st->pool, &cand->foundation, 333 cand->type, &cand->base_addr); 334 335 PJ_LOG(4,(ice_st->obj_name, 336 "Comp %d: host candidate %s added", 337 comp_id, pj_sockaddr_print(&cand->addr, addrinfo, 338 sizeof(addrinfo), 3))); 339 } 340 } 341 } 342 343 /* Create TURN relay if configured. */ 344 if (ice_st->cfg.turn.server.slen) { 345 pj_turn_sock_cb turn_sock_cb; 346 pj_ice_sess_cand *cand; 347 348 /* Init TURN socket */ 349 pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb)); 350 turn_sock_cb.on_rx_data = &turn_on_rx_data; 351 turn_sock_cb.on_state = &turn_on_state; 352 353 status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, ice_st->cfg.af, 354 ice_st->cfg.turn.conn_type, 355 &turn_sock_cb, 0, comp, 356 &comp->turn_sock); 357 if (status != PJ_SUCCESS) { 358 return status; 359 } 360 361 /* Add pending job */ 362 ///sess_add_ref(ice_st); 363 364 /* Start allocation */ 365 status=pj_turn_sock_alloc(comp->turn_sock, 366 &ice_st->cfg.turn.server, 367 ice_st->cfg.turn.port, 368 ice_st->cfg.resolver, 369 &ice_st->cfg.turn.auth_cred, 370 &ice_st->cfg.turn.alloc_param); 371 if (status != PJ_SUCCESS) { 372 ///sess_dec_ref(ice_st); 373 return status; 374 } 375 376 /* Add relayed candidate with pending status */ 377 cand = &comp->cand_list[comp->cand_cnt++]; 378 cand->type = PJ_ICE_CAND_TYPE_RELAYED; 379 cand->status = PJ_EPENDING; 380 cand->local_pref = RELAY_PREF; 381 cand->transport_id = TP_TURN; 382 cand->comp_id = (pj_uint8_t) comp_id; 383 384 PJ_LOG(4,(ice_st->obj_name, 385 "Comp %d: TURN relay candidate waiting for allocation", 386 comp_id)); 387 388 /* Set default candidate to relay */ 389 comp->default_cand = cand - comp->cand_list; 390 } 391 392 return PJ_SUCCESS; 393 } 394 82 395 83 396 /* 84 397 * Create ICE stream transport 85 398 */ 86 PJ_DEF(pj_status_t) pj_ice_strans_create( pj_stun_config *stun_cfg,87 const char *name,399 PJ_DEF(pj_status_t) pj_ice_strans_create( const char *name, 400 const pj_ice_strans_cfg *cfg, 88 401 unsigned comp_cnt, 89 402 void *user_data, … … 93 406 pj_pool_t *pool; 94 407 pj_ice_strans *ice_st; 95 96 PJ_ASSERT_RETURN(stun_cfg && comp_cnt && cb && p_ice_st, PJ_EINVAL); 97 PJ_ASSERT_RETURN(stun_cfg->ioqueue && stun_cfg->timer_heap, PJ_EINVAL); 408 unsigned i; 409 pj_status_t status; 410 411 status = pj_ice_strans_cfg_check_valid(cfg); 412 if (status != PJ_SUCCESS) 413 return status; 414 415 PJ_ASSERT_RETURN(comp_cnt && cb && p_ice_st, PJ_EINVAL); 98 416 99 417 if (name == NULL) 100 name = "ic str%p";101 102 pool = pj_pool_create( stun_cfg->pf, name, PJNATH_POOL_LEN_ICE_STRANS,418 name = "ice%p"; 419 420 pool = pj_pool_create(cfg->stun_cfg.pf, name, PJNATH_POOL_LEN_ICE_STRANS, 103 421 PJNATH_POOL_INC_ICE_STRANS, NULL); 104 422 ice_st = PJ_POOL_ZALLOC_T(pool, pj_ice_strans); 105 423 ice_st->pool = pool; 106 pj_memcpy(ice_st->obj_name, pool->obj_name, PJ_MAX_OBJ_NAME);424 ice_st->obj_name = pool->obj_name; 107 425 ice_st->user_data = user_data; 426 427 PJ_LOG(4,(ice_st->obj_name, 428 "Creating ICE stream transport with %d component(s)", 429 comp_cnt)); 430 431 pj_ice_strans_cfg_copy(pool, &ice_st->cfg, cfg); 432 pj_memcpy(&ice_st->cb, cb, sizeof(*cb)); 108 433 434 status = pj_atomic_create(pool, 0, &ice_st->busy_cnt); 435 if (status != PJ_SUCCESS) { 436 destroy_ice_st(ice_st); 437 return status; 438 } 439 109 440 ice_st->comp_cnt = comp_cnt; 110 ice_st->comp = (pj_ice_strans_comp**) pj_pool_calloc(pool, comp_cnt, 111 sizeof(void*)); 112 113 pj_memcpy(&ice_st->cb, cb, sizeof(*cb)); 114 pj_memcpy(&ice_st->stun_cfg, stun_cfg, sizeof(*stun_cfg)); 115 441 ice_st->comp = (pj_ice_strans_comp**) 442 pj_pool_calloc(pool, comp_cnt, sizeof(pj_ice_strans_comp*)); 443 444 for (i=0; i<comp_cnt; ++i) { 445 status = create_comp(ice_st, i+1); 446 if (status != PJ_SUCCESS) { 447 destroy_ice_st(ice_st); 448 return status; 449 } 450 } 451 452 /* Check if all candidates are ready (this may call callback) */ 453 sess_init_update(ice_st); 116 454 117 455 PJ_LOG(4,(ice_st->obj_name, "ICE stream transport created")); … … 122 460 123 461 /* Destroy ICE */ 124 static void destroy_ice_st(pj_ice_strans *ice_st , pj_status_t reason)462 static void destroy_ice_st(pj_ice_strans *ice_st) 125 463 { 126 464 unsigned i; 127 char obj_name[PJ_MAX_OBJ_NAME];128 129 if (reason == PJ_SUCCESS) {130 pj_memcpy(obj_name, ice_st->obj_name, PJ_MAX_OBJ_NAME);131 PJ_LOG(4,(obj_name, "ICE stream transport shutting down"));132 }133 134 /* Kill keep-alive timer, if any */135 stop_ka_timer(ice_st);136 465 137 466 /* Destroy ICE if we have ICE */ … … 144 473 for (i=0; i<ice_st->comp_cnt; ++i) { 145 474 if (ice_st->comp[i]) { 146 destroy_component(ice_st->comp[i]); 147 ice_st->comp[i] = NULL; 475 if (ice_st->comp[i]->stun_sock) { 476 pj_stun_sock_set_user_data(ice_st->comp[i]->stun_sock, NULL); 477 pj_stun_sock_destroy(ice_st->comp[i]->stun_sock); 478 ice_st->comp[i]->stun_sock = NULL; 479 } 480 if (ice_st->comp[i]->turn_sock) { 481 pj_turn_sock_set_user_data(ice_st->comp[i]->turn_sock, NULL); 482 pj_turn_sock_destroy(ice_st->comp[i]->turn_sock); 483 ice_st->comp[i]->turn_sock = NULL; 484 } 148 485 } 149 486 } 150 487 ice_st->comp_cnt = 0; 488 489 /* Destroy reference counter */ 490 if (ice_st->busy_cnt) { 491 pj_assert(pj_atomic_get(ice_st->busy_cnt)==0); 492 pj_atomic_destroy(ice_st->busy_cnt); 493 ice_st->busy_cnt = NULL; 494 } 151 495 152 496 /* Done */ 153 497 pj_pool_release(ice_st->pool); 154 155 if (reason == PJ_SUCCESS) { 156 PJ_LOG(4,(obj_name, "ICE stream transport destroyed")); 157 } 498 } 499 500 /* Notification about failure */ 501 static void sess_fail(pj_ice_strans *ice_st, pj_ice_strans_op op, 502 const char *title, pj_status_t status) 503 { 504 char errmsg[PJ_ERR_MSG_SIZE]; 505 506 pj_strerror(status, errmsg, sizeof(errmsg)); 507 PJ_LOG(4,(ice_st->obj_name, "%s: %s", title, errmsg)); 508 509 if (op==PJ_ICE_STRANS_OP_INIT && ice_st->cb_called) 510 return; 511 512 ice_st->cb_called = PJ_TRUE; 513 514 if (ice_st->cb.on_ice_complete) 515 (*ice_st->cb.on_ice_complete)(ice_st, op, status); 516 } 517 518 /* Update initialization status */ 519 static void sess_init_update(pj_ice_strans *ice_st) 520 { 521 unsigned i; 522 523 /* Ignore if init callback has been called */ 524 if (ice_st->cb_called) 525 return; 526 527 /* Notify application when all candidates have been gathered */ 528 for (i=0; i<ice_st->comp_cnt; ++i) { 529 unsigned j; 530 pj_ice_strans_comp *comp = ice_st->comp[i]; 531 532 for (j=0; j<comp->cand_cnt; ++j) { 533 pj_ice_sess_cand *cand = &comp->cand_list[j]; 534 535 if (cand->status == PJ_EPENDING) 536 return; 537 } 538 } 539 540 /* All candidates have been gathered */ 541 ice_st->cb_called = PJ_TRUE; 542 if (ice_st->cb.on_ice_complete) 543 (*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_INIT, 544 PJ_SUCCESS); 158 545 } 159 546 … … 163 550 PJ_DEF(pj_status_t) pj_ice_strans_destroy(pj_ice_strans *ice_st) 164 551 { 165 destroy_ice_st(ice_st, PJ_SUCCESS); 552 char obj_name[PJ_MAX_OBJ_NAME]; 553 554 PJ_ASSERT_RETURN(ice_st, PJ_EINVAL); 555 556 ice_st->destroy_req = PJ_TRUE; 557 if (pj_atomic_get(ice_st->busy_cnt) > 0) { 558 PJ_LOG(5,(ice_st->obj_name, 559 "ICE strans object is busy, will destroy later")); 560 return PJ_EPENDING; 561 } 562 563 pj_memcpy(obj_name, ice_st->obj_name, PJ_MAX_OBJ_NAME); 564 destroy_ice_st(ice_st); 565 566 PJ_LOG(4,(obj_name, "ICE stream transport destroyed")); 166 567 return PJ_SUCCESS; 167 568 } 168 569 169 /* 170 * Resolve STUN server 171 */ 172 PJ_DEF(pj_status_t) pj_ice_strans_set_stun_domain(pj_ice_strans *ice_st, 173 pj_dns_resolver *resolver, 174 const pj_str_t *domain) 175 { 176 /* Yeah, TODO */ 177 PJ_UNUSED_ARG(ice_st); 178 PJ_UNUSED_ARG(resolver); 179 PJ_UNUSED_ARG(domain); 180 return -1; 181 } 182 183 /* 184 * Set STUN server address. 185 */ 186 PJ_DEF(pj_status_t) pj_ice_strans_set_stun_srv( pj_ice_strans *ice_st, 187 const pj_sockaddr_in *stun_srv, 188 const pj_sockaddr_in *turn_srv) 189 { 190 PJ_ASSERT_RETURN(ice_st, PJ_EINVAL); 191 /* Must not have pending resolver job */ 192 PJ_ASSERT_RETURN(ice_st->has_rjob==PJ_FALSE, PJ_EINVALIDOP); 193 194 if (stun_srv) { 195 pj_memcpy(&ice_st->stun_srv, stun_srv, sizeof(pj_sockaddr_in)); 570 571 /* 572 * Increment busy counter. 573 */ 574 static void sess_add_ref(pj_ice_strans *ice_st) 575 { 576 pj_atomic_inc(ice_st->busy_cnt); 577 } 578 579 /* 580 * Decrement busy counter. If the counter has reached zero and destroy 581 * has been requested, destroy the object and return FALSE. 582 */ 583 static pj_bool_t sess_dec_ref(pj_ice_strans *ice_st) 584 { 585 int count = pj_atomic_dec_and_get(ice_st->busy_cnt); 586 pj_assert(count >= 0); 587 if (count==0 && ice_st->destroy_req) { 588 pj_ice_strans_destroy(ice_st); 589 return PJ_FALSE; 196 590 } else { 197 pj_bzero(&ice_st->stun_srv, sizeof(pj_sockaddr_in)); 198 } 199 200 if (turn_srv) { 201 pj_memcpy(&ice_st->turn_srv, turn_srv, sizeof(pj_sockaddr_in)); 202 } else { 203 pj_bzero(&ice_st->turn_srv, sizeof(pj_sockaddr_in)); 204 } 205 206 return PJ_SUCCESS; 207 } 208 209 /* Add new candidate */ 210 static pj_status_t add_cand( pj_ice_strans *ice_st, 211 pj_ice_strans_comp *comp, 212 unsigned comp_id, 213 pj_ice_cand_type type, 214 pj_uint16_t local_pref, 215 const pj_sockaddr_in *addr, 216 pj_bool_t set_default) 217 { 218 pj_ice_strans_cand *cand; 219 unsigned i; 220 221 PJ_ASSERT_RETURN(ice_st && comp && addr, PJ_EINVAL); 222 PJ_ASSERT_RETURN(comp->cand_cnt < PJ_ICE_ST_MAX_CAND, PJ_ETOOMANY); 223 224 /* Check that we don't have candidate with the same 225 * address. 226 */ 227 for (i=0; i<comp->cand_cnt; ++i) { 228 if (pj_memcmp(addr, &comp->cand_list[i].addr, 229 sizeof(pj_sockaddr_in))==0) 230 { 231 /* Duplicate */ 232 PJ_LOG(5,(ice_st->obj_name, "Duplicate candidate not added")); 233 return PJ_SUCCESS; 234 } 235 } 236 237 cand = &comp->cand_list[comp->cand_cnt]; 238 239 pj_bzero(cand, sizeof(*cand)); 240 cand->type = type; 241 cand->status = PJ_SUCCESS; 242 pj_memcpy(&cand->addr, addr, sizeof(pj_sockaddr_in)); 243 cand->ice_cand_id = -1; 244 cand->local_pref = local_pref; 245 pj_ice_calc_foundation(ice_st->pool, &cand->foundation, type, 246 &comp->local_addr); 247 248 if (set_default) 249 comp->default_cand = comp->cand_cnt; 250 251 PJ_LOG(5,(ice_st->obj_name, 252 "Candidate %s:%d (type=%s) added to component %d", 253 pj_inet_ntoa(addr->sin_addr), 254 (int)pj_ntohs(addr->sin_port), 255 pj_ice_get_cand_type_name(type), 256 comp_id)); 257 258 comp->cand_cnt++; 259 return PJ_SUCCESS; 260 } 261 262 /* Create new component (i.e. socket) */ 263 static pj_status_t create_component(pj_ice_strans *ice_st, 264 unsigned comp_id, 265 pj_uint32_t options, 266 const pj_sockaddr_in *addr, 267 pj_ice_strans_comp **p_comp) 268 { 269 enum { MAX_RETRY=100, PORT_INC=2 }; 270 pj_ioqueue_callback ioqueue_cb; 271 pj_ice_strans_comp *comp; 272 int retry, addr_len; 273 struct { 274 pj_uint32_t a1, a2, a3; 275 } tsx_id; 276 pj_status_t status; 277 278 comp = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_strans_comp); 279 comp->ice_st = ice_st; 280 comp->comp_id = comp_id; 281 comp->options = options; 282 comp->sock = PJ_INVALID_SOCKET; 283 comp->last_status = PJ_SUCCESS; 284 285 /* Create transaction ID for STUN keep alives */ 286 tsx_id.a1 = 0; 287 tsx_id.a2 = comp_id; 288 tsx_id.a3 = (pj_uint32_t) (unsigned long) ice_st; 289 pj_memcpy(comp->ka_tsx_id, &tsx_id, sizeof(comp->ka_tsx_id)); 290 291 /* Create socket */ 292 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &comp->sock); 293 if (status != PJ_SUCCESS) 294 return status; 295 296 /* Init address */ 297 if (addr) 298 pj_memcpy(&comp->local_addr, addr, sizeof(pj_sockaddr_in)); 299 else 300 pj_sockaddr_in_init(&comp->local_addr.ipv4, NULL, 0); 301 302 /* Retry binding socket */ 303 for (retry=0; retry<MAX_RETRY; ++retry) { 304 pj_uint16_t port; 305 306 status = pj_sock_bind(comp->sock, &comp->local_addr, 307 sizeof(pj_sockaddr_in)); 308 if (status == PJ_SUCCESS) 309 break; 310 311 if (options & PJ_ICE_ST_OPT_NO_PORT_RETRY) 312 goto on_error; 313 314 port = pj_ntohs(comp->local_addr.ipv4.sin_port); 315 port += PORT_INC; 316 comp->local_addr.ipv4.sin_port = pj_htons(port); 317 } 318 319 /* Get the actual port where the socket is bound to. 320 * (don't care about the address, it will be retrieved later) 321 */ 322 addr_len = sizeof(comp->local_addr); 323 status = pj_sock_getsockname(comp->sock, &comp->local_addr, &addr_len); 324 if (status != PJ_SUCCESS) 325 goto on_error; 326 327 /* Register to ioqueue */ 328 pj_bzero(&ioqueue_cb, sizeof(ioqueue_cb)); 329 ioqueue_cb.on_read_complete = &on_read_complete; 330 status = pj_ioqueue_register_sock(ice_st->pool, ice_st->stun_cfg.ioqueue, 331 comp->sock, comp, &ioqueue_cb, 332 &comp->key); 333 if (status != PJ_SUCCESS) 334 goto on_error; 335 336 /* Disable concurrency */ 337 status = pj_ioqueue_set_concurrency(comp->key, PJ_FALSE); 338 if (status != PJ_SUCCESS) 339 goto on_error; 340 341 pj_ioqueue_op_key_init(&comp->read_op, sizeof(comp->read_op)); 342 pj_ioqueue_op_key_init(&comp->write_op, sizeof(comp->write_op)); 343 344 /* Kick start reading the socket */ 345 on_read_complete(comp->key, &comp->read_op, 0); 346 347 /* If the socket is bound to INADDR_ANY, then lookup all interfaces in 348 * the host and add them into cand_list. Otherwise if the socket is bound 349 * to a specific interface, then only add that specific interface to 350 * cand_list. 351 */ 352 if (((options & PJ_ICE_ST_OPT_DONT_ADD_CAND)==0) && 353 comp->local_addr.ipv4.sin_addr.s_addr == 0) 354 { 355 /* Socket is bound to INADDR_ANY */ 356 unsigned i, ifs_cnt; 357 pj_sockaddr ifs[PJ_ICE_ST_MAX_CAND-2]; 358 359 /* Reset default candidate */ 360 comp->default_cand = -1; 361 362 /* Enum all IP interfaces in the host */ 363 ifs_cnt = PJ_ARRAY_SIZE(ifs); 364 status = pj_enum_ip_interface(pj_AF_INET(), &ifs_cnt, ifs); 365 if (status != PJ_SUCCESS) 366 goto on_error; 367 368 /* Set default IP interface as the base address */ 369 status = pj_gethostip(pj_AF_INET(), &comp->local_addr); 370 if (status != PJ_SUCCESS) 371 goto on_error; 372 373 /* Add candidate entry for each interface */ 374 for (i=0; i<ifs_cnt; ++i) { 375 pj_sockaddr_in cand_addr; 376 pj_bool_t set_default; 377 pj_uint16_t local_pref; 378 379 /* Ignore 127.0.0.0/24 address */ 380 if ((pj_ntohl(ifs[i].ipv4.sin_addr.s_addr) >> 24)==127) 381 continue; 382 383 pj_memcpy(&cand_addr, &comp->local_addr, sizeof(pj_sockaddr_in)); 384 cand_addr.sin_addr.s_addr = ifs[i].ipv4.sin_addr.s_addr; 385 386 387 /* If the IP address is equal to local address, assign it 388 * as default candidate. 389 */ 390 if (ifs[i].ipv4.sin_addr.s_addr == comp->local_addr.ipv4.sin_addr.s_addr) { 391 set_default = PJ_TRUE; 392 local_pref = 65535; 393 } else { 394 set_default = PJ_FALSE; 395 local_pref = 0; 396 } 397 398 status = add_cand(ice_st, comp, comp_id, 399 PJ_ICE_CAND_TYPE_HOST, 400 local_pref, &cand_addr, set_default); 401 if (status != PJ_SUCCESS) 402 goto on_error; 403 } 404 405 406 } else if ((options & PJ_ICE_ST_OPT_DONT_ADD_CAND)==0) { 407 /* Socket is bound to specific address. 408 * In this case only add that address as a single entry in the 409 * cand_list table. 410 */ 411 status = add_cand(ice_st, comp, comp_id, 412 PJ_ICE_CAND_TYPE_HOST, 413 65535, &comp->local_addr.ipv4, 414 PJ_TRUE); 415 if (status != PJ_SUCCESS) 416 goto on_error; 417 418 } else if (options & PJ_ICE_ST_OPT_DONT_ADD_CAND) { 419 /* If application doesn't want to add candidate, just fix local_addr 420 * in case its value is zero. 421 */ 422 if (comp->local_addr.ipv4.sin_addr.s_addr == 0) { 423 status = pj_gethostip(pj_AF_INET(), &comp->local_addr); 424 if (status != PJ_SUCCESS) 425 return status; 426 } 427 } 428 429 430 /* Done */ 431 if (p_comp) 432 *p_comp = comp; 433 434 return PJ_SUCCESS; 435 436 on_error: 437 destroy_component(comp); 438 return status; 439 } 440 441 /* 442 * This is callback called by ioqueue on incoming packet 443 */ 444 static void on_read_complete(pj_ioqueue_key_t *key, 445 pj_ioqueue_op_key_t *op_key, 446 pj_ssize_t bytes_read) 447 { 448 pj_ice_strans_comp *comp = (pj_ice_strans_comp*) 449 pj_ioqueue_get_user_data(key); 450 pj_ice_strans *ice_st = comp->ice_st; 451 pj_ssize_t pkt_size; 452 enum { RETRY = 10 }; 453 unsigned retry; 454 pj_status_t status; 455 456 if (bytes_read > 0) { 457 /* 458 * Okay, we got a packet from the socket for the component. There is 459 * a bit of situation here, since this packet could be one of these: 460 * 461 * 1) this could be the response of STUN binding request sent by 462 * this component to a) an initial request to get the STUN mapped 463 * address of this component, or b) subsequent request to keep 464 * the binding alive. 465 * 466 * 2) this could be a packet (STUN or not STUN) sent from the STUN 467 * relay server. In this case, still there are few options to do 468 * for this packet: a) process this locally if this packet is 469 * related to TURN session management (e.g. Allocate response), 470 * b) forward this packet to ICE if this is related to ICE 471 * discovery process. 472 * 473 * 3) this could be a STUN request or response sent as part of ICE 474 * discovery process. 475 * 476 * 4) this could be application's packet, e.g. when ICE processing 477 * is done and agents start sending RTP/RTCP packets to each 478 * other, or when ICE processing is not done and this ICE stream 479 * transport decides to allow sending data. 480 * 481 * So far we don't have good solution for this. 482 * The process below is just a workaround. 483 */ 484 status = pj_stun_msg_check(comp->pkt, bytes_read, 485 PJ_STUN_IS_DATAGRAM); 486 487 if (status == PJ_SUCCESS) { 488 if (comp->stun_sess && 489 PJ_STUN_IS_RESPONSE(((pj_stun_msg_hdr*)comp->pkt)->type) && 490 pj_memcmp(comp->pkt+8, comp->ka_tsx_id, 12) == 0) 491 { 492 status = pj_stun_session_on_rx_pkt(comp->stun_sess, comp->pkt, 493 bytes_read, 494 PJ_STUN_IS_DATAGRAM, NULL, 495 NULL, &comp->src_addr, 496 comp->src_addr_len); 497 } else if (ice_st->ice) { 498 PJ_TODO(DISTINGUISH_BETWEEN_LOCAL_AND_RELAY); 499 500 TRACE_PKT((comp->ice_st->obj_name, 501 "Component %d RX packet from %s:%d", 502 comp->comp_id, 503 pj_inet_ntoa(comp->src_addr.ipv4.sin_addr), 504 (int)pj_ntohs(comp->src_addr.ipv4.sin_port))); 505 506 status = pj_ice_sess_on_rx_pkt(ice_st->ice, comp->comp_id, 507 comp->pkt, bytes_read, 508 &comp->src_addr, 509 comp->src_addr_len); 510 } else { 511 /* This must have been a very late STUN reponse, 512 * or an early STUN Binding Request when our local 513 * ICE has not been created yet. */ 514 } 515 } else { 516 (*ice_st->cb.on_rx_data)(ice_st, comp->comp_id, 517 comp->pkt, bytes_read, 518 &comp->src_addr, comp->src_addr_len); 519 } 520 521 } else if (bytes_read < 0) { 522 ice_st_perror(comp->ice_st, "ioqueue read callback error", 523 -bytes_read); 524 } 525 526 /* Read next packet */ 527 for (retry=0; retry<RETRY;) { 528 pkt_size = sizeof(comp->pkt); 529 comp->src_addr_len = sizeof(comp->src_addr); 530 status = pj_ioqueue_recvfrom(key, op_key, comp->pkt, &pkt_size, 531 PJ_IOQUEUE_ALWAYS_ASYNC, 532 &comp->src_addr, &comp->src_addr_len); 533 if (status == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK) || 534 status == PJ_STATUS_FROM_OS(OSERR_EINPROGRESS) || 535 status == PJ_STATUS_FROM_OS(OSERR_ECONNRESET)) 536 { 537 ice_st_perror(comp->ice_st, "ioqueue recvfrom() error", status); 538 ++retry; 539 continue; 540 } else if (status != PJ_SUCCESS && status != PJ_EPENDING) { 541 retry += 2; 542 ice_st_perror(comp->ice_st, "ioqueue recvfrom() error", status); 543 } else { 544 break; 545 } 546 } 547 } 548 549 /* 550 * Destroy a component 551 */ 552 static void destroy_component(pj_ice_strans_comp *comp) 553 { 554 if (comp->stun_sess) { 555 pj_stun_session_destroy(comp->stun_sess); 556 comp->stun_sess = NULL; 557 } 558 559 if (comp->key) { 560 pj_ioqueue_unregister(comp->key); 561 comp->key = NULL; 562 comp->sock = PJ_INVALID_SOCKET; 563 } else if (comp->sock != PJ_INVALID_SOCKET && comp->sock != 0) { 564 pj_sock_close(comp->sock); 565 comp->sock = PJ_INVALID_SOCKET; 566 } 567 } 568 569 570 /* STUN keep-alive timer callback */ 571 static void ka_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te) 572 { 573 pj_ice_strans *ice_st = (pj_ice_strans*)te->user_data; 574 unsigned i; 575 pj_status_t status; 576 577 PJ_UNUSED_ARG(th); 578 579 ice_st->ka_timer.id = PJ_FALSE; 580 581 for (i=0; i<ice_st->comp_cnt; ++i) { 582 pj_ice_strans_comp *comp = ice_st->comp[i]; 583 pj_stun_tx_data *tdata; 584 unsigned j; 585 586 /* Does this component have STUN server reflexive candidate? */ 587 for (j=0; j<comp->cand_cnt; ++j) { 588 if (comp->cand_list[j].type == PJ_ICE_CAND_TYPE_SRFLX) 589 break; 590 } 591 if (j == comp->cand_cnt) 592 continue; 593 594 /* Create STUN binding request */ 595 status = pj_stun_session_create_req(comp->stun_sess, 596 PJ_STUN_BINDING_REQUEST, 597 PJ_STUN_MAGIC, 598 comp->ka_tsx_id, &tdata); 599 if (status != PJ_SUCCESS) 600 continue; 601 602 /* tdata->user_data is NULL for keep-alive */ 603 //tdata->user_data = NULL; 604 605 ++comp->pending_cnt; 606 607 608 /* Send STUN binding request */ 609 PJ_LOG(5,(ice_st->obj_name, "Sending STUN keep-alive from %s;%d", 610 pj_inet_ntoa(comp->local_addr.ipv4.sin_addr), 611 pj_ntohs(comp->local_addr.ipv4.sin_port))); 612 status = pj_stun_session_send_msg(comp->stun_sess, &comp->cand_list[j], 613 PJ_FALSE, PJ_TRUE, &ice_st->stun_srv, 614 sizeof(pj_sockaddr_in), tdata); 615 if (status != PJ_SUCCESS) { 616 --comp->pending_cnt; 617 } 618 } 619 620 /* Start next timer */ 621 start_ka_timer(ice_st); 622 } 623 624 /* Start STUN keep-alive timer */ 625 static void start_ka_timer(pj_ice_strans *ice_st) 626 { 627 pj_time_val delay; 628 629 /* Skip if timer is already running */ 630 if (ice_st->ka_timer.id != PJ_FALSE) 631 return; 632 633 delay.sec = PJ_ICE_ST_KEEP_ALIVE_MIN; 634 delay.msec = pj_rand() % (PJ_ICE_ST_KEEP_ALIVE_MAX_RAND * 1000); 635 pj_time_val_normalize(&delay); 636 637 ice_st->ka_timer.cb = &ka_timer_cb; 638 ice_st->ka_timer.user_data = ice_st; 639 640 if (pj_timer_heap_schedule(ice_st->stun_cfg.timer_heap, 641 &ice_st->ka_timer, &delay)==PJ_SUCCESS) 642 { 643 ice_st->ka_timer.id = PJ_TRUE; 644 } 645 } 646 647 648 /* Stop STUN keep-alive timer */ 649 static void stop_ka_timer(pj_ice_strans *ice_st) 650 { 651 /* Skip if timer is already stop */ 652 if (ice_st->ka_timer.id == PJ_FALSE) 653 return; 654 655 pj_timer_heap_cancel(ice_st->stun_cfg.timer_heap, &ice_st->ka_timer); 656 ice_st->ka_timer.id = PJ_FALSE; 657 } 658 659 660 /* 661 * Add STUN mapping to a component. 662 */ 663 static pj_status_t get_stun_mapped_addr(pj_ice_strans *ice_st, 664 pj_ice_strans_comp *comp) 665 { 666 pj_ice_strans_cand *cand; 667 pj_stun_session_cb sess_cb; 668 pj_stun_tx_data *tdata; 669 pj_status_t status; 670 671 PJ_ASSERT_RETURN(ice_st && comp, PJ_EINVAL); 672 673 /* Bail out if STUN server is still being resolved */ 674 if (ice_st->has_rjob) 675 return PJ_EBUSY; 676 677 /* Just return (successfully) if STUN server is not configured */ 678 if (ice_st->stun_srv.sin_family == 0) 679 return PJ_SUCCESS; 680 681 682 /* Create STUN session for this component */ 683 pj_bzero(&sess_cb, sizeof(sess_cb)); 684 sess_cb.on_request_complete = &stun_on_request_complete; 685 sess_cb.on_send_msg = &stun_on_send_msg; 686 status = pj_stun_session_create(&ice_st->stun_cfg, ice_st->obj_name, 687 &sess_cb, PJ_FALSE, &comp->stun_sess); 688 if (status != PJ_SUCCESS) 689 return status; 690 691 /* Associate component with STUN session */ 692 pj_stun_session_set_user_data(comp->stun_sess, (void*)comp); 693 694 /* Create STUN binding request */ 695 status = pj_stun_session_create_req(comp->stun_sess, 696 PJ_STUN_BINDING_REQUEST, 697 PJ_STUN_MAGIC, 698 comp->ka_tsx_id, 699 &tdata); 700 if (status != PJ_SUCCESS) 701 return status; 702 703 /* Will be attached to tdata in send_msg() */ 704 cand = &comp->cand_list[comp->cand_cnt]; 705 706 /* Add pending count first, since stun_on_request_complete() 707 * may be called before this function completes 708 */ 709 comp->pending_cnt++; 710 711 /* Add new alias to this component */ 712 cand->type = PJ_ICE_CAND_TYPE_SRFLX; 713 cand->status = PJ_EPENDING; 714 cand->ice_cand_id = -1; 715 cand->local_pref = 65535; 716 pj_ice_calc_foundation(ice_st->pool, &cand->foundation, 717 PJ_ICE_CAND_TYPE_SRFLX, &comp->local_addr); 718 719 ++comp->cand_cnt; 720 721 /* Send STUN binding request */ 722 status = pj_stun_session_send_msg(comp->stun_sess, (void*)cand, PJ_FALSE, 723 PJ_TRUE, &ice_st->stun_srv, 724 sizeof(pj_sockaddr_in), tdata); 725 if (status != PJ_SUCCESS) { 726 --comp->pending_cnt; 727 --comp->cand_cnt; 728 return status; 729 } 730 731 return PJ_SUCCESS; 732 } 733 734 735 /* 736 * Create the component. 737 */ 738 PJ_DEF(pj_status_t) pj_ice_strans_create_comp(pj_ice_strans *ice_st, 739 unsigned comp_id, 740 pj_uint32_t options, 741 const pj_sockaddr_in *addr) 742 { 743 pj_ice_strans_comp *comp = NULL; 744 pj_status_t status; 745 746 /* Verify arguments */ 747 PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL); 748 749 /* Check that component ID present */ 750 PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID); 751 752 /* Can't add new component while ICE is running */ 753 PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EBUSY); 754 755 /* Can't add new component while resolver is running */ 756 PJ_ASSERT_RETURN(ice_st->has_rjob == PJ_FALSE, PJ_EBUSY); 757 758 759 /* Create component */ 760 status = create_component(ice_st, comp_id, options, addr, &comp); 761 if (status != PJ_SUCCESS) 762 return status; 763 764 if ((options & PJ_ICE_ST_OPT_DISABLE_STUN) == 0) { 765 status = get_stun_mapped_addr(ice_st, comp); 766 if (status != PJ_SUCCESS) { 767 destroy_component(comp); 768 return status; 769 } 770 } 771 772 /* Store this component */ 773 ice_st->comp[comp_id-1] = comp; 774 775 return PJ_SUCCESS; 776 } 777 778 779 PJ_DEF(pj_status_t) pj_ice_strans_add_cand( pj_ice_strans *ice_st, 780 unsigned comp_id, 781 pj_ice_cand_type type, 782 pj_uint16_t local_pref, 783 const pj_sockaddr_in *addr, 784 pj_bool_t set_default) 785 { 786 pj_ice_strans_comp *comp; 787 788 789 PJ_ASSERT_RETURN(ice_st && comp_id && addr, PJ_EINVAL); 790 PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJ_EINVAL); 791 PJ_ASSERT_RETURN(ice_st->comp[comp_id-1] != NULL, PJ_EINVALIDOP); 792 793 comp = ice_st->comp[comp_id-1]; 794 return add_cand(ice_st, comp, comp_id, type, local_pref, addr, 795 set_default); 796 } 797 798 799 PJ_DEF(pj_status_t) pj_ice_strans_get_comps_status(pj_ice_strans *ice_st) 800 { 801 unsigned i; 802 pj_status_t worst = PJ_SUCCESS; 803 804 for (i=0; i<ice_st->comp_cnt; ++i) { 805 pj_ice_strans_comp *comp = ice_st->comp[i]; 806 807 if (comp->last_status == PJ_SUCCESS) { 808 /* okay */ 809 } else if (comp->pending_cnt && worst==PJ_SUCCESS) { 810 worst = PJ_EPENDING; 811 break; 812 } else if (comp->last_status != PJ_SUCCESS) { 813 worst = comp->last_status; 814 break; 815 } 816 817 if (worst != PJ_SUCCESS) 818 break; 819 } 820 821 return worst; 822 } 591 return PJ_TRUE; 592 } 593 } 594 595 /* 596 * Get user data 597 */ 598 PJ_DEF(void*) pj_ice_strans_get_user_data(pj_ice_strans *ice_st) 599 { 600 PJ_ASSERT_RETURN(ice_st, NULL); 601 return ice_st->user_data; 602 } 603 823 604 824 605 /* … … 833 614 unsigned i; 834 615 pj_ice_sess_cb ice_cb; 835 const pj_uint8_t srflx_prio[4] = { 100, 126, 110, 0 };616 //const pj_uint8_t srflx_prio[4] = { 100, 126, 110, 0 }; 836 617 837 618 /* Check arguments */ … … 849 630 850 631 /* Create! */ 851 status = pj_ice_sess_create(&ice_st-> stun_cfg, ice_st->obj_name, role,632 status = pj_ice_sess_create(&ice_st->cfg.stun_cfg, ice_st->obj_name, role, 852 633 ice_st->comp_cnt, &ice_cb, 853 634 local_ufrag, local_passwd, &ice_st->ice); … … 858 639 ice_st->ice->user_data = (void*)ice_st; 859 640 641 #if 0 860 642 /* If default candidate for components are SRFLX one, upload a custom 861 643 * type priority to ICE session so that SRFLX candidates will get … … 868 650 pj_ice_sess_set_prefs(ice_st->ice, srflx_prio); 869 651 } 870 871 872 /* Add c andidates */652 #endif 653 654 /* Add components/candidates */ 873 655 for (i=0; i<ice_st->comp_cnt; ++i) { 874 656 unsigned j; 875 pj_ice_strans_comp *comp= ice_st->comp[i]; 657 pj_ice_strans_comp *comp = ice_st->comp[i]; 658 659 /* Re-enable logging for Send/Data indications */ 660 if (comp->turn_sock) { 661 PJ_LOG(5,(ice_st->obj_name, 662 "Disabling STUN Indication logging for " 663 "component %d", i+1)); 664 pj_turn_sock_set_log(comp->turn_sock, 0xFFFF); 665 } 876 666 877 667 for (j=0; j<comp->cand_cnt; ++j) { 878 pj_ice_strans_cand *cand = &comp->cand_list[j]; 668 pj_ice_sess_cand *cand = &comp->cand_list[j]; 669 unsigned ice_cand_id; 879 670 880 671 /* Skip if candidate is not ready */ 881 672 if (cand->status != PJ_SUCCESS) { 882 673 PJ_LOG(5,(ice_st->obj_name, 883 "Candidate %d in component %d is not added",674 "Candidate %d of comp %d is not added (pending)", 884 675 j, i)); 885 676 continue; 886 677 } 887 678 679 /* Must have address */ 680 pj_assert(pj_sockaddr_has_addr(&cand->addr)); 681 682 /* Add the candidate */ 888 683 status = pj_ice_sess_add_cand(ice_st->ice, comp->comp_id, 889 cand->type, cand->local_pref, 684 cand->transport_id, cand->type, 685 cand->local_pref, 890 686 &cand->foundation, &cand->addr, 891 &c omp->local_addr, NULL,892 sizeof(pj_sockaddr_in),893 (unsigned*)& cand->ice_cand_id);687 &cand->base_addr, &cand->rel_addr, 688 pj_sockaddr_get_len(&cand->addr), 689 (unsigned*)&ice_cand_id); 894 690 if (status != PJ_SUCCESS) 895 691 goto on_error; … … 908 704 */ 909 705 PJ_DEF(pj_status_t) pj_ice_strans_enum_cands(pj_ice_strans *ice_st, 910 unsigned *count, 911 pj_ice_sess_cand cand[]) 706 unsigned comp_id, 707 unsigned *count, 708 pj_ice_sess_cand cand[]) 912 709 { 913 710 unsigned i, cnt; 914 pj_ice_sess_cand *pcand; 915 916 PJ_ASSERT_RETURN(ice_st && count && cand, PJ_EINVAL); 917 PJ_ASSERT_RETURN(ice_st->ice, PJ_EINVALIDOP); 918 919 cnt = ice_st->ice->lcand_cnt; 711 pj_ice_strans_comp *comp; 712 713 PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt && 714 count && cand, PJ_EINVAL); 715 716 comp = ice_st->comp[comp_id - 1]; 717 cnt = comp->cand_cnt; 920 718 cnt = (cnt > *count) ? *count : cnt; 921 *count = 0;922 719 923 720 for (i=0; i<cnt; ++i) { 924 pcand = &ice_st->ice->lcand[i]; 925 pj_memcpy(&cand[i], pcand, sizeof(pj_ice_sess_cand)); 721 pj_memcpy(&cand[i], &comp->cand_list[i], sizeof(pj_ice_sess_cand)); 926 722 } 927 723 928 724 *count = cnt; 929 725 return PJ_SUCCESS; 726 } 727 728 /* 729 * Get default candidate. 730 */ 731 PJ_DEF(pj_status_t) pj_ice_strans_get_def_cand( pj_ice_strans *ice_st, 732 unsigned comp_id, 733 pj_ice_sess_cand *cand) 734 { 735 const pj_ice_sess_check *valid_pair; 736 737 PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt && 738 cand, PJ_EINVAL); 739 740 valid_pair = pj_ice_strans_get_valid_pair(ice_st, comp_id); 741 if (valid_pair) { 742 pj_memcpy(cand, valid_pair->lcand, sizeof(pj_ice_sess_cand)); 743 } else { 744 pj_ice_strans_comp *comp = ice_st->comp[comp_id - 1]; 745 pj_assert(comp->default_cand>=0 && comp->default_cand<comp->cand_cnt); 746 pj_memcpy(cand, &comp->cand_list[comp->default_cand], 747 sizeof(pj_ice_sess_cand)); 748 } 749 return PJ_SUCCESS; 750 } 751 752 /* 753 * Get the current ICE role. 754 */ 755 PJ_DEF(pj_ice_sess_role) pj_ice_strans_get_role(pj_ice_strans *ice_st) 756 { 757 PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_ICE_SESS_ROLE_UNKNOWN); 758 return ice_st->ice->role; 759 } 760 761 /* 762 * Change session role. 763 */ 764 PJ_DEF(pj_status_t) pj_ice_strans_change_role( pj_ice_strans *ice_st, 765 pj_ice_sess_role new_role) 766 { 767 PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_EINVALIDOP); 768 return pj_ice_sess_change_role(ice_st->ice, new_role); 930 769 } 931 770 … … 941 780 pj_status_t status; 942 781 782 PJ_ASSERT_RETURN(ice_st && rem_ufrag && rem_passwd && 783 rem_cand_cnt && rem_cand, PJ_EINVAL); 784 785 /* Mark start time */ 786 pj_gettimeofday(&ice_st->start_time); 787 788 /* Build check list */ 943 789 status = pj_ice_sess_create_check_list(ice_st->ice, rem_ufrag, rem_passwd, 944 790 rem_cand_cnt, rem_cand); … … 946 792 return status; 947 793 794 /* Start ICE negotiation! */ 948 795 status = pj_ice_sess_start_check(ice_st->ice); 949 796 if (status != PJ_SUCCESS) { … … 955 802 956 803 /* 804 * Get valid pair. 805 */ 806 PJ_DEF(const pj_ice_sess_check*) 807 pj_ice_strans_get_valid_pair(const pj_ice_strans *ice_st, 808 unsigned comp_id) 809 { 810 PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt, 811 NULL); 812 813 if (ice_st->ice == NULL) 814 return NULL; 815 816 return ice_st->ice->comp[comp_id-1].valid_check; 817 } 818 819 /* 957 820 * Stop ICE! 958 821 */ 959 822 PJ_DEF(pj_status_t) pj_ice_strans_stop_ice(pj_ice_strans *ice_st) 960 823 { 961 unsigned i;962 963 824 if (ice_st->ice) { 964 825 pj_ice_sess_destroy(ice_st->ice); … … 966 827 } 967 828 968 /* Invalidate all candidate Ids */969 for (i=0; i<ice_st->comp_cnt; ++i) {970 unsigned j;971 for (j=0; j<ice_st->comp[i]->cand_cnt; ++j) {972 ice_st->comp[i]->cand_list[j].ice_cand_id = -1;973 }974 }975 976 829 return PJ_SUCCESS; 977 830 } 978 831 979 832 /* 980 * Send packet using non-ICE means (e.g. when ICE was not negotiated).833 * Application wants to send outgoing packet. 981 834 */ 982 835 PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st, … … 998 851 /* If ICE is available, send data with ICE */ 999 852 if (ice_st->ice) { 1000 return pj_ice_sess_send_data(ice_st->ice, comp_id, data, data_len); 1001 } 1002 1003 /* Otherwise send direcly with the socket. This is for compatibility 1004 * with remote that doesn't support ICE. 1005 */ 1006 pkt_size = data_len; 1007 status = pj_ioqueue_sendto(comp->key, &comp->write_op, 1008 data, &pkt_size, 0, 1009 dst_addr, dst_addr_len); 1010 1011 return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status; 853 if (comp->turn_sock) { 854 pj_turn_sock_lock(comp->turn_sock); 855 } 856 status = pj_ice_sess_send_data(ice_st->ice, comp_id, data, data_len); 857 if (comp->turn_sock) { 858 pj_turn_sock_unlock(comp->turn_sock); 859 } 860 return status; 861 862 } else if (comp->stun_sock) { 863 864 pkt_size = data_len; 865 status = pj_stun_sock_sendto(comp->stun_sock, NULL, data, data_len, 866 0, dst_addr, dst_addr_len); 867 return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status; 868 869 } else 870 return PJ_EINVALIDOP; 1012 871 } 1013 872 … … 1019 878 { 1020 879 pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data; 880 pj_time_val t; 881 unsigned msec; 882 883 sess_add_ref(ice_st); 884 885 pj_gettimeofday(&t); 886 PJ_TIME_VAL_SUB(t, ice_st->start_time); 887 msec = PJ_TIME_VAL_MSEC(t); 888 1021 889 if (ice_st->cb.on_ice_complete) { 1022 (*ice_st->cb.on_ice_complete)(ice_st, status); 1023 } 890 if (status != PJ_SUCCESS) { 891 char errmsg[PJ_ERR_MSG_SIZE]; 892 pj_strerror(status, errmsg, sizeof(errmsg)); 893 PJ_LOG(4,(ice_st->obj_name, 894 "ICE negotiation failed after %ds:%03d: %s", 895 msec/1000, msec%1000, errmsg)); 896 } else { 897 unsigned i; 898 enum { 899 msg_disable_ind = 0xFFFF & 900 ~(PJ_STUN_SESS_LOG_TX_IND| 901 PJ_STUN_SESS_LOG_RX_IND) 902 }; 903 904 PJ_LOG(4,(ice_st->obj_name, 905 "ICE negotiation success after %ds:%03d", 906 msec/1000, msec%1000)); 907 908 for (i=0; i<ice_st->comp_cnt; ++i) { 909 const pj_ice_sess_check *check; 910 911 check = pj_ice_strans_get_valid_pair(ice_st, i+1); 912 if (check) { 913 char lip[PJ_INET6_ADDRSTRLEN+10]; 914 char rip[PJ_INET6_ADDRSTRLEN+10]; 915 916 pj_sockaddr_print(&check->lcand->addr, lip, 917 sizeof(lip), 3); 918 pj_sockaddr_print(&check->rcand->addr, rip, 919 sizeof(rip), 3); 920 921 if (check->lcand->transport_id == TP_TURN) { 922 /* Disable logging for Send/Data indications */ 923 PJ_LOG(5,(ice_st->obj_name, 924 "Disabling STUN Indication logging for " 925 "component %d", i+1)); 926 pj_turn_sock_set_log(ice_st->comp[i]->turn_sock, 927 msg_disable_ind); 928 } 929 930 PJ_LOG(4,(ice_st->obj_name, " Comp %d: " 931 "sending from %s candidate %s to " 932 "%s candidate %s", 933 i+1, 934 pj_ice_get_cand_type_name(check->lcand->type), 935 lip, 936 pj_ice_get_cand_type_name(check->rcand->type), 937 rip)); 938 939 } else { 940 PJ_LOG(4,(ice_st->obj_name, 941 "Comp %d: disabled", i+1)); 942 } 943 } 944 } 945 946 (*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_NEGOTIATION, 947 status); 948 949 950 } 951 952 sess_dec_ref(ice_st); 1024 953 } 1025 954 … … 1029 958 static pj_status_t ice_tx_pkt(pj_ice_sess *ice, 1030 959 unsigned comp_id, 960 unsigned transport_id, 1031 961 const void *pkt, pj_size_t size, 1032 962 const pj_sockaddr_t *dst_addr, … … 1034 964 { 1035 965 pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data; 1036 pj_ice_strans_comp *comp = NULL; 1037 pj_ssize_t pkt_size; 966 pj_ice_strans_comp *comp; 1038 967 pj_status_t status; 1039 968 1040 PJ_TODO(TX_TO_RELAY);1041 1042 969 PJ_ASSERT_RETURN(comp_id && comp_id <= ice_st->comp_cnt, PJ_EINVAL); 970 1043 971 comp = ice_st->comp[comp_id-1]; 1044 972 1045 973 TRACE_PKT((comp->ice_st->obj_name, 1046 "Component %d TX packet to %s:%d ",1047 comp_id, 974 "Component %d TX packet to %s:%d with transport %d", 975 comp_id, 1048 976 pj_inet_ntoa(((pj_sockaddr_in*)dst_addr)->sin_addr), 1049 (int)pj_ntohs(((pj_sockaddr_in*)dst_addr)->sin_port))); 1050 1051 pkt_size = size; 1052 status = pj_ioqueue_sendto(comp->key, &comp->write_op, 1053 pkt, &pkt_size, 0, 1054 dst_addr, dst_addr_len); 977 (int)pj_ntohs(((pj_sockaddr_in*)dst_addr)->sin_port), 978 transport_id)); 979 980 if (transport_id == TP_TURN) { 981 if (comp->turn_sock) { 982 status = pj_turn_sock_sendto(comp->turn_sock, 983 (const pj_uint8_t*)pkt, size, 984 dst_addr, dst_addr_len); 985 } else { 986 status = PJ_EINVALIDOP; 987 } 988 } else if (transport_id == TP_STUN) { 989 status = pj_stun_sock_sendto(comp->stun_sock, NULL, 990 pkt, size, 0, 991 dst_addr, dst_addr_len); 992 } else { 993 pj_assert(!"Invalid transport ID"); 994 status = PJ_EINVALIDOP; 995 } 1055 996 1056 997 return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status; … … 1062 1003 static void ice_rx_data(pj_ice_sess *ice, 1063 1004 unsigned comp_id, 1005 unsigned transport_id, 1064 1006 void *pkt, pj_size_t size, 1065 1007 const pj_sockaddr_t *src_addr, … … 1068 1010 pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data; 1069 1011 1012 PJ_UNUSED_ARG(transport_id); 1013 1070 1014 if (ice_st->cb.on_rx_data) { 1071 1015 (*ice_st->cb.on_rx_data)(ice_st, comp_id, pkt, size, … … 1074 1018 } 1075 1019 1076 /* 1077 * Callback called by STUN session to send outgoing packet. 1078 */ 1079 static pj_status_t stun_on_send_msg(pj_stun_session *sess, 1080 void *token, 1081 const void *pkt, 1082 pj_size_t size, 1083 const pj_sockaddr_t *dst_addr, 1084 unsigned dst_addr_len) 1020 /* Notification when incoming packet has been received from 1021 * the STUN socket. 1022 */ 1023 static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock, 1024 void *pkt, 1025 unsigned pkt_len, 1026 const pj_sockaddr_t *src_addr, 1027 unsigned addr_len) 1085 1028 { 1086 1029 pj_ice_strans_comp *comp; 1087 pj_ ssize_t pkt_size;1030 pj_ice_strans *ice_st; 1088 1031 pj_status_t status; 1089 1032 1090 PJ_UNUSED_ARG(token); 1091 1092 comp = (pj_ice_strans_comp*) pj_stun_session_get_user_data(sess); 1093 pkt_size = size; 1094 status = pj_ioqueue_sendto(comp->key, &comp->write_op, 1095 pkt, &pkt_size, 0, 1096 dst_addr, dst_addr_len); 1097 1098 return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status; 1099 } 1100 1101 /* 1102 * Callback sent by STUN session when outgoing STUN request has 1103 * completed. 1104 */ 1105 static void stun_on_request_complete(pj_stun_session *sess, 1106 pj_status_t status, 1107 void *token, 1108 pj_stun_tx_data *tdata, 1109 const pj_stun_msg *response, 1110 const pj_sockaddr_t *src_addr, 1111 unsigned src_addr_len) 1033 comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock); 1034 ice_st = comp->ice_st; 1035 1036 sess_add_ref(ice_st); 1037 1038 if (ice_st->ice == NULL) { 1039 /* The ICE session is gone, but we're still receiving packets. 1040 * This could also happen if remote doesn't do ICE. So just 1041 * report this to application. 1042 */ 1043 if (ice_st->cb.on_rx_data) { 1044 (*ice_st->cb.on_rx_data)(ice_st, comp->comp_id, pkt, pkt_len, 1045 src_addr, addr_len); 1046 } 1047 1048 } else { 1049 1050 /* Hand over the packet to ICE session */ 1051 status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id, 1052 TP_STUN, pkt, pkt_len, 1053 src_addr, addr_len); 1054 1055 if (status != PJ_SUCCESS) { 1056 ice_st_perror(comp->ice_st, "Error processing packet", 1057 status); 1058 } 1059 } 1060 1061 return sess_dec_ref(ice_st); 1062 } 1063 1064 /* Notifification when asynchronous send operation to the STUN socket 1065 * has completed. 1066 */ 1067 static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock, 1068 pj_ioqueue_op_key_t *send_key, 1069 pj_ssize_t sent) 1070 { 1071 PJ_UNUSED_ARG(stun_sock); 1072 PJ_UNUSED_ARG(send_key); 1073 PJ_UNUSED_ARG(sent); 1074 return PJ_TRUE; 1075 } 1076 1077 /* Notification when the status of the STUN transport has changed. */ 1078 static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, 1079 pj_stun_sock_op op, 1080 pj_status_t status) 1112 1081 { 1113 1082 pj_ice_strans_comp *comp; 1114 pj_ice_strans_cand *cand = NULL; 1115 pj_stun_xor_mapped_addr_attr *xa; 1116 pj_stun_mapped_addr_attr *ma; 1117 pj_sockaddr *mapped_addr; 1118 char ip[20]; 1119 1120 comp = (pj_ice_strans_comp*) pj_stun_session_get_user_data(sess); 1121 cand = (pj_ice_strans_cand*) token; 1122 1123 PJ_UNUSED_ARG(token); 1124 PJ_UNUSED_ARG(tdata); 1125 PJ_UNUSED_ARG(src_addr); 1126 PJ_UNUSED_ARG(src_addr_len); 1127 1128 if (cand == NULL) { 1129 /* This is keep-alive */ 1083 pj_ice_strans *ice_st; 1084 pj_ice_sess_cand *cand = NULL; 1085 unsigned i; 1086 1087 comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock); 1088 ice_st = comp->ice_st; 1089 1090 sess_add_ref(ice_st); 1091 1092 /* Find the srflx cancidate */ 1093 for (i=0; i<comp->cand_cnt; ++i) { 1094 if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX) { 1095 cand = &comp->cand_list[i]; 1096 break; 1097 } 1098 } 1099 1100 pj_assert(status != PJ_EPENDING); 1101 1102 switch (op) { 1103 case PJ_STUN_SOCK_DNS_OP: 1130 1104 if (status != PJ_SUCCESS) { 1131 ice_st_perror(comp->ice_st, "STUN keep-alive request failed", 1105 /* May not have cand, e.g. when error during init */ 1106 if (cand) 1107 cand->status = status; 1108 sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT, "DNS resolution failed", 1109 status); 1110 } 1111 break; 1112 case PJ_STUN_SOCK_BINDING_OP: 1113 if (status == PJ_SUCCESS) { 1114 pj_stun_sock_info info; 1115 1116 status = pj_stun_sock_get_info(stun_sock, &info); 1117 if (status == PJ_SUCCESS) { 1118 char ipaddr[PJ_INET6_ADDRSTRLEN+10]; 1119 pj_bool_t dup = PJ_FALSE; 1120 1121 /* Eliminate the srflx candidate if the address is 1122 * equal to other (host) candidates. 1123 */ 1124 for (i=0; i<comp->cand_cnt; ++i) { 1125 if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_HOST && 1126 pj_sockaddr_cmp(&comp->cand_list[i].addr, 1127 &info.mapped_addr) == 0) 1128 { 1129 dup = PJ_TRUE; 1130 break; 1131 } 1132 } 1133 1134 if (dup) { 1135 /* Duplicate found, remove the srflx candidate */ 1136 pj_array_erase(comp->cand_list, sizeof(comp->cand_list[0]), 1137 comp->cand_cnt, cand - comp->cand_list); 1138 --comp->cand_cnt; 1139 } else { 1140 /* Otherwise update the address */ 1141 pj_sockaddr_cp(&cand->addr, &info.mapped_addr); 1142 cand->status = PJ_SUCCESS; 1143 } 1144 1145 PJ_LOG(4,(comp->ice_st->obj_name, 1146 "Comp %d: Binding discovery complete, " 1147 "srflx address is %s", 1148 comp->comp_id, 1149 pj_sockaddr_print(&info.mapped_addr, ipaddr, 1150 sizeof(ipaddr), 3))); 1151 1152 sess_init_update(ice_st); 1153 } 1154 } 1155 1156 if (status != PJ_SUCCESS) { 1157 /* May not have cand, e.g. when error during init */ 1158 if (cand) 1159 cand->status = status; 1160 sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT, 1161 "STUN binding request failed", status); 1162 } 1163 break; 1164 case PJ_STUN_SOCK_KEEP_ALIVE_OP: 1165 if (status != PJ_SUCCESS) { 1166 pj_assert(cand != NULL); 1167 cand->status = status; 1168 sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT, 1169 "STUN keep-alive failed", status); 1170 } 1171 break; 1172 } 1173 1174 return sess_dec_ref(ice_st); 1175 } 1176 1177 /* Callback when TURN socket has received a packet */ 1178 static void turn_on_rx_data(pj_turn_sock *turn_sock, 1179 void *pkt, 1180 unsigned pkt_len, 1181 const pj_sockaddr_t *peer_addr, 1182 unsigned addr_len) 1183 { 1184 pj_ice_strans_comp *comp; 1185 pj_status_t status; 1186 1187 comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock); 1188 if (comp == NULL) { 1189 /* We have disassociated ourselves from the TURN socket */ 1190 return; 1191 } 1192 1193 sess_add_ref(comp->ice_st); 1194 1195 if (comp->ice_st->ice == NULL) { 1196 /* The ICE session is gone, but we're still receiving packets. 1197 * This could also happen if remote doesn't do ICE and application 1198 * specifies TURN as the default address in SDP. 1199 * So in this case just give the packet to application. 1200 */ 1201 if (comp->ice_st->cb.on_rx_data) { 1202 (*comp->ice_st->cb.on_rx_data)(comp->ice_st, comp->comp_id, pkt, 1203 pkt_len, peer_addr, addr_len); 1204 } 1205 1206 } else { 1207 1208 /* Hand over the packet to ICE */ 1209 status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id, 1210 TP_TURN, pkt, pkt_len, 1211 peer_addr, addr_len); 1212 1213 if (status != PJ_SUCCESS) { 1214 ice_st_perror(comp->ice_st, 1215 "Error processing packet from TURN relay", 1132 1216 status); 1133 1217 } 1218 } 1219 1220 sess_dec_ref(comp->ice_st); 1221 } 1222 1223 1224 /* Callback when TURN client state has changed */ 1225 static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state, 1226 pj_turn_state_t new_state) 1227 { 1228 pj_ice_strans_comp *comp; 1229 1230 comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock); 1231 if (comp == NULL) { 1232 /* Not interested in further state notification once the relay is 1233 * disconnecting. 1234 */ 1134 1235 return; 1135 1236 } 1136 1237 1137 /* Decrement pending count for this component */ 1138 pj_assert(comp->pending_cnt > 0); 1139 comp->pending_cnt--; 1140 1141 if (status == PJNATH_ESTUNTIMEDOUT) { 1238 PJ_LOG(5,(comp->ice_st->obj_name, "TURN client state changed %s --> %s", 1239 pj_turn_state_name(old_state), pj_turn_state_name(new_state))); 1240 1241 sess_add_ref(comp->ice_st); 1242 1243 if (new_state == PJ_TURN_STATE_READY) { 1244 pj_turn_session_info rel_info; 1245 char ipaddr[PJ_INET6_ADDRSTRLEN+8]; 1246 pj_ice_sess_cand *cand = NULL; 1247 unsigned i; 1248 1249 /* Get allocation info */ 1250 pj_turn_sock_get_info(turn_sock, &rel_info); 1251 1252 /* Find relayed candidate in the component */ 1253 for (i=0; i<comp->cand_cnt; ++i) { 1254 if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED) { 1255 cand = &comp->cand_list[i]; 1256 break; 1257 } 1258 } 1259 pj_assert(cand != NULL); 1260 1261 /* Update candidate */ 1262 pj_sockaddr_cp(&cand->addr, &rel_info.relay_addr); 1263 pj_sockaddr_cp(&cand->base_addr, &rel_info.relay_addr); 1264 pj_sockaddr_cp(&cand->rel_addr, &rel_info.mapped_addr); 1265 pj_ice_calc_foundation(comp->ice_st->pool, &cand->foundation, 1266 PJ_ICE_CAND_TYPE_RELAYED, 1267 &rel_info.relay_addr); 1268 cand->status = PJ_SUCCESS; 1142 1269 1143 1270 PJ_LOG(4,(comp->ice_st->obj_name, 1144 "STUN Binding request has timed-out, will retry " 1145 "again alter")); 1146 1147 /* Restart keep-alive timer */ 1148 start_ka_timer(comp->ice_st); 1149 return; 1150 1151 } else if (status != PJ_SUCCESS) { 1152 comp->last_status = cand->status = status; 1153 ice_st_perror(comp->ice_st, "STUN Binding request failed", 1154 cand->status); 1155 return; 1156 } 1157 1158 xa = (pj_stun_xor_mapped_addr_attr*) 1159 pj_stun_msg_find_attr(response, PJ_STUN_ATTR_XOR_MAPPED_ADDR, 0); 1160 ma = (pj_stun_mapped_addr_attr*) 1161 pj_stun_msg_find_attr(response, PJ_STUN_ATTR_MAPPED_ADDR, 0); 1162 1163 if (xa) 1164 mapped_addr = &xa->sockaddr; 1165 else if (ma) 1166 mapped_addr = &ma->sockaddr; 1167 else { 1168 cand->status = PJNATH_ESTUNNOMAPPEDADDR; 1169 ice_st_perror(comp->ice_st, "STUN Binding request failed", 1170 cand->status); 1171 return; 1172 } 1173 1174 /* Save IP address for logging */ 1175 pj_ansi_strcpy(ip, pj_inet_ntoa(comp->local_addr.ipv4.sin_addr)); 1176 1177 /* Ignore response if it reports the same address */ 1178 if (comp->local_addr.ipv4.sin_addr.s_addr == mapped_addr->ipv4.sin_addr.s_addr && 1179 comp->local_addr.ipv4.sin_port == mapped_addr->ipv4.sin_port) 1180 { 1181 PJ_LOG(4,(comp->ice_st->obj_name, 1182 "Candidate %s:%d is directly connected to Internet, " 1183 "STUN mapped address is ignored", 1184 ip, pj_ntohs(comp->local_addr.ipv4.sin_port))); 1185 return; 1186 } 1187 1188 PJ_LOG(5,(comp->ice_st->obj_name, 1189 "STUN mapped address for %s:%d is %s:%d", 1190 ip, (int)pj_ntohs(comp->local_addr.ipv4.sin_port), 1191 pj_inet_ntoa(mapped_addr->ipv4.sin_addr), 1192 (int)pj_ntohs(mapped_addr->ipv4.sin_port))); 1193 pj_memcpy(&cand->addr, mapped_addr, sizeof(pj_sockaddr_in)); 1194 cand->status = PJ_SUCCESS; 1195 1196 /* Set this candidate as the default candidate */ 1197 comp->default_cand = (cand - comp->cand_list); 1198 comp->last_status = PJ_SUCCESS; 1199 1200 /* We have STUN, so we must start the keep-alive timer */ 1201 start_ka_timer(comp->ice_st); 1202 1203 /* Notify app that STUN address has changed. */ 1204 if (comp->ice_st->cb.on_addr_change) 1205 (*comp->ice_st->cb.on_addr_change)(comp->ice_st, comp->comp_id, 1206 (cand - comp->cand_list)); 1207 } 1208 1271 "Comp %d: TURN allocation complete, relay address is %s", 1272 comp->comp_id, 1273 pj_sockaddr_print(&rel_info.relay_addr, ipaddr, 1274 sizeof(ipaddr), 3))); 1275 1276 sess_init_update(comp->ice_st); 1277 1278 } else if (new_state >= PJ_TURN_STATE_DEALLOCATING) { 1279 pj_turn_session_info info; 1280 1281 pj_turn_sock_get_info(turn_sock, &info); 1282 1283 /* Unregister ourself from the TURN relay */ 1284 pj_turn_sock_set_user_data(turn_sock, NULL); 1285 comp->turn_sock = NULL; 1286 1287 /* Set session to fail if we're still initializing */ 1288 if (old_state < PJ_TURN_STATE_READY) { 1289 sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT, 1290 "TURN relay failed", info.last_status); 1291 } 1292 } 1293 1294 sess_dec_ref(comp->ice_st); 1295 } 1296
Note: See TracChangeset
for help on using the changeset viewer.