📄 mediaproxyservice.java
字号:
/**
* $Revision$
* $Date$
*
* Copyright (C) 2008 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, or a commercial license
* agreement with Jive.
*/
package org.jivesoftware.openfire.mediaproxy;
import org.dom4j.Attribute;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jivesoftware.openfire.*;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.container.BasicModule;
import org.jivesoftware.openfire.disco.*;
import org.jivesoftware.openfire.forms.spi.XDataFormImpl;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import org.xmpp.packet.PacketError;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.*;
/**
* A proxy service for UDP traffic such as RTP. It provides Jingle transport candidates
* to be used for media transmission. The media proxy is especially useful for users
* behind NAT devices or firewalls that prevent peer to peer communication..
*
* @author Thiago Camargo
*/
public class MediaProxyService extends BasicModule
implements ServerItemsProvider, RoutableChannelHandler, DiscoInfoProvider, DiscoItemsProvider {
private String serviceName;
private RoutingTable routingTable;
private PacketRouter router;
private Echo echo = null;
private int echoPort = 10020;
private SessionManager sessionManager = null;
private MediaProxy mediaProxy = null;
private boolean enabled = true;
public static final String NAMESPACE = "http://www.jivesoftware.com/protocol/rtpbridge";
/**
* Constructs a new MediaProxyService.
*/
public MediaProxyService() {
super("Media Proxy Service");
}
public void initialize(XMPPServer server) {
super.initialize(server);
sessionManager = server.getSessionManager();
// In some cases, the domain name of the server may not be the actual address of the machine
// (ie, when using DNS SRV records). In that case, the "mediaproxy.externalip" property should be
// set to the IP address of the actual server where the media proxy is listening.
String ipAddress = JiveGlobals.getProperty("mediaproxy.externalip", server.getServerInfo().getXMPPDomain());
mediaProxy = new MediaProxy(ipAddress);
String defaultName = "rtpbridge";
serviceName = JiveGlobals.getProperty("mediaproxy.serviceName", defaultName);
serviceName = serviceName.equals("") ? defaultName : serviceName;
echoPort = JiveGlobals.getIntProperty("mediaproxy.echoPort", echoPort);
routingTable = server.getRoutingTable();
router = server.getPacketRouter();
initMediaProxy();
}
public void start() {
if (isEnabled()) {
try {
echo = new Echo(echoPort);
Thread t = new Thread(echo);
t.start();
} catch (UnknownHostException e) {
// Ignore
} catch (SocketException e) {
// Ignore
}
routingTable.addComponentRoute(getAddress(), this);
XMPPServer.getInstance().getIQDiscoItemsHandler().addServerItemsProvider(this);
} else {
if (echo != null) echo.cancel();
XMPPServer.getInstance().getIQDiscoItemsHandler().removeComponentItem(getAddress().toString());
}
}
public void stop() {
super.stop();
mediaProxy.stopProxy();
XMPPServer.getInstance().getIQDiscoItemsHandler().removeComponentItem(getAddress().toString());
routingTable.removeComponentRoute(getAddress());
if (echo != null) echo.cancel();
}
// Component Interface
public String getName() {
// Get the name from the plugin.xml file.
return serviceName;
}
public Iterator<DiscoItem> getItems(String name, String node, JID senderJID) {
// A proxy server has no items
return new ArrayList<DiscoItem>().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)) {
reply = XMPPServer.getInstance().getIQDiscoInfoHandler().handleIQ(iq);
router.route(reply);
return;
} else if ("http://jabber.org/protocol/disco#items".equals(namespace)) {
// a component
reply = XMPPServer.getInstance().getIQDiscoItemsHandler().handleIQ(iq);
router.route(reply);
return;
} else if (NAMESPACE.equals(namespace) && enabled) {
Element candidateElement = childElementCopy.element("candidate");
String sid = childElementCopy.attribute("sid").getValue() + "-" + iq.getFrom();
if (candidateElement != null) {
childElementCopy.remove(candidateElement);
Element candidate = childElementCopy.addElement("candidate ");
ProxyCandidate proxyCandidate = mediaProxy.addRelayAgent(sid, iq.getFrom().toString());
Log.debug("MediaProxyService: "+sid);
proxyCandidate.start();
candidate.addAttribute("name", "voicechannel");
candidate.addAttribute("ip", mediaProxy.getPublicIP());
candidate.addAttribute("porta", String.valueOf(proxyCandidate.getLocalPortA()));
candidate.addAttribute("portb", String.valueOf(proxyCandidate.getLocalPortB()));
candidate.addAttribute("pass", proxyCandidate.getPass());
} else {
candidateElement = childElementCopy.element("relay");
if (candidateElement != null) {
MediaProxySession session = mediaProxy.getSession(sid);
Log.debug("MediaProxyService: "+sid);
if (session != null) {
Attribute pass = candidateElement.attribute("pass");
if (pass != null && pass.getValue().trim().equals(session.getPass().trim())) {
Attribute portA = candidateElement.attribute("porta");
Attribute portB = candidateElement.attribute("portb");
Attribute hostA = candidateElement.attribute("hosta");
Attribute hostB = candidateElement.attribute("hostb");
try {
if (hostA != null && portA != null) {
for (int i = 0; i < 2; i++) {
session.sendFromPortA(hostB.getValue(), Integer.parseInt(portB.getValue()));
}
}
}
catch (Exception e) {
Log.error(e);
}
} else {
reply.setError(PacketError.Condition.forbidden);
}
}
childElementCopy.remove(candidateElement);
} else {
candidateElement = childElementCopy.element("publicip");
if (candidateElement != null) {
childElementCopy.remove(candidateElement);
Element publicIp = childElementCopy.addElement("publicip");
try {
String ip = sessionManager.getSession(iq.getFrom()).getHostAddress();
if (ip != null) {
publicIp.addAttribute("ip", ip);
}
} catch (UnknownHostException e) {
Log.error(e);
}
} else {
childElementCopy.remove(candidateElement);
reply.setError(PacketError.Condition.forbidden);
}
}
}
} else {
// Answer an error since the server can't handle the requested namespace
reply.setError(PacketError.Condition.service_unavailable);
}
try {
if (Log.isDebugEnabled()) {
Log.debug("MediaProxyService: RETURNED:" + reply.toXML());
}
router.route(reply);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -