/* Register socket to ioqueue */ static pj_status_t register_to_ioqueue(struct udp_transport *tp) { pj_ioqueue_t *ioqueue; pj_ioqueue_callback ioqueue_cb; pj_status_t status; /* Ignore if already registered */ if (tp->key != NULL) return PJ_SUCCESS; /* Create group lock */ status = pj_grp_lock_create(tp->base.pool, NULL, &tp->grp_lock); if (status != PJ_SUCCESS) return status; pj_grp_lock_add_ref(tp->grp_lock); pj_grp_lock_add_handler(tp->grp_lock, tp->base.pool, tp, &udp_on_destroy); /* Register to ioqueue. */ ioqueue = pjsip_endpt_get_ioqueue(tp->base.endpt); pj_memset(&ioqueue_cb, 0, sizeof(ioqueue_cb)); ioqueue_cb.on_read_complete = &udp_on_read_complete; ioqueue_cb.on_write_complete = &udp_on_write_complete; return pj_ioqueue_register_sock2(tp->base.pool, ioqueue, tp->sock, tp->grp_lock, tp, &ioqueue_cb, &tp->key); }
PJ_DEF(pj_status_t) pj_activesock_create( pj_pool_t *pool, pj_sock_t sock, int sock_type, const pj_activesock_cfg *opt, pj_ioqueue_t *ioqueue, const pj_activesock_cb *cb, void *user_data, pj_activesock_t **p_asock) { pj_activesock_t *asock; pj_ioqueue_callback ioq_cb; pj_status_t status; PJ_ASSERT_RETURN(pool && ioqueue && cb && p_asock, PJ_EINVAL); PJ_ASSERT_RETURN(sock!=0 && sock!=PJ_INVALID_SOCKET, PJ_EINVAL); PJ_ASSERT_RETURN(sock_type==pj_SOCK_STREAM() || sock_type==pj_SOCK_DGRAM(), PJ_EINVAL); PJ_ASSERT_RETURN(!opt || opt->async_cnt >= 1, PJ_EINVAL); asock = PJ_POOL_ZALLOC_T(pool, pj_activesock_t); asock->ioqueue = ioqueue; asock->stream_oriented = (sock_type == pj_SOCK_STREAM()); asock->async_count = (opt? opt->async_cnt : 1); asock->whole_data = (opt? opt->whole_data : 1); asock->max_loop = PJ_ACTIVESOCK_MAX_LOOP; asock->user_data = user_data; pj_memcpy(&asock->cb, cb, sizeof(*cb)); pj_bzero(&ioq_cb, sizeof(ioq_cb)); ioq_cb.on_read_complete = &ioqueue_on_read_complete; ioq_cb.on_write_complete = &ioqueue_on_write_complete; #if PJ_HAS_TCP ioq_cb.on_connect_complete = &ioqueue_on_connect_complete; ioq_cb.on_accept_complete = &ioqueue_on_accept_complete; #endif status = pj_ioqueue_register_sock2(pool, ioqueue, sock, (opt? opt->grp_lock : NULL), asock, &ioq_cb, &asock->key); if (status != PJ_SUCCESS) { pj_activesock_close(asock); return status; } if (asock->whole_data) { /* Must disable concurrency otherwise there is a race condition */ pj_ioqueue_set_concurrency(asock->key, 0); } else if (opt && opt->concurrency >= 0) { pj_ioqueue_set_concurrency(asock->key, opt->concurrency); } #if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \ PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0 asock->sock = sock; asock->bg_setting = PJ_ACTIVESOCK_TCP_IPHONE_OS_BG; #endif *p_asock = asock; return PJ_SUCCESS; }
PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool, pj_ioqueue_t *ioqueue, pj_sock_t sock, void *user_data, const pj_ioqueue_callback *cb, pj_ioqueue_key_t **p_key) { return pj_ioqueue_register_sock2(pool, ioqueue, sock, NULL, user_data, cb, p_key); }
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_grp_lock_create(pool, NULL, &sess->grp_lock); if (status != PJ_SUCCESS) { /* Group lock not created yet, just destroy pool and return */ pj_pool_release(pool); return status; } pj_grp_lock_add_ref(sess->grp_lock); pj_grp_lock_add_handler(sess->grp_lock, pool, sess, &sess_on_destroy); 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_sock2(sess->pool, stun_cfg->ioqueue, sess->sock, sess->grp_lock, 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, sess->grp_lock, &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; }