Commit 59095821 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

External components are now using MINA. JM-1269

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@9912 b35dd754-fafc-0310-a699-88a17e54d16e
parent cde5f965
...@@ -322,9 +322,9 @@ public class SessionManager extends BasicModule implements ClusterEventListener ...@@ -322,9 +322,9 @@ public class SessionManager extends BasicModule implements ClusterEventListener
return session; return session;
} }
public LocalComponentSession createComponentSession(JID address, Connection conn) throws UnauthorizedException { public LocalComponentSession createComponentSession(JID address, Connection conn) {
if (serverName == null) { if (serverName == null) {
throw new UnauthorizedException("Server not initialized"); throw new IllegalStateException("Server not initialized");
} }
StreamID id = nextStreamID(); StreamID id = nextStreamID();
LocalComponentSession session = new LocalComponentSession(serverName, conn, id); LocalComponentSession session = new LocalComponentSession(serverName, conn, id);
......
/** /**
* $RCSfile: ComponentSocketReader.java,v $ * $Revision: $
* $Revision: 3174 $ * $Date: $
* $Date: 2005-12-08 17:41:00 -0300 (Thu, 08 Dec 2005) $
* *
* Copyright (C) 2007 Jive Software. All rights reserved. * Copyright (C) 2008 Jive Software. All rights reserved.
* *
* This software is published under the terms of the GNU Public License (GPL), * This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution. * a copy of which is included in this distribution.
...@@ -12,44 +11,51 @@ ...@@ -12,44 +11,51 @@
package org.jivesoftware.openfire.net; package org.jivesoftware.openfire.net;
import org.dom4j.Element; import org.dom4j.Element;
import org.jivesoftware.openfire.Connection;
import org.jivesoftware.openfire.PacketRouter; import org.jivesoftware.openfire.PacketRouter;
import org.jivesoftware.openfire.RoutingTable;
import org.jivesoftware.openfire.auth.UnauthorizedException; import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.component.InternalComponentManager; import org.jivesoftware.openfire.component.InternalComponentManager;
import org.jivesoftware.openfire.session.ComponentSession; import org.jivesoftware.openfire.session.ComponentSession;
import org.jivesoftware.openfire.session.LocalComponentSession; import org.jivesoftware.openfire.session.LocalComponentSession;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
import org.xmpp.component.ComponentException; import org.xmpp.component.ComponentException;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Message;
import org.xmpp.packet.PacketError; import org.xmpp.packet.PacketError;
import org.xmpp.packet.Presence;
import java.io.IOException;
import java.net.Socket;
/** /**
* A SocketReader specialized for component connections. This reader will be used when the open * Handler of XML stanzas sent by external components connected directly to the server. Received packet will
* stream contains a jabber:component:accept namespace. * have their FROM attribute overriden to avoid spoofing.<p>
*
* This is an implementation of the XEP-114. In the future we will add support for XEP-225 now that
* we are using MINA things should be easier. Since we are now using MINA incoming traffic is handled
* by a set of worker threads.
* *
* @author Gaston Dombiak * @author Gaston Dombiak
*/ */
public class ComponentSocketReader extends SocketReader { public class ComponentStanzaHandler extends StanzaHandler {
public ComponentSocketReader(PacketRouter router, RoutingTable routingTable, String serverName, public ComponentStanzaHandler(PacketRouter router, String serverName, Connection connection) {
Socket socket, SocketConnection connection, boolean useBlockingMode) { super(router, serverName, connection);
super(router, routingTable, serverName, socket, connection, useBlockingMode);
} }
/** boolean processUnknowPacket(Element doc) throws UnauthorizedException {
* Only <tt>bind<tt> packets will be processed by this class to bind more domains String tag = doc.getName();
* to existing external components. Any other type of packet is unknown and thus if ("handshake".equals(tag)) {
* rejected generating the connection to be closed. // External component is trying to authenticate
* if (!((LocalComponentSession) session).authenticate(doc.getStringValue())) {
* @param doc the unknown DOM element that was received session.close();
* @return false if packet is unknown otherwise true. }
*/ return true;
protected boolean processUnknowPacket(Element doc) { } else if ("error".equals(tag) && "stream".equals(doc.getNamespacePrefix())) {
// Handle subsequent bind packets session.close();
if ("bind".equals(doc.getName())) { return true;
} else if ("bind".equals(tag)) {
// Handle subsequent bind packets
LocalComponentSession componentSession = (LocalComponentSession) session; LocalComponentSession componentSession = (LocalComponentSession) session;
// Get the external component of this session // Get the external component of this session
ComponentSession.ExternalComponent component = componentSession.getExternalComponent(); ComponentSession.ExternalComponent component = componentSession.getExternalComponent();
...@@ -107,29 +113,76 @@ public class ComponentSocketReader extends SocketReader { ...@@ -107,29 +113,76 @@ public class ComponentSocketReader extends SocketReader {
} }
return true; return true;
} }
// This is an unknown packet so return false (and close the connection)
return false; return false;
} }
boolean createSession(String namespace) throws UnauthorizedException, XmlPullParserException, protected void processIQ(IQ packet) throws UnauthorizedException {
IOException { if (session.getStatus() != Session.STATUS_AUTHENTICATED) {
if ("jabber:component:accept".equals(namespace)) { // Session is not authenticated so return error
// The connected client is a component so create a ComponentSession IQ reply = new IQ();
session = LocalComponentSession.createSession(serverName, reader, connection); reply.setChildElement(packet.getChildElement().createCopy());
return true; reply.setID(packet.getID());
reply.setTo(packet.getFrom());
reply.setFrom(packet.getTo());
reply.setError(PacketError.Condition.not_authorized);
session.process(reply);
return;
} }
return false; super.processIQ(packet);
}
protected void processPresence(Presence packet) throws UnauthorizedException {
if (session.getStatus() != Session.STATUS_AUTHENTICATED) {
// Session is not authenticated so return error
Presence reply = new Presence();
reply.setID(packet.getID());
reply.setTo(packet.getFrom());
reply.setFrom(packet.getTo());
reply.setError(PacketError.Condition.not_authorized);
session.process(reply);
return;
}
super.processPresence(packet);
}
protected void processMessage(Message packet) throws UnauthorizedException {
if (session.getStatus() != Session.STATUS_AUTHENTICATED) {
// Session is not authenticated so return error
Message reply = new Message();
reply.setID(packet.getID());
reply.setTo(packet.getFrom());
reply.setFrom(packet.getTo());
reply.setError(PacketError.Condition.not_authorized);
session.process(reply);
return;
}
super.processMessage(packet);
}
void startTLS() throws Exception {
// TODO Finish implementation. We need to get the name of the CM if we want to validate certificates of the CM that requested TLS
connection.startTLS(false, "IMPLEMENT_ME", Connection.ClientAuth.disabled);
} }
String getNamespace() { String getNamespace() {
return "jabber:component:accept"; return "jabber:component:accept";
} }
String getName() { boolean validateHost() {
return "Component SR - " + hashCode(); return false;
} }
boolean validateHost() { boolean validateJIDs() {
return false;
}
boolean createSession(String namespace, String serverName, XmlPullParser xpp, Connection connection)
throws XmlPullParserException {
if (getNamespace().equals(namespace)) {
// The connected client is a connection manager so create a ConnectionMultiplexerSession
session = LocalComponentSession.createSession(serverName, xpp, connection);
return true;
}
return false; return false;
} }
} }
...@@ -22,12 +22,7 @@ import org.jivesoftware.util.Log; ...@@ -22,12 +22,7 @@ import org.jivesoftware.util.Log;
import org.jivesoftware.util.StringUtils; import org.jivesoftware.util.StringUtils;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
import org.xmpp.packet.IQ; import org.xmpp.packet.*;
import org.xmpp.packet.Message;
import org.xmpp.packet.PacketError;
import org.xmpp.packet.Presence;
import org.xmpp.packet.Roster;
import org.xmpp.packet.StreamError;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
...@@ -69,7 +64,7 @@ public abstract class StanzaHandler { ...@@ -69,7 +64,7 @@ public abstract class StanzaHandler {
/** /**
* Server name for which we are attending clients. * Server name for which we are attending clients.
*/ */
private String serverName; protected String serverName;
/** /**
* Router used to route incoming packets to the correct channels. * Router used to route incoming packets to the correct channels.
......
/**
* $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.
*/
package org.jivesoftware.openfire.nio;
import org.apache.mina.common.IoSession;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.net.ComponentStanzaHandler;
import org.jivesoftware.openfire.net.StanzaHandler;
import org.jivesoftware.util.JiveGlobals;
/**
* ConnectionHandler that knows which subclass of {@link StanzaHandler} should
* be created and how to build and configure a {@link NIOConnection}.
*
* @author Gaston Dombiak
*/
public class ComponentConnectionHandler extends ConnectionHandler {
public ComponentConnectionHandler(String serverName) {
super(serverName);
}
NIOConnection createNIOConnection(IoSession session) {
return new NIOConnection(session, XMPPServer.getInstance().getPacketDeliverer());
}
StanzaHandler createStanzaHandler(NIOConnection connection) {
return new ComponentStanzaHandler(XMPPServer.getInstance().getPacketRouter(), serverName, connection);
}
int getMaxIdleTime() {
return JiveGlobals.getIntProperty("xmpp.component.idle", 6 * 60 * 1000) / 1000;
}
}
...@@ -10,28 +10,23 @@ ...@@ -10,28 +10,23 @@
*/ */
package org.jivesoftware.openfire.session; package org.jivesoftware.openfire.session;
import org.dom4j.Element;
import org.dom4j.io.XMPPPacketReader;
import org.jivesoftware.openfire.Connection; import org.jivesoftware.openfire.Connection;
import org.jivesoftware.openfire.PacketException; import org.jivesoftware.openfire.PacketException;
import org.jivesoftware.openfire.SessionManager; import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.StreamID; import org.jivesoftware.openfire.StreamID;
import org.jivesoftware.openfire.auth.AuthFactory; import org.jivesoftware.openfire.auth.AuthFactory;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.component.ExternalComponentManager; import org.jivesoftware.openfire.component.ExternalComponentManager;
import org.jivesoftware.openfire.component.InternalComponentManager; import org.jivesoftware.openfire.component.InternalComponentManager;
import org.jivesoftware.openfire.net.SocketConnection;
import org.jivesoftware.util.LocaleUtils; import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
import org.xmpp.component.ComponentException;
import org.xmpp.component.ComponentManager; import org.xmpp.component.ComponentManager;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
import org.xmpp.packet.StreamError; import org.xmpp.packet.StreamError;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
...@@ -44,6 +39,13 @@ import java.util.List; ...@@ -44,6 +39,13 @@ import java.util.List;
public class LocalComponentSession extends LocalSession implements ComponentSession { public class LocalComponentSession extends LocalSession implements ComponentSession {
private LocalExternalComponent component; private LocalExternalComponent component;
/**
* When using XEP-114 (the old spec) components will include in the TO attribute
* of the intial stream header the domain they would like to have. The requested
* domain is used only after the authentication was successful so we need keep track
* of this information until the handshake is done.
*/
private String defaultSubdomain;
/** /**
* Returns a newly created session between the server and a component. The session will be * Returns a newly created session between the server and a component. The session will be
...@@ -53,24 +55,19 @@ public class LocalComponentSession extends LocalSession implements ComponentSess ...@@ -53,24 +55,19 @@ public class LocalComponentSession extends LocalSession implements ComponentSess
* the JEP-114 where the domain to bind is sent in the TO attribute of the stream header. * the JEP-114 where the domain to bind is sent in the TO attribute of the stream header.
* *
* @param serverName the name of the server where the session is connecting to. * @param serverName the name of the server where the session is connecting to.
* @param reader the reader that is reading the provided XML through the connection. * @param xpp the parser that is reading the provided XML through the connection.
* @param connection the connection with the component. * @param connection the connection with the component.
* @return a newly created session between the server and a component. * @return a newly created session between the server and a component.
* @throws UnauthorizedException if the connection required security but was not secured.
* @throws XmlPullParserException if there was an XML error while creating the session. * @throws XmlPullParserException if there was an XML error while creating the session.
* @throws IOException if an IO error occured while creating the session.
*/ */
public static LocalComponentSession createSession(String serverName, XMPPPacketReader reader, public static LocalComponentSession createSession(String serverName, XmlPullParser xpp, Connection connection)
SocketConnection connection) throws UnauthorizedException, IOException, throws XmlPullParserException {
XmlPullParserException
{
XmlPullParser xpp = reader.getXPPParser();
String domain = xpp.getAttributeValue("", "to"); String domain = xpp.getAttributeValue("", "to");
Boolean allowMultiple = reader.getXPPParser().getAttributeValue("", "allowMultiple") != null; Boolean allowMultiple = xpp.getAttributeValue("", "allowMultiple") != null;
Log.debug("LocalComponentSession: [ExComp] Starting registration of new external component for domain: " + domain); Log.debug("LocalComponentSession: [ExComp] Starting registration of new external component for domain: " +
domain);
Writer writer = connection.getWriter();
// Default answer header in case of an error // Default answer header in case of an error
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("<?xml version='1.0' encoding='"); sb.append("<?xml version='1.0' encoding='");
...@@ -88,8 +85,7 @@ public class LocalComponentSession extends LocalSession implements ComponentSess ...@@ -88,8 +85,7 @@ public class LocalComponentSession extends LocalSession implements ComponentSess
// Include the bad-format in the response // Include the bad-format in the response
StreamError error = new StreamError(StreamError.Condition.bad_format); StreamError error = new StreamError(StreamError.Condition.bad_format);
sb.append(error.toXML()); sb.append(error.toXML());
writer.write(sb.toString()); connection.deliverRawText(sb.toString());
writer.flush();
// Close the underlying connection // Close the underlying connection
connection.close(); connection.close();
return null; return null;
...@@ -105,11 +101,11 @@ public class LocalComponentSession extends LocalSession implements ComponentSess ...@@ -105,11 +101,11 @@ public class LocalComponentSession extends LocalSession implements ComponentSess
JID componentJID = new JID(domain); JID componentJID = new JID(domain);
// Check that an external component for the specified subdomain may connect to this server // Check that an external component for the specified subdomain may connect to this server
if (!ExternalComponentManager.canAccess(subdomain)) { if (!ExternalComponentManager.canAccess(subdomain)) {
Log.debug("LocalComponentSession: [ExComp] Component is not allowed to connect with subdomain: " + subdomain); Log.debug(
"LocalComponentSession: [ExComp] Component is not allowed to connect with subdomain: " + subdomain);
StreamError error = new StreamError(StreamError.Condition.host_unknown); StreamError error = new StreamError(StreamError.Condition.host_unknown);
sb.append(error.toXML()); sb.append(error.toXML());
writer.write(sb.toString()); connection.deliverRawText(sb.toString());
writer.flush();
// Close the underlying connection // Close the underlying connection
connection.close(); connection.close();
return null; return null;
...@@ -121,8 +117,7 @@ public class LocalComponentSession extends LocalSession implements ComponentSess ...@@ -121,8 +117,7 @@ public class LocalComponentSession extends LocalSession implements ComponentSess
// Include the internal-server-error in the response // Include the internal-server-error in the response
StreamError error = new StreamError(StreamError.Condition.internal_server_error); StreamError error = new StreamError(StreamError.Condition.internal_server_error);
sb.append(error.toXML()); sb.append(error.toXML());
writer.write(sb.toString()); connection.deliverRawText(sb.toString());
writer.flush();
// Close the underlying connection // Close the underlying connection
connection.close(); connection.close();
return null; return null;
...@@ -134,8 +129,7 @@ public class LocalComponentSession extends LocalSession implements ComponentSess ...@@ -134,8 +129,7 @@ public class LocalComponentSession extends LocalSession implements ComponentSess
// Include the conflict error in the response // Include the conflict error in the response
StreamError error = new StreamError(StreamError.Condition.conflict); StreamError error = new StreamError(StreamError.Condition.conflict);
sb.append(error.toXML()); sb.append(error.toXML());
writer.write(sb.toString()); connection.deliverRawText(sb.toString());
writer.flush();
// Close the underlying connection // Close the underlying connection
connection.close(); connection.close();
return null; return null;
...@@ -161,36 +155,13 @@ public class LocalComponentSession extends LocalSession implements ComponentSess ...@@ -161,36 +155,13 @@ public class LocalComponentSession extends LocalSession implements ComponentSess
sb.append("\" id=\""); sb.append("\" id=\"");
sb.append(session.getStreamID().toString()); sb.append(session.getStreamID().toString());
sb.append("\">"); sb.append("\">");
writer.write(sb.toString()); connection.deliverRawText(sb.toString());
writer.flush();
// Return session although session has not been authentication yet. Until
// Perform authentication. Wait for the handshake (with the secret key) // it is authenticated traffic will be rejected except for authentication
Element doc = reader.parseDocument().getRootElement(); // requests
String digest = "handshake".equals(doc.getName()) ? doc.getStringValue() : ""; session.defaultSubdomain = subdomain;
String anticipatedDigest = AuthFactory.createDigest(session.getStreamID().getID(), secretKey); return session;
// Check that the provided handshake (secret key + sessionID) is correct
if (!anticipatedDigest.equalsIgnoreCase(digest)) {
Log.debug("LocalComponentSession: [ExComp] Incorrect handshake for component with domain: " + domain);
// The credentials supplied by the initiator are not valid (answer an error
// and close the connection)
writer.write(new StreamError(StreamError.Condition.not_authorized).toXML());
writer.flush();
// Close the underlying connection
connection.close();
return null;
}
else {
// Component has authenticated fine
session.setStatus(STATUS_AUTHENTICATED);
// Send empty handshake element to acknowledge success
writer.write("<handshake></handshake>");
writer.flush();
// Bind the domain to this component
ExternalComponent component = session.getExternalComponent();
InternalComponentManager.getInstance().addComponent(subdomain, component);
Log.debug("LocalComponentSession: [ExComp] External component was registered SUCCESSFULLY with domain: " + domain);
return session;
}
} }
catch (Exception e) { catch (Exception e) {
Log.error("An error occured while creating a ComponentSession", e); Log.error("An error occured while creating a ComponentSession", e);
...@@ -221,6 +192,56 @@ public class LocalComponentSession extends LocalSession implements ComponentSess ...@@ -221,6 +192,56 @@ public class LocalComponentSession extends LocalSession implements ComponentSess
return component; return component;
} }
/**
* Authenticate the external component using a digest method. The digest includes the
* stream ID and the secret key of the main domain of the external component. A component
* needs to authenticate just once but it may bind several domains.
*
* @param digest the digest sent in the handshake.
* @return true if the authentication was successful.
*/
public boolean authenticate(String digest) {
// Perform authentication. Wait for the handshake (with the secret key)
String secretKey = ExternalComponentManager.getSecretForComponent(defaultSubdomain);
String anticipatedDigest = AuthFactory.createDigest(getStreamID().getID(), secretKey);
// Check that the provided handshake (secret key + sessionID) is correct
if (!anticipatedDigest.equalsIgnoreCase(digest)) {
Log.debug("LocalComponentSession: [ExComp] Incorrect handshake for component with domain: " +
defaultSubdomain);
// The credentials supplied by the initiator are not valid (answer an error
// and close the connection)
conn.deliverRawText(new StreamError(StreamError.Condition.not_authorized).toXML());
// Close the underlying connection
conn.close();
return false;
}
else {
// Component has authenticated fine
setStatus(STATUS_AUTHENTICATED);
// Send empty handshake element to acknowledge success
conn.deliverRawText("<handshake></handshake>");
// Bind the domain to this component
ExternalComponent component = getExternalComponent();
try {
InternalComponentManager.getInstance().addComponent(defaultSubdomain, component);
Log.debug(
"LocalComponentSession: [ExComp] External component was registered SUCCESSFULLY with domain: " +
defaultSubdomain);
return true;
}
catch (ComponentException e) {
Log.debug("LocalComponentSession: [ExComp] Another component is already using domain: " +
defaultSubdomain);
// The credentials supplied by the initiator are not valid (answer an error
// and close the connection)
conn.deliverRawText(new StreamError(StreamError.Condition.conflict).toXML());
// Close the underlying connection
conn.close();
return false;
}
}
}
/** /**
* The ExternalComponent acts as a proxy of the remote connected component. Any Packet that is * The ExternalComponent acts as a proxy of the remote connected component. Any Packet that is
* sent to this component will be delivered to the real component on the other side of the * sent to this component will be delivered to the real component on the other side of the
......
...@@ -28,6 +28,7 @@ import org.jivesoftware.openfire.container.PluginManagerListener; ...@@ -28,6 +28,7 @@ import org.jivesoftware.openfire.container.PluginManagerListener;
import org.jivesoftware.openfire.http.HttpBindManager; import org.jivesoftware.openfire.http.HttpBindManager;
import org.jivesoftware.openfire.net.*; import org.jivesoftware.openfire.net.*;
import org.jivesoftware.openfire.nio.ClientConnectionHandler; import org.jivesoftware.openfire.nio.ClientConnectionHandler;
import org.jivesoftware.openfire.nio.ComponentConnectionHandler;
import org.jivesoftware.openfire.nio.MultiplexerConnectionHandler; import org.jivesoftware.openfire.nio.MultiplexerConnectionHandler;
import org.jivesoftware.openfire.nio.XMPPCodecFactory; import org.jivesoftware.openfire.nio.XMPPCodecFactory;
import org.jivesoftware.util.*; import org.jivesoftware.util.*;
...@@ -53,7 +54,7 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana ...@@ -53,7 +54,7 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
private SocketAcceptor socketAcceptor; private SocketAcceptor socketAcceptor;
private SocketAcceptor sslSocketAcceptor; private SocketAcceptor sslSocketAcceptor;
private SocketAcceptThread componentSocketThread; private SocketAcceptor componentAcceptor;
private SocketAcceptThread serverSocketThread; private SocketAcceptThread serverSocketThread;
private SocketAcceptor multiplexerSocketAcceptor; private SocketAcceptor multiplexerSocketAcceptor;
private ArrayList<ServerPort> ports; private ArrayList<ServerPort> ports;
...@@ -83,7 +84,7 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana ...@@ -83,7 +84,7 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
// Create the port listener for Connections Multiplexers // Create the port listener for Connections Multiplexers
createConnectionManagerListener(); createConnectionManagerListener();
// Create the port listener for external components // Create the port listener for external components
createComponentListener(localIPAddress); createComponentListener();
// Create the port listener for clients // Create the port listener for clients
createClientListeners(); createClientListeners();
// Create the port listener for secured clients // Create the port listener for secured clients
...@@ -243,23 +244,22 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana ...@@ -243,23 +244,22 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
} }
} }
private void createComponentListener(String localIPAddress) { private void createComponentListener() {
// Start components socket unless it's been disabled. // Start components socket unless it's been disabled.
if (isComponentListenerEnabled()) { if (isComponentListenerEnabled()) {
int port = getComponentListenerPort(); // Create SocketAcceptor with correct number of processors
try { componentAcceptor = buildSocketAcceptor();
componentSocketThread = new SocketAcceptThread(this, new ServerPort(port, // Customize Executor that will be used by processors to process incoming stanzas
serverName, localIPAddress, false, null, ServerPort.Type.component)); ExecutorThreadModel threadModel = ExecutorThreadModel.getInstance("component");
ports.add(componentSocketThread.getServerPort()); int eventThreads = JiveGlobals.getIntProperty("xmpp.component.processing.threads", 16);
componentSocketThread.setDaemon(true); ThreadPoolExecutor eventExecutor = (ThreadPoolExecutor)threadModel.getExecutor();
componentSocketThread.setPriority(Thread.MAX_PRIORITY); eventExecutor.setCorePoolSize(eventThreads + 1);
eventExecutor.setMaximumPoolSize(eventThreads + 1);
eventExecutor.setKeepAliveTime(60, TimeUnit.SECONDS);
} componentAcceptor.getDefaultConfig().setThreadModel(threadModel);
catch (Exception e) { // Add the XMPP codec filter
System.err.println("Error starting component listener on port " + port + ": " + componentAcceptor.getFilterChain().addFirst("xmpp", new ProtocolCodecFilter(new XMPPCodecFactory()));
e.getMessage());
Log.error(LocaleUtils.getLocalizedString("admin.error.socket-setup"), e);
}
} }
} }
...@@ -268,10 +268,22 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana ...@@ -268,10 +268,22 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
if (isComponentListenerEnabled()) { if (isComponentListenerEnabled()) {
int port = getComponentListenerPort(); int port = getComponentListenerPort();
try { try {
componentSocketThread.start(); // Listen on a specific network interface if it has been set.
String interfaceName = JiveGlobals.getXMLProperty("network.interface");
InetAddress bindInterface = null;
if (interfaceName != null) {
if (interfaceName.trim().length() > 0) {
bindInterface = InetAddress.getByName(interfaceName);
}
}
// Start accepting connections
componentAcceptor
.bind(new InetSocketAddress(bindInterface, port), new ComponentConnectionHandler(serverName));
ports.add(new ServerPort(port, serverName, localIPAddress, false, null, ServerPort.Type.component));
List<String> params = new ArrayList<String>(); List<String> params = new ArrayList<String>();
params.add(Integer.toString(componentSocketThread.getPort())); params.add(Integer.toString(port));
Log.info(LocaleUtils.getLocalizedString("startup.component", params)); Log.info(LocaleUtils.getLocalizedString("startup.component", params));
} }
catch (Exception e) { catch (Exception e) {
...@@ -283,10 +295,15 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana ...@@ -283,10 +295,15 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
} }
private void stopComponentListener() { private void stopComponentListener() {
if (componentSocketThread != null) { if (componentAcceptor != null) {
componentSocketThread.shutdown(); componentAcceptor.unbindAll();
ports.remove(componentSocketThread.getServerPort()); for (ServerPort port : ports) {
componentSocketThread = null; if (port.isComponentPort()) {
ports.remove(port);
break;
}
}
componentAcceptor = null;
} }
} }
...@@ -488,12 +505,7 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana ...@@ -488,12 +505,7 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
public SocketReader createSocketReader(Socket sock, boolean isSecure, ServerPort serverPort, public SocketReader createSocketReader(Socket sock, boolean isSecure, ServerPort serverPort,
boolean useBlockingMode) throws IOException { boolean useBlockingMode) throws IOException {
if (serverPort.isComponentPort()) { if (serverPort.isServerPort()) {
SocketConnection conn = new SocketConnection(deliverer, sock, isSecure);
return new ComponentSocketReader(router, routingTable, serverName, sock, conn,
useBlockingMode);
}
else if (serverPort.isServerPort()) {
SocketConnection conn = new SocketConnection(deliverer, sock, isSecure); SocketConnection conn = new SocketConnection(deliverer, sock, isSecure);
return new ServerSocketReader(router, routingTable, serverName, sock, conn, return new ServerSocketReader(router, routingTable, serverName, sock, conn,
useBlockingMode); useBlockingMode);
...@@ -578,7 +590,7 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana ...@@ -578,7 +590,7 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
if (enabled) { if (enabled) {
JiveGlobals.setProperty("xmpp.component.socket.active", "true"); JiveGlobals.setProperty("xmpp.component.socket.active", "true");
// Start the port listener for external components // Start the port listener for external components
createComponentListener(localIPAddress); createComponentListener();
startComponentListener(); startComponentListener();
} }
else { else {
...@@ -692,7 +704,7 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana ...@@ -692,7 +704,7 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
stopComponentListener(); stopComponentListener();
if (isComponentListenerEnabled()) { if (isComponentListenerEnabled()) {
// Start the port listener for external components // Start the port listener for external components
createComponentListener(localIPAddress); createComponentListener();
startComponentListener(); startComponentListener();
} }
} }
......
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