STUN Service discovery and Server/Port Retrieve added

git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@6583 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
Thiago Camargo 2007-01-05 20:03:10 +00:00 committed by thiago
parent 92d1de2dce
commit 9facc5fd63
2 changed files with 231 additions and 0 deletions

View File

@ -0,0 +1,223 @@
package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.packet.DiscoverInfo;
import org.jivesoftware.smackx.packet.DiscoverItems;
import org.xmlpull.v1.XmlPullParser;
import java.util.Iterator;
/**
* STUN IQ Packet used to request and retrieve a STUN server and port to make p2p connections easier. STUN is usually used by Jingle Media Transmission between two parties that are behind NAT.
* <p/>
* High Level Usage Example:
* <p/>
* STUN stun = STUN.getSTUNServer(xmppConnection);
*
* @author Thiago Camargo
*/
public class STUN extends IQ {
private int port = -1;
private String host;
/**
* Element name of the packet extension.
*/
public static final String NAME = "stun";
/**
* Element name of the packet extension.
*/
public static final String ELEMENT_NAME = "query";
/**
* Namespace of the packet extension.
*/
public static final String NAMESPACE = "google:jingleinfo";
static {
ProviderManager.getInstance().addIQProvider(NAME, NAMESPACE, new STUN.Provider());
}
/**
* Creates a STUN IQ
*/
public STUN() {
}
/**
* Get the Host Address
*
* @return
*/
public String getHost() {
return host;
}
/**
* Set the Host Address
*
* @param host
*/
public void setHost(String host) {
this.host = host;
}
/**
* Get STUN port
*
* @return
*/
public int getPort() {
return port;
}
/**
* Set STUN port
*
* @param port
*/
public void setPort(int port) {
this.port = port;
}
/**
* Get the Child Element XML of the Packet
*
* @return
*/
public String getChildElementXML() {
StringBuilder str = new StringBuilder();
str.append("<" + ELEMENT_NAME + " xmlns='" + NAMESPACE + "'/>");
return str.toString();
}
/**
* IQProvider for RTP Bridge packets.
* Parse receive RTPBridge packet to a RTPBridge instance
*
* @author Thiago Rocha
*/
public static class Provider implements IQProvider {
public Provider() {
super();
}
public IQ parseIQ(XmlPullParser parser) throws Exception {
boolean done = false;
int eventType;
String elementName;
String namespace;
if (!parser.getNamespace().equals(NAMESPACE))
throw new Exception("Not a STUN packet");
STUN iq = new STUN();
// Start processing sub-elements
while (!done) {
eventType = parser.next();
elementName = parser.getName();
namespace = parser.getNamespace();
if (eventType == XmlPullParser.START_TAG) {
if (elementName.equals("server")) {
for (int i = 0; i < parser.getAttributeCount(); i++) {
if (parser.getAttributeName(i).equals("host"))
iq.setHost(parser.getAttributeValue(i));
else if (parser.getAttributeName(i).equals("udp"))
iq.setPort(Integer.parseInt(parser.getAttributeValue(i)));
}
}
} else if (eventType == XmlPullParser.END_TAG) {
if (parser.getName().equals(ELEMENT_NAME)) {
done = true;
}
}
}
return iq;
}
}
/**
* Get a new STUN Server Address and port from the server.
* If a error occurs or the server don´t support STUN Service, null is returned.
*
* @param xmppConnection
* @return
*/
public static STUN getSTUNServer(XMPPConnection xmppConnection) {
if (!xmppConnection.isConnected()) {
return null;
}
STUN stunPacket = new STUN();
stunPacket.setTo(NAME + "." + xmppConnection.getServiceName());
PacketCollector collector = xmppConnection
.createPacketCollector(new PacketIDFilter(stunPacket.getPacketID()));
xmppConnection.sendPacket(stunPacket);
STUN response = (STUN) collector
.nextResult(SmackConfiguration.getPacketReplyTimeout());
// Cancel the collector.
collector.cancel();
return response;
}
/**
* Check if the server support STUN Service.
*
* @param xmppConnection
* @return
*/
public static boolean serviceAvailable(XMPPConnection xmppConnection) {
if (!xmppConnection.isConnected()) {
return false;
}
System.out.println("Service listing");
ServiceDiscoveryManager disco = ServiceDiscoveryManager
.getInstanceFor(xmppConnection);
try {
DiscoverItems items = disco.discoverItems(xmppConnection.getServiceName());
Iterator iter = items.getItems();
while (iter.hasNext()) {
DiscoverItems.Item item = (DiscoverItems.Item) iter.next();
DiscoverInfo info = disco.discoverInfo(item.getEntityID());
Iterator<DiscoverInfo.Identity> iter2 = info.getIdentities();
while (iter2.hasNext()) {
DiscoverInfo.Identity identity = iter2.next();
if (identity.getCategory().equals("proxy") && identity.getType().equals("stun"))
if (info.containsFeature(NAMESPACE))
return true;
}
}
}
catch (XMPPException e) {
e.printStackTrace();
}
return false;
}
}

View File

@ -162,6 +162,14 @@ public class STUNResolverTest extends SmackTestCase {
System.out.println(stunServers.size() + " servers loaded");
}
public void testGetSTUNServer() {
System.out.println(STUN.serviceAvailable(getConnection(0)));
STUN stun = STUN.getSTUNServer(getConnection(0));
System.out.println(stun.getHost() + ":" +stun.getPort());
}
/**
* Test for resolve()
*