1 /*
2 * Copyright (c) 2004-2006 Maxim Sobolev <sobomax@FreeBSD.org>
3 * Copyright (c) 2006-2016 Sippy Software, Inc., http://www.sippysoft.com
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29 #include <pthread.h>
30 #include <stddef.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33
34 #include "rtpp_types.h"
35 #include "rtpp_mallocs.h"
36 #include "rtpp_refcnt.h"
37 #include "rtpp_port_table.h"
38 #include "rtpp_port_table_fin.h"
39
40 struct rtpp_ptbl_priv {
41 struct rtpp_port_table pub;
42 pthread_mutex_t lock;
43 int port_table_len;
44 int port_table_idx;
45 uint16_t *port_table;
46 uint16_t port_ctl;
47 int seq_ports;
48 };
49
50 static void rtpp_ptbl_dtor(struct rtpp_ptbl_priv *);
51 static int rtpp_ptbl_get_port(struct rtpp_port_table *, rtpp_pt_use_t, void *);
52
53 #define PUB2PVT(pubp) \
54 ((struct rtpp_ptbl_priv *)((char *)(pubp) - offsetof(struct rtpp_ptbl_priv, pub)))
55
56 struct rtpp_port_table *
rtpp_port_table_ctor(int port_min,int port_max,int seq_ports,uint16_t port_ctl)57 rtpp_port_table_ctor(int port_min, int port_max, int seq_ports, uint16_t port_ctl)
58 {
59 struct rtpp_ptbl_priv *pvt;
60 struct rtpp_refcnt *rcnt;
61 int i, j;
62 uint16_t portnum;
63
64 pvt = rtpp_rzmalloc(sizeof(struct rtpp_ptbl_priv), &rcnt);
65 if (pvt == NULL) {
66 goto e0;
67 }
68 pvt->pub.rcnt = rcnt;
69 if (pthread_mutex_init(&pvt->lock, NULL) != 0) {
70 goto e1;
71 }
72 pvt->port_table_len = ((port_max - port_min) / 2) + 1;
73 pvt->port_table = malloc(sizeof(uint16_t) * pvt->port_table_len);
74 if (pvt->port_table == NULL) {
75 goto e2;
76 }
77 pvt->port_ctl = port_ctl;
78
79 /* Generate linear table */
80 portnum = port_min;
81 for (i = 0; i < pvt->port_table_len; i += 1) {
82 pvt->port_table[i] = portnum;
83 portnum += 2;
84 }
85 if (seq_ports == 0) {
86 /* Shuffle elements ramdomly */
87 for (i = 0; i < pvt->port_table_len; i += 1) {
88 j = random() % pvt->port_table_len;
89 portnum = pvt->port_table[i];
90 pvt->port_table[i] = pvt->port_table[j];
91 pvt->port_table[j] = portnum;
92 }
93 }
94 pvt->seq_ports = seq_ports;
95 /* Set the last used element to be the last element */
96 pvt->port_table_idx = pvt->port_table_len - 1;
97
98 pvt->pub.get_port = &rtpp_ptbl_get_port;
99 CALL_SMETHOD(pvt->pub.rcnt, attach, (rtpp_refcnt_dtor_t)&rtpp_ptbl_dtor,
100 pvt);
101 return ((&pvt->pub));
102
103 e2:
104 pthread_mutex_destroy(&pvt->lock);
105 e1:
106 CALL_SMETHOD(pvt->pub.rcnt, decref);
107 free(pvt);
108 e0:
109 return (NULL);
110 }
111
112 static void
rtpp_ptbl_dtor(struct rtpp_ptbl_priv * pvt)113 rtpp_ptbl_dtor(struct rtpp_ptbl_priv *pvt)
114 {
115
116 rtpp_port_table_fin(&pvt->pub);
117 pthread_mutex_destroy(&pvt->lock);
118 free(pvt->port_table);
119 free(pvt);
120 }
121
122 static int
rtpp_ptbl_get_port(struct rtpp_port_table * self,rtpp_pt_use_t use_port,void * uarg)123 rtpp_ptbl_get_port(struct rtpp_port_table *self, rtpp_pt_use_t use_port, void *uarg)
124 {
125 struct rtpp_ptbl_priv *pvt;
126 int i, j, idx, rval;
127 uint16_t port;
128
129 pvt = PUB2PVT(self);
130
131 pthread_mutex_lock(&pvt->lock);
132 for (i = 1; i < pvt->port_table_len; i++) {
133 idx = (pvt->port_table_idx + i) % pvt->port_table_len;
134 port = pvt->port_table[idx];
135 if (port == pvt->port_ctl || port == (pvt->port_ctl - 1))
136 continue;
137 rval = use_port(port, uarg);
138 if (!pvt->seq_ports) {
139 /* Shuffle table as we go, so we are not easy to outguess */
140 j = random() % pvt->port_table_len;
141 pvt->port_table[idx] = pvt->port_table[j];
142 pvt->port_table[j] = port;
143 }
144 if (rval == RTPP_PTU_OK) {
145 pvt->port_table_idx = idx;
146 pthread_mutex_unlock(&pvt->lock);
147 return 0;
148 }
149 if (rval != RTPP_PTU_ONEMORE) {
150 pvt->port_table_idx = idx;
151 break;
152 }
153 }
154 pthread_mutex_unlock(&pvt->lock);
155 return -1;
156 }
157