Commit 59e84539 authored by Thiago Camargo's avatar Thiago Camargo Committed by thiago

STUN Server Module added

git-svn-id: http://svn.igniterealtime.org/svn/repos/wildfire/trunk@6598 b35dd754-fafc-0310-a699-88a17e54d16e
parent 2c9e6f17
......@@ -149,7 +149,7 @@
<fileset dir="${lib.build.dir}" includes="*.jar" excludes="junit.jar"/>
<fileset dir="${lib.merge.dir}" includes="*.jar"/>
<fileset dir="${lib.dist.dir}"
includes="servlet.jar, mail.jar, activation.jar, jdic.jar, bouncycastle.jar"/>
includes="servlet.jar, mail.jar, activation.jar, jdic.jar, bouncycastle.jar, jstun-0.6.1.jar"/>
</path>
<path id="compile.dependencies">
......@@ -780,7 +780,7 @@
<for param="jar">
<path>
<fileset dir="${release.out.dir}/lib" includes="*.jar"
excludes="startup.jar,jdic.jar,mail.jar,activation.jar,bouncycastle.jar"/>
excludes="startup.jar,jdic.jar,mail.jar,activation.jar,bouncycastle.jar,jstun-0.6.1.jar"/>
</path>
<sequential>
<delete file="@{jar}.pack"/>
......@@ -797,7 +797,7 @@
<for param="jar">
<path>
<fileset dir="${release.out.dir}/plugins/admin/webapp/WEB-INF/lib" includes="*.jar"
excludes="startup.jar,jdic.jar,mail.jar,activation.jar,bouncycastle.jar"/>
excludes="startup.jar,jdic.jar,mail.jar,activation.jar,bouncycastle.jar,jstun-0.6.1.jar"/>
</path>
<sequential>
<delete file="@{jar}.pack"/>
......@@ -1195,7 +1195,7 @@
be manually added to this list.
-->
<property name="pack200.excludes"
value="gnujaxp.jar,mail.jar,activation.jar,bouncycastle.jar"/>
value="gnujaxp.jar,mail.jar,activation.jar,bouncycastle.jar,jstun-0.6.1.jar"/>
<for param="jar">
<path>
......
......@@ -44,6 +44,7 @@ import org.jivesoftware.wildfire.update.UpdateManager;
import org.jivesoftware.wildfire.user.UserManager;
import org.jivesoftware.wildfire.vcard.VCardManager;
import org.jivesoftware.wildfire.mediaproxy.MediaProxyService;
import org.jivesoftware.wildfire.stun.STUNService;
import org.xmpp.packet.JID;
import java.io.File;
......@@ -489,6 +490,7 @@ public class XMPPServer {
loadModule(DefaultFileTransferManager.class.getName());
loadModule(FileTransferProxy.class.getName());
loadModule(MediaProxyService.class.getName());
loadModule(STUNService.class.getName());
loadModule(PubSubModule.class.getName());
loadModule(UpdateManager.class.getName());
loadModule(InternalComponentManager.class.getName());
......@@ -1268,12 +1270,23 @@ public class XMPPServer {
* <code>MediaProxyService</code> was registered with the server as a module while starting up
* the server.
*
* @return the <code>FileTransferProxy</code> registered with this server.
* @return the <code>MediaProxyService</code> registered with this server.
*/
public MediaProxyService getMediaProxyService() {
return (MediaProxyService) modules.get(MediaProxyService.class);
}
/**
* Returns the <code>STUNService</code> registered with this server. The
* <code>MediaProxyService</code> was registered with the server as a module while starting up
* the server.
*
* @return the <code>STUNService</code> registered with this server.
*/
public STUNService getSTUNService() {
return (STUNService) modules.get(STUNService.class);
}
/**
* Returns the <code>InternalComponentManager</code> registered with this server. The
* <code>InternalComponentManager</code> was registered with the server as a module while starting up
......
/**
* $RCSfile$
* $Revision: 3144 $
* $Date: 2005-12-01 14:20:11 -0300 (Thu, 01 Dec 2005) $
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.wildfire.stun;
import de.javawi.jstun.test.demo.StunServer;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.jivesoftware.wildfire.*;
import org.jivesoftware.wildfire.auth.UnauthorizedException;
import org.jivesoftware.wildfire.container.BasicModule;
import org.jivesoftware.wildfire.disco.DiscoInfoProvider;
import org.jivesoftware.wildfire.disco.DiscoItemsProvider;
import org.jivesoftware.wildfire.disco.DiscoServerItem;
import org.jivesoftware.wildfire.disco.ServerItemsProvider;
import org.jivesoftware.wildfire.forms.spi.XDataFormImpl;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import org.xmpp.packet.PacketError;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* STUN Server and Service Module
* Provides especial Address discovery for p2p sessions to be used for media transmission and receiving of UDP packets.
* Especialy used for behind NAT users to ensure connectivity between parties.
*
* @author Thiago Camargo
*/
public class STUNService extends BasicModule implements ServerItemsProvider, RoutableChannelHandler, DiscoInfoProvider, DiscoItemsProvider {
private String serviceName;
private RoutingTable routingTable;
private PacketRouter router;
private StunServer stunServer = null;
private String name = "stun";
private boolean enabled = false;
private String primaryAddress;
private String secondaryAddress;
private int primaryPort = 3478;
private int secondaryPort = 3576;
public static final String NAMESPACE = "google:jingleinfo";
/**
* Constructs a new STUN Service
*/
public STUNService() {
super("STUN Service");
}
/**
* Load config using JiveGlobals
*/
private void loadSTUNConfig() {
primaryAddress = JiveGlobals.getProperty("stun.address.primary");
secondaryAddress = JiveGlobals.getProperty("stun.address.secondary");
if (primaryAddress == null || primaryAddress.equals(""))
primaryAddress = JiveGlobals.getProperty("xmpp.domain",
JiveGlobals.getProperty("network.interface", "localhost"));
if (secondaryAddress == null || secondaryAddress.equals(""))
secondaryAddress = "127.0.0.1";
try {
primaryPort = Integer.valueOf(JiveGlobals.getProperty("stun.port.primary"));
}
catch (NumberFormatException e) {
// Do nothing let the default values to be used.
}
try {
secondaryPort = Integer.valueOf(JiveGlobals.getProperty("stun.port.secondary"));
}
catch (NumberFormatException e) {
// Do nothing let the default values to be used.
}
if (JiveGlobals.getProperty("stun.enabled") == null) {
this.enabled = true;
} else {
this.enabled = Boolean.parseBoolean(JiveGlobals.getProperty("stun.enabled"));
}
}
public void destroy() {
super.destroy();
stunServer = null;
}
public void initialize(XMPPServer server) {
super.initialize(server);
routingTable = server.getRoutingTable();
router = server.getPacketRouter();
loadSTUNConfig();
}
public void start() {
if (isEnabled()) {
startServer();
} else {
XMPPServer.getInstance().getIQDiscoItemsHandler().removeServerItemsProvider(this);
}
}
public void startServer() {
try {
InetAddress primary = InetAddress.getByName(primaryAddress);
InetAddress secondary = InetAddress.getByName(secondaryAddress);
if (primary != null && secondary != null) {
stunServer = new StunServer(primaryPort, primary, secondaryPort, secondary);
serviceName = JiveGlobals.getProperty("stun.serviceName", name);
serviceName = serviceName == null ? name : serviceName.equals("") ? name : serviceName;
stunServer.start();
} else
setEnabled(false);
} catch (SocketException e) {
setEnabled(false);
} catch (UnknownHostException e) {
setEnabled(false);
}
if (stunServer != null) {
routingTable.addRoute(getAddress(), this);
XMPPServer server = XMPPServer.getInstance();
server.getIQDiscoItemsHandler().addServerItemsProvider(this);
}
}
public void stop() {
super.stop();
this.enabled = false;
if (stunServer != null)
stunServer.stop();
stunServer = null;
XMPPServer.getInstance().getIQDiscoItemsHandler()
.removeComponentItem(getAddress().toString());
if (routingTable != null)
routingTable.removeRoute(getAddress());
}
public String getName() {
return serviceName;
}
public Iterator<Element> getItems(String name, String node, JID senderJID) {
List<Element> identities = new ArrayList<Element>();
// Answer the identity of the proxy
Element identity = DocumentHelper.createElement("item");
identity.addAttribute("jid", getServiceDomain());
identity.addAttribute("name", "STUN Service");
identities.add(identity);
return identities.iterator();
}
public void process(Packet packet) throws UnauthorizedException, PacketException {
// Check if user is allowed to send packet to this service
if (packet instanceof IQ) {
// Handle disco packets
IQ iq = (IQ) packet;
// Ignore IQs of type ERROR or RESULT
if (IQ.Type.error == iq.getType() || IQ.Type.result == iq.getType()) {
return;
}
processIQ(iq);
}
}
private void processIQ(IQ iq) {
IQ reply = IQ.createResultIQ(iq);
Element childElement = iq.getChildElement();
String namespace = childElement.getNamespaceURI();
Element childElementCopy = iq.getChildElement().createCopy();
reply.setChildElement(childElementCopy);
if ("http://jabber.org/protocol/disco#info".equals(namespace)) {
try {
reply = XMPPServer.getInstance().getIQDiscoInfoHandler().handleIQ(iq);
router.route(reply);
return;
}
catch (UnauthorizedException e) {
// Do nothing. This error should never happen
}
} else if ("http://jabber.org/protocol/disco#items".equals(namespace)) {
try {
// a component
reply = XMPPServer.getInstance().getIQDiscoItemsHandler().handleIQ(iq);
router.route(reply);
return;
}
catch (UnauthorizedException e) {
// Do nothing. This error should never happen
}
} else if (NAMESPACE.equals(namespace)) {
Element stun = childElementCopy.addElement("stun");
Element server = stun.addElement("server");
server.addAttribute("host", primaryAddress);
server.addAttribute("udp", String.valueOf(primaryPort));
} else {
// Answer an error since the server can't handle the requested namespace
reply.setError(PacketError.Condition.service_unavailable);
}
try {
Log.debug("RETURNED:" + reply.toXML());
router.route(reply);
}
catch (Exception e) {
Log.error(e);
}
}
/**
* Returns the fully-qualifed domain name of this chat service.
* The domain is composed by the service name and the
* name of the XMPP server where the service is running.
*
* @return the file transfer server domain (service name + host name).
*/
public String getServiceDomain() {
return serviceName + "." + XMPPServer.getInstance().getServerInfo().getName();
}
public JID getAddress() {
return new JID(null, getServiceDomain(), null);
}
public Iterator<DiscoServerItem> getItems() {
List<DiscoServerItem> items = new ArrayList<DiscoServerItem>();
if (!isEnabled()) {
return items.iterator();
}
items.add(new DiscoServerItem() {
public String getJID() {
return getServiceDomain();
}
public String getName() {
return "STUN Service";
}
public String getAction() {
return null;
}
public String getNode() {
return null;
}
public DiscoInfoProvider getDiscoInfoProvider() {
return STUNService.this;
}
public DiscoItemsProvider getDiscoItemsProvider() {
return STUNService.this;
}
});
return items.iterator();
}
public Iterator<Element> getIdentities(String name, String node, JID senderJID) {
List<Element> identities = new ArrayList<Element>();
// Answer the identity of the proxy
Element identity = DocumentHelper.createElement("identity");
identity.addAttribute("category", "proxy");
identity.addAttribute("name", "STUN Service");
identity.addAttribute("type", "stun");
identities.add(identity);
return identities.iterator();
}
public Iterator<String> getFeatures(String name, String node, JID senderJID) {
return Arrays.asList(NAMESPACE,
"http://jabber.org/protocol/disco#info").iterator();
}
public XDataFormImpl getExtendedInfo(String name, String node, JID senderJID) {
return null;
}
public boolean hasInfo(String name, String node, JID senderJID) {
return true;
}
/**
* Get if the service is enabled.
*
* @return enabled
*/
public boolean isEnabled() {
return enabled;
}
/**
* Set the service enable status.
*
* @param enabled
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
loadSTUNConfig();
if (isEnabled()) {
startServer();
} else {
stop();
}
}
/**
* Get the secondary Port used by the STUN server
*
* @return
*/
public int getSecondaryPort() {
return secondaryPort;
}
/**
* Get the primary Port used by the STUN server
*
* @return
*/
public int getPrimaryPort() {
return primaryPort;
}
/**
* Get the secondary Address used by the STUN server
*
* @return
*/
public String getSecondaryAddress() {
return secondaryAddress;
}
/**
* Get the primary Address used by the STUN server
*
* @return
*/
public String getPrimaryAddress() {
return primaryAddress;
}
}
......@@ -136,6 +136,10 @@
url="media-proxy.jsp"
description="Media proxy settings"/>
<!-- STUN Server Settings -->
<item id="stun-settings" name="STUN Server Settings"
url="stun-settings.jsp"
description="STUN Server Settings"/>
</sidebar>
</tab>
......
<%--
- $Revision: 5321 $
- $Date: 2006-09-11 01:22:53 -0300 (seg, 11 set 2006) $
-
- Copyright (C) 2004-2005 Jive Software. All rights reserved.
-
- This software is published under the terms of the GNU Public License (GPL),
- a copy of which is included in this distribution.
--%>
<%@ page import="org.jivesoftware.util.JiveGlobals" %>
<%@ page import="org.jivesoftware.util.ParamUtils" %>
<%@ page import="org.jivesoftware.wildfire.XMPPServer" %>
<%@ page import="org.jivesoftware.wildfire.stun.STUNService" %>
<%
STUNService stunService = XMPPServer.getInstance().getSTUNService();
boolean save = request.getParameter("set") != null;
boolean success = false;
boolean enabled = false;
String primaryAddress;
String secondaryAddress;
int primaryPort = 3478;
int secondaryPort = 3576;
if (save) {
primaryPort = ParamUtils.getIntParameter(request, "primaryPort", primaryPort);
JiveGlobals.setProperty("stun.port.primary", String.valueOf(primaryPort));
secondaryPort = ParamUtils.getIntParameter(request, "secondaryPort", secondaryPort);
JiveGlobals.setProperty("stun.port.secondary", String.valueOf(secondaryPort));
primaryAddress = ParamUtils.getParameter(request, "primaryAddress", true);
JiveGlobals.setProperty("stun.address.primary", primaryAddress);
secondaryAddress = ParamUtils.getParameter(request, "secondaryAddress", true);
JiveGlobals.setProperty("stun.address.secondary", secondaryAddress);
enabled = ParamUtils.getBooleanParameter(request, "enabled", enabled);
JiveGlobals.setProperty("stun.enabled", String.valueOf(enabled));
stunService.stop();
stunService.setEnabled(enabled);
success = true;
}
%>
<html>
<head>
<title>STUN Server Settings</title>
<meta name="pageID" content="stun-settings"/>
</head>
<body>
<p>
Use the form below to manage STUN Server settings.<br>
</p>
<% if (success) { %>
<div class="jive-success">
<table cellpadding="0" cellspacing="0" border="0">
<tbody>
<tr>
<td class="jive-icon"><img src="images/success-16x16.gif" width="16" height="16"
border="0"></td>
<td class="jive-icon-label">Settings updated successfully.</td>
</tr>
</tbody>
</table>
</div>
<br>
<% } %>
<form action="stun-settings.jsp" method="post">
<fieldset>
<legend>STUN Server Settings</legend>
<div>
<p>
The settings will just take effects after savings settings.
</p>
<table cellpadding="3" cellspacing="0" border="0" width="100%">
<tbody>
<tr>
<td align="left">Primary Address:&nbsp<input type="text" size="20"
maxlength="100"
name="primaryAddress"
value="<%=stunService.getPrimaryAddress()%>"
align="left">
</td>
</tr>
<tr>
<td align="left">Secondary Address:&nbsp<input type="text" size="20"
maxlength="100"
name="secondaryAddress"
value="<%=stunService.getSecondaryAddress()%>"
align="left">
</td>
</tr>
<tr>
<td align="left">Primary Port Value:&nbsp<input type="text" size="20"
maxlength="100"
name="primaryPort"
value="<%=stunService.getPrimaryPort()%>"
align="left">
</td>
</tr>
<tr>
<td align="left">Secondary Port Value:&nbsp<input type="text" size="20"
maxlength="100"
name="secondaryPort"
value="<%=stunService.getSecondaryPort()%>"
align="left">
</td>
</tr>
<tr>
<td align="left">Enabled:&nbsp<input type="checkbox"
name="enabled"
<%=stunService.isEnabled()?"checked":""%>
align="left">
</td>
</tr>
</tbody>
</table>
</div>
<input type="submit" name="set" value="Change">
</fieldset>
</form>
</body>
</html>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment