static void destroy_client(struct stun_client *client) { if (client->sock) { pj_stun_sock_destroy(client->sock); client->sock = NULL; } pj_pool_release(client->pool); }
static int stun_destroy_test_session(struct stun_test_session *test_sess) { unsigned i; pj_stun_sock_cb stun_cb; pj_status_t status; pj_stun_sock *stun_sock[MAX_SOCK_CLIENTS]; pj_bzero(&stun_cb, sizeof(stun_cb)); stun_cb.on_status = &stun_sock_on_status; pj_event_reset(test_sess->server_event); /* Create all clients first */ for (i=0; i<MAX_SOCK_CLIENTS; ++i) { char name[10]; sprintf(name, "stun%02d", i); status = pj_stun_sock_create(&test_sess->stun_cfg, name, pj_AF_INET(), &stun_cb, NULL, test_sess, &stun_sock[i]); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "Error creating stun socket")); return -10; } } /* Start resolution */ for (i=0; i<MAX_SOCK_CLIENTS; ++i) { pj_str_t server_ip = pj_str("127.0.0.1"); status = pj_stun_sock_start(stun_sock[i], &server_ip, (pj_uint16_t)test_sess->server_port, NULL); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "Error starting stun socket")); return -20; } } /* settle down */ pj_thread_sleep(test_sess->param.client_sleep_after_start); /* Resume server threads */ pj_event_set(test_sess->server_event); pj_thread_sleep(test_sess->param.client_sleep_before_destroy); /* Destroy clients */ for (i=0; i<MAX_SOCK_CLIENTS; ++i) { status = pj_stun_sock_destroy(stun_sock[i]); if (status != PJ_SUCCESS) { PJ_PERROR(1,(THIS_FILE, status, "Error destroying stun socket")); } } /* Give some time to ioqueue to free sockets */ pj_thread_sleep(PJ_IOQUEUE_KEY_FREE_DELAY); return 0; }
static pj_bool_t stun_sock_on_status(pj_stun_sock *stun_sock, pj_stun_sock_op op, pj_status_t status) { struct stun_client *client; client = (struct stun_client*) pj_stun_sock_get_user_data(stun_sock); client->on_status_cnt++; client->last_op = op; client->last_status = status; if (status != PJ_SUCCESS && client->destroy_on_err) { pj_stun_sock_destroy(client->sock); client->sock = NULL; return PJ_FALSE; } return PJ_TRUE; }
static int client_shutdown() { unsigned i; if (g.thread) { g.quit = 1; pj_thread_join(g.thread); pj_thread_destroy(g.thread); g.thread = NULL; } if (g.relay) { pj_turn_sock_destroy(g.relay); g.relay = NULL; } for (i=0; i<PJ_ARRAY_SIZE(g.peer); ++i) { if (g.peer[i].stun_sock) { pj_stun_sock_destroy(g.peer[i].stun_sock); g.peer[i].stun_sock = NULL; } } if (g.stun_config.timer_heap) { pj_timer_heap_destroy(g.stun_config.timer_heap); g.stun_config.timer_heap = NULL; } if (g.stun_config.ioqueue) { pj_ioqueue_destroy(g.stun_config.ioqueue); g.stun_config.ioqueue = NULL; } if (g.pool) { pj_pool_release(g.pool); g.pool = NULL; } pj_pool_factory_dump(&g.cp.factory, PJ_TRUE); pj_caching_pool_destroy(&g.cp); return PJ_SUCCESS; }
/* * 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; }