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 */ 072 @Override 073 public synchronized void resolve(JingleSession session) throws XMPPException, NotConnectedException, InterruptedException { 074 075 setResolveInit(); 076 077 clearCandidates(); 078 079 sid = random.nextInt(Integer.MAX_VALUE); 080 081 RTPBridge rtpBridge = RTPBridge.getRTPBridge(connection, String.valueOf(sid)); 082 083 String localIp = getLocalHost(); 084 085 TransportCandidate localCandidate = new TransportCandidate.Fixed( 086 rtpBridge.getIp(), rtpBridge.getPortA()); 087 localCandidate.setLocalIp(localIp); 088 089 TransportCandidate remoteCandidate = new TransportCandidate.Fixed( 090 rtpBridge.getIp(), rtpBridge.getPortB()); 091 remoteCandidate.setLocalIp(localIp); 092 093 localCandidate.setSymmetric(remoteCandidate); 094 remoteCandidate.setSymmetric(localCandidate); 095 096 localCandidate.setPassword(rtpBridge.getPass()); 097 remoteCandidate.setPassword(rtpBridge.getPass()); 098 099 localCandidate.setSessionId(rtpBridge.getSid()); 100 remoteCandidate.setSessionId(rtpBridge.getSid()); 101 102 localCandidate.setConnection(this.connection); 103 remoteCandidate.setConnection(this.connection); 104 105 addCandidate(localCandidate); 106 107 setResolveEnd(); 108 } 109 110 @Override 111 public void initialize() throws SmackException.SmackMessageException, XMPPErrorException, InterruptedException, 112 NoResponseException, NotConnectedException { 113 114 clearCandidates(); 115 116 if (!RTPBridge.serviceAvailable(connection)) { 117 setInitialized(); 118 throw new SmackException.SmackMessageException("No RTP Bridge service available"); 119 } 120 setInitialized(); 121 122 } 123 124 @Override 125 public void cancel() throws XMPPException { 126 // Nothing to do here 127 } 128 129 public static String getLocalHost() { 130 Enumeration<NetworkInterface> ifaces = null; 131 132 try { 133 ifaces = NetworkInterface.getNetworkInterfaces(); 134 } 135 catch (SocketException e) { 136 LOGGER.log(Level.WARNING, "exception", e); 137 } 138 139 while (ifaces.hasMoreElements()) { 140 141 NetworkInterface iface = ifaces.nextElement(); 142 Enumeration<InetAddress> iaddresses = iface.getInetAddresses(); 143 144 while (iaddresses.hasMoreElements()) { 145 InetAddress iaddress = iaddresses.nextElement(); 146 if (!iaddress.isLoopbackAddress() && !iaddress.isLinkLocalAddress() && !iaddress.isSiteLocalAddress() && !(iaddress instanceof Inet6Address)) { 147 return iaddress.getHostAddress(); 148 } 149 } 150 } 151 152 try { 153 return InetAddress.getLocalHost().getHostAddress(); 154 } 155 catch (Exception e) { 156 LOGGER.log(Level.WARNING, "exception", e); 157 } 158 159 return "127.0.0.1"; 160 161 } 162 163}