]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
add rtp port allocator
authorAnthony Minessale <anthony.minessale@gmail.com>
Tue, 11 Dec 2007 19:15:02 +0000 (19:15 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Tue, 11 Dec 2007 19:15:02 +0000 (19:15 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@6658 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_core.h
src/include/switch_rtp.h
src/include/switch_types.h
src/mod/applications/mod_esf/mod_esf.c
src/mod/endpoints/mod_dingaling/mod_dingaling.c
src/mod/endpoints/mod_sofia/sofia_glue.c
src/switch_core.c
src/switch_core_port_allocator.c
src/switch_rtp.c

index 5d0c02926b0f0038a5cb6db402cdfd8ef8c127d3..2e41094edd4ef6d048f15835298aab7d1a0ec08a 100644 (file)
@@ -216,14 +216,16 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_read(switch_media_bug_t *b
   \return SWITCH_STATUS_SUCCESS if the operation was a success
 */
 SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_new(switch_port_t start,
-                                                                                                                          switch_port_t end, uint8_t inc, switch_core_port_allocator_t **new_allocator);
+                                                                                                                          switch_port_t end, switch_port_flag_t flags, switch_core_port_allocator_t **new_allocator);
 
 /*!
   \brief Get a port from the port allocator
   \param alloc the allocator object
-  \return the port
+  \param port a pointer to the port
+  \return SUCCESS
 */
-SWITCH_DECLARE(switch_port_t) switch_core_port_allocator_request_port(switch_core_port_allocator_t *alloc);
+SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_request_port(switch_core_port_allocator_t *alloc, switch_port_t *port_ptr);
+SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_free_port(switch_core_port_allocator_t *alloc, switch_port_t port);
 
 /*!
   \brief destroythe port allocator
index 896c11bdb441a3961f2a48ca2847c00561bf234a..67e0f324d39b8a7359c2e25715b610895d5be141 100644 (file)
@@ -53,6 +53,7 @@ typedef void (*switch_rtp_invalid_handler_t) (switch_rtp_t *rtp_session,
   \note Generally called by the core_init
 */
 SWITCH_DECLARE(void) switch_rtp_init(switch_memory_pool_t *pool);
+SWITCH_DECLARE(void) switch_rtp_shutdown(void);
 
 /*!
   \brief Set/Get RTP start port
@@ -70,9 +71,10 @@ SWITCH_DECLARE(switch_port_t) switch_rtp_set_end_port(switch_port_t port);
 
 /*! 
   \brief Request a new port to be used for media
+  \param ip the ip to request a port from
   \return the new port to use
 */
-SWITCH_DECLARE(switch_port_t) switch_rtp_request_port(void);
+SWITCH_DECLARE(switch_port_t) switch_rtp_request_port(const char *ip);
 
 /*! 
   \brief create a new RTP session handle
index 76067565f24c217339755e79d23335cc127117db..03c406688685260741f6d4bf8dcd57c05967454b 100644 (file)
@@ -136,6 +136,12 @@ SWITCH_BEGIN_EXTERN_C
 #define SWITCH_BITS_PER_BYTE 8
 typedef uint8_t switch_byte_t;
 
+typedef enum {
+       SPF_NONE = 0,
+       SPF_ODD = (1 << 0),
+       SPF_EVEN = (1 << 1)
+} switch_port_flag_t;
+
 typedef enum {
        ED_MUX_READ = (1 << 0),
        ED_MUX_WRITE = (1 << 1),
index 43d9b8d7dc12d228fc607922141649ddd40229ea..337c2434ea1e8bde07b7b4861aeda1c397173f89 100644 (file)
@@ -153,7 +153,10 @@ SWITCH_STANDARD_APP(bcast_function)
        }
 
        if (ready == SEND_TYPE_RTP) {
-               rtp_port = switch_rtp_request_port();
+               if (!(rtp_port = switch_rtp_request_port(guess_ip))) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP Port Error\n");
+                       goto fail;
+               }
                switch_find_local_ip(guess_ip, sizeof(guess_ip), AF_INET);
                rtp_session = switch_rtp_new(guess_ip,
                                                                         rtp_port,
index 983ef7f0771350c6134c7a7ca43d9ad5227bb14a..93caada71b66f031095fac607cd05bfa22571947 100644 (file)
@@ -1697,7 +1697,11 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
                        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();
+                       if (!(tech_pvt->local_port = switch_rtp_request_port(tech_pvt->profile->ip))) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "No RTP port available!\n");
+                               terminate_session(new_session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                               return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+                       }
                        tech_pvt->recip = switch_core_session_strdup(*new_session, full_id);
                        tech_pvt->dnis = switch_core_session_strdup(*new_session, dnis);
                } else {
@@ -2584,7 +2588,12 @@ static ldl_status handle_signalling(ldl_handle_t * handle, ldl_session_t * dlses
                                tech_pvt->session = session;
                                tech_pvt->codec_index = -1;
                                tech_pvt->profile = profile;
-                               tech_pvt->local_port = switch_rtp_request_port();
+                               if (!(tech_pvt->local_port = switch_rtp_request_port(profile->ip))) {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "No RTP port available!\n");
+                                       terminate_session(&session, __LINE__, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                                       status = LDL_STATUS_FALSE;
+                                       goto done;
+                               }
                                switch_set_flag_locked(tech_pvt, TFLAG_ANSWER);
                                tech_pvt->recip = switch_core_session_strdup(session, from);
                                if (!(exten = ldl_session_get_value(dlsession, "dnis"))) {
index b56d78d7523b43fb55a3a3797d3eb55bd4f13d4b..3266f8ca05f01b441d9d896bde336e32155f0162 100644 (file)
@@ -398,7 +398,10 @@ switch_status_t sofia_glue_tech_choose_port(private_object_t *tech_pvt)
        }
 
        tech_pvt->local_sdp_audio_ip = ip;
-       tech_pvt->local_sdp_audio_port = switch_rtp_request_port();
+       if (!(tech_pvt->local_sdp_audio_port = switch_rtp_request_port(tech_pvt->profile->rtpip))) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "No RTP ports available!\n");
+               return SWITCH_STATUS_FALSE;
+       }
        sdp_port = tech_pvt->local_sdp_audio_port;
 
        if (tech_pvt->profile->extrtpip) {
@@ -428,7 +431,10 @@ switch_status_t sofia_glue_tech_choose_video_port(private_object_t *tech_pvt)
                return SWITCH_STATUS_SUCCESS;
        }
 
-       tech_pvt->local_sdp_video_port = switch_rtp_request_port();
+       if (!(tech_pvt->local_sdp_video_port = switch_rtp_request_port(tech_pvt->profile->rtpip))) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "No RTP ports available!\n");
+               return SWITCH_STATUS_FALSE;
+       }
        sdp_port = tech_pvt->local_sdp_video_port;
 
        if (tech_pvt->profile->extrtpip) {
index b31740261dabca94df29e6579670237fafc519c7..a9ecd784d2f1dcfd0a50d503a0e0d1205340b76f 100644 (file)
@@ -994,13 +994,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void)
        }
        switch_scheduler_task_thread_stop();
 
+       switch_rtp_shutdown();
        switch_xml_destroy();
        switch_core_memory_stop();
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Finalizing Shutdown.\n");
        switch_log_shutdown();
 
-
-
        if (runtime.console && runtime.console != stdout && runtime.console != stderr) {
                fclose(runtime.console);
                runtime.console = NULL;
@@ -1028,6 +1027,18 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void)
        return SWITCH_STATUS_SUCCESS;
 }
 
+SWITCH_DECLARE(switch_status_t) switch_core_management_exec(char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen)
+{
+       const switch_management_interface_t *ptr;
+       switch_status_t status = SWITCH_STATUS_FALSE;
+
+       if ((ptr = switch_loadable_module_get_management_interface(relative_oid))) {
+               status = ptr->management_function(relative_oid, action, data, datalen);
+       }
+
+       return status;
+}
+
 SWITCH_DECLARE(void) switch_core_memory_reclaim_all(void)
 {
        switch_core_memory_reclaim_logger();    
index a2170e1b3696f56c9a7764e78052c96aab85b2d2..7d912529e4b8ac2dbe9bbb331c9d938afe73d564 100644 (file)
@@ -38,18 +38,21 @@ struct switch_core_port_allocator {
        switch_port_t start;
        switch_port_t end;
        switch_port_t next;
-       uint8_t inc;
+       switch_byte_t *track;
+       uint32_t track_len;
+       uint32_t track_used;
+       switch_port_flag_t flags;
        switch_mutex_t *mutex;
        switch_memory_pool_t *pool;
 };
 
 SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_new(switch_port_t start,
-                                                                                                                          switch_port_t end, uint8_t inc, switch_core_port_allocator_t **new_allocator)
+                                                                                                                          switch_port_t end, switch_port_flag_t flags, switch_core_port_allocator_t **new_allocator)
 {
        switch_status_t status;
        switch_memory_pool_t *pool;
        switch_core_port_allocator_t *alloc;
-
+       
        if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
                return status;
        }
@@ -58,13 +61,21 @@ SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_new(switch_port_t sta
                switch_core_destroy_memory_pool(&pool);
                return SWITCH_STATUS_MEMERR;
        }
+       
+       alloc->track_len = (end - start) + 2;
+       alloc->flags = flags;
+
+       if (!(switch_test_flag(alloc, SPF_EVEN) && switch_test_flag(alloc, SPF_ODD))) {
+               alloc->track_len /= 2;
+       }
+
+       alloc->track = switch_core_alloc(pool, (alloc->track_len + 2) * sizeof(switch_byte_t));
 
        alloc->start = start;
        alloc->next = start;
        alloc->end = end;
-       if (!(alloc->inc = inc)) {
-               alloc->inc = 2;
-       }
+
+
        switch_mutex_init(&alloc->mutex, SWITCH_MUTEX_NESTED, pool);
        alloc->pool = pool;
        *new_allocator = alloc;
@@ -72,34 +83,89 @@ SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_new(switch_port_t sta
        return SWITCH_STATUS_SUCCESS;
 }
 
-SWITCH_DECLARE(switch_status_t) switch_core_management_exec(char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen)
+
+SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_request_port(switch_core_port_allocator_t *alloc, switch_port_t *port_ptr)
 {
-       const switch_management_interface_t *ptr;
+       switch_port_t port = 0;
        switch_status_t status = SWITCH_STATUS_FALSE;
+       int even = switch_test_flag(alloc, SPF_EVEN);
+       int odd = switch_test_flag(alloc, SPF_ODD);
+
+       switch_mutex_lock(alloc->mutex);
+       srand(getpid() + time(NULL));
+       
+       while(alloc->track_used < alloc->track_len) {
+               double r;
+               int index;
+               int tries = 0;
+
+               do {
+                       r = ((double)rand() / ((double)(RAND_MAX)+(double)(1)));
+                       index = (int) (r * alloc->track_len);
+                       tries++;
+               } while((alloc->track[index] || index >= alloc->track_len) && tries < 10000);
+               
+               while(alloc->track[index]) {
+                       if (++index >= alloc->track_len) {
+                               index = 0;
+                       }
+               }
 
-       if ((ptr = switch_loadable_module_get_management_interface(relative_oid))) {
-               status = ptr->management_function(relative_oid, action, data, datalen);
+               if (index < alloc->track_len) {
+                       alloc->track[index] = 1;
+                       alloc->track_used++;
+                       status = SWITCH_STATUS_SUCCESS;
+
+                       if ((even && odd)) {
+                               port = index + alloc->start;
+                       } else {
+                               port = index + (alloc->start / 2);
+                               port *= 2;
+                       } 
+                       goto end;
+               }
        }
+       
+       
+ end:
 
+       switch_mutex_unlock(alloc->mutex);
+       
+       if (status == SWITCH_STATUS_SUCCESS) {
+               *port_ptr = port;
+       } else {
+               *port_ptr = 0;
+       }
+
+       
        return status;
+       
 }
 
 
-
-SWITCH_DECLARE(switch_port_t) switch_core_port_allocator_request_port(switch_core_port_allocator_t *alloc)
+SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_free_port(switch_core_port_allocator_t *alloc, switch_port_t port)
 {
-       switch_port_t port;
+       switch_status_t status = SWITCH_STATUS_FALSE;
+       int even = switch_test_flag(alloc, SPF_EVEN);
+       int odd = switch_test_flag(alloc, SPF_ODD);
+       int index = port - alloc->start;
+       
+       if (!(even && odd)) {
+               index /= 2;
+       }
 
        switch_mutex_lock(alloc->mutex);
-       port = alloc->next;
-       alloc->next = alloc->next + alloc->inc;
-       if (alloc->next > alloc->end) {
-               alloc->next = alloc->start;
+       if (alloc->track[index]) {
+               alloc->track[index] = 0;
+               alloc->track_used--;
+               status = SWITCH_STATUS_SUCCESS;
        }
        switch_mutex_unlock(alloc->mutex);
-       return port;
+
+       return status;
 }
 
+
 SWITCH_DECLARE(void) switch_core_port_allocator_destroy(switch_core_port_allocator_t **alloc)
 {
        switch_memory_pool_t *pool = (*alloc)->pool;
index 9663fbcb3c065d88b93d0d15974402c141874067..69be118cda285c772ce7103ccb0b38ddce1d4c46 100644 (file)
@@ -67,7 +67,7 @@ typedef srtp_hdr_t rtp_hdr_t;
 #pragma pack()
 #endif
 
-
+static switch_hash_t *alloc_hash = NULL;
 
 typedef struct {
        srtp_hdr_t header;
@@ -147,7 +147,8 @@ struct switch_rtp {
        uint32_t flags;
        switch_memory_pool_t *pool;
        switch_sockaddr_t *from_addr;
-
+       char *rx_host;
+       switch_port_t rx_port;
        char *ice_user;
        char *user_ice;
        char *timer_name;
@@ -261,12 +262,17 @@ SWITCH_DECLARE(void) switch_rtp_init(switch_memory_pool_t *pool)
        if (global_init) {
                return;
        }
-
+       switch_core_hash_init(&alloc_hash, pool);
        srtp_init();
        switch_mutex_init(&port_lock, SWITCH_MUTEX_NESTED, pool);
        global_init = 1;
 }
 
+SWITCH_DECLARE(void) switch_rtp_shutdown(void)
+{
+       switch_core_hash_destroy(&alloc_hash);
+}
+
 SWITCH_DECLARE(switch_port_t) switch_rtp_set_start_port(switch_port_t port)
 {
        if (port) {
@@ -304,16 +310,43 @@ SWITCH_DECLARE(switch_port_t) switch_rtp_set_end_port(switch_port_t port)
         return END_PORT;
 }
 
-SWITCH_DECLARE(switch_port_t) switch_rtp_request_port(void)
+static void release_port(switch_rtp_t *rtp_session)
 {
-       switch_port_t port;
+       switch_core_port_allocator_t *alloc = NULL;
 
+       if (!rtp_session->rx_host) {
+               return;
+       }
+
+    switch_mutex_lock(port_lock);
+    if ((alloc = switch_core_hash_find(alloc_hash, rtp_session->rx_host))) {
+               switch_core_port_allocator_free_port(alloc, rtp_session->rx_port);
+       }
+       switch_mutex_unlock(port_lock);
+
+}
+
+SWITCH_DECLARE(switch_port_t) switch_rtp_request_port(const char *ip)
+{
+       switch_port_t port = 0;
+       switch_core_port_allocator_t *alloc = NULL;
+       
        switch_mutex_lock(port_lock);
-       port = NEXT_PORT;
-       NEXT_PORT += 2;
-       if (NEXT_PORT > END_PORT) {
-               NEXT_PORT = START_PORT;
+       alloc = switch_core_hash_find(alloc_hash, ip);
+       if (!alloc) {
+               if (switch_core_port_allocator_new(START_PORT, END_PORT, SPF_EVEN, &alloc) != SWITCH_STATUS_SUCCESS) {
+                       port = 0;
+                       goto end;
+               }
+
+               switch_core_hash_insert(alloc_hash, ip, alloc);
+       }
+       
+       if (switch_core_port_allocator_request_port(alloc, &port) != SWITCH_STATUS_SUCCESS) {
+               port = 0;
        }
+
+ end:
        switch_mutex_unlock(port_lock);
        return port;
 }
@@ -379,7 +412,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s
                *err = "Send myself a packet failed!";
                goto done;
        }
-
+       release_port(rtp_session);
+       
        old_sock = rtp_session->sock;
        rtp_session->sock = new_sock;
        new_sock = NULL;
@@ -395,7 +429,9 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s
 
   done:
 
-       if (status != SWITCH_STATUS_SUCCESS) {
+       if (status == SWITCH_STATUS_SUCCESS) {
+               rtp_session->rx_host = switch_core_strdup(rtp_session->pool, host);
+               rtp_session->rx_port = port;
                rtp_session->ready = 1;
        }
 
@@ -653,6 +689,7 @@ SWITCH_DECLARE(void) switch_rtp_destroy(switch_rtp_t **rtp_session)
                return;
        }
 
+
        (*rtp_session)->ready = 0;
 
        switch_mutex_lock((*rtp_session)->flag_mutex);
@@ -683,6 +720,8 @@ SWITCH_DECLARE(void) switch_rtp_destroy(switch_rtp_t **rtp_session)
                switch_core_timer_destroy(&(*rtp_session)->timer);
        }
 
+       release_port(*rtp_session);
+
        switch_mutex_unlock((*rtp_session)->flag_mutex);
        return;
 }