/* * Copyright (C) 2005-2008 Jive Software, 2017-2026 Ignite Realtime Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jivesoftware.openfire; import org.dom4j.Namespace; import org.jivesoftware.openfire.auth.UnauthorizedException; import org.jivesoftware.openfire.session.LocalSession; import org.jivesoftware.openfire.spi.ConnectionConfiguration; import org.xmpp.packet.Packet; import org.xmpp.packet.StreamError; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.Closeable; import java.net.UnknownHostException; import java.security.cert.Certificate; import java.util.Collections; import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletionStage; /** * Represents a connection on the server. * * @author Iain Shigeoka */ public interface Connection extends Closeable { /** * Verifies that the connection is still live. Typically, this is done by * sending a whitespace character between packets. * * @return true if the socket remains valid, false otherwise. */ boolean validate(); /** * Initializes the connection with it's owning session. Allows the * connection class to configure itself with session related information * (e.g. stream ID). * * @param session the session that owns this connection */ void init( LocalSession session ); /** * Reinitializes the connection to switch to a different session. This allows for * XEP-0198 resumption and transport-switching. * * @param session The new session now owning the connection. */ void reinit( LocalSession session ); /** * Checks if the connection has finished initialization. * * @return true if connection has finished initialization. */ boolean isInitialized(); /** * Returns the raw IP address of this InetAddress * object. The result is in network byte order: the highest order * byte of the address is in getAddress()[0]. * * @return the raw IP address of this object. * @throws java.net.UnknownHostException if IP address of host could not be determined. */ byte[] getAddress() throws UnknownHostException; /** * Returns the IP address string in textual presentation. * * @return the raw IP address in a string format. * @throws java.net.UnknownHostException if IP address of host could not be determined. */ String getHostAddress() throws UnknownHostException; /** * Gets the host name for this IP address. * *

If this InetAddress was created with a host name, * this host name will be remembered and returned; * otherwise, a reverse name lookup will be performed * and the result will be returned based on the system * configured name lookup service. If a lookup of the name service * is required, call * {@link java.net.InetAddress#getCanonicalHostName() getCanonicalHostName}. * *

If there is a security manager, its * checkConnect method is first called * with the hostname and -1 * as its arguments to see if the operation is allowed. * If the operation is not allowed, it will return * the textual representation of the IP address. * * @return the host name for this IP address, or if the operation * is not allowed by the security check, the textual * representation of the IP address. * @throws java.net.UnknownHostException if IP address of host could not be determined. * * @see java.net.InetAddress#getCanonicalHostName * @see SecurityManager#checkConnect */ String getHostName() throws UnknownHostException; /** * Returns the local underlying {@link javax.security.cert.X509Certificate} * chain for the connection. * * @return an ordered array of certificates, with the local certificate * first followed by any certificate authorities. If no certificates * is present for the connection, then {@code null} is returned. */ Certificate[] getLocalCertificates(); /** * Returns the underlying {@link javax.security.cert.X509Certificate} for * the connection of the peer. * * @return an ordered array of peer certificates, with the peer's own * certificate first followed by any certificate authorities. */ Certificate[] getPeerCertificates(); /** * Returns channel binding data for this connection, as defined by the provided type. * * Channel binding data is used to bind higher-level authentication to the underlying transport layer, improving * security against man-in-the-middle attacks. * * The type, identified by a unique prefix that's typically defined in an RFC, determines which channel binding * mechanism is used, such as: *

* * Note that channel binding type prefixes are case-sensitive. * * If the connection is not encrypted, or the requested channel binding type is not available, returns {@link Optional#empty()}. * * @param cbPrefix the RFC-defined unique prefix for the channel binding type (must not be null) * @return An Optional containing the channel binding data, or empty if not available. * @see RFC 5705: Keying Material Exporters for Transport Layer Security (TLS) * @see RFC 5929: Channel Bindings for TLS * @see RFC 9266: Channel Bindings for TLS 1.3 */ default Optional getChannelBindingData(@Nonnull final String cbPrefix) { return Optional.empty(); } /** * Returns the unique prefixes of the channel binding types that are supported by this connection in its current * state. Notably, this may change if the connection is encrypted or if the underlying TLS implementation changes. * When no channel binding types are supported, an empty set is returned. * * Implementation note: This method is used to determine if SASL -PLUS mechanisms (such as SCRAM-SHA-1-PLUS) * should be offered to the client. If channel binding is not supported in the current state (e.g., not encrypted, * or the connection type does not support channel binding), this method must return an empty set. * * @return supported channel binding types. */ default Set getSupportedChannelBindingTypes() { return Collections.emptySet(); } /** * Keeps track if the other peer of this session presented a self-signed certificate. When * using self-signed certificate for server-2-server sessions then SASL EXTERNAL will not be * used and instead server-dialback will be preferred for verifying the identify of the remote * server. * * @param isSelfSigned true if the other peer presented a self-signed certificate. */ void setUsingSelfSignedCertificate( boolean isSelfSigned ); /** * Returns true if the other peer of this session presented a self-signed certificate. When * using self-signed certificate for server-2-server sessions then SASL EXTERNAL will not be * used and instead server-dialback will be preferred for verifying the identify of the remote * server. * * @return true if the other peer of this session presented a self-signed certificate. */ boolean isUsingSelfSignedCertificate(); /** * Close this connection including associated session. The events for closing * the connection are: * * * * Not all implementations use the same order of events. * * Invocation of this method is expected to occur when a coordinated, 'clean' disconnect occurs. Such disconnects * are expected to be user (or server) initiated. As a result, a session closed by this method is not resumable, * even if Stream Management was activated for this session. Refer to {@link #close(StreamError, boolean)} for * processing of unexpected disconnects (that are potentially resumable). */ @Override default void close() { close(null); } /** * Close this connection including associated session, optionally citing a stream error. * * The 'networkInterruption' argument should be set to 'true' if the connection is being closed because it is known * or assumed that the network connection between Openfire and the peer was unexpectedly terminated (eg: due to a * networking failure). These typically are scenarios where a peer becomes unresponsive (without having terminated * its session with a or comparable message). * * When the 'networkInterruption' argument is set to 'true', then a session is eligible for resumption (if Stream * Management was activiated for the session). * * The events for closing the connection are: * * * Not all implementations use the same order of events. * * @param error If non-null, the end-stream tag will be preceded with this error. */ void close(@Nullable final StreamError error); /** * Notification message indicating that the server is being shutdown. Implementors * should send a stream error whose condition is system-shutdown before closing * the connection. */ void systemShutdown(); /** * Returns true if this connection is in the process of closing or has been closed. * * Note that a return value of {@code true} does not mean teardown is complete. Physical transport closure and * {@link ConnectionCloseListener} notification may still be in progress. Use {@link #getCloseFuture()} to be * notified when all close processing has finished. * * @return true if the connection is closed or closing. */ boolean isClosed(); /** * Returns true if this connection is encrypted. * * @return true if the connection is encrypted (e.g. uses TLS) */ boolean isEncrypted(); /** * Registers a listener for close event notification. Registrations after * the Session is closed will be immediately notified before * the registration call returns (within the context of the * registration call). An optional handback object can be associated with * the registration if the same listener is registered to listen for multiple * connection closures. * * @param listener the listener to register for events. * @param handbackMessage the object to send in the event notification. */ void registerCloseListener( ConnectionCloseListener listener, Object handbackMessage ); /** * Removes a registered close event listener. Registered listeners must * be able to receive close events up until the time this method returns. * (i.e. it is possible to call unregister, receive a close event registration, * and then have the unregister call return.) * * @param listener the listener to deregister for close events. */ void removeCloseListener( ConnectionCloseListener listener ); /** * Returns a stage that completes when ALL close operations for this connection have finished, including the * physical transport closure and the invocation of all registered {@link ConnectionCloseListener} instances. * * The stage completes normally with {@code null} regardless of whether individual close listeners encountered * errors. Listener errors are logged but do not cause the stage to complete exceptionally. * * Callers that must not establish a replacement connection until this one is fully torn down (e.g. to prevent * duplicate session conflicts in server-to-server scenarios) should chain on this stage rather than relying on * {@link #isClosed()} alone. {@code isClosed()} returning {@code true} only indicates that the intent * to close has been recorded; teardown may still be in progress. * * The stage will only complete if {@link #close()} or {@link #close(StreamError)} is eventually invoked. * Callers that choose to await this stage should account for the possibility that close is never called on * abandoned connections. * * @return a {@link CompletionStage} that completes once all close processing is done. The returned stage is * read-only; it cannot be used to externally trigger or cancel the close sequence. */ CompletionStage getCloseFuture(); /** * Delivers the packet to this connection without checking the recipient. * The method essentially calls socket.send(packet.getWriteBuffer()). * * Use with caution! This code is unlikely to be called directly. Instead, ensure * that data sent to the entities is sent through the appropriate LocalSession object. * For clients, this prevents, for example, synchronisation issues with stanza counts * related to Stream Management (XEP-0198). * * @param packet the packet to deliver. * @throws org.jivesoftware.openfire.auth.UnauthorizedException if a permission error was detected. */ void deliver( Packet packet ) throws UnauthorizedException; /** * Delivers raw text to this connection. This is a very low level way for sending * XML stanzas to the client. This method should not be used unless you have very * good reasons for not using {@link #deliver(org.xmpp.packet.Packet)}.

* * This method avoids having to get the writer of this connection and mess directly * with the writer. Therefore, this method ensures a correct delivery of the stanza * even if other threads were sending data concurrently. * * @param text the XML stanzas represented kept in a String. */ void deliverRawText( String text ); /** * Returns the major version of XMPP being used by this connection * (major_version.minor_version. In most cases, the version should be * "1.0". However, older clients using the "Jabber" protocol do not set a * version. In that case, the version is "0.0". * * @return the major XMPP version being used by this connection. */ int getMajorXMPPVersion(); /** * Returns the minor version of XMPP being used by this connection * (major_version.minor_version. In most cases, the version should be * "1.0". However, older clients using the "Jabber" protocol do not set a * version. In that case, the version is "0.0". * * @return the minor XMPP version being used by this connection. */ int getMinorXMPPVersion(); /** * Sets the XMPP version information. In most cases, the version should be "1.0". * However, older clients using the "Jabber" protocol do not set a version. In that * case, the version is "0.0". * * @param majorVersion the major version. * @param minorVersion the minor version. */ void setXMPPVersion( int majorVersion, int minorVersion ); /** * Returns true if the connection is using compression. * * @return true if the connection is using compression. */ boolean isCompressed(); /** * Returns the TLS protocol name used by the connection of the session, if any. * * @return a TLS protocol (version) name. */ Optional getTLSProtocolName(); /** * Returns the TLS cipher suite name used by the connection of the session, if any. * * @return cipher suite name. */ Optional getCipherSuiteName(); /** * Returns the packet deliverer to use when delivering a packet over the socket fails. The * packet deliverer will retry to send the packet using some other connection or will store * the packet offline for later retrieval. When null, packets will just be dropped. * * @return the packet deliverer to use when delivering a packet over the socket fails. */ @Nullable PacketDeliverer getPacketDeliverer(); /** * Encrypts the plain connection by negotiating TLS with the other peer. In a server-2-server * connection the server requesting the TLS negotiation will be the client and the other server * will be the server during the TLS negotiation. Therefore, the server requesting the TLS * negotiation must pass true in the {@code clientMode} parameter and the server * receiving the TLS request must pass false in the {@code clientMode} parameter.

*

* In the case of client-2-server the XMPP server must pass false in the * {@code clientMode} parameter since it will behave as the server in the TLS negotiation. * * @param clientMode boolean indicating if this entity is a client or a server in the TLS negotiation. * @param directTLS boolean indicating if the negotiation is directTLS (true) or startTLS (false). * @throws Exception if an error occurred while encrypting the connection. */ void startTLS(boolean clientMode, boolean directTLS) throws Exception; /** * Adds the compression filter to the connection but only filter incoming traffic. Do not filter * outgoing traffic since we still need to send an uncompressed stanza to the client indicating * that he can start compressing the traffic. After we sent the uncompresses stanza we can * start compression outgoing traffic as well. */ void addCompression(); /** * Start compressing outgoing traffic for this connection. Compression will only be available after * TLS has been negotiated. This means that a connection can never be using compression before * TLS. However, it is possible to use compression without TLS. */ void startCompression(); /** * Returns a representation of the desired state for this connection. Note that this is different from the current * state of the connection. For example, TLS can be required by configuration, but while the connection has yet to * be fully initialized, the current state might not be TLS-encrypted. * * @return The desired configuration for the connection (never null). */ ConnectionConfiguration getConfiguration(); /** * When a connection is used to transmit an XML data, the root element of that data can define XML namespaces other * than the ones that are default (eg: 'jabber:client', 'jabber:server', etc). For an XML parser to be able to parse * stanzas or other elements that are defined in that namespace (eg: are prefixed), these namespaces are recorded * here. * * @return A collection that contains all non-default namespaces that the peer defined when last opening a new stream. */ Set getAdditionalNamespaces(); /** * When a connection is used to transmit an XML data, the root element of that data can define XML namespaces other * than the ones that are default (eg: 'jabber:client', 'jabber:server', etc). For an XML parser to be able to parse * stanzas or other elements that are defined in that namespace (eg: are prefixed), these namespaces are recorded * here. * * @param additionalNamespaces A collection that contains all non-default namespaces that the peer defined when last * opening a new stream. */ void setAdditionalNamespaces(@Nonnull final Set additionalNamespaces); /** * Enumeration of possible compression policies required to interact with the server. */ enum CompressionPolicy { /** * compression is optional to interact with the server. */ optional, /** * compression is not available. Entities that request a compression negotiation * will get a stream error and their connections will be closed. */ disabled } /** * Enumeration of possible TLS policies required to interact with the server. */ enum TLSPolicy { /** * TLS is required to interact with the server. Entities that do not encrypt their * connections using TLS will get a stream error and their connections will be closed. */ required, /** * TLS is optional to interact with the server. Entities may or may not encrypt their * connections using TLS. */ optional, /** * TLS is not available. Entities that request a TLS negotiation will get a stream * error and their connections will be closed. */ disabled, /** * A policy that requires connections to be encrypted immediately (as opposed to the * 'required' policy, that allows for an initially unencrypted connection to become * encrypted through StartTLS. */ directTLS } /** * Enumeration that specifies if clients should be authenticated (and how) while * negotiating TLS. */ enum ClientAuth { /** * No authentication will be performed on the client. Client credentials will not * be verified while negotiating TLS. */ disabled, /** * Clients will try to be authenticated. Unlike {@link #needed}, if the client * chooses not to provide authentication information about itself, the TLS negotiations * will stop and the connection will be dropped. This option is only useful for * engines in the server mode. */ wanted, /** * Clients need to be authenticated. Unlike {@link #wanted}, if the client * chooses not to provide authentication information about itself, the TLS negotiations * will continue. This option is only useful for engines in the server mode. */ needed } /** * Used to specify operational status for the corresponding connection */ enum State { OPEN, CLOSED } }