001/** 002 * 003 * Copyright 2003-2005 Jive Software. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.jingleold.nat; 018 019import java.net.Inet6Address; 020import java.net.InetAddress; 021import java.net.NetworkInterface; 022import java.net.SocketException; 023import java.util.Enumeration; 024import java.util.Random; 025import java.util.logging.Level; 026import java.util.logging.Logger; 027 028import org.jivesoftware.smack.SmackException; 029import org.jivesoftware.smack.SmackException.NoResponseException; 030import org.jivesoftware.smack.SmackException.NotConnectedException; 031import org.jivesoftware.smack.XMPPConnection; 032import org.jivesoftware.smack.XMPPException; 033import org.jivesoftware.smack.XMPPException.XMPPErrorException; 034 035import org.jivesoftware.smackx.jingleold.JingleSession; 036 037/** 038 * Bridged Resolver use a RTPBridge Service to add a relayed candidate. 039 * A very reliable solution for NAT Traversal. 040 * 041 * The resolver verify is the XMPP Server that the client is connected offer this service. 042 * If the server supports, a candidate is requested from the service. 043 * The resolver adds this candidate 044 */ 045public class BridgedResolver extends TransportResolver { 046 private static final Logger LOGGER = Logger.getLogger(BridgedResolver.class.getName()); 047 048 private final XMPPConnection connection; 049 050 private final Random random = new Random(); 051 052 private long sid; 053 054 /** 055 * Constructor. 056 * A Bridged Resolver need an XMPPConnection to connect to a RTP Bridge. 057 * 058 * @param connection the XMPP connection. 059 */ 060 public BridgedResolver(XMPPConnection connection) { 061 super(); 062 this.connection = connection; 063 } 064 065 /** 066 * Resolve Bridged Candidate. 067 * 068 * The BridgedResolver takes the IP address and ports of a jmf proxy service. 069 * @throws NotConnectedException if the XMPP connection is not connected. 070 * @throws InterruptedException if the calling thread was interrupted. 071 * @throws NoResponseException if there was no response from the remote entity. 072 */ 073 @Override 074 public synchronized void resolve(JingleSession session) throws XMPPException, NotConnectedException, InterruptedException, NoResponseException { 075 076 setResolveInit(); 077 078 clearCandidates(); 079 080 sid = random.nextInt(Integer.MAX_VALUE); 081 082 RTPBridge rtpBridge = RTPBridge.getRTPBridge(connection, String.valueOf(sid)); 083 084 String localIp = getLocalHost(); 085 086 TransportCandidate localCandidate = new TransportCandidate.Fixed( 087 rtpBridge.getIp(), rtpBridge.getPortA()); 088 localCandidate.setLocalIp(localIp); 089 090 TransportCandidate remoteCandidate = new TransportCandidate.Fixed( 091 rtpBridge.getIp(), rtpBridge.getPortB()); 092 remoteCandidate.setLocalIp(localIp); 093 094 localCandidate.setSymmetric(remoteCandidate); 095 remoteCandidate.setSymmetric(localCandidate); 096 097 localCandidate.setPassword(rtpBridge.getPass()); 098 remoteCandidate.setPassword(rtpBridge.getPass()); 099 100 localCandidate.setSessionId(rtpBridge.getSid()); 101 remoteCandidate.setSessionId(rtpBridge.getSid()); 102 103 localCandidate.setConnection(this.connection); 104 remoteCandidate.setConnection(this.connection); 105 106 addCandidate(localCandidate); 107 108 setResolveEnd(); 109 } 110 111 @Override 112 public void initialize() throws SmackException.SmackMessageException, XMPPErrorException, InterruptedException, 113 NoResponseException, NotConnectedException { 114 115 clearCandidates(); 116 117 if (!RTPBridge.serviceAvailable(connection)) { 118 setInitialized(); 119 throw new SmackException.SmackMessageException("No RTP Bridge service available"); 120 } 121 setInitialized(); 122 123 } 124 125 @Override 126 public void cancel() throws XMPPException { 127 // Nothing to do here 128 } 129 130 public static String getLocalHost() { 131 Enumeration<NetworkInterface> ifaces = null; 132 133 try { 134 ifaces = NetworkInterface.getNetworkInterfaces(); 135 } 136 catch (SocketException e) { 137 LOGGER.log(Level.WARNING, "exception", e); 138 } 139 140 while (ifaces.hasMoreElements()) { 141 142 NetworkInterface iface = ifaces.nextElement(); 143 Enumeration<InetAddress> iaddresses = iface.getInetAddresses(); 144 145 while (iaddresses.hasMoreElements()) { 146 InetAddress iaddress = iaddresses.nextElement(); 147 if (!iaddress.isLoopbackAddress() && !iaddress.isLinkLocalAddress() && !iaddress.isSiteLocalAddress() && !(iaddress instanceof Inet6Address)) { 148 return iaddress.getHostAddress(); 149 } 150 } 151 } 152 153 try { 154 return InetAddress.getLocalHost().getHostAddress(); 155 } 156 catch (Exception e) { 157 LOGGER.log(Level.WARNING, "exception", e); 158 } 159 160 return "127.0.0.1"; 161 162 } 163 164}