/* * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application * Copyright (C) 2005-2012, Anthony Minessale II * * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application * * The Initial Developer of the Original Code is * Anthony Minessale II * Portions created by the Initial Developer are Copyright (C) * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Anthony Minessale II * Michael Jerris * Paul D. Tinsley * * * switch_core_port_allocator.c -- Main Core Library (port allocator) * */ #include #include "private/switch_core_pvt.h" struct switch_core_port_allocator { switch_port_t start; switch_port_t end; switch_port_t next; int8_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, 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; int even, odd; if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) { return status; } if (!(alloc = switch_core_alloc(pool, sizeof(*alloc)))) { switch_core_destroy_memory_pool(&pool); return SWITCH_STATUS_MEMERR; } alloc->flags = flags; even = switch_test_flag(alloc, SPF_EVEN); odd = switch_test_flag(alloc, SPF_ODD); if (!(even && odd)) { if (even) { if ((start % 2) != 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Rounding odd start port %d to %d\n", start, start + 1); start++; } if ((end % 2) != 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Rounding odd end port %d to %d\n", end, end - 1); end--; } } else if (odd) { if ((start % 2) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Rounding even start port %d to %d\n", start, start + 1); start++; } if ((end % 2) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Rounding even end port %d to %d\n", end, end - 1); end--; } } } alloc->track_len = (end - start) + 2; if (!(even && 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; switch_mutex_init(&alloc->mutex, SWITCH_MUTEX_NESTED, pool); alloc->pool = pool; *new_allocator = alloc; return SWITCH_STATUS_SUCCESS; } SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_request_port(switch_core_port_allocator_t *alloc, switch_port_t *port_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((unsigned) ((unsigned) (intptr_t) port_ptr + (unsigned) (intptr_t) switch_thread_self() + switch_micro_time_now())); while (alloc->track_used < alloc->track_len) { uint32_t index; uint32_t tries = 0; /* randomly pick a port */ index = rand() % alloc->track_len; /* if it is used walk up the list to find a free one */ while (alloc->track[index] && tries < alloc->track_len) { tries++; if (alloc->track[index] < 0) { alloc->track[index]++; } if (++index >= alloc->track_len) { index = 0; } } if (tries < alloc->track_len) { alloc->track[index] = 1; alloc->track_used++; status = SWITCH_STATUS_SUCCESS; if ((even && odd)) { port = (switch_port_t) (index + alloc->start); } else { port = (switch_port_t) (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_status_t) switch_core_port_allocator_free_port(switch_core_port_allocator_t *alloc, 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); if (alloc->track[index] > 0) { alloc->track[index] = -4; alloc->track_used--; status = SWITCH_STATUS_SUCCESS; } switch_mutex_unlock(alloc->mutex); return status; } SWITCH_DECLARE(void) switch_core_port_allocator_destroy(switch_core_port_allocator_t **alloc) { switch_memory_pool_t *pool = (*alloc)->pool; switch_core_destroy_memory_pool(&pool); *alloc = NULL; } /* For Emacs: * Local Variables: * mode:c * indent-tabs-mode:t * tab-width:4 * c-basic-offset:4 * End: * For VIM: * vim:set softtabstop=4 shiftwidth=4 tabstop=4: */