Commit 2ea7e588 authored by Guus der Kinderen's avatar Guus der Kinderen

Merge remote-tracking branch 'upstream/master' into refactor-connectionmanagement

Conflicts:
	src/i18n/openfire_i18n_en.properties
	src/java/org/jivesoftware/openfire/session/LocalOutgoingServerSession.java
parents 1b22ea34 c34759e0
...@@ -259,7 +259,9 @@ servers, some of which are detailed below: ...@@ -259,7 +259,9 @@ servers, some of which are detailed below:
you you
enable SSL connections, the LDAP server port number most likely should be changed to enable SSL connections, the LDAP server port number most likely should be changed to
636.</li> 636.</li>
<li>ldap.startTlsEnabled -- a value of "true" to enable StartTLS connections to your LDAP server. If
you enable StartTLS connections, the LDAP server port number most likely should be changed to
389.</li>
<li>ldap.initialContextFactory -- the name of the class that should be used as an initial <li>ldap.initialContextFactory -- the name of the class that should be used as an initial
context context
factory. if this value is not specified, "com.sun.jndi.ldap.LdapCtxFactory" will be used factory. if this value is not specified, "com.sun.jndi.ldap.LdapCtxFactory" will be used
......
...@@ -1300,6 +1300,8 @@ setup.ldap.server.connection_pool=Use Connection Pool ...@@ -1300,6 +1300,8 @@ setup.ldap.server.connection_pool=Use Connection Pool
setup.ldap.server.connection_pool_help=Connection Pooling. Default is 'Yes' setup.ldap.server.connection_pool_help=Connection Pooling. Default is 'Yes'
setup.ldap.server.ssl=Use SSL setup.ldap.server.ssl=Use SSL
setup.ldap.server.ssl_help=Enable SSL connections to your LDAP server, default port is usually 636 setup.ldap.server.ssl_help=Enable SSL connections to your LDAP server, default port is usually 636
setup.ldap.server.starttls=Verwende StartTLS
setup.ldap.server.starttls_help=Verwende StartTLS Verbindungen zu deinem LDAP server, der standard port ist normalerweise 389
setup.ldap.server.debug=Enable Debug setup.ldap.server.debug=Enable Debug
setup.ldap.server.debug_help=Write trace information about LDAP connections to System.out setup.ldap.server.debug_help=Write trace information about LDAP connections to System.out
setup.ldap.server.referral=Follow Referrals setup.ldap.server.referral=Follow Referrals
......
...@@ -2030,6 +2030,8 @@ setup.ldap.server.connection_pool=Use Connection Pool ...@@ -2030,6 +2030,8 @@ setup.ldap.server.connection_pool=Use Connection Pool
setup.ldap.server.connection_pool_help=Connection Pooling. Default is 'Yes' setup.ldap.server.connection_pool_help=Connection Pooling. Default is 'Yes'
setup.ldap.server.ssl=Use SSL setup.ldap.server.ssl=Use SSL
setup.ldap.server.ssl_help=Enable SSL connections to your LDAP server, default port is usually 636 setup.ldap.server.ssl_help=Enable SSL connections to your LDAP server, default port is usually 636
setup.ldap.server.starttls=Use StartTLS
setup.ldap.server.starttls_help=Enable StartTLS connections to your LDAP server, default port is usually 389
setup.ldap.server.debug=Enable Debug setup.ldap.server.debug=Enable Debug
setup.ldap.server.debug_help=Write trace information about LDAP connections to System.out setup.ldap.server.debug_help=Write trace information about LDAP connections to System.out
setup.ldap.server.referral=Follow Referrals setup.ldap.server.referral=Follow Referrals
......
...@@ -94,7 +94,7 @@ public interface RoutingTable { ...@@ -94,7 +94,7 @@ public interface RoutingTable {
* @param route the address associated to the route. * @param route the address associated to the route.
* @param destination the outgoing server session. * @param destination the outgoing server session.
*/ */
void addServerRoute(JID route, LocalOutgoingServerSession destination); void addServerRoute(JID route, RoutableChannelHandler destination);
/** /**
* Adds a route to the routing table for the specified internal or external component. <p> * Adds a route to the routing table for the specified internal or external component. <p>
......
...@@ -54,7 +54,6 @@ import org.jivesoftware.openfire.event.SessionEventDispatcher; ...@@ -54,7 +54,6 @@ import org.jivesoftware.openfire.event.SessionEventDispatcher;
import org.jivesoftware.openfire.http.HttpConnection; import org.jivesoftware.openfire.http.HttpConnection;
import org.jivesoftware.openfire.http.HttpSession; import org.jivesoftware.openfire.http.HttpSession;
import org.jivesoftware.openfire.multiplex.ConnectionMultiplexerManager; import org.jivesoftware.openfire.multiplex.ConnectionMultiplexerManager;
import org.jivesoftware.openfire.server.OutgoingSessionPromise;
import org.jivesoftware.openfire.session.ClientSession; import org.jivesoftware.openfire.session.ClientSession;
import org.jivesoftware.openfire.session.ClientSessionInfo; import org.jivesoftware.openfire.session.ClientSessionInfo;
import org.jivesoftware.openfire.session.ComponentSession; import org.jivesoftware.openfire.session.ComponentSession;
...@@ -1485,8 +1484,6 @@ public class SessionManager extends BasicModule implements ClusterEventListener/ ...@@ -1485,8 +1484,6 @@ public class SessionManager extends BasicModule implements ClusterEventListener/
@Override @Override
public void stop() { public void stop() {
Log.debug("SessionManager: Stopping server"); Log.debug("SessionManager: Stopping server");
// Stop threads that are sending packets to remote servers
OutgoingSessionPromise.getInstance().shutdown();
if (JiveGlobals.getBooleanProperty("shutdownMessage.enabled")) { if (JiveGlobals.getBooleanProperty("shutdownMessage.enabled")) {
sendServerMessage(null, LocaleUtils.getLocalizedString("admin.shutdown.now")); sendServerMessage(null, LocaleUtils.getLocalizedString("admin.shutdown.now"));
} }
......
...@@ -875,7 +875,7 @@ public abstract class Node { ...@@ -875,7 +875,7 @@ public abstract class Node {
formField.setLabel(LocaleUtils.getLocalizedString("pubsub.form.conf.collection")); formField.setLabel(LocaleUtils.getLocalizedString("pubsub.form.conf.collection"));
} }
if (!parent.isRootCollectionNode()) { if (parent != null && !parent.isRootCollectionNode()) {
formField.addValue(parent.getNodeID()); formField.addValue(parent.getNodeID());
} }
......
...@@ -159,8 +159,6 @@ public class Roster implements Cacheable, Externalizable { ...@@ -159,8 +159,6 @@ public class Roster implements Cacheable, Externalizable {
if (group.isUser(jid)) { if (group.isUser(jid)) {
item.addSharedGroup(group); item.addSharedGroup(group);
itemGroups.add(group); itemGroups.add(group);
item.setNickname(UserNameManager.getUserName(jid));
broadcast(item, true);
} else { } else {
item.addInvisibleSharedGroup(group); item.addInvisibleSharedGroup(group);
} }
......
/**
*
*/
package org.jivesoftware.openfire.server;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import org.jivesoftware.openfire.PacketException;
import org.jivesoftware.openfire.RoutableChannelHandler;
import org.jivesoftware.openfire.RoutingTable;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.session.ConnectionSettings;
import org.jivesoftware.openfire.session.LocalOutgoingServerSession;
import org.jivesoftware.openfire.session.LocalSession;
import org.jivesoftware.openfire.session.ServerSession;
import org.jivesoftware.openfire.spi.RoutingTableImpl;
import org.jivesoftware.util.JiveGlobals;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import org.xmpp.packet.PacketError;
import org.xmpp.packet.Presence;
/**
* @author dwd
*
*/
public class LocalOutgoingServerProxy implements RoutableChannelHandler {
private static final Logger log = LoggerFactory.getLogger(LocalOutgoingServerProxy.class);
private JID domain;
private ServerSession session;
private Queue<Packet> packets;
private static ExecutorService pool = createPool();
private long failureTimestamp = -1;
private boolean isTrying;
private static ExecutorService createPool() {
// Create a pool of threads that will process queued session requests.
int maxThreads = JiveGlobals.getIntProperty(ConnectionSettings.Server.QUEUE_MAX_THREADS, 20);
if (maxThreads < 10) {
// Ensure that the max number of threads in the pool is at least 10
maxThreads = 10;
}
ExecutorService pool = Executors.newFixedThreadPool(maxThreads);
return pool;
}
public LocalOutgoingServerProxy(final JID domain) {
this.domain = domain;
this.session = null;
this.packets = null;
}
public LocalOutgoingServerProxy(final String domain) {
this.domain = new JID(domain);
this.session = null;
this.packets = null;
}
public LocalOutgoingServerProxy(final JID domain, ServerSession session) {
this.domain = domain;
this.session = null;
this.packets = null;
}
public LocalOutgoingServerProxy(final String domain, ServerSession session) {
this.domain = new JID(domain);
this.session = null;
this.packets = null;
}
/* (non-Javadoc)
* @see org.jivesoftware.openfire.ChannelHandler#process(org.xmpp.packet.Packet)
*/
@Override
public synchronized void process(final Packet packet) throws UnauthorizedException,
PacketException {
if (this.session != null) {
this.session.process(packet);
return;
}
if (packets == null) {
packets = new LinkedBlockingQueue<Packet>();
log.info("Queued packet for {}.", domain.toString());
}
packets.add(packet.createCopy());
if (isTrying == false) {
final String fromDomain = packet.getFrom().getDomain().toString();
final String toDomain = packet.getTo().getDomain().toString();
if ((failureTimestamp == -1) || ((System.currentTimeMillis() - failureTimestamp) >= 5000)) {
isTrying = true;
log.debug("Spinning up new session to {}", domain.toString());
pool.execute(new Runnable() {
public void run() {
log.debug("Initiating connection thread for {} -> {} ({})", fromDomain, toDomain, domain.toString());
try {
ServerSession s = LocalOutgoingServerSession.authenticateDomain(fromDomain, toDomain); // Long-running.
if (s != null) {
sessionReady(s);
} else {
sessionFailed();
}
} catch(Exception e) {
log.debug("Session for {} failed with:", domain.toString(), e);
sessionFailed();
}
log.debug("Finished connection thread for {}", domain.toString());
return;
}
});
} else {
sessionFailed();
}
} else {
// Session creation in progress.
packets.add(packet);
}
}
protected synchronized void sessionReady(ServerSession session) {
isTrying = false;
log.debug("Spun up new session to {}", domain.toString());
int sent = 0;
this.session = session;
while (!this.packets.isEmpty()) {
Packet packet = this.packets.remove();
this.session.process(packet);
sent = sent + 1;
}
this.packets = null;
log.debug("Done, sent {} pending stanzas.", sent);
}
protected synchronized void sessionFailed() {
isTrying = false;
log.debug("Failed to spin up new session to {}", domain.toString());
while (!this.packets.isEmpty()) {
Packet packet = this.packets.remove();
LocalSession.returnErrorToSender(packet);
}
this.packets = null;
}
/* (non-Javadoc)
* @see org.jivesoftware.openfire.RoutableChannelHandler#getAddress()
*/
@Override
public JID getAddress() {
return this.domain;
}
public ServerSession getSession() {
return this.session;
}
}
...@@ -64,7 +64,6 @@ import org.xmpp.packet.JID; ...@@ -64,7 +64,6 @@ import org.xmpp.packet.JID;
import org.xmpp.packet.Message; import org.xmpp.packet.Message;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
import org.xmpp.packet.PacketError; import org.xmpp.packet.PacketError;
import org.xmpp.packet.PacketExtension;
import org.xmpp.packet.Presence; import org.xmpp.packet.Presence;
import com.jcraft.jzlib.JZlib; import com.jcraft.jzlib.JZlib;
...@@ -121,18 +120,15 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou ...@@ -121,18 +120,15 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou
* @param hostname the hostname of the remote server. * @param hostname the hostname of the remote server.
* @return True if the domain was authenticated by the remote server. * @return True if the domain was authenticated by the remote server.
*/ */
public static boolean authenticateDomain(final String domain, final String hostname) { public static OutgoingServerSession authenticateDomain(String domain, String hostname) {
Log.debug( "[domain {} hostname {}]: Start authentication.", domain, hostname );
if (hostname == null || hostname.length() == 0 || hostname.trim().indexOf(' ') > -1) { if (hostname == null || hostname.length() == 0 || hostname.trim().indexOf(' ') > -1) {
// Do nothing if the target hostname is empty, null or contains whitespaces // Do nothing if the target hostname is empty, null or contains whitespaces
Log.debug( "[domain {} hostname {}]: Authentication failed - null or whitespace in hostname.", domain, hostname ); return null;
return false;
} }
try { try {
// Check if the remote hostname is in the blacklist // Check if the remote hostname is in the blacklist
if (!RemoteServerManager.canAccess(hostname)) { if (!RemoteServerManager.canAccess(hostname)) {
Log.debug( "[domain {} hostname {}]: Authentication failed - hostname in blacklist.", domain, hostname ); return null;
return false;
} }
OutgoingServerSession session; OutgoingServerSession session;
...@@ -142,14 +138,11 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou ...@@ -142,14 +138,11 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou
SessionManager sessionManager = SessionManager.getInstance(); SessionManager sessionManager = SessionManager.getInstance();
if (sessionManager == null) { if (sessionManager == null) {
// Server is shutting down while we are trying to create a new s2s connection // Server is shutting down while we are trying to create a new s2s connection
Log.debug( "[domain {} hostname {}]: Authentication failed - no session manager available. Server might be shutting down.", domain, hostname ); return null;
return false;
} }
Log.debug( "[domain {} hostname {}]: Locating pre-exisiting outgoing session...", domain, hostname );
session = sessionManager.getOutgoingServerSession(hostname); session = sessionManager.getOutgoingServerSession(hostname);
if (session == null) { if (session == null) {
// Try locating if the remote server has previously authenticated with this server // Try locating if the remote server has previously authenticated with this server
Log.debug( "[domain {} hostname {}]: Outgoing session found. Locating related incoming session...", domain, hostname );
for (IncomingServerSession incomingSession : sessionManager.getIncomingServerSessions(hostname)) { for (IncomingServerSession incomingSession : sessionManager.getIncomingServerSessions(hostname)) {
for (String otherHostname : incomingSession.getValidatedDomains()) { for (String otherHostname : incomingSession.getValidatedDomains()) {
session = sessionManager.getOutgoingServerSession(otherHostname); session = sessionManager.getOutgoingServerSession(otherHostname);
...@@ -157,7 +150,6 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou ...@@ -157,7 +150,6 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou
if (session.isUsingServerDialback()) { if (session.isUsingServerDialback()) {
// A session to the same remote server but with different hostname // A session to the same remote server but with different hostname
// was found. Use this session. // was found. Use this session.
Log.debug( "[domain {} hostname {}]: Incoming session found. Reuse this connection.", domain, hostname );
break; break;
} else { } else {
session = null; session = null;
...@@ -167,7 +159,6 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou ...@@ -167,7 +159,6 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou
} }
} }
if (session == null) { if (session == null) {
Log.debug( "[domain {} hostname {}]: No re-usable existing connecting. Create new session.", domain, hostname );
int port = RemoteServerManager.getPortForServer(hostname); int port = RemoteServerManager.getPortForServer(hostname);
session = createOutgoingSession(domain, hostname, port); session = createOutgoingSession(domain, hostname, port);
if (session != null) { if (session != null) {
...@@ -177,26 +168,25 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou ...@@ -177,26 +168,25 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou
session.addHostname(hostname); session.addHostname(hostname);
// Notify the SessionManager that a new session has been created // Notify the SessionManager that a new session has been created
sessionManager.outgoingServerSessionCreated((LocalOutgoingServerSession) session); sessionManager.outgoingServerSessionCreated((LocalOutgoingServerSession) session);
return true; return session;
} else { } else {
Log.warn("Fail to connect to {} for {}", hostname, domain); Log.warn("Fail to connect to {} for {}", hostname, domain);
return false; return null;
} }
} }
// A session already exists. The session was established using server dialback so // A session already exists. The session was established using server dialback so
// it is possible to do piggybacking to authenticate more domains // it is possible to do piggybacking to authenticate more domains
if (session.getAuthenticatedDomains().contains(domain) && session.getHostnames().contains(hostname)) { if (session.getAuthenticatedDomains().contains(domain) && session.getHostnames().contains(hostname)) {
Log.debug( "[domain {} hostname {}]: Do nothing since the domain has already been authenticated.", domain, hostname ); // Do nothing since the domain has already been authenticated
return true; return session;
} }
// A session already exists so authenticate the domain using that session // A session already exists so authenticate the domain using that session
Log.debug( "[domain {} hostname {}]: An session already exists, so authenticate the domain using that session.", domain, hostname ); if (session.authenticateSubdomain(domain, hostname)) return session;
return session.authenticateSubdomain(domain, hostname);
} }
catch (Exception e) { catch (Exception e) {
Log.error("Error authenticating domain with remote server: " + hostname, e); Log.error("Error authenticating domain with remote server: " + hostname, e);
} }
return false; return null;
} }
/** /**
...@@ -604,7 +594,7 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou ...@@ -604,7 +594,7 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou
if (!getAuthenticatedDomains().contains(senderDomain) && if (!getAuthenticatedDomains().contains(senderDomain) &&
!authenticateSubdomain(senderDomain, packet.getTo().getDomain())) { !authenticateSubdomain(senderDomain, packet.getTo().getDomain())) {
// Return error since sender domain was not validated by remote server // Return error since sender domain was not validated by remote server
returnErrorToSender(packet); LocalSession.returnErrorToSender(packet);
return false; return false;
} }
} }
...@@ -638,59 +628,6 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou ...@@ -638,59 +628,6 @@ public class LocalOutgoingServerSession extends LocalServerSession implements Ou
return false; return false;
} }
private void returnErrorToSender(Packet packet) {
RoutingTable routingTable = XMPPServer.getInstance().getRoutingTable();
if (packet.getError() != null) {
Log.debug("Possible double bounce: " + packet.toXML());
}
try {
if (packet instanceof IQ) {
if (((IQ) packet).isResponse()) {
Log.debug("XMPP specs forbid us to respond with an IQ error to: " + packet.toXML());
return;
}
IQ reply = new IQ();
reply.setID(packet.getID());
reply.setTo(packet.getFrom());
reply.setFrom(packet.getTo());
reply.setChildElement(((IQ) packet).getChildElement().createCopy());
reply.setType(IQ.Type.error);
reply.setError(PacketError.Condition.remote_server_not_found);
routingTable.routePacket(reply.getTo(), reply, true);
}
else if (packet instanceof Presence) {
if (((Presence)packet).getType() == Presence.Type.error) {
Log.debug("Double-bounce of presence: " + packet.toXML());
return;
}
Presence reply = new Presence();
reply.setID(packet.getID());
reply.setTo(packet.getFrom());
reply.setFrom(packet.getTo());
reply.setType(Presence.Type.error);
reply.setError(PacketError.Condition.remote_server_not_found);
routingTable.routePacket(reply.getTo(), reply, true);
}
else if (packet instanceof Message) {
if (((Message)packet).getType() == Message.Type.error){
Log.debug("Double-bounce of message: " + packet.toXML());
return;
}
Message reply = new Message();
reply.setID(packet.getID());
reply.setTo(packet.getFrom());
reply.setFrom(packet.getTo());
reply.setType(Message.Type.error);
reply.setThread(((Message)packet).getThread());
reply.setError(PacketError.Condition.remote_server_not_found);
routingTable.routePacket(reply.getTo(), reply, true);
}
}
catch (Exception e) {
Log.error("Error returning error to sender. Original packet: " + packet, e);
}
}
@Override @Override
public Collection<String> getAuthenticatedDomains() { public Collection<String> getAuthenticatedDomains() {
return Collections.unmodifiableCollection(authenticatedDomains); return Collections.unmodifiableCollection(authenticatedDomains);
......
...@@ -27,6 +27,7 @@ import javax.net.ssl.SSLSession; ...@@ -27,6 +27,7 @@ import javax.net.ssl.SSLSession;
import org.dom4j.Element; import org.dom4j.Element;
import org.jivesoftware.openfire.Connection; import org.jivesoftware.openfire.Connection;
import org.jivesoftware.openfire.RoutingTable;
import org.jivesoftware.openfire.SessionManager; import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.StreamID; import org.jivesoftware.openfire.StreamID;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
...@@ -35,6 +36,7 @@ import org.jivesoftware.openfire.interceptor.InterceptorManager; ...@@ -35,6 +36,7 @@ import org.jivesoftware.openfire.interceptor.InterceptorManager;
import org.jivesoftware.openfire.interceptor.PacketRejectedException; import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.net.SocketConnection; import org.jivesoftware.openfire.net.SocketConnection;
import org.jivesoftware.openfire.net.TLSStreamHandler; import org.jivesoftware.openfire.net.TLSStreamHandler;
import org.jivesoftware.openfire.spi.RoutingTableImpl;
import org.jivesoftware.openfire.streammanagement.StreamManager; import org.jivesoftware.openfire.streammanagement.StreamManager;
import org.jivesoftware.util.LocaleUtils; import org.jivesoftware.util.LocaleUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -479,4 +481,57 @@ public abstract class LocalSession implements Session { ...@@ -479,4 +481,57 @@ public abstract class LocalSession implements Session {
public final Locale getLanguage() { public final Locale getLanguage() {
return language; return language;
} }
public static void returnErrorToSender(Packet packet) {
RoutingTable routingTable = XMPPServer.getInstance().getRoutingTable();
if (packet.getError() != null) {
Log.debug("Possible double bounce: " + packet.toXML());
}
try {
if (packet instanceof IQ) {
if (((IQ) packet).isResponse()) {
Log.debug("XMPP specs forbid us to respond with an IQ error to: " + packet.toXML());
return;
}
IQ reply = new IQ();
reply.setID(packet.getID());
reply.setTo(packet.getFrom());
reply.setFrom(packet.getTo());
reply.setChildElement(((IQ) packet).getChildElement().createCopy());
reply.setType(IQ.Type.error);
reply.setError(PacketError.Condition.remote_server_not_found);
routingTable.routePacket(reply.getTo(), reply, true);
}
else if (packet instanceof Presence) {
if (((Presence)packet).getType() == Presence.Type.error) {
Log.debug("Double-bounce of presence: " + packet.toXML());
return;
}
Presence reply = new Presence();
reply.setID(packet.getID());
reply.setTo(packet.getFrom());
reply.setFrom(packet.getTo());
reply.setType(Presence.Type.error);
reply.setError(PacketError.Condition.remote_server_not_found);
routingTable.routePacket(reply.getTo(), reply, true);
}
else if (packet instanceof Message) {
if (((Message)packet).getType() == Message.Type.error){
Log.debug("Double-bounce of message: " + packet.toXML());
return;
}
Message reply = new Message();
reply.setID(packet.getID());
reply.setTo(packet.getFrom());
reply.setFrom(packet.getTo());
reply.setType(Message.Type.error);
reply.setThread(((Message)packet).getThread());
reply.setError(PacketError.Condition.remote_server_not_found);
routingTable.routePacket(reply.getTo(), reply, true);
}
}
catch (Exception e) {
Log.error("Error returning error to sender. Original packet: " + packet, e);
}
}
} }
...@@ -32,7 +32,7 @@ import org.jivesoftware.openfire.component.ExternalComponentManager; ...@@ -32,7 +32,7 @@ import org.jivesoftware.openfire.component.ExternalComponentManager;
import org.jivesoftware.openfire.container.BasicModule; import org.jivesoftware.openfire.container.BasicModule;
import org.jivesoftware.openfire.forward.Forwarded; import org.jivesoftware.openfire.forward.Forwarded;
import org.jivesoftware.openfire.handler.PresenceUpdateHandler; import org.jivesoftware.openfire.handler.PresenceUpdateHandler;
import org.jivesoftware.openfire.server.OutgoingSessionPromise; import org.jivesoftware.openfire.server.LocalOutgoingServerProxy;
import org.jivesoftware.openfire.session.*; import org.jivesoftware.openfire.session.*;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.cache.Cache; import org.jivesoftware.util.cache.Cache;
...@@ -118,8 +118,21 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust ...@@ -118,8 +118,21 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust
} }
@Override @Override
public void addServerRoute(JID route, LocalOutgoingServerSession destination) { public void addServerRoute(JID route, RoutableChannelHandler destination) {
String address = route.getDomain(); String address = route.getDomain();
try {
ServerSession s = (ServerSession)destination;
ServerSession old = this.getServerRoute(route);
if (s == old) {
return; // Already done.
}
if (old == null) {
return; // This will get added later.
}
destination = new LocalOutgoingServerProxy(route, s);
} catch(Exception e) {
// Just ignore this.
}
localRoutingTable.addRoute(address, destination); localRoutingTable.addRoute(address, destination);
Lock lock = CacheFactory.getLock(address, serversCache); Lock lock = CacheFactory.getLock(address, serversCache);
try { try {
...@@ -475,10 +488,31 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust ...@@ -475,10 +488,31 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust
} }
} }
else { else {
// Return a promise of a remote session. This object will queue packets pending boolean retry = false;
// to be sent to remote servers // If we're here, it means we have no functional route. Sort it out.
OutgoingSessionPromise.getInstance().process(packet); final String domain = jid.getDomain();
synchronized (domain.intern()) { // Only create one route at a time.
// Retry routing, in case someone else beat us to it before we got the lock.
if (serversCache.get(jid.getDomain()) == null) {
RoutableChannelHandler route = localRoutingTable.getRoute(jid.getDomain());
if (route == null) {
LocalOutgoingServerProxy proxy = new LocalOutgoingServerProxy(jid.getDomain());
try {
proxy.process(packet); // Put ours in first.
addServerRoute(new JID(jid.getDomain()), proxy); // At this point it may receive additional packets.
} catch (UnauthorizedException e) {
Log.error("Unable to route packet through new route: {}", packet.toXML(), e);
}
}
routed = true; routed = true;
} else {
retry = true;
}
}
if (retry) {
// Curses! Need to recurse.
routed = routeToRemoteDomain(jid, packet, routed);
}
} }
return routed; return routed;
} }
...@@ -741,7 +775,7 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust ...@@ -741,7 +775,7 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust
@Override @Override
public OutgoingServerSession getServerRoute(JID jid) { public OutgoingServerSession getServerRoute(JID jid) {
// Check if this session is hosted by this cluster node // Check if this session is hosted by this cluster node
OutgoingServerSession session = (OutgoingServerSession) localRoutingTable.getRoute(jid.getDomain()); RoutableChannelHandler session = localRoutingTable.getRoute(jid.getDomain());
if (session == null) { if (session == null) {
// The session is not in this JVM so assume remote // The session is not in this JVM so assume remote
RemoteSessionLocator locator = server.getRemoteSessionLocator(); RemoteSessionLocator locator = server.getRemoteSessionLocator();
...@@ -752,8 +786,12 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust ...@@ -752,8 +786,12 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust
session = locator.getOutgoingServerSession(nodeID, jid); session = locator.getOutgoingServerSession(nodeID, jid);
} }
} }
} else {
// Local ones are proxies.
LocalOutgoingServerProxy proxy = (LocalOutgoingServerProxy) session;
session = proxy.getSession();
} }
return session; return (OutgoingServerSession)session;
} }
@Override @Override
...@@ -1019,7 +1057,7 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust ...@@ -1019,7 +1057,7 @@ public class RoutingTableImpl extends BasicModule implements RoutingTable, Clust
Lock clientLock = CacheFactory.getLock(nodeID, usersCache); Lock clientLock = CacheFactory.getLock(nodeID, usersCache);
try { try {
clientLock.lock(); clientLock.lock();
List<String> remoteClientRoutes = new ArrayList<>(); List<String> remoteClientRoutes = new ArrayList<String>();
for (Map.Entry<String, ClientRoute> entry : usersCache.entrySet()) { for (Map.Entry<String, ClientRoute> entry : usersCache.entrySet()) {
if (entry.getValue().getNodeID().equals(nodeID)) { if (entry.getValue().getNodeID().equals(nodeID)) {
remoteClientRoutes.add(entry.getKey()); remoteClientRoutes.add(entry.getKey());
......
...@@ -75,6 +75,7 @@ ...@@ -75,6 +75,7 @@
<p><span>Spark Plugin - </span>download https://your-server.com:7443/ofmeet/spark/ofmeet-plugin.jar</p> <p><span>Spark Plugin - </span>download https://your-server.com:7443/ofmeet/spark/ofmeet-plugin.jar</p>
<p>Candy - https://your-server.com:7443/ofmeet/candy.html</p> <p>Candy - https://your-server.com:7443/ofmeet/candy.html</p>
<p>JavaScript example - https://your-server.com:7443/ofmeet/api</p> <p>JavaScript example - https://your-server.com:7443/ofmeet/api</p>
<p>Replace port 7443 by 7070 for http instead of https</p>
<p style="min-height: 8pt; padding: 0px;">&nbsp;</p><p><a href="https://community.igniterealtime.org/servlet/JiveServlet/showImage/38-1730-22278/ofmeet5.png"><img alt="ofmeet5.png" height="93" src="https://community.igniterealtime.org/servlet/JiveServlet/downloadImage/38-1730-22278/ofmeet5.png" style="height: auto;" width="300"/></a></p> <p style="min-height: 8pt; padding: 0px;">&nbsp;</p><p><a href="https://community.igniterealtime.org/servlet/JiveServlet/showImage/38-1730-22278/ofmeet5.png"><img alt="ofmeet5.png" height="93" src="https://community.igniterealtime.org/servlet/JiveServlet/downloadImage/38-1730-22278/ofmeet5.png" style="height: auto;" width="300"/></a></p>
</div> </div>
<div> <div>
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
String adminPassword; String adminPassword;
boolean connectionPoolEnabled = true; boolean connectionPoolEnabled = true;
boolean sslEnabled = false; boolean sslEnabled = false;
boolean startTlsEnabled = false;
boolean debugEnabled = false; boolean debugEnabled = false;
boolean referralsEnabled = false; boolean referralsEnabled = false;
boolean aliasReferralsEnabled = true; boolean aliasReferralsEnabled = true;
...@@ -47,6 +48,7 @@ ...@@ -47,6 +48,7 @@
connectionPoolEnabled = connectionPoolEnabled =
ParamUtils.getBooleanParameter(request, "connectionpool", connectionPoolEnabled); ParamUtils.getBooleanParameter(request, "connectionpool", connectionPoolEnabled);
sslEnabled = ParamUtils.getBooleanParameter(request, "ssl", sslEnabled); sslEnabled = ParamUtils.getBooleanParameter(request, "ssl", sslEnabled);
startTlsEnabled = ParamUtils.getBooleanParameter(request, "starttls", startTlsEnabled);
debugEnabled = ParamUtils.getBooleanParameter(request, "debug", debugEnabled); debugEnabled = ParamUtils.getBooleanParameter(request, "debug", debugEnabled);
referralsEnabled = ParamUtils.getBooleanParameter(request, "referrals", referralsEnabled); referralsEnabled = ParamUtils.getBooleanParameter(request, "referrals", referralsEnabled);
aliasReferralsEnabled = ParamUtils.getBooleanParameter(request, "aliasreferrals", aliasReferralsEnabled); aliasReferralsEnabled = ParamUtils.getBooleanParameter(request, "aliasreferrals", aliasReferralsEnabled);
...@@ -68,6 +70,7 @@ ...@@ -68,6 +70,7 @@
settings.put("ldap.connectionPoolEnabled", settings.put("ldap.connectionPoolEnabled",
Boolean.toString(connectionPoolEnabled)); Boolean.toString(connectionPoolEnabled));
settings.put("ldap.sslEnabled", Boolean.toString(sslEnabled)); settings.put("ldap.sslEnabled", Boolean.toString(sslEnabled));
settings.put("ldap.startTlsEnabled", Boolean.toString(startTlsEnabled));
settings.put("ldap.debugEnabled", Boolean.toString(debugEnabled)); settings.put("ldap.debugEnabled", Boolean.toString(debugEnabled));
settings.put("ldap.autoFollowReferrals", Boolean.toString(referralsEnabled)); settings.put("ldap.autoFollowReferrals", Boolean.toString(referralsEnabled));
settings.put("ldap.autoFollowAliasReferrals", Boolean.toString(aliasReferralsEnabled)); settings.put("ldap.autoFollowAliasReferrals", Boolean.toString(aliasReferralsEnabled));
...@@ -91,6 +94,7 @@ ...@@ -91,6 +94,7 @@
manager.setAdminPassword(adminPassword); manager.setAdminPassword(adminPassword);
manager.setConnectionPoolEnabled(connectionPoolEnabled); manager.setConnectionPoolEnabled(connectionPoolEnabled);
manager.setSslEnabled(sslEnabled); manager.setSslEnabled(sslEnabled);
manager.setStartTlsEnabled(startTlsEnabled);
manager.setDebugEnabled(debugEnabled); manager.setDebugEnabled(debugEnabled);
manager.setFollowReferralsEnabled(referralsEnabled); manager.setFollowReferralsEnabled(referralsEnabled);
manager.setFollowAliasReferralsEnabled(aliasReferralsEnabled); manager.setFollowAliasReferralsEnabled(aliasReferralsEnabled);
...@@ -105,6 +109,7 @@ ...@@ -105,6 +109,7 @@
xmppSettings.put("ldap.adminPassword", adminPassword); xmppSettings.put("ldap.adminPassword", adminPassword);
xmppSettings.put("ldap.connectionPoolEnabled", Boolean.toString(connectionPoolEnabled)); xmppSettings.put("ldap.connectionPoolEnabled", Boolean.toString(connectionPoolEnabled));
xmppSettings.put("ldap.sslEnabled", Boolean.toString(sslEnabled)); xmppSettings.put("ldap.sslEnabled", Boolean.toString(sslEnabled));
xmppSettings.put("ldap.startTlsEnabled", Boolean.toString(startTlsEnabled));
xmppSettings.put("ldap.debugEnabled", Boolean.toString(debugEnabled)); xmppSettings.put("ldap.debugEnabled", Boolean.toString(debugEnabled));
xmppSettings.put("ldap.autoFollowReferrals", Boolean.toString(referralsEnabled)); xmppSettings.put("ldap.autoFollowReferrals", Boolean.toString(referralsEnabled));
xmppSettings.put("ldap.autoFollowAliasReferrals", Boolean.toString(aliasReferralsEnabled)); xmppSettings.put("ldap.autoFollowAliasReferrals", Boolean.toString(aliasReferralsEnabled));
...@@ -137,6 +142,7 @@ ...@@ -137,6 +142,7 @@
adminPassword = manager.getAdminPassword(); adminPassword = manager.getAdminPassword();
connectionPoolEnabled = manager.isConnectionPoolEnabled(); connectionPoolEnabled = manager.isConnectionPoolEnabled();
sslEnabled = manager.isSslEnabled(); sslEnabled = manager.isSslEnabled();
startTlsEnabled = manager.isStartTlsEnabled();
debugEnabled = manager.isDebugEnabled(); debugEnabled = manager.isDebugEnabled();
referralsEnabled = manager.isFollowReferralsEnabled(); referralsEnabled = manager.isFollowReferralsEnabled();
aliasReferralsEnabled = manager.isFollowAliasReferralsEnabled(); aliasReferralsEnabled = manager.isFollowAliasReferralsEnabled();
...@@ -304,6 +310,20 @@ ...@@ -304,6 +310,20 @@
<input type="radio" name="ssl" value="false" <% if (!sslEnabled) { %>checked <% } %>> <input type="radio" name="ssl" value="false" <% if (!sslEnabled) { %>checked <% } %>>
</td> </td>
</tr> </tr>
<tr>
<td class="jive-advancedLabel" nowrap>
<fmt:message key="setup.ldap.server.starttls" />:
</td>
<td class="jive-advancedDesc jive-advancedBorderBottom jive-advancedBorderRight">
<fmt:message key="setup.ldap.server.starttls_help" />
</td>
<td class="jive-advancedBorderBottom jive-advancedBorderRight" align="center">
<input type="radio" name="starttls" value="true" <% if (startTlsEnabled) { %>checked <% } %>>
</td>
<td class="jive-advancedBorderBottom" align="center">
<input type="radio" name="starttls" value="false" <% if (!startTlsEnabled) { %>checked <% } %>>
</td>
</tr>
<tr> <tr>
<td class="jive-advancedLabel" nowrap> <td class="jive-advancedLabel" nowrap>
<fmt:message key="setup.ldap.server.debug" />: <fmt:message key="setup.ldap.server.debug" />:
......
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