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_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_port_t rx_port,
char *tx_ip,

View File

@ -36,7 +36,7 @@
*/
#ifndef _SWITCH_STUN_PARSER_H
#define _SWITCH_STUN_PARSER_H
#define SWITCH_STUN_DEFAULT_PORT 3478
#define SWITCH_STUN_PACKET_MIN_LEN 20
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);
/*!
\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
\param packet the packet in question

View File

@ -68,7 +68,6 @@ static struct {
int codec_rates_last;
unsigned int flags;
unsigned int init;
uint16_t rtp_port;
switch_hash *profile_hash;
int running;
int handles;
@ -95,7 +94,6 @@ struct private_object {
struct switch_frame read_frame;
struct switch_frame cng_frame;
struct mdl_profile *profile;
switch_sockaddr_t *switch_stun_addr;
unsigned char read_buf[SWITCH_RECCOMMENDED_BUFFER_SIZE];
unsigned char cng_buf[SWITCH_RECCOMMENDED_BUFFER_SIZE];
switch_core_session *session;
@ -108,7 +106,8 @@ struct private_object {
struct switch_rtp *rtp_session;
ldl_session_t *dlsession;
char *remote_ip;
uint16_t remote_port;
switch_port_t local_port;
switch_port_t remote_port;
char local_user[16];
char *remote_user;
unsigned int cand_id;
@ -135,12 +134,6 @@ struct rfc2833_digit {
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_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].address = advip;
cand[0].port = next_rtp_port();
cand[0].port = tech_pvt->local_port;
cand[0].username = tech_pvt->local_user;
cand[0].password = tech_pvt->local_user;
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);
if ((tech_pvt =
(struct private_object *) switch_core_session_alloc(*new_session, sizeof(struct private_object))) != 0) {
if ((tech_pvt = (struct private_object *) switch_core_session_alloc(*new_session, sizeof(struct private_object))) != 0) {
memset(tech_pvt, 0, sizeof(*tech_pvt));
channel = switch_core_session_get_channel(*new_session);
switch_core_session_set_private(*new_session, tech_pvt);
tech_pvt->session = *new_session;
tech_pvt->codec_index = -1;
tech_pvt->local_port = switch_rtp_request_port();
} else {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
switch_core_session_destroy(new_session);
@ -1009,7 +1002,6 @@ static switch_status load_config(void)
int lastcat = -1;
memset(&globals, 0, sizeof(globals));
globals.rtp_port = 10000;
globals.running = 1;
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->codec_index = -1;
tech_pvt->profile = profile;
tech_pvt->local_port = switch_rtp_request_port();
} else {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
switch_core_session_destroy(&session);
@ -1219,7 +1212,7 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi
if (signal) {
ldl_candidate_t *candidates;
unsigned int len = 0;
char *err;
if (ldl_session_get_candidates(dlsession, &candidates, &len) == LDL_STATUS_SUCCESS) {
@ -1257,16 +1250,6 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi
tech_pvt->remote_port = candidates[x].port;
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) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Don't have my codec yet here's one\n");
@ -1286,24 +1269,44 @@ static ldl_status handle_signalling(ldl_handle_t *handle, ldl_session_t *dlsessi
memset(cand, 0, sizeof(cand));
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].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].password = tech_pvt->local_user;
cand[0].pref = 1;
cand[0].protocol = "udp";
cand[0].type = "local";
tech_pvt->cand_id = ldl_session_candidates(dlsession, cand, 1);
tech_pvt->desc_id = ldl_session_describe(dlsession, payloads, 1, LDL_DESCRIPTION_ACCEPT);
if (!tech_pvt->rtp_session) {
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,
cand[0].port,
tech_pvt->local_port,
tech_pvt->remote_ip,
tech_pvt->remote_port,
tech_pvt->codec_num,

View File

@ -80,13 +80,10 @@ static struct {
int bytes_per_frame;
char *dialplan;
int port;
switch_port_t rtp_start;
switch_port_t rtp_end;
char *codec_string;
char *codec_order[SWITCH_MAX_CODECS];
int codec_order_last;
switch_hash *call_hash;
switch_mutex_t *port_lock;
int running;
int codec_ms;
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 {
char digit;
int duration;
@ -268,7 +251,7 @@ static switch_status exosip_on_init(switch_core_session *session)
osip_rfc3264_init(&tech_pvt->sdp_config);
/* Decide on local IP and rtp port */
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 */
sdp_message_init(&tech_pvt->local_sdp);
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;
}
switch_mutex_init(&globals.port_lock, SWITCH_MUTEX_NESTED, module_pool);
switch_core_hash_init(&globals.call_hash, module_pool);
/* 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);
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);
/* Add in what codecs we support locally */
@ -1565,8 +1547,6 @@ static int config_exosip(int reload)
return SWITCH_STATUS_TERM;
}
globals.rtp_start = 16384;
globals.rtp_end = 32768;
globals.dtmf_duration = 100;
while (switch_config_next_pair(&cfg, &var, &val)) {
@ -1583,12 +1563,7 @@ static int config_exosip(int reload)
set_global_dialplan(val);
} else if (!strcmp(var, "codec_prefs")) {
set_global_codec_string(val);
globals.codec_order_last =
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);
globals.codec_order_last = switch_separate_string(globals.codec_string, ',', globals.codec_order, SWITCH_MAX_CODECS);
} else if (!strcmp(var, "codec_ms")) {
globals.codec_ms = atoi(val);
} 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_event_init(runtime.memory_pool);
assert(runtime.memory_pool != NULL);
switch_rtp_init(runtime.memory_pool);
/* Activate SQL database */
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_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) {

View File

@ -42,6 +42,11 @@
#define MAX_KEY_LEN 64
#define rtp_header_len 12
#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;
@ -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) {
return;
}
srtp_init();
switch_mutex_init(&port_lock, SWITCH_MUTEX_NESTED, pool);
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_port_t rx_port,
char *tx_ip,
@ -187,9 +207,6 @@ SWITCH_DECLARE(switch_rtp *)switch_rtp_new(char *rx_ip,
char key[MAX_KEY_LEN];
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) {
*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->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;
}

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;
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;
}