From f5c4ac3cbadd515c83b71618e7ff2b1683c2aca2 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Thu, 20 Mar 2008 16:32:06 +0000 Subject: More ticket #485: client and server self tested git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1879 74dad513-b988-da41-8d7b-12977e46ad98 --- pjnath/src/pjnath/stun_session.c | 3 + pjnath/src/pjnath/turn_session.c | 43 ++++++++-- pjnath/src/pjnath/turn_udp.c | 147 +++++++++++++++++++++++++++++---- pjnath/src/pjturn-client/client_main.c | 59 +++++++------ pjnath/src/pjturn-srv/allocation.c | 79 ++++++++++++------ pjnath/src/pjturn-srv/auth.c | 12 +-- pjnath/src/pjturn-srv/auth.h | 10 +-- pjnath/src/pjturn-srv/main.c | 98 ++++++++++++++++++++-- pjnath/src/pjturn-srv/server.c | 26 +++--- pjnath/src/pjturn-srv/turn.h | 2 +- 10 files changed, 366 insertions(+), 113 deletions(-) (limited to 'pjnath/src') 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 #include #include +#include #include #include #include +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; icore.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 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; icore.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; -- cgit v1.2.3