blob: fc7096df1ff687a6f15f17fa42b6f5278cc59033 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
|
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.neomedia;
import java.net.*;
import net.java.sip.communicator.impl.neomedia.*;
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.util.*;
/**
* Represents a default implementation of <tt>StreamConnector</tt> which is
* initialized with a specific pair of control and data <tt>DatagramSocket</tt>s
* and which closes them (if they exist) when its {@link #close()} is invoked.
*
* @author Lubomir Marinov
*/
public class DefaultStreamConnector
implements StreamConnector
{
/**
* The <tt>Logger</tt> used by the <tt>DefaultStreamConnector</tt> class and
* its instances for logging output.
*/
private static final Logger logger
= Logger.getLogger(DefaultStreamConnector.class);
/**
* The default number of binds that a Media Service Implementation should
* execute in case a port is already bound to (each retry would be on a
* new random port).
*/
public static final int BIND_RETRIES_DEFAULT_VALUE = 50;
/**
* The name of the property containing the number of binds that a Media
* Service Implementation should execute in case a port is already
* bound to (each retry would be on a new port in the allowed boundaries).
*/
public static final String BIND_RETRIES_PROPERTY_NAME
= "net.java.sip.communicator.service.media.BIND_RETRIES";
/**
* The name of the property that contains the maximum port number that we'd
* like our RTP managers to bind upon.
*/
public static final String MAX_PORT_NUMBER_PROPERTY_NAME
= "net.java.sip.communicator.service.media.MAX_PORT_NUMBER";
/**
* The maximum port number <tt>DefaultStreamConnector</tt> instances are to
* attempt to bind to.
*/
private static int maxPort = -1;
/**
* The name of the property that contains the minimum port number that we'd
* like our RTP managers to bind upon.
*/
public static final String MIN_PORT_NUMBER_PROPERTY_NAME
= "net.java.sip.communicator.service.media.MIN_PORT_NUMBER";
/**
* The minimum port number <tt>DefaultStreamConnector</tt> instances are to
* attempt to bind to.
*/
private static int minPort = -1;
/**
* The local <tt>InetAddress</tt> this <tt>StreamConnector</tt> attempts to
* bind to on demand.
*/
private final InetAddress bindAddr;
/**
* The <tt>DatagramSocket</tt> that a stream should use for control data
* (e.g. RTCP) traffic.
*/
protected DatagramSocket controlSocket;
/**
* The <tt>DatagramSocket</tt> that a stream should use for data (e.g. RTP)
* traffic.
*/
protected DatagramSocket dataSocket;
/**
* Initializes a new <tt>DefaultStreamConnector</tt> instance with no
* control and data <tt>DatagramSocket</tt>s.
* <p>
* Suitable for extenders willing to delay the creation of the control and
* data sockets. For example, they could override
* {@link #getControlSocket()} and/or {@link #getDataSocket()} and create
* them on demand.
*/
public DefaultStreamConnector()
{
this(null, null);
}
/**
* Creates a new <tt>DatagramSocket</tt> instance which is bound to the
* specified local <tt>InetAddress</tt> and its port is within the range
* defined by the <tt>ConfigurationService</tt> properties
* {@link #MIN_PORT_NUMBER_PROPERTY_NAME} and
* {@link #MAX_PORT_NUMBER_PROPERTY_NAME}. Attempts at most
* {@link #BIND_RETRIES_PROPERTY_NAME} times to bind.
*
* @param bindAddr the local <tt>InetAddress</tt> the new
* <tt>DatagramSocket</tt> is to bind to
* @return a new <tt>DatagramSocket</tt> instance bound to the specified
* local <tt>InetAddress</tt>
*/
private static synchronized DatagramSocket createDatagramSocket(
InetAddress bindAddr)
{
ConfigurationService cfg = NeomediaActivator.getConfigurationService();
int bindRetries = BIND_RETRIES_DEFAULT_VALUE;
if (cfg != null)
bindRetries = cfg.getInt(BIND_RETRIES_PROPERTY_NAME, bindRetries);
if (maxPort < 0)
{
maxPort = 6000;
if (cfg != null)
maxPort = cfg.getInt(MAX_PORT_NUMBER_PROPERTY_NAME, maxPort);
}
for (int i = 0; i < bindRetries; i++)
{
if ((minPort < 0) || (minPort > maxPort))
{
minPort = 5000;
if (cfg != null)
{
minPort
= cfg.getInt(MIN_PORT_NUMBER_PROPERTY_NAME, minPort);
}
}
int port = minPort++;
try
{
return
(bindAddr == null)
? new DatagramSocket(port)
: new DatagramSocket(port, bindAddr);
}
catch (SocketException se)
{
logger.warn(
"Retrying a bind because of a failure to bind to address "
+ bindAddr
+ " and port "
+ port,
se);
}
}
return null;
}
/**
* Initializes a new <tt>DefaultStreamConnector</tt> instance with a
* specific bind <tt>InetAddress</tt>. The new instance is to attempt to
* bind on demand to the specified <tt>InetAddress</tt> in the port range
* defined by the <tt>ConfigurationService</tt> properties
* {@link #MIN_PORT_NUMBER_PROPERTY_NAME} and
* {@link #MAX_PORT_NUMBER_PROPERTY_NAME} at most
* {@link #BIND_RETRIES_PROPERTY_NAME} times.
*
* @param bindAddr the local <tt>InetAddress</tt> the new instance is to
* attempt to bind to
*/
public DefaultStreamConnector(InetAddress bindAddr)
{
this.bindAddr = bindAddr;
}
/**
* Initializes a new <tt>DefaultStreamConnector</tt> instance which is to
* represent a specific pair of control and data <tt>DatagramSocket</tt>s.
*
* @param dataSocket the <tt>DatagramSocket</tt> to be used for data (e.g.
* RTP) traffic
* @param controlSocket the <tt>DatagramSocket</tt> to be used for control
* data (e.g. RTCP) traffic
*/
public DefaultStreamConnector(
DatagramSocket dataSocket,
DatagramSocket controlSocket)
{
this.controlSocket = controlSocket;
this.dataSocket = dataSocket;
this.bindAddr = null;
}
/**
* Releases the resources allocated by this instance in the course of its
* execution and prepares it to be garbage collected.
*
* @see StreamConnector#close()
*/
public void close()
{
if (controlSocket != null)
controlSocket.close();
if (dataSocket != null)
dataSocket.close();
}
/**
* Returns a reference to the <tt>DatagramSocket</tt> that a stream should
* use for control data (e.g. RTCP) traffic.
*
* @return a reference to the <tt>DatagramSocket</tt> that a stream should
* use for control data (e.g. RTCP) traffic
* @see StreamConnector#getControlSocket()
*/
public DatagramSocket getControlSocket()
{
if ((controlSocket == null) && (bindAddr != null))
controlSocket = createDatagramSocket(bindAddr);
return controlSocket;
}
/**
* Returns a reference to the <tt>DatagramSocket</tt> that a stream should
* use for data (e.g. RTP) traffic.
*
* @return a reference to the <tt>DatagramSocket</tt> that a stream should
* use for data (e.g. RTP) traffic
* @see StreamConnector#getDataSocket()
*/
public DatagramSocket getDataSocket()
{
if ((dataSocket == null) && (bindAddr != null))
dataSocket = createDatagramSocket(bindAddr);
return dataSocket;
}
/**
* Returns a reference to the <tt>Socket</tt> that a stream should
* use for data (e.g. RTP) traffic.
*
* @return a reference to the <tt>Socket</tt> that a stream should
* use for data (e.g. RTP) traffic.
*/
public Socket getDataTCPSocket()
{
return null;
}
/**
* Returns a reference to the <tt>Socket</tt> that a stream should
* use for control data (e.g. RTCP).
*
* @return a reference to the <tt>Socket</tt> that a stream should
* use for control data (e.g. RTCP).
*/
public Socket getControlTCPSocket()
{
return null;
}
/**
* Returns the protocol of this <tt>StreamConnector</tt>.
*
* @return the protocol of this <tt>StreamConnector</tt>
*/
public Protocol getProtocol()
{
return Protocol.UDP;
}
/**
* Notifies this instance that utilization of its <tt>DatagramSocket</tt>s
* for data and/or control traffic has started.
*
* @see StreamConnector#started()
*/
public void started()
{
}
/**
* Notifies this instance that utilization of its <tt>DatagramSocket</tt>s
* for data and/or control traffic has temporarily stopped. This instance
* should be prepared to be started at a later time again though.
*
* @see StreamConnector#stopped()
*/
public void stopped()
{
}
}
|