]> sjero.net Git - linphone/blob - p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/IPUtils.java
remove mediastreamer2 and add it as a submodule instead.
[linphone] / p2pproxy / dependencies-src / jxse-src-2.5 / impl / src / net / jxta / impl / endpoint / IPUtils.java
1 /*
2  * Copyright (c) 2001-2007 Sun Microsystems, Inc.  All rights reserved.
3  *  
4  *  The Sun Project JXTA(TM) Software License
5  *  
6  *  Redistribution and use in source and binary forms, with or without 
7  *  modification, are permitted provided that the following conditions are met:
8  *  
9  *  1. Redistributions of source code must retain the above copyright notice,
10  *     this list of conditions and the following disclaimer.
11  *  
12  *  2. Redistributions in binary form must reproduce the above copyright notice, 
13  *     this list of conditions and the following disclaimer in the documentation 
14  *     and/or other materials provided with the distribution.
15  *  
16  *  3. The end-user documentation included with the redistribution, if any, must 
17  *     include the following acknowledgment: "This product includes software 
18  *     developed by Sun Microsystems, Inc. for JXTA(TM) technology." 
19  *     Alternately, this acknowledgment may appear in the software itself, if 
20  *     and wherever such third-party acknowledgments normally appear.
21  *  
22  *  4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must 
23  *     not be used to endorse or promote products derived from this software 
24  *     without prior written permission. For written permission, please contact 
25  *     Project JXTA at http://www.jxta.org.
26  *  
27  *  5. Products derived from this software may not be called "JXTA", nor may 
28  *     "JXTA" appear in their name, without prior written permission of Sun.
29  *  
30  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
31  *  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
32  *  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN 
33  *  MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
34  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
35  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
36  *  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
37  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
38  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
39  *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  *  
41  *  JXTA is a registered trademark of Sun Microsystems, Inc. in the United 
42  *  States and other countries.
43  *  
44  *  Please see the license information page at :
45  *  <http://www.jxta.org/project/www/license.html> for instructions on use of 
46  *  the license in source files.
47  *  
48  *  ====================================================================
49  *  
50  *  This software consists of voluntary contributions made by many individuals 
51  *  on behalf of Project JXTA. For more information on Project JXTA, please see 
52  *  http://www.jxta.org.
53  *  
54  *  This license is based on the BSD license adopted by the Apache Foundation. 
55  */
56
57 package net.jxta.impl.endpoint;
58
59
60 import java.io.IOException;
61 import java.net.BindException;
62 import java.net.Inet6Address;
63 import java.net.InetAddress;
64 import java.net.InetSocketAddress;
65 import java.net.NetworkInterface;
66 import java.net.ServerSocket;
67 import java.net.Socket;
68 import java.net.SocketException;
69 import java.util.ArrayList;
70 import java.util.Collections;
71 import java.util.Enumeration;
72 import java.util.Iterator;
73 import java.util.List;
74 import java.util.Random;
75 import javax.net.ServerSocketFactory;
76
77 import java.util.logging.Level;
78 import net.jxta.logging.Logging;
79 import java.util.logging.Logger;
80
81
82 /**
83  * Utility methods for use by IP based transports.
84  */
85 public final class IPUtils {
86     
87     /**
88      * Logger
89      */
90     private final static Logger LOG = Logger.getLogger(IPUtils.class.getName());
91     
92     final static Random random = new Random();
93     
94     final static String IPV4ANYADDRESS = "0.0.0.0";
95     final static String IPV6ANYADDRESS = "::";
96     
97     final static String IPV4LOOPBACK = "127.0.0.1";
98     final static String IPV6LOOPBACK = "::1";
99     
100     /**
101      * Constant which works as the IP "Any Address" value
102      */
103     public final static InetAddress ANYADDRESS;
104     public final static InetAddress ANYADDRESSV4;
105     public final static InetAddress ANYADDRESSV6;
106     
107     /**
108      * Constant which works as the IP "Local Loopback" value;
109      */
110     public final static InetAddress LOOPBACK;
111     public final static InetAddress LOOPBACKV4;
112     public final static InetAddress LOOPBACKV6;
113     
114     /**
115      * Socket factory to allow changing the way Sockets are created
116      * and connected.  A null value is ok and results in the regular
117      * connectToFromNoFactory being used.
118      *
119      * <p/>Plugin in a different implementation via setSocketFactory().
120      */
121     private static SocketFactory socketFactory;
122     
123     /**
124      * Socket factory to allow changing the way Sockets are created
125      * and connected.  A null value is ok and results in the regular
126      * connectToFromNoFactory being used.
127      *
128      * <p/>Plugin in a different implementation via setSocketFactory().
129      */
130     private static ServerSocketFactory serverSocketFactory;
131     
132     static {
133         InetAddress GET_ADDRESS = null;
134         
135         try {
136             GET_ADDRESS = InetAddress.getByName(IPV4ANYADDRESS);
137         } catch (Exception ignored) {
138             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
139                 LOG.warning("failed to intialize ANYADDRESSV4. Not fatal");
140             }
141         }
142         
143         ANYADDRESSV4 = GET_ADDRESS;
144
145         InetAddress GET_ANYADDRESSV6 = null;
146
147         GET_ADDRESS = null;
148         try {
149             GET_ADDRESS = InetAddress.getByName(IPV6ANYADDRESS);
150         } catch (Exception ignored) {
151             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
152                 LOG.warning("failed to intialize IPV6ANYADDRESS. Not fatal");
153             }
154         }
155         
156         ANYADDRESSV6 = GET_ADDRESS;
157         
158         ANYADDRESS = (ANYADDRESSV4 == null) ? ANYADDRESSV6 : ANYADDRESSV4;
159         
160         GET_ADDRESS = null;
161         try {
162             GET_ADDRESS = InetAddress.getByName(IPV4LOOPBACK);
163         } catch (Exception ignored) {
164             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
165                 LOG.warning("failed to intialize IPV4LOOPBACK. Not fatal");
166             }
167         }
168         
169         LOOPBACKV4 = GET_ADDRESS;
170         
171         GET_ADDRESS = null;
172         try {
173             GET_ADDRESS = InetAddress.getByName(IPV6LOOPBACK);
174         } catch (Exception ignored) {
175             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
176                 LOG.warning("failed to intialize ANYADDRESSV4. Not fatal");
177             }
178         }
179         
180         LOOPBACKV6 = GET_ADDRESS;
181         
182         LOOPBACK = (LOOPBACKV4 == null) ? LOOPBACKV6 : LOOPBACKV4;
183         
184         if (LOOPBACK == null || ANYADDRESS == null) {
185             if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
186                 LOG.severe("failure initializing statics. Neither IPV4 nor IPV6 seem to work.");
187             }
188             
189             throw new IllegalStateException("failure initializing statics. Neither IPV4 nor IPV6 seem to work.");
190         }
191     }
192     
193     /**
194      * This is a static utility class, you don't make instances.
195      */
196     private IPUtils() {}
197     
198     /**
199      * Provide an iterator which returns all of the local InetAddresses for this
200      * host.
201      *
202      * @return iterator of InetAddress which is all of the InetAddress for all
203      *         local interfaces.
204      */
205     public static Iterator<InetAddress> getAllLocalAddresses() {
206         List<InetAddress> allAddr = new ArrayList<InetAddress>();
207         
208         Enumeration<NetworkInterface> allInterfaces = null;
209
210         try {
211             allInterfaces = NetworkInterface.getNetworkInterfaces();
212         } catch (SocketException caught) {
213             if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
214                 LOG.log(Level.SEVERE, "Could not get local interfaces list", caught);
215             }
216         }
217         
218         if (null == allInterfaces) {
219             allInterfaces = Collections.enumeration(Collections.<NetworkInterface>emptyList());
220         }
221         
222         while (allInterfaces.hasMoreElements()) {
223             NetworkInterface anInterface = allInterfaces.nextElement();
224             
225             try {
226                 Enumeration<InetAddress> allIntfAddr = anInterface.getInetAddresses();
227                 
228                 while (allIntfAddr.hasMoreElements()) {
229                     InetAddress anAddr = allIntfAddr.nextElement();
230                     
231                     if (anAddr.isLoopbackAddress() || anAddr.isAnyLocalAddress()) {
232                         continue;
233                     }
234                     
235                     if (!allAddr.contains(anAddr)) {
236                         allAddr.add(anAddr);
237                     }
238                 }
239             } catch (Throwable caught) {
240                 if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
241                     LOG.log(Level.SEVERE, "Could not get addresses for " + anInterface, caught);
242                 }
243             }
244         }
245         
246         // if nothing suitable was found then return loopback address.
247         if (allAddr.isEmpty() || Boolean.getBoolean("net.jxta.impl.IPUtils.localOnly")) {
248             if (null != LOOPBACKV4) {
249                 allAddr.add(LOOPBACKV4);
250             }
251             
252             if (null != LOOPBACKV6) {
253                 allAddr.add(LOOPBACKV6);
254             }
255             
256             if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) {
257                 LOG.fine("Adding loopback interfaces");
258             }
259         }
260         
261         if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) {
262             LOG.fine("Returning " + allAddr.size() + " addresses.");
263         }
264         
265         return allAddr.iterator();
266     }
267     
268     /**
269      * Normalized version of {@link java.net.InetAddress#getHostAddress()} that
270      * handles IPv6 addresss formatting using the style of IETF RFC 2732 and
271      * also handles removal of IPv6 scoping identifiers.
272      *
273      * @see <a href="http://www.ietf.org/rfc/rfc2732.txt" target="_blank">IETF RFC 2732 <i>MIME : IPv6 Literal Addresses in URL's</i></a>
274      * @param anAddress The address to format as a <tt>String</tt>.
275      * @return The addresss formatted as a String.
276      */
277     public static String getHostAddress(InetAddress anAddress) {
278         String hostAddress;
279         
280         if (anAddress instanceof Inet6Address) {
281             hostAddress = anAddress.getHostAddress();
282             int percentAt = hostAddress.indexOf('%');
283             
284             if (-1 == percentAt) {
285                 // no scoping identifier. Just add the brackets.
286                 hostAddress = "[" + hostAddress + "]";
287             } else {
288                 // Remove scoping identifier. They aren't relevant when published.
289                 hostAddress = "[" + hostAddress.substring(0, percentAt) + "]";
290             }
291         } else {
292             hostAddress = anAddress.getHostAddress();
293         }
294         
295         return hostAddress;
296     }
297     
298     /**
299      *  Parses a String containing a SokectAddress formatted as either:
300      *  <p/>
301      *  <pre>
302      *     &lt;host> ":" &lt;port>
303      *
304      *     "[" &lt;numeric_host> "]:" &lt;port>
305      *  </pre>
306      *  <p/>
307      *  @param anAddress The address string to be parsed.
308      *  @return The parsed address.
309      */
310     public static InetSocketAddress parseSocketAddress(String anAddress) {
311         String hostAddress;
312         String port;
313         
314         if (anAddress.startsWith("[")) {
315             int endBracketAt = anAddress.indexOf(']');
316             int portSeparatorAt = anAddress.lastIndexOf(':');
317             
318             if (-1 == endBracketAt) {
319                 throw new IllegalArgumentException("missing final ]");
320             }
321             
322             if (-1 == portSeparatorAt) {
323                 throw new IllegalArgumentException("missing port separator");
324             }
325             
326             if (portSeparatorAt < endBracketAt) {
327                 throw new IllegalArgumentException("missing port");
328             }
329             
330             hostAddress = anAddress.substring(1, endBracketAt);
331             port = anAddress.substring(portSeparatorAt);
332         } else {
333             int portSeparatorAt = anAddress.lastIndexOf(':');
334             
335             if (-1 == portSeparatorAt) {
336                 throw new IllegalArgumentException("missing port separator");
337             }
338             
339             hostAddress = anAddress.substring(0, portSeparatorAt);
340             port = anAddress.substring(portSeparatorAt + 1);
341         }
342         
343         int portNum = Integer.parseInt(port);
344         
345         return InetSocketAddress.createUnresolved(hostAddress, portNum);
346     }
347     
348     /**
349      * Create a client socket using the configured socketFactory or
350      * connectToFromNoFactory if none is available.
351      *
352      * @param inetAddress    Destination address
353      * @param port           Destination port
354      * @param usingInterface Interface to use
355      * @param localPort      local port
356      * @param timeout        timeout in millis
357      * @return a client socket with the JDK1.4 method connect().
358      * @throws IOException if an io error occurs
359      */
360     public static Socket connectToFrom(InetAddress inetAddress, int port, InetAddress usingInterface, int localPort, int timeout) throws IOException {
361         if (socketFactory != null) {
362             return socketFactory.createConnection(inetAddress, port, usingInterface, localPort, timeout);
363         } else {
364             return connectToFromNoFactory(inetAddress, port, usingInterface, localPort, timeout);
365         }
366     }
367     
368     /**
369      * Create a client socket with the JDK1.4 method connect().
370      *
371      * @param inetAddress    Destination address
372      * @param port           Destination port
373      * @param usingInterface Interface to use
374      * @param localPort      local port
375      * @param timeout        timeout in millis
376      * @return a client socket with the JDK1.4 method connect().
377      * @throws IOException if an io error occurs
378      */
379     public static Socket connectToFromNoFactory(InetAddress inetAddress, int port, InetAddress usingInterface, int localPort, int timeout) throws IOException {
380         
381         Socket socket = new Socket();
382         InetSocketAddress src = new InetSocketAddress(usingInterface, localPort);
383         InetSocketAddress dst = new InetSocketAddress(inetAddress, port);
384
385         socket.bind(src);
386         socket.connect(dst, timeout);
387         
388         return socket;
389     }
390     
391     /**
392      * makes connectToFrom create sockets with this factory.
393      *
394      * @param sf is the socket factory to use or null if you want the
395      *           default behaviour provided by connectToFromNoFactory().
396      */
397     public static void setSocketFactory(SocketFactory sf) {
398         socketFactory = sf;
399     }
400     
401     /**
402      * returns the socketFactory used by connectToFrom() to create sockets, or
403      * null if connectToFromNoFactory() is being used.
404      *
405      * @return the socket factory used by connectToFrom() or null if
406      *         the connectToFromNoFactory() method is used to create Sockets.
407      */
408     public static SocketFactory getSocketFactory() {
409         return socketFactory;
410     }
411     
412     /**
413      * makes connectToFrom create sockets with this factory.
414      *
415      * @param sf is the socket factory to use or null if you want the
416      *           default behaviour provided by new SeverSocket().
417      */
418     public static void setServerSocketFactory(ServerSocketFactory sf) {
419         serverSocketFactory = sf;
420     }
421     
422     /**
423      * returns the ServerSocketFactory to create server sockets, or
424      * null if new SeverSocket() is being used.
425      *
426      * @return the socket factory used or null if
427      *         the new SeverSocket() method is used to create ServerSockets.
428      */
429     public static ServerSocketFactory getServerSocketFactory() {
430         return serverSocketFactory;
431     }
432     
433     /**
434      * Size of port groups we will probe.
435      */
436     final static int rangesize = 200;
437     
438     /**
439      * Open a ServerSocket in the specified range.
440      *
441      * <p/>
442      * The method used is done so that the entire range is examined if
443      * needed while ensuring that the process eventually terminates if no port
444      * is available.
445      *
446      * @param start       The lowest numbered port to try.
447      * @param end         The highest numbered port to try.
448      * @param backlog     the allowed backlog of unaccepted connections.
449      * @param bindAddress the InetAddress to which to bind.
450      * @return a ServerSocket in the specified range.
451      * @throws IOException when the socket cannot be opened. (Lame, but that's what ServerSocket says).
452      */
453     public static ServerSocket openServerSocketInRange(int start, int end, int backlog, InetAddress bindAddress) throws IOException {
454         ServerSocketFactory factory = getServerSocketFactory();
455         
456         if ((start < 1) || (start > 65535)) {
457             throw new IllegalArgumentException("Invalid start port");
458         }
459         
460         if ((end < 1) || (end > 65535) || (end < start)) {
461             throw new IllegalArgumentException("Invalid end port");
462         }
463         
464         // fill the inRange array.
465         List<Integer> inRange = new ArrayList<Integer>(rangesize);
466
467         for (int eachInRange = 0; eachInRange < rangesize; eachInRange++) {
468             inRange.add(eachInRange, eachInRange);
469         }
470         
471         // fill the ranges array.
472         List<Integer> ranges = new ArrayList<Integer>();
473         int starts = start;
474         
475         while (starts <= end) {
476             ranges.add(starts);
477             starts += rangesize;
478         }
479         
480         // shuffle the ranges
481         Collections.shuffle(ranges);
482         while (!ranges.isEmpty()) {
483             int range = ranges.remove(0);
484             
485             // reshuffle the inRange
486             Collections.shuffle(inRange);
487             
488             for (int eachInRange = 0; eachInRange < rangesize; eachInRange++) {
489                 int tryPort = range + inRange.get(eachInRange);
490                 
491                 if (tryPort > end) {
492                     continue;
493                 }
494                 
495                 try {
496                     ServerSocket result;
497
498                     if (null == factory) {
499                         result = new ServerSocket(tryPort, backlog, bindAddress);
500                     } else {
501                         result = factory.createServerSocket(tryPort, backlog, bindAddress);
502                     }
503                     
504                     return result;
505                 } catch (BindException failed) {// this one is busy. try another.
506                 }
507             }
508         }
509         throw new BindException("All ports in range are in use.");
510     }
511 }