/* Destroy */ PJ_DEF(pj_status_t) pj_stun_sock_destroy(pj_stun_sock *stun_sock) { TRACE_((stun_sock->obj_name, "STUN sock %p request, ref_cnt=%d", stun_sock, pj_grp_lock_get_ref(stun_sock->grp_lock))); pj_grp_lock_acquire(stun_sock->grp_lock); if (stun_sock->is_destroying) { /* Destroy already called */ pj_grp_lock_release(stun_sock->grp_lock); return PJ_EINVALIDOP; } stun_sock->is_destroying = PJ_TRUE; pj_timer_heap_cancel_if_active(stun_sock->stun_cfg.timer_heap, &stun_sock->ka_timer, 0); if (stun_sock->stun_sess) { pj_stun_session_set_user_data(stun_sock->stun_sess, NULL); } /* Destroy the active socket first just in case we'll get * stray callback. */ if (stun_sock->active_sock != NULL) { pj_activesock_t *asock = stun_sock->active_sock; stun_sock->active_sock = NULL; stun_sock->sock_fd = PJ_INVALID_SOCKET; pj_activesock_set_user_data(asock, NULL); pj_activesock_close(asock); } else if (stun_sock->sock_fd != PJ_INVALID_SOCKET) { pj_sock_close(stun_sock->sock_fd); stun_sock->sock_fd = PJ_INVALID_SOCKET; } if (stun_sock->stun_sess) { pj_stun_session_destroy(stun_sock->stun_sess); stun_sock->stun_sess = NULL; } pj_grp_lock_dec_ref(stun_sock->grp_lock); pj_grp_lock_release(stun_sock->grp_lock); return PJ_SUCCESS; }
/* * Create new allocation. */ PJ_DEF(pj_status_t) pj_turn_allocation_create(pj_turn_transport *transport, const pj_sockaddr_t *src_addr, unsigned src_addr_len, const pj_stun_rx_data *rdata, pj_stun_session *srv_sess, pj_turn_allocation **p_alloc) { pj_turn_srv *srv = transport->listener->server; const pj_stun_msg *msg = rdata->msg; pj_pool_t *pool; alloc_request req; pj_turn_allocation *alloc; pj_stun_session_cb sess_cb; char str_tmp[80]; pj_status_t status; /* Parse ALLOCATE request */ status = parse_allocate_req(&req, srv_sess, rdata, src_addr, src_addr_len); if (status != PJ_SUCCESS) return status; pool = pj_pool_create(srv->core.pf, "alloc%p", 1000, 1000, NULL); /* Init allocation structure */ alloc = PJ_POOL_ZALLOC_T(pool, pj_turn_allocation); alloc->pool = pool; alloc->obj_name = pool->obj_name; alloc->relay.tp.sock = PJ_INVALID_SOCKET; alloc->server = transport->listener->server; alloc->bandwidth = req.bandwidth; /* Set transport */ alloc->transport = transport; pj_turn_transport_add_ref(transport, alloc); alloc->hkey.tp_type = transport->listener->tp_type; pj_memcpy(&alloc->hkey.clt_addr, src_addr, src_addr_len); status = pj_lock_create_recursive_mutex(pool, alloc->obj_name, &alloc->lock); if (status != PJ_SUCCESS) { goto on_error; } /* Create peer hash table */ alloc->peer_table = pj_hash_create(pool, PEER_TABLE_SIZE); /* Create channel hash table */ alloc->ch_table = pj_hash_create(pool, PEER_TABLE_SIZE); /* Print info */ pj_ansi_strcpy(alloc->info, pj_turn_tp_type_name(transport->listener->tp_type)); alloc->info[3] = ':'; pj_sockaddr_print(src_addr, alloc->info+4, sizeof(alloc->info)-4, 3); /* Create STUN session to handle STUN communication with client */ pj_bzero(&sess_cb, sizeof(sess_cb)); sess_cb.on_send_msg = &stun_on_send_msg; sess_cb.on_rx_request = &stun_on_rx_request; sess_cb.on_rx_indication = &stun_on_rx_indication; status = pj_stun_session_create(&srv->core.stun_cfg, alloc->obj_name, &sess_cb, PJ_FALSE, NULL, &alloc->sess); if (status != PJ_SUCCESS) { goto on_error; } /* Attach to STUN session */ pj_stun_session_set_user_data(alloc->sess, alloc); /* Init authentication credential */ status = init_cred(alloc, msg); if (status != PJ_SUCCESS) { goto on_error; } /* Attach authentication credential to STUN session */ pj_stun_session_set_credential(alloc->sess, PJ_STUN_AUTH_LONG_TERM, &alloc->cred); /* Create the relay resource */ status = create_relay(srv, alloc, msg, &req, &alloc->relay); if (status != PJ_SUCCESS) { goto on_error; } /* Register this allocation */ pj_turn_srv_register_allocation(srv, alloc); /* Respond to ALLOCATE request */ status = send_allocate_response(alloc, srv_sess, transport, rdata); if (status != PJ_SUCCESS) goto on_error; /* Done */ pj_sockaddr_print(&alloc->relay.hkey.addr, str_tmp, sizeof(str_tmp), 3); PJ_LOG(4,(alloc->obj_name, "Client %s created, relay addr=%s:%s", alloc->info, pj_turn_tp_type_name(req.tp_type), str_tmp)); /* Success */ *p_alloc = alloc; return PJ_SUCCESS; on_error: /* Send reply to the ALLOCATE request */ pj_strerror(status, str_tmp, sizeof(str_tmp)); pj_stun_session_respond(srv_sess, rdata, PJ_STUN_SC_BAD_REQUEST, str_tmp, transport, PJ_TRUE, src_addr, src_addr_len); /* Cleanup */ destroy_allocation(alloc); return status; }
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; }
/* * Create the STUN transport using the specified configuration. */ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg, const char *name, int af, const pj_stun_sock_cb *cb, const pj_stun_sock_cfg *cfg, void *user_data, pj_stun_sock **p_stun_sock) { pj_pool_t *pool; pj_stun_sock *stun_sock; pj_stun_sock_cfg default_cfg; unsigned i; pj_status_t status; PJ_ASSERT_RETURN(stun_cfg && cb && p_stun_sock, PJ_EINVAL); PJ_ASSERT_RETURN(af==pj_AF_INET()||af==pj_AF_INET6(), PJ_EAFNOTSUP); PJ_ASSERT_RETURN(!cfg || pj_stun_sock_cfg_is_valid(cfg), PJ_EINVAL); PJ_ASSERT_RETURN(cb->on_status, PJ_EINVAL); status = pj_stun_config_check_valid(stun_cfg); if (status != PJ_SUCCESS) return status; if (name == NULL) name = "stuntp%p"; if (cfg == NULL) { pj_stun_sock_cfg_default(&default_cfg); cfg = &default_cfg; } /* Create structure */ pool = pj_pool_create(stun_cfg->pf, name, 256, 512, NULL); stun_sock = PJ_POOL_ZALLOC_T(pool, pj_stun_sock); stun_sock->pool = pool; stun_sock->obj_name = pool->obj_name; stun_sock->user_data = user_data; stun_sock->af = af; stun_sock->sock_fd = PJ_INVALID_SOCKET; pj_memcpy(&stun_sock->stun_cfg, stun_cfg, sizeof(*stun_cfg)); pj_memcpy(&stun_sock->cb, cb, sizeof(*cb)); stun_sock->ka_interval = cfg->ka_interval; if (stun_sock->ka_interval == 0) stun_sock->ka_interval = PJ_STUN_KEEP_ALIVE_SEC; /* Create socket and bind socket */ status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &stun_sock->sock_fd); if (status != PJ_SUCCESS) goto on_error; /* Apply QoS, if specified */ status = pj_sock_apply_qos2(stun_sock->sock_fd, cfg->qos_type, &cfg->qos_params, 2, stun_sock->obj_name, NULL); if (status != PJ_SUCCESS && !cfg->qos_ignore_error) goto on_error; /* Bind socket */ if (pj_sockaddr_has_addr(&cfg->bound_addr)) { status = pj_sock_bind(stun_sock->sock_fd, &cfg->bound_addr, pj_sockaddr_get_len(&cfg->bound_addr)); } else { pj_sockaddr bound_addr; pj_sockaddr_init(af, &bound_addr, NULL, 0); status = pj_sock_bind(stun_sock->sock_fd, &bound_addr, pj_sockaddr_get_len(&bound_addr)); } if (status != PJ_SUCCESS) goto on_error; /* Create more useful information string about this transport */ #if 0 { pj_sockaddr bound_addr; int addr_len = sizeof(bound_addr); status = pj_sock_getsockname(stun_sock->sock_fd, &bound_addr, &addr_len); if (status != PJ_SUCCESS) goto on_error; stun_sock->info = pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN+10); pj_sockaddr_print(&bound_addr, stun_sock->info, PJ_INET6_ADDRSTRLEN, 3); } #endif /* Init active socket configuration */ { pj_activesock_cfg activesock_cfg; pj_activesock_cb activesock_cb; pj_activesock_cfg_default(&activesock_cfg); activesock_cfg.async_cnt = cfg->async_cnt; activesock_cfg.concurrency = 0; /* Create the active socket */ pj_bzero(&activesock_cb, sizeof(activesock_cb)); activesock_cb.on_data_recvfrom = &on_data_recvfrom; activesock_cb.on_data_sent = &on_data_sent; status = pj_activesock_create(pool, stun_sock->sock_fd, pj_SOCK_DGRAM(), &activesock_cfg, stun_cfg->ioqueue, &activesock_cb, stun_sock, &stun_sock->active_sock); if (status != PJ_SUCCESS) goto on_error; /* Start asynchronous read operations */ status = pj_activesock_start_recvfrom(stun_sock->active_sock, pool, cfg->max_pkt_size, 0); if (status != PJ_SUCCESS) goto on_error; /* Init send keys */ pj_ioqueue_op_key_init(&stun_sock->send_key, sizeof(stun_sock->send_key)); pj_ioqueue_op_key_init(&stun_sock->int_send_key, sizeof(stun_sock->int_send_key)); } /* Create STUN session */ { pj_stun_session_cb sess_cb; pj_bzero(&sess_cb, sizeof(sess_cb)); sess_cb.on_request_complete = &sess_on_request_complete; sess_cb.on_send_msg = &sess_on_send_msg; status = pj_stun_session_create(&stun_sock->stun_cfg, stun_sock->obj_name, &sess_cb, PJ_FALSE, &stun_sock->stun_sess); if (status != PJ_SUCCESS) goto on_error; } /* Associate us with the STUN session */ pj_stun_session_set_user_data(stun_sock->stun_sess, stun_sock); /* Initialize random numbers to be used as STUN transaction ID for * outgoing Binding request. We use the 80bit number to distinguish * STUN messages we sent with STUN messages that the application sends. * The last 16bit value in the array is a counter. */ for (i=0; i<PJ_ARRAY_SIZE(stun_sock->tsx_id); ++i) { stun_sock->tsx_id[i] = (pj_uint16_t) pj_rand(); } stun_sock->tsx_id[5] = 0; /* Init timer entry */ stun_sock->ka_timer.cb = &ka_timer_cb; stun_sock->ka_timer.user_data = stun_sock; /* Done */ *p_stun_sock = stun_sock; return PJ_SUCCESS; on_error: pj_stun_sock_destroy(stun_sock); return status; }
/* * Create the STUN transport using the specified configuration. */ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg, const char *name, int af, const pj_stun_sock_cb *cb, const pj_stun_sock_cfg *cfg, void *user_data, pj_stun_sock **p_stun_sock) { pj_pool_t *pool; pj_stun_sock *stun_sock; pj_stun_sock_cfg default_cfg; pj_sockaddr bound_addr; unsigned i; pj_uint16_t max_bind_retry; pj_status_t status; PJ_ASSERT_RETURN(stun_cfg && cb && p_stun_sock, PJ_EINVAL); PJ_ASSERT_RETURN(af==pj_AF_INET()||af==pj_AF_INET6(), PJ_EAFNOTSUP); PJ_ASSERT_RETURN(!cfg || pj_stun_sock_cfg_is_valid(cfg), PJ_EINVAL); PJ_ASSERT_RETURN(cb->on_status, PJ_EINVAL); status = pj_stun_config_check_valid(stun_cfg); if (status != PJ_SUCCESS) return status; if (name == NULL) name = "stuntp%p"; if (cfg == NULL) { pj_stun_sock_cfg_default(&default_cfg); cfg = &default_cfg; } /* Create structure */ pool = pj_pool_create(stun_cfg->pf, name, 256, 512, NULL); stun_sock = PJ_POOL_ZALLOC_T(pool, pj_stun_sock); stun_sock->pool = pool; stun_sock->obj_name = pool->obj_name; stun_sock->user_data = user_data; stun_sock->af = af; stun_sock->sock_fd = PJ_INVALID_SOCKET; pj_memcpy(&stun_sock->stun_cfg, stun_cfg, sizeof(*stun_cfg)); pj_memcpy(&stun_sock->cb, cb, sizeof(*cb)); stun_sock->ka_interval = cfg->ka_interval; stun_sock->timerstat = cfg->timerstat; if (stun_sock->ka_interval == 0) stun_sock->ka_interval = PJ_STUN_KEEP_ALIVE_SEC; printf(": cfg->stunProtocol=%d\n", cfg->stunProtocol); printf("%s", cfg->timerstat ? "SBR keepalive enabled\n": "SBR keepalive disabled\n"); if (cfg->grp_lock) { stun_sock->grp_lock = cfg->grp_lock; } else { status = pj_grp_lock_create(pool, NULL, &stun_sock->grp_lock); if (status != PJ_SUCCESS) { pj_pool_release(pool); return status; } } pj_grp_lock_add_ref(stun_sock->grp_lock); pj_grp_lock_add_handler(stun_sock->grp_lock, pool, stun_sock, &stun_sock_destructor); /* Create socket and bind socket */ // status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &stun_sock->sock_fd); if(cfg->stunProtocol == 1) status = pj_sock_socket(af, PJ_SOCK_STREAM, 0, &stun_sock->sock_fd); else status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &stun_sock->sock_fd); if (status != PJ_SUCCESS) goto on_error; /* Apply QoS, if specified */ status = pj_sock_apply_qos2(stun_sock->sock_fd, cfg->qos_type, &cfg->qos_params, 2, stun_sock->obj_name, NULL); if (status != PJ_SUCCESS && !cfg->qos_ignore_error) goto on_error; /* Apply socket buffer size */ if (cfg->so_rcvbuf_size > 0) { unsigned sobuf_size = cfg->so_rcvbuf_size; status = pj_sock_setsockopt_sobuf(stun_sock->sock_fd, pj_SO_RCVBUF(), PJ_TRUE, &sobuf_size); if (status != PJ_SUCCESS) { pj_perror(3, stun_sock->obj_name, status, "Failed setting SO_RCVBUF"); } else { if (sobuf_size < cfg->so_rcvbuf_size) { PJ_LOG(4, (stun_sock->obj_name, "Warning! Cannot set SO_RCVBUF as configured, " "now=%d, configured=%d", sobuf_size, cfg->so_rcvbuf_size)); } else { PJ_LOG(5, (stun_sock->obj_name, "SO_RCVBUF set to %d", sobuf_size)); } } } if (cfg->so_sndbuf_size > 0) { unsigned sobuf_size = cfg->so_sndbuf_size; status = pj_sock_setsockopt_sobuf(stun_sock->sock_fd, pj_SO_SNDBUF(), PJ_TRUE, &sobuf_size); if (status != PJ_SUCCESS) { pj_perror(3, stun_sock->obj_name, status, "Failed setting SO_SNDBUF"); } else { if (sobuf_size < cfg->so_sndbuf_size) { PJ_LOG(4, (stun_sock->obj_name, "Warning! Cannot set SO_SNDBUF as configured, " "now=%d, configured=%d", sobuf_size, cfg->so_sndbuf_size)); } else { PJ_LOG(5, (stun_sock->obj_name, "SO_SNDBUF set to %d", sobuf_size)); } } } #if 1 /* Bind socket */ max_bind_retry = MAX_BIND_RETRY; if (cfg->port_range && cfg->port_range < max_bind_retry) max_bind_retry = cfg->port_range; pj_sockaddr_init(af, &bound_addr, NULL, 0); if (cfg->bound_addr.addr.sa_family == pj_AF_INET() || cfg->bound_addr.addr.sa_family == pj_AF_INET6()) { pj_sockaddr_cp(&bound_addr, &cfg->bound_addr); } status = pj_sock_bind_random(stun_sock->sock_fd, &bound_addr, cfg->port_range, max_bind_retry); if (status != PJ_SUCCESS) goto on_error; #endif /* Create more useful information string about this transport */ #if 0 { pj_sockaddr bound_addr; int addr_len = sizeof(bound_addr); status = pj_sock_getsockname(stun_sock->sock_fd, &bound_addr, &addr_len); if (status != PJ_SUCCESS) goto on_error; stun_sock->info = pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN+10); pj_sockaddr_print(&bound_addr, stun_sock->info, PJ_INET6_ADDRSTRLEN, 3); } #endif /* Init active socket configuration */ { pj_activesock_cfg activesock_cfg; pj_activesock_cb activesock_cb; pj_activesock_cfg_default(&activesock_cfg); activesock_cfg.grp_lock = stun_sock->grp_lock; activesock_cfg.async_cnt = cfg->async_cnt; activesock_cfg.concurrency = 0; /* Create the active socket */ pj_bzero(&activesock_cb, sizeof(activesock_cb)); activesock_cb.on_data_recvfrom = &on_data_recvfrom; activesock_cb.on_data_sent = &on_data_sent; if(cfg->stunProtocol == 1) { status = pj_activesock_create(pool, stun_sock->sock_fd, PJ_SOCK_STREAM, &activesock_cfg, stun_cfg->ioqueue, &activesock_cb, stun_sock, &stun_sock->active_sock); } else { status = pj_activesock_create(pool, stun_sock->sock_fd, pj_SOCK_DGRAM(), //nish &activesock_cfg, stun_cfg->ioqueue, &activesock_cb, stun_sock, &stun_sock->active_sock); } if (status != PJ_SUCCESS) goto on_error; if(cfg->stunProtocol == 1) { stun_sock->srv_addr.addr.sa_family = AF_INET; stun_sock->srv_addr.ipv4.sin_port= pj_htons(cfg->sin_port); stun_sock->srv_addr.ipv4.sin_addr = (cfg->sin_addr); status=pj_activesock_start_connect(stun_sock->active_sock, pool, &(stun_sock->srv_addr), pj_sockaddr_get_len(&(stun_sock->srv_addr))); if (status == PJ_SUCCESS) { printf("actie sock connect succesful"); } } /* Start asynchronous read operations */ status = pj_activesock_start_recvfrom(stun_sock->active_sock, pool, cfg->max_pkt_size, 0); if (status != PJ_SUCCESS) goto on_error; /* Init send keys */ pj_ioqueue_op_key_init(&stun_sock->send_key, sizeof(stun_sock->send_key)); pj_ioqueue_op_key_init(&stun_sock->int_send_key, sizeof(stun_sock->int_send_key)); } /* Create STUN session */ { pj_stun_session_cb sess_cb; pj_bzero(&sess_cb, sizeof(sess_cb)); sess_cb.on_request_complete = &sess_on_request_complete; sess_cb.on_send_msg = &sess_on_send_msg; // stun_sock->stunProtocol = 1; //FIXME: cfg->stunProtocol; // stun_sock->stunProtocol = 0; //FIXME: cfg->stunProtocol; printf(" stun_sock->stunProtocol=%d\n", stun_sock->stunProtocol); status = pj_stun_session_create(&stun_sock->stun_cfg, stun_sock->obj_name, &sess_cb, PJ_FALSE, stun_sock->grp_lock, &stun_sock->stun_sess); if (status != PJ_SUCCESS) goto on_error; } /* Associate us with the STUN session */ pj_stun_session_set_user_data(stun_sock->stun_sess, stun_sock); /* Initialize random numbers to be used as STUN transaction ID for * outgoing Binding request. We use the 80bit number to distinguish * STUN messages we sent with STUN messages that the application sends. * The last 16bit value in the array is a counter. */ for (i=0; i<PJ_ARRAY_SIZE(stun_sock->tsx_id); ++i) { stun_sock->tsx_id[i] = (pj_uint16_t) pj_rand(); } stun_sock->tsx_id[5] = 0; /* Init timer entry */ stun_sock->ka_timer.cb = &ka_timer_cb; stun_sock->ka_timer.user_data = stun_sock; /* Done */ *p_stun_sock = stun_sock; return PJ_SUCCESS; on_error: pj_stun_sock_destroy(stun_sock); return status; }
/* * Create server. */ PJ_DEF(pj_status_t) pj_turn_srv_create(pj_pool_factory *pf, pj_turn_srv **p_srv) { pj_pool_t *pool; pj_stun_session_cb sess_cb; pj_turn_srv *srv; unsigned i; pj_status_t status; PJ_ASSERT_RETURN(pf && p_srv, PJ_EINVAL); /* Create server and init core settings */ pool = pj_pool_create(pf, "srv%p", 1000, 1000, NULL); srv = PJ_POOL_ZALLOC_T(pool, pj_turn_srv); srv->obj_name = pool->obj_name; srv->core.pf = pf; srv->core.pool = pool; srv->core.tls_key = srv->core.tls_data = -1; /* Create ioqueue */ status = pj_ioqueue_create(pool, MAX_HANDLES, &srv->core.ioqueue); if (status != PJ_SUCCESS) goto on_error; /* Server mutex */ status = pj_lock_create_recursive_mutex(pool, srv->obj_name, &srv->core.lock); if (status != PJ_SUCCESS) goto on_error; /* Allocate TLS */ status = pj_thread_local_alloc(&srv->core.tls_key); if (status != PJ_SUCCESS) goto on_error; status = pj_thread_local_alloc(&srv->core.tls_data); if (status != PJ_SUCCESS) goto on_error; /* Create timer heap */ status = pj_timer_heap_create(pool, MAX_TIMER, &srv->core.timer_heap); if (status != PJ_SUCCESS) goto on_error; /* Configure lock for the timer heap */ pj_timer_heap_set_lock(srv->core.timer_heap, srv->core.lock, PJ_FALSE); /* Array of listeners */ srv->core.listener = (pj_turn_listener**) pj_pool_calloc(pool, MAX_LISTENERS, sizeof(srv->core.listener[0])); /* Create hash tables */ srv->tables.alloc = pj_hash_create(pool, MAX_CLIENTS); srv->tables.res = pj_hash_create(pool, MAX_CLIENTS); /* Init ports settings */ srv->ports.min_udp = srv->ports.next_udp = MIN_PORT; srv->ports.max_udp = MAX_PORT; srv->ports.min_tcp = srv->ports.next_tcp = MIN_PORT; srv->ports.max_tcp = MAX_PORT; /* Init STUN config */ pj_stun_config_init(&srv->core.stun_cfg, pf, 0, srv->core.ioqueue, srv->core.timer_heap); /* Init STUN credential */ srv->core.cred.type = PJ_STUN_AUTH_CRED_DYNAMIC; srv->core.cred.data.dyn_cred.user_data = srv; srv->core.cred.data.dyn_cred.get_auth = &pj_turn_get_auth; srv->core.cred.data.dyn_cred.get_password = &pj_turn_get_password; srv->core.cred.data.dyn_cred.verify_nonce = &pj_turn_verify_nonce; /* Create STUN session to handle new allocation */ pj_bzero(&sess_cb, sizeof(sess_cb)); sess_cb.on_rx_request = &on_rx_stun_request; sess_cb.on_send_msg = &on_tx_stun_msg; status = pj_stun_session_create(&srv->core.stun_cfg, srv->obj_name, &sess_cb, PJ_FALSE, NULL, &srv->core.stun_sess); if (status != PJ_SUCCESS) { goto on_error; } pj_stun_session_set_user_data(srv->core.stun_sess, srv); pj_stun_session_set_credential(srv->core.stun_sess, PJ_STUN_AUTH_LONG_TERM, &srv->core.cred); /* Array of worker threads */ srv->core.thread_cnt = MAX_THREADS; srv->core.thread = (pj_thread_t**) pj_pool_calloc(pool, srv->core.thread_cnt, sizeof(pj_thread_t*)); /* Start the worker threads */ for (i=0; i<srv->core.thread_cnt; ++i) { status = pj_thread_create(pool, srv->obj_name, &server_thread_proc, srv, 0, 0, &srv->core.thread[i]); if (status != PJ_SUCCESS) goto on_error; } /* We're done. Application should add listeners now */ PJ_LOG(4,(srv->obj_name, "TURN server v%s is running", pj_get_version())); *p_srv = srv; return PJ_SUCCESS; on_error: pj_turn_srv_destroy(srv); return status; }
/* * Create TCP client session. */ PJ_DEF(pj_status_t) pj_tcp_session_create( const pj_stun_config *cfg, const char *name, int af, const pj_tcp_session_cb *cb, unsigned options, void *user_data, pj_stun_session *default_stun, pj_tcp_session **p_sess, int sess_idx, int check_idx) { pj_pool_t *pool; pj_tcp_session *sess; pj_stun_session_cb stun_cb; pj_lock_t *null_lock; pj_status_t status; PJ_ASSERT_RETURN(cfg && cfg->pf && cb && p_sess, PJ_EINVAL); PJ_ASSERT_RETURN(cb->on_send_pkt, PJ_EINVAL); PJ_UNUSED_ARG(options); if (name == NULL) name = "tcp%p"; /* Allocate and create TCP session */ pool = pj_pool_create(cfg->pf, name, PJNATH_POOL_LEN_TCP_SESS, PJNATH_POOL_INC_TCP_SESS, NULL); sess = PJ_POOL_ZALLOC_T(pool, pj_tcp_session); sess->pool = pool; sess->obj_name = pool->obj_name; sess->timer_heap = cfg->timer_heap; sess->af = (pj_uint16_t)af; sess->ka_interval = PJ_TCP_KEEP_ALIVE_SEC; sess->user_data = user_data; sess->sess_idx = sess_idx; sess->check_idx = check_idx; /* Copy STUN session */ pj_memcpy(&sess->stun_cfg, cfg, sizeof(pj_stun_config)); /* Copy callback */ pj_memcpy(&sess->cb, cb, sizeof(*cb)); /* Session lock */ status = pj_lock_create_recursive_mutex(pool, sess->obj_name, &sess->lock); if (status != PJ_SUCCESS) { do_destroy(sess); return status; } /* Timer */ pj_timer_entry_init(&sess->timer, TIMER_NONE, sess, &on_timer_event); //DEAN if (default_stun) { sess->stun = default_stun; } else { /* Create STUN session */ pj_bzero(&stun_cb, sizeof(stun_cb)); stun_cb.on_send_msg = &stun_on_send_msg; #if 0 stun_cb.on_request_complete = &stun_on_request_complete; #else stun_cb.on_request_complete = &on_stun_request_complete; #endif stun_cb.on_rx_request = &on_stun_rx_request; stun_cb.on_rx_indication = &on_stun_rx_indication; status = pj_stun_session_create2(&sess->stun_cfg, sess->obj_name, &stun_cb, PJ_FALSE, NULL, &sess->stun, PJ_TRUE, sess); if (status != PJ_SUCCESS) { do_destroy(sess); return status; } } /* Attach ourself to STUN session */ pj_stun_session_set_user_data(sess->stun, pj_tcp_sock_get_tsd(user_data)); /* Replace mutex in STUN session with a NULL mutex, since access to * STUN session is serialized. */ status = pj_lock_create_null_mutex(pool, name, &null_lock); if (status != PJ_SUCCESS) { do_destroy(sess); return status; } pj_stun_session_set_lock(sess->stun, null_lock, PJ_TRUE); /* Done */ PJ_LOG(4,(sess->obj_name, "TCP client session created")); *p_sess = sess; return PJ_SUCCESS; }
PJ_DEF(void) pj_tcp_session_set_stun_session_user_data(pj_tcp_session *tcp_sess, void *user_data) { pj_stun_session_set_user_data(tcp_sess->stun, user_data); }