/** * Tries to obtain a mapped/public address for the specified port (possibly by executing a STUN * query). * * @param dst the destination that we'd like to use this address with. * @param port the port whose mapping we are interested in. * @return a public address corresponding to the specified port or null if all attempts to * retrieve such an address have failed. * @throws IOException if an error occurs while stun4j is using sockets. * @throws BindException if the port is already in use. */ public InetSocketAddress getPublicAddressFor(InetAddress dst, int port) throws IOException, BindException { if (!useStun || (dst instanceof Inet6Address)) { logger.debug( "Stun is disabled for destination " + dst + ", skipping mapped address recovery (useStun=" + useStun + ", IPv6@=" + (dst instanceof Inet6Address) + ")."); // we'll still try to bind though so that we could notify the caller // if the port has been taken already. DatagramSocket bindTestSocket = new DatagramSocket(port); bindTestSocket.close(); // if we're here then the port was free. return new InetSocketAddress(getLocalHost(dst), port); } StunAddress mappedAddress = queryStunServer(port); InetSocketAddress result = null; if (mappedAddress != null) result = mappedAddress.getSocketAddress(); else { // Apparently STUN failed. Let's try to temporarily disble it // and use algorithms in getLocalHost(). ... We should probably // eveng think about completely disabling stun, and not only // temporarily. // Bug report - John J. Barton - IBM InetAddress localHost = getLocalHost(dst); result = new InetSocketAddress(localHost, port); } if (logger.isDebugEnabled()) logger.debug("Returning mapping for port:" + port + " as follows: " + result); return result; }
/** * Initializes this network address manager service implementation and starts all * processes/threads associated with this address manager, such as a stun firewall/nat detector, * keep alive threads, binding lifetime discovery threads and etc. The method may also be used * after a call to stop() as a reinitialization technique. */ public void start() { // init stun String stunAddressStr = null; int port = -1; stunAddressStr = NetaddrActivator.getConfigurationService().getString(PROP_STUN_SERVER_ADDRESS); String portStr = NetaddrActivator.getConfigurationService().getString(PROP_STUN_SERVER_PORT); this.localHostFinderSocket = initRandomPortSocket(); if (stunAddressStr == null || portStr == null) { useStun = false; // we use the default stun server address only for chosing a public // route and not for stun queries. stunServerAddress = new StunAddress(DEFAULT_STUN_SERVER_ADDRESS, DEFAULT_STUN_SERVER_PORT); logger.info( "Stun server address(" + stunAddressStr + ")/port(" + portStr + ") not set (or invalid). Disabling STUN."); } else { try { port = Integer.valueOf(portStr).intValue(); } catch (NumberFormatException ex) { logger.error(portStr + " is not a valid port number. " + "Defaulting to 3478", ex); port = 3478; } stunServerAddress = new StunAddress(stunAddressStr, port); detector = new SimpleAddressDetector(stunServerAddress); if (logger.isDebugEnabled()) { logger.debug( "Created a STUN Address detector for the following " + "STUN server: " + stunAddressStr + ":" + port); } detector.start(); logger.debug("STUN server detector started;"); // make sure that someone doesn't set invalid stun address and port NetaddrActivator.getConfigurationService() .addVetoableChangeListener(PROP_STUN_SERVER_ADDRESS, this); NetaddrActivator.getConfigurationService() .addVetoableChangeListener(PROP_STUN_SERVER_PORT, this); // now start a thread query to the stun server and only set the // useStun flag to true if it succeeds. launchStunServerTest(); } }
/** * The method queries a Stun server for a binding for the specified port. * * @param port the port to resolve (the stun message gets sent trhough that port) * @return StunAddress the address returned by the stun server or null if an error occurred or no * address was returned * @throws IOException if an error occurs while stun4j is using sockets. * @throws BindException if the port is already in use. */ private StunAddress queryStunServer(int port) throws IOException, BindException { StunAddress mappedAddress = null; if (detector != null && useStun) { mappedAddress = detector.getMappingFor(port); if (logger.isDebugEnabled()) logger.debug( "For port:" + port + "a Stun server returned the " + "following mapping [" + mappedAddress); } return mappedAddress; }