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 org.jivesoftware.smack.SmackException; 020import org.jivesoftware.smack.SmackException.NotConnectedException; 021import org.jivesoftware.smack.XMPPConnection; 022import org.jivesoftware.smack.XMPPException; 023import org.jivesoftware.smack.XMPPException.XMPPErrorException; 024import org.jivesoftware.smackx.jingleold.JingleSession; 025 026import java.net.Inet6Address; 027import java.net.InetAddress; 028import java.net.NetworkInterface; 029import java.net.SocketException; 030import java.util.Enumeration; 031import java.util.Random; 032import java.util.logging.Level; 033import java.util.logging.Logger; 034 035/** 036 * Bridged Resolver use a RTPBridge Service to add a relayed candidate. 037 * A very reliable solution for NAT Traversal. 038 * <p/> 039 * The resolver verify is the XMPP Server that the client is connected offer this service. 040 * If the server supports, a candidate is requested from the service. 041 * The resolver adds this candidate 042 */ 043public class BridgedResolver extends TransportResolver { 044 private static final Logger LOGGER = Logger.getLogger(BridgedResolver.class.getName()); 045 046 XMPPConnection connection; 047 048 Random random = new Random(); 049 050 long sid; 051 052 /** 053 * Constructor. 054 * A Bridged Resolver need an XMPPConnection to connect to a RTP Bridge. 055 */ 056 public BridgedResolver(XMPPConnection connection) { 057 super(); 058 this.connection = connection; 059 } 060 061 /** 062 * Resolve Bridged Candidate. 063 * <p/> 064 * The BridgedResolver takes the IP addresse and ports of a jmf proxy service. 065 * @throws NotConnectedException 066 * @throws InterruptedException 067 */ 068 @Override 069 public synchronized void resolve(JingleSession session) throws XMPPException, NotConnectedException, InterruptedException { 070 071 setResolveInit(); 072 073 clearCandidates(); 074 075 sid = Math.abs(random.nextLong()); 076 077 RTPBridge rtpBridge = RTPBridge.getRTPBridge(connection, String.valueOf(sid)); 078 079 String localIp = getLocalHost(); 080 081 TransportCandidate localCandidate = new TransportCandidate.Fixed( 082 rtpBridge.getIp(), rtpBridge.getPortA()); 083 localCandidate.setLocalIp(localIp); 084 085 TransportCandidate remoteCandidate = new TransportCandidate.Fixed( 086 rtpBridge.getIp(), rtpBridge.getPortB()); 087 remoteCandidate.setLocalIp(localIp); 088 089 localCandidate.setSymmetric(remoteCandidate); 090 remoteCandidate.setSymmetric(localCandidate); 091 092 localCandidate.setPassword(rtpBridge.getPass()); 093 remoteCandidate.setPassword(rtpBridge.getPass()); 094 095 localCandidate.setSessionId(rtpBridge.getSid()); 096 remoteCandidate.setSessionId(rtpBridge.getSid()); 097 098 localCandidate.setConnection(this.connection); 099 remoteCandidate.setConnection(this.connection); 100 101 addCandidate(localCandidate); 102 103 setResolveEnd(); 104 } 105 106 @Override 107 public void initialize() throws SmackException, XMPPErrorException, InterruptedException { 108 109 clearCandidates(); 110 111 if (!RTPBridge.serviceAvailable(connection)) { 112 setInitialized(); 113 throw new SmackException("No RTP Bridge service available"); 114 } 115 setInitialized(); 116 117 } 118 119 @Override 120 public void cancel() throws XMPPException { 121 // Nothing to do here 122 } 123 124 public static String getLocalHost() { 125 Enumeration<NetworkInterface> ifaces = null; 126 127 try { 128 ifaces = NetworkInterface.getNetworkInterfaces(); 129 } 130 catch (SocketException e) { 131 LOGGER.log(Level.WARNING, "exception", e); 132 } 133 134 while (ifaces.hasMoreElements()) { 135 136 NetworkInterface iface = ifaces.nextElement(); 137 Enumeration<InetAddress> iaddresses = iface.getInetAddresses(); 138 139 while (iaddresses.hasMoreElements()) { 140 InetAddress iaddress = iaddresses.nextElement(); 141 if (!iaddress.isLoopbackAddress() && !iaddress.isLinkLocalAddress() && !iaddress.isSiteLocalAddress() && !(iaddress instanceof Inet6Address)) { 142 return iaddress.getHostAddress(); 143 } 144 } 145 } 146 147 try { 148 return InetAddress.getLocalHost().getHostAddress(); 149 } 150 catch (Exception e) { 151 LOGGER.log(Level.WARNING, "exception", e); 152 } 153 154 return "127.0.0.1"; 155 156 } 157 158}