@Override
        public void run()
        {
            log("Start reading from socket" + (socket instanceof SSLSocket ? " (encrypted)" : ""));
            try {
                sendStreamHeader();

                do {
                    try {
                        final byte[] buffer = new byte[1024 * 16];
                        int count;
                        while (!processingService.isShutdown() && (count = is.read(buffer)) > 0) {
                            String read = new String(buffer, 0, count);
                            if (read.startsWith("<?")) {
                                log("(stripping prolog from data that's read)");
                                final int endProlog = read.indexOf("?>") + 2;
                                read = read.substring(endProlog);
                            }
                            if (read.startsWith("<stream:") && !read.contains("xmlns:stream=")) {
                                // Ugly hack to get stream prefix to work.
                                read = read.replaceFirst(">", " xmlns:stream=\"http://etherx.jabber.org/streams\">");
                                log("# recv (Hacked inbound stanza to include stream namespace declaration)" + (socket instanceof SSLSocket ? " (encrypted)" : ""));
                            } else if (read.startsWith("<db:") && !read.contains("xmlns:db=")) {
                                // Ugly hack to get Dialback to work.
                                read = read.replaceFirst(" ", " xmlns:db=\"jabber:server:dialback\" ");
                                log("# recv (Hacked inbound stanza to include Dialback namespace declaration)" + (socket instanceof SSLSocket ? " (encrypted)" : ""));
                            } else {
                                log("# recv from Openfire" + (socket instanceof SSLSocket ? " (encrypted)" : ""));
                            }
                            log(read);
                            log("");

                            if (read.contains("<stream:error")) {
                                log("Peer sends a stream error. Can't use this connection anymore.");
                                return;
                            }
                            if (!read.equals("</stream:stream>")) {
                                Element inbound = parse(read);
                                if (inbound.getName().equals("stream")) {
                                    // This is expected to be the response stream header. No need to act on this, but if it contains a dialback namespace, then this suggests that the peer supports dialback.
                                    peerAdvertisedDialbackNamespace = inbound.declaredNamespaces().stream().anyMatch(namespace -> "jabber:server:dialback".equals(namespace.getURI()));
                                    if (inbound.attributeValue("id") != null) receivedStreamIDs.add(BasicStreamIDFactory.createStreamID(inbound.attributeValue("id")));
                                    if (inbound.attributeValue("to") != null) receivedStreamToValues.add(inbound.attributeValue("to"));
                                    if (inbound.attributeValue("from") != null) receivedStreamFromValues.add(inbound.attributeValue("from"));
                                    switch (inbound.elements().size()) {
                                        case 0:
                                            // Done processing the input. Iterate, to try to read more.
                                            continue;
                                        case 1:
                                            // There are child elements to process!
                                            inbound = inbound.elements().get(0);
                                            break;
                                        default:
                                            // More than one child element. This test implementation can't currently handle that.
                                            throw new IllegalStateException("Unable to process more than one child element.");
                                    }
                                }
                                switch (inbound.getName()) {
                                    case "features":
                                        negotiateFeatures(inbound);
                                        break;
                                    case "result":
                                        processDialbackResult(inbound);
                                        break;
                                    case "proceed":
                                        processStartTLSProceed(inbound);
                                        return; // stop reading more from this inputstream.
                                    case "success": // intended fall-through
                                    case "failure":
                                        if (inbound.getNamespaceURI().equals("urn:ietf:params:xml:ns:xmpp-sasl")) {
                                            if (processSaslResponse(inbound)) {
                                                log("Successfully authenticated using SASL! We're done setting up a connection.");
                                                return;
                                            } else if (peerSupportsDialback && !disableDialback) {
                                                log("Unable to authenticate using SASL! Dialback seems to be available. Trying that...");
                                                startDialbackAuth();
                                                break;
                                            } else {
                                                throw new InterruptedIOException("Unable to authenticate");
                                            }
                                        } else if (inbound.getNamespaceURI().equals("urn:ietf:params:xml:ns:xmpp-tls")) {
                                            throw new InterruptedIOException("Received StartTLS failure from Openfire. Aborting connection");
                                        }
                                        // intended fall-through
                                    default:
                                        log("Received stanza '" + inbound.getName() + "' that I don't know how to respond to." + (socket instanceof SSLSocket ? " (encrypted)" : ""));
                                }
                            } else {
                                // received an end of stream: if the peer closes the connection, then we're done trying.
                                break;
                            }
                        }
                        // Maybe we should immediately return here, as the stream has ended. Socket timeouts (which are processed by the remainder of this method) seem not relevant in that case. return;
                    } catch (SocketTimeoutException e) {
                        allowableSocketTimeouts--;
                        if (allowableSocketTimeouts <= 0) {
                            throw e;
                        }
                    }
                } while (!processingService.isShutdown() && allowableSocketTimeouts > 0);
                log("Ending read loop" + (socket instanceof SSLSocket ? " (encrypted)" : ""));
            } catch (Throwable t) {
                // Log exception only when not cleanly closed.
                if (doLog && !processingService.isShutdown()) {
                    t.printStackTrace();
                }
            } finally {
                log("Stopped reading from socket" + (socket instanceof SSLSocket ? " (encrypted)" : ""));
                done();
            }
        }
To speed up the test execution, SO_TIMEOUT (the socket read timeout) has been set to a low value. When negotiating Server Dialback, a second
socket connection is used. XMPP session establishment on the first socket connection is paused while the Server Dialback negotiation takes
place. This can easily cause the SO_TIMEOUT to run out. To prevent issues, this implementation allows for reads of the first socket connection
to time out for a certain number of times, before treating this as a terminal exception.
xmppserver/src/test/java/org/jivesoftware/openfire/session/RemoteInitiatingServerDummy.java