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