Search in sources :

Example 16 with StreamID

use of org.jivesoftware.openfire.StreamID in project Openfire by igniterealtime.

the class HttpSession method processConnection.

/**
 * Schedules the connection for processing, ensuring that connections are processed in the order of their request ID
 * values. Processing causes data delivered by the client to be routed in the server to their intended recipients,
 * and allow the connection to be used to send back data to the client.
 *
 * @param connection The connection ready to be processed.
 * @param context the context of the asynchronous servlet call leading up to this method call.
 */
private void processConnection(@Nonnull final HttpConnection connection, @Nonnull final AsyncContext context) throws HttpConnectionClosedException, IOException {
    final long rid = connection.getRequestId();
    final StreamID streamid = getStreamID();
    if (Log.isDebugEnabled()) {
        Log.debug("Adding connection to stream {} with rid {}", streamid, rid);
    }
    // Note that connections can be expected to arrive 'out of order'. The implementation should only use a connection
    // that has a request ID value that's exactly one higher than the last request ID value in the 'gapless' sequence
    // of request IDs. When a connection is being processed that has a higher value, it should go unused until another
    // connection arrives that 'fills the gap' (and be used only _after_ that connection gets used).
    boolean aConnectionAvailableForDelivery = false;
    synchronized (connectionQueue) {
        connectionQueue.add(connection);
        // Order the connection queue, and determine if the sequence of consecutive request IDs can be updated.
        connectionQueue.sort(connectionComparator);
        for (final HttpConnection queuedConnection : connectionQueue) {
            final long queuedRequestID = queuedConnection.getRequestId();
            if (queuedRequestID <= lastSequentialRequestID) {
                continue;
            }
            if (queuedRequestID == lastSequentialRequestID + 1) {
                // There is a new connection available for consumption.
                lastSequentialRequestID = queuedRequestID;
                if (queuedConnection.isClosed()) {
                    // Unsure if this can happen - perhaps at edge-cases involving time-outs?
                    continue;
                }
                // The data that was provided by the client can now be processed by the server.
                sendPendingPackets(queuedConnection.getInboundDataQueue());
                // Evaluate edge-cases.
                if (queuedConnection.isTerminate()) {
                    queuedConnection.deliverBody(createEmptyBody(true), true);
                    close();
                } else if (queuedConnection.isRestart()) {
                    queuedConnection.deliverBody(createSessionRestartResponse(), true);
                } else if (queuedConnection.getPause() != null && queuedConnection.getPause().compareTo(getMaxPause()) <= 0) {
                    // TODO shouldn't we error when the requested pause is higher than the allowed maximum?
                    pause(queuedConnection.getPause());
                    connection.deliverBody(createEmptyBody(false), true);
                    setLastResponseEmpty(true);
                } else {
                    // At least one new connection has become available, and can be used to return data to the client.
                    aConnectionAvailableForDelivery = true;
                }
            // Note that when this connection fills a gap in the sequence, other connections might already be
            // available that have the 'next' Request ID value. We need to keep iterating.
            } else {
                // when a gap is detected (subsequent connections will only have higher Request ID values).
                break;
            }
        }
        if (isPollingSession()) {
            // guarantee that 'a new connection is now available for delivery').
            assert aConnectionAvailableForDelivery;
        }
        if (isPollingSession() || (aConnectionAvailableForDelivery && !pendingElements.isEmpty())) {
            lastActivity = Instant.now();
            // TODO is this the right place to dispatch this event?
            SessionEventDispatcher.dispatchEvent(this, SessionEventDispatcher.EventType.connection_opened, connection, context);
            deliver(pendingElements);
            pendingElements.clear();
        }
        // When a new connection has become available, older connections need to be released (allowing the client to
        // send more data if it needs to).
        final List<HttpConnection> openConnections = connectionQueue.stream().filter(c -> !c.isClosed()).filter(c -> c.getRequestId() <= lastSequentialRequestID).sorted(connectionComparator).collect(Collectors.toList());
        while (openConnections.size() > hold) {
            if (Log.isTraceEnabled()) {
                Log.trace("Stream {}: releasing oldest connection (rid {}), as the amount of open connections ({}) is higher than the requested amount to hold ({}).", streamid, rid, openConnections.size(), hold);
            }
            final HttpConnection openConnection = openConnections.remove(0);
            openConnection.deliverBody(createEmptyBody(false), true);
        }
    }
}
Also used : Presence(org.xmpp.packet.Presence) X509Certificate(java.security.cert.X509Certificate) LocalClientSession(org.jivesoftware.openfire.session.LocalClientSession) java.util(java.util) TaskEngine(org.jivesoftware.util.TaskEngine) LoggerFactory(org.slf4j.LoggerFactory) DocumentHelper(org.dom4j.DocumentHelper) PacketDeliverer(org.jivesoftware.openfire.PacketDeliverer) AsyncEvent(javax.servlet.AsyncEvent) StreamID(org.jivesoftware.openfire.StreamID) UnauthorizedException(org.jivesoftware.openfire.auth.UnauthorizedException) JiveGlobals(org.jivesoftware.util.JiveGlobals) InetAddress(java.net.InetAddress) AsyncContext(javax.servlet.AsyncContext) AsyncListener(javax.servlet.AsyncListener) SessionPacketRouter(org.jivesoftware.openfire.SessionPacketRouter) ConnectionManagerImpl(org.jivesoftware.openfire.spi.ConnectionManagerImpl) Message(org.xmpp.packet.Message) Duration(java.time.Duration) XMPPServer(org.jivesoftware.openfire.XMPPServer) VirtualConnection(org.jivesoftware.openfire.net.VirtualConnection) Nonnull(javax.annotation.Nonnull) Nullable(javax.annotation.Nullable) ConnectionConfiguration(org.jivesoftware.openfire.spi.ConnectionConfiguration) Logger(org.slf4j.Logger) SASLAuthentication(org.jivesoftware.openfire.net.SASLAuthentication) ConnectionType(org.jivesoftware.openfire.spi.ConnectionType) Namespace(org.dom4j.Namespace) MXParser(org.jivesoftware.openfire.net.MXParser) XMPPPacketReader(org.dom4j.io.XMPPPacketReader) IOException(java.io.IOException) GuardedBy(javax.annotation.concurrent.GuardedBy) Instant(java.time.Instant) UnknownHostException(java.net.UnknownHostException) Collectors(java.util.stream.Collectors) XmlPullParserException(org.xmlpull.v1.XmlPullParserException) StringReader(java.io.StringReader) XmlPullParserFactory(org.xmlpull.v1.XmlPullParserFactory) Packet(org.xmpp.packet.Packet) Element(org.dom4j.Element) QName(org.dom4j.QName) UnknownStanzaException(org.jivesoftware.openfire.multiplex.UnknownStanzaException) IQ(org.xmpp.packet.IQ) Immutable(javax.annotation.concurrent.Immutable) StreamID(org.jivesoftware.openfire.StreamID)

Example 17 with StreamID

use of org.jivesoftware.openfire.StreamID in project Openfire by igniterealtime.

the class ConnectionMultiplexerManager method removeSession.

private void removeSession(Session session) {
    // Remove trace indicating that a connection manager is hosting a connection
    StreamID streamID = session.getStreamID();
    String connectionManagerDomain = streamIDs.remove(streamID);
    // Remove trace indicating that a connection manager is hosting a session
    if (connectionManagerDomain != null) {
        Map<StreamID, LocalClientSession> sessions = sessionsByManager.get(connectionManagerDomain);
        if (sessions != null) {
            sessions.remove(streamID);
        }
    }
}
Also used : LocalClientSession(org.jivesoftware.openfire.session.LocalClientSession) StreamID(org.jivesoftware.openfire.StreamID)

Example 18 with StreamID

use of org.jivesoftware.openfire.StreamID in project Openfire by igniterealtime.

the class ConnectionMultiplexerManager method multiplexerUnavailable.

/**
 * A connection manager has gone unavailable. Close client sessions that were established
 * to the specified connection manager.
 *
 * @param connectionManagerName the connection manager that is no longer available.
 */
public void multiplexerUnavailable(String connectionManagerName) {
    // Remove the connection manager and the hosted sessions
    Map<StreamID, LocalClientSession> sessions = sessionsByManager.remove(connectionManagerName);
    if (sessions != null) {
        for (StreamID streamID : sessions.keySet()) {
            // Remove inverse track of connection manager hosting streamIDs
            streamIDs.remove(streamID);
            // Close the session
            sessions.get(streamID).close();
        }
    }
}
Also used : LocalClientSession(org.jivesoftware.openfire.session.LocalClientSession) StreamID(org.jivesoftware.openfire.StreamID)

Example 19 with StreamID

use of org.jivesoftware.openfire.StreamID in project Openfire by igniterealtime.

the class ConnectionMultiplexerManager method closeClientSession.

/**
 * Closes an existing client session that was established through a connection manager.
 *
 * @param connectionManagerDomain the connection manager that is handling the connection
 *        of the session.
 * @param streamID the stream ID created by the connection manager for the session.
 */
public void closeClientSession(String connectionManagerDomain, StreamID streamID) {
    Map<StreamID, LocalClientSession> sessions = sessionsByManager.get(connectionManagerDomain);
    if (sessions != null) {
        Session session = sessions.remove(streamID);
        if (session != null) {
            Log.debug("Closing session: {}", session);
            session.close();
        }
    }
}
Also used : LocalClientSession(org.jivesoftware.openfire.session.LocalClientSession) StreamID(org.jivesoftware.openfire.StreamID) LocalClientSession(org.jivesoftware.openfire.session.LocalClientSession) ConnectionMultiplexerSession(org.jivesoftware.openfire.session.ConnectionMultiplexerSession) Session(org.jivesoftware.openfire.session.Session)

Example 20 with StreamID

use of org.jivesoftware.openfire.StreamID in project Openfire by igniterealtime.

the class ConnectionMultiplexerManager method createClientSession.

/**
 * Creates a new client session that was established to the specified connection manager.
 * The new session will not be findable through its stream ID.
 *
 * @param connectionManagerDomain the connection manager that is handling the connection
 *        of the session.
 * @param streamID the stream ID created by the connection manager for the new session.
 * @param hostName the address's hostname of the client or null if using old connection manager.
 * @param hostAddress the textual representation of the address of the client or null if using old CM.
 * @return true if a session was created or false if the client should disconnect.
 */
public boolean createClientSession(String connectionManagerDomain, StreamID streamID, String hostName, String hostAddress) {
    Connection connection = new ClientSessionConnection(connectionManagerDomain, hostName, hostAddress);
    // Check if client is allowed to connect from the specified IP address. Ignore the checking if connection
    // manager is old version and is not passing client's address
    byte[] address = null;
    try {
        address = connection.getAddress();
    } catch (UnknownHostException e) {
    // Ignore
    }
    if (address == null || LocalClientSession.isAllowed(connection)) {
        LocalClientSession session = SessionManager.getInstance().createClientSession(connection, streamID);
        // Register that this streamID belongs to the specified connection manager
        streamIDs.put(streamID, connectionManagerDomain);
        // Register which sessions are being hosted by the speicifed connection manager
        Map<StreamID, LocalClientSession> sessions = sessionsByManager.get(connectionManagerDomain);
        if (sessions == null) {
            synchronized (connectionManagerDomain.intern()) {
                sessions = sessionsByManager.get(connectionManagerDomain);
                if (sessions == null) {
                    sessions = new ConcurrentHashMap<>();
                    sessionsByManager.put(connectionManagerDomain, sessions);
                }
            }
        }
        sessions.put(streamID, session);
        return true;
    }
    return false;
}
Also used : LocalClientSession(org.jivesoftware.openfire.session.LocalClientSession) StreamID(org.jivesoftware.openfire.StreamID) UnknownHostException(java.net.UnknownHostException) Connection(org.jivesoftware.openfire.Connection)

Aggregations

StreamID (org.jivesoftware.openfire.StreamID)20 LocalClientSession (org.jivesoftware.openfire.session.LocalClientSession)7 IOException (java.io.IOException)5 Element (org.dom4j.Element)5 UnauthorizedException (org.jivesoftware.openfire.auth.UnauthorizedException)4 ConnectionMultiplexerSession (org.jivesoftware.openfire.session.ConnectionMultiplexerSession)4 Logger (org.slf4j.Logger)4 XmlPullParserException (org.xmlpull.v1.XmlPullParserException)4 Nonnull (javax.annotation.Nonnull)3 Connection (org.jivesoftware.openfire.Connection)3 OutgoingServerSocketReader (org.jivesoftware.openfire.server.OutgoingServerSocketReader)3 XmlPullParser (org.xmlpull.v1.XmlPullParser)3 JID (org.xmpp.packet.JID)3 InputStreamReader (java.io.InputStreamReader)2 UnknownHostException (java.net.UnknownHostException)2 java.util (java.util)2 Collectors (java.util.stream.Collectors)2 AsyncEvent (javax.servlet.AsyncEvent)2 AsyncListener (javax.servlet.AsyncListener)2 XMPPPacketReader (org.dom4j.io.XMPPPacketReader)2