/* Destroy test session */ static void destroy_sess(struct test_sess *sess, unsigned wait_msec) { if (sess->caller.ice) { pj_ice_strans_destroy(sess->caller.ice); sess->caller.ice = NULL; } if (sess->callee.ice) { pj_ice_strans_destroy(sess->callee.ice); sess->callee.ice = NULL; } poll_events(sess->stun_cfg, wait_msec, PJ_FALSE); if (sess->resolver) { pj_dns_resolver_destroy(sess->resolver, PJ_FALSE); sess->resolver = NULL; } if (sess->server) { destroy_test_server(sess->server); sess->server = NULL; } if (sess->pool) { pj_pool_t *pool = sess->pool; sess->pool = NULL; pj_pool_release(pool); } }
static void ice_on_ice_complete(pj_ice_strans *ice_st, pj_ice_strans_op op, pj_status_t status) { struct ice_ept *ept; ept = (struct ice_ept*) pj_ice_strans_get_user_data(ice_st); switch (op) { case PJ_ICE_STRANS_OP_INIT: ept->result.init_status = status; if (status != PJ_SUCCESS && (ept->cfg.client_flag & DEL_ON_ERR)) { pj_ice_strans_destroy(ice_st); ept->ice = NULL; } break; case PJ_ICE_STRANS_OP_NEGOTIATION: ept->result.nego_status = status; break; case PJ_ICE_STRANS_OP_KEEP_ALIVE: /* keep alive failed? */ break; default: pj_assert(!"Unknown op"); } }
/* * This is the callback that is registered to the ICE stream transport to * receive notification about ICE state progression. */ static void cb_on_ice_complete(pj_ice_strans *ice_st, pj_ice_strans_op op, pj_status_t status) { const char *opname = (op==PJ_ICE_STRANS_OP_INIT? "initialization" : (op==PJ_ICE_STRANS_OP_NEGOTIATION ? "negotiation" : "unknown_op")); printf("[DEBUG] operation: %s, %d %s \n", __func__, __LINE__, opname); if (status == PJ_SUCCESS) { PJ_LOG(3,(THIS_FILE, "[DEBUG] ICE %s successful", opname)); } else { char errmsg[PJ_ERR_MSG_SIZE]; pj_strerror(status, errmsg, sizeof(errmsg)); PJ_LOG(1,(THIS_FILE, "[DEBUG] ICE %s failed: %s", opname, errmsg)); pj_ice_strans_destroy(ice_st); // FIXME: update the ICE transaction //nat_controller.icest = NULL; } }
/* Utility: display error message and exit application (usually * because of fatal error. */ static void err_exit(const char *title, pj_status_t status) { if (status != PJ_SUCCESS) { icedemo_perror(title, status); } PJ_LOG(3,(THIS_FILE, "Shutting down..")); if (icedemo.icest) pj_ice_strans_destroy(icedemo.icest); pj_thread_sleep(500); icedemo.thread_quit_flag = PJ_TRUE; if (icedemo.thread) { pj_thread_join(icedemo.thread); pj_thread_destroy(icedemo.thread); } if (icedemo.ice_cfg.stun_cfg.ioqueue) pj_ioqueue_destroy(icedemo.ice_cfg.stun_cfg.ioqueue); if (icedemo.ice_cfg.stun_cfg.timer_heap) pj_timer_heap_destroy(icedemo.ice_cfg.stun_cfg.timer_heap); pj_caching_pool_destroy(&icedemo.cp); pj_shutdown(); if (icedemo.log_fhnd) { fclose(icedemo.log_fhnd); icedemo.log_fhnd = NULL; } exit(status != PJ_SUCCESS); }
/* Destroy test session */ static void destroy_sess(struct test_sess *sess, unsigned wait_msec) { unsigned i; if (sess->caller.ice) { pj_ice_strans_destroy(sess->caller.ice); sess->caller.ice = NULL; } if (sess->callee.ice) { pj_ice_strans_destroy(sess->callee.ice); sess->callee.ice = NULL; } sess->param->worker_quit = PJ_TRUE; for (i=0; i<sess->param->worker_cnt; ++i) { if (sess->worker_threads[i]) pj_thread_join(sess->worker_threads[i]); } poll_events(sess->stun_cfg, wait_msec, PJ_FALSE); if (sess->resolver) { pj_dns_resolver_destroy(sess->resolver, PJ_FALSE); sess->resolver = NULL; } if (sess->server) { destroy_test_server(sess->server); sess->server = NULL; } if (sess->pool) { pj_pool_t *pool = sess->pool; sess->pool = NULL; pj_pool_release(pool); } }
/* * Destroy ICE stream transport instance, invoked from the menu. */ void natclient_destroy_instance(struct ice_trans_s* icetrans) { if (icetrans->icest == NULL) { PJ_LOG(1,(THIS_FILE, "Error: No ICE instance, create it first")); return; } pj_ice_strans_destroy(icetrans->icest); icetrans->icest = NULL; reset_rem_info(icetrans); PJ_LOG(3,(THIS_FILE, "ICE instance destroyed")); }
/* * Destroy ICE stream transport instance, invoked from the menu. */ static void icedemo_destroy_instance(void) { if (icedemo.icest == NULL) { PJ_LOG(1,(THIS_FILE, "Error: No ICE instance, create it first")); return; } pj_ice_strans_destroy(icedemo.icest); icedemo.icest = NULL; reset_rem_info(); PJ_LOG(3,(THIS_FILE, "ICE instance destroyed")); }
/* * Destroy ICE media transport. */ static pj_status_t transport_destroy(pjmedia_transport *tp) { struct transport_ice *tp_ice = (struct transport_ice*)tp; if (tp_ice->ice_st) { pj_ice_strans_destroy(tp_ice->ice_st); tp_ice->ice_st = NULL; } if (tp_ice->pool) { pj_pool_t *pool = tp_ice->pool; tp_ice->pool = NULL; pj_pool_release(pool); } return PJ_SUCCESS; }
/* * This is the callback that is registered to the ICE stream transport to * receive notification about ICE state progression. */ static void cb_on_ice_complete(pj_ice_strans *ice_st, pj_ice_strans_op op, pj_status_t status) { const char *opname = (op==PJ_ICE_STRANS_OP_INIT? "initialization" : (op==PJ_ICE_STRANS_OP_NEGOTIATION ? "negotiation" : "unknown_op")); if (status == PJ_SUCCESS) { PJ_LOG(3,(THIS_FILE, "ICE %s successful", opname)); } else { char errmsg[PJ_ERR_MSG_SIZE]; pj_strerror(status, errmsg, sizeof(errmsg)); PJ_LOG(1,(THIS_FILE, "ICE %s failed: %s", opname, errmsg)); pj_ice_strans_destroy(ice_st); icedemo.icest = NULL; } }
static int perform_test(const char *title, pj_stun_config *stun_cfg, unsigned server_flag, struct test_cfg *caller_cfg, struct test_cfg *callee_cfg) { pjlib_state pjlib_state; struct test_sess *sess; int rc; PJ_LOG(3,("", INDENT "%s", title)); capture_pjlib_state(stun_cfg, &pjlib_state); rc = create_sess(stun_cfg, server_flag, caller_cfg, callee_cfg, &sess); if (rc != 0) return rc; #define ALL_READY (sess->caller.result.init_status!=PJ_EPENDING && \ sess->callee.result.init_status!=PJ_EPENDING) /* Wait until both ICE transports are initialized */ WAIT_UNTIL(30, ALL_READY, rc); if (!ALL_READY) { PJ_LOG(3,("", INDENT "err: init timed-out")); destroy_sess(sess, 500); return -100; } if (sess->caller.result.init_status != sess->caller.cfg.expected.init_status) { app_perror(INDENT "err: caller init", sess->caller.result.init_status); destroy_sess(sess, 500); return -102; } if (sess->callee.result.init_status != sess->callee.cfg.expected.init_status) { app_perror(INDENT "err: callee init", sess->callee.result.init_status); destroy_sess(sess, 500); return -104; } /* Failure condition */ if (sess->caller.result.init_status != PJ_SUCCESS || sess->callee.result.init_status != PJ_SUCCESS) { rc = 0; goto on_return; } /* Init ICE on caller */ rc = pj_ice_strans_init_ice(sess->caller.ice, sess->caller.cfg.role, &sess->caller.ufrag, &sess->caller.pass); if (rc != PJ_SUCCESS) { app_perror(INDENT "err: caller pj_ice_strans_init_ice()", rc); destroy_sess(sess, 500); return -100; } /* Init ICE on callee */ rc = pj_ice_strans_init_ice(sess->callee.ice, sess->callee.cfg.role, &sess->callee.ufrag, &sess->callee.pass); if (rc != PJ_SUCCESS) { app_perror(INDENT "err: callee pj_ice_strans_init_ice()", rc); destroy_sess(sess, 500); return -110; } /* Start ICE on callee */ rc = start_ice(&sess->callee, &sess->caller); if (rc != PJ_SUCCESS) { destroy_sess(sess, 500); return -120; } /* Wait for callee's answer_delay */ poll_events(stun_cfg, sess->callee.cfg.answer_delay, PJ_FALSE); /* Start ICE on caller */ rc = start_ice(&sess->caller, &sess->callee); if (rc != PJ_SUCCESS) { destroy_sess(sess, 500); return -130; } /* Wait until negotiation is complete on both endpoints */ #define ALL_DONE (sess->caller.result.nego_status!=PJ_EPENDING && \ sess->callee.result.nego_status!=PJ_EPENDING) WAIT_UNTIL(30, ALL_DONE, rc); if (!ALL_DONE) { PJ_LOG(3,("", INDENT "err: negotiation timed-out")); destroy_sess(sess, 500); return -140; } if (sess->caller.result.nego_status != sess->caller.cfg.expected.nego_status) { app_perror(INDENT "err: caller negotiation failed", sess->caller.result.nego_status); destroy_sess(sess, 500); return -150; } if (sess->callee.result.nego_status != sess->callee.cfg.expected.nego_status) { app_perror(INDENT "err: callee negotiation failed", sess->callee.result.nego_status); destroy_sess(sess, 500); return -160; } /* Verify that both agents have agreed on the same pair */ rc = check_pair(&sess->caller, &sess->callee, -170); if (rc != 0) { destroy_sess(sess, 500); return rc; } rc = check_pair(&sess->callee, &sess->caller, -180); if (rc != 0) { destroy_sess(sess, 500); return rc; } /* Looks like everything is okay */ /* Destroy ICE stream transports first to let it de-allocate * TURN relay (otherwise there'll be timer/memory leak, unless * we wait for long time in the last poll_events() below). */ if (sess->caller.ice) { pj_ice_strans_destroy(sess->caller.ice); sess->caller.ice = NULL; } if (sess->callee.ice) { pj_ice_strans_destroy(sess->callee.ice); sess->callee.ice = NULL; } on_return: /* Wait.. */ poll_events(stun_cfg, 500, PJ_FALSE); /* Now destroy everything */ destroy_sess(sess, 500); /* Flush events */ poll_events(stun_cfg, 100, PJ_FALSE); rc = check_pjlib_state(stun_cfg, &pjlib_state); if (rc != 0) { return rc; } return 0; }
static int perform_test2(const char *title, pj_stun_config *stun_cfg, unsigned server_flag, struct test_cfg *caller_cfg, struct test_cfg *callee_cfg, struct sess_param *test_param) { pjlib_state pjlib_state; struct test_sess *sess; unsigned i; int rc; PJ_LOG(3,(THIS_FILE, INDENT "%s", title)); capture_pjlib_state(stun_cfg, &pjlib_state); rc = create_sess(stun_cfg, server_flag, caller_cfg, callee_cfg, test_param, &sess); if (rc != 0) return rc; #define ALL_READY (sess->caller.result.init_status!=PJ_EPENDING && \ sess->callee.result.init_status!=PJ_EPENDING) /* Wait until both ICE transports are initialized */ WAIT_UNTIL(30000, ALL_READY, rc); if (!ALL_READY) { PJ_LOG(3,(THIS_FILE, INDENT "err: init timed-out")); destroy_sess(sess, 500); return -100; } if (sess->caller.result.init_status != sess->caller.cfg.expected.init_status) { app_perror(INDENT "err: caller init", sess->caller.result.init_status); destroy_sess(sess, 500); return -102; } if (sess->callee.result.init_status != sess->callee.cfg.expected.init_status) { app_perror(INDENT "err: callee init", sess->callee.result.init_status); destroy_sess(sess, 500); return -104; } /* Failure condition */ if (sess->caller.result.init_status != PJ_SUCCESS || sess->callee.result.init_status != PJ_SUCCESS) { rc = 0; goto on_return; } /* Init ICE on caller */ rc = pj_ice_strans_init_ice(sess->caller.ice, sess->caller.cfg.role, &sess->caller.ufrag, &sess->caller.pass); if (rc != PJ_SUCCESS) { app_perror(INDENT "err: caller pj_ice_strans_init_ice()", rc); destroy_sess(sess, 500); return -100; } /* Init ICE on callee */ rc = pj_ice_strans_init_ice(sess->callee.ice, sess->callee.cfg.role, &sess->callee.ufrag, &sess->callee.pass); if (rc != PJ_SUCCESS) { app_perror(INDENT "err: callee pj_ice_strans_init_ice()", rc); destroy_sess(sess, 500); return -110; } /* Start ICE on callee */ rc = start_ice(&sess->callee, &sess->caller); if (rc != PJ_SUCCESS) { destroy_sess(sess, 500); return -120; } /* Wait for callee's answer_delay */ poll_events(stun_cfg, sess->callee.cfg.answer_delay, PJ_FALSE); /* Start ICE on caller */ rc = start_ice(&sess->caller, &sess->callee); if (rc != PJ_SUCCESS) { destroy_sess(sess, 500); return -130; } for (i=0; i<sess->param->worker_cnt; ++i) { pj_status_t status; status = pj_thread_create(sess->pool, "worker_thread", worker_thread_proc, sess, 0, 0, &sess->worker_threads[i]); if (status != PJ_SUCCESS) { PJ_LOG(3,(THIS_FILE, INDENT "err: create thread")); destroy_sess(sess, 500); return -135; } } if (sess->param->destroy_after_create) goto on_destroy; if (sess->param->destroy_after_one_done) { while (sess->caller.result.init_status==PJ_EPENDING && sess->callee.result.init_status==PJ_EPENDING) { if (sess->param->worker_cnt) pj_thread_sleep(0); else poll_events(stun_cfg, 0, PJ_FALSE); } goto on_destroy; } WAIT_UNTIL(30000, ALL_DONE, rc); if (!ALL_DONE) { PJ_LOG(3,(THIS_FILE, INDENT "err: negotiation timed-out")); destroy_sess(sess, 500); return -140; } if (sess->caller.result.nego_status != sess->caller.cfg.expected.nego_status) { app_perror(INDENT "err: caller negotiation failed", sess->caller.result.nego_status); destroy_sess(sess, 500); return -150; } if (sess->callee.result.nego_status != sess->callee.cfg.expected.nego_status) { app_perror(INDENT "err: callee negotiation failed", sess->callee.result.nego_status); destroy_sess(sess, 500); return -160; } /* Verify that both agents have agreed on the same pair */ rc = check_pair(&sess->caller, &sess->callee, -170); if (rc != 0) { destroy_sess(sess, 500); return rc; } rc = check_pair(&sess->callee, &sess->caller, -180); if (rc != 0) { destroy_sess(sess, 500); return rc; } /* Looks like everything is okay */ on_destroy: /* Destroy ICE stream transports first to let it de-allocate * TURN relay (otherwise there'll be timer/memory leak, unless * we wait for long time in the last poll_events() below). */ if (sess->caller.ice) { pj_ice_strans_destroy(sess->caller.ice); sess->caller.ice = NULL; } if (sess->callee.ice) { pj_ice_strans_destroy(sess->callee.ice); sess->callee.ice = NULL; } on_return: /* Wait.. */ poll_events(stun_cfg, 200, PJ_FALSE); /* Now destroy everything */ destroy_sess(sess, 500); /* Flush events */ poll_events(stun_cfg, 100, PJ_FALSE); rc = check_pjlib_state(stun_cfg, &pjlib_state); if (rc != 0) { return rc; } return rc; }