openfire 원본 분석 ---6

17300 단어

사용자 연결 요청


이 장부터 업무 분석에 따라 오픈파이어의 원본을 분석합니다.사용자가 Openfire 서버에 연결할 때 먼저 Openfire에 다음과 같은 XMPP 메시지를 보냅니다.
<stream:stream to="192.168.1.1" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" version="1.0"></stream:stream>

앞의 몇 장의 분석에 의하면 이 함수는 최종적으로ClientStanzaHandler의process 함수에 도달할 것이다. 분석을 편리하게 하기 위해 여기에 이 함수를 붙인다.
    public void process(String stanza, XMPPPacketReader reader) throws Exception {

        boolean initialStream = stanza.startsWith("<stream:stream") || stanza.startsWith("<flash:stream");
        if (!sessionCreated || initialStream) {

            ...

            if (!sessionCreated) {
                sessionCreated = true;
                MXParser parser = reader.getXPPParser();
                parser.setInput(new StringReader(stanza));
                createSession(parser);
            }

            ...

            return;
        }

        ...

    }

클라이언트가 보낸 메시지에 따르면 여기 initial Stream은true이고 클라이언트가 보낸 첫 번째 메시지이기 때문에 Session이 생성되지 않았습니다. 따라서createSession 함수를 실행하여 ClientStanzaHandler에 정의합니다.
    boolean createSession(String namespace, String serverName, XmlPullParser xpp, Connection connection) throws XmlPullParserException {
        if ("jabber:client".equals(namespace)) {
            session = LocalClientSession.createSession(serverName, xpp, connection);
            return true;
        }
        return false;
    }

클라이언트 메시지에 의하면 이곳의 이름 공간namespace는 확실히'jabber:client'이기 때문에createSession을 호출하여 LocalSession을 구성합니다.여기에 전송된 매개 변수connection은 ConnectionHandler의sessionOpened 함수에서 구성된 NIOConnection입니다.
    public static LocalClientSession createSession(String serverName, XmlPullParser xpp, Connection connection)
            throws XmlPullParserException {

        String language = "en";
        int majorVersion = 0;
        int minorVersion = 0;
        for (int i = 0; i < xpp.getAttributeCount(); i++) {
            if ("lang".equals(xpp.getAttributeName(i))) {
                language = xpp.getAttributeValue(i);
            }
            if ("version".equals(xpp.getAttributeName(i))) {
                try {
                    int[] version = decodeVersion(xpp.getAttributeValue(i));
                    majorVersion = version[0];
                    minorVersion = version[1];
                }
                catch (Exception e) {

                }
            }
        }
        connection.setLanaguage(language);
        connection.setXMPPVersion(majorVersion, minorVersion);

        if (!connection.isSecure()) {
            boolean hasCertificates = false;
            try {
                hasCertificates = SSLConfig.getKeyStore().size() > 0;
            }
            catch (Exception e) {

            }
            Connection.TLSPolicy tlsPolicy = getTLSPolicy();
            if (Connection.TLSPolicy.required == tlsPolicy && !hasCertificates) {
                return null;
            }
            connection.setTlsPolicy(hasCertificates ? tlsPolicy : Connection.TLSPolicy.disabled);
        } else {
            connection.setTlsPolicy(Connection.TLSPolicy.disabled);
        }

        connection.setCompressionPolicy(getCompressionPolicy());
        LocalClientSession session = SessionManager.getInstance().createClientSession(connection);

        StringBuilder sb = new StringBuilder(200);
        sb.append("<?xml version='1.0' encoding='");
        sb.append(CHARSET);
        sb.append("'?>");
        if (isFlashClient) {
            sb.append("<flash:stream xmlns:flash=\"http://www.jabber.com/streams/flash\" ");
        }
        else {
            sb.append("<stream:stream ");
        }
        sb.append("xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:client\" from=\"");
        sb.append(serverName);
        sb.append("\" id=\"");
        sb.append(session.getStreamID().toString());
        sb.append("\" xml:lang=\"");
        sb.append(language);
        if (majorVersion != 0) {
            sb.append("\" version=\"");
            sb.append(majorVersion).append(".").append(minorVersion);
        }
        sb.append("\">");
        connection.deliverRawText(sb.toString());

        sb = new StringBuilder(490);
        sb.append("<stream:features>");
        if (connection.getTlsPolicy() != Connection.TLSPolicy.disabled) {
            sb.append("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\">");
            if (connection.getTlsPolicy() == Connection.TLSPolicy.required) {
                sb.append("<required/>");
            }
            sb.append("</starttls>");
        }
        sb.append(SASLAuthentication.getSASLMechanisms(session));
        String specificFeatures = session.getAvailableStreamFeatures();
        if (specificFeatures != null) {
            sb.append(specificFeatures);
        }
        sb.append("</stream:features>");

        connection.deliverRawText(sb.toString());
        return session;
    }

첫 번째 for 순환은 클라이언트가 보낸 xmpp 메시지를 훑어보며'lang'또는'version'속성이 있는지 확인합니다. 앞의 xmpp 메시지에 따라 여기가 순환을 끝낼 때language는 변하지 않습니다.majorVersion=1,minorVersion=0.그리고 이 언어와 버전 정보를 NIOConnection에 설정합니다. 이 NIOConnection은 ClientConnectionHandler의sessionOpened 함수에서 구성된 것으로 세션 정보를 저장합니다.isSecure는 NIOConnection에 정의되어 있습니다.
    public boolean isSecure() {
        return ioSession.getFilterChain().contains(TLS_FILTER_NAME);
    }

이 함수는 Session에 보안 전송 프로토콜이 포함되어 있는지 확인합니다. 그 근거는 Session의 필터에 TLS_가 포함되어 있는지 여부입니다.FILTER_NAME가 지정한 이름의 필터입니다. 이 필터는 없다고 가정합니다. 뒤에 있는 코드 가설은 마지막에 tls 정책을 disable로 설정합니다. 테이블은 보안 전송을 사용하지 않습니다.다음은 setCompressionPolicy를 호출하여 압축 정책을 설정합니다. CompressionPolicy는 enum 변수입니다. 여기는 기본적으로optional로 설정되어 있습니다. 압축 정책을 시작합니다.그리고 SessionManager의createClientSession을 호출하여 Session을 만듭니다. 이 Session은 Openfire의 Session이고 앞의 Session은mina 프레임워크에서 구성된 Session입니다. 두 가지 기능이 일치하지 않습니다.
    public LocalClientSession createClientSession(Connection conn) {
        return createClientSession(conn, nextStreamID());
    }

nextStreamID는 BasicStreamIDFactory를 호출하여 무작위 ID를 구성합니다.
    public LocalClientSession createClientSession(Connection conn, StreamID id) {

        LocalClientSession session = new LocalClientSession(serverName, conn, id);
        conn.init(session);
        conn.registerCloseListener(clientSessionListener, session);
        localSessionManager.getPreAuthenticatedSessions().put(session.getAddress().getResource(), session);
        connectionsCounter.incrementAndGet();
        return session;
    }

먼저 LocalClientSession을 만들고 init 함수를 호출하여 LocalClientSession을 NioConnection에 설정한 다음 연결이 닫힐 때의 감청기를 설정한 다음 방금 구성된 LocalClientSession을 검증되지 않은 Session 해시 테이블에 설정합니다. 이곳의localSessionManager는 LocalSessionManager로 오픈파이어의 Session을 저장합니다.createSession 함수로 돌아가면 다음부터 반환 정보를 구성합니다. 코드에 따라 마지막으로 구성된 XMPP 반환 정보는 다음과 같습니다.
<?xml version='1.0' encoding='UTF-8'?>
<stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="#serverName" id="#id" xml:lang="en" version="1.0"\>
<stream:features>
<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
<mechanism>DIGEST-MD5</mechanism>
<mechanism>JIVE-SHAREDSECRET</mechanism>
<mechanism>PLAIN</mechanism>
<mechanism>ANONYMOUS</mechanism>
<mechanism>CRAM-MD5</mechanism>
</mechanisms>
<compression xmlns="http://jabber.org/features/compress">
<method>zlib</method>
</compression>
<auth xmlns="http://jabber.org/features/iq-auth"/>
<register xmlns="http://jabber.org/features/iq-register"/>
</stream:features>

여기 #serverName과 #id는 각각 서버 호스트 이름과 앞에서 nextStream ID 구조를 호출하는 랜덤 ID입니다.몇 개의 메커니즘 태그는 SASLAuthentication입니다.getSASLMechanisms 함수가 기본적으로 지원하는 Openfire SASL 방법을 되돌려줍니다.compression, auth, register 탭은 get Available Stream Features가 되돌아온 결과입니다.마지막으로deliverRawText를 호출하여 데이터를 보내는데deliverRawText는 바로 미나 프레임워크 IoSession을 호출하는 write 방법입니다.
이로써 클라이언트는 오픈파이어 서버와의 첫 번째 요청을 완성했다. 총괄적으로 오픈파이어 서버는 이번 요청에 따라 Connection과 Session을 구성하여 인증되지 않은 Session 해시표에 저장하고 서버가 지원할 수 있는 SASL 방법, 업소 정책, 주석 방법 등을 되돌려준다.

좋은 웹페이지 즐겨찾기