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,
*/
#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 {
*/
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
int codec_rates_last;
unsigned int flags;
unsigned int init;
- uint16_t rtp_port;
switch_hash *profile_hash;
int running;
int handles;
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;
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;
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)
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;
}
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);
int lastcat = -1;
memset(&globals, 0, sizeof(globals));
- globals.rtp_port = 10000;
globals.running = 1;
switch_core_hash_init(&globals.profile_hash, module_pool);
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);
if (signal) {
ldl_candidate_t *candidates;
unsigned int len = 0;
-
+ char *err;
if (ldl_session_get_candidates(dlsession, &candidates, &len) == LDL_STATUS_SUCCESS) {
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");
tech_pvt->codec_name = tech_pvt->codecs[0]->iananame;
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,
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;
};
-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;
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");
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 */
}
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 */
return SWITCH_STATUS_TERM;
}
- globals.rtp_start = 16384;
- globals.rtp_end = 32768;
globals.dtmf_duration = 100;
while (switch_config_next_pair(&cfg, &var, &val)) {
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")) {
}
-
+ 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 ) {
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) {
#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;
}
-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,
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!";
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;
}
bytes = sizeof(rtp_msg_t);
switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock, 0, (void *)&rtp_session->recv_msg, &bytes);
-
+
if (bytes <= 0) {
return 0;
}
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;
+}