FreeSWITCH API Documentation  1.7.0
switch_core_port_allocator.c
Go to the documentation of this file.
1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Anthony Minessale II <anthm@freeswitch.org>
27  * Michael Jerris <mike@jerris.com>
28  * Paul D. Tinsley <pdt at jackhammer.org>
29  *
30  *
31  * switch_core_port_allocator.c -- Main Core Library (port allocator)
32  *
33  */
34 
35 #include <switch.h>
37 
39  char *ip;
43  int8_t *track;
44  uint32_t track_len;
45  uint32_t track_used;
49 };
50 
53 {
54  switch_status_t status;
57  int even, odd;
58 
59  if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
60  return status;
61  }
62 
63  if (!(alloc = switch_core_alloc(pool, sizeof(*alloc)))) {
65  return SWITCH_STATUS_MEMERR;
66  }
67 
68  alloc->flags = flags;
69  alloc->ip = switch_core_strdup(pool, ip);
70  even = switch_test_flag(alloc, SPF_EVEN);
71  odd = switch_test_flag(alloc, SPF_ODD);
72 
73  alloc->flags |= runtime.port_alloc_flags;
74 
75 
76  if (!(even && odd)) {
77  if (even) {
78  if ((start % 2) != 0) {
79  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Rounding odd start port %d to %d\n", start, start + 1);
80  start++;
81  }
82  if ((end % 2) != 0) {
83  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Rounding odd end port %d to %d\n", end, end - 1);
84  end--;
85  }
86  } else if (odd) {
87  if ((start % 2) == 0) {
88  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Rounding even start port %d to %d\n", start, start + 1);
89  start++;
90  }
91  if ((end % 2) == 0) {
92  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Rounding even end port %d to %d\n", end, end - 1);
93  end--;
94  }
95  }
96  }
97 
98  alloc->track_len = (end - start) + 2;
99 
100  if (!(even && odd)) {
101  alloc->track_len /= 2;
102  }
103 
104  alloc->track = switch_core_alloc(pool, (alloc->track_len + 2) * sizeof(switch_byte_t));
105 
106  alloc->start = start;
107  alloc->next = start;
108  alloc->end = end;
109 
110 
112  alloc->pool = pool;
113  *new_allocator = alloc;
114 
115  return SWITCH_STATUS_SUCCESS;
116 }
117 
118 static switch_bool_t test_port(switch_core_port_allocator_t *alloc, int family, int type, switch_port_t port)
119 {
120  switch_memory_pool_t *pool = NULL;
121  switch_sockaddr_t *local_addr = NULL;
122  switch_socket_t *sock = NULL;
124 
126  return SWITCH_FALSE;
127  }
128 
129  if (switch_sockaddr_info_get(&local_addr, alloc->ip, SWITCH_UNSPEC, port, 0, pool) == SWITCH_STATUS_SUCCESS) {
130  if (switch_socket_create(&sock, family, type, 0, pool) == SWITCH_STATUS_SUCCESS) {
131  if (switch_socket_bind(sock, local_addr) == SWITCH_STATUS_SUCCESS) {
132  r = SWITCH_TRUE;
133  }
134  switch_socket_close(sock);
135  }
136  }
137 
139 
140  return r;
141 }
142 
144 {
145  switch_port_t port = 0;
147  int even = switch_test_flag(alloc, SPF_EVEN);
148  int odd = switch_test_flag(alloc, SPF_ODD);
149 
150  switch_mutex_lock(alloc->mutex);
151  srand((unsigned) ((unsigned) (intptr_t) port_ptr + (unsigned) (intptr_t) switch_thread_self() + switch_micro_time_now()));
152 
153  while (alloc->track_used < alloc->track_len) {
154  uint32_t index;
155  uint32_t tries = 0;
156 
157  /* randomly pick a port */
158  index = rand() % alloc->track_len;
159 
160  /* if it is used walk up the list to find a free one */
161  while (alloc->track[index] && tries < alloc->track_len) {
162  tries++;
163  if (alloc->track[index] < 0) {
164  alloc->track[index]++;
165  }
166  if (++index >= alloc->track_len) {
167  index = 0;
168  }
169  }
170 
171  if (tries < alloc->track_len) {
173 
174  if ((even && odd)) {
175  port = (switch_port_t) (index + alloc->start);
176  } else {
177  port = (switch_port_t) (index + (alloc->start / 2));
178  port *= 2;
179  }
180 
181  if ((alloc->flags & SPF_ROBUST_UDP)) {
182  r = test_port(alloc, AF_INET, SOCK_DGRAM, port);
183  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "UDP port robustness check for port %d %s\n", port, r ? "pass" : "fail");
184  }
185 
186  if ((alloc->flags & SPF_ROBUST_TCP)) {
187  r = test_port(alloc, AF_INET, SOCK_STREAM, port);
188  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TCP port robustness check for port %d %s\n", port, r ? "pass" : "fail");
189  }
190 
191  if (r) {
192  alloc->track[index] = 1;
193  alloc->track_used++;
194  status = SWITCH_STATUS_SUCCESS;
195  goto end;
196  } else {
197  alloc->track[index] = -4;
198  }
199  }
200  }
201 
202 
203  end:
204 
205  switch_mutex_unlock(alloc->mutex);
206 
207  if (status == SWITCH_STATUS_SUCCESS) {
208  *port_ptr = port;
209  } else {
210  *port_ptr = 0;
211  }
212 
213 
214  return status;
215 
216 }
217 
219 {
221  int even = switch_test_flag(alloc, SPF_EVEN);
222  int odd = switch_test_flag(alloc, SPF_ODD);
223  int index;
224 
225  if (port < alloc->start) {
226  return SWITCH_STATUS_GENERR;
227  }
228 
229  index = port - alloc->start;
230 
231  if (!(even && odd)) {
232  index /= 2;
233  }
234 
235  switch_mutex_lock(alloc->mutex);
236  if (alloc->track[index] > 0) {
237  alloc->track[index] = -4;
238  alloc->track_used--;
239  status = SWITCH_STATUS_SUCCESS;
240  }
241  switch_mutex_unlock(alloc->mutex);
242 
243  return status;
244 }
245 
247 {
248  switch_memory_pool_t *pool = (*alloc)->pool;
250  *alloc = NULL;
251 }
252 
253 /* For Emacs:
254  * Local Variables:
255  * mode:c
256  * indent-tabs-mode:t
257  * tab-width:4
258  * c-basic-offset:4
259  * End:
260  * For VIM:
261  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
262  */
switch_time_t switch_micro_time_now(void)
Get the current epoch time in microseconds.
Definition: switch_time.c:310
switch_status_t switch_core_port_allocator_new(const char *ip, switch_port_t start, switch_port_t end, switch_port_flag_t flags, switch_core_port_allocator_t **new_allocator)
#define switch_core_new_memory_pool(p)
Create a new sub memory pool from the core's master pool.
Definition: switch_core.h:631
switch_status_t switch_core_port_allocator_request_port(switch_core_port_allocator_t *alloc, switch_port_t *port_ptr)
#define SWITCH_CHANNEL_LOG
switch_status_t switch_socket_bind(switch_socket_t *sock, switch_sockaddr_t *sa)
Definition: switch_apr.c:719
switch_bool_t
Definition: switch_types.h:405
#define switch_core_strdup(_pool, _todup)
Copy a string using memory allocation from a given pool.
Definition: switch_core.h:729
#define switch_core_destroy_memory_pool(p)
Returns a subpool back to the main pool.
Definition: switch_core.h:640
switch_memory_pool_t * pool
void switch_core_port_allocator_destroy(switch_core_port_allocator_t **alloc)
struct switch_runtime runtime
Definition: switch_core.c:64
uint8_t switch_byte_t
Definition: switch_types.h:246
switch_status_t switch_mutex_unlock(switch_mutex_t *lock)
Definition: switch_apr.c:290
#define SWITCH_MUTEX_NESTED
Definition: switch_apr.h:318
struct apr_sockaddr_t switch_sockaddr_t
Definition: switch_apr.h:1029
switch_status_t switch_mutex_lock(switch_mutex_t *lock)
Definition: switch_apr.c:285
#define switch_core_alloc(_pool, _mem)
Allocate memory directly from a memory pool.
Definition: switch_core.h:682
switch_status_t switch_mutex_init(switch_mutex_t **lock, unsigned int flags, switch_memory_pool_t *pool)
Definition: switch_apr.c:270
switch_status_t switch_core_port_allocator_free_port(switch_core_port_allocator_t *alloc, switch_port_t port)
uint16_t switch_port_t
switch_status_t switch_socket_create(switch_socket_t **new_sock, int family, int type, int protocol, switch_memory_pool_t *pool)
Definition: switch_apr.c:704
struct apr_thread_mutex_t switch_mutex_t
Definition: switch_apr.h:314
switch_status_t
Common return values.
switch_status_t switch_socket_close(switch_socket_t *sock)
Definition: switch_apr.c:714
#define SWITCH_UNSPEC
Definition: switch_apr.h:1022
Main Library Header.
#define SWITCH_DECLARE(type)
uint32_t switch_port_flag_t
Definition: switch_types.h:334
uint32_t port_alloc_flags
struct apr_pool_t switch_memory_pool_t
#define switch_test_flag(obj, flag)
Test for the existance of a flag on an arbitary object.
Definition: switch_utils.h:624
void switch_log_printf(_In_ switch_text_channel_t channel, _In_z_ const char *file, _In_z_ const char *func, _In_ int line, _In_opt_z_ const char *userdata, _In_ switch_log_level_t level, _In_z_ _Printf_format_string_ const char *fmt,...) PRINTF_FUNCTION(7
Write log data to the logging engine.
switch_thread_id_t switch_thread_self(void)
Definition: switch_apr.c:79
struct apr_socket_t switch_socket_t
Definition: switch_apr.h:1026
switch_status_t switch_sockaddr_info_get(switch_sockaddr_t **sa, const char *hostname, int32_t family, switch_port_t port, int32_t flags, switch_memory_pool_t *pool)
Definition: switch_apr.c:817
static switch_bool_t test_port(switch_core_port_allocator_t *alloc, int family, int type, switch_port_t port)