A really initial implementation on STUN server
git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1049 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
12e1daa4b9
commit
e631558f81
|
@ -99,6 +99,10 @@ SOURCE="..\src\pjstun-srv-test\server.c"
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE="..\src\pjstun-srv-test\turn_usage.c"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE="..\src\pjstun-srv-test\usage.c"
|
||||
# End Source File
|
||||
# End Group
|
||||
|
|
|
@ -338,13 +338,13 @@ typedef enum pj_stun_attr_type
|
|||
PJ_STUN_ATTR_DATA = 0x0013,/**< DATA attribute. */
|
||||
PJ_STUN_ATTR_REALM = 0x0014,/**< REALM attribute. */
|
||||
PJ_STUN_ATTR_NONCE = 0x0015,/**< NONCE attribute. */
|
||||
PJ_STUN_ATTR_RELAY_ADDRESS = 0x0016,/**< RELAY-ADDRESS attribute. */
|
||||
PJ_STUN_ATTR_REQUESTED_ADDR_TYPE= 0x0017,/**< REQUESTED-ADDRESS-TYPE */
|
||||
PJ_STUN_ATTR_REQUESTED_PORT_PROPS=0x0018,/**< REQUESTED-PORT-PROPS */
|
||||
PJ_STUN_ATTR_REQUESTED_TRANSPORT= 0x0019,/**< REQUESTED-TRANSPORT */
|
||||
PJ_STUN_ATTR_XOR_MAPPED_ADDRESS = 0x0020,/**< XOR-MAPPED-ADDRESS */
|
||||
PJ_STUN_ATTR_RELAY_ADDR = 0x0016,/**< RELAY-ADDRESS attribute. */
|
||||
PJ_STUN_ATTR_REQ_ADDR_TYPE = 0x0017,/**< REQUESTED-ADDRESS-TYPE */
|
||||
PJ_STUN_ATTR_REQ_PORT_PROPS = 0x0018,/**< REQUESTED-PORT-PROPS */
|
||||
PJ_STUN_ATTR_REQ_TRANSPORT = 0x0019,/**< REQUESTED-TRANSPORT */
|
||||
PJ_STUN_ATTR_XOR_MAPPED_ADDR = 0x0020,/**< XOR-MAPPED-ADDRESS */
|
||||
PJ_STUN_ATTR_TIMER_VAL = 0x0021,/**< TIMER-VAL attribute. */
|
||||
PJ_STUN_ATTR_REQUESTED_IP = 0x0022,/**< REQUESTED-IP attribute */
|
||||
PJ_STUN_ATTR_REQ_IP = 0x0022,/**< REQUESTED-IP attribute */
|
||||
PJ_STUN_ATTR_XOR_REFLECTED_FROM = 0x0023,/**< XOR-REFLECTED-FROM */
|
||||
PJ_STUN_ATTR_PRIORITY = 0x0024,/**< PRIORITY */
|
||||
PJ_STUN_ATTR_USE_CANDIDATE = 0x0025,/**< USE-CANDIDATE */
|
||||
|
@ -390,7 +390,9 @@ typedef enum pj_stun_status
|
|||
PJ_STUN_STATUS_OPER_TCP_ONLY = 445, /**< Operation for TCP Only */
|
||||
PJ_STUN_STATUS_CONNECTION_FAILURE = 446, /**< Connection Failure */
|
||||
PJ_STUN_STATUS_CONNECTION_TIMEOUT = 447, /**< Connection Timeout */
|
||||
PJ_STUN_STATUS_ALLOCATION_QUOTA_REACHED = 486, /**< Allocation Quota Reached (TURN) */
|
||||
PJ_STUN_STATUS_SERVER_ERROR = 500, /**< Server Error */
|
||||
PJ_STUN_STATUS_INSUFFICIENT_CAPACITY = 507, /**< Insufficient Capacity (TURN) */
|
||||
PJ_STUN_STATUS_GLOBAL_FAILURE = 600 /**< Global Failure */
|
||||
} pj_stun_status;
|
||||
|
||||
|
@ -933,7 +935,7 @@ typedef struct pj_stun_ip_addr_attr pj_stun_relay_addr_attr;
|
|||
|
||||
\endverbatim
|
||||
*/
|
||||
typedef struct pj_stun_uint_attr pj_stun_requested_addr_type;
|
||||
typedef struct pj_stun_uint_attr pj_stun_req_addr_type;
|
||||
|
||||
/**
|
||||
* This describes the STUN REQUESTED-PORT-PROPS attribute.
|
||||
|
@ -953,7 +955,7 @@ typedef struct pj_stun_uint_attr pj_stun_requested_addr_type;
|
|||
|
||||
\endverbatim
|
||||
*/
|
||||
typedef struct pj_stun_uint_attr pj_stun_requested_port_props_attr;
|
||||
typedef struct pj_stun_uint_attr pj_stun_req_port_props_attr;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -962,7 +964,7 @@ typedef struct pj_stun_uint_attr pj_stun_requested_port_props_attr;
|
|||
* protocol for the allocated transport address. It is a 32 bit
|
||||
* unsigned integer. Its values are: 0x0000 for UDP and 0x0000 for TCP.
|
||||
*/
|
||||
typedef struct pj_stun_uint_attr pj_stun_requested_transport_attr;
|
||||
typedef struct pj_stun_uint_attr pj_stun_req_transport_attr;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -970,7 +972,7 @@ typedef struct pj_stun_uint_attr pj_stun_requested_transport_attr;
|
|||
* The REQUESTED-IP attribute is used by the client to request that a
|
||||
* specific IP address be allocated to it.
|
||||
*/
|
||||
typedef struct pj_stun_ip_addr_attr pj_stun_requested_ip_attr;
|
||||
typedef struct pj_stun_ip_addr_attr pj_stun_req_ip_attr;
|
||||
|
||||
/**
|
||||
* This describes the XOR-REFLECTED-FROM attribute, as described by
|
||||
|
|
|
@ -71,7 +71,9 @@ static struct
|
|||
{ PJ_STUN_STATUS_OPER_TCP_ONLY, "Operation for TCP Only"},
|
||||
{ PJ_STUN_STATUS_CONNECTION_FAILURE, "Connection Failure"},
|
||||
{ PJ_STUN_STATUS_CONNECTION_TIMEOUT, "Connection Timeout"},
|
||||
{ PJ_STUN_STATUS_ALLOCATION_QUOTA_REACHED, "Allocation Quota Reached"},
|
||||
{ PJ_STUN_STATUS_SERVER_ERROR, "Server Error"},
|
||||
{ PJ_STUN_STATUS_INSUFFICIENT_CAPACITY, "Insufficient Capacity"},
|
||||
{ PJ_STUN_STATUS_GLOBAL_FAILURE, "Global Failure"}
|
||||
};
|
||||
|
||||
|
|
|
@ -69,9 +69,9 @@ static int print_attr(char *buffer, unsigned length,
|
|||
case PJ_STUN_ATTR_CHANGED_ADDR:
|
||||
case PJ_STUN_ATTR_REFLECTED_FROM:
|
||||
case PJ_STUN_ATTR_REMOTE_ADDRESS:
|
||||
case PJ_STUN_ATTR_RELAY_ADDRESS:
|
||||
case PJ_STUN_ATTR_XOR_MAPPED_ADDRESS:
|
||||
case PJ_STUN_ATTR_REQUESTED_IP:
|
||||
case PJ_STUN_ATTR_RELAY_ADDR:
|
||||
case PJ_STUN_ATTR_XOR_MAPPED_ADDR:
|
||||
case PJ_STUN_ATTR_REQ_IP:
|
||||
case PJ_STUN_ATTR_XOR_REFLECTED_FROM:
|
||||
case PJ_STUN_ATTR_XOR_INTERNAL_ADDR:
|
||||
case PJ_STUN_ATTR_ALTERNATE_SERVER:
|
||||
|
@ -99,9 +99,9 @@ static int print_attr(char *buffer, unsigned length,
|
|||
case PJ_STUN_ATTR_CHANGE_REQUEST:
|
||||
case PJ_STUN_ATTR_LIFETIME:
|
||||
case PJ_STUN_ATTR_BANDWIDTH:
|
||||
case PJ_STUN_ATTR_REQUESTED_ADDR_TYPE:
|
||||
case PJ_STUN_ATTR_REQUESTED_PORT_PROPS:
|
||||
case PJ_STUN_ATTR_REQUESTED_TRANSPORT:
|
||||
case PJ_STUN_ATTR_REQ_ADDR_TYPE:
|
||||
case PJ_STUN_ATTR_REQ_PORT_PROPS:
|
||||
case PJ_STUN_ATTR_REQ_TRANSPORT:
|
||||
case PJ_STUN_ATTR_TIMER_VAL:
|
||||
case PJ_STUN_ATTR_PRIORITY:
|
||||
case PJ_STUN_ATTR_FINGERPRINT:
|
||||
|
|
|
@ -176,6 +176,7 @@ static void destroy_tdata(pj_stun_tx_data *tdata)
|
|||
pj_timer_heap_cancel(tdata->sess->endpt->timer_heap,
|
||||
&tdata->res_timer);
|
||||
tdata->res_timer.id = PJ_FALSE;
|
||||
pj_list_erase(tdata);
|
||||
}
|
||||
pj_pool_release(tdata->pool);
|
||||
}
|
||||
|
@ -348,6 +349,17 @@ PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess)
|
|||
{
|
||||
PJ_ASSERT_RETURN(sess, PJ_EINVAL);
|
||||
|
||||
pj_mutex_lock(sess->mutex);
|
||||
while (!pj_list_empty(&sess->pending_request_list)) {
|
||||
pj_stun_tx_data *tdata = sess->pending_request_list.next;
|
||||
destroy_tdata(tdata);
|
||||
}
|
||||
while (!pj_list_empty(&sess->cached_response_list)) {
|
||||
pj_stun_tx_data *tdata = sess->cached_response_list.next;
|
||||
destroy_tdata(tdata);
|
||||
}
|
||||
pj_mutex_unlock(sess->mutex);
|
||||
|
||||
pj_mutex_destroy(sess->mutex);
|
||||
pj_pool_release(sess->pool);
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ static void usage_on_rx_data(pj_stun_usage *usage,
|
|||
pj_size_t pkt_size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len);
|
||||
static void usage_on_destroy(pj_stun_usage *usage);
|
||||
static pj_status_t sess_on_send_msg(pj_stun_session *sess,
|
||||
const void *pkt,
|
||||
pj_size_t pkt_size,
|
||||
|
@ -37,14 +38,22 @@ static pj_status_t sess_on_rx_request(pj_stun_session *sess,
|
|||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len);
|
||||
|
||||
struct bind_usage
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
pj_stun_usage *usage;
|
||||
pj_stun_session *session;
|
||||
};
|
||||
|
||||
|
||||
PJ_DEF(pj_status_t) pj_stun_bind_usage_create(pj_stun_server *srv,
|
||||
const pj_str_t *ip_addr,
|
||||
unsigned port,
|
||||
pj_stun_usage **p_bu)
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
struct bind_usage *bu;
|
||||
pj_stun_server_info *si;
|
||||
pj_stun_session *session;
|
||||
pj_stun_usage *usage;
|
||||
pj_stun_usage_cb usage_cb;
|
||||
pj_stun_session_cb sess_cb;
|
||||
pj_sockaddr_in local_addr;
|
||||
|
@ -52,34 +61,42 @@ PJ_DEF(pj_status_t) pj_stun_bind_usage_create(pj_stun_server *srv,
|
|||
|
||||
si = pj_stun_server_get_info(srv);
|
||||
|
||||
pool = pj_pool_create(si->pf, "bind%p", 128, 128, NULL);
|
||||
bu = PJ_POOL_ZALLOC_T(pool, struct bind_usage);
|
||||
bu->pool = pool;
|
||||
|
||||
status = pj_sockaddr_in_init(&local_addr, ip_addr, (pj_uint16_t)port);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
pj_bzero(&usage_cb, sizeof(usage_cb));
|
||||
usage_cb.on_rx_data = &usage_on_rx_data;
|
||||
usage_cb.on_destroy = &usage_on_destroy;
|
||||
|
||||
status = pj_stun_usage_create(srv, "bind%p", &usage_cb,
|
||||
PJ_AF_INET, PJ_SOCK_DGRAM, 0,
|
||||
&local_addr, sizeof(local_addr),
|
||||
&usage);
|
||||
if (status != PJ_SUCCESS)
|
||||
&bu->usage);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_pool_release(pool);
|
||||
return status;
|
||||
}
|
||||
|
||||
pj_bzero(&sess_cb, sizeof(sess_cb));
|
||||
sess_cb.on_send_msg = &sess_on_send_msg;
|
||||
sess_cb.on_rx_request = &sess_on_rx_request;
|
||||
status = pj_stun_session_create(si->endpt, "bind%p", &sess_cb, PJ_FALSE,
|
||||
&session);
|
||||
&bu->session);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_stun_usage_destroy(usage);
|
||||
pj_stun_usage_destroy(bu->usage);
|
||||
return status;
|
||||
}
|
||||
|
||||
pj_stun_usage_set_user_data(usage, session);
|
||||
pj_stun_session_set_user_data(session, usage);
|
||||
pj_stun_usage_set_user_data(bu->usage, bu);
|
||||
pj_stun_session_set_user_data(bu->session, bu);
|
||||
|
||||
*p_bu = usage;
|
||||
if (p_bu)
|
||||
*p_bu = bu->usage;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
@ -91,10 +108,12 @@ static void usage_on_rx_data(pj_stun_usage *usage,
|
|||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len)
|
||||
{
|
||||
struct bind_usage *bu;
|
||||
pj_stun_session *session;
|
||||
pj_status_t status;
|
||||
|
||||
session = (pj_stun_session*) pj_stun_usage_get_user_data(usage);
|
||||
bu = (struct bind_usage*) pj_stun_usage_get_user_data(usage);
|
||||
session = bu->session;
|
||||
|
||||
/* Handle packet to session */
|
||||
status = pj_stun_session_on_rx_pkt(session, (pj_uint8_t*)pkt, pkt_size,
|
||||
|
@ -113,9 +132,11 @@ static pj_status_t sess_on_send_msg(pj_stun_session *sess,
|
|||
const pj_sockaddr_t *dst_addr,
|
||||
unsigned addr_len)
|
||||
{
|
||||
struct bind_usage *bu;
|
||||
pj_stun_usage *usage;
|
||||
|
||||
usage = pj_stun_session_get_user_data(sess);
|
||||
bu = (struct bind_usage*) pj_stun_session_get_user_data(sess);
|
||||
usage = bu->usage;
|
||||
|
||||
return pj_stun_usage_sendto(usage, pkt, pkt_size, 0,
|
||||
dst_addr, addr_len);
|
||||
|
@ -155,7 +176,7 @@ static pj_status_t sess_on_rx_request(pj_stun_session *sess,
|
|||
if (msg->hdr.magic == PJ_STUN_MAGIC) {
|
||||
status =
|
||||
pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg,
|
||||
PJ_STUN_ATTR_XOR_MAPPED_ADDRESS,
|
||||
PJ_STUN_ATTR_XOR_MAPPED_ADDR,
|
||||
PJ_TRUE,
|
||||
src_addr, src_addr_len);
|
||||
if (status != PJ_SUCCESS) {
|
||||
|
@ -172,3 +193,14 @@ static pj_status_t sess_on_rx_request(pj_stun_session *sess,
|
|||
|
||||
}
|
||||
|
||||
static void usage_on_destroy(pj_stun_usage *usage)
|
||||
{
|
||||
struct bind_usage *bu;
|
||||
|
||||
bu = (struct bind_usage*) pj_stun_usage_get_user_data(usage);
|
||||
if (bu==NULL)
|
||||
return;
|
||||
|
||||
pj_stun_session_destroy(bu->session);
|
||||
pj_pool_release(bu->pool);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
#include "server.h"
|
||||
|
||||
#define THIS_FILE "main.c"
|
||||
|
||||
struct options
|
||||
{
|
||||
char *realm;
|
||||
|
@ -41,7 +43,7 @@ static void usage(void)
|
|||
}
|
||||
|
||||
|
||||
static void server_main(void)
|
||||
static void server_main(pj_stun_server *srv)
|
||||
{
|
||||
int quit = 0;
|
||||
|
||||
|
@ -49,12 +51,17 @@ static void server_main(void)
|
|||
char line[10];
|
||||
|
||||
printf("Menu:\n"
|
||||
" d Dump status\n"
|
||||
" q Quit\n"
|
||||
"Choice:");
|
||||
|
||||
fgets(line, sizeof(line), stdin);
|
||||
if (line[0] == 'q')
|
||||
if (line[0] == 'q') {
|
||||
quit = 1;
|
||||
} else if (line[0] == 'd') {
|
||||
pj_stun_server_info *si = pj_stun_server_get_info(srv);
|
||||
pj_pool_factory_dump(si->pf, PJ_TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,7 +78,6 @@ int main(int argc, char *argv[])
|
|||
int c, opt_id;
|
||||
pj_caching_pool cp;
|
||||
pj_stun_server *srv;
|
||||
pj_stun_usage *bu;
|
||||
pj_status_t status;
|
||||
|
||||
while((c=pj_getopt_long(argc,argv, "r:u:p:hF", long_options, &opt_id))!=-1) {
|
||||
|
@ -116,15 +122,14 @@ int main(int argc, char *argv[])
|
|||
return 1;
|
||||
}
|
||||
|
||||
status = pj_stun_bind_usage_create(srv, NULL, 3478, &bu);
|
||||
status = pj_stun_bind_usage_create(srv, NULL, 3478, NULL);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_stun_perror(THIS_FILE, "Unable to create bind usage", status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
server_main();
|
||||
server_main(srv);
|
||||
|
||||
pj_stun_usage_destroy(bu);
|
||||
pj_stun_server_destroy(srv);
|
||||
pj_pool_factory_dump(&cp.factory, PJ_TRUE);
|
||||
pj_shutdown();
|
||||
|
|
|
@ -29,6 +29,9 @@ struct pj_stun_server
|
|||
|
||||
pj_bool_t thread_quit_flag;
|
||||
pj_thread_t **threads;
|
||||
|
||||
unsigned usage_cnt;
|
||||
pj_stun_usage *usage[32];
|
||||
};
|
||||
|
||||
PJ_DEF(pj_status_t) pj_stun_perror( const char *sender,
|
||||
|
@ -109,10 +112,62 @@ PJ_DEF(pj_stun_server_info*) pj_stun_server_get_info(pj_stun_server *srv)
|
|||
}
|
||||
|
||||
|
||||
pj_status_t pj_stun_server_register_usage(pj_stun_server *srv,
|
||||
pj_stun_usage *usage)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<PJ_ARRAY_SIZE(srv->usage); ++i) {
|
||||
if (srv->usage[i] == usage)
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
for (i=0; i<PJ_ARRAY_SIZE(srv->usage); ++i) {
|
||||
if (srv->usage[i] == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == PJ_ARRAY_SIZE(srv->usage))
|
||||
return PJ_ETOOMANY;
|
||||
|
||||
srv->usage[i] = usage;
|
||||
++srv->usage_cnt;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
pj_status_t pj_stun_server_unregister_usage(pj_stun_server *srv,
|
||||
pj_stun_usage *usage)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<PJ_ARRAY_SIZE(srv->usage); ++i) {
|
||||
if (srv->usage[i] == usage)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i != PJ_ARRAY_SIZE(srv->usage)) {
|
||||
srv->usage[i] = NULL;
|
||||
--srv->usage_cnt;
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
return PJ_ENOTFOUND;
|
||||
}
|
||||
|
||||
|
||||
PJ_DEF(pj_status_t) pj_stun_server_destroy(pj_stun_server *srv)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<PJ_ARRAY_SIZE(srv->usage); ++i) {
|
||||
if (!srv->usage[i])
|
||||
continue;
|
||||
|
||||
pj_stun_usage_destroy(srv->usage[i]);
|
||||
pj_stun_server_unregister_usage(srv, srv->usage[i]);
|
||||
}
|
||||
|
||||
srv->thread_quit_flag = PJ_TRUE;
|
||||
for (i=0; i<srv->si.thread_cnt; ++i) {
|
||||
pj_thread_join(srv->threads[i]);
|
||||
|
|
|
@ -47,6 +47,7 @@ typedef struct pj_stun_usage_cb
|
|||
pj_size_t pkt_size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len);
|
||||
void (*on_destroy)(pj_stun_usage *usage);
|
||||
} pj_stun_usage_cb;
|
||||
|
||||
|
||||
|
@ -117,6 +118,13 @@ PJ_DEF(pj_status_t) pj_stun_bind_usage_create(pj_stun_server *srv,
|
|||
pj_stun_usage **p_bu);
|
||||
|
||||
|
||||
|
||||
pj_status_t pj_stun_server_register_usage(pj_stun_server *srv,
|
||||
pj_stun_usage *usage);
|
||||
pj_status_t pj_stun_server_unregister_usage(pj_stun_server *srv,
|
||||
pj_stun_usage *usage);
|
||||
|
||||
|
||||
#endif /* __STUN_SERVER_H__ */
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,662 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
* Copyright (C) 2003-2005 Benny Prijono <benny@prijono.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "server.h"
|
||||
|
||||
#define THIS_FILE "turn_usage.c"
|
||||
|
||||
#define MAX_CLIENTS 8000
|
||||
#define MAX_PEER_PER_CLIENTS 16
|
||||
#define START_PORT 2000
|
||||
#define END_PORT 65530
|
||||
|
||||
static void tu_on_rx_data(pj_stun_usage *usage,
|
||||
void *pkt,
|
||||
pj_size_t pkt_size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len);
|
||||
static void tu_on_destroy(pj_stun_usage *usage);
|
||||
|
||||
static pj_status_t sess_on_send_msg(pj_stun_session *sess,
|
||||
const void *pkt,
|
||||
pj_size_t pkt_size,
|
||||
const pj_sockaddr_t *dst_addr,
|
||||
unsigned addr_len);
|
||||
static pj_status_t sess_on_rx_request(pj_stun_session *sess,
|
||||
const pj_uint8_t *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_stun_msg *msg,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len);
|
||||
|
||||
|
||||
struct turn_usage
|
||||
{
|
||||
pj_pool_factory *pf;
|
||||
pj_stun_endpoint *endpt;
|
||||
pj_ioqueue_t *ioqueue;
|
||||
pj_pool_t *pool;
|
||||
pj_stun_usage *usage;
|
||||
int type;
|
||||
pj_stun_session *default_session;
|
||||
pj_hash_table_t *client_htable;
|
||||
pj_hash_table_t *peer_htable;
|
||||
|
||||
unsigned max_bw_kbps;
|
||||
unsigned max_lifetime;
|
||||
|
||||
unsigned next_port;
|
||||
};
|
||||
|
||||
struct peer;
|
||||
|
||||
struct turn_client
|
||||
{
|
||||
struct turn_usage *tu;
|
||||
pj_pool_t *pool;
|
||||
pj_sockaddr_in addr;
|
||||
pj_stun_session *session;
|
||||
|
||||
unsigned bw_kbps;
|
||||
unsigned lifetime;
|
||||
|
||||
pj_sock_t sock;
|
||||
pj_ioqueue_key_t *key;
|
||||
char packet[4000];
|
||||
pj_sockaddr_in src_addr;
|
||||
int src_addr_len;
|
||||
pj_ioqueue_op_key_t read_key;
|
||||
pj_ioqueue_op_key_t write_key;
|
||||
|
||||
pj_bool_t has_ad;
|
||||
pj_bool_t ad_is_pending;
|
||||
pj_sockaddr_in ad;
|
||||
};
|
||||
|
||||
struct peer
|
||||
{
|
||||
struct turn_client *client;
|
||||
pj_sockaddr_in addr;
|
||||
};
|
||||
|
||||
struct session_data
|
||||
{
|
||||
struct turn_usage *tu;
|
||||
struct turn_client *client;
|
||||
};
|
||||
|
||||
|
||||
PJ_DEF(pj_status_t) pj_stun_turn_usage_create(pj_stun_server *srv,
|
||||
int type,
|
||||
const pj_str_t *ip_addr,
|
||||
unsigned port,
|
||||
pj_stun_usage **p_bu)
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
struct turn_usage *tu;
|
||||
pj_stun_server_info *si;
|
||||
pj_stun_usage_cb usage_cb;
|
||||
pj_stun_session_cb sess_cb;
|
||||
struct session_data *sd;
|
||||
pj_sockaddr_in local_addr;
|
||||
pj_status_t status;
|
||||
|
||||
PJ_ASSERT_RETURN(srv && (type==PJ_SOCK_DGRAM||type==PJ_SOCK_STREAM) &&
|
||||
p_bu, PJ_EINVAL);
|
||||
si = pj_stun_server_get_info(srv);
|
||||
|
||||
pool = pj_pool_create(si->pf, "turn%p", 4000, 4000, NULL);
|
||||
tu = PJ_POOL_ZALLOC_T(pool, struct turn_usage);
|
||||
tu->pool = pool;
|
||||
tu->type = type;
|
||||
tu->pf = si->pf;
|
||||
tu->endpt = si->endpt;
|
||||
tu->next_port = START_PORT;
|
||||
|
||||
status = pj_sockaddr_in_init(&local_addr, ip_addr, (pj_uint16_t)port);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Create usage */
|
||||
pj_bzero(&usage_cb, sizeof(usage_cb));
|
||||
usage_cb.on_rx_data = &tu_on_rx_data;
|
||||
usage_cb.on_destroy = &tu_on_destroy;
|
||||
status = pj_stun_usage_create(srv, "turn%p", &usage_cb,
|
||||
PJ_AF_INET, tu->type, 0,
|
||||
&local_addr, sizeof(local_addr),
|
||||
&tu->usage);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_pool_release(pool);
|
||||
return status;
|
||||
}
|
||||
pj_stun_usage_set_user_data(tu->usage, tu);
|
||||
|
||||
/* Init hash tables */
|
||||
tu->client_htable = pj_hash_create(tu->pool, MAX_CLIENTS);
|
||||
tu->peer_htable = pj_hash_create(tu->pool, MAX_CLIENTS);
|
||||
|
||||
/* Create default session */
|
||||
pj_bzero(&sess_cb, sizeof(sess_cb));
|
||||
sess_cb.on_send_msg = &sess_on_send_msg;
|
||||
sess_cb.on_rx_request = &sess_on_rx_request;
|
||||
status = pj_stun_session_create(si->endpt, "turns%p", &sess_cb, PJ_FALSE,
|
||||
&tu->default_session);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_stun_usage_destroy(tu->usage);
|
||||
return status;
|
||||
}
|
||||
|
||||
sd = PJ_POOL_ZALLOC_T(pool, struct session_data);
|
||||
sd->tu = tu;
|
||||
pj_stun_session_set_user_data(tu->default_session, sd);
|
||||
|
||||
*p_bu = tu->usage;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void tu_on_destroy(pj_stun_usage *usage)
|
||||
{
|
||||
struct turn_usage *tu;
|
||||
|
||||
tu = (struct turn_usage*) pj_stun_usage_get_user_data(usage);
|
||||
PJ_TODO(DESTROY_ALL_CLIENTS);
|
||||
pj_pool_release(tu->pool);
|
||||
}
|
||||
|
||||
|
||||
static void tu_on_rx_data(pj_stun_usage *usage,
|
||||
void *pkt,
|
||||
pj_size_t pkt_size,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len)
|
||||
{
|
||||
struct turn_usage *tu;
|
||||
pj_stun_session *session;
|
||||
struct turn_client *client;
|
||||
unsigned flags;
|
||||
pj_status_t status;
|
||||
|
||||
/* Which usage instance is this */
|
||||
tu = (struct turn_usage*) pj_stun_usage_get_user_data(usage);
|
||||
|
||||
/* Lookup client structure based on source address */
|
||||
client = (struct turn_client*) pj_hash_get(tu->client_htable, src_addr,
|
||||
src_addr_len, NULL);
|
||||
|
||||
if (client == NULL) {
|
||||
session = tu->default_session;
|
||||
} else {
|
||||
session = client->session;
|
||||
}
|
||||
|
||||
/* Handle packet to session */
|
||||
flags = PJ_STUN_CHECK_PACKET;
|
||||
if (tu->type == PJ_SOCK_DGRAM)
|
||||
flags |= PJ_STUN_IS_DATAGRAM;
|
||||
|
||||
status = pj_stun_session_on_rx_pkt(session, (pj_uint8_t*)pkt, pkt_size,
|
||||
flags, NULL, src_addr, src_addr_len);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_stun_perror(THIS_FILE, "Error handling incoming packet", status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static pj_status_t tu_alloc_port(struct turn_usage *tu,
|
||||
int type,
|
||||
unsigned rpp_bits,
|
||||
const pj_sockaddr_in *req_addr,
|
||||
pj_sock_t *p_sock,
|
||||
int *err_code)
|
||||
{
|
||||
enum { RETRY = 100 };
|
||||
pj_sockaddr_in addr;
|
||||
pj_sock_t sock = PJ_INVALID_SOCKET;
|
||||
unsigned retry;
|
||||
pj_status_t status;
|
||||
|
||||
if (req_addr && req_addr->sin_port != 0) {
|
||||
|
||||
*err_code = PJ_STUN_STATUS_INVALID_PORT;
|
||||
|
||||
/* Allocate specific port */
|
||||
status = pj_sock_socket(PJ_AF_INET, type, 0, &sock);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Bind */
|
||||
status = pj_sock_bind(sock, req_addr, sizeof(pj_sockaddr_in));
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_sock_close(sock);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
*p_sock = sock;
|
||||
return PJ_SUCCESS;
|
||||
|
||||
} else {
|
||||
*err_code = PJ_STUN_STATUS_INSUFFICIENT_CAPACITY;
|
||||
|
||||
if (req_addr && req_addr->sin_addr.s_addr) {
|
||||
*err_code = PJ_STUN_STATUS_INVALID_IP_ADDR;
|
||||
pj_memcpy(&addr, req_addr, sizeof(pj_sockaddr_in));
|
||||
} else {
|
||||
pj_sockaddr_in_init(&addr, NULL, 0);
|
||||
}
|
||||
|
||||
for (retry=0; retry<RETRY && sock == PJ_INVALID_SOCKET; ++retry) {
|
||||
switch (rpp_bits) {
|
||||
case 1:
|
||||
if ((tu->next_port & 0x01)==0)
|
||||
tu->next_port++;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
if ((tu->next_port & 0x01)==1)
|
||||
tu->next_port++;
|
||||
break;
|
||||
}
|
||||
|
||||
status = pj_sock_socket(PJ_AF_INET, type, 0, &sock);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
addr.sin_port = pj_htons((pj_uint16_t)tu->next_port);
|
||||
|
||||
if (++tu->next_port > END_PORT)
|
||||
tu->next_port = START_PORT;
|
||||
|
||||
status = pj_sock_bind(sock, &addr, sizeof(addr));
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_sock_close(sock);
|
||||
sock = PJ_INVALID_SOCKET;
|
||||
|
||||
/* If client requested specific IP address, assume that
|
||||
* bind failed because the IP address is not valid. We
|
||||
* don't want to retry that since it will exhaust our
|
||||
* port space.
|
||||
*/
|
||||
if (req_addr && req_addr->sin_addr.s_addr)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sock == PJ_INVALID_SOCKET) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static pj_status_t client_create(struct turn_usage *tu,
|
||||
const pj_stun_msg *msg,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len,
|
||||
struct turn_client **p_client)
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
struct turn_client *client;
|
||||
pj_stun_session_cb sess_cb;
|
||||
struct session_data *sd;
|
||||
pj_status_t status;
|
||||
|
||||
PJ_UNUSED_ARG(msg);
|
||||
|
||||
pool = pj_pool_create(tu->pf, "turnc%p", 4000, 4000, NULL);
|
||||
client = PJ_POOL_ZALLOC_T(pool, struct turn_client);
|
||||
client->pool = pool;
|
||||
client->tu = tu;
|
||||
client->sock = PJ_INVALID_SOCKET;
|
||||
|
||||
/* Create session */
|
||||
pj_bzero(&sess_cb, sizeof(sess_cb));
|
||||
sess_cb.on_send_msg = &sess_on_send_msg;
|
||||
sess_cb.on_rx_request = &sess_on_rx_request;
|
||||
status = pj_stun_session_create(tu->endpt, "turnc%p", &sess_cb, PJ_FALSE,
|
||||
&client->session);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_pool_release(pool);
|
||||
return status;
|
||||
}
|
||||
|
||||
sd = PJ_POOL_ZALLOC_T(pool, struct session_data);
|
||||
sd->tu = tu;
|
||||
sd->client = client;
|
||||
pj_stun_session_set_user_data(client->session, sd);
|
||||
|
||||
/* Register to hash table */
|
||||
pj_hash_set(pool, tu->client_htable, src_addr, src_addr_len, 0, client);
|
||||
|
||||
*p_client = client;
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
static pj_status_t client_destroy(struct turn_client *client)
|
||||
{
|
||||
}
|
||||
|
||||
static void client_on_read_complete(pj_ioqueue_key_t *key,
|
||||
pj_ioqueue_op_key_t *op_key,
|
||||
pj_ssize_t bytes_read)
|
||||
{
|
||||
}
|
||||
|
||||
static void client_on_write_complete(pj_ioqueue_key_t *key,
|
||||
pj_ioqueue_op_key_t *op_key,
|
||||
pj_ssize_t bytes_sent)
|
||||
{
|
||||
}
|
||||
|
||||
static pj_status_t client_create_relay(struct turn_client *client)
|
||||
{
|
||||
pj_ioqueue_callback client_ioq_cb;
|
||||
pj_status_t status;
|
||||
|
||||
/* Register to ioqueue */
|
||||
pj_bzero(&client_ioq_cb, sizeof(client_ioq_cb));
|
||||
client_ioq_cb.on_read_complete = &client_on_read_complete;
|
||||
client_ioq_cb.on_write_complete = &client_on_write_complete;
|
||||
status = pj_ioqueue_register_sock(client->pool, client->tu->ioqueue,
|
||||
client->sock, client,
|
||||
&client_ioq_cb, &client->key);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_sock_close(client->sock);
|
||||
client->sock = PJ_INVALID_SOCKET;
|
||||
return status;
|
||||
}
|
||||
|
||||
pj_ioqueue_op_key_init(&client->read_key, sizeof(client->read_key));
|
||||
pj_ioqueue_op_key_init(&client->write_key, sizeof(client->write_key));
|
||||
|
||||
/* Trigger the first read */
|
||||
client_on_read_complete(client->key, &client->read_key, 0);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
static pj_status_t client_handle_allocate_req(struct turn_client *client,
|
||||
const pj_uint8_t *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_stun_msg *msg,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len)
|
||||
{
|
||||
const pj_stun_bandwidth_attr *a_bw;
|
||||
const pj_stun_lifetime_attr *a_lf;
|
||||
const pj_stun_req_port_props_attr *a_rpp;
|
||||
const pj_stun_req_transport_attr *a_rt;
|
||||
const pj_stun_req_ip_attr *a_rip;
|
||||
pj_stun_tx_data *response;
|
||||
pj_sockaddr_in req_addr;
|
||||
int addr_len;
|
||||
unsigned type;
|
||||
unsigned rpp_bits;
|
||||
pj_status_t status;
|
||||
|
||||
a_bw = (const pj_stun_bandwidth_attr *)
|
||||
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_BANDWIDTH, 0);
|
||||
a_lf = (const pj_stun_lifetime_attr*)
|
||||
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_LIFETIME, 0);
|
||||
a_rpp = (const pj_stun_req_port_props_attr*)
|
||||
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REQ_PORT_PROPS, 0);
|
||||
a_rt = (const pj_stun_req_transport_attr*)
|
||||
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REQ_TRANSPORT, 0);
|
||||
a_rip = (const pj_stun_req_ip_attr*)
|
||||
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REQ_IP, 0);
|
||||
|
||||
/* Init requested local address */
|
||||
pj_sockaddr_in_init(&req_addr, NULL, 0);
|
||||
|
||||
/* Process BANDWIDTH attribute */
|
||||
if (a_bw && a_bw->value > client->tu->max_bw_kbps) {
|
||||
status = pj_stun_session_create_response(client->session, msg,
|
||||
PJ_STUN_STATUS_INSUFFICIENT_CAPACITY,
|
||||
NULL, &response);
|
||||
if (status == PJ_SUCCESS && response) {
|
||||
pj_stun_session_send_msg(client->session, PJ_TRUE,
|
||||
src_addr, src_addr_len, response);
|
||||
}
|
||||
return -1;
|
||||
} else if (a_bw) {
|
||||
client->bw_kbps = a_bw->value;
|
||||
} else {
|
||||
client->bw_kbps = client->tu->max_bw_kbps;
|
||||
}
|
||||
|
||||
/* Process REQUESTED-TRANSPORT attribute */
|
||||
if (a_rt && a_rt->value != 0) {
|
||||
status = pj_stun_session_create_response(client->session, msg,
|
||||
PJ_STUN_STATUS_UNSUPP_TRANSPORT_PROTO,
|
||||
NULL, &response);
|
||||
if (status == PJ_SUCCESS && response) {
|
||||
pj_stun_session_send_msg(client->session, PJ_TRUE,
|
||||
src_addr, src_addr_len, response);
|
||||
}
|
||||
return -1;
|
||||
} else if (a_rt) {
|
||||
type = a_rt->value ? PJ_SOCK_STREAM : PJ_SOCK_DGRAM;
|
||||
} else {
|
||||
type = client->tu->type;;
|
||||
}
|
||||
|
||||
/* Process REQUESTED-IP attribute */
|
||||
if (a_rip && a_rip->addr.addr.sa_family != PJ_AF_INET) {
|
||||
status = pj_stun_session_create_response(client->session, msg,
|
||||
PJ_STUN_STATUS_INVALID_IP_ADDR,
|
||||
NULL, &response);
|
||||
if (status == PJ_SUCCESS && response) {
|
||||
pj_stun_session_send_msg(client->session, PJ_TRUE,
|
||||
src_addr, src_addr_len, response);
|
||||
}
|
||||
return -1;
|
||||
|
||||
} else if (a_rip) {
|
||||
req_addr.sin_addr.s_addr = a_rip->addr.ipv4.sin_addr.s_addr;
|
||||
}
|
||||
|
||||
/* Process REQUESTED-PORT-PROPS attribute */
|
||||
if (a_rpp) {
|
||||
unsigned port;
|
||||
|
||||
rpp_bits = (a_rpp->value & 0x00030000) >> 16;
|
||||
port = (a_rpp->value & 0xFFFF);
|
||||
req_addr.sin_port = pj_htons((pj_uint8_t)port);
|
||||
} else {
|
||||
rpp_bits = 0;
|
||||
}
|
||||
|
||||
/* Process LIFETIME attribute */
|
||||
if (a_lf && a_lf->value > client->tu->max_lifetime) {
|
||||
client->lifetime = client->tu->max_lifetime;
|
||||
} else if (a_lf) {
|
||||
client->lifetime = a_lf->value;
|
||||
} else {
|
||||
client->lifetime = client->tu->max_lifetime;
|
||||
}
|
||||
|
||||
/* Allocate socket if we don't have one */
|
||||
if (client->sock == PJ_INVALID_SOCKET) {
|
||||
int err_code;
|
||||
|
||||
status = tu_alloc_port(client->tu, type, rpp_bits, &req_addr,
|
||||
&client->sock, &err_code);
|
||||
if (status != PJ_SUCCESS) {
|
||||
|
||||
status = pj_stun_session_create_response(client->session, msg,
|
||||
err_code, NULL,
|
||||
&response);
|
||||
if (status == PJ_SUCCESS && response) {
|
||||
pj_stun_session_send_msg(client->session, PJ_TRUE,
|
||||
src_addr, src_addr_len, response);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = client_create_relay(client);
|
||||
if (status != PJ_SUCCESS) {
|
||||
status = pj_stun_session_create_response(client->session, msg,
|
||||
PJ_STUN_STATUS_SERVER_ERROR,
|
||||
NULL, &response);
|
||||
if (status == PJ_SUCCESS && response) {
|
||||
pj_stun_session_send_msg(client->session, PJ_TRUE,
|
||||
src_addr, src_addr_len, response);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* Otherwise check if the port parameter stays the same */
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
/* Done successfully, create and send success response */
|
||||
status = pj_stun_session_create_response(client->session, msg,
|
||||
0, NULL, &response);
|
||||
if (status != PJ_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pj_stun_msg_add_uint_attr(response->pool, response->msg,
|
||||
PJ_STUN_ATTR_BANDWIDTH, client->bw_kbps);
|
||||
pj_stun_msg_add_uint_attr(response->pool, response->msg,
|
||||
PJ_STUN_ATTR_LIFETIME, client->lifetime);
|
||||
pj_stun_msg_add_ip_addr_attr(response->pool, response->msg,
|
||||
PJ_STUN_ATTR_MAPPED_ADDR, PJ_FALSE,
|
||||
src_addr, src_addr_len);
|
||||
pj_stun_msg_add_ip_addr_attr(response->pool, response->msg,
|
||||
PJ_STUN_ATTR_XOR_MAPPED_ADDR, PJ_TRUE,
|
||||
src_addr, src_addr_len);
|
||||
|
||||
addr_len = sizeof(req_addr);
|
||||
pj_sock_getsockname(client->sock, &req_addr, &addr_len);
|
||||
pj_stun_msg_add_ip_addr_attr(response->pool, response->msg,
|
||||
PJ_STUN_ATTR_RELAY_ADDR, PJ_FALSE,
|
||||
&req_addr, addr_len);
|
||||
|
||||
return pj_stun_session_send_msg(client->session, PJ_TRUE,
|
||||
src_addr, src_addr_len, response);
|
||||
}
|
||||
|
||||
static pj_status_t client_handle_send_ind(struct turn_client *client,
|
||||
const pj_uint8_t *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_stun_msg *msg,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len)
|
||||
{
|
||||
}
|
||||
|
||||
static pj_status_t client_handle_unknown_msg(struct turn_client *client,
|
||||
const pj_uint8_t *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_stun_msg *msg,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len)
|
||||
{
|
||||
}
|
||||
|
||||
static pj_status_t client_handle_stun_msg(struct turn_client *client,
|
||||
const pj_uint8_t *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_stun_msg *msg,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len)
|
||||
{
|
||||
pj_status_t status;
|
||||
|
||||
switch (msg->hdr.type) {
|
||||
case PJ_STUN_ALLOCATE_REQUEST:
|
||||
return client_handle_allocate_req(client, pkt, pkt_len, msg,
|
||||
src_addr, src_addr_len);
|
||||
|
||||
case PJ_STUN_SEND_INDICATION:
|
||||
return client_handle_send_ind(client, pkt, pkt_len, msg,
|
||||
src_addr, src_addr_len);
|
||||
|
||||
default:
|
||||
return client_handle_unknown_msg(client, pkt, pkt_len, msg,
|
||||
src_addr, src_addr_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static pj_status_t sess_on_rx_request(pj_stun_session *sess,
|
||||
const pj_uint8_t *pkt,
|
||||
unsigned pkt_len,
|
||||
const pj_stun_msg *msg,
|
||||
const pj_sockaddr_t *src_addr,
|
||||
unsigned src_addr_len)
|
||||
{
|
||||
struct session_data *sd;
|
||||
struct turn_client *client;
|
||||
pj_stun_tx_data *tdata;
|
||||
pj_status_t status;
|
||||
|
||||
sd = (struct session_data*) pj_stun_session_get_user_data(sess);
|
||||
|
||||
if (sd->client == NULL) {
|
||||
/* No client is associated with this source address. Create a new
|
||||
* one if this is an Allocate request.
|
||||
*/
|
||||
if (msg->hdr.type != PJ_STUN_ALLOCATE_REQUEST) {
|
||||
PJ_LOG(4,(THIS_FILE, "Received first packet not Allocate request"));
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
PJ_TODO(SUPPORT_MOVE);
|
||||
|
||||
status = client_create(sd->tu, msg, src_addr, src_addr_len, &client);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pj_stun_perror(THIS_FILE, "Error creating new TURN client", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
} else {
|
||||
client = sd->client;
|
||||
}
|
||||
|
||||
return client_handle_stun_msg(client, pkt, pkt_len, msg,
|
||||
src_addr, src_addr_len);
|
||||
}
|
||||
|
||||
static pj_status_t sess_on_send_msg(pj_stun_session *sess,
|
||||
const void *pkt,
|
||||
pj_size_t pkt_size,
|
||||
const pj_sockaddr_t *dst_addr,
|
||||
unsigned addr_len)
|
||||
{
|
||||
struct session_data *sd;
|
||||
|
||||
sd = (struct session_data*) pj_stun_session_get_user_data(sess);
|
||||
|
||||
if (sd->tu->type == PJ_SOCK_DGRAM) {
|
||||
return pj_stun_usage_sendto(sd->tu->usage, pkt, pkt_size, 0,
|
||||
dst_addr, addr_len);
|
||||
} else {
|
||||
return PJ_ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -30,6 +30,7 @@ struct worker
|
|||
struct pj_stun_usage
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
pj_stun_server *srv;
|
||||
pj_mutex_t *mutex;
|
||||
pj_stun_usage_cb cb;
|
||||
int type;
|
||||
|
@ -75,6 +76,7 @@ PJ_DEF(pj_status_t) pj_stun_usage_create( pj_stun_server *srv,
|
|||
pool = pj_pool_create(si->pf, name, 4000, 4000, NULL);
|
||||
usage = PJ_POOL_ZALLOC_T(pool, pj_stun_usage);
|
||||
usage->pool = pool;
|
||||
usage->srv = srv;
|
||||
|
||||
status = pj_mutex_create_simple(pool, name, &usage->mutex);
|
||||
if (status != PJ_SUCCESS)
|
||||
|
@ -129,6 +131,8 @@ PJ_DEF(pj_status_t) pj_stun_usage_create( pj_stun_server *srv,
|
|||
goto on_error;
|
||||
}
|
||||
|
||||
pj_stun_server_register_usage(srv, usage);
|
||||
|
||||
*p_usage = usage;
|
||||
return PJ_SUCCESS;
|
||||
|
||||
|
@ -143,6 +147,10 @@ on_error:
|
|||
*/
|
||||
PJ_DEF(pj_status_t) pj_stun_usage_destroy(pj_stun_usage *usage)
|
||||
{
|
||||
pj_stun_server_unregister_usage(usage->srv, usage);
|
||||
if (usage->cb.on_destroy)
|
||||
(*usage->cb.on_destroy)(usage);
|
||||
|
||||
if (usage->key) {
|
||||
pj_ioqueue_unregister(usage->key);
|
||||
usage->key = NULL;
|
||||
|
|
Loading…
Reference in New Issue