]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
add stun to dingaling
authorAnthony Minessale <anthony.minessale@gmail.com>
Wed, 5 Apr 2006 20:17:22 +0000 (20:17 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Wed, 5 Apr 2006 20:17:22 +0000 (20:17 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@1049 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_rtp.h
src/include/switch_stun.h
src/mod/endpoints/mod_dingaling/mod_dingaling.c
src/mod/endpoints/mod_exosip/mod_exosip.c
src/switch_core.c
src/switch_ivr.c
src/switch_rtp.c
src/switch_stun.c

index e778c5916d231701ca82fdc0c723a1cdeea4f1d9..51f9e69779a5ecf14e4ee544be9302068548f6ba 100644 (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,
index 0326b3966c602ba6664c11070f947390821d51fc..84ebfd5b7bb6cce9acc6fde08d42a5d7356f96cc 100644 (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
index 508427570c4d98367b9bf8b9ca55612cc0c22891..9c240c23f7f53a537b8f8c03488020e03cc31baf 100644 (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,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_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;
@@ -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,
index 72fa52c5548201fad046409ee7aba9a5edaa6d6f..1e519d949045b1a00a6b2e861effff1bd03ce7bc 100644 (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")) {
index 2df845c1fbfbfc425776e0c1f33eb317be294eb2..7ae5a74717e42bae73c6c7cee0a351c042fb212e 100644 (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 ) {
index c4be7bc168643e089b7c8126c04dd9c3432034df..29b4b5b5782a630b988c82ae08b66ae5bfed1377 100644 (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) {
index c218a337691dffcd0c08c427c09d8befbc0265b5..9cf1260186e6ddae75f9898f5592609af52f25cb 100644 (file)
 #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;
 }
 
@@ -319,7 +342,7 @@ SWITCH_DECLARE(int) switch_rtp_read(switch_rtp *rtp_session, void *data, uint32_
        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;
        }
index e640838fb33efdf34c1e21b0ebd9e9170b402fde..832133defdb284e37580a9360831d85a6bd0ab19 100644 (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;
+}