summaryrefslogtreecommitdiff
path: root/pjnath/src/pjnath/stun_sock.c
diff options
context:
space:
mode:
Diffstat (limited to 'pjnath/src/pjnath/stun_sock.c')
-rw-r--r--pjnath/src/pjnath/stun_sock.c189
1 files changed, 137 insertions, 52 deletions
diff --git a/pjnath/src/pjnath/stun_sock.c b/pjnath/src/pjnath/stun_sock.c
index 3f756f50..bc395411 100644
--- a/pjnath/src/pjnath/stun_sock.c
+++ b/pjnath/src/pjnath/stun_sock.c
@@ -28,9 +28,15 @@
#include <pj/assert.h>
#include <pj/ip_helper.h>
#include <pj/log.h>
+#include <pj/os.h>
#include <pj/pool.h>
#include <pj/rand.h>
+#if 1
+# define TRACE_(x) PJ_LOG(5,x)
+#else
+# define TRACE_(x)
+#endif
enum { MAX_BIND_RETRY = 100 };
@@ -39,7 +45,7 @@ struct pj_stun_sock
char *obj_name; /* Log identification */
pj_pool_t *pool; /* Pool */
void *user_data; /* Application user data */
-
+ pj_bool_t is_destroying; /* Destroy already called */
int af; /* Address family */
pj_stun_config stun_cfg; /* STUN config (ioqueue etc)*/
pj_stun_sock_cb cb; /* Application callbacks */
@@ -58,13 +64,16 @@ struct pj_stun_sock
pj_uint16_t tsx_id[6]; /* .. to match STUN msg */
pj_stun_session *stun_sess; /* STUN session */
-
+ pj_grp_lock_t *grp_lock; /* Session group lock */
};
/*
* Prototypes for static functions
*/
+/* Destructor for group lock */
+static void stun_sock_destructor(void *obj);
+
/* This callback is called by the STUN session to send packet */
static pj_status_t sess_on_send_msg(pj_stun_session *sess,
void *token,
@@ -202,6 +211,20 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg,
if (stun_sock->ka_interval == 0)
stun_sock->ka_interval = PJ_STUN_KEEP_ALIVE_SEC;
+ if (cfg && 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 (status != PJ_SUCCESS)
@@ -252,6 +275,7 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_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;
@@ -290,6 +314,7 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg,
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;
@@ -332,6 +357,8 @@ PJ_DEF(pj_status_t) pj_stun_sock_start( pj_stun_sock *stun_sock,
PJ_ASSERT_RETURN(stun_sock && domain && default_port, PJ_EINVAL);
+ pj_grp_lock_acquire(stun_sock->grp_lock);
+
/* Check whether the domain contains IP address */
stun_sock->srv_addr.addr.sa_family = (pj_uint16_t)stun_sock->af;
status = pj_inet_pton(stun_sock->af, domain,
@@ -360,7 +387,6 @@ PJ_DEF(pj_status_t) pj_stun_sock_start( pj_stun_sock *stun_sock,
&stun_sock->q);
/* Processing will resume when the DNS SRV callback is called */
- return status;
} else {
@@ -378,53 +404,70 @@ PJ_DEF(pj_status_t) pj_stun_sock_start( pj_stun_sock *stun_sock,
pj_sockaddr_set_port(&stun_sock->srv_addr, (pj_uint16_t)default_port);
/* Start sending Binding request */
- return get_mapped_addr(stun_sock);
+ status = get_mapped_addr(stun_sock);
}
+
+ pj_grp_lock_release(stun_sock->grp_lock);
+ return status;
}
-/* Destroy */
-PJ_DEF(pj_status_t) pj_stun_sock_destroy(pj_stun_sock *stun_sock)
+/* Destructor */
+static void stun_sock_destructor(void *obj)
{
+ pj_stun_sock *stun_sock = (pj_stun_sock*)obj;
+
if (stun_sock->q) {
pj_dns_srv_cancel_query(stun_sock->q, PJ_FALSE);
stun_sock->q = NULL;
}
+ /*
if (stun_sock->stun_sess) {
- pj_stun_session_set_user_data(stun_sock->stun_sess, NULL);
+ pj_stun_session_destroy(stun_sock->stun_sess);
+ stun_sock->stun_sess = NULL;
}
-
- /* Destroy the active socket first just in case we'll get
- * stray callback.
- */
+ */
+
+ if (stun_sock->pool) {
+ pj_pool_t *pool = stun_sock->pool;
+ stun_sock->pool = NULL;
+ pj_pool_release(pool);
+ }
+
+ TRACE_(("", "STUN sock %p destroyed", stun_sock));
+
+}
+
+/* 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->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);
+ pj_activesock_close(stun_sock->active_sock);
} 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->ka_timer.id != 0) {
- pj_timer_heap_cancel(stun_sock->stun_cfg.timer_heap,
- &stun_sock->ka_timer);
- stun_sock->ka_timer.id = 0;
- }
-
if (stun_sock->stun_sess) {
pj_stun_session_destroy(stun_sock->stun_sess);
- stun_sock->stun_sess = NULL;
}
-
- if (stun_sock->pool) {
- pj_pool_t *pool = stun_sock->pool;
- stun_sock->pool = NULL;
- pj_pool_release(pool);
- }
-
+ pj_grp_lock_dec_ref(stun_sock->grp_lock);
+ pj_grp_lock_release(stun_sock->grp_lock);
return PJ_SUCCESS;
}
@@ -468,12 +511,15 @@ static void dns_srv_resolver_cb(void *user_data,
{
pj_stun_sock *stun_sock = (pj_stun_sock*) user_data;
+ pj_grp_lock_acquire(stun_sock->grp_lock);
+
/* Clear query */
stun_sock->q = NULL;
/* Handle error */
if (status != PJ_SUCCESS) {
sess_fail(stun_sock, PJ_STUN_SOCK_DNS_OP, status);
+ pj_grp_lock_release(stun_sock->grp_lock);
return;
}
@@ -490,6 +536,8 @@ static void dns_srv_resolver_cb(void *user_data,
/* Start sending Binding request */
get_mapped_addr(stun_sock);
+
+ pj_grp_lock_release(stun_sock->grp_lock);
}
@@ -533,6 +581,8 @@ PJ_DEF(pj_status_t) pj_stun_sock_get_info( pj_stun_sock *stun_sock,
PJ_ASSERT_RETURN(stun_sock && info, PJ_EINVAL);
+ pj_grp_lock_acquire(stun_sock->grp_lock);
+
/* Copy STUN server address and mapped address */
pj_memcpy(&info->srv_addr, &stun_sock->srv_addr,
sizeof(pj_sockaddr));
@@ -543,8 +593,10 @@ PJ_DEF(pj_status_t) pj_stun_sock_get_info( pj_stun_sock *stun_sock,
addr_len = sizeof(info->bound_addr);
status = pj_sock_getsockname(stun_sock->sock_fd, &info->bound_addr,
&addr_len);
- if (status != PJ_SUCCESS)
+ if (status != PJ_SUCCESS) {
+ pj_grp_lock_release(stun_sock->grp_lock);
return status;
+ }
/* If socket is bound to a specific interface, then only put that
* interface in the alias list. Otherwise query all the interfaces
@@ -560,8 +612,10 @@ PJ_DEF(pj_status_t) pj_stun_sock_get_info( pj_stun_sock *stun_sock,
/* Get the default address */
status = pj_gethostip(stun_sock->af, &def_addr);
- if (status != PJ_SUCCESS)
+ if (status != PJ_SUCCESS) {
+ pj_grp_lock_release(stun_sock->grp_lock);
return status;
+ }
pj_sockaddr_set_port(&def_addr, port);
@@ -569,8 +623,10 @@ PJ_DEF(pj_status_t) pj_stun_sock_get_info( pj_stun_sock *stun_sock,
info->alias_cnt = PJ_ARRAY_SIZE(info->aliases);
status = pj_enum_ip_interface(stun_sock->af, &info->alias_cnt,
info->aliases);
- if (status != PJ_SUCCESS)
+ if (status != PJ_SUCCESS) {
+ pj_grp_lock_release(stun_sock->grp_lock);
return status;
+ }
/* Set the port number for each address.
*/
@@ -590,6 +646,7 @@ PJ_DEF(pj_status_t) pj_stun_sock_get_info( pj_stun_sock *stun_sock,
}
}
+ pj_grp_lock_release(stun_sock->grp_lock);
return PJ_SUCCESS;
}
@@ -603,14 +660,29 @@ PJ_DEF(pj_status_t) pj_stun_sock_sendto( pj_stun_sock *stun_sock,
unsigned addr_len)
{
pj_ssize_t size;
+ pj_status_t status;
+
PJ_ASSERT_RETURN(stun_sock && pkt && dst_addr && addr_len, PJ_EINVAL);
+ pj_grp_lock_acquire(stun_sock->grp_lock);
+
+ if (!stun_sock->active_sock) {
+ /* We have been shutdown, but this callback may still get called
+ * by retransmit timer.
+ */
+ pj_grp_lock_release(stun_sock->grp_lock);
+ return PJ_EINVALIDOP;
+ }
+
if (send_key==NULL)
send_key = &stun_sock->send_key;
size = pkt_len;
- return pj_activesock_sendto(stun_sock->active_sock, send_key,
- pkt, &size, flag, dst_addr, addr_len);
+ status = pj_activesock_sendto(stun_sock->active_sock, send_key,
+ pkt, &size, flag, dst_addr, addr_len);
+
+ pj_grp_lock_release(stun_sock->grp_lock);
+ return status;
}
/* This callback is called by the STUN session to send packet */
@@ -625,14 +697,18 @@ static pj_status_t sess_on_send_msg(pj_stun_session *sess,
pj_ssize_t size;
stun_sock = (pj_stun_sock *) pj_stun_session_get_user_data(sess);
- if (!stun_sock || !stun_sock->active_sock)
+ if (!stun_sock || !stun_sock->active_sock) {
+ /* We have been shutdown, but this callback may still get called
+ * by retransmit timer.
+ */
return PJ_EINVALIDOP;
+ }
pj_assert(token==INTERNAL_MSG_TOKEN);
PJ_UNUSED_ARG(token);
size = pkt_size;
- return pj_activesock_sendto(stun_sock->active_sock,
+ return pj_activesock_sendto(stun_sock->active_sock,
&stun_sock->int_send_key,
pkt, &size, 0, dst_addr, addr_len);
}
@@ -726,25 +802,20 @@ on_return:
/* Schedule keep-alive timer */
static void start_ka_timer(pj_stun_sock *stun_sock)
{
- if (stun_sock->ka_timer.id != 0) {
- pj_timer_heap_cancel(stun_sock->stun_cfg.timer_heap,
- &stun_sock->ka_timer);
- stun_sock->ka_timer.id = 0;
- }
+ pj_timer_heap_cancel_if_active(stun_sock->stun_cfg.timer_heap,
+ &stun_sock->ka_timer, 0);
pj_assert(stun_sock->ka_interval != 0);
- if (stun_sock->ka_interval > 0) {
+ if (stun_sock->ka_interval > 0 && !stun_sock->is_destroying) {
pj_time_val delay;
delay.sec = stun_sock->ka_interval;
delay.msec = 0;
- if (pj_timer_heap_schedule(stun_sock->stun_cfg.timer_heap,
- &stun_sock->ka_timer,
- &delay) == PJ_SUCCESS)
- {
- stun_sock->ka_timer.id = PJ_TRUE;
- }
+ pj_timer_heap_schedule_w_grp_lock(stun_sock->stun_cfg.timer_heap,
+ &stun_sock->ka_timer,
+ &delay, PJ_TRUE,
+ stun_sock->grp_lock);
}
}
@@ -756,14 +827,18 @@ static void ka_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te)
stun_sock = (pj_stun_sock *) te->user_data;
PJ_UNUSED_ARG(th);
+ pj_grp_lock_acquire(stun_sock->grp_lock);
/* Time to send STUN Binding request */
- if (get_mapped_addr(stun_sock) != PJ_SUCCESS)
+ if (get_mapped_addr(stun_sock) != PJ_SUCCESS) {
+ pj_grp_lock_release(stun_sock->grp_lock);
return;
+ }
/* Next keep-alive timer will be scheduled once the request
* is complete.
*/
+ pj_grp_lock_release(stun_sock->grp_lock);
}
/* Callback from active socket when incoming packet is received */
@@ -788,6 +863,8 @@ static pj_bool_t on_data_recvfrom(pj_activesock_t *asock,
return PJ_TRUE;
}
+ pj_grp_lock_acquire(stun_sock->grp_lock);
+
/* Check that this is STUN message */
status = pj_stun_msg_check((const pj_uint8_t*)data, size,
PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET);
@@ -823,7 +900,10 @@ static pj_bool_t on_data_recvfrom(pj_activesock_t *asock,
status = pj_stun_session_on_rx_pkt(stun_sock->stun_sess, data, size,
PJ_STUN_IS_DATAGRAM, NULL, NULL,
src_addr, addr_len);
- return status!=PJNATH_ESTUNDESTROYED ? PJ_TRUE : PJ_FALSE;
+
+ status = pj_grp_lock_release(stun_sock->grp_lock);
+
+ return status!=PJ_EGONE ? PJ_TRUE : PJ_FALSE;
process_app_data:
if (stun_sock->cb.on_rx_data) {
@@ -831,10 +911,12 @@ process_app_data:
ret = (*stun_sock->cb.on_rx_data)(stun_sock, data, size,
src_addr, addr_len);
- return ret;
+ status = pj_grp_lock_release(stun_sock->grp_lock);
+ return status!=PJ_EGONE ? PJ_TRUE : PJ_FALSE;
}
- return PJ_TRUE;
+ status = pj_grp_lock_release(stun_sock->grp_lock);
+ return status!=PJ_EGONE ? PJ_TRUE : PJ_FALSE;
}
/* Callback from active socket about send status */
@@ -857,6 +939,8 @@ static pj_bool_t on_data_sent(pj_activesock_t *asock,
if (stun_sock->cb.on_data_sent) {
pj_bool_t ret;
+ pj_grp_lock_acquire(stun_sock->grp_lock);
+
/* If app gives NULL send_key in sendto() function, then give
* NULL in the callback too
*/
@@ -866,6 +950,7 @@ static pj_bool_t on_data_sent(pj_activesock_t *asock,
/* Call callback */
ret = (*stun_sock->cb.on_data_sent)(stun_sock, send_key, sent);
+ pj_grp_lock_release(stun_sock->grp_lock);
return ret;
}