Changeset 1988 for pjproject/trunk/pjnath/src/pjnath-test/ice_test.c
- Timestamp:
- Jun 6, 2008 2:47:10 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjnath/src/pjnath-test/ice_test.c
r1288 r1988 18 18 */ 19 19 #include "test.h" 20 21 #define THIS_FILE "ice_test.c" 22 23 24 struct ice_data 25 { 26 const char *obj_name; 27 pj_bool_t complete; 28 pj_status_t err_code; 29 unsigned rx_rtp_cnt; 30 unsigned rx_rtcp_cnt; 31 32 unsigned rx_rtp_count; 33 char last_rx_rtp_data[32]; 34 unsigned rx_rtcp_count; 35 char last_rx_rtcp_data[32]; 20 #include "server.h" 21 22 enum 23 { 24 NO = 0, 25 YES = 1, 26 SRV = 3, 36 27 }; 37 28 38 static pj_stun_config stun_cfg; 39 40 static void on_ice_complete(pj_ice_strans *icest, 41 pj_status_t status) 42 { 43 struct ice_data *id = (struct ice_data*) icest->user_data; 44 id->complete = PJ_TRUE; 45 id->err_code = status; 46 PJ_LOG(3,(THIS_FILE, " ICE %s complete %s", id->obj_name, 47 (status==PJ_SUCCESS ? "successfully" : "with failure"))); 29 #define NODELAY 0xFFFFFFFF 30 #define SRV_DOMAIN "pjsip.lab.domain" 31 32 #define INDENT " " 33 34 /* Client flags */ 35 enum 36 { 37 WRONG_TURN = 1, 38 DEL_ON_ERR = 2, 39 }; 40 41 42 /* Test results */ 43 struct test_result 44 { 45 pj_status_t init_status; /* init successful? */ 46 pj_status_t nego_status; /* negotiation successful? */ 47 unsigned rx_cnt[4]; /* Number of data received */ 48 }; 49 50 51 /* Test session configuration */ 52 struct test_cfg 53 { 54 pj_ice_sess_role role; /* Role. */ 55 unsigned comp_cnt; /* Component count */ 56 unsigned enable_host; /* Enable host candidates */ 57 unsigned enable_stun; /* Enable srflx candidates */ 58 unsigned enable_turn; /* Enable turn candidates */ 59 unsigned client_flag; /* Client flags */ 60 61 unsigned answer_delay; /* Delay before sending SDP */ 62 unsigned send_delay; /* Delay before sending data */ 63 unsigned destroy_delay; /* Delay before destroy() */ 64 65 struct test_result expected;/* Expected result */ 66 }; 67 68 /* ICE endpoint state */ 69 struct ice_ept 70 { 71 struct test_cfg cfg; /* Configuratino. */ 72 pj_ice_strans *ice; /* ICE stream transport */ 73 struct test_result result;/* Test result. */ 74 75 pj_str_t ufrag; /* username fragment. */ 76 pj_str_t pass; /* password */ 77 }; 78 79 /* The test session */ 80 struct test_sess 81 { 82 pj_pool_t *pool; 83 pj_stun_config *stun_cfg; 84 pj_dns_resolver *resolver; 85 86 test_server *server; 87 88 unsigned server_flag; 89 struct ice_ept caller; 90 struct ice_ept callee; 91 }; 92 93 94 static void ice_on_rx_data(pj_ice_strans *ice_st, 95 unsigned comp_id, 96 void *pkt, pj_size_t size, 97 const pj_sockaddr_t *src_addr, 98 unsigned src_addr_len); 99 static void ice_on_ice_complete(pj_ice_strans *ice_st, 100 pj_ice_strans_op op, 101 pj_status_t status); 102 static void destroy_sess(struct test_sess *sess, unsigned wait_msec); 103 104 /* Create ICE stream transport */ 105 static int create_ice_strans(struct test_sess *test_sess, 106 struct ice_ept *ept, 107 pj_ice_strans **p_ice) 108 { 109 pj_ice_strans *ice; 110 pj_ice_strans_cb ice_cb; 111 pj_ice_strans_cfg ice_cfg; 112 pj_sockaddr hostip; 113 char serverip[PJ_INET6_ADDRSTRLEN]; 114 pj_status_t status; 115 116 status = pj_gethostip(pj_AF_INET(), &hostip); 117 if (status != PJ_SUCCESS) 118 return -1030; 119 120 pj_sockaddr_print(&hostip, serverip, sizeof(serverip), 0); 121 122 /* Init callback structure */ 123 pj_bzero(&ice_cb, sizeof(ice_cb)); 124 ice_cb.on_rx_data = &ice_on_rx_data; 125 ice_cb.on_ice_complete = &ice_on_ice_complete; 126 127 /* Init ICE stream transport configuration structure */ 128 pj_ice_strans_cfg_default(&ice_cfg); 129 pj_memcpy(&ice_cfg.stun_cfg, test_sess->stun_cfg, sizeof(pj_stun_config)); 130 if ((ept->cfg.enable_stun & SRV)==SRV || (ept->cfg.enable_turn & SRV)==SRV) 131 ice_cfg.resolver = test_sess->resolver; 132 133 if (ept->cfg.enable_stun & YES) { 134 if ((ept->cfg.enable_stun & SRV) == SRV) { 135 ice_cfg.stun.server = pj_str(SRV_DOMAIN); 136 } else { 137 ice_cfg.stun.server = pj_str(serverip); 138 } 139 ice_cfg.stun.port = STUN_SERVER_PORT; 140 } 141 142 if (ept->cfg.enable_host == 0) { 143 ice_cfg.stun.no_host_cands = PJ_TRUE; 144 } else { 145 ice_cfg.stun.no_host_cands = PJ_FALSE; 146 ice_cfg.stun.loop_addr = PJ_TRUE; 147 } 148 149 150 if (ept->cfg.enable_turn & YES) { 151 if ((ept->cfg.enable_turn & SRV) == SRV) { 152 ice_cfg.turn.server = pj_str(SRV_DOMAIN); 153 } else { 154 ice_cfg.turn.server = pj_str(serverip); 155 } 156 ice_cfg.turn.port = TURN_SERVER_PORT; 157 ice_cfg.turn.conn_type = PJ_TURN_TP_UDP; 158 ice_cfg.turn.auth_cred.type = PJ_STUN_AUTH_CRED_STATIC; 159 ice_cfg.turn.auth_cred.data.static_cred.realm = pj_str(SRV_DOMAIN); 160 if (ept->cfg.client_flag & WRONG_TURN) 161 ice_cfg.turn.auth_cred.data.static_cred.username = pj_str("xxx"); 162 else 163 ice_cfg.turn.auth_cred.data.static_cred.username = pj_str(TURN_USERNAME); 164 ice_cfg.turn.auth_cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN; 165 ice_cfg.turn.auth_cred.data.static_cred.data = pj_str(TURN_PASSWD); 166 } 167 168 /* Create ICE stream transport */ 169 status = pj_ice_strans_create(NULL, &ice_cfg, ept->cfg.comp_cnt, 170 (void*)ept, &ice_cb, 171 &ice); 172 if (status != PJ_SUCCESS) { 173 app_perror(INDENT "err: pj_ice_strans_create()", status); 174 return status; 175 } 176 177 pj_create_unique_string(test_sess->pool, &ept->ufrag); 178 pj_create_unique_string(test_sess->pool, &ept->pass); 179 180 /* Looks alright */ 181 *p_ice = ice; 182 return PJ_SUCCESS; 48 183 } 49 50 51 static void on_rx_data(pj_ice_strans *icest, unsigned comp_id, 52 void *pkt, pj_size_t size, 53 const pj_sockaddr_t *src_addr, 54 unsigned src_addr_len) 55 { 56 struct ice_data *id = (struct ice_data*) icest->user_data; 57 58 if (comp_id == 1) { 59 id->rx_rtp_cnt++; 60 pj_memcpy(id->last_rx_rtp_data, pkt, size); 61 id->last_rx_rtp_data[size] = '\0'; 62 } else if (comp_id == 2) { 63 id->rx_rtcp_cnt++; 64 pj_memcpy(id->last_rx_rtcp_data, pkt, size); 65 id->last_rx_rtcp_data[size] = '\0'; 66 } else { 67 pj_assert(!"Invalid component ID"); 68 } 69 184 185 /* Create test session */ 186 static int create_sess(pj_stun_config *stun_cfg, 187 unsigned server_flag, 188 struct test_cfg *caller_cfg, 189 struct test_cfg *callee_cfg, 190 struct test_sess **p_sess) 191 { 192 pj_pool_t *pool; 193 struct test_sess *sess; 194 pj_str_t ns_ip; 195 pj_uint16_t ns_port; 196 unsigned flags; 197 pj_status_t status; 198 199 /* Create session structure */ 200 pool = pj_pool_create(mem, "testsess", 512, 512, NULL); 201 sess = PJ_POOL_ZALLOC_T(pool, struct test_sess); 202 sess->pool = pool; 203 sess->stun_cfg = stun_cfg; 204 205 pj_memcpy(&sess->caller.cfg, caller_cfg, sizeof(*caller_cfg)); 206 sess->caller.result.init_status = sess->caller.result.nego_status = PJ_EPENDING; 207 208 pj_memcpy(&sess->callee.cfg, callee_cfg, sizeof(*callee_cfg)); 209 sess->callee.result.init_status = sess->callee.result.nego_status = PJ_EPENDING; 210 211 /* Create server */ 212 flags = server_flag; 213 status = create_test_server(stun_cfg, flags, SRV_DOMAIN, &sess->server); 214 if (status != PJ_SUCCESS) { 215 app_perror(INDENT "error: create_test_server()", status); 216 destroy_sess(sess, 500); 217 return -10; 218 } 219 sess->server->turn_respond_allocate = 220 sess->server->turn_respond_refresh = PJ_TRUE; 221 222 /* Create resolver */ 223 status = pj_dns_resolver_create(mem, NULL, 0, stun_cfg->timer_heap, 224 stun_cfg->ioqueue, &sess->resolver); 225 if (status != PJ_SUCCESS) { 226 app_perror(INDENT "error: pj_dns_resolver_create()", status); 227 destroy_sess(sess, 500); 228 return -20; 229 } 230 231 ns_ip = pj_str("127.0.0.1"); 232 ns_port = (pj_uint16_t)DNS_SERVER_PORT; 233 status = pj_dns_resolver_set_ns(sess->resolver, 1, &ns_ip, &ns_port); 234 if (status != PJ_SUCCESS) { 235 app_perror( INDENT "error: pj_dns_resolver_set_ns()", status); 236 destroy_sess(sess, 500); 237 return -21; 238 } 239 240 /* Create caller ICE stream transport */ 241 status = create_ice_strans(sess, &sess->caller, &sess->caller.ice); 242 if (status != PJ_SUCCESS) { 243 destroy_sess(sess, 500); 244 return -30; 245 } 246 247 /* Create callee ICE stream transport */ 248 status = create_ice_strans(sess, &sess->callee, &sess->callee.ice); 249 if (status != PJ_SUCCESS) { 250 destroy_sess(sess, 500); 251 return -40; 252 } 253 254 *p_sess = sess; 255 return 0; 256 } 257 258 /* Destroy test session */ 259 static void destroy_sess(struct test_sess *sess, unsigned wait_msec) 260 { 261 if (sess->caller.ice) { 262 pj_ice_strans_destroy(sess->caller.ice); 263 sess->caller.ice = NULL; 264 } 265 266 if (sess->callee.ice) { 267 pj_ice_strans_destroy(sess->callee.ice); 268 sess->callee.ice = NULL; 269 } 270 271 poll_events(sess->stun_cfg, wait_msec, PJ_FALSE); 272 273 if (sess->resolver) { 274 pj_dns_resolver_destroy(sess->resolver, PJ_FALSE); 275 sess->resolver = NULL; 276 } 277 278 if (sess->server) { 279 destroy_test_server(sess->server); 280 sess->server = NULL; 281 } 282 283 if (sess->pool) { 284 pj_pool_t *pool = sess->pool; 285 sess->pool = NULL; 286 pj_pool_release(pool); 287 } 288 } 289 290 static void ice_on_rx_data(pj_ice_strans *ice_st, 291 unsigned comp_id, 292 void *pkt, pj_size_t size, 293 const pj_sockaddr_t *src_addr, 294 unsigned src_addr_len) 295 { 296 struct ice_ept *ept; 297 298 PJ_UNUSED_ARG(pkt); 299 PJ_UNUSED_ARG(size); 70 300 PJ_UNUSED_ARG(src_addr); 71 301 PJ_UNUSED_ARG(src_addr_len); 302 303 ept = (struct ice_ept*) pj_ice_strans_get_user_data(ice_st); 304 ept->result.rx_cnt[comp_id]++; 72 305 } 73 306 74 307 75 static void handle_events(unsigned msec_timeout) 76 { 77 pj_time_val delay; 78 79 pj_timer_heap_poll(stun_cfg.timer_heap, NULL); 80 81 delay.sec = 0; 82 delay.msec = msec_timeout; 83 pj_time_val_normalize(&delay); 84 85 pj_ioqueue_poll(stun_cfg.ioqueue, &delay); 308 static void ice_on_ice_complete(pj_ice_strans *ice_st, 309 pj_ice_strans_op op, 310 pj_status_t status) 311 { 312 struct ice_ept *ept; 313 314 ept = (struct ice_ept*) pj_ice_strans_get_user_data(ice_st); 315 switch (op) { 316 case PJ_ICE_STRANS_OP_INIT: 317 ept->result.init_status = status; 318 if (status != PJ_SUCCESS && (ept->cfg.client_flag & DEL_ON_ERR)) { 319 pj_ice_strans_destroy(ice_st); 320 ept->ice = NULL; 321 } 322 break; 323 case PJ_ICE_STRANS_OP_NEGOTIATION: 324 ept->result.nego_status = status; 325 break; 326 default: 327 pj_assert(!"Unknown op"); 328 } 86 329 } 87 330 88 331 89 /* Basic create and destroy test */ 90 static int ice_basic_create_destroy_test() 91 { 92 pj_ice_strans *im; 93 pj_ice_strans_cb icest_cb; 332 /* Start ICE negotiation on the endpoint, based on parameter from 333 * the other endpoint. 334 */ 335 static pj_status_t start_ice(struct ice_ept *ept, const struct ice_ept *remote) 336 { 337 pj_ice_sess_cand rcand[32]; 338 unsigned i, rcand_cnt = 0; 94 339 pj_status_t status; 95 340 96 PJ_LOG(3,(THIS_FILE, "...basic create/destroy")); 97 98 pj_bzero(&icest_cb, sizeof(icest_cb)); 99 icest_cb.on_ice_complete = &on_ice_complete; 100 icest_cb.on_rx_data = &on_rx_data; 101 102 status = pj_ice_strans_create(&stun_cfg, "icetest", 2, NULL, &icest_cb, &im); 103 if (status != PJ_SUCCESS) 104 return -10; 105 106 pj_ice_strans_destroy(im); 341 /* Enum remote candidates */ 342 for (i=0; i<remote->cfg.comp_cnt; ++i) { 343 unsigned cnt = PJ_ARRAY_SIZE(rcand) - rcand_cnt; 344 status = pj_ice_strans_enum_cands(remote->ice, i+1, &cnt, rcand+rcand_cnt); 345 if (status != PJ_SUCCESS) { 346 app_perror(INDENT "err: pj_ice_strans_enum_cands()", status); 347 return status; 348 } 349 rcand_cnt += cnt; 350 } 351 352 status = pj_ice_strans_start_ice(ept->ice, &remote->ufrag, &remote->pass, 353 rcand_cnt, rcand); 354 if (status != PJ_SUCCESS) { 355 app_perror(INDENT "err: pj_ice_strans_start_ice()", status); 356 return status; 357 } 358 359 return PJ_SUCCESS; 360 } 361 362 363 /* Check that the pair in both agents are matched */ 364 static int check_pair(const struct ice_ept *ept1, const struct ice_ept *ept2, 365 int start_err) 366 { 367 unsigned i, min_cnt, max_cnt; 368 369 if (ept1->cfg.comp_cnt < ept2->cfg.comp_cnt) { 370 min_cnt = ept1->cfg.comp_cnt; 371 max_cnt = ept2->cfg.comp_cnt; 372 } else { 373 min_cnt = ept2->cfg.comp_cnt; 374 max_cnt = ept1->cfg.comp_cnt; 375 } 376 377 /* Must have valid pair for common components */ 378 for (i=0; i<min_cnt; ++i) { 379 const pj_ice_sess_check *c1; 380 const pj_ice_sess_check *c2; 381 382 c1 = pj_ice_strans_get_valid_pair(ept1->ice, i+1); 383 if (c1 == NULL) { 384 PJ_LOG(3,("", INDENT "err: unable to get valid pair for ice1 " 385 "component %d", i+1)); 386 return start_err - 2; 387 } 388 389 c2 = pj_ice_strans_get_valid_pair(ept2->ice, i+1); 390 if (c2 == NULL) { 391 PJ_LOG(3,("", INDENT "err: unable to get valid pair for ice2 " 392 "component %d", i+1)); 393 return start_err - 4; 394 } 395 396 if (pj_sockaddr_cmp(&c1->rcand->addr, &c2->lcand->addr) != 0) { 397 PJ_LOG(3,("", INDENT "err: candidate pair does not match " 398 "for component %d", i+1)); 399 return start_err - 6; 400 } 401 } 402 403 /* Extra components must not have valid pair */ 404 for (; i<max_cnt; ++i) { 405 if (ept1->cfg.comp_cnt>i && 406 pj_ice_strans_get_valid_pair(ept1->ice, i+1) != NULL) 407 { 408 PJ_LOG(3,("", INDENT "err: ice1 shouldn't have valid pair " 409 "for component %d", i+1)); 410 return start_err - 8; 411 } 412 if (ept2->cfg.comp_cnt>i && 413 pj_ice_strans_get_valid_pair(ept2->ice, i+1) != NULL) 414 { 415 PJ_LOG(3,("", INDENT "err: ice2 shouldn't have valid pair " 416 "for component %d", i+1)); 417 return start_err - 9; 418 } 419 } 107 420 108 421 return 0; … … 110 423 111 424 112 static pj_status_t start_ice(pj_ice_strans *ist, pj_ice_strans *remote) 113 { 114 unsigned count; 115 pj_ice_sess_cand cand[PJ_ICE_MAX_CAND]; 116 pj_status_t status; 117 118 count = PJ_ARRAY_SIZE(cand); 119 status = pj_ice_strans_enum_cands(remote, &count, cand); 120 if (status != PJ_SUCCESS) 121 return status; 122 123 return pj_ice_strans_start_ice(ist, &remote->ice->rx_ufrag, &remote->ice->rx_pass, 124 count, cand); 125 } 126 127 128 struct dummy_cand 129 { 130 unsigned comp_id; 131 pj_ice_cand_type type; 132 const char *addr; 133 unsigned port; 134 }; 135 136 static int init_ice_st(pj_ice_strans *ice_st, 137 pj_bool_t add_valid_comp, 138 unsigned dummy_cnt, 139 struct dummy_cand cand[]) 140 { 141 pj_str_t a; 142 pj_status_t status; 143 unsigned i; 144 145 /* Create components */ 146 for (i=0; i<ice_st->comp_cnt; ++i) { 147 status = pj_ice_strans_create_comp(ice_st, i+1, PJ_ICE_ST_OPT_DONT_ADD_CAND, NULL); 148 if (status != PJ_SUCCESS) 149 return -21; 150 } 151 152 /* Add dummy candidates */ 153 for (i=0; i<dummy_cnt; ++i) { 154 pj_sockaddr_in addr; 155 156 pj_sockaddr_in_init(&addr, pj_cstr(&a, cand[i].addr), (pj_uint16_t)cand[i].port); 157 status = pj_ice_strans_add_cand(ice_st, cand[i].comp_id, cand[i].type, 158 65535, &addr, PJ_FALSE); 159 if (status != PJ_SUCCESS) 160 return -22; 161 } 162 163 /* Add the real candidate */ 164 if (add_valid_comp) { 165 for (i=0; i<ice_st->comp_cnt; ++i) { 166 status = pj_ice_strans_add_cand(ice_st, i+1, PJ_ICE_CAND_TYPE_HOST, 65535, 167 &ice_st->comp[i]->local_addr.ipv4, PJ_TRUE); 168 if (status != PJ_SUCCESS) 169 return -23; 170 } 425 #define WAIT_UNTIL(timeout,expr, RC) { \ 426 pj_time_val t0, t; \ 427 pj_gettimeofday(&t0); \ 428 RC = -1; \ 429 for (;;) { \ 430 poll_events(stun_cfg, 10, PJ_FALSE); \ 431 pj_gettimeofday(&t); \ 432 if (expr) { \ 433 rc = PJ_SUCCESS; \ 434 break; \ 435 } \ 436 if (t.sec - t0.sec > (timeout)) break; \ 437 } \ 438 } 439 440 441 static int perform_test(const char *title, 442 pj_stun_config *stun_cfg, 443 unsigned server_flag, 444 struct test_cfg *caller_cfg, 445 struct test_cfg *callee_cfg) 446 { 447 pjlib_state pjlib_state; 448 struct test_sess *sess; 449 int rc; 450 451 PJ_LOG(3,("", INDENT "%s", title)); 452 453 capture_pjlib_state(stun_cfg, &pjlib_state); 454 455 rc = create_sess(stun_cfg, server_flag, caller_cfg, callee_cfg, &sess); 456 if (rc != 0) 457 return rc; 458 459 #define ALL_READY (sess->caller.result.init_status!=PJ_EPENDING && \ 460 sess->callee.result.init_status!=PJ_EPENDING) 461 462 /* Wait until both ICE transports are initialized */ 463 WAIT_UNTIL(30, ALL_READY, rc); 464 465 if (!ALL_READY) { 466 PJ_LOG(3,("", INDENT "err: init timed-out")); 467 destroy_sess(sess, 500); 468 return -100; 469 } 470 471 if (sess->caller.result.init_status != sess->caller.cfg.expected.init_status) { 472 app_perror(INDENT "err: caller init", sess->caller.result.init_status); 473 destroy_sess(sess, 500); 474 return -102; 475 } 476 if (sess->callee.result.init_status != sess->callee.cfg.expected.init_status) { 477 app_perror(INDENT "err: callee init", sess->callee.result.init_status); 478 destroy_sess(sess, 500); 479 return -104; 480 } 481 482 /* Failure condition */ 483 if (sess->caller.result.init_status != PJ_SUCCESS || 484 sess->callee.result.init_status != PJ_SUCCESS) 485 { 486 rc = 0; 487 goto on_return; 488 } 489 490 /* Init ICE on caller */ 491 rc = pj_ice_strans_init_ice(sess->caller.ice, sess->caller.cfg.role, 492 &sess->caller.ufrag, &sess->caller.pass); 493 if (rc != PJ_SUCCESS) { 494 app_perror(INDENT "err: caller pj_ice_strans_init_ice()", rc); 495 destroy_sess(sess, 500); 496 return -100; 497 } 498 499 /* Init ICE on callee */ 500 rc = pj_ice_strans_init_ice(sess->callee.ice, sess->callee.cfg.role, 501 &sess->callee.ufrag, &sess->callee.pass); 502 if (rc != PJ_SUCCESS) { 503 app_perror(INDENT "err: callee pj_ice_strans_init_ice()", rc); 504 destroy_sess(sess, 500); 505 return -110; 506 } 507 508 /* Start ICE on callee */ 509 rc = start_ice(&sess->callee, &sess->caller); 510 if (rc != PJ_SUCCESS) { 511 destroy_sess(sess, 500); 512 return -120; 513 } 514 515 /* Wait for callee's answer_delay */ 516 poll_events(stun_cfg, sess->callee.cfg.answer_delay, PJ_FALSE); 517 518 /* Start ICE on caller */ 519 rc = start_ice(&sess->caller, &sess->callee); 520 if (rc != PJ_SUCCESS) { 521 destroy_sess(sess, 500); 522 return -130; 523 } 524 525 /* Wait until negotiation is complete on both endpoints */ 526 #define ALL_DONE (sess->caller.result.nego_status!=PJ_EPENDING && \ 527 sess->callee.result.nego_status!=PJ_EPENDING) 528 WAIT_UNTIL(30, ALL_DONE, rc); 529 530 if (!ALL_DONE) { 531 PJ_LOG(3,("", INDENT "err: negotiation timed-out")); 532 destroy_sess(sess, 500); 533 return -140; 534 } 535 536 if (sess->caller.result.nego_status != sess->caller.cfg.expected.nego_status) { 537 app_perror(INDENT "err: caller negotiation failed", sess->caller.result.nego_status); 538 destroy_sess(sess, 500); 539 return -150; 540 } 541 542 if (sess->callee.result.nego_status != sess->callee.cfg.expected.nego_status) { 543 app_perror(INDENT "err: callee negotiation failed", sess->callee.result.nego_status); 544 destroy_sess(sess, 500); 545 return -160; 546 } 547 548 /* Verify that both agents have agreed on the same pair */ 549 rc = check_pair(&sess->caller, &sess->callee, -170); 550 if (rc != 0) { 551 destroy_sess(sess, 500); 552 return rc; 553 } 554 rc = check_pair(&sess->callee, &sess->caller, -180); 555 if (rc != 0) { 556 destroy_sess(sess, 500); 557 return rc; 558 } 559 560 /* Looks like everything is okay */ 561 562 /* Destroy ICE stream transports first to let it de-allocate 563 * TURN relay (otherwise there'll be timer/memory leak, unless 564 * we wait for long time in the last poll_events() below). 565 */ 566 if (sess->caller.ice) { 567 pj_ice_strans_destroy(sess->caller.ice); 568 sess->caller.ice = NULL; 569 } 570 571 if (sess->callee.ice) { 572 pj_ice_strans_destroy(sess->callee.ice); 573 sess->callee.ice = NULL; 574 } 575 576 on_return: 577 /* Wait.. */ 578 poll_events(stun_cfg, 500, PJ_FALSE); 579 580 /* Now destroy everything */ 581 destroy_sess(sess, 500); 582 583 /* Flush events */ 584 poll_events(stun_cfg, 100, PJ_FALSE); 585 586 rc = check_pjlib_state(stun_cfg, &pjlib_state); 587 if (rc != 0) { 588 return rc; 171 589 } 172 590 … … 174 592 } 175 593 176 177 /* When ICE completes, both agents should agree on the same candidate pair. 178 * Check that the remote address selected by agent1 is equal to the 179 * local address of selected by agent 2. 180 */ 181 static int verify_address(pj_ice_strans *agent1, pj_ice_strans *agent2, 182 unsigned comp_id) 183 { 184 pj_ice_sess_cand *rcand, *lcand; 185 int lcand_id; 186 187 if (agent1->ice->comp[comp_id-1].valid_check == NULL) { 188 PJ_LOG(3,(THIS_FILE, "....error: valid_check not set for comp_id %d", comp_id)); 189 return -60; 190 } 191 192 /* Get default remote candidate of agent 1 */ 193 rcand = agent1->ice->comp[comp_id-1].valid_check->rcand; 194 195 /* Get default local candidate of agent 2 */ 196 pj_ice_sess_find_default_cand(agent2->ice, comp_id, &lcand_id); 197 if (lcand_id < 0) 198 return -62; 199 200 lcand = &agent2->ice->lcand[lcand_id]; 201 202 if (pj_memcmp(&rcand->addr, &lcand->addr, sizeof(pj_sockaddr_in))!=0) { 203 PJ_LOG(3,(THIS_FILE, "....error: the selected addresses are incorrect for comp_id %d", comp_id)); 204 return -64; 205 } 206 207 return 0; 208 } 209 210 211 /* Perform ICE test with the following parameters: 212 * 213 * - title: The title of the test 214 * - ocand_cnt, 215 * ocand Additional candidates to be added to offerer 216 * - acand_cnt, 217 * acand Additional candidates to be added to answerer 218 * 219 * The additional candidates are normally invalid candidates, meaning 220 * they won't be reachable by the agents. They are used to "confuse" 221 * ICE processing. 222 */ 223 static int perform_ice_test(const char *title, 224 pj_bool_t expected_success, 225 unsigned comp_cnt, 226 pj_bool_t add_valid_comp, 227 unsigned wait_before_send, 228 unsigned max_total_time, 229 unsigned ocand_cnt, 230 struct dummy_cand ocand[], 231 unsigned acand_cnt, 232 struct dummy_cand acand[]) 233 { 234 pj_ice_strans *im1, *im2; 235 pj_ice_strans_cb icest_cb; 236 struct ice_data *id1, *id2; 237 pj_timestamp t_start, t_end; 594 #define ROLE1 PJ_ICE_SESS_ROLE_CONTROLLED 595 #define ROLE2 PJ_ICE_SESS_ROLE_CONTROLLING 596 597 int ice_test(void) 598 { 599 pj_pool_t *pool; 600 pj_stun_config stun_cfg; 238 601 unsigned i; 239 pj_str_t data_from_offerer, data_from_answerer; 240 pj_status_t status; 241 242 #define CHECK_COMPLETE() if (id1->complete && id2->complete) { \ 243 if (t_end.u32.lo==0) pj_get_timestamp(&t_end); \ 244 } else {} 245 246 PJ_LOG(3,(THIS_FILE, "...%s", title)); 247 248 pj_bzero(&t_end, sizeof(t_end)); 249 250 pj_bzero(&icest_cb, sizeof(icest_cb)); 251 icest_cb.on_ice_complete = &on_ice_complete; 252 icest_cb.on_rx_data = &on_rx_data; 253 254 /* Create first ICE */ 255 status = pj_ice_strans_create(&stun_cfg, "offerer", comp_cnt, NULL, &icest_cb, &im1); 256 if (status != PJ_SUCCESS) 257 return -20; 258 259 id1 = PJ_POOL_ZALLOC_T(im1->pool, struct ice_data); 260 id1->obj_name = "offerer"; 261 im1->user_data = id1; 262 263 /* Init components */ 264 status = init_ice_st(im1, add_valid_comp, ocand_cnt, ocand); 265 if (status != 0) 266 return status; 267 268 /* Create second ICE */ 269 status = pj_ice_strans_create(&stun_cfg, "answerer", comp_cnt, NULL, &icest_cb, &im2); 270 if (status != PJ_SUCCESS) 271 return -25; 272 273 id2 = PJ_POOL_ZALLOC_T(im2->pool, struct ice_data); 274 id2->obj_name = "answerer"; 275 im2->user_data = id2; 276 277 /* Init components */ 278 status = init_ice_st(im2, add_valid_comp, acand_cnt, acand); 279 if (status != 0) 280 return status; 281 282 283 /* Init ICE on im1 */ 284 status = pj_ice_strans_init_ice(im1, PJ_ICE_SESS_ROLE_CONTROLLING, NULL, NULL); 285 if (status != PJ_SUCCESS) 286 return -29; 287 288 /* Init ICE on im2 */ 289 status = pj_ice_strans_init_ice(im2, PJ_ICE_SESS_ROLE_CONTROLLED, NULL, NULL); 290 if (status != PJ_SUCCESS) 291 return -29; 292 293 /* Start ICE on im2 */ 294 status = start_ice(im2, im1); 295 if (status != PJ_SUCCESS) { 296 app_perror(" error starting ICE", status); 297 return -30; 298 } 299 300 /* Start ICE on im1 */ 301 status = start_ice(im1, im2); 302 if (status != PJ_SUCCESS) 303 return -35; 304 305 /* Apply delay to let other checks commence */ 306 pj_thread_sleep(40); 307 308 /* Mark start time */ 309 pj_get_timestamp(&t_start); 310 311 /* Poll for wait_before_send msecs before we send the first data */ 312 if (expected_success) { 313 for (;;) { 314 pj_timestamp t_now; 315 316 handle_events(1); 317 318 CHECK_COMPLETE(); 319 320 pj_get_timestamp(&t_now); 321 if (pj_elapsed_msec(&t_start, &t_now) >= wait_before_send) 322 break; 323 } 324 325 /* Send data. It must be successful! */ 326 data_from_offerer = pj_str("from offerer"); 327 status = pj_ice_sess_send_data(im1->ice, 1, data_from_offerer.ptr, data_from_offerer.slen); 328 if (status != PJ_SUCCESS) 329 return -47; 330 331 data_from_answerer = pj_str("from answerer"); 332 status = pj_ice_sess_send_data(im2->ice, 1, data_from_answerer.ptr, data_from_answerer.slen); 333 if (status != PJ_SUCCESS) { 334 app_perror(" error sending packet", status); 335 return -48; 336 } 337 338 /* Poll to allow data to be received */ 339 for (;;) { 340 pj_timestamp t_now; 341 handle_events(1); 342 CHECK_COMPLETE(); 343 pj_get_timestamp(&t_now); 344 if (pj_elapsed_msec(&t_start, &t_now) >= (wait_before_send + 200)) 345 break; 346 } 347 } 348 349 /* Just wait until both completes, or timed out */ 350 while (!id1->complete || !id2->complete) { 351 pj_timestamp t_now; 352 353 handle_events(1); 354 355 CHECK_COMPLETE(); 356 pj_get_timestamp(&t_now); 357 if (pj_elapsed_msec(&t_start, &t_now) >= max_total_time) { 358 PJ_LOG(3,(THIS_FILE, "....error: timed-out")); 359 return -50; 360 } 361 } 362 363 /* Mark end-time */ 364 CHECK_COMPLETE(); 365 366 /* If expected to fail, then just check that both fail */ 367 if (!expected_success) { 368 /* Check status */ 369 if (id1->err_code == PJ_SUCCESS) 370 return -51; 371 if (id2->err_code == PJ_SUCCESS) 372 return -52; 373 goto on_return; 374 } 375 376 /* Check status */ 377 if (id1->err_code != PJ_SUCCESS) 378 return -53; 379 if (id2->err_code != PJ_SUCCESS) 380 return -56; 381 382 /* Verify that offerer gets answerer's transport address */ 383 for (i=0; i<comp_cnt; ++i) { 384 status = verify_address(im1, im2, i+1); 385 if (status != 0) 386 return status; 387 } 388 389 /* And the other way around */ 390 for (i=0; i<comp_cnt; ++i) { 391 status = verify_address(im2, im1, i+1); 392 if (status != 0) 393 return status; 394 } 395 396 /* Check that data is received in offerer */ 397 if (id1->rx_rtp_cnt != 1) { 398 PJ_LOG(3,(THIS_FILE, "....error: data not received in offerer")); 399 return -80; 400 } 401 if (pj_strcmp2(&data_from_answerer, id1->last_rx_rtp_data) != 0) { 402 PJ_LOG(3,(THIS_FILE, "....error: data mismatch in offerer")); 403 return -82; 404 } 405 406 /* And the same in answerer */ 407 if (id2->rx_rtp_cnt != 1) { 408 PJ_LOG(3,(THIS_FILE, "....error: data not received in answerer")); 409 return -84; 410 } 411 if (pj_strcmp2(&data_from_offerer, id2->last_rx_rtp_data) != 0) { 412 PJ_LOG(3,(THIS_FILE, "....error: data mismatch in answerer")); 413 return -82; 414 } 415 602 int rc; 603 struct sess_cfg_t { 604 const char *title; 605 unsigned server_flag; 606 struct test_cfg ua1; 607 struct test_cfg ua2; 608 } sess_cfg[] = 609 { 610 /* Role comp# host? stun? turn? flag? ans_del snd_del des_del */ 611 { 612 "hosts candidates only", 613 0xFFFF, 614 {ROLE1, 1, YES, NO, NO, NO, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}}, 615 {ROLE2, 1, YES, NO, NO, NO, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}} 616 }, 617 { 618 "host and srflxes", 619 0xFFFF, 620 {ROLE1, 1, YES, YES, NO, NO, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}}, 621 {ROLE2, 1, YES, YES, NO, NO, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}} 622 }, 623 { 624 "host vs relay", 625 0xFFFF, 626 {ROLE1, 1, YES, NO, NO, NO, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}}, 627 {ROLE2, 1, NO, NO, YES, NO, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}} 628 }, 629 { 630 "relay vs host", 631 0xFFFF, 632 {ROLE1, 1, NO, NO, YES, NO, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}}, 633 {ROLE2, 1, YES, NO, NO, NO, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}} 634 }, 635 { 636 "relay vs relay", 637 0xFFFF, 638 {ROLE1, 1, NO, NO, YES, NO, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}}, 639 {ROLE2, 1, NO, NO, YES, NO, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}} 640 }, 641 { 642 "all candidates", 643 0xFFFF, 644 {ROLE1, 1, YES, YES, YES, NO, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}}, 645 {ROLE2, 1, YES, YES, YES, NO, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}} 646 }, 647 }; 648 649 pool = pj_pool_create(mem, NULL, 512, 512, NULL); 650 rc = create_stun_config(pool, &stun_cfg); 651 if (rc != PJ_SUCCESS) { 652 pj_pool_release(pool); 653 return -7; 654 } 655 656 /* Simple test first with host candidate */ 657 if (1) { 658 struct sess_cfg_t cfg = 659 { 660 "Basic with host candidates", 661 0x0, 662 /* Role comp# host? stun? turn? flag? ans_del snd_del des_del */ 663 {ROLE1, 1, YES, NO, NO, 0, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}}, 664 {ROLE2, 1, YES, NO, NO, 0, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}} 665 }; 666 667 rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag, 668 &cfg.ua1, &cfg.ua2); 669 if (rc != 0) 670 goto on_return; 671 672 cfg.ua1.comp_cnt = 4; 673 cfg.ua2.comp_cnt = 4; 674 rc = perform_test("Basic with host candidates, 4 components", 675 &stun_cfg, cfg.server_flag, 676 &cfg.ua1, &cfg.ua2); 677 if (rc != 0) 678 goto on_return; 679 } 680 681 /* Simple test first with srflx candidate */ 682 if (1) { 683 struct sess_cfg_t cfg = 684 { 685 "Basic with srflx candidates", 686 0xFFFF, 687 /* Role comp# host? stun? turn? flag? ans_del snd_del des_del */ 688 {ROLE1, 1, YES, YES, NO, 0, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}}, 689 {ROLE2, 1, YES, YES, NO, 0, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}} 690 }; 691 692 rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag, 693 &cfg.ua1, &cfg.ua2); 694 if (rc != 0) 695 goto on_return; 696 697 cfg.ua1.comp_cnt = 4; 698 cfg.ua2.comp_cnt = 4; 699 700 rc = perform_test("Basic with srflx candidates, 4 components", 701 &stun_cfg, cfg.server_flag, 702 &cfg.ua1, &cfg.ua2); 703 if (rc != 0) 704 goto on_return; 705 } 706 707 /* Simple test with relay candidate */ 708 if (1) { 709 struct sess_cfg_t cfg = 710 { 711 "Basic with relay candidates", 712 0xFFFF, 713 /* Role comp# host? stun? turn? flag? ans_del snd_del des_del */ 714 {ROLE1, 1, NO, NO, YES, 0, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}}, 715 {ROLE2, 1, NO, NO, YES, 0, 0, 0, 0, {PJ_SUCCESS, PJ_SUCCESS}} 716 }; 717 718 rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag, 719 &cfg.ua1, &cfg.ua2); 720 if (rc != 0) 721 goto on_return; 722 723 cfg.ua1.comp_cnt = 4; 724 cfg.ua2.comp_cnt = 4; 725 726 rc = perform_test("Basic with relay candidates, 4 components", 727 &stun_cfg, cfg.server_flag, 728 &cfg.ua1, &cfg.ua2); 729 if (rc != 0) 730 goto on_return; 731 } 732 733 /* Failure test with STUN resolution */ 734 if (1) { 735 struct sess_cfg_t cfg = 736 { 737 "STUN resolution failure", 738 0x0, 739 /* Role comp# host? stun? turn? flag? ans_del snd_del des_del */ 740 {ROLE1, 2, NO, YES, NO, 0, 0, 0, 0, {PJNATH_ESTUNTIMEDOUT, -1}}, 741 {ROLE2, 2, NO, YES, NO, 0, 0, 0, 0, {PJNATH_ESTUNTIMEDOUT, -1}} 742 }; 743 744 rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag, 745 &cfg.ua1, &cfg.ua2); 746 if (rc != 0) 747 goto on_return; 748 749 cfg.ua1.client_flag |= DEL_ON_ERR; 750 cfg.ua2.client_flag |= DEL_ON_ERR; 751 752 rc = perform_test("STUN resolution failure with destroy on callback", 753 &stun_cfg, cfg.server_flag, 754 &cfg.ua1, &cfg.ua2); 755 if (rc != 0) 756 goto on_return; 757 } 758 759 /* Failure test with TURN resolution */ 760 if (1) { 761 struct sess_cfg_t cfg = 762 { 763 "TURN allocation failure", 764 0xFFFF, 765 /* Role comp# host? stun? turn? flag? ans_del snd_del des_del */ 766 {ROLE1, 4, NO, NO, YES, WRONG_TURN, 0, 0, 0, {PJ_STATUS_FROM_STUN_CODE(401), -1}}, 767 {ROLE2, 4, NO, NO, YES, WRONG_TURN, 0, 0, 0, {PJ_STATUS_FROM_STUN_CODE(401), -1}} 768 }; 769 770 rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag, 771 &cfg.ua1, &cfg.ua2); 772 if (rc != 0) 773 goto on_return; 774 775 cfg.ua1.client_flag |= DEL_ON_ERR; 776 cfg.ua2.client_flag |= DEL_ON_ERR; 777 778 rc = perform_test("TURN allocation failure with destroy on callback", 779 &stun_cfg, cfg.server_flag, 780 &cfg.ua1, &cfg.ua2); 781 if (rc != 0) 782 goto on_return; 783 } 784 785 /* STUN failure, testing TURN deallocation */ 786 if (1) { 787 struct sess_cfg_t cfg = 788 { 789 "STUN failure, testing TURN deallocation", 790 0xFFFF & (~(CREATE_STUN_SERVER)), 791 /* Role comp# host? stun? turn? flag? ans_del snd_del des_del */ 792 {ROLE1, 2, YES, YES, YES, 0, 0, 0, 0, {PJNATH_ESTUNTIMEDOUT, -1}}, 793 {ROLE2, 2, YES, YES, YES, 0, 0, 0, 0, {PJNATH_ESTUNTIMEDOUT, -1}} 794 }; 795 796 rc = perform_test(cfg.title, &stun_cfg, cfg.server_flag, 797 &cfg.ua1, &cfg.ua2); 798 if (rc != 0) 799 goto on_return; 800 801 cfg.ua1.client_flag |= DEL_ON_ERR; 802 cfg.ua2.client_flag |= DEL_ON_ERR; 803 804 rc = perform_test("STUN failure, testing TURN deallocation (cb)", 805 &stun_cfg, cfg.server_flag, 806 &cfg.ua1, &cfg.ua2); 807 if (rc != 0) 808 goto on_return; 809 } 810 811 rc = 0; 812 /* Iterate each test item */ 813 for (i=0; i<PJ_ARRAY_SIZE(sess_cfg); ++i) { 814 struct sess_cfg_t *cfg = &sess_cfg[i]; 815 unsigned delay[] = { 50, 2000 }; 816 unsigned d; 817 818 PJ_LOG(3,("", " %s", cfg->title)); 819 820 /* For each test item, test with various answer delay */ 821 for (d=0; d<PJ_ARRAY_SIZE(delay); ++d) { 822 struct role_t { 823 pj_ice_sess_role ua1; 824 pj_ice_sess_role ua2; 825 } role[] = 826 { 827 { ROLE1, ROLE2}, 828 { ROLE2, ROLE1}, 829 { ROLE1, ROLE1}, 830 { ROLE2, ROLE2} 831 }; 832 unsigned j; 833 834 cfg->ua1.answer_delay = delay[d]; 835 cfg->ua2.answer_delay = delay[d]; 836 837 /* For each test item, test with role conflict scenarios */ 838 for (j=0; j<PJ_ARRAY_SIZE(role); ++j) { 839 unsigned k1; 840 841 cfg->ua1.role = role[j].ua1; 842 cfg->ua2.role = role[j].ua2; 843 844 /* For each test item, test with different number of components */ 845 for (k1=1; k1<=2; ++k1) { 846 unsigned k2; 847 848 cfg->ua1.comp_cnt = k1; 849 850 for (k2=1; k2<=2; ++k2) { 851 char title[120]; 852 853 sprintf(title, 854 "%s/%s, %dms answer delay, %d vs %d components", 855 pj_ice_sess_role_name(role[j].ua1), 856 pj_ice_sess_role_name(role[j].ua2), 857 delay[d], k1, k2); 858 859 cfg->ua2.comp_cnt = k2; 860 rc = perform_test(title, &stun_cfg, cfg->server_flag, 861 &cfg->ua1, &cfg->ua2); 862 if (rc != 0) 863 goto on_return; 864 } 865 } 866 } 867 } 868 } 416 869 417 870 on_return: 418 419 /* Done */ 420 PJ_LOG(3,(THIS_FILE, "....success: ICE completed in %d msec, waiting..", 421 pj_elapsed_msec(&t_start, &t_end))); 422 423 /* Wait for some more time */ 424 for (;;) { 425 pj_timestamp t_now; 426 427 pj_get_timestamp(&t_now); 428 if (pj_elapsed_msec(&t_start, &t_now) > max_total_time) 429 break; 430 431 handle_events(1); 432 } 433 434 435 pj_ice_strans_destroy(im1); 436 pj_ice_strans_destroy(im2); 437 handle_events(100); 438 return 0; 439 } 440 441 442 int ice_test(void) 443 { 444 int rc = 0; 445 pj_pool_t *pool; 446 pj_ioqueue_t *ioqueue; 447 pj_timer_heap_t *timer_heap; 448 enum { D1=500, D2=5000, D3=15000 }; 449 struct dummy_cand ocand[] = 450 { 451 {1, PJ_ICE_CAND_TYPE_SRFLX, "127.1.1.1", 65534 }, 452 {2, PJ_ICE_CAND_TYPE_SRFLX, "127.1.1.1", 65535 }, 453 }; 454 struct dummy_cand acand[] = 455 { 456 {1, PJ_ICE_CAND_TYPE_SRFLX, "127.2.2.2", 65534 }, 457 {2, PJ_ICE_CAND_TYPE_SRFLX, "127.2.2.2", 65535 }, 458 }; 459 460 pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); 461 pj_ioqueue_create(pool, 12, &ioqueue); 462 pj_timer_heap_create(pool, 100, &timer_heap); 463 464 pj_stun_config_init(&stun_cfg, mem, 0, ioqueue, timer_heap); 465 466 #if 0 467 pj_log_set_level(5); 468 #endif 469 470 //goto test; 471 472 /* Basic create/destroy */ 473 rc = ice_basic_create_destroy_test(); 474 if (rc != 0) 475 goto on_return; 476 477 /* Direct communication */ 478 rc = perform_ice_test("Simple test (1 component)", PJ_TRUE, 1, PJ_TRUE, D1, D2, 0, NULL, 0, NULL); 479 if (rc != 0) 480 goto on_return; 481 482 /* Failure case (all checks fail) */ 483 #if 0 484 /* Cannot just add an SRFLX candidate; it needs a base */ 485 rc = perform_ice_test("Failure case (all checks fail)", PJ_FALSE, 1, PJ_FALSE, D3, D3, 1, ocand, 1, acand); 486 if (rc != 0) 487 goto on_return; 488 #endif 489 490 /* Direct communication with invalid address */ 491 rc = perform_ice_test("With 1 unreachable address", PJ_TRUE, 1, PJ_TRUE, D1, D2, 1, ocand, 0, NULL); 492 if (rc != 0) 493 goto on_return; 494 495 /* Direct communication with invalid address */ 496 rc = perform_ice_test("With 2 unreachable addresses (one each)", PJ_TRUE, 1, PJ_TRUE, D1, D2, 1, ocand, 1, acand); 497 if (rc != 0) 498 goto on_return; 499 500 /* Direct communication with two components */ 501 //test: 502 rc = perform_ice_test("With two components (RTP and RTCP)", PJ_TRUE, 2, PJ_TRUE, D1, D2, 0, NULL, 0, NULL); 503 if (rc != 0) 504 goto on_return; 505 506 goto on_return; 507 508 /* Direct communication with mismatch number of components */ 509 510 /* Direct communication with 2 components and 2 invalid address */ 511 rc = perform_ice_test("With 2 two components and 2 unreachable address", PJ_TRUE, 2, PJ_TRUE, D1, D2, 1, ocand, 1, acand); 512 if (rc != 0) 513 goto on_return; 514 515 516 517 on_return: 518 pj_log_set_level(3); 519 pj_ioqueue_destroy(stun_cfg.ioqueue); 871 destroy_stun_config(&stun_cfg); 520 872 pj_pool_release(pool); 521 873 return rc;
Note: See TracChangeset
for help on using the changeset viewer.