ClientSessionConnection.java 8.07 KB
Newer Older
Gaston Dombiak's avatar
Gaston Dombiak committed
1 2 3 4 5
/**
 * $RCSfile: $
 * $Revision: $
 * $Date: $
 *
6
 * Copyright (C) 2005-2008 Jive Software. All rights reserved.
Gaston Dombiak's avatar
Gaston Dombiak committed
7
 *
8 9 10 11 12 13 14 15 16 17 18
 * 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.
Gaston Dombiak's avatar
Gaston Dombiak committed
19 20
 */

21
package org.jivesoftware.openfire.multiplex;
Gaston Dombiak's avatar
Gaston Dombiak committed
22 23

import org.dom4j.Element;
24 25 26
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.net.VirtualConnection;
import org.jivesoftware.openfire.session.ConnectionMultiplexerSession;
Gaston Dombiak's avatar
Gaston Dombiak committed
27 28 29
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;

30
import java.net.InetAddress;
31
import java.net.UnknownHostException;
Gaston Dombiak's avatar
Gaston Dombiak committed
32 33 34 35

/**
 * Represents a connection of a Client Session that was established to a Connection Manager.
 * Connection Managers have their own physical connections to the server that are multiplexed
36
 * among connected clients. Each created {@link org.jivesoftware.openfire.session.ClientSession}
37
 * will use an instance of this class as its connection.
Gaston Dombiak's avatar
Gaston Dombiak committed
38 39 40 41 42 43 44 45
 *
 * @author Gaston Dombiak
 */
public class ClientSessionConnection extends VirtualConnection {

    private String connectionManagerName;
    private String serverName;
    private ConnectionMultiplexerManager multiplexerManager;
46 47
    private String hostName;
    private String hostAddress;
Gaston Dombiak's avatar
Gaston Dombiak committed
48

49
    public ClientSessionConnection(String connectionManagerName, String hostName, String hostAddress) {
Gaston Dombiak's avatar
Gaston Dombiak committed
50 51
        this.connectionManagerName = connectionManagerName;
        multiplexerManager = ConnectionMultiplexerManager.getInstance();
52
        serverName = XMPPServer.getInstance().getServerInfo().getXMPPDomain();
53 54
        this.hostName = hostName;
        this.hostAddress = hostAddress;
Gaston Dombiak's avatar
Gaston Dombiak committed
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
    }

    /**
     * Delivers the packet to the Connection Manager that in turn will forward it to the
     * target user. Connection Managers may have one or many connections to the server so
     * just get any connection to the Connection Manager (uses a random) and use it.<p>
     *
     * If the packet to send does not have a TO attribute then wrap the packet with a
     * special IQ packet. The wrapper IQ packet will be sent to the Connection Manager
     * and the stream ID of this Client Session will be used for identifying that the wrapped
     * packet must be sent to the connected user. Since some packets can be exchanged before
     * the user has a binded JID we need to use the stream ID as the unique identifier.
     *
     * @param packet the packet to send to the user.
     */
70
    @Override
Gaston Dombiak's avatar
Gaston Dombiak committed
71
    public void deliver(Packet packet) {
72
        String streamID = session.getStreamID().getID();
Gaston Dombiak's avatar
Gaston Dombiak committed
73
        ConnectionMultiplexerSession multiplexerSession =
74
                multiplexerManager.getMultiplexerSession(connectionManagerName,streamID);
Gaston Dombiak's avatar
Gaston Dombiak committed
75
        if (multiplexerSession != null) {
76
            // Wrap packet so that the connection manager can figure out the target session
77
            Route wrapper = new Route(streamID);
78 79 80 81
            wrapper.setFrom(serverName);
            wrapper.setTo(connectionManagerName);
            wrapper.setChildElement(packet.getElement().createCopy());
            // Deliver wrapper
82
            multiplexerSession.process(wrapper);
Gaston Dombiak's avatar
Gaston Dombiak committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
            session.incrementServerPacketCount();
        }
    }

    /**
     * Delivers the stanza to the Connection Manager that in turn will forward it to the
     * target user. Connection Managers may have one or many connections to the server so
     * just get any connection to the Connection Manager (uses a random) and use it.<p>
     *
     * The stanza to send wrapped with a special IQ packet. The wrapper IQ packet will be
     * sent to the Connection Manager and the stream ID of this Client Session will be used
     * for identifying that the wrapped stanza must be sent to the connected user.
     *
     * @param text the stanza to send to the user.
     */
98
    @Override
Gaston Dombiak's avatar
Gaston Dombiak committed
99
    public void deliverRawText(String text) {
100
        String streamID = session.getStreamID().getID();
Gaston Dombiak's avatar
Gaston Dombiak committed
101
        ConnectionMultiplexerSession multiplexerSession =
102
                multiplexerManager.getMultiplexerSession(connectionManagerName,streamID);
Gaston Dombiak's avatar
Gaston Dombiak committed
103 104 105
        if (multiplexerSession != null) {
            // Wrap packet so that the connection manager can figure out the target session
            StringBuilder sb = new StringBuilder(200 + text.length());
106
            sb.append("<route from=\"").append(serverName);
Gaston Dombiak's avatar
Gaston Dombiak committed
107
            sb.append("\" to=\"").append(connectionManagerName);
108
            sb.append("\" streamid=\"").append(streamID).append("\">");
Gaston Dombiak's avatar
Gaston Dombiak committed
109
            sb.append(text);
110
            sb.append("</route>");
Gaston Dombiak's avatar
Gaston Dombiak committed
111
            // Deliver the wrapped stanza
112
            multiplexerSession.deliverRawText(sb.toString());
Gaston Dombiak's avatar
Gaston Dombiak committed
113 114 115
        }
    }

116
    @Override
117
    public byte[] getAddress() throws UnknownHostException {
118 119 120
        if (hostAddress != null) {
            return InetAddress.getByName(hostAddress).getAddress();
        }
121 122 123
        return null;
    }

124
    @Override
125
    public String getHostAddress() throws UnknownHostException {
126 127 128
        if (hostAddress != null) {
            return hostAddress;
        }
129 130 131 132 133 134 135 136 137
        // Return IP address of the connection manager that the client used to log in
        ConnectionMultiplexerSession multiplexerSession =
                multiplexerManager.getMultiplexerSession(connectionManagerName);
        if (multiplexerSession != null) {
            return multiplexerSession.getHostAddress();
        }
        return null;
    }

138
    @Override
139
    public String getHostName() throws UnknownHostException {
140 141 142
        if (hostName != null) {
            return hostName;
        }
Gaston Dombiak's avatar
Gaston Dombiak committed
143 144 145 146
        // Return IP address of the connection manager that the client used to log in
        ConnectionMultiplexerSession multiplexerSession =
                multiplexerManager.getMultiplexerSession(connectionManagerName);
        if (multiplexerSession != null) {
147
            return multiplexerSession.getHostName();
Gaston Dombiak's avatar
Gaston Dombiak committed
148 149 150 151
        }
        return null;
    }

152
    @Override
153 154 155 156 157 158
    public void systemShutdown() {
        // Do nothing since a system-shutdown error will be sent to the Connection Manager
        // that in turn will send a system-shutdown to connected clients. This is an
        // optimization to reduce number of packets being sent from the server.
    }

Gaston Dombiak's avatar
Gaston Dombiak committed
159 160 161 162 163 164
    /**
     * If the Connection Manager or the Client requested to close the connection then just do
     * nothing. But if the server originated the request to close the connection then we need
     * to send to the Connection Manager a packet letting him know that the Client Session needs
     * to be terminated.
     */
165 166
    @Override
	public void closeVirtualConnection() {
Gaston Dombiak's avatar
Gaston Dombiak committed
167 168 169 170 171 172 173
        // Figure out who requested the connection to be closed
        String streamID = session.getStreamID().getID();
        if (multiplexerManager.getClientSession(connectionManagerName, streamID) == null) {
            // Client or Connection manager requested to close the session
            // Do nothing since it has already been removed and closed
        }
        else {
174
            ConnectionMultiplexerSession multiplexerSession =
175
                    multiplexerManager.getMultiplexerSession(connectionManagerName,streamID);
176 177 178 179 180 181 182 183 184 185
            if (multiplexerSession != null) {
                // Server requested to close the client session so let the connection manager
                // know that he has to finish the client session
                IQ closeRequest = new IQ(IQ.Type.set);
                closeRequest.setFrom(serverName);
                closeRequest.setTo(connectionManagerName);
                Element child = closeRequest.setChildElement("session",
                        "http://jabber.org/protocol/connectionmanager");
                child.addAttribute("id", streamID);
                child.addElement("close");
186
                multiplexerSession.process(closeRequest);
187
            }
Gaston Dombiak's avatar
Gaston Dombiak committed
188 189 190
        }
    }
}