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