/* * Initialize codec manager. */ PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_create( pj_pool_t *pool, pjmedia_vid_codec_mgr **p_mgr) { pjmedia_vid_codec_mgr *mgr; pj_status_t status; PJ_ASSERT_RETURN(pool, PJ_EINVAL); mgr = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_codec_mgr); mgr->pf = pool->factory; pj_list_init (&mgr->factory_list); mgr->codec_cnt = 0; /* Create mutex */ status = pj_mutex_create_recursive(pool, "vid-codec-mgr", &mgr->mutex); if (status != PJ_SUCCESS) return status; if (!def_vid_codec_mgr) def_vid_codec_mgr = mgr; if (p_mgr) *p_mgr = mgr; return PJ_SUCCESS; }
static pj_status_t job_queue_create(pj_pool_t *pool, job_queue **pjq) { unsigned i; pj_status_t status; job_queue *jq = PJ_POOL_ZALLOC_T(pool, job_queue); jq->size = MAX_JOBS; status = pj_sem_create(pool, "thread_sem", 0, jq->size + 1, &jq->sem); if (status != PJ_SUCCESS) goto on_error; for (i = 0; i < jq->size; i++) { status = pj_sem_create(pool, "job_sem", 0, 1, &jq->job_sem[i]); if (status != PJ_SUCCESS) goto on_error; } status = pj_mutex_create_recursive(pool, "job_mutex", &jq->mutex); if (status != PJ_SUCCESS) goto on_error; status = pj_thread_create(pool, "job_th", job_thread, jq, 0, 0, &jq->thread); if (status != PJ_SUCCESS) goto on_error; *pjq = jq; return PJ_SUCCESS; on_error: job_queue_destroy(jq); return status; }
/* * mod_ua_load() * * Called when module is being loaded by endpoint. */ static pj_status_t mod_ua_load(pjsip_endpoint *endpt) { pj_status_t status; /* Initialize the user agent. */ mod_ua.endpt = endpt; mod_ua.pool = pjsip_endpt_create_pool( endpt, "ua%p", PJSIP_POOL_LEN_UA, PJSIP_POOL_INC_UA); if (mod_ua.pool == NULL) return PJ_ENOMEM; status = pj_mutex_create_recursive(mod_ua.pool, " ua%p", &mod_ua.mutex); if (status != PJ_SUCCESS) return status; mod_ua.dlg_table = pj_hash_create(mod_ua.pool, PJSIP_MAX_DIALOG_COUNT); if (mod_ua.dlg_table == NULL) return PJ_ENOMEM; pj_list_init(&mod_ua.free_dlgset_nodes); /* Initialize dialog lock. */ status = pj_thread_local_alloc(&pjsip_dlg_lock_tls_id); if (status != PJ_SUCCESS) return status; pj_thread_local_set(pjsip_dlg_lock_tls_id, NULL); return PJ_SUCCESS; }
SIPPresence::SIPPresence(SIPAccount *acc) : publish_sess_() , status_data_() , enabled_(false) , publish_supported_(false) , subscribe_supported_(false) , status_(false) , note_(" ") , acc_(acc) , sub_server_list_() //IP2IP context , sub_client_list_() , mutex_() , mutex_nesting_level_() , mutex_owner_() , cp_() , pool_() { /* init pool */ pj_caching_pool_init(&cp_, &pj_pool_factory_default_policy, 0); pool_ = pj_pool_create(&cp_.factory, "pres", 1000, 1000, NULL); if (!pool_) throw std::runtime_error("Could not allocate pool for presence"); /* Create mutex */ if (pj_mutex_create_recursive(pool_, "pres", &mutex_) != PJ_SUCCESS) { pj_pool_release(pool_); pj_caching_pool_destroy(&cp_); throw std::runtime_error("Unable to create mutex"); } /* init default status */ updateStatus(false, " "); }
PJ_DEF(pj_status_t) pjsip_publishc_create( pjsip_endpoint *endpt, const pjsip_publishc_opt *opt, void *token, pjsip_publishc_cb *cb, pjsip_publishc **p_pubc) { pj_pool_t *pool; pjsip_publishc *pubc; pjsip_publishc_opt default_opt; pj_status_t status; /* Verify arguments. */ PJ_ASSERT_RETURN(endpt && cb && p_pubc, PJ_EINVAL); pool = pjsip_endpt_create_pool(endpt, "pubc%p", 1024, 1024); PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM); pubc = PJ_POOL_ZALLOC_T(pool, pjsip_publishc); pubc->pool = pool; pubc->endpt = endpt; pubc->token = token; pubc->cb = cb; pubc->expires = PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED; if (!opt) { pjsip_publishc_opt_default(&default_opt); opt = &default_opt; } pj_memcpy(&pubc->opt, opt, sizeof(*opt)); pj_list_init(&pubc->pending_reqs); pj_list_init(&pubc->pending_reqs_empty); status = pj_mutex_create_recursive(pubc->pool, "pubc%p", &pubc->mutex); if (status != PJ_SUCCESS) { pj_pool_release(pool); return status; } status = pjsip_auth_clt_init(&pubc->auth_sess, endpt, pubc->pool, 0); if (status != PJ_SUCCESS) { pj_mutex_destroy(pubc->mutex); pj_pool_release(pool); return status; } pj_list_init(&pubc->route_set); pj_list_init(&pubc->usr_hdr); /* Done */ *p_pubc = pubc; return PJ_SUCCESS; }
PJ_DEF(pj_status_t) pjmedia_event_mgr_create(pj_pool_t *pool, unsigned options, pjmedia_event_mgr **p_mgr) { pjmedia_event_mgr *mgr; pj_status_t status; mgr = PJ_POOL_ZALLOC_T(pool, pjmedia_event_mgr); mgr->pool = pj_pool_create(pool->factory, "evt mgr", 500, 500, NULL); pj_list_init(&mgr->esub_list); pj_list_init(&mgr->free_esub_list); if (!(options & PJMEDIA_EVENT_MGR_NO_THREAD)) { status = pj_sem_create(mgr->pool, "ev_sem", 0, MAX_EVENTS + 1, &mgr->sem); if (status != PJ_SUCCESS) return status; status = pj_thread_create(mgr->pool, "ev_thread", &event_worker_thread, mgr, 0, 0, &mgr->thread); if (status != PJ_SUCCESS) { pjmedia_event_mgr_destroy(mgr); return status; } } status = pj_mutex_create_recursive(mgr->pool, "ev_mutex", &mgr->mutex); if (status != PJ_SUCCESS) { pjmedia_event_mgr_destroy(mgr); return status; } if (!event_manager_instance) event_manager_instance = mgr; if (p_mgr) *p_mgr = mgr; return PJ_SUCCESS; }
/* * Initialize codec manager. */ PJ_DEF(pj_status_t) pjmedia_codec_mgr_init (pjmedia_codec_mgr *mgr, pj_pool_factory *pf) { pj_status_t status; PJ_ASSERT_RETURN(mgr && pf, PJ_EINVAL); /* Init codec manager */ pj_bzero(mgr, sizeof(pjmedia_codec_mgr)); mgr->pf = pf; pj_list_init (&mgr->factory_list); mgr->codec_cnt = 0; /* Create pool */ mgr->pool = pj_pool_create(mgr->pf, "codec-mgr", 256, 256, NULL); /* Create mutex */ status = pj_mutex_create_recursive(mgr->pool, "codec-mgr", &mgr->mutex); if (status != PJ_SUCCESS) return status; return PJ_SUCCESS; }
int transport_rt_test( pjsip_transport_type_e tp_type, pjsip_transport *ref_tp, char *target_url, int *lost) { enum { THREADS = 4, INTERVAL = 10 }; int i; pj_status_t status; pj_pool_t *pool; pj_bool_t logger_enabled; pj_timestamp zero_time, total_time; unsigned usec_rt; unsigned total_sent; unsigned total_recv; PJ_UNUSED_ARG(tp_type); PJ_UNUSED_ARG(ref_tp); PJ_LOG(3,(THIS_FILE, " multithreaded round-trip test (%d threads)...", THREADS)); PJ_LOG(3,(THIS_FILE, " this will take approx %d seconds, please wait..", INTERVAL)); /* Make sure msg logger is disabled. */ logger_enabled = msg_logger_set_enabled(0); /* Register module (if not yet registered) */ if (rt_module.id == -1) { status = pjsip_endpt_register_module( endpt, &rt_module ); if (status != PJ_SUCCESS) { app_perror(" error: unable to register module", status); return -600; } } /* Create pool for this test. */ pool = pjsip_endpt_create_pool(endpt, NULL, 4000, 4000); if (!pool) return -610; /* Initialize static test data. */ pj_ansi_strcpy(rt_target_uri, target_url); rt_call_id = pj_str("RT-Call-Id/"); rt_stop = PJ_FALSE; /* Initialize thread data. */ for (i=0; i<THREADS; ++i) { char buf[1]; pj_str_t str_id; pj_strset(&str_id, buf, 1); pj_bzero(&rt_test_data[i], sizeof(rt_test_data[i])); /* Init timer entry */ rt_test_data[i].tx_timer.id = i; rt_test_data[i].tx_timer.cb = &rt_tx_timer; rt_test_data[i].timeout_timer.id = i; rt_test_data[i].timeout_timer.cb = &rt_timeout_timer; /* Generate Call-ID for each thread. */ rt_test_data[i].call_id.ptr = (char*) pj_pool_alloc(pool, rt_call_id.slen+1); pj_strcpy(&rt_test_data[i].call_id, &rt_call_id); buf[0] = '0' + (char)i; pj_strcat(&rt_test_data[i].call_id, &str_id); /* Init mutex. */ status = pj_mutex_create_recursive(pool, "rt", &rt_test_data[i].mutex); if (status != PJ_SUCCESS) { app_perror(" error: unable to create mutex", status); return -615; } /* Create thread, suspended. */ status = pj_thread_create(pool, "rttest%p", &rt_worker_thread, (void*)(long)i, 0, PJ_THREAD_SUSPENDED, &rt_test_data[i].thread); if (status != PJ_SUCCESS) { app_perror(" error: unable to create thread", status); return -620; } } /* Start threads! */ for (i=0; i<THREADS; ++i) { pj_time_val delay = {0,0}; pj_thread_resume(rt_test_data[i].thread); /* Schedule first message transmissions. */ rt_test_data[i].tx_timer.user_data = (void*)1; pjsip_endpt_schedule_timer(endpt, &rt_test_data[i].tx_timer, &delay); } /* Sleep for some time. */ pj_thread_sleep(INTERVAL * 1000); /* Signal thread to stop. */ rt_stop = PJ_TRUE; /* Wait threads to complete. */ for (i=0; i<THREADS; ++i) { pj_thread_join(rt_test_data[i].thread); pj_thread_destroy(rt_test_data[i].thread); } /* Destroy rt_test_data */ for (i=0; i<THREADS; ++i) { pj_mutex_destroy(rt_test_data[i].mutex); pjsip_endpt_cancel_timer(endpt, &rt_test_data[i].timeout_timer); } /* Gather statistics. */ pj_bzero(&total_time, sizeof(total_time)); pj_bzero(&zero_time, sizeof(zero_time)); usec_rt = total_sent = total_recv = 0; for (i=0; i<THREADS; ++i) { total_sent += rt_test_data[i].sent_request_count; total_recv += rt_test_data[i].recv_response_count; pj_add_timestamp(&total_time, &rt_test_data[i].total_rt_time); } /* Display statistics. */ if (total_recv) total_time.u64 = total_time.u64/total_recv; else total_time.u64 = 0; usec_rt = pj_elapsed_usec(&zero_time, &total_time); PJ_LOG(3,(THIS_FILE, " done.")); PJ_LOG(3,(THIS_FILE, " total %d messages sent", total_sent)); PJ_LOG(3,(THIS_FILE, " average round-trip=%d usec", usec_rt)); pjsip_endpt_release_pool(endpt, pool); *lost = total_sent-total_recv; /* Flush events. */ flush_events(500); /* Restore msg logger. */ msg_logger_set_enabled(logger_enabled); return 0; }
/* * pj_ioqueue_create() * * Create select ioqueue. */ PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, pj_size_t max_fd, pj_ioqueue_t **p_ioqueue) { pj_ioqueue_t *ioqueue; pj_lock_t *lock; unsigned i; pj_status_t rc; /* Check that arguments are valid. */ PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL && max_fd > 0 && max_fd <= PJ_IOQUEUE_MAX_HANDLES, PJ_EINVAL); /* Check that size of pj_ioqueue_op_key_t is sufficient */ PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >= sizeof(union operation_key), PJ_EBUG); /* Create and init common ioqueue stuffs */ ioqueue = PJ_POOL_ALLOC_T(pool, pj_ioqueue_t); ioqueue_init(ioqueue); ioqueue->max = max_fd; ioqueue->count = 0; PJ_FD_ZERO(&ioqueue->rfdset); PJ_FD_ZERO(&ioqueue->wfdset); #if PJ_HAS_TCP PJ_FD_ZERO(&ioqueue->xfdset); #endif pj_list_init(&ioqueue->active_list); rescan_fdset(ioqueue); #if PJ_IOQUEUE_HAS_SAFE_UNREG /* When safe unregistration is used (the default), we pre-create * all keys and put them in the free list. */ /* Mutex to protect key's reference counter * We don't want to use key's mutex or ioqueue's mutex because * that would create deadlock situation in some cases. */ rc = pj_mutex_create_simple(pool, NULL, &ioqueue->ref_cnt_mutex); if (rc != PJ_SUCCESS) return rc; /* Init key list */ pj_list_init(&ioqueue->free_list); pj_list_init(&ioqueue->closing_list); /* Pre-create all keys according to max_fd */ for (i=0; i<max_fd; ++i) { pj_ioqueue_key_t *key; key = PJ_POOL_ALLOC_T(pool, pj_ioqueue_key_t); key->ref_count = 0; rc = pj_mutex_create_recursive(pool, NULL, &key->mutex); if (rc != PJ_SUCCESS) { key = ioqueue->free_list.next; while (key != &ioqueue->free_list) { pj_mutex_destroy(key->mutex); key = key->next; } pj_mutex_destroy(ioqueue->ref_cnt_mutex); return rc; } pj_list_push_back(&ioqueue->free_list, key); } #endif /* Create and init ioqueue mutex */ rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock); if (rc != PJ_SUCCESS) return rc; rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE); if (rc != PJ_SUCCESS) return rc; PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioqueue)); *p_ioqueue = ioqueue; return PJ_SUCCESS; }
/* * Create the resolver. */ PJ_DEF(pj_status_t) pj_dns_resolver_create( pj_pool_factory *pf, const char *name, unsigned options, pj_timer_heap_t *timer, pj_ioqueue_t *ioqueue, pj_dns_resolver **p_resolver) { pj_pool_t *pool; pj_dns_resolver *resv; pj_ioqueue_callback socket_cb; pj_status_t status; /* Sanity check */ PJ_ASSERT_RETURN(pf && p_resolver, PJ_EINVAL); if (name == NULL) name = THIS_FILE; /* Create and initialize resolver instance */ pool = pj_pool_create(pf, name, 4000, 4000, NULL); if (!pool) return PJ_ENOMEM; /* Create pool and name */ resv = PJ_POOL_ZALLOC_T(pool, struct pj_dns_resolver); resv->pool = pool; resv->udp_sock = PJ_INVALID_SOCKET; pj_strdup2_with_null(pool, &resv->name, name); /* Create the mutex */ status = pj_mutex_create_recursive(pool, name, &resv->mutex); if (status != PJ_SUCCESS) goto on_error; /* Timer, ioqueue, and settings */ resv->timer = timer; resv->ioqueue = ioqueue; resv->last_id = 1; pj_dns_settings_default(&resv->settings); resv->settings.options = options; /* Create the timer heap if one is not specified */ if (resv->timer == NULL) { status = pj_timer_heap_create(pool, TIMER_SIZE, &resv->timer); if (status != PJ_SUCCESS) goto on_error; } /* Create the ioqueue if one is not specified */ if (resv->ioqueue == NULL) { status = pj_ioqueue_create(pool, MAX_FD, &resv->ioqueue); if (status != PJ_SUCCESS) goto on_error; } /* Response cache hash table */ resv->hrescache = pj_hash_create(pool, RES_HASH_TABLE_SIZE); /* Query hash table and free list. */ resv->hquerybyid = pj_hash_create(pool, Q_HASH_TABLE_SIZE); resv->hquerybyres = pj_hash_create(pool, Q_HASH_TABLE_SIZE); pj_list_init(&resv->query_free_nodes); /* Create the UDP socket */ status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &resv->udp_sock); if (status != PJ_SUCCESS) goto on_error; /* Bind to any address/port */ status = pj_sock_bind_in(resv->udp_sock, 0, 0); if (status != PJ_SUCCESS) goto on_error; /* Register to ioqueue */ pj_bzero(&socket_cb, sizeof(socket_cb)); socket_cb.on_read_complete = &on_read_complete; status = pj_ioqueue_register_sock(pool, resv->ioqueue, resv->udp_sock, resv, &socket_cb, &resv->udp_key); if (status != PJ_SUCCESS) goto on_error; pj_ioqueue_op_key_init(&resv->udp_op_key, sizeof(resv->udp_op_key)); /* Start asynchronous read to the UDP socket */ resv->udp_len = sizeof(resv->udp_rx_pkt); resv->udp_addr_len = sizeof(resv->udp_src_addr); status = pj_ioqueue_recvfrom(resv->udp_key, &resv->udp_op_key, resv->udp_rx_pkt, &resv->udp_len, PJ_IOQUEUE_ALWAYS_ASYNC, &resv->udp_src_addr, &resv->udp_addr_len); if (status != PJ_EPENDING) goto on_error; /* Looks like everything is okay */ *p_resolver = resv; return PJ_SUCCESS; on_error: pj_dns_resolver_destroy(resv, PJ_FALSE); return status; }
/* * pj_ioqueue_create() */ PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, pj_size_t max_fd, pj_ioqueue_t **p_ioqueue) { pj_ioqueue_t *ioqueue; unsigned i; pj_status_t rc; PJ_UNUSED_ARG(max_fd); PJ_ASSERT_RETURN(pool && p_ioqueue, PJ_EINVAL); rc = sizeof(union operation_key); /* Check that sizeof(pj_ioqueue_op_key_t) makes sense. */ PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >= sizeof(union operation_key), PJ_EBUG); /* Create IOCP */ ioqueue = pj_pool_zalloc(pool, sizeof(*ioqueue)); ioqueue->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); if (ioqueue->iocp == NULL) return PJ_RETURN_OS_ERROR(GetLastError()); /* Create IOCP mutex */ rc = pj_lock_create_recursive_mutex(pool, NULL, &ioqueue->lock); if (rc != PJ_SUCCESS) { CloseHandle(ioqueue->iocp); return rc; } ioqueue->auto_delete_lock = PJ_TRUE; ioqueue->default_concurrency = PJ_IOQUEUE_DEFAULT_ALLOW_CONCURRENCY; #if PJ_IOQUEUE_HAS_SAFE_UNREG /* * Create and initialize key pools. */ pj_list_init(&ioqueue->active_list); pj_list_init(&ioqueue->free_list); pj_list_init(&ioqueue->closing_list); /* Preallocate keys according to max_fd setting, and put them * in free_list. */ for (i=0; i<max_fd; ++i) { pj_ioqueue_key_t *key; key = pj_pool_alloc(pool, sizeof(pj_ioqueue_key_t)); rc = pj_atomic_create(pool, 0, &key->ref_count); if (rc != PJ_SUCCESS) { key = ioqueue->free_list.next; while (key != &ioqueue->free_list) { pj_atomic_destroy(key->ref_count); pj_mutex_destroy(key->mutex); key = key->next; } CloseHandle(ioqueue->iocp); return rc; } rc = pj_mutex_create_recursive(pool, "ioqkey", &key->mutex); if (rc != PJ_SUCCESS) { pj_atomic_destroy(key->ref_count); key = ioqueue->free_list.next; while (key != &ioqueue->free_list) { pj_atomic_destroy(key->ref_count); pj_mutex_destroy(key->mutex); key = key->next; } CloseHandle(ioqueue->iocp); return rc; } pj_list_push_back(&ioqueue->free_list, key); } #endif *p_ioqueue = ioqueue; PJ_LOG(4, ("pjlib", "WinNT IOCP I/O Queue created (%p)", ioqueue)); return PJ_SUCCESS; }
/* * Create the resolver. */ PJ_DEF(pj_status_t) pj_dns_resolver_create( pj_pool_factory *pf, const char *name, unsigned options, pj_timer_heap_t *timer, pj_ioqueue_t *ioqueue, pj_dns_resolver **p_resolver) { pj_pool_t *pool; pj_dns_resolver *resv; pj_status_t status; /* Sanity check */ PJ_ASSERT_RETURN(pf && p_resolver, PJ_EINVAL); if (name == NULL) name = THIS_FILE; /* Create and initialize resolver instance */ pool = pj_pool_create(pf, name, 4000, 4000, NULL); if (!pool) return PJ_ENOMEM; /* Create pool and name */ resv = PJ_POOL_ZALLOC_T(pool, struct pj_dns_resolver); resv->pool = pool; resv->udp_sock = PJ_INVALID_SOCKET; pj_strdup2_with_null(pool, &resv->name, name); /* Create the mutex */ status = pj_mutex_create_recursive(pool, name, &resv->mutex); if (status != PJ_SUCCESS) goto on_error; /* Timer, ioqueue, and settings */ resv->timer = timer; resv->ioqueue = ioqueue; resv->last_id = 1; pj_dns_settings_default(&resv->settings); resv->settings.options = options; /* Create the timer heap if one is not specified */ if (resv->timer == NULL) { status = pj_timer_heap_create(pool, TIMER_SIZE, &resv->timer); if (status != PJ_SUCCESS) goto on_error; } /* Create the ioqueue if one is not specified */ if (resv->ioqueue == NULL) { status = pj_ioqueue_create(pool, MAX_FD, &resv->ioqueue); if (status != PJ_SUCCESS) goto on_error; } /* Response cache hash table */ resv->hrescache = pj_hash_create(pool, RES_HASH_TABLE_SIZE); /* Query hash table and free list. */ resv->hquerybyid = pj_hash_create(pool, Q_HASH_TABLE_SIZE); resv->hquerybyres = pj_hash_create(pool, Q_HASH_TABLE_SIZE); pj_list_init(&resv->query_free_nodes); /* Initialize the UDP socket */ status = init_sock(resv); if (status != PJ_SUCCESS) goto on_error; /* Looks like everything is okay */ *p_resolver = resv; return PJ_SUCCESS; on_error: pj_dns_resolver_destroy(resv, PJ_FALSE); return status; }
/* * pj_ioqueue_create() * * Create select ioqueue. */ PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, pj_size_t max_fd, pj_ioqueue_t **p_ioqueue) { pj_ioqueue_t *ioqueue; pj_status_t rc; pj_lock_t *lock; int i; /* Check that arguments are valid. */ PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL && max_fd > 0, PJ_EINVAL); /* Check that size of pj_ioqueue_op_key_t is sufficient */ PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >= sizeof(union operation_key), PJ_EBUG); ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t)); ioqueue_init(ioqueue); ioqueue->max = max_fd; ioqueue->count = 0; pj_list_init(&ioqueue->active_list); #if PJ_IOQUEUE_HAS_SAFE_UNREG /* When safe unregistration is used (the default), we pre-create * all keys and put them in the free list. */ /* Mutex to protect key's reference counter * We don't want to use key's mutex or ioqueue's mutex because * that would create deadlock situation in some cases. */ rc = pj_mutex_create_simple(pool, NULL, &ioqueue->ref_cnt_mutex); if (rc != PJ_SUCCESS) return rc; /* Init key list */ pj_list_init(&ioqueue->free_list); pj_list_init(&ioqueue->closing_list); /* Pre-create all keys according to max_fd */ for ( i=0; i<max_fd; ++i) { pj_ioqueue_key_t *key; key = PJ_POOL_ALLOC_T(pool, pj_ioqueue_key_t); key->ref_count = 0; rc = pj_mutex_create_recursive(pool, NULL, &key->mutex); if (rc != PJ_SUCCESS) { key = ioqueue->free_list.next; while (key != &ioqueue->free_list) { pj_mutex_destroy(key->mutex); key = key->next; } pj_mutex_destroy(ioqueue->ref_cnt_mutex); return rc; } pj_list_push_back(&ioqueue->free_list, key); } #endif rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock); if (rc != PJ_SUCCESS) return rc; rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE); if (rc != PJ_SUCCESS) return rc; ioqueue->epfd = os_epoll_create(max_fd); if (ioqueue->epfd < 0) { ioqueue_destroy(ioqueue); return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); } /*ioqueue->events = pj_pool_calloc(pool, max_fd, sizeof(struct epoll_event)); PJ_ASSERT_RETURN(ioqueue->events != NULL, PJ_ENOMEM); ioqueue->queue = pj_pool_calloc(pool, max_fd, sizeof(struct queue)); PJ_ASSERT_RETURN(ioqueue->queue != NULL, PJ_ENOMEM); */ PJ_LOG(4, ("pjlib", "epoll I/O Queue created (%p)", ioqueue)); *p_ioqueue = ioqueue; return PJ_SUCCESS; }
PJ_DEF(pj_status_t) pj_stun_detect_nat_type(const pj_sockaddr_in *server, pj_stun_config *stun_cfg, void *user_data, pj_stun_nat_detect_cb *cb) { pj_pool_t *pool; nat_detect_session *sess; pj_stun_session_cb sess_cb; pj_ioqueue_callback ioqueue_cb; int addr_len; pj_status_t status; PJ_ASSERT_RETURN(server && stun_cfg, PJ_EINVAL); PJ_ASSERT_RETURN(stun_cfg->pf && stun_cfg->ioqueue && stun_cfg->timer_heap, PJ_EINVAL); /* * Init NAT detection session. */ pool = pj_pool_create(stun_cfg->pf, "natck%p", PJNATH_POOL_LEN_NATCK, PJNATH_POOL_INC_NATCK, NULL); if (!pool) return PJ_ENOMEM; sess = PJ_POOL_ZALLOC_T(pool, nat_detect_session); sess->pool = pool; sess->user_data = user_data; sess->cb = cb; status = pj_mutex_create_recursive(pool, pool->obj_name, &sess->mutex); if (status != PJ_SUCCESS) goto on_error; pj_memcpy(&sess->server, server, sizeof(pj_sockaddr_in)); /* * Init timer to self-destroy. */ sess->timer_heap = stun_cfg->timer_heap; sess->timer.cb = &on_sess_timer; sess->timer.user_data = sess; /* * Initialize socket. */ status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sess->sock); if (status != PJ_SUCCESS) goto on_error; /* * Bind to any. */ pj_bzero(&sess->local_addr, sizeof(pj_sockaddr_in)); sess->local_addr.sin_family = pj_AF_INET(); status = pj_sock_bind(sess->sock, &sess->local_addr, sizeof(pj_sockaddr_in)); if (status != PJ_SUCCESS) goto on_error; /* * Get local/bound address. */ addr_len = sizeof(sess->local_addr); status = pj_sock_getsockname(sess->sock, &sess->local_addr, &addr_len); if (status != PJ_SUCCESS) goto on_error; /* * Find out which interface is used to send to the server. */ status = get_local_interface(server, &sess->local_addr.sin_addr); if (status != PJ_SUCCESS) goto on_error; PJ_LOG(5,(sess->pool->obj_name, "Local address is %s:%d", pj_inet_ntoa(sess->local_addr.sin_addr), pj_ntohs(sess->local_addr.sin_port))); PJ_LOG(5,(sess->pool->obj_name, "Server set to %s:%d", pj_inet_ntoa(server->sin_addr), pj_ntohs(server->sin_port))); /* * Register socket to ioqueue to receive asynchronous input * notification. */ pj_bzero(&ioqueue_cb, sizeof(ioqueue_cb)); ioqueue_cb.on_read_complete = &on_read_complete; status = pj_ioqueue_register_sock(sess->pool, stun_cfg->ioqueue, sess->sock, sess, &ioqueue_cb, &sess->key); if (status != PJ_SUCCESS) goto on_error; /* * Create STUN session. */ pj_bzero(&sess_cb, sizeof(sess_cb)); sess_cb.on_request_complete = &on_request_complete; sess_cb.on_send_msg = &on_send_msg; status = pj_stun_session_create(stun_cfg, pool->obj_name, &sess_cb, PJ_FALSE, NULL, &sess->stun_sess); if (status != PJ_SUCCESS) goto on_error; pj_stun_session_set_user_data(sess->stun_sess, sess); /* * Kick-off ioqueue reading. */ pj_ioqueue_op_key_init(&sess->read_op, sizeof(sess->read_op)); pj_ioqueue_op_key_init(&sess->write_op, sizeof(sess->write_op)); on_read_complete(sess->key, &sess->read_op, 0); /* * Start TEST_1 */ sess->timer.id = TIMER_TEST; on_sess_timer(stun_cfg->timer_heap, &sess->timer); return PJ_SUCCESS; on_error: sess_destroy(sess); return status; }
/* * pj_thread_create(...) */ PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, const char *thread_name, pj_thread_proc *proc, void *arg, pj_size_t stack_size, unsigned flags, pj_thread_t **ptr_thread) { #if PJ_HAS_THREADS pj_thread_t *rec; pthread_attr_t thread_attr; void *stack_addr; int rc; PJ_UNUSED_ARG(stack_addr); PJ_CHECK_STACK(); PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL); /* Create thread record and assign name for the thread */ rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t)); PJ_ASSERT_RETURN(rec, PJ_ENOMEM); /* Set name. */ if (!thread_name) thread_name = "thr%p"; if (strchr(thread_name, '%')) { pj_ansi_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec); } else { strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME); rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; } /* Set default stack size */ if (stack_size == 0) stack_size = PJ_THREAD_DEFAULT_STACK_SIZE; #if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 rec->stk_size = stack_size; rec->stk_max_usage = 0; #endif /* Emulate suspended thread with mutex. */ if (flags & PJ_THREAD_SUSPENDED) { rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex); if (rc != PJ_SUCCESS) { return rc; } pj_mutex_lock(rec->suspended_mutex); } else { pj_assert(rec->suspended_mutex == NULL); } /* * Create wait mutex because thread can be run before as * pthread_create() set thread ID */ rc = pj_mutex_create_recursive(pool, NULL, &rec->wait_mutex); if (rc != PJ_SUCCESS) return rc; /* Init thread attributes */ pthread_attr_init(&thread_attr); #if defined(PJ_THREAD_SET_STACK_SIZE) && PJ_THREAD_SET_STACK_SIZE!=0 /* Set thread's stack size */ rc = pthread_attr_setstacksize(&thread_attr, stack_size); if (rc != 0) return PJ_RETURN_OS_ERROR(rc); #endif /* PJ_THREAD_SET_STACK_SIZE */ #if defined(PJ_THREAD_ALLOCATE_STACK) && PJ_THREAD_ALLOCATE_STACK!=0 /* Allocate memory for the stack */ stack_addr = pj_pool_alloc(pool, stack_size); PJ_ASSERT_RETURN(stack_addr, PJ_ENOMEM); rc = pthread_attr_setstackaddr(&thread_attr, stack_addr); if (rc != 0) return PJ_RETURN_OS_ERROR(rc); #endif /* PJ_THREAD_ALLOCATE_STACK */ /* Create the thread. */ rec->proc = proc; rec->arg = arg; rc = pthread_create( &rec->thread, &thread_attr, &thread_main, rec); if (rc != 0) { return PJ_RETURN_OS_ERROR(rc); } /* unlock new thread... now thread ID is set*/ if (rec->wait_mutex->owner == pj_thread_this()) pj_mutex_unlock(rec->wait_mutex); *ptr_thread = rec; PJ_LOG(6, (rec->obj_name, "Thread created")); return PJ_SUCCESS; #else pj_assert(!"Threading is disabled!"); return PJ_EINVALIDOP; #endif }