use of org.jivesoftware.openfire.StreamID in project Openfire by igniterealtime.
the class HttpSession method createConnection.
/**
* Creates a new connection on this session.
*
* @param body the body element that was sent containing the request for a new session.
* @param context the context of the asynchronous servlet call leading up to this method call.
* @return the created {@link org.jivesoftware.openfire.http.HttpConnection} which represents
* the connection.
*/
@Nonnull
synchronized HttpConnection createConnection(@Nonnull final HttpBindBody body, @Nonnull final AsyncContext context) {
final HttpConnection connection = new HttpConnection(body, context);
final StreamID streamID = getStreamID();
final long rid = body.getRid();
if (Log.isDebugEnabled()) {
Log.debug("Creating connection for rid: {} in session {}", rid, streamID);
}
connection.setSession(this);
context.setTimeout(getWait().toMillis());
context.addListener(new AsyncListener() {
@Override
public void onComplete(AsyncEvent asyncEvent) {
if (Log.isTraceEnabled()) {
Log.trace("Session {} Request ID {}, event complete: {}", streamID, rid, asyncEvent);
}
synchronized (connectionQueue) {
connectionQueue.remove(connection);
lastActivity = Instant.now();
}
SessionEventDispatcher.dispatchEvent(HttpSession.this, SessionEventDispatcher.EventType.connection_closed, connection, context);
}
@Override
public void onTimeout(AsyncEvent asyncEvent) throws IOException {
if (Log.isTraceEnabled()) {
Log.trace("Session {} Request ID {}, event timeout: {}. Returning an empty response.", streamID, rid, asyncEvent);
}
try {
// This is why this body is to be delivered in a non-async fashion.
synchronized (connectionQueue) {
deliver(connection, Collections.singletonList(new Deliverable("")), false);
setLastResponseEmpty(true);
}
} catch (HttpConnectionClosedException e) {
Log.warn("Unexpected exception while processing connection timeout.", e);
}
// Note that 'onComplete' will be invoked.
}
@Override
public void onError(AsyncEvent asyncEvent) {
if (Log.isTraceEnabled()) {
Log.trace("Session {} Request ID {}, event error: {}", streamID, rid, asyncEvent);
}
Log.warn("For session {} an unhandled AsyncListener error occurred: ", streamID, asyncEvent.getThrowable());
synchronized (connectionQueue) {
connectionQueue.remove(connection);
}
SessionEventDispatcher.dispatchEvent(HttpSession.this, SessionEventDispatcher.EventType.connection_closed, connection, context);
}
@Override
public void onStartAsync(AsyncEvent asyncEvent) {
if (Log.isTraceEnabled()) {
Log.trace("Session {} Request ID {}, event start: {}", streamID, rid, asyncEvent);
}
}
});
return connection;
}
use of org.jivesoftware.openfire.StreamID in project Openfire by igniterealtime.
the class MultiplexerPacketHandler method handle.
/**
* Process IQ packet sent by a connection manager indicating that a new session has
* been created, should be closed or that a packet was failed to be delivered.
*
* @param packet the IQ packet.
*/
public void handle(Packet packet) {
if (packet instanceof IQ) {
IQ iq = (IQ) packet;
if (iq.getType() == IQ.Type.result) {
// Do nothing with result packets
} else if (iq.getType() == IQ.Type.error) {
// Log the IQ error packet that the connection manager failed to process
Log.warn("Connection Manager failed to process IQ packet: " + packet.toXML());
} else if (iq.getType() == IQ.Type.set) {
Element child = iq.getChildElement();
String streamIDValue = child.attributeValue("id");
if (streamIDValue == null) {
// No stream ID was included so return a bad_request error
Element extraError = DocumentHelper.createElement(QName.get("id-required", "http://jabber.org/protocol/connectionmanager#errors"));
sendErrorPacket(iq, PacketError.Condition.bad_request, extraError);
} else if ("session".equals(child.getName())) {
StreamID streamID = BasicStreamIDFactory.createStreamID(streamIDValue);
Element create = child.element("create");
if (create != null) {
// Get the InetAddress of the client
Element hostElement = create.element("host");
String hostName = hostElement != null ? hostElement.attributeValue("name") : null;
String hostAddress = hostElement != null ? hostElement.attributeValue("address") : null;
// Connection Manager wants to create a Client Session
boolean created = multiplexerManager.createClientSession(connectionManagerDomain, streamID, hostName, hostAddress);
if (created) {
sendResultPacket(iq);
} else {
// Send error to CM. The CM should close the new-born connection
sendErrorPacket(iq, PacketError.Condition.not_allowed, null);
}
} else {
ClientSession session = multiplexerManager.getClientSession(connectionManagerDomain, streamID);
if (session == null) {
// Specified Client Session does not exist
sendErrorPacket(iq, PacketError.Condition.item_not_found, null);
} else if (child.element("close") != null) {
// Connection Manager wants to close a Client Session
multiplexerManager.closeClientSession(connectionManagerDomain, streamID);
sendResultPacket(iq);
} else if (child.element("failed") != null) {
// Connection Manager failed to deliver a message
// Connection Manager wrapped a packet from a Client Session.
List wrappedElements = child.element("failed").elements();
if (wrappedElements.size() != 1) {
// Wrapper element is wrapping 0 or many items
Element extraError = DocumentHelper.createElement(QName.get("invalid-payload", "http://jabber.org/protocol/connectionmanager#errors"));
sendErrorPacket(iq, PacketError.Condition.bad_request, extraError);
} else {
Element wrappedElement = (Element) wrappedElements.get(0);
String tag = wrappedElement.getName();
if ("message".equals(tag)) {
XMPPServer.getInstance().getOfflineMessageStrategy().storeOffline(new Message(wrappedElement));
sendResultPacket(iq);
} else {
Element extraError = DocumentHelper.createElement(QName.get("unknown-stanza", "http://jabber.org/protocol/connectionmanager#errors"));
sendErrorPacket(iq, PacketError.Condition.bad_request, extraError);
}
}
} else {
// Unknown IQ packet received so return error to sender
sendErrorPacket(iq, PacketError.Condition.bad_request, null);
}
}
} else {
// Unknown IQ packet received so return error to sender
sendErrorPacket(iq, PacketError.Condition.bad_request, null);
}
} else {
// Unknown IQ packet received so return error to sender
sendErrorPacket(iq, PacketError.Condition.bad_request, null);
}
}
}
use of org.jivesoftware.openfire.StreamID in project Openfire by igniterealtime.
the class MultiplexerPacketHandler method route.
/**
* Processes a route packet that is wrapping a stanza sent by a client that is connected
* to the connection manager.
*
* @param route the route packet.
*/
public void route(Route route) {
StreamID streamID = route.getStreamID();
if (streamID == null) {
// No stream ID was included so return a bad_request error
Element extraError = DocumentHelper.createElement(QName.get("id-required", "http://jabber.org/protocol/connectionmanager#errors"));
sendErrorPacket(route, PacketError.Condition.bad_request, extraError);
}
LocalClientSession session = multiplexerManager.getClientSession(connectionManagerDomain, streamID);
if (session == null) {
// Specified Client Session does not exist
sendErrorPacket(route, PacketError.Condition.item_not_found, null);
return;
}
SessionPacketRouter router = new SessionPacketRouter(session);
// Connection Manager already validate JIDs so just skip this expensive operation
router.setSkipJIDValidation(true);
try {
router.route(route.getChildElement());
} catch (UnknownStanzaException use) {
Element extraError = DocumentHelper.createElement(QName.get("unknown-stanza", "http://jabber.org/protocol/connectionmanager#errors"));
sendErrorPacket(route, PacketError.Condition.bad_request, extraError);
} catch (Exception e) {
Log.error("Error processing wrapped packet: " + route.getChildElement().asXML(), e);
sendErrorPacket(route, PacketError.Condition.internal_server_error, null);
}
}
use of org.jivesoftware.openfire.StreamID in project Openfire by igniterealtime.
the class LocalIncomingServerSession method createSession.
/**
* Creates a new session that will receive packets. The new session will be authenticated
* before being returned. If the authentication process fails then the answer will be
* <tt>null</tt>.<p>
*
* @param serverName hostname of this server.
* @param reader reader on the new established connection with the remote server.
* @param connection the new established connection with the remote server.
* @return a new session that will receive packets or null if a problem occured while
* authenticating the remote server or when acting as the Authoritative Server during
* a Server Dialback authentication process.
* @throws org.xmlpull.v1.XmlPullParserException if an error occurs while parsing the XML.
* @throws java.io.IOException if an input/output error occurs while using the connection.
*/
public static LocalIncomingServerSession createSession(String serverName, XMPPPacketReader reader, SocketConnection connection) throws XmlPullParserException, IOException {
XmlPullParser xpp = reader.getXPPParser();
String version = xpp.getAttributeValue("", "version");
String fromDomain = xpp.getAttributeValue("", "from");
String toDomain = xpp.getAttributeValue("", "to");
int[] serverVersion = version != null ? decodeVersion(version) : new int[] { 0, 0 };
if (toDomain == null) {
toDomain = serverName;
}
try {
// Get the stream ID for the new session
StreamID streamID = SessionManager.getInstance().nextStreamID();
// Create a server Session for the remote server
LocalIncomingServerSession session = SessionManager.getInstance().createIncomingServerSession(connection, streamID, fromDomain);
// Send the stream header
StringBuilder openingStream = new StringBuilder();
openingStream.append("<stream:stream");
openingStream.append(" xmlns:db=\"jabber:server:dialback\"");
openingStream.append(" xmlns:stream=\"http://etherx.jabber.org/streams\"");
openingStream.append(" xmlns=\"jabber:server\"");
openingStream.append(" from=\"").append(toDomain).append("\"");
if (fromDomain != null) {
openingStream.append(" to=\"").append(fromDomain).append("\"");
}
openingStream.append(" id=\"").append(streamID).append("\"");
// implementations appears to reduce connection issues with those domains (patch by Marcin Cieślak).
if (serverVersion[0] >= 1) {
openingStream.append(" version=\"1.0\">");
} else {
openingStream.append('>');
}
connection.deliverRawText(openingStream.toString());
if (serverVersion[0] >= 1) {
// Remote server is XMPP 1.0 compliant so offer TLS and SASL to establish the connection (and server dialback)
// Indicate the TLS policy to use for this connection
Connection.TLSPolicy tlsPolicy = connection.getTlsPolicy();
boolean hasCertificates = false;
try {
hasCertificates = XMPPServer.getInstance().getCertificateStoreManager().getIdentityStore(ConnectionType.SOCKET_S2S).getStore().size() > 0;
} catch (Exception e) {
Log.error(e.getMessage(), e);
}
if (Connection.TLSPolicy.required == tlsPolicy && !hasCertificates) {
Log.error("Server session rejected. TLS is required but no certificates " + "were created.");
return null;
}
connection.setTlsPolicy(hasCertificates ? tlsPolicy : Connection.TLSPolicy.disabled);
}
// Indicate the compression policy to use for this connection
connection.setCompressionPolicy(connection.getConfiguration().getCompressionPolicy());
StringBuilder sb = new StringBuilder();
if (serverVersion[0] >= 1) {
// Remote server is XMPP 1.0 compliant so offer TLS and SASL to establish the connection (and server dialback)
// Don't offer stream-features to pre-1.0 servers, as it confuses them. Sending features to Openfire < 3.7.1 confuses it too - OF-443)
sb.append("<stream:features>");
if (JiveGlobals.getBooleanProperty(ConnectionSettings.Server.TLS_ENABLED, true)) {
sb.append("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\">");
if (!ServerDialback.isEnabled()) {
// Server dialback is disabled so TLS is required
sb.append("<required/>");
}
sb.append("</starttls>");
}
// Include available SASL Mechanisms
sb.append(SASLAuthentication.getSASLMechanisms(session));
if (ServerDialback.isEnabled()) {
// Also offer server dialback (when TLS is not required). Server dialback may be offered
// after TLS has been negotiated and a self-signed certificate is being used
sb.append("<dialback xmlns=\"urn:xmpp:features:dialback\"><errors/></dialback>");
}
sb.append("</stream:features>");
}
connection.deliverRawText(sb.toString());
// Set the domain or subdomain of the local server targeted by the remote server
session.setLocalDomain(serverName);
return session;
} catch (Exception e) {
Log.error("Error establishing connection from remote server:" + connection, e);
connection.close();
return null;
}
}
use of org.jivesoftware.openfire.StreamID in project Openfire by igniterealtime.
the class LocalOutgoingServerSession method attemptDialbackOverTLS.
private static LocalOutgoingServerSession attemptDialbackOverTLS(Connection connection, XMPPPacketReader reader, String localDomain, String remoteDomain, String id) {
final Logger log = LoggerFactory.getLogger(Log.getName() + "[Dialback over TLS for: " + localDomain + " to: " + remoteDomain + " (Stream ID: " + id + ")]");
if (ServerDialback.isEnabled() || ServerDialback.isEnabledForSelfSigned()) {
log.debug("Trying to connecting using dialback over TLS.");
ServerDialback method = new ServerDialback(connection, localDomain);
OutgoingServerSocketReader newSocketReader = new OutgoingServerSocketReader(reader);
if (method.authenticateDomain(newSocketReader, localDomain, remoteDomain, id)) {
log.debug("Dialback over TLS was successful.");
StreamID streamID = new BasicStreamIDFactory().createStreamID(id);
LocalOutgoingServerSession session = new LocalOutgoingServerSession(localDomain, connection, newSocketReader, streamID);
connection.init(session);
// Set the hostname as the address of the session
session.setAddress(new JID(null, remoteDomain, null));
return session;
} else {
log.debug("Dialback over TLS failed");
return null;
}
} else {
log.debug("Skipping server dialback attempt as it has been disabled by local configuration.");
return null;
}
}
Aggregations