protected void createSession(XmlPullParser xpp) throws XmlPullParserException, IOException {
        for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) {
            eventType = xpp.next();
        }

        final String serverName = XMPPServer.getInstance().getServerInfo().getXMPPDomain();
        String host = xpp.getAttributeValue("", "to");

        try {
            // Check that the TO attribute of the stream header matches the server name or a valid
            // subdomain. If the value of the 'to' attribute is not valid then return a host-unknown
            // error and close the underlying connection.
            if (validateHost() && isHostUnknown(host)) {
                throw new StreamErrorException(StreamError.Condition.host_unknown, "Incorrect hostname in stream header: " + host);
            }

            // Validate the stream namespace
            if (!"http://etherx.jabber.org/streams".equals(xpp.getNamespace())) {
                throw new StreamErrorException(StreamError.Condition.invalid_namespace, "Invalid namespace in stream header: " + xpp.getNamespace());
            }

            // http://xmpp.org/rfcs/rfc6120.html#streams-error-conditions-invalid-namespace
            // "or the content namespace declared as the default namespace is not supported (e.g., something other than "jabber:client" or "jabber:server")."
            if (!getNamespace().getURI().equals(xpp.getNamespace(null))) {
                throw new StreamErrorException(StreamError.Condition.invalid_namespace, "Invalid namespace in stream header. Expected: '" + getNamespace().getURI() + "'. Received: '" + xpp.getNamespace(null) + "'.");
            }

            // Create the correct session based on the sent namespace. At this point the server
            // may offer the client to encrypt the connection. If the client decides to encrypt
            // the connection then a <starttls> stanza should be received
            createSession(serverName, xpp, connection);

            if (session == null) {
                throw new StreamErrorException(StreamError.Condition.internal_server_error, "Unable to create a session.");
            }
        }
        catch (final StreamErrorException ex) {
            Log.warn("Failed to create a session. Closing connection: {}", connection, ex);
            final Element stream = DocumentHelper.createElement(QName.get("stream", "stream", "http://etherx.jabber.org/streams"));
            final Document document = DocumentHelper.createDocument(stream);
            document.setXMLEncoding(StandardCharsets.UTF_8.toString());
            stream.add(Namespace.get(xpp.getNamespace(null)));
            stream.addAttribute("from", host);
            stream.addAttribute("id", STREAM_ID_FACTORY.createStreamID().getID());
            stream.addAttribute("version", "1.0");
            stream.add(ex.getStreamError().getElement());

            // Deliver stanza
            connection.deliverRawText(StringUtils.asUnclosedStream(document));

            // Close the underlying connection
            connection.close();
        }
    }
Uses the XPP to grab the opening stream tag and create an active session
object. The session to create will depend on the sent namespace. In all
cases, the method obtains the opening stream tag, checks for errors, and
either creates a session or returns an error and kills the connection.
If the connection remains open, the XPP will be set to be ready for the
first packet. A call to next() should result in an START_TAG state with
the first packet in the stream.
@param xpp the pull parser
@throws XmlPullParserException if an exception occurs reading from the pull parser
@throws IOException if an IO exception occurs reading from the pull parser
xmppserver/src/main/java/org/jivesoftware/openfire/net/StanzaHandler.java