outgoingserversession.java

来自「基于Jabber协议的即时消息服务器」· Java 代码 · 共 679 行 · 第 1/3 页

JAVA
679
字号
     * @param port default port to use to establish the connection.
     * @return new outgoing session to a remote server.
     */
    private static OutgoingServerSession createOutgoingSession(String domain, String hostname,
            int port) {
        boolean useTLS = JiveGlobals.getBooleanProperty("xmpp.server.tls.enabled", true);
        RemoteServerConfiguration configuration = RemoteServerManager.getConfiguration(hostname);
        if (configuration != null) {
            // TODO Use the specific TLS configuration for this remote server
            //useTLS = configuration.isTLSEnabled();
        }

        if (useTLS) {
            // Connect to remote server using TLS + SASL
            SocketConnection connection = null;
            String realHostname = null;
            int realPort = port;
            Socket socket = new Socket();
            try {
                // Get the real hostname to connect to using DNS lookup of the specified hostname
                DNSUtil.HostAddress address = DNSUtil.resolveXMPPServerDomain(hostname, port);
                realHostname = address.getHost();
                realPort = address.getPort();
                Log.debug("OS - Trying to connect to " + hostname + ":" + port +
                        "(DNS lookup: " + realHostname + ":" + realPort + ")");
                // Establish a TCP connection to the Receiving Server
                socket.connect(new InetSocketAddress(realHostname, realPort),
                        RemoteServerManager.getSocketTimeout());
                Log.debug("OS - Plain connection to " + hostname + ":" + port + " successful");
            }
            catch (Exception e) {
                Log.error("Error trying to connect to remote server: " + hostname +
                        "(DNS lookup: " + realHostname + ":" + realPort + ")", e);
                return null;
            }

            try {
                connection =
                        new SocketConnection(XMPPServer.getInstance().getPacketDeliverer(), socket,
                                false);

                // Send the stream header
                StringBuilder openingStream = new StringBuilder();
                openingStream.append("<stream:stream");
                openingStream.append(" xmlns:stream=\"http://etherx.jabber.org/streams\"");
                openingStream.append(" xmlns=\"jabber:server\"");
                openingStream.append(" to=\"").append(hostname).append("\"");
                openingStream.append(" version=\"1.0\">");
                connection.deliverRawText(openingStream.toString());

                // Set a read timeout (of 5 seconds) so we don't keep waiting forever
                int soTimeout = socket.getSoTimeout();
                socket.setSoTimeout(5000);

                XMPPPacketReader reader = new XMPPPacketReader();
                reader.getXPPParser().setInput(new InputStreamReader(socket.getInputStream(),
                        CHARSET));
                // Get the answer from the Receiving Server
                XmlPullParser xpp = reader.getXPPParser();
                for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) {
                    eventType = xpp.next();
                }

                String serverVersion = xpp.getAttributeValue("", "version");

                // Check if the remote server is XMPP 1.0 compliant
                if (serverVersion != null && decodeVersion(serverVersion)[0] >= 1) {
                    // Restore default timeout
                    socket.setSoTimeout(soTimeout);
                    // Get the stream features
                    Element features = reader.parseDocument().getRootElement();
                    // Check if TLS is enabled
                    if (features != null && features.element("starttls") != null) {
                        // Secure the connection with TLS and authenticate using SASL
                        OutgoingServerSession answer;
                        answer = secureAndAuthenticate(hostname, connection, reader, openingStream,
                                domain);
                        if (answer != null) {
                            // Everything went fine so return the secured and
                            // authenticated connection
                            return answer;
                        }
                    }
                    else {
                        Log.debug("OS - Error, <starttls> was not received");
                    }
                }
                // Something went wrong so close the connection and try server dialback over
                // a plain connection
                if (connection != null) {
                    connection.close();
                }
            }
            catch (SSLHandshakeException e) {
                Log.debug("Handshake error while creating secured outgoing session to remote " +
                        "server: " + hostname + "(DNS lookup: " + realHostname + ":" + realPort +
                        ")", e);
                // Close the connection
                if (connection != null) {
                    connection.close();
                }
            }
            catch (XmlPullParserException e) {
                Log.warn("Error creating secured outgoing session to remote server: " + hostname +
                        "(DNS lookup: " + realHostname + ":" + realPort + ")", e);
                // Close the connection
                if (connection != null) {
                    connection.close();
                }
            }
            catch (Exception e) {
                Log.error("Error creating secured outgoing session to remote server: " + hostname +
                        "(DNS lookup: " + realHostname + ":" + realPort + ")", e);
                // Close the connection
                if (connection != null) {
                    connection.close();
                }
            }
        }
        if (ServerDialback.isEnabled()) {
            Log.debug("OS - Going to try connecting using server dialback with: " + hostname);
            // Use server dialback over a plain connection
            return new ServerDialback().createOutgoingSession(domain, hostname, port);
        }
        return null;
    }

    private static OutgoingServerSession secureAndAuthenticate(String hostname,
            SocketConnection connection, XMPPPacketReader reader, StringBuilder openingStream,
            String domain) throws Exception {
        Element features;
        Log.debug("OS - Indicating we want TLS to " + hostname);
        connection.deliverRawText("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");

        MXParser xpp = reader.getXPPParser();
        // Wait for the <proceed> response
        Element proceed = reader.parseDocument().getRootElement();
        if (proceed != null && proceed.getName().equals("proceed")) {
            Log.debug("OS - Negotiating TLS with " + hostname);
            connection.startTLS(true, hostname);
            Log.debug("OS - TLS negotiation with " + hostname + " was successful");

            // TLS negotiation was successful so initiate a new stream
            connection.deliverRawText(openingStream.toString());

            // Reset the parser to use the new secured reader
            xpp.setInput(new InputStreamReader(connection.getTLSStreamHandler().getInputStream(),
                    CHARSET));
            // Skip new stream element
            for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) {
                eventType = xpp.next();
            }
            // Get new stream features
            features = reader.parseDocument().getRootElement();
            if (features != null && features.element("mechanisms") != null) {
                // Check if we can use stream compression
                String policyName = JiveGlobals.getProperty("xmpp.server.compression.policy",
                        Connection.CompressionPolicy.disabled.toString());
                Connection.CompressionPolicy compressionPolicy =
                        Connection.CompressionPolicy.valueOf(policyName);
                if (Connection.CompressionPolicy.optional == compressionPolicy) {
                    // Verify if the remote server supports stream compression
                    Element compression = features.element("compression");
                    if (compression != null) {
                        boolean zlibSupported = false;
                        Iterator it = compression.elementIterator("method");
                        while (it.hasNext()) {
                            Element method = (Element) it.next();
                            if ("zlib".equals(method.getTextTrim())) {
                                zlibSupported = true;
                            }
                        }
                        if (zlibSupported) {
                            // Request Stream Compression
                            connection.deliverRawText("<compress xmlns='http://jabber.org/protocol/compress'><method>zlib</method></compress>");
                            // Check if we are good to start compression
                            Element answer = reader.parseDocument().getRootElement();
                            if ("compressed".equals(answer.getName())) {
                                // Server confirmed that we can use zlib compression
                                connection.startCompression();
                                Log.debug("OS - Stream compression was successful with " + hostname);
                                // Stream compression was successful so initiate a new stream
                                connection.deliverRawText(openingStream.toString());
                                // Reset the parser to use stream compression over TLS
                                ZInputStream in = new ZInputStream(
                                        connection.getTLSStreamHandler().getInputStream());
                                in.setFlushMode(JZlib.Z_PARTIAL_FLUSH);
                                xpp.setInput(new InputStreamReader(in, CHARSET));
                                // Skip the opening stream sent by the server
                                for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;)
                                {
                                    eventType = xpp.next();
                                }
                                // Get new stream features
                                features = reader.parseDocument().getRootElement();
                                if (features == null || features.element("mechanisms") == null) {
                                    Log.debug("OS - Error, EXTERNAL SASL was not offered by " + hostname);
                                    return null;
                                }
                            }
                            else {
                                Log.debug("OS - Stream compression was rejected by " + hostname);
                            }
                        }
                        else {
                            Log.debug(
                                    "OS - Stream compression found but zlib method is not supported by" +
                                            hostname);
                        }
                    }
                    else {
                        Log.debug("OS - Stream compression not supoprted by " + hostname);
                    }
                }

                Iterator it = features.element("mechanisms").elementIterator();
                while (it.hasNext()) {
                    Element mechanism = (Element) it.next();
                    if ("EXTERNAL".equals(mechanism.getTextTrim())) {
                        Log.debug("OS - Starting EXTERNAL SASL with " + hostname);
                        if (doExternalAuthentication(domain, connection, reader)) {
                            Log.debug("OS - EXTERNAL SASL with " + hostname + " was successful");
                            // SASL was successful so initiate a new stream
                            connection.deliverRawText(openingStream.toString());

                            // Reset the parser
                            xpp.resetInput();

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?