summaryrefslogtreecommitdiff
path: root/pjnath
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2008-03-20 16:32:06 +0000
committerBenny Prijono <bennylp@teluu.com>2008-03-20 16:32:06 +0000
commitf5c4ac3cbadd515c83b71618e7ff2b1683c2aca2 (patch)
treef3378bd897fc58e21490005bb0000999eaa0940b /pjnath
parent7f5db291ab29a7396137961f69470562f5bce4a7 (diff)
More ticket #485: client and server self tested
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1879 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjnath')
-rw-r--r--pjnath/src/pjnath/stun_session.c3
-rw-r--r--pjnath/src/pjnath/turn_session.c43
-rw-r--r--pjnath/src/pjnath/turn_udp.c147
-rw-r--r--pjnath/src/pjturn-client/client_main.c59
-rw-r--r--pjnath/src/pjturn-srv/allocation.c79
-rw-r--r--pjnath/src/pjturn-srv/auth.c12
-rw-r--r--pjnath/src/pjturn-srv/auth.h10
-rw-r--r--pjnath/src/pjturn-srv/main.c98
-rw-r--r--pjnath/src/pjturn-srv/server.c26
-rw-r--r--pjnath/src/pjturn-srv/turn.h2
10 files changed, 366 insertions, 113 deletions
diff --git a/pjnath/src/pjnath/stun_session.c b/pjnath/src/pjnath/stun_session.c
index 02b017cf..63598bba 100644
--- a/pjnath/src/pjnath/stun_session.c
+++ b/pjnath/src/pjnath/stun_session.c
@@ -267,6 +267,9 @@ static pj_status_t handle_auth_challenge(pj_stun_session *sess,
*notify_user = PJ_TRUE;
+ if (response==NULL)
+ return PJ_SUCCESS;
+
if (sess->auth_type != PJ_STUN_AUTH_LONG_TERM)
return PJ_SUCCESS;
diff --git a/pjnath/src/pjnath/turn_session.c b/pjnath/src/pjnath/turn_session.c
index e5540b00..e5364edc 100644
--- a/pjnath/src/pjnath/turn_session.c
+++ b/pjnath/src/pjnath/turn_session.c
@@ -188,6 +188,7 @@ PJ_DEF(pj_status_t) pj_turn_session_create( pj_stun_config *cfg,
sess->tp_type = tp_type;
sess->ka_interval = PJ_TURN_KEEP_ALIVE_SEC;
sess->user_data = user_data;
+ sess->next_ch = PJ_TURN_CHANNEL_MIN;
/* Copy callback */
pj_memcpy(&sess->cb, cb, sizeof(*cb));
@@ -325,7 +326,7 @@ static void sess_shutdown(pj_turn_session *sess,
case PJ_TURN_STATE_READY:
/* Send REFRESH with LIFETIME=0 */
can_destroy = PJ_FALSE;
- sess->pending_destroy = PJ_TRUE;
+ send_refresh(sess, 0);
break;
case PJ_TURN_STATE_DEALLOCATING:
can_destroy = PJ_FALSE;
@@ -778,7 +779,7 @@ PJ_DEF(pj_status_t) pj_turn_session_bind_channel(pj_turn_session *sess,
/* Add CHANNEL-NUMBER attribute */
pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
PJ_STUN_ATTR_CHANNEL_NUMBER,
- PJ_STUN_SET_CH_NB(sess->next_ch));
+ PJ_STUN_SET_CH_NB(ch_num));
/* Add PEER-ADDRESS attribute */
pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
@@ -1023,7 +1024,23 @@ static void on_allocate_success(pj_turn_session *sess,
}
/* Save relayed address */
- pj_memcpy(&sess->relay_addr, &raddr_attr->sockaddr, sizeof(pj_sockaddr));
+ if (raddr_attr) {
+ /* If we already have relay address, check if the relay address
+ * in the response matches our relay address.
+ */
+ if (pj_sockaddr_has_addr(&sess->relay_addr)) {
+ if (pj_sockaddr_cmp(&sess->relay_addr, &raddr_attr->sockaddr)) {
+ on_session_fail(sess, method, PJNATH_EINSTUNMSG,
+ pj_cstr(&s, "Error: different RELAY-ADDRESS is"
+ "returned by server"));
+ return;
+ }
+ } else {
+ /* Otherwise save the relayed address */
+ pj_memcpy(&sess->relay_addr, &raddr_attr->sockaddr,
+ sizeof(pj_sockaddr));
+ }
+ }
/* Success */
@@ -1180,6 +1197,8 @@ static pj_status_t stun_on_rx_indication(pj_stun_session *stun,
pj_stun_peer_addr_attr *peer_attr;
pj_stun_data_attr *data_attr;
+ PJ_UNUSED_ARG(pkt);
+ PJ_UNUSED_ARG(pkt_len);
PJ_UNUSED_ARG(src_addr);
PJ_UNUSED_ARG(src_addr_len);
@@ -1209,7 +1228,7 @@ static pj_status_t stun_on_rx_indication(pj_stun_session *stun,
/* Notify application */
if (sess->cb.on_rx_data) {
- (*sess->cb.on_rx_data)(sess, pkt, pkt_len,
+ (*sess->cb.on_rx_data)(sess, data_attr->data, data_attr->length,
&peer_attr->sockaddr,
pj_sockaddr_get_len(&peer_attr->sockaddr));
}
@@ -1298,13 +1317,15 @@ static struct peer *lookup_peer_by_addr(pj_turn_session *sess,
}
if (bind_channel) {
+ pj_uint32_t hval = 0;
/* Register by channel number */
pj_assert(peer->ch_id != PJ_TURN_INVALID_CHANNEL && peer->bound);
- pj_assert(pj_hash_get(sess->peer_table, &peer->ch_id,
- sizeof(peer->ch_id), NULL)==0);
- pj_hash_set(sess->pool, sess->peer_table, &peer->ch_id,
- sizeof(peer->ch_id), 0, peer);
+ if (pj_hash_get(sess->peer_table, &peer->ch_id,
+ sizeof(peer->ch_id), &hval)==0) {
+ pj_hash_set(sess->pool, sess->peer_table, &peer->ch_id,
+ sizeof(peer->ch_id), hval, peer);
+ }
}
}
@@ -1405,6 +1426,7 @@ static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e)
delay.sec = sess->ka_interval;
delay.msec = 0;
+ sess->timer.id = TIMER_KEEP_ALIVE;
pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &delay);
}
@@ -1414,6 +1436,9 @@ static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e)
/* Time to destroy */
pj_lock_release(sess->lock);
do_destroy(sess);
- }
+ } else {
+ pj_assert(!"Unknown timer event");
+ pj_lock_release(sess->lock);
+ }
}
diff --git a/pjnath/src/pjnath/turn_udp.c b/pjnath/src/pjnath/turn_udp.c
index 8d5ff9d4..a9fd4705 100644
--- a/pjnath/src/pjnath/turn_udp.c
+++ b/pjnath/src/pjnath/turn_udp.c
@@ -19,10 +19,17 @@
#include <pjnath/turn_udp.h>
#include <pj/assert.h>
#include <pj/errno.h>
+#include <pj/lock.h>
#include <pj/log.h>
#include <pj/pool.h>
#include <pj/ioqueue.h>
+enum
+{
+ TIMER_NONE,
+ TIMER_DESTROY
+};
+
struct pj_turn_udp
{
pj_pool_t *pool;
@@ -30,6 +37,12 @@ struct pj_turn_udp
pj_turn_udp_cb cb;
void *user_data;
+ pj_lock_t *lock;
+
+ pj_bool_t destroy_request;
+ pj_timer_heap_t *timer_heap;
+ pj_timer_entry timer;
+
pj_sock_t sock;
pj_ioqueue_key_t *key;
pj_ioqueue_op_key_t read_key;
@@ -64,6 +77,10 @@ static void on_read_complete(pj_ioqueue_key_t *key,
pj_ssize_t bytes_read);
+static void destroy(pj_turn_udp *udp_rel);
+static void timer_cb(pj_timer_heap_t *th, pj_timer_entry *e);
+
+
/*
* Create.
*/
@@ -93,23 +110,22 @@ PJ_DEF(pj_status_t) pj_turn_udp_create( pj_stun_config *cfg,
pj_memcpy(&udp_rel->cb, cb, sizeof(*cb));
}
- /* Init TURN session */
- pj_bzero(&sess_cb, sizeof(sess_cb));
- sess_cb.on_send_pkt = &turn_on_send_pkt;
- sess_cb.on_channel_bound = &turn_on_channel_bound;
- sess_cb.on_rx_data = &turn_on_rx_data;
- sess_cb.on_state = &turn_on_state;
- status = pj_turn_session_create(cfg, pool->obj_name, af, PJ_TURN_TP_UDP,
- &sess_cb, udp_rel, 0, &udp_rel->sess);
+ /* Create lock */
+ status = pj_lock_create_recursive_mutex(pool, pool->obj_name,
+ &udp_rel->lock);
if (status != PJ_SUCCESS) {
- pj_turn_udp_destroy(udp_rel);
+ destroy(udp_rel);
return status;
}
+ /* Init timer */
+ udp_rel->timer_heap = cfg->timer_heap;
+ pj_timer_entry_init(&udp_rel->timer, TIMER_NONE, udp_rel, &timer_cb);
+
/* Init socket */
status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &udp_rel->sock);
if (status != PJ_SUCCESS) {
- pj_turn_udp_destroy(udp_rel);
+ destroy(udp_rel);
return status;
}
@@ -118,7 +134,7 @@ PJ_DEF(pj_status_t) pj_turn_udp_create( pj_stun_config *cfg,
status = pj_sock_bind(udp_rel->sock, &udp_rel->src_addr,
pj_sockaddr_get_len(&udp_rel->src_addr));
if (status != PJ_SUCCESS) {
- pj_turn_udp_destroy(udp_rel);
+ destroy(udp_rel);
return status;
}
@@ -129,7 +145,20 @@ PJ_DEF(pj_status_t) pj_turn_udp_create( pj_stun_config *cfg,
udp_rel->sock, udp_rel,
&ioq_cb, &udp_rel->key);
if (status != PJ_SUCCESS) {
- pj_turn_udp_destroy(udp_rel);
+ destroy(udp_rel);
+ return status;
+ }
+
+ /* Init TURN session */
+ pj_bzero(&sess_cb, sizeof(sess_cb));
+ sess_cb.on_send_pkt = &turn_on_send_pkt;
+ sess_cb.on_channel_bound = &turn_on_channel_bound;
+ sess_cb.on_rx_data = &turn_on_rx_data;
+ sess_cb.on_state = &turn_on_state;
+ status = pj_turn_session_create(cfg, pool->obj_name, af, PJ_TURN_TP_UDP,
+ &sess_cb, udp_rel, 0, &udp_rel->sess);
+ if (status != PJ_SUCCESS) {
+ destroy(udp_rel);
return status;
}
@@ -144,13 +173,33 @@ PJ_DEF(pj_status_t) pj_turn_udp_create( pj_stun_config *cfg,
/*
* Destroy.
*/
-PJ_DEF(void) pj_turn_udp_destroy(pj_turn_udp *udp_rel)
+static void destroy(pj_turn_udp *udp_rel)
{
+ if (udp_rel->lock) {
+ pj_lock_acquire(udp_rel->lock);
+ }
+
if (udp_rel->sess) {
+ pj_turn_session_set_user_data(udp_rel->sess, NULL);
pj_turn_session_destroy(udp_rel->sess);
udp_rel->sess = NULL;
}
+ if (udp_rel->key) {
+ pj_ioqueue_unregister(udp_rel->key);
+ udp_rel->key = NULL;
+ udp_rel->sock = 0;
+ } else if (udp_rel->sock) {
+ pj_sock_close(udp_rel->sock);
+ udp_rel->sock = 0;
+ }
+
+ if (udp_rel->lock) {
+ pj_lock_release(udp_rel->lock);
+ pj_lock_destroy(udp_rel->lock);
+ udp_rel->lock = NULL;
+ }
+
if (udp_rel->pool) {
pj_pool_t *pool = udp_rel->pool;
udp_rel->pool = NULL;
@@ -158,6 +207,46 @@ PJ_DEF(void) pj_turn_udp_destroy(pj_turn_udp *udp_rel)
}
}
+PJ_DEF(void) pj_turn_udp_destroy(pj_turn_udp *udp_rel)
+{
+ pj_lock_acquire(udp_rel->lock);
+ udp_rel->destroy_request = PJ_TRUE;
+
+ if (udp_rel->sess) {
+ pj_turn_session_destroy(udp_rel->sess);
+ /* This will ultimately call our state callback, and when
+ * session state is DESTROYING we will schedule a timer to
+ * destroy ourselves.
+ */
+ pj_lock_release(udp_rel->lock);
+ } else {
+ pj_lock_release(udp_rel->lock);
+ destroy(udp_rel);
+ }
+
+}
+
+/* Timer callback */
+static void timer_cb(pj_timer_heap_t *th, pj_timer_entry *e)
+{
+ pj_turn_udp *udp_rel = (pj_turn_udp*)e->user_data;
+ int eid = e->id;
+
+ PJ_UNUSED_ARG(th);
+
+ e->id = TIMER_NONE;
+
+ switch (eid) {
+ case TIMER_DESTROY:
+ destroy(udp_rel);
+ break;
+ default:
+ pj_assert(!"Invalid timer id");
+ break;
+ }
+}
+
+
/*
* Set user data.
*/
@@ -271,6 +360,7 @@ static void on_read_complete(pj_ioqueue_key_t *key,
pj_status_t status;
udp_rel = (pj_turn_udp*) pj_ioqueue_get_user_data(key);
+ pj_lock_acquire(udp_rel->lock);
do {
/* Report incoming packet to TURN session */
@@ -300,6 +390,7 @@ static void on_read_complete(pj_ioqueue_key_t *key,
} while (status != PJ_EPENDING && status != PJ_ECANCELLED &&
++retry < MAX_RETRY);
+ pj_lock_release(udp_rel->lock);
}
@@ -316,6 +407,12 @@ static pj_status_t turn_on_send_pkt(pj_turn_session *sess,
pj_turn_session_get_user_data(sess);
pj_ssize_t len = pkt_len;
+ if (udp_rel == NULL) {
+ /* We've been destroyed */
+ pj_assert(!"We should shutdown gracefully");
+ return PJ_EINVALIDOP;
+ }
+
return pj_sock_sendto(udp_rel->sock, pkt, &len, 0,
dst_addr, dst_addr_len);
}
@@ -347,6 +444,11 @@ static void turn_on_rx_data(pj_turn_session *sess,
{
pj_turn_udp *udp_rel = (pj_turn_udp*)
pj_turn_session_get_user_data(sess);
+ if (udp_rel == NULL) {
+ /* We've been destroyed */
+ return;
+ }
+
if (udp_rel->cb.on_rx_data) {
(*udp_rel->cb.on_rx_data)(udp_rel, pkt, pkt_len,
peer_addr, addr_len);
@@ -363,12 +465,27 @@ static void turn_on_state(pj_turn_session *sess,
{
pj_turn_udp *udp_rel = (pj_turn_udp*)
pj_turn_session_get_user_data(sess);
+ if (udp_rel == NULL) {
+ /* We've been destroyed */
+ return;
+ }
+
if (udp_rel->cb.on_state) {
(*udp_rel->cb.on_state)(udp_rel, old_state, new_state);
}
- if (new_state > PJ_TURN_STATE_READY) {
- udp_rel->sess = NULL;
+ if (new_state >= PJ_TURN_STATE_DESTROYING && udp_rel->sess) {
+ if (udp_rel->destroy_request) {
+ pj_time_val delay = {0, 0};
+
+ pj_turn_session_set_user_data(udp_rel->sess, NULL);
+
+ udp_rel->timer.id = TIMER_DESTROY;
+ pj_timer_heap_schedule(udp_rel->timer_heap, &udp_rel->timer,
+ &delay);
+ } else {
+ udp_rel->sess = NULL;
+ }
}
}
diff --git a/pjnath/src/pjturn-client/client_main.c b/pjnath/src/pjturn-client/client_main.c
index 114f47c8..470ad251 100644
--- a/pjnath/src/pjturn-client/client_main.c
+++ b/pjnath/src/pjturn-client/client_main.c
@@ -61,7 +61,6 @@ static struct options
char *realm;
char *user_name;
char *password;
- char *nonce;
pj_bool_t use_fingerprint;
} o;
@@ -135,7 +134,7 @@ static int init()
port = pj_sockaddr_get_port(&addr);
CHECK( pj_gethostip(pj_AF_INET(), &g.peer[i].addr) );
- pj_sockaddr_set_port(&g.peer[0].addr, port);
+ pj_sockaddr_set_port(&g.peer[i].addr, port);
}
@@ -265,7 +264,7 @@ static pj_status_t create_relay(void)
cred.data.static_cred.username = pj_str(o.user_name);
cred.data.static_cred.data_type = 0;
cred.data.static_cred.data = pj_str(o.password);
- cred.data.static_cred.nonce = pj_str(o.nonce);
+ //cred.data.static_cred.nonce = pj_str(o.nonce);
} else {
PJ_LOG(2,(THIS_FILE, "Warning: no credential is set"));
}
@@ -286,7 +285,6 @@ static void destroy_relay(void)
{
if (g.udp_rel) {
pj_turn_udp_destroy(g.udp_rel);
- g.udp_rel = NULL;
}
}
@@ -309,10 +307,16 @@ static void turn_on_rx_data(pj_turn_udp *udp_rel,
static void turn_on_state(pj_turn_udp *udp_rel, pj_turn_state_t old_state,
pj_turn_state_t new_state)
{
+ PJ_LOG(3,(THIS_FILE, "State %s --> %s", pj_turn_state_name(old_state),
+ pj_turn_state_name(new_state)));
+
if (new_state == PJ_TURN_STATE_READY) {
pj_turn_session_info info;
pj_turn_udp_get_info(udp_rel, &info);
pj_memcpy(&g.relay_addr, &info.relay_addr, sizeof(pj_sockaddr));
+ } else if (new_state > PJ_TURN_STATE_READY && g.udp_rel) {
+ PJ_LOG(3,(THIS_FILE, "Relay shutting down.."));
+ g.udp_rel = NULL;
}
}
@@ -379,10 +383,10 @@ static void menu(void)
printf("| Relay addr: %-21s | |\n",
relay_addr);
puts("| | 0 Send data to relay address |");
- puts("| A Allocate relay +--------------------------------+ ");
- puts("| S[01] Send data to peer 0/1 | PEER-1 |");
- puts("| B[01] BindChannel to peer 0/1 | |");
- printf("| X Delete allocation | Address: %-21s |\n",
+ puts("| a Allocate relay +--------------------------------+ ");
+ puts("| s,ss Send data to peer 0/1 | PEER-1 |");
+ puts("| b,bb BindChannel to peer 0/1 | |");
+ printf("| x Delete allocation | Address: %-21s |\n",
peer1_addr);
puts("+-----------------------------------+ |");
puts("| q Quit | 1 Send data to relay adderss |");
@@ -405,19 +409,19 @@ static void console_main(void)
fgets(input, sizeof(input), stdin);
switch (input[0]) {
- case 'A':
+ case 'a':
create_relay();
break;
- case 'S':
+ case 's':
if (g.udp_rel == NULL) {
puts("Error: no relay");
continue;
}
- if (input[1] != '0' && input[1] != '1') {
- puts("Usage: S0 or S1");
- continue;
- }
- peer = &g.peer[input[1]-'0'];
+ if (input[1]!='s')
+ peer = &g.peer[0];
+ else
+ peer = &g.peer[1];
+
strcpy(input, "Hello from client");
status = pj_turn_udp_sendto(g.udp_rel, input, strlen(input)+1,
&peer->addr,
@@ -425,22 +429,22 @@ static void console_main(void)
if (status != PJ_SUCCESS)
my_perror("turn_udp_sendto() failed", status);
break;
- case 'B':
+ case 'b':
if (g.udp_rel == NULL) {
puts("Error: no relay");
continue;
}
- if (input[1] != '0' && input[1] != '1') {
- puts("Usage: B0 or B1");
- continue;
- }
- peer = &g.peer[input[1]-'0'];
+ if (input[1]!='b')
+ peer = &g.peer[0];
+ else
+ peer = &g.peer[1];
+
status = pj_turn_udp_bind_channel(g.udp_rel, &peer->addr,
pj_sockaddr_get_len(&peer->addr));
if (status != PJ_SUCCESS)
my_perror("turn_udp_bind_channel() failed", status);
break;
- case 'X':
+ case 'x':
if (g.udp_rel == NULL) {
puts("Error: no relay");
continue;
@@ -449,7 +453,7 @@ static void console_main(void)
break;
case '0':
case '1':
- peer = &g.peer[input[1]-'0'];
+ peer = &g.peer[input[0]-'0'];
sprintf(input, "Hello from peer%d", input[0]-'0');
len = strlen(input)+1;
pj_sock_sendto(peer->sock, input, &len, 0, &g.relay_addr,
@@ -473,7 +477,6 @@ static void usage(void)
puts(" --realm, -r Set realm of the credential");
puts(" --username, -u Set username of the credential");
puts(" --password, -p Set password of the credential");
- puts(" --nonce, -N Set NONCE");
puts(" --fingerprint, -F Use fingerprint for outgoing requests");
puts(" --help, -h");
}
@@ -484,7 +487,6 @@ int main(int argc, char *argv[])
{ "realm", 1, 0, 'r'},
{ "username", 1, 0, 'u'},
{ "password", 1, 0, 'p'},
- { "nonce", 1, 0, 'N'},
{ "fingerprint",0, 0, 'F'},
{ "data", 1, 0, 'D'},
{ "help", 0, 0, 'h'}
@@ -504,9 +506,6 @@ int main(int argc, char *argv[])
case 'p':
o.password = pj_optarg;
break;
- case 'N':
- o.nonce = pj_optarg;
- break;
case 'h':
usage();
return 0;
@@ -537,8 +536,8 @@ int main(int argc, char *argv[])
if ((status=init()) != 0)
goto on_return;
- if ((status=create_relay()) != 0)
- goto on_return;
+ //if ((status=create_relay()) != 0)
+ // goto on_return;
console_main();
diff --git a/pjnath/src/pjturn-srv/allocation.c b/pjnath/src/pjturn-srv/allocation.c
index 14ed228b..339b2924 100644
--- a/pjnath/src/pjturn-srv/allocation.c
+++ b/pjnath/src/pjturn-srv/allocation.c
@@ -668,7 +668,7 @@ static pj_status_t create_relay(pj_turn_srv *srv,
if (status != PJ_SUCCESS) {
/* Unable to allocate port */
- PJ_LOG(4,(THIS_FILE, "bind() failed: err %d",
+ PJ_LOG(4,(THIS_FILE, "Unable to allocate relay, giving up: err %d",
status));
pj_sock_close(relay->tp.sock);
relay->tp.sock = PJ_INVALID_SOCKET;
@@ -688,6 +688,11 @@ static pj_status_t create_relay(pj_turn_srv *srv,
if (!pj_sockaddr_has_addr(&relay->hkey.addr)) {
pj_sockaddr_copy_addr(&relay->hkey.addr, &alloc->listener->addr);
}
+ if (!pj_sockaddr_has_addr(&relay->hkey.addr)) {
+ pj_sockaddr tmp_addr;
+ pj_gethostip(af, &tmp_addr);
+ pj_sockaddr_copy_addr(&relay->hkey.addr, &tmp_addr);
+ }
/* Init ioqueue */
pj_bzero(&icb, sizeof(icb));
@@ -751,14 +756,18 @@ static void send_reply_ok(pj_turn_allocation *alloc,
interval = 0;
}
- /* Add LIFETIME. */
- pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
- PJ_STUN_ATTR_LIFETIME, interval);
+ /* Add LIFETIME if this is not ChannelBind. */
+ if (PJ_STUN_GET_METHOD(tdata->msg->hdr.type)!=PJ_STUN_CHANNEL_BIND_METHOD){
+ pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
+ PJ_STUN_ATTR_LIFETIME, interval);
- /* Add BANDWIDTH */
- pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
- PJ_STUN_ATTR_BANDWIDTH,
- alloc->bandwidth);
+ /* Add BANDWIDTH if lifetime is not zero */
+ if (interval != 0) {
+ pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
+ PJ_STUN_ATTR_BANDWIDTH,
+ alloc->bandwidth);
+ }
+ }
status = pj_stun_session_send_msg(alloc->sess, PJ_TRUE,
&alloc->hkey.clt_addr,
@@ -773,8 +782,8 @@ static void send_reply_ok(pj_turn_allocation *alloc,
/* Create new permission */
static pj_turn_permission *create_permission(pj_turn_allocation *alloc,
- const pj_sockaddr_t *peer_addr,
- unsigned addr_len)
+ const pj_sockaddr_t *peer_addr,
+ unsigned addr_len)
{
pj_turn_permission *perm;
@@ -794,6 +803,10 @@ static pj_turn_permission *create_permission(pj_turn_allocation *alloc,
pj_gettimeofday(&perm->expiry);
perm->expiry.sec += PJ_TURN_PERM_TIMEOUT;
+ /* Register to hash table */
+ pj_hash_set(alloc->pool, alloc->peer_table, &perm->hkey.peer_addr,
+ pj_sockaddr_get_len(&perm->hkey.peer_addr), 0, perm);
+
return perm;
}
@@ -804,14 +817,14 @@ static pj_turn_permission *check_permission_expiry(pj_turn_permission *perm)
pj_time_val now;
pj_gettimeofday(&now);
- if (PJ_TIME_VAL_LT(perm->expiry, now)) {
+ if (PJ_TIME_VAL_GT(perm->expiry, now)) {
/* Permission has not expired */
return perm;
}
/* Remove from permission hash table */
- pj_hash_set(NULL, alloc->peer_table, &perm->hkey, sizeof(perm->hkey),
- 0, NULL);
+ pj_hash_set(NULL, alloc->peer_table, &perm->hkey.peer_addr,
+ pj_sockaddr_get_len(&perm->hkey.peer_addr), 0, NULL);
/* Remove from channel hash table, if assigned a channel number */
if (perm->channel != PJ_TURN_INVALID_CHANNEL) {
@@ -828,16 +841,12 @@ lookup_permission_by_addr(pj_turn_allocation *alloc,
const pj_sockaddr_t *peer_addr,
unsigned addr_len)
{
- pj_turn_permission_key key;
pj_turn_permission *perm;
- pj_bzero(&key, sizeof(key));
- pj_memcpy(&key, peer_addr, addr_len);
-
/* Lookup in peer hash table */
- perm = (pj_turn_permission*) pj_hash_get(alloc->peer_table, &key,
- sizeof(key), NULL);
- return check_permission_expiry(perm);
+ perm = (pj_turn_permission*) pj_hash_get(alloc->peer_table, peer_addr,
+ addr_len, NULL);
+ return perm ? check_permission_expiry(perm) : NULL;
}
/* Lookup permission in hash table by the channel number */
@@ -849,9 +858,9 @@ lookup_permission_by_chnum(pj_turn_allocation *alloc,
pj_turn_permission *perm;
/* Lookup in peer hash table */
- perm = (pj_turn_permission*) pj_hash_get(alloc->peer_table, &chnum16,
+ perm = (pj_turn_permission*) pj_hash_get(alloc->ch_table, &chnum16,
sizeof(chnum16), NULL);
- return check_permission_expiry(perm);
+ return perm ? check_permission_expiry(perm) : NULL;
}
/* Update permission because of data from client to peer.
@@ -930,8 +939,8 @@ PJ_DEF(void) pj_turn_allocation_on_rx_client_pkt(pj_turn_allocation *alloc,
if (!perm) {
/* Discard */
PJ_LOG(4,(alloc->obj_name,
- "ChannelData from %s discarded: not found",
- alloc->info));
+ "ChannelData from %s discarded: ch#0x%x not found",
+ alloc->info, pj_ntohs(cd->ch_number)));
goto on_return;
}
@@ -991,7 +1000,7 @@ static void handle_peer_pkt(pj_turn_allocation *alloc,
cd->length = pj_htons((pj_uint16_t)len);
/* Copy data */
- pj_memcpy(rel->tp.rx_pkt+sizeof(pj_turn_channel_data), pkt, len);
+ pj_memcpy(rel->tp.tx_pkt+sizeof(pj_turn_channel_data), pkt, len);
/* Send to client */
pj_turn_listener_sendto(alloc->listener, rel->tp.tx_pkt,
@@ -1009,6 +1018,18 @@ static void handle_peer_pkt(pj_turn_allocation *alloc,
alloc_err(alloc, "Error creating Data indication", status);
return;
}
+
+ pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
+ PJ_STUN_ATTR_PEER_ADDR, PJ_TRUE,
+ src_addr, pj_sockaddr_get_len(src_addr));
+ pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg,
+ PJ_STUN_ATTR_DATA,
+ (const pj_uint8_t*)pkt, len);
+
+ pj_stun_session_send_msg(alloc->sess, PJ_FALSE,
+ &alloc->hkey.clt_addr,
+ pj_sockaddr_get_len(&alloc->hkey.clt_addr),
+ tdata);
}
}
@@ -1186,6 +1207,9 @@ static pj_status_t stun_on_rx_request(pj_stun_session *sess,
/* Refresh permission */
refresh_permission(p1);
+ /* Send response */
+ send_reply_ok(alloc, rdata);
+
/* Done */
return PJ_SUCCESS;
}
@@ -1212,6 +1236,11 @@ static pj_status_t stun_on_rx_request(pj_stun_session *sess,
/* Assign channel number to permission */
p2->channel = PJ_STUN_GET_CH_NB(ch_attr->value);
+ /* Register to hash table */
+ pj_assert(sizeof(p2->channel==2));
+ pj_hash_set(alloc->pool, alloc->ch_table, &p2->channel,
+ sizeof(p2->channel), 0, p2);
+
/* Update */
refresh_permission(p2);
diff --git a/pjnath/src/pjturn-srv/auth.c b/pjnath/src/pjturn-srv/auth.c
index 3071221c..8e6c9c59 100644
--- a/pjnath/src/pjturn-srv/auth.c
+++ b/pjnath/src/pjturn-srv/auth.c
@@ -113,11 +113,11 @@ PJ_DEF(pj_status_t) pj_turn_get_password(const pj_stun_msg *msg,
* in the message can be accepted. If this callback returns
* PJ_FALSE, 438 (Stale Nonce) response will be created.
*/
-PJ_DEF(pj_status_t) pj_turn_verify_nonce(const pj_stun_msg *msg,
- void *user_data,
- const pj_str_t *realm,
- const pj_str_t *username,
- const pj_str_t *nonce)
+PJ_DEF(pj_bool_t) pj_turn_verify_nonce(const pj_stun_msg *msg,
+ void *user_data,
+ const pj_str_t *realm,
+ const pj_str_t *username,
+ const pj_str_t *nonce)
{
PJ_UNUSED_ARG(msg);
PJ_UNUSED_ARG(user_data);
@@ -127,6 +127,6 @@ PJ_DEF(pj_status_t) pj_turn_verify_nonce(const pj_stun_msg *msg,
if (pj_stricmp2(nonce, THE_NONCE))
return PJ_FALSE;
- return PJ_SUCCESS;
+ return PJ_TRUE;
}
diff --git a/pjnath/src/pjturn-srv/auth.h b/pjnath/src/pjturn-srv/auth.h
index db928051..2e342a73 100644
--- a/pjnath/src/pjturn-srv/auth.h
+++ b/pjnath/src/pjturn-srv/auth.h
@@ -105,11 +105,11 @@ PJ_DECL(pj_status_t) pj_turn_get_password(const pj_stun_msg *msg,
* @return The callback MUST return non-zero if the
* NONCE can be accepted.
*/
-PJ_DECL(pj_status_t) pj_turn_verify_nonce(const pj_stun_msg *msg,
- void *user_data,
- const pj_str_t *realm,
- const pj_str_t *username,
- const pj_str_t *nonce);
+PJ_DECL(pj_bool_t) pj_turn_verify_nonce(const pj_stun_msg *msg,
+ void *user_data,
+ const pj_str_t *realm,
+ const pj_str_t *username,
+ const pj_str_t *nonce);
#endif /* __PJ_TURN_SRV_AUTH_H__ */
diff --git a/pjnath/src/pjturn-srv/main.c b/pjnath/src/pjturn-srv/main.c
index 60c420b2..164b3c25 100644
--- a/pjnath/src/pjturn-srv/main.c
+++ b/pjnath/src/pjturn-srv/main.c
@@ -21,6 +21,8 @@
#define REALM "pjsip.org"
+static pj_caching_pool g_cp;
+
int err(const char *title, pj_status_t status)
{
char errmsg[PJ_ERR_MSG_SIZE];
@@ -30,9 +32,91 @@ int err(const char *title, pj_status_t status)
return 1;
}
+static void dump_status(pj_turn_srv *srv)
+{
+ char addr[80];
+ pj_hash_iterator_t itbuf, *it;
+ pj_time_val now;
+ unsigned i;
+
+ for (i=0; i<srv->core.lis_cnt; ++i) {
+ pj_turn_listener *lis = srv->core.listener[i];
+ printf("Server address : %s\n", lis->info);
+ }
+
+ printf("Worker threads : %d\n", srv->core.thread_cnt);
+ printf("Total mem usage: %d.%03dMB\n", g_cp.used_size / 1000000,
+ (g_cp.used_size % 1000000)/1000);
+ printf("UDP port range : %u %u %u (next/min/max)\n", srv->ports.next_udp,
+ srv->ports.min_udp, srv->ports.max_udp);
+ printf("TCP port range : %u %u %u (next/min/max)\n", srv->ports.next_tcp,
+ srv->ports.min_tcp, srv->ports.max_tcp);
+ printf("Clients # : %u\n", pj_hash_count(srv->tables.alloc));
+
+ puts("");
+
+ if (pj_hash_count(srv->tables.alloc)==0) {
+ return;
+ }
+
+ puts("# Client addr. Alloc addr. Username Lftm Expy #prm #chl");
+ puts("------------------------------------------------------------------------------");
+
+ pj_gettimeofday(&now);
+
+ it = pj_hash_first(srv->tables.alloc, &itbuf);
+ i=1;
+ while (it) {
+ pj_turn_allocation *alloc = (pj_turn_allocation*)
+ pj_hash_this(srv->tables.alloc, it);
+ printf("%-3d %-22s %-22s %-8.*s %-4d %-4d %-4d %-4d\n",
+ i,
+ alloc->info,
+ pj_sockaddr_print(&alloc->relay.hkey.addr, addr, sizeof(addr), 3),
+ (int)alloc->cred.data.static_cred.username.slen,
+ (int)alloc->cred.data.static_cred.username.ptr,
+ alloc->relay.lifetime,
+ alloc->relay.expiry.sec - now.sec,
+ pj_hash_count(alloc->peer_table),
+ pj_hash_count(alloc->ch_table));
+ it = pj_hash_next(srv->tables.alloc, it);
+ ++i;
+ }
+}
+
+static void menu(void)
+{
+ puts("");
+ puts("Menu:");
+ puts(" d Dump status");
+ puts(" q Quit");
+ printf(">> ");
+}
+
+static void console_main(pj_turn_srv *srv)
+{
+ pj_bool_t quit = PJ_FALSE;
+
+ while (!quit) {
+ char line[10];
+
+ menu();
+
+ fgets(line, sizeof(line), stdin);
+
+ switch (line[0]) {
+ case 'd':
+ dump_status(srv);
+ break;
+ case 'q':
+ quit = PJ_TRUE;
+ break;
+ }
+ }
+}
+
int main()
{
- pj_caching_pool cp;
pj_turn_srv *srv;
pj_turn_listener *listener;
pj_status_t status;
@@ -44,11 +128,11 @@ int main()
pjlib_util_init();
pjnath_init();
- pj_caching_pool_init(&cp, NULL, 0);
+ pj_caching_pool_init(&g_cp, NULL, 0);
pj_turn_auth_init(REALM);
- status = pj_turn_srv_create(&cp.factory, &srv);
+ status = pj_turn_srv_create(&g_cp.factory, &srv);
if (status != PJ_SUCCESS)
return err("Error creating server", status);
@@ -62,15 +146,11 @@ int main()
return err("Error adding listener", status);
puts("Server is running");
- puts("Press <ENTER> to quit");
- {
- char line[10];
- fgets(line, sizeof(line), stdin);
- }
+ console_main(srv);
pj_turn_srv_destroy(srv);
- pj_caching_pool_destroy(&cp);
+ pj_caching_pool_destroy(&g_cp);
pj_shutdown();
return 0;
diff --git a/pjnath/src/pjturn-srv/server.c b/pjnath/src/pjturn-srv/server.c
index b22cc53b..66f1c6a7 100644
--- a/pjnath/src/pjturn-srv/server.c
+++ b/pjnath/src/pjturn-srv/server.c
@@ -135,7 +135,7 @@ PJ_DEF(pj_status_t) pj_turn_srv_create(pj_pool_factory *pf,
/* Init ports settings */
srv->ports.min_udp = srv->ports.next_udp = MIN_PORT;
- srv->ports.max_tcp = MAX_PORT;
+ srv->ports.max_udp = MAX_PORT;
srv->ports.min_tcp = srv->ports.next_tcp = MIN_PORT;
srv->ports.max_tcp = MAX_PORT;
@@ -265,6 +265,18 @@ PJ_DEF(pj_status_t) pj_turn_srv_destroy(pj_turn_srv *srv)
}
}
+ /* Destroy all allocations FIRST */
+ if (srv->tables.alloc) {
+ it = pj_hash_first(srv->tables.alloc, &itbuf);
+ while (it != NULL) {
+ pj_turn_allocation *alloc = (pj_turn_allocation*)
+ pj_hash_this(srv->tables.alloc, it);
+ pj_hash_iterator_t *next = pj_hash_next(srv->tables.alloc, it);
+ pj_turn_allocation_destroy(alloc);
+ it = next;
+ }
+ }
+
/* Destroy all listeners and STUN sessions associated with them. */
for (i=0; i<srv->core.lis_cnt; ++i) {
if (srv->core.listener[i]) {
@@ -277,18 +289,6 @@ PJ_DEF(pj_status_t) pj_turn_srv_destroy(pj_turn_srv *srv)
}
}
- /* Destroy all allocations */
- if (srv->tables.alloc) {
- it = pj_hash_first(srv->tables.alloc, &itbuf);
- while (it != NULL) {
- pj_turn_allocation *alloc = (pj_turn_allocation*)
- pj_hash_this(srv->tables.alloc, it);
- pj_turn_allocation_destroy(alloc);
- it = pj_hash_next(srv->tables.alloc, it);
- }
- }
-
-
/* Destroy hash tables (well, sort of) */
if (srv->tables.alloc) {
srv->tables.alloc = NULL;
diff --git a/pjnath/src/pjturn-srv/turn.h b/pjnath/src/pjturn-srv/turn.h
index 2eb99254..337e8746 100644
--- a/pjnath/src/pjturn-srv/turn.h
+++ b/pjnath/src/pjturn-srv/turn.h
@@ -190,7 +190,7 @@ struct pj_turn_permission
pj_turn_allocation *allocation;
/** Optional channel number, or PJ_TURN_INVALID_CHANNEL if channel number
- * is not requested for this permission.
+ * is not requested for this permission.
*/
pj_uint16_t channel;