add stun to dingaling

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@1049 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2006-04-05 20:17:22 +00:00
parent cd06692667
commit 35b309e91b
8 changed files with 192 additions and 67 deletions

View File

@ -55,6 +55,9 @@ typedef void (*switch_rtp_invalid_handler)(switch_rtp *rtp_session,
switch_sockaddr_t *from_addr); switch_sockaddr_t *from_addr);
SWITCH_DECLARE(void) switch_rtp_init(switch_memory_pool *pool);
SWITCH_DECLARE(switch_port_t) switch_rtp_request_port(void);
SWITCH_DECLARE(switch_rtp *)switch_rtp_new(char *rx_ip, SWITCH_DECLARE(switch_rtp *)switch_rtp_new(char *rx_ip,
switch_port_t rx_port, switch_port_t rx_port,
char *tx_ip, char *tx_ip,

View File

@ -36,7 +36,7 @@
*/ */
#ifndef _SWITCH_STUN_PARSER_H #ifndef _SWITCH_STUN_PARSER_H
#define _SWITCH_STUN_PARSER_H #define _SWITCH_STUN_PARSER_H
#define SWITCH_STUN_DEFAULT_PORT 3478
#define SWITCH_STUN_PACKET_MIN_LEN 20 #define SWITCH_STUN_PACKET_MIN_LEN 20
typedef enum { typedef enum {
@ -196,6 +196,23 @@ SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_add_username(switch_stun_pa
*/ */
SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_add_binded_address(switch_stun_packet_t *packet, char *ipstr, uint16_t port); SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_add_binded_address(switch_stun_packet_t *packet, char *ipstr, uint16_t port);
/*!
\brief Perform a stun lookup
\param ip the local ip to use (replaced with stun results)
\param port the local port to use (replaced with stun results)
\param stunip the ip of the stun server
\param pool the memory pool to use
\return SUCCESS or FAIL
*/
SWITCH_DECLARE(switch_status) switch_stun_lookup (char **ip,
switch_port_t *port,
char *stunip,
switch_port_t stunport,
char **err,
switch_memory_pool *pool);
/*! /*!
\brief set a switch_stun_packet_attribute_t pointer to point at the first attribute in a packet \brief set a switch_stun_packet_attribute_t pointer to point at the first attribute in a packet
\param packet the packet in question \param packet the packet in question

View File

@ -68,7 +68,6 @@ static struct {
int codec_rates_last; int codec_rates_last;
unsigned int flags; unsigned int flags;
unsigned int init; unsigned int init;
uint16_t rtp_port;
switch_hash *profile_hash; switch_hash *profile_hash;
int running; int running;
int handles; int handles;
@ -95,7 +94,6 @@ struct private_object {
struct switch_frame read_frame; struct switch_frame read_frame;
struct switch_frame cng_frame; struct switch_frame cng_frame;
struct mdl_profile *profile; struct mdl_profile *profile;
switch_sockaddr_t *switch_stun_addr;
unsigned char read_buf[SWITCH_RECCOMMENDED_BUFFER_SIZE]; unsigned char read_buf[SWITCH_RECCOMMENDED_BUFFER_SIZE];
unsigned char cng_buf[SWITCH_RECCOMMENDED_BUFFER_SIZE]; unsigned char cng_buf[SWITCH_RECCOMMENDED_BUFFER_SIZE];
switch_core_session *session; switch_core_session *session;
@ -108,7 +106,8 @@ struct private_object {
struct switch_rtp *rtp_session; struct switch_rtp *rtp_session;
ldl_session_t *dlsession; ldl_session_t *dlsession;
char *remote_ip; char *remote_ip;
uint16_t remote_port; switch_port_t local_port;
switch_port_t remote_port;
char local_user[16]; char local_user[16];
char *remote_user; char *remote_user;
unsigned int cand_id; unsigned int cand_id;
@ -135,12 +134,6 @@ struct rfc2833_digit {
int duration; int duration;
}; };
static uint16_t next_rtp_port(void)
{
uint16_t ret = globals.rtp_port++;
globals.rtp_port++;
return ret;
}
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan) SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan)
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_string, globals.codec_string) SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_string, globals.codec_string)
@ -280,7 +273,7 @@ static void *SWITCH_THREAD_FUNC negotiate_thread_run(switch_thread *thread, void
cand[0].name = "rtp"; cand[0].name = "rtp";
cand[0].address = advip; cand[0].address = advip;
cand[0].port = next_rtp_port(); cand[0].port = tech_pvt->local_port;
cand[0].username = tech_pvt->local_user; cand[0].username = tech_pvt->local_user;
cand[0].password = tech_pvt->local_user; cand[0].password = tech_pvt->local_user;
cand[0].pref = 1; cand[0].pref = 1;
@ -878,13 +871,13 @@ static switch_status channel_outgoing_channel(switch_core_session *session, swit
} }
switch_core_session_add_stream(*new_session, NULL); switch_core_session_add_stream(*new_session, NULL);
if ((tech_pvt = if ((tech_pvt = (struct private_object *) switch_core_session_alloc(*new_session, sizeof(struct private_object))) != 0) {
(struct private_object *) switch_core_session_alloc(*new_session, sizeof(struct private_object))) != 0) {
memset(tech_pvt, 0, sizeof(*tech_pvt)); memset(tech_pvt, 0, sizeof(*tech_pvt));
channel = switch_core_session_get_channel(*new_session); channel = switch_core_session_get_channel(*new_session);
switch_core_session_set_private(*new_session, tech_pvt); switch_core_session_set_private(*new_session, tech_pvt);
tech_pvt->session = *new_session; tech_pvt->session = *new_session;
tech_pvt->codec_index = -1; tech_pvt->codec_index = -1;
tech_pvt->local_port = switch_rtp_request_port();
} else { } else {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n"); switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
switch_core_session_destroy(new_session); switch_core_session_destroy(new_session);
@ -1009,7 +1002,6 @@ static switch_status load_config(void)
int lastcat = -1; int lastcat = -1;
memset(&globals, 0, sizeof(globals)); memset(&globals, 0, sizeof(globals));
globals.rtp_port = 10000;
globals.running = 1; globals.running = 1;
switch_core_hash_init(&globals.profile_hash, module_pool); switch_core_hash_init(&globals.profile_hash, module_pool);
@ -1134,6 +1126,7 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi
tech_pvt->session = session; tech_pvt->session = session;
tech_pvt->codec_index = -1; tech_pvt->codec_index = -1;
tech_pvt->profile = profile; tech_pvt->profile = profile;
tech_pvt->local_port = switch_rtp_request_port();
} else { } else {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n"); switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
switch_core_session_destroy(&session); switch_core_session_destroy(&session);
@ -1219,7 +1212,7 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi
if (signal) { if (signal) {
ldl_candidate_t *candidates; ldl_candidate_t *candidates;
unsigned int len = 0; unsigned int len = 0;
char *err;
if (ldl_session_get_candidates(dlsession, &candidates, &len) == LDL_STATUS_SUCCESS) { if (ldl_session_get_candidates(dlsession, &candidates, &len) == LDL_STATUS_SUCCESS) {
@ -1257,17 +1250,7 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi
tech_pvt->remote_port = candidates[x].port; tech_pvt->remote_port = candidates[x].port;
tech_pvt->remote_user = switch_core_session_strdup(session, candidates[x].username); tech_pvt->remote_user = switch_core_session_strdup(session, candidates[x].username);
if (switch_sockaddr_info_get(&tech_pvt->switch_stun_addr,
tech_pvt->remote_ip,
SWITCH_UNSPEC,
tech_pvt->remote_port,
0,
switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Address Error!\n");
return LDL_STATUS_FALSE;
}
if (tech_pvt->codec_index < 0) { if (tech_pvt->codec_index < 0) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Don't have my codec yet here's one\n"); switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Don't have my codec yet here's one\n");
tech_pvt->codec_name = tech_pvt->codecs[0]->iananame; tech_pvt->codec_name = tech_pvt->codecs[0]->iananame;
@ -1286,24 +1269,44 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi
memset(cand, 0, sizeof(cand)); memset(cand, 0, sizeof(cand));
switch_stun_random_string(tech_pvt->local_user, 16, NULL); switch_stun_random_string(tech_pvt->local_user, 16, NULL);
cand[0].name = "rtp";
cand[0].port = tech_pvt->local_port;
cand[0].address = advip; cand[0].address = advip;
cand[0].port = next_rtp_port();
if (!strncasecmp(advip, "stun:", 5)) {
cand[0].address = profile->ip;
if (switch_stun_lookup(&cand[0].address,
&cand[0].port,
advip + 5,
SWITCH_STUN_DEFAULT_PORT,
&err,
switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Stun Failed! %s:%d [%s]\n", advip + 5, SWITCH_STUN_DEFAULT_PORT, err);
switch_channel_hangup(channel);
return LDL_STATUS_FALSE;
}
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Stun Success %s:%d\n", cand[0].address, cand[0].port);
cand[0].type = "stun";
} else {
cand[0].type = "local";
}
cand[0].name = "rtp";
cand[0].username = tech_pvt->local_user; cand[0].username = tech_pvt->local_user;
cand[0].password = tech_pvt->local_user; cand[0].password = tech_pvt->local_user;
cand[0].pref = 1; cand[0].pref = 1;
cand[0].protocol = "udp"; cand[0].protocol = "udp";
cand[0].type = "local";
tech_pvt->cand_id = ldl_session_candidates(dlsession, cand, 1); tech_pvt->cand_id = ldl_session_candidates(dlsession, cand, 1);
tech_pvt->desc_id = ldl_session_describe(dlsession, payloads, 1, LDL_DESCRIPTION_ACCEPT); tech_pvt->desc_id = ldl_session_describe(dlsession, payloads, 1, LDL_DESCRIPTION_ACCEPT);
if (!tech_pvt->rtp_session) { if (!tech_pvt->rtp_session) {
const char *err; const char *err;
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "SETUP RTP %s:%d -> %s:%d\n", profile->ip, cand[0].port, tech_pvt->remote_ip, tech_pvt->remote_port); switch_console_printf(SWITCH_CHANNEL_CONSOLE, "SETUP RTP %s:%d -> %s:%d\n", profile->ip, tech_pvt->local_port, tech_pvt->remote_ip, tech_pvt->remote_port);
if (!(tech_pvt->rtp_session = switch_rtp_new(profile->ip, if (!(tech_pvt->rtp_session = switch_rtp_new(profile->ip,
cand[0].port, tech_pvt->local_port,
tech_pvt->remote_ip, tech_pvt->remote_ip,
tech_pvt->remote_port, tech_pvt->remote_port,
tech_pvt->codec_num, tech_pvt->codec_num,

View File

@ -80,13 +80,10 @@ static struct {
int bytes_per_frame; int bytes_per_frame;
char *dialplan; char *dialplan;
int port; int port;
switch_port_t rtp_start;
switch_port_t rtp_end;
char *codec_string; char *codec_string;
char *codec_order[SWITCH_MAX_CODECS]; char *codec_order[SWITCH_MAX_CODECS];
int codec_order_last; int codec_order_last;
switch_hash *call_hash; switch_hash *call_hash;
switch_mutex_t *port_lock;
int running; int running;
int codec_ms; int codec_ms;
int dtmf_duration; int dtmf_duration;
@ -134,20 +131,6 @@ struct private_object {
}; };
static switch_port_t next_rtp_port(void)
{
switch_port_t port;
switch_mutex_lock(globals.port_lock);
port = globals.rtp_start;
globals.rtp_start += 2;
if (port >= globals.rtp_end) {
port = globals.rtp_start;
}
switch_mutex_unlock(globals.port_lock);
return port;
}
struct rfc2833_digit { struct rfc2833_digit {
char digit; char digit;
int duration; int duration;
@ -268,7 +251,7 @@ static switch_status exosip_on_init(switch_core_session *session)
osip_rfc3264_init(&tech_pvt->sdp_config); osip_rfc3264_init(&tech_pvt->sdp_config);
/* Decide on local IP and rtp port */ /* Decide on local IP and rtp port */
strncpy(tech_pvt->local_sdp_audio_ip, localip, sizeof(tech_pvt->local_sdp_audio_ip)); strncpy(tech_pvt->local_sdp_audio_ip, localip, sizeof(tech_pvt->local_sdp_audio_ip));
tech_pvt->local_sdp_audio_port = next_rtp_port(); tech_pvt->local_sdp_audio_port = switch_rtp_request_port();
/* Initialize SDP */ /* Initialize SDP */
sdp_message_init(&tech_pvt->local_sdp); sdp_message_init(&tech_pvt->local_sdp);
sdp_message_v_version_set(tech_pvt->local_sdp, "0"); sdp_message_v_version_set(tech_pvt->local_sdp, "0");
@ -1028,7 +1011,6 @@ SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_modul
return SWITCH_STATUS_TERM; return SWITCH_STATUS_TERM;
} }
switch_mutex_init(&globals.port_lock, SWITCH_MUTEX_NESTED, module_pool);
switch_core_hash_init(&globals.call_hash, module_pool); switch_core_hash_init(&globals.call_hash, module_pool);
/* connect my internal structure to the blank pointer passed to me */ /* connect my internal structure to the blank pointer passed to me */
@ -1116,7 +1098,7 @@ static switch_status exosip_create_call(eXosip_event_t * event)
} }
eXosip_guess_localip(AF_INET, tech_pvt->local_sdp_audio_ip, 50); eXosip_guess_localip(AF_INET, tech_pvt->local_sdp_audio_ip, 50);
tech_pvt->local_sdp_audio_port = next_rtp_port(); tech_pvt->local_sdp_audio_port = switch_rtp_request_port();
osip_rfc3264_init(&tech_pvt->sdp_config); osip_rfc3264_init(&tech_pvt->sdp_config);
/* Add in what codecs we support locally */ /* Add in what codecs we support locally */
@ -1565,8 +1547,6 @@ static int config_exosip(int reload)
return SWITCH_STATUS_TERM; return SWITCH_STATUS_TERM;
} }
globals.rtp_start = 16384;
globals.rtp_end = 32768;
globals.dtmf_duration = 100; globals.dtmf_duration = 100;
while (switch_config_next_pair(&cfg, &var, &val)) { while (switch_config_next_pair(&cfg, &var, &val)) {
@ -1583,12 +1563,7 @@ static int config_exosip(int reload)
set_global_dialplan(val); set_global_dialplan(val);
} else if (!strcmp(var, "codec_prefs")) { } else if (!strcmp(var, "codec_prefs")) {
set_global_codec_string(val); set_global_codec_string(val);
globals.codec_order_last = globals.codec_order_last = switch_separate_string(globals.codec_string, ',', globals.codec_order, SWITCH_MAX_CODECS);
switch_separate_string(globals.codec_string, ',', globals.codec_order, SWITCH_MAX_CODECS);
} else if (!strcmp(var, "rtp_min_port")) {
globals.rtp_start = (switch_port_t)atoi(val);
} else if (!strcmp(var, "rtp_max_port")) {
globals.rtp_end = (switch_port_t)atoi(val);
} else if (!strcmp(var, "codec_ms")) { } else if (!strcmp(var, "codec_ms")) {
globals.codec_ms = atoi(val); globals.codec_ms = atoi(val);
} else if (!strcmp(var, "dtmf_duration")) { } else if (!strcmp(var, "dtmf_duration")) {

View File

@ -2414,11 +2414,10 @@ SWITCH_DECLARE(switch_status) switch_core_init(char *console)
} }
assert(runtime.memory_pool != NULL);
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Allocated memory pool. Sessions are %u bytes\n", sizeof(struct switch_core_session)); switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Allocated memory pool. Sessions are %u bytes\n", sizeof(struct switch_core_session));
switch_event_init(runtime.memory_pool); switch_event_init(runtime.memory_pool);
switch_rtp_init(runtime.memory_pool);
assert(runtime.memory_pool != NULL);
/* Activate SQL database */ /* Activate SQL database */
if ((runtime.db = switch_core_db_handle()) == 0 ) { if ((runtime.db = switch_core_db_handle()) == 0 ) {

View File

@ -780,6 +780,9 @@ static void *audio_bridge_thread(switch_thread *thread, void *obj)
switch_channel_hangup(chan_b); switch_channel_hangup(chan_b);
} }
switch_channel_clear_flag(chan_a, CF_ORIGINATOR); switch_channel_clear_flag(chan_a, CF_ORIGINATOR);
} else if (!switch_channel_test_flag(chan_a, CF_ORIGINATOR) && !switch_channel_test_flag(chan_a, CF_TRANSFER)) {
switch_core_session_kill_channel(session_a, SWITCH_SIG_KILL);
switch_channel_hangup(chan_a);
} }
while (his_thread->running > 0) { while (his_thread->running > 0) {

View File

@ -42,6 +42,11 @@
#define MAX_KEY_LEN 64 #define MAX_KEY_LEN 64
#define rtp_header_len 12 #define rtp_header_len 12
#define RTP_MAX_BUF_LEN 16384 #define RTP_MAX_BUF_LEN 16384
#define RTP_START_PORT 16384
#define RTP_END_PORT 32768
static switch_port_t NEXT_PORT = RTP_START_PORT;
static switch_mutex_t *port_lock = NULL;
typedef srtp_hdr_t rtp_hdr_t; typedef srtp_hdr_t rtp_hdr_t;
@ -160,16 +165,31 @@ static void handle_ice(switch_rtp *rtp_session, void *data, switch_size_t len)
} }
static void init_rtp(void) SWITCH_DECLARE(void) switch_rtp_init(switch_memory_pool *pool)
{ {
if (global_init) { if (global_init) {
return; return;
} }
srtp_init(); srtp_init();
switch_mutex_init(&port_lock, SWITCH_MUTEX_NESTED, pool);
global_init = 1; global_init = 1;
} }
SWITCH_DECLARE(switch_port_t) switch_rtp_request_port(void)
{
switch_port_t port;
switch_mutex_lock(port_lock);
port = NEXT_PORT;
NEXT_PORT += 2;
if (port > RTP_END_PORT) {
port = RTP_START_PORT;
}
switch_mutex_unlock(port_lock);
return port;
}
SWITCH_DECLARE(switch_rtp *)switch_rtp_new(char *rx_ip, SWITCH_DECLARE(switch_rtp *)switch_rtp_new(char *rx_ip,
switch_port_t rx_port, switch_port_t rx_port,
char *tx_ip, char *tx_ip,
@ -187,9 +207,6 @@ SWITCH_DECLARE(switch_rtp *)switch_rtp_new(char *rx_ip,
char key[MAX_KEY_LEN]; char key[MAX_KEY_LEN];
uint32_t ssrc = rand() & 0xffff; uint32_t ssrc = rand() & 0xffff;
if (!global_init) {
init_rtp();
}
if (switch_sockaddr_info_get(&rx_addr, rx_ip, SWITCH_UNSPEC, rx_port, 0, pool) != SWITCH_STATUS_SUCCESS) { if (switch_sockaddr_info_get(&rx_addr, rx_ip, SWITCH_UNSPEC, rx_port, 0, pool) != SWITCH_STATUS_SUCCESS) {
*err = "RX Address Error!"; *err = "RX Address Error!";
@ -281,6 +298,12 @@ SWITCH_DECLARE(switch_status) switch_rtp_activate_ice(switch_rtp *rtp_session, c
rtp_session->ice_user = switch_core_strdup(rtp_session->pool, ice_user); rtp_session->ice_user = switch_core_strdup(rtp_session->pool, ice_user);
rtp_session->user_ice = switch_core_strdup(rtp_session->pool, user_ice); rtp_session->user_ice = switch_core_strdup(rtp_session->pool, user_ice);
if (rtp_session->ice_user) {
if (ice_out(rtp_session) != SWITCH_STATUS_SUCCESS) {
return -1;
}
}
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
@ -319,7 +342,7 @@ SWITCH_DECLARE(int) switch_rtp_read(switch_rtp *rtp_session, void *data, uint32_
bytes = sizeof(rtp_msg_t); bytes = sizeof(rtp_msg_t);
switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock, 0, (void *)&rtp_session->recv_msg, &bytes); switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock, 0, (void *)&rtp_session->recv_msg, &bytes);
if (bytes <= 0) { if (bytes <= 0) {
return 0; return 0;
} }

View File

@ -266,3 +266,105 @@ SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_add_username(switch_stun_pa
packet->header.length += htons(sizeof(switch_stun_packet_attribute_t)) + attribute->length; packet->header.length += htons(sizeof(switch_stun_packet_attribute_t)) + attribute->length;
return 1; return 1;
} }
SWITCH_DECLARE(switch_status) switch_stun_lookup (char **ip,
switch_port_t *port,
char *stunip,
switch_port_t stunport,
char **err,
switch_memory_pool *pool)
{
switch_sockaddr_t *local_addr = NULL, *remote_addr = NULL, *from_addr = NULL;
switch_socket_t *sock = NULL;
uint8_t buf[256] = {0};
switch_stun_packet_t *packet;
switch_stun_packet_attribute_t *attr;
switch_size_t bytes = 0;
char username[33] = {0};
char rip[16];
uint16_t rport = 0;
switch_time_t started = 0;
unsigned int elapsed = 0;
*err = "Success";
switch_sockaddr_info_get(&from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool);
if (switch_sockaddr_info_get(&local_addr, *ip, SWITCH_UNSPEC, *port, 0, pool) != SWITCH_STATUS_SUCCESS) {
*err = "Local Address Error!";
return SWITCH_STATUS_FALSE;
}
if (switch_sockaddr_info_get(&remote_addr, stunip, SWITCH_UNSPEC, stunport, 0, pool) != SWITCH_STATUS_SUCCESS) {
*err = "Remote Address Error!";
return SWITCH_STATUS_FALSE;
}
if (switch_socket_create(&sock, AF_INET, SOCK_DGRAM, 0, pool) != SWITCH_STATUS_SUCCESS) {
*err = "Socket Error!";
return SWITCH_STATUS_FALSE;
}
if (switch_socket_bind(sock, local_addr) != SWITCH_STATUS_SUCCESS) {
*err = "Bind Error!";
return SWITCH_STATUS_FALSE;
}
switch_socket_opt_set(sock, APR_SO_NONBLOCK, TRUE);
packet = switch_stun_packet_build_header(SWITCH_STUN_BINDING_REQUEST, NULL, buf);
switch_stun_random_string(username, 32, NULL);
switch_stun_packet_attribute_add_username(packet, username, 32);
bytes = switch_stun_packet_length(packet);
switch_socket_sendto(sock, remote_addr, 0, (void *)packet, &bytes);
started = switch_time_now();
*ip = NULL;
*port = 0;
for(;;) {
bytes = sizeof(buf);
if (switch_socket_recvfrom(from_addr, sock, 0, (char *)&buf, &bytes) == SWITCH_STATUS_SUCCESS && bytes > 0) {
break;
}
if ((elapsed = (unsigned int)((switch_time_now() - started) / 1000)) > 5000) {
*err = "Timeout";
switch_socket_shutdown(sock, APR_SHUTDOWN_READWRITE);
switch_socket_close(sock);
return SWITCH_STATUS_TIMEOUT;
}
switch_yield(1000);
}
switch_socket_close(sock);
packet = switch_stun_packet_parse(buf, sizeof(buf));
switch_stun_packet_first_attribute(packet, attr);
do {
switch(attr->type) {
case SWITCH_STUN_ATTR_MAPPED_ADDRESS:
if (attr->type) {
switch_stun_packet_attribute_get_mapped_address(attr, rip, &rport);
}
break;
case SWITCH_STUN_ATTR_USERNAME:
if(attr->type) {
switch_stun_packet_attribute_get_username(attr, username, 32);
}
break;
}
} while (switch_stun_packet_next_attribute(attr));
if (packet->header.type == SWITCH_STUN_BINDING_RESPONSE) {
*ip = switch_core_strdup(pool, rip);
*port = rport;
return SWITCH_STATUS_SUCCESS;
} else {
*err = "Invalid Reply";
}
return SWITCH_STATUS_FALSE;
}