/** * Initializes and binds a socket that on a random port number. The method would try to bind on a * random port and retry 5 times until a free port is found. * * @return the socket that we have initialized on a randomport number. */ private DatagramSocket initRandomPortSocket() { DatagramSocket resultSocket = null; String bindRetriesStr = NetaddrActivator.getConfigurationService().getString(BIND_RETRIES_PROPERTY_NAME); int bindRetries = 5; if (bindRetriesStr != null) { try { bindRetries = Integer.parseInt(bindRetriesStr); } catch (NumberFormatException ex) { logger.error( bindRetriesStr + " does not appear to be an integer. " + "Defaulting port bind retries to " + bindRetries, ex); } } int currentlyTriedPort = NetworkUtils.getRandomPortNumber(); // we'll first try to bind to a random port. if this fails we'll try // again (bindRetries times in all) until we find a free local port. for (int i = 0; i < bindRetries; i++) { try { resultSocket = new DatagramSocket(currentlyTriedPort); // we succeeded - break so that we don't try to bind again break; } catch (SocketException exc) { if (exc.getMessage().indexOf("Address already in use") == -1) { logger.fatal( "An exception occurred while trying to create" + "a local host discovery socket.", exc); resultSocket = null; return null; } // port seems to be taken. try another one. logger.debug("Port " + currentlyTriedPort + " seems in use."); currentlyTriedPort = NetworkUtils.getRandomPortNumber(); logger.debug("Retrying bind on port " + currentlyTriedPort); } } return resultSocket; }
/** * Sends local candidate addresses from the local peer to the remote peer using the * <tt>candidates</tt> {@link SessionIQ}. * * @param candidates the local candidate addresses to be sent from the local peer to the remote * peer using the <tt>candidates</tt> {@link SessionIQ} */ protected void sendCandidates(Iterable<GTalkCandidatePacketExtension> candidates) { ProtocolProviderServiceJabberImpl protocolProvider = getProtocolProvider(); SessionIQ candidatesIQ = new SessionIQ(); candidatesIQ.setGTalkType(GTalkType.CANDIDATES); candidatesIQ.setFrom(protocolProvider.getOurJID()); candidatesIQ.setInitiator(isInitiator() ? getAddress() : protocolProvider.getOurJID()); candidatesIQ.setID(getSID()); candidatesIQ.setTo(getAddress()); candidatesIQ.setType(IQ.Type.SET); for (GTalkCandidatePacketExtension candidate : candidates) { // Android phone and Google Talk client does not seems to like IPv6 // candidates since it reject the IQ candidates with an error // so do not send IPv6 candidates to Android phone or Talk client if (isAndroidOrVtokOrTalkClient(getAddress()) && NetworkUtils.isIPv6Address(candidate.getAddress())) continue; candidatesIQ.addExtension(candidate); } protocolProvider.getConnection().sendPacket(candidatesIQ); }
/** * Returns the Google Contacts connection. * * @return Google Contacts connection */ public GoogleContactsConnectionImpl getConnection() { int s = login.indexOf('@'); boolean isGoogleAppsOrGmail = false; if (s == -1) { return null; } String domain = login.substring((s + 1)); try { SRVRecord srvRecords[] = NetworkUtils.getSRVRecords("xmpp-client", "tcp", domain); if (srvRecords != null) { // To detect that account is a google ones, we try following: // - lookup in SRV and see if it is google.com; // - if the account has been created with GoogleTalk form; // - if it is an "external" google contact. // SRV checks for (SRVRecord srv : srvRecords) { if (srv.getTarget().endsWith("google.com") || srv.getTarget().endsWith("google.com.")) { isGoogleAppsOrGmail = true; break; } } } // GoogleTalk based account or external Google Contacts ? if (!isGoogleAppsOrGmail) { isGoogleAppsOrGmail = googleTalk; } if (isGoogleAppsOrGmail) { if (cnx == null) { cnx = new GoogleContactsConnectionImpl(login, password); if (cnx.connect() == GoogleContactsConnection.ConnectionStatus.ERROR_INVALID_CREDENTIALS) { synchronized (this) { if (settings != null) { cnx = null; return null; } else { settings = new AccountSettingsForm(); } } settings.setModal(true); settings.loadData(cnx); int ret = settings.showDialog(); if (ret == 1) { cnx = settings.getConnection(); GoogleContactsActivator.getGoogleContactsService().saveConfig(cnx); } else { cnx = null; } } } else if (cnx.connect() == GoogleContactsConnection.ConnectionStatus.ERROR_INVALID_CREDENTIALS) { synchronized (this) { if (settings != null) { cnx = null; return null; } else { settings = new AccountSettingsForm(); } } settings.setModal(true); settings.loadData(cnx); int ret = settings.showDialog(); if (ret == 1) { cnx = settings.getConnection(); GoogleContactsActivator.getGoogleContactsService().saveConfig(cnx); } else { cnx = null; } } } else { cnx = null; } } catch (Exception e) { logger.info("GoogleContacts connection error", e); return null; } return (GoogleContactsConnectionImpl) cnx; }
/** * Attach JAIN-SIP <tt>SipProvider</tt> and <tt>ListeningPoint</tt> to the stack either for clear * communications or TLS. Clear UDP and TCP <tt>ListeningPoint</tt>s are not handled separately as * the former is a fallback for the latter (depending on the size of the data transmitted). Both * <tt>ListeningPoint</tt>s must be bound to the same address and port in order for the related * <tt>SipProvider</tt> to be created. If a UDP or TCP <tt>ListeningPoint</tt> cannot bind, retry * for both on another port. * * @param preferredPort which port to try first to bind. * @param retries how many times should we try to find a free port to bind * @param secure whether to create the TLS SipProvider. or the clear UDP/TCP one. * @throws TransportNotSupportedException in case we try to create a provider for a transport not * currently supported by jain-sip * @throws InvalidArgumentException if we try binding to an illegal port (which we won't) * @throws ObjectInUseException if another <tt>SipProvider</tt> is already associated with this * <tt>ListeningPoint</tt>. * @throws TransportAlreadySupportedException if there is already a ListeningPoint associated to * this <tt>SipProvider</tt> with the same transport of the <tt>ListeningPoint</tt>. * @throws TooManyListenersException if we try to add a new <tt>SipListener</tt> with a * <tt>SipProvider</tt> when one was already registered. */ private void createProvider(int preferredPort, int retries, boolean secure) throws TransportNotSupportedException, InvalidArgumentException, ObjectInUseException, TransportAlreadySupportedException, TooManyListenersException { String context = (secure ? "TLS: " : "clear UDP/TCP: "); if (retries < 0) { // very unlikely to happen with the default 50 retries logger.error(context + "couldn't find free ports to listen on."); return; } ListeningPoint tlsLP = null; ListeningPoint udpLP = null; ListeningPoint tcpLP = null; try { if (secure) { tlsLP = this.stack.createListeningPoint( NetworkUtils.IN_ADDR_ANY, preferredPort, ListeningPoint.TLS); if (logger.isTraceEnabled()) logger.trace("TLS secure ListeningPoint has been created."); this.secureJainSipProvider = this.stack.createSipProvider(tlsLP); this.secureJainSipProvider.addSipListener(this); } else { udpLP = this.stack.createListeningPoint( NetworkUtils.IN_ADDR_ANY, preferredPort, ListeningPoint.UDP); tcpLP = this.stack.createListeningPoint( NetworkUtils.IN_ADDR_ANY, preferredPort, ListeningPoint.TCP); if (logger.isTraceEnabled()) logger.trace("UDP and TCP clear ListeningPoints have " + "been created."); this.clearJainSipProvider = this.stack.createSipProvider(udpLP); this.clearJainSipProvider.addListeningPoint(tcpLP); this.clearJainSipProvider.addSipListener(this); } if (logger.isTraceEnabled()) logger.trace(context + "SipProvider has been created."); } catch (InvalidArgumentException ex) { // makes sure we didn't leave an open listener // as both UDP and TCP listener have to bind to the same port if (tlsLP != null) this.stack.deleteListeningPoint(tlsLP); if (udpLP != null) this.stack.deleteListeningPoint(udpLP); if (tcpLP != null) this.stack.deleteListeningPoint(tcpLP); // FIXME: "Address already in use" is not working // as ex.getMessage() displays in the locale language in SC // (getMessage() is always supposed to be English though) // this should be a temporary workaround // if (ex.getMessage().indexOf("Address already in use") != -1) // another software is probably using the port if (ex.getCause() instanceof java.io.IOException) { if (logger.isDebugEnabled()) logger.debug("Port " + preferredPort + " seems in use for either TCP or UDP."); // tries again on a new random port int currentlyTriedPort = NetworkUtils.getRandomPortNumber(); if (logger.isDebugEnabled()) logger.debug("Retrying bind on port " + currentlyTriedPort); this.createProvider(currentlyTriedPort, retries - 1, secure); } else throw ex; } }