Commit 37bf168a authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gaston

Added support for external components. JM-5


git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@945 b35dd754-fafc-0310-a699-88a17e54d16e
parent c5e9bc33
...@@ -12,29 +12,26 @@ ...@@ -12,29 +12,26 @@
package org.jivesoftware.messenger; package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.AuthToken; import org.jivesoftware.messenger.auth.AuthToken;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.xmpp.packet.Presence;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import java.util.Date; import java.util.Date;
/** /**
* The session is the primary interface to the entire chat server.
* Use the session to obtain references to all system managers, permissions,
* authentication, and other resources.<p>
*
* The session represents a connection between the server and a client (c2s) or * The session represents a connection between the server and a client (c2s) or
* another server (s2s). Authentication and user accounts are associated with * another server (s2s) as well as a connection with a component. Authentication and
* c2s connections while s2s has an optional authentication association but no * user accounts are associated with c2s connections while s2s has an optional authentication
* single user user.<p> * association but no single user user.<p>
* *
* Obtain object managers from the session in order to access server resources. * Obtain object managers from the session in order to access server resources.
* *
* @author Iain Shigeoka * @author Gaston Dombiak
*/
public abstract class Session implements RoutableChannelHandler {
/**
* The utf-8 charset for decoding and encoding Jabber packet streams.
*/ */
public interface Session extends RoutableChannelHandler { protected static String CHARSET = "UTF-8";
public static final int STATUS_CLOSED = -1; public static final int STATUS_CLOSED = -1;
public static final int STATUS_CONNECTED = 1; public static final int STATUS_CONNECTED = 1;
...@@ -42,109 +39,104 @@ public interface Session extends RoutableChannelHandler { ...@@ -42,109 +39,104 @@ public interface Session extends RoutableChannelHandler {
public static final int STATUS_AUTHENTICATED = 3; public static final int STATUS_AUTHENTICATED = 3;
/** /**
* Obtain the address of the user. The address is used by services like the core * The Address this session is authenticated as.
* server packet router to determine if a packet should be sent to the handler.
* Handlers that are working on behalf of the server should use the generic server
* hostname address (e.g. server.com).
*
* @return the address of the packet handler.
*/ */
public JID getAddress(); private JID address;
/** /**
* Sets the new address of this session. The address is used by services like the core * The stream id for this session (random and unique).
* server packet router to determine if a packet should be sent to the handler.
* Handlers that are working on behalf of the server should use the generic server
* hostname address (e.g. server.com).
*/ */
public void setAddress(JID address); private StreamID streamID;
/** /**
* Returns the connection associated with this Session. * The current session status.
*
* @return The connection for this session
*/ */
public Connection getConnection(); protected int status = STATUS_CONNECTED;
/** /**
* Obtain the current status of this session. * The connection that this session represents.
*
* @return The status code for this session
*/ */
public int getStatus(); protected Connection conn;
/** /**
* Set the new status of this session. Setting a status may trigger * The authentication token for this session.
* certain events to occur (setting a closed status will close this
* session).
*
* @param status The new status code for this session
*/ */
public void setStatus(int status) throws UnauthorizedException; protected AuthToken authToken;
/** protected SessionManager sessionManager;
* Flag indicating if this session has been initialized once coming
* online. Session initialization occurs after the session receives private String serverName;
* the first "available" presence update from the client. Initialization
* actions include pushing offline messages, presence subscription requests, private Date startDate = new Date();
* and presence statuses to the client. Initialization occurs only once
* following the first available presence transition. private long lastActiveDate;
* private long clientPacketCount = 0;
* @return True if the session has already been initializsed private long serverPacketCount = 0;
*/
public boolean isInitialized();
/** /**
* Sets the initialization state of the session. * Creates a session with an underlying connection and permission protection.
* *
* @param isInit True if the session has been initialized * @param connection The connection we are proxying
* @throws UnauthorizedException If the caller does not have permission to make this change
* @see #isInitialized
*/ */
public void setInitialized(boolean isInit) throws UnauthorizedException; public Session(String serverName, Connection connection, StreamID streamID) {
conn = connection;
this.streamID = streamID;
this.serverName = serverName;
String id = streamID.getID();
this.address = new JID(null, serverName, id);
this.sessionManager = SessionManager.getInstance();
}
/** /**
* Obtain the presence of this session. * Obtain the address of the user. The address is used by services like the core
* server packet router to determine if a packet should be sent to the handler.
* Handlers that are working on behalf of the server should use the generic server
* hostname address (e.g. server.com).
* *
* @return The presence of this session or null if not authenticated * @return the address of the packet handler.
*/ */
public Presence getPresence(); public JID getAddress() {
return address;
}
/** /**
* Set the presence of this session * Sets the new address of this session. The address is used by services like the core
* * server packet router to determine if a packet should be sent to the handler.
* @param presence The presence for the session * Handlers that are working on behalf of the server should use the generic server
* @return The old priority of the session or null if not authenticated * hostname address (e.g. server.com).
*/ */
public Presence setPresence(Presence presence) throws UnauthorizedException; public void setAddress(JID address){
this.address = address;
}
/** /**
* Initialize the session with a valid authentication token and * Returns the connection associated with this Session.
* resource name. This automatically upgrades the session's
* status to authenticated and enables many features that are not
* available until authenticated (obtaining managers for example).
* *
* @param auth The authentication token obtained from the AuthFactory * @return The connection for this session
* @param resource The resource this session authenticated under
* @param userManager The user manager this authentication occured under
*/ */
public void setAuthToken(AuthToken auth, UserManager userManager, String resource) public Connection getConnection() {
throws UserNotFoundException, UnauthorizedException; return conn;
}
/** /**
* <p>Initialize the session as an anonymous login.</p> * Obtain the current status of this session.
* <p>This automatically upgrades the session's *
* status to authenticated and enables many features that are not * @return The status code for this session
* available until authenticated (obtaining managers for example).</p>
*/ */
public void setAnonymousAuth() throws UnauthorizedException; public int getStatus() {
return status;
}
/** /**
* <p>Obtain the authentication token associated with this session.</p> * Set the new status of this session. Setting a status may trigger
* certain events to occur (setting a closed status will close this
* session).
* *
* @return The authentication token associated with this session (can be null) * @param status The new status code for this session
*/ */
public AuthToken getAuthToken(); public void setStatus(int status) {
this.status = status;
}
/** /**
* Obtain the stream ID associated with this sesison. Stream ID's are generated by the server * Obtain the stream ID associated with this sesison. Stream ID's are generated by the server
...@@ -152,85 +144,68 @@ public interface Session extends RoutableChannelHandler { ...@@ -152,85 +144,68 @@ public interface Session extends RoutableChannelHandler {
* *
* @return This session's assigned stream ID * @return This session's assigned stream ID
*/ */
public StreamID getStreamID(); public StreamID getStreamID() {
return streamID;
/** }
* Returns the username associated with this session. Use this information
* with the user manager to obtain the user based on username.
*
* @return the username associated with this session
* @throws UserNotFoundException if a user is not associated with a session
* (the session has not authenticated yet)
* @throws UnauthorizedException If caller doesn't have permission to access this information.
*/
public String getUsername() throws UserNotFoundException, UnauthorizedException;
/** /**
* Obtain the name of the server this session belongs to. * Obtain the name of the server this session belongs to.
* *
* @return the server name. * @return the server name.
*/ */
public String getServerName(); public String getServerName() {
return serverName;
}
/** /**
* Obtain the date the session was created. * Obtain the date the session was created.
* *
* @return the session's creation date. * @return the session's creation date.
*/ */
public Date getCreationDate(); public Date getCreationDate() {
return startDate;
}
/** /**
* Obtain the time the session last had activity. * Obtain the time the session last had activity.
* *
* @return The last time the session received activity. * @return The last time the session received activity.
*/ */
public Date getLastActiveDate(); public Date getLastActiveDate() {
return new Date(lastActiveDate);
}
/** /**
* Obtain the number of packets sent from the client to the server. * Obtain the number of packets sent from the client to the server.
*
* @throws UnauthorizedException If caller doesn't have permission to access this information
*/ */
public void incrementClientPacketCount() throws UnauthorizedException; public void incrementClientPacketCount() {
clientPacketCount++;
lastActiveDate = System.currentTimeMillis();
}
/** /**
* Obtain the number of packets sent from the server to the client. * Obtain the number of packets sent from the server to the client.
*
* @throws UnauthorizedException If caller doesn't have permission to access this information
*/ */
public void incrementServerPacketCount() throws UnauthorizedException; public void incrementServerPacketCount() {
serverPacketCount++;
lastActiveDate = System.currentTimeMillis();
}
/** /**
* Obtain the number of packets sent from the client to the server. * Obtain the number of packets sent from the client to the server.
* *
* @return The number of packets sent from the client to the server. * @return The number of packets sent from the client to the server.
*/ */
public long getNumClientPackets(); public long getNumClientPackets() {
return clientPacketCount;
}
/** /**
* Obtain the number of packets sent from the server to the client. * Obtain the number of packets sent from the server to the client.
* *
* @return The number of packets sent from the server to the client. * @return The number of packets sent from the server to the client.
*/ */
public long getNumServerPackets(); public long getNumServerPackets() {
return serverPacketCount;
/** }
* Returns the number of conflicts detected on this session.
* Conflicts typically occur when another session authenticates properly
* to the user account and requests to use a resource matching the one
* in use by this session. Administrators may configure the server to automatically
* kick off existing sessions when their conflict count exceeds some limit including
* 0 (old sessions are kicked off immediately to accommodate new sessions). Conflicts
* typically signify the existing (old) session is broken/hung.
*
* @return The number of conflicts detected for this session
*/
public int getConflictCount();
/**
* Increments the conflict by one.
*
* @throws UnauthorizedException If caller doesn't have permission to access this information
*/
public void incrementConflictCount() throws UnauthorizedException;
} }
\ No newline at end of file
...@@ -22,11 +22,12 @@ import java.util.LinkedList; ...@@ -22,11 +22,12 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import org.jivesoftware.messenger.audit.AuditStreamIDFactory; import org.jivesoftware.messenger.audit.AuditStreamIDFactory;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.container.BasicModule; import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.spi.BasicStreamIDFactory; import org.jivesoftware.messenger.spi.BasicStreamIDFactory;
import org.jivesoftware.messenger.spi.SessionImpl;
import org.jivesoftware.messenger.user.UserManager; import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException; import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.messenger.handler.PresenceUpdateHandler; import org.jivesoftware.messenger.handler.PresenceUpdateHandler;
...@@ -44,7 +45,7 @@ import org.xmpp.packet.Presence; ...@@ -44,7 +45,7 @@ import org.xmpp.packet.Presence;
* *
* @author Derek DeMoro * @author Derek DeMoro
*/ */
public class SessionManager extends BasicModule implements ConnectionCloseListener { public class SessionManager extends BasicModule {
private int sessionCount = 0; private int sessionCount = 0;
public static final int NEVER_KICK = -1; public static final int NEVER_KICK = -1;
...@@ -56,7 +57,42 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -56,7 +57,42 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
private UserManager userManager; private UserManager userManager;
private int conflictLimit; private int conflictLimit;
private Map<String, Session> preAuthenticatedSessions = new ConcurrentHashMap<String, Session>(); private ClientSessionListener clientSessionListener = new ClientSessionListener();
private ComponentSessionListener componentSessionListener = new ComponentSessionListener();
/**
* Map that holds sessions that has been created but haven't been authenticated yet. The Map
* will hold client sessions.
*/
private Map<String, ClientSession> preAuthenticatedSessions = new ConcurrentHashMap<String, ClientSession>();
/**
* Map of priority ordered SessionMap objects with username (toLowerCase) as key. The sessions
* contained in this Map are client sessions. For each username a SessionMap is kept which
* tracks the session for each user resource.
*/
private Map<String, SessionMap> sessions = new ConcurrentHashMap<String, SessionMap>();
/**
* Map of anonymous server sessions. They need to be treated separately as they
* have no associated user, and don't follow the normal routing rules for
* priority based fall over. The sessions contained in this Map are client sessions.
*/
private Map<String, ClientSession> anonymousSessions = new ConcurrentHashMap<String, ClientSession>();
/**
* The sessions contained in this List are component sessions. For each connected component
* this Map will keep the component's session.
*/
private List<ComponentSession> componentsSessions = new CopyOnWriteArrayList<ComponentSession>();
/**
* <p>Session manager must maintain the routing table as sessions are added and
* removed.</p>
*/
private RoutingTable routingTable;
private StreamIDFactory streamIDFactory;
/** /**
* Returns the instance of <CODE>SessionManagerImpl</CODE> being used by the XMPPServer. * Returns the instance of <CODE>SessionManagerImpl</CODE> being used by the XMPPServer.
...@@ -92,31 +128,12 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -92,31 +128,12 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
} }
} }
/**
* Map of priority ordered SessionMap objects with username (toLowerCase) as key.
* The map and its contents should NOT be persisted to disk.
*/
private Map<String, SessionMap> sessions = new ConcurrentHashMap<String, SessionMap>();
/**
* <p>Session manager must maintain the routing table as sessions are added and
* removed.</p>
*/
private RoutingTable routingTable;
/**
* Map of anonymous server sessions. They need to be treated separately as they
* have no associated user, and don't follow the normal routing rules for
* priority based fall over.
*/
private Map<String, Session> anonymousSessions = new ConcurrentHashMap<String, Session>();
/** /**
* Simple data structure to track sessions for a single user (tracked by resource * Simple data structure to track sessions for a single user (tracked by resource
* and priority). * and priority).
*/ */
private class SessionMap { private class SessionMap {
private Map<String,Session> resources = new HashMap<String,Session>(); private Map<String,ClientSession> resources = new HashMap<String,ClientSession>();
private LinkedList priorityList = new LinkedList(); private LinkedList priorityList = new LinkedList();
/** /**
...@@ -124,7 +141,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -124,7 +141,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
* *
* @param session * @param session
*/ */
void addSession(Session session) { void addSession(ClientSession session) {
String resource = session.getAddress().getResource(); String resource = session.getAddress().getResource();
resources.put(resource, session); resources.put(resource, session);
Presence presence = session.getPresence(); Presence presence = session.getPresence();
...@@ -143,7 +160,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -143,7 +160,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
if (priorityList.size() > 0) { if (priorityList.size() > 0) {
Iterator iter = priorityList.iterator(); Iterator iter = priorityList.iterator();
for (int i = 0; iter.hasNext(); i++) { for (int i = 0; iter.hasNext(); i++) {
Session sess = resources.get(iter.next()); ClientSession sess = resources.get(iter.next());
if (sess.getPresence().getPriority() <= priority) { if (sess.getPresence().getPriority() <= priority) {
priorityList.add(i, resource); priorityList.add(i, resource);
break; break;
...@@ -186,7 +203,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -186,7 +203,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
* @param resource The resource describing the particular session * @param resource The resource describing the particular session
* @return The session for that resource or null if none found (use getDefaultSession() to obtain default) * @return The session for that resource or null if none found (use getDefaultSession() to obtain default)
*/ */
Session getSession(String resource) { ClientSession getSession(String resource) {
return resources.get(resource); return resources.get(resource);
} }
...@@ -209,7 +226,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -209,7 +226,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
* considered. * considered.
* @return The default session for the user. * @return The default session for the user.
*/ */
Session getDefaultSession(boolean filterAvailable) { ClientSession getDefaultSession(boolean filterAvailable) {
if (priorityList.isEmpty()) { if (priorityList.isEmpty()) {
return null; return null;
} }
...@@ -219,7 +236,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -219,7 +236,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
} }
else { else {
for (int i=0; i < priorityList.size(); i++) { for (int i=0; i < priorityList.size(); i++) {
Session s = resources.get(priorityList.get(i)); ClientSession s = resources.get(priorityList.get(i));
if (s.getPresence().isAvailable()) { if (s.getPresence().isAvailable()) {
return s; return s;
} }
...@@ -269,9 +286,9 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -269,9 +286,9 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
* *
* @return a collection of all the sessions whose presence is available. * @return a collection of all the sessions whose presence is available.
*/ */
public Collection<Session> getAvailableSessions() { public Collection<ClientSession> getAvailableSessions() {
LinkedList<Session> list = new LinkedList<Session>(); LinkedList<ClientSession> list = new LinkedList<ClientSession>();
for (Session session : resources.values()) { for (ClientSession session : resources.values()) {
if (session.getPresence().isAvailable()) { if (session.getPresence().isAvailable()) {
list.add(session); list.add(session);
} }
...@@ -280,58 +297,66 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -280,58 +297,66 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
} }
} }
private StreamIDFactory streamIDFactory;
/** /**
* Creates a new <tt>Session</tt>. * Creates a new <tt>ClientSession</tt>.
* *
* @param conn the connection to create the session from. * @param conn the connection to create the session from.
* @return a newly created session. * @return a newly created session.
* @throws UnauthorizedException * @throws UnauthorizedException
*/ */
public Session createSession(Connection conn) throws UnauthorizedException { public Session createClientSession(Connection conn) throws UnauthorizedException {
if (serverName == null) { if (serverName == null) {
throw new UnauthorizedException("Server not initialized"); throw new UnauthorizedException("Server not initialized");
} }
StreamID id = streamIDFactory.createStreamID(); StreamID id = streamIDFactory.createStreamID();
Session session = new SessionImpl(serverName, conn, id); ClientSession session = new ClientSession(serverName, conn, id);
conn.init(session); conn.init(session);
conn.registerCloseListener(this, session); // Register to receive close notification on this session so we can
// remove its route from the sessions set and also send an unavailable presence if it wasn't
// sent before
conn.registerCloseListener(clientSessionListener, session);
// Add to pre-authenticated sessions. // Add to pre-authenticated sessions.
preAuthenticatedSessions.put(session.getAddress().toString(), session); preAuthenticatedSessions.put(session.getAddress().toString(), session);
return session; return session;
} }
public Session createComponentSession(Connection conn) throws UnauthorizedException {
if (serverName == null) {
throw new UnauthorizedException("Server not initialized");
}
StreamID id = streamIDFactory.createStreamID();
ComponentSession session = new ComponentSession(serverName, conn, id);
conn.init(session);
// Register to receive close notification on this session so we can
// remove the external component from the list of components
conn.registerCloseListener(componentSessionListener, session);
// Add to component session.
componentsSessions.add(session);
return session;
}
/** /**
* Add a new session to be managed. * Add a new session to be managed.
*/ */
public boolean addSession(Session session) { public boolean addSession(ClientSession session) {
boolean success = false; boolean success = false;
String username = session.getAddress().getNode().toLowerCase(); String username = session.getAddress().getNode().toLowerCase();
SessionMap resources = null; SessionMap resources = null;
synchronized(username.intern()) { synchronized(username.intern()) {
try {
resources = sessions.get(username); resources = sessions.get(username);
if (resources == null) { if (resources == null) {
resources = new SessionMap(); resources = new SessionMap();
sessions.put(username, resources); sessions.put(username, resources);
} }
resources.addSession(session); resources.addSession(session);
// Register to recieve close notification on this session so we can
// remove its route from the sessions set. We hand the session back
// to ourselves in the message.
session.getConnection().registerCloseListener(this, session);
// Remove the pre-Authenticated session but remember to use the temporary JID as the key // Remove the pre-Authenticated session but remember to use the temporary JID as the key
preAuthenticatedSessions.remove(new JID(null, session.getAddress().getDomain(), preAuthenticatedSessions.remove(new JID(null, session.getAddress().getDomain(),
session.getStreamID().toString()).toString()); session.getStreamID().toString()).toString());
success = true; success = true;
} }
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
return success; return success;
} }
...@@ -343,7 +368,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -343,7 +368,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
* *
* @param session the session that receieved an available presence. * @param session the session that receieved an available presence.
*/ */
public void sessionAvailable(Session session) { public void sessionAvailable(ClientSession session) {
if (anonymousSessions.containsValue(session)) { if (anonymousSessions.containsValue(session)) {
// Anonymous session always have resources so we only need to add one route. That is // Anonymous session always have resources so we only need to add one route. That is
// the route to the anonymous session // the route to the anonymous session
...@@ -379,12 +404,12 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -379,12 +404,12 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
* @param session the session that received the new presence and therefore will not receive * @param session the session that received the new presence and therefore will not receive
* the notification. * the notification.
*/ */
private void broadcastPresenceToOtherResource(Session session) throws UserNotFoundException, private void broadcastPresenceToOtherResource(ClientSession session)
UnauthorizedException { throws UserNotFoundException, UnauthorizedException {
Presence presence = null; Presence presence = null;
SessionMap sessionMap = sessions.get(session.getUsername()); SessionMap sessionMap = sessions.get(session.getUsername());
if (sessionMap != null) { if (sessionMap != null) {
for (Session userSession : sessionMap.getAvailableSessions()) { for (ClientSession userSession : sessionMap.getAvailableSessions()) {
if (userSession != session) { if (userSession != session) {
// Send the presence of an existing session to the session that has just changed // Send the presence of an existing session to the session that has just changed
// the presence // the presence
...@@ -410,7 +435,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -410,7 +435,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
* *
* @param session the session that receieved an unavailable presence. * @param session the session that receieved an unavailable presence.
*/ */
public void sessionUnavailable(Session session) { public void sessionUnavailable(ClientSession session) {
if (session.getAddress() != null && routingTable != null && if (session.getAddress() != null && routingTable != null &&
session.getAddress().toBareJID().trim().length() != 0) { session.getAddress().toBareJID().trim().length() != 0) {
// Remove route to the removed session (anonymous or not) // Remove route to the removed session (anonymous or not)
...@@ -497,7 +522,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -497,7 +522,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
* @return The XMPPAddress best suited to use for delivery to the recipient * @return The XMPPAddress best suited to use for delivery to the recipient
*/ */
public Session getBestRoute(JID recipient) { public Session getBestRoute(JID recipient) {
Session session = null; ClientSession session = null;
String resource = recipient.getResource(); String resource = recipient.getResource();
String username = recipient.getNode(); String username = recipient.getNode();
if (username == null || "".equals(username)) { if (username == null || "".equals(username)) {
...@@ -576,16 +601,16 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -576,16 +601,16 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
* @param from the sender of the packet. * @param from the sender of the packet.
* @return the <code>Session</code> associated with the JID. * @return the <code>Session</code> associated with the JID.
*/ */
public Session getSession(JID from) { public ClientSession getSession(JID from) {
if (from == null) { if (from == null) {
return null; return null;
} }
Session session = null; ClientSession session = null;
// Initially Check preAuthenticated Sessions // Initially Check preAuthenticated Sessions
session = preAuthenticatedSessions.get(from.toString()); session = preAuthenticatedSessions.get(from.toString());
if(session != null){ if(session != null){
return session; return (ClientSession)session;
} }
String resource = from.getResource(); String resource = from.getResource();
...@@ -620,8 +645,8 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -620,8 +645,8 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
} }
public Collection<Session> getSessions(SessionResultFilter filter) { public Collection<ClientSession> getSessions(SessionResultFilter filter) {
List<Session> results = new ArrayList<Session>(); List<ClientSession> results = new ArrayList<ClientSession>();
if (filter != null) { if (filter != null) {
// Grab all the possible matching sessions by user // Grab all the possible matching sessions by user
if (filter.getUsername() == null) { if (filter.getUsername() == null) {
...@@ -646,8 +671,8 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -646,8 +671,8 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
// Now we have a copy of the references so we can spend some time // Now we have a copy of the references so we can spend some time
// doing the rest of the filtering without locking out session access // doing the rest of the filtering without locking out session access
// so let's iterate and filter each session one by one // so let's iterate and filter each session one by one
List<Session> filteredResults = new ArrayList<Session>(); List<ClientSession> filteredResults = new ArrayList<ClientSession>();
for (Session session : results) { for (ClientSession session : results) {
// Now filter on creation date if needed // Now filter on creation date if needed
if (createMin != null || createMax != null) { if (createMin != null || createMax != null) {
if (!isBetweenDates(session.getCreationDate(), createMin, createMax)) { if (!isBetweenDates(session.getCreationDate(), createMin, createMax)) {
...@@ -689,11 +714,11 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -689,11 +714,11 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
// Now generate the final list. I believe it's faster to to build up a new // Now generate the final list. I believe it's faster to to build up a new
// list than it is to remove items from head and tail of the sorted tree // list than it is to remove items from head and tail of the sorted tree
List<Session> finalResults = new ArrayList<Session>(); List<ClientSession> finalResults = new ArrayList<ClientSession>();
int startIndex = filter.getStartIndex(); int startIndex = filter.getStartIndex();
Iterator<Session> sortedIter = filteredResults.iterator(); Iterator<ClientSession> sortedIter = filteredResults.iterator();
for (int i = 0; sortedIter.hasNext() && finalResults.size() < maxResults; i++) { for (int i = 0; sortedIter.hasNext() && finalResults.size() < maxResults; i++) {
Session result = sortedIter.next(); ClientSession result = sortedIter.next();
if (i >= startIndex) { if (i >= startIndex) {
finalResults.add(result); finalResults.add(result);
} }
...@@ -763,7 +788,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -763,7 +788,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
private void copyUserSessions(List sessions) { private void copyUserSessions(List sessions) {
// Get a copy of the sessions from all users // Get a copy of the sessions from all users
for (String username : getSessionUsers()) { for (String username : getSessionUsers()) {
Collection<Session> usrSessions = getSessions(username); Collection<ClientSession> usrSessions = getSessions(username);
for (Session session : usrSessions) { for (Session session : usrSessions) {
sessions.add(session); sessions.add(session);
} }
...@@ -785,8 +810,8 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -785,8 +810,8 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
return Arrays.asList(anonymousSessions.values().toArray()).iterator(); return Arrays.asList(anonymousSessions.values().toArray()).iterator();
} }
public Collection<Session> getSessions(String username) { public Collection<ClientSession> getSessions(String username) {
List<Session> sessionList = new ArrayList<Session>(); List<ClientSession> sessionList = new ArrayList<ClientSession>();
if (username != null) { if (username != null) {
copyUserSessions(username, sessionList); copyUserSessions(username, sessionList);
} }
...@@ -859,7 +884,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -859,7 +884,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
* *
* @param session the session. * @param session the session.
*/ */
public void removeSession(Session session) { public void removeSession(ClientSession session) {
// TODO: Requires better error checking to ensure the session count is maintained // TODO: Requires better error checking to ensure the session count is maintained
// TODO: properly (removal actually does remove). // TODO: properly (removal actually does remove).
if (session == null) { if (session == null) {
...@@ -901,17 +926,11 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -901,17 +926,11 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
} }
} }
public void addAnonymousSession(Session session) { public void addAnonymousSession(ClientSession session) {
try {
anonymousSessions.put(session.getAddress().getResource(), session); anonymousSessions.put(session.getAddress().getResource(), session);
session.getConnection().registerCloseListener(this, session);
// Remove the session from the pre-Authenticated sessions list // Remove the session from the pre-Authenticated sessions list
preAuthenticatedSessions.remove(session.getAddress().toString()); preAuthenticatedSessions.remove(session.getAddress().toString());
} }
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
public int getConflictKickLimit() { public int getConflictKickLimit() {
return conflictLimit; return conflictLimit;
...@@ -922,6 +941,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -922,6 +941,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
JiveGlobals.setProperty("xmpp.session.conflict-limit", Integer.toString(conflictLimit)); JiveGlobals.setProperty("xmpp.session.conflict-limit", Integer.toString(conflictLimit));
} }
private class ClientSessionListener implements ConnectionCloseListener {
/** /**
* Handle a session that just closed. * Handle a session that just closed.
* *
...@@ -929,7 +949,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -929,7 +949,7 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
*/ */
public void onConnectionClose(Object handback) { public void onConnectionClose(Object handback) {
try { try {
Session session = (Session)handback; ClientSession session = (ClientSession)handback;
if (session.getPresence().isAvailable()) { if (session.getPresence().isAvailable()) {
// Send an unavailable presence to the user's subscribers // Send an unavailable presence to the user's subscribers
// Note: This gives us a chance to send an unavailable presence to the // Note: This gives us a chance to send an unavailable presence to the
...@@ -947,6 +967,28 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen ...@@ -947,6 +967,28 @@ public class SessionManager extends BasicModule implements ConnectionCloseListen
Log.error(LocaleUtils.getLocalizedString("admin.error.close"), e); Log.error(LocaleUtils.getLocalizedString("admin.error.close"), e);
} }
} }
}
private class ComponentSessionListener implements ConnectionCloseListener {
/**
* Handle a session that just closed.
*
* @param handback The session that just closed
*/
public void onConnectionClose(Object handback) {
try {
ComponentSession session = (ComponentSession)handback;
// Unbind the domain for this external component
ComponentManager.getInstance().removeComponent(session.getAddress().getDomain());
// Remove the session
componentsSessions.remove(session);
}
catch (Exception e) {
// Can't do anything about this problem...
Log.error(LocaleUtils.getLocalizedString("admin.error.close"), e);
}
}
}
public void initialize(XMPPServer server) { public void initialize(XMPPServer server) {
super.initialize(server); super.initialize(server);
......
...@@ -11,23 +11,24 @@ ...@@ -11,23 +11,24 @@
package org.jivesoftware.messenger.handler; package org.jivesoftware.messenger.handler;
import org.jivesoftware.util.LocaleUtils; import org.dom4j.DocumentHelper;
import org.jivesoftware.util.Log; import org.dom4j.Element;
import org.dom4j.QName;
import org.jivesoftware.messenger.*; import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.AuthFactory; import org.jivesoftware.messenger.auth.AuthFactory;
import org.jivesoftware.messenger.auth.AuthToken; import org.jivesoftware.messenger.auth.AuthToken;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserManager; import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException; import org.jivesoftware.messenger.user.UserNotFoundException;
import java.util.ArrayList; import org.jivesoftware.util.LocaleUtils;
import java.util.List; import org.jivesoftware.util.Log;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.xmpp.packet.IQ; import org.xmpp.packet.IQ;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError; import org.xmpp.packet.PacketError;
import java.util.ArrayList;
import java.util.List;
/** /**
* Implements the TYPE_IQ jabber:iq:auth protocol (plain only). Clients * Implements the TYPE_IQ jabber:iq:auth protocol (plain only). Clients
* use this protocol to authenticate with the server. A 'get' query * use this protocol to authenticate with the server. A 'get' query
...@@ -79,7 +80,7 @@ public class IQAuthHandler extends IQHandler implements IQAuthInfo { ...@@ -79,7 +80,7 @@ public class IQAuthHandler extends IQHandler implements IQAuthInfo {
public IQ handleIQ(IQ packet) throws UnauthorizedException, PacketException { public IQ handleIQ(IQ packet) throws UnauthorizedException, PacketException {
try { try {
Session session = sessionManager.getSession(packet.getFrom()); ClientSession session = sessionManager.getSession(packet.getFrom());
IQ response = null; IQ response = null;
try { try {
Element iq = packet.getElement(); Element iq = packet.getElement();
...@@ -146,14 +147,15 @@ public class IQAuthHandler extends IQHandler implements IQAuthInfo { ...@@ -146,14 +147,15 @@ public class IQAuthHandler extends IQHandler implements IQAuthInfo {
} }
private IQ login(String username, Element iq, IQ packet, IQ response, String password, private IQ login(String username, Element iq, IQ packet, IQ response, String password,
Session session, String digest) throws UnauthorizedException, UserNotFoundException ClientSession session, String digest) throws UnauthorizedException,
UserNotFoundException
{ {
JID jid = localServer.createJID(username, iq.elementTextTrim("resource")); JID jid = localServer.createJID(username, iq.elementTextTrim("resource"));
// If a session already exists with the requested JID, then check to see // If a session already exists with the requested JID, then check to see
// if we should kick it off or refuse the new connection // if we should kick it off or refuse the new connection
if (sessionManager.isActiveRoute(jid)) { if (sessionManager.isActiveRoute(jid)) {
Session oldSession = null; ClientSession oldSession = null;
try { try {
oldSession = sessionManager.getSession(jid); oldSession = sessionManager.getSession(jid);
oldSession.incrementConflictCount(); oldSession.incrementConflictCount();
...@@ -218,7 +220,7 @@ public class IQAuthHandler extends IQHandler implements IQAuthInfo { ...@@ -218,7 +220,7 @@ public class IQAuthHandler extends IQHandler implements IQAuthInfo {
return response; return response;
} }
private IQ anonymousLogin(Session session, IQ packet) throws UnauthorizedException { private IQ anonymousLogin(ClientSession session, IQ packet) {
IQ response = IQ.createResultIQ(packet);; IQ response = IQ.createResultIQ(packet);;
if (anonymousAllowed) { if (anonymousAllowed) {
session.setAnonymousAuth(); session.setAnonymousAuth();
......
...@@ -11,30 +11,32 @@ ...@@ -11,30 +11,32 @@
package org.jivesoftware.messenger.handler; package org.jivesoftware.messenger.handler;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.disco.ServerFeaturesProvider; import org.jivesoftware.messenger.disco.ServerFeaturesProvider;
import org.jivesoftware.messenger.forms.DataForm; import org.jivesoftware.messenger.forms.DataForm;
import org.jivesoftware.messenger.forms.FormField; import org.jivesoftware.messenger.forms.FormField;
import org.jivesoftware.messenger.forms.spi.XDataFormImpl; import org.jivesoftware.messenger.forms.spi.XDataFormImpl;
import org.jivesoftware.messenger.forms.spi.XFormFieldImpl; import org.jivesoftware.messenger.forms.spi.XFormFieldImpl;
import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.group.GroupManager; import org.jivesoftware.messenger.group.GroupManager;
import org.jivesoftware.messenger.roster.RosterManager; import org.jivesoftware.messenger.roster.RosterManager;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.user.User;
import org.jivesoftware.messenger.user.*; import org.jivesoftware.messenger.user.UserAlreadyExistsException;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.util.Log;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError;
/** /**
* Implements the TYPE_IQ jabber:iq:register protocol (plain only). Clients * Implements the TYPE_IQ jabber:iq:register protocol (plain only). Clients
* use this protocol to register a user account with the server. * use this protocol to register a user account with the server.
...@@ -146,7 +148,7 @@ public class IQRegisterHandler extends IQHandler implements ServerFeaturesProvid ...@@ -146,7 +148,7 @@ public class IQRegisterHandler extends IQHandler implements ServerFeaturesProvid
return delegate.handleIQ(packet); return delegate.handleIQ(packet);
} }
Session session = sessionManager.getSession(packet.getFrom()); ClientSession session = sessionManager.getSession(packet.getFrom());
IQ reply = null; IQ reply = null;
// If inband registration is not allowed, return an error. // If inband registration is not allowed, return an error.
if (!enabled) { if (!enabled) {
...@@ -185,9 +187,6 @@ public class IQRegisterHandler extends IQHandler implements ServerFeaturesProvid ...@@ -185,9 +187,6 @@ public class IQRegisterHandler extends IQHandler implements ServerFeaturesProvid
catch (UserNotFoundException e) { catch (UserNotFoundException e) {
reply.setChildElement(probeResult.createCopy()); reply.setChildElement(probeResult.createCopy());
} }
catch (UnauthorizedException e) {
reply.setChildElement(probeResult.createCopy());
}
} }
else { else {
// This is a workaround. Since we don't want to have an incorrect TO attribute // This is a workaround. Since we don't want to have an incorrect TO attribute
......
...@@ -11,15 +11,21 @@ ...@@ -11,15 +11,21 @@
package org.jivesoftware.messenger.handler; package org.jivesoftware.messenger.handler;
import org.jivesoftware.messenger.disco.ServerFeaturesProvider;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.*; import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.roster.*;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.*; import org.jivesoftware.messenger.disco.ServerFeaturesProvider;
import org.jivesoftware.messenger.roster.Roster; import org.jivesoftware.messenger.roster.Roster;
import org.xmpp.packet.*; import org.jivesoftware.messenger.roster.RosterItem;
import org.jivesoftware.messenger.user.User;
import org.jivesoftware.messenger.user.UserAlreadyExistsException;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import org.xmpp.packet.PacketError;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
...@@ -157,7 +163,7 @@ public class IQRosterHandler extends IQHandler implements ServerFeaturesProvider ...@@ -157,7 +163,7 @@ public class IQRosterHandler extends IQHandler implements ServerFeaturesProvider
UserAlreadyExistsException, SharedGroupException { UserAlreadyExistsException, SharedGroupException {
IQ returnPacket = null; IQ returnPacket = null;
Session session = sessionManager.getSession(packet.getFrom()); ClientSession session = sessionManager.getSession(packet.getFrom());
IQ.Type type = packet.getType(); IQ.Type type = packet.getType();
......
...@@ -11,18 +11,9 @@ ...@@ -11,18 +11,9 @@
package org.jivesoftware.messenger.net; package org.jivesoftware.messenger.net;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import java.net.Socket;
import java.net.SocketException;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.io.XPPPacketReader; import org.dom4j.io.XPPPacketReader;
import org.jivesoftware.messenger.Connection; import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.PacketRouter;
import org.jivesoftware.messenger.Session;
import org.jivesoftware.messenger.audit.Auditor; import org.jivesoftware.messenger.audit.Auditor;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.util.LocaleUtils; import org.jivesoftware.util.LocaleUtils;
...@@ -35,6 +26,13 @@ import org.xmpp.packet.Message; ...@@ -35,6 +26,13 @@ import org.xmpp.packet.Message;
import org.xmpp.packet.Presence; import org.xmpp.packet.Presence;
import org.xmpp.packet.Roster; import org.xmpp.packet.Roster;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import java.net.Socket;
import java.net.SocketException;
/** /**
* Reads XMPP XML from a socket. * Reads XMPP XML from a socket.
* *
...@@ -47,9 +45,6 @@ public class SocketReadThread extends Thread { ...@@ -47,9 +45,6 @@ public class SocketReadThread extends Thread {
*/ */
private static String CHARSET = "UTF-8"; private static String CHARSET = "UTF-8";
private static final String ETHERX_NAMESPACE = "http://etherx.jabber.org/streams";
private static final String FLASH_NAMESPACE = "http://www.jabber.com/streams/flash";
private Socket sock; private Socket sock;
private Session session; private Session session;
private Connection connection; private Connection connection;
...@@ -73,16 +68,15 @@ public class SocketReadThread extends Thread { ...@@ -73,16 +68,15 @@ public class SocketReadThread extends Thread {
* @param serverName The name of the server this socket is working for * @param serverName The name of the server this socket is working for
* @param auditor The audit manager that will audit incoming packets * @param auditor The audit manager that will audit incoming packets
* @param sock The socket to read from * @param sock The socket to read from
* @param session The session being read * @param conn The connection being read
*/ */
public SocketReadThread(PacketRouter router, String serverName, Auditor auditor, Socket sock, public SocketReadThread(PacketRouter router, String serverName, Auditor auditor, Socket sock,
Session session) { Connection conn) {
super("SRT reader"); super("SRT reader");
this.serverName = serverName; this.serverName = serverName;
this.router = router; this.router = router;
this.auditor = auditor; this.auditor = auditor;
this.session = session; this.connection = conn;
connection = session.getConnection();
this.sock = sock; this.sock = sock;
} }
...@@ -122,7 +116,8 @@ public class SocketReadThread extends Thread { ...@@ -122,7 +116,8 @@ public class SocketReadThread extends Thread {
// unavailable presence // unavailable presence
if (clearSignout == false) { if (clearSignout == false) {
if (session != null && session.getStatus() == Session.STATUS_AUTHENTICATED) { if (session != null && session.getStatus() == Session.STATUS_AUTHENTICATED) {
Presence presence = session.getPresence(); if (session instanceof ClientSession) {
Presence presence = ((ClientSession) session).getPresence();
if (presence != null) { if (presence != null) {
// Simulate an unavailable presence sent by the user. // Simulate an unavailable presence sent by the user.
Presence packet = presence.createCopy(); Presence packet = presence.createCopy();
...@@ -133,6 +128,7 @@ public class SocketReadThread extends Thread { ...@@ -133,6 +128,7 @@ public class SocketReadThread extends Thread {
} }
} }
} }
}
// It is normal for clients to abruptly cut a connection // It is normal for clients to abruptly cut a connection
// rather than closing the stream document // rather than closing the stream document
// Since this is normal behavior, we won't log it as an error // Since this is normal behavior, we won't log it as an error
...@@ -224,88 +220,44 @@ public class SocketReadThread extends Thread { ...@@ -224,88 +220,44 @@ public class SocketReadThread extends Thread {
} }
/** /**
* Uses the XPP to grab the opening stream tag and create * Uses the XPP to grab the opening stream tag and create an active session
* an active session object. In all cases, the method obtains the * object. The session to create will depend on the sent namespace. In all
* opening stream tag, checks for errors, and either creates a session * cases, the method obtains the opening stream tag, checks for errors, and
* or returns an error and kills the connection. If the connection * either creates a session or returns an error and kills the connection.
* remains open, the XPP will be set to be ready for the first packet. * If the connection remains open, the XPP will be set to be ready for the
* A call to next() should result in an START_TAG state with the first * first packet. A call to next() should result in an START_TAG state with
* packet in the stream. * the first packet in the stream.
*
* @throws UnauthorizedException If the caller did not have permission
* to use this method.
*/ */
private void createSession() throws UnauthorizedException, XmlPullParserException, IOException, Exception { private void createSession() throws UnauthorizedException, XmlPullParserException, IOException {
XmlPullParser xpp = reader.getXPPParser(); XmlPullParser xpp = reader.getXPPParser();
for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) { for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) {
eventType = xpp.next(); eventType = xpp.next();
} }
boolean isFlashClient = xpp.getPrefix().equals("flash"); // Create the correct session based on the sent namespace
// Conduct error checking, the opening tag should be 'stream' if ("jabber:client".equals(xpp.getNamespaceUri(xpp.getDepth()-1))) {
// in the 'etherx' namespace // The connected client is a regular client so create a ClientSession
if (!xpp.getName().equals("stream") && !isFlashClient) { session = ClientSession.createSession(serverName, reader, connection);
throw new XmlPullParserException(LocaleUtils.getLocalizedString("admin.error.bad-stream"));
} }
else if ("jabber:component:accept".equals(xpp.getNamespaceUri(xpp.getDepth()-1))) {
if (!xpp.getNamespace(xpp.getPrefix()).equals(ETHERX_NAMESPACE) && // The connected client is a component so create a ComponentSession
!(isFlashClient && xpp.getNamespace(xpp.getPrefix()).equals(FLASH_NAMESPACE))) { session = ComponentSession.createSession(serverName, reader, connection);
throw new XmlPullParserException(LocaleUtils.getLocalizedString("admin.error.bad-namespace"));
}
// TODO Should we keep the language requested by the client in the session so that future
// messages to the client may use the correct resource bundle? So far we are only answering
// the same language specified by the client (if any) or if none then answer a default
// language
String language = "en";
for (int i = 0; i < xpp.getAttributeCount(); i++) {
if ("lang".equals(xpp.getAttributeName(i))) {
language = xpp.getAttributeValue(i);
} }
} else {
Writer writer = connection.getWriter(); Writer writer = connection.getWriter();
// Build the start packet response
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
sb.append("<?xml version='1.0' encoding='"); sb.append("<?xml version='1.0' encoding='");
sb.append(CHARSET); sb.append(CHARSET);
sb.append("'?>"); sb.append("'?>");
if (isFlashClient) { // Include the bad-namespace-prefix in the response
sb.append("<flash:stream xmlns:flash=\"http://www.jabber.com/streams/flash\" "); sb.append("<stream:error>");
} sb.append("<bad-namespace-prefix xmlns=\"urn:ietf:params:xml:ns:xmpp-streams\"/>");
else { sb.append("</stream:error>");
sb.append("<stream:stream "); 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);
sb.append("\">");
writer.write(sb.toString()); writer.write(sb.toString());
// If this is a flash client then flag the connection and append a special caracter to the
// response
if (isFlashClient) {
session.getConnection().setFlashClient(true);
writer.write('\0');
// Skip possible end of tags and \0 characters
/*final int[] holderForStartAndLength = new int[2];
final char[] chars = xpp.getTextCharacters(holderForStartAndLength);
if (chars[xpp.getColumnNumber()-2] == '/') {
xpp.next();
try {
xpp.next();
}
catch (XmlPullParserException ie) {
// We expect this exception since the parser is reading a \0 character
}
}*/
}
writer.flush(); writer.flush();
// TODO: check for SASL support in opening stream tag // Close the underlying connection
connection.close();
}
} }
} }
...@@ -11,16 +11,16 @@ ...@@ -11,16 +11,16 @@
package org.jivesoftware.messenger.spi; package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.*; import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.audit.AuditManager; import org.jivesoftware.messenger.audit.AuditManager;
import org.jivesoftware.messenger.auth.UnauthorizedException; import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.net.SSLSocketAcceptThread; import org.jivesoftware.messenger.net.SSLSocketAcceptThread;
import org.jivesoftware.messenger.net.SocketAcceptThread; import org.jivesoftware.messenger.net.SocketAcceptThread;
import org.jivesoftware.messenger.net.SocketConnection; import org.jivesoftware.messenger.net.SocketConnection;
import org.jivesoftware.messenger.net.SocketReadThread; import org.jivesoftware.messenger.net.SocketReadThread;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
...@@ -113,16 +113,11 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana ...@@ -113,16 +113,11 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
auditManager.getAuditor(), auditManager.getAuditor(),
sock, sock,
isSecure); isSecure);
Session session = sessionManager.createSession(conn); SocketReadThread reader = new SocketReadThread(router, serverName,
SocketReadThread reader = new SocketReadThread(router, auditManager.getAuditor(), sock, conn);
serverName, auditManager.getAuditor(),
sock, session);
reader.setDaemon(true); reader.setDaemon(true);
reader.start(); reader.start();
} }
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
catch (IOException e) { catch (IOException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e); Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
} }
......
...@@ -11,21 +11,7 @@ ...@@ -11,21 +11,7 @@
package org.jivesoftware.messenger.spi; package org.jivesoftware.messenger.spi;
import java.util.ArrayList; import org.jivesoftware.messenger.*;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.jivesoftware.messenger.Component;
import org.jivesoftware.messenger.ComponentManager;
import org.jivesoftware.messenger.PacketDeliverer;
import org.jivesoftware.messenger.PresenceManager;
import org.jivesoftware.messenger.Session;
import org.jivesoftware.messenger.SessionManager;
import org.jivesoftware.messenger.XMPPServer;
import org.jivesoftware.messenger.container.BasicModule; import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.user.User; import org.jivesoftware.messenger.user.User;
import org.jivesoftware.messenger.user.UserManager; import org.jivesoftware.messenger.user.UserManager;
...@@ -37,6 +23,9 @@ import org.jivesoftware.util.Log; ...@@ -37,6 +23,9 @@ import org.jivesoftware.util.Log;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import org.xmpp.packet.Presence; import org.xmpp.packet.Presence;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* Simple in memory implementation of the PresenceManager interface. * Simple in memory implementation of the PresenceManager interface.
* *
...@@ -238,7 +227,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -238,7 +227,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
} }
Presence presence = null; Presence presence = null;
for (Session session : sessionManager.getSessions(user.getUsername())) { for (ClientSession session : sessionManager.getSessions(user.getUsername())) {
if (presence == null) { if (presence == null) {
presence = session.getPresence(); presence = session.getPresence();
} }
...@@ -263,7 +252,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -263,7 +252,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
} }
List<Presence> presences = new ArrayList<Presence>(); List<Presence> presences = new ArrayList<Presence>();
for (Session session : sessionManager.getSessions(user.getUsername())) { for (ClientSession session : sessionManager.getSessions(user.getUsername())) {
presences.add(session.getPresence()); presences.add(session.getPresence());
} }
return Collections.unmodifiableCollection(presences); return Collections.unmodifiableCollection(presences);
...@@ -298,9 +287,9 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -298,9 +287,9 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
Component component = getPresenceComponent(probee); Component component = getPresenceComponent(probee);
if (server.isLocal(probee)) { if (server.isLocal(probee)) {
if (probee.getNode() != null && !"".equals(probee.getNode())) { if (probee.getNode() != null && !"".equals(probee.getNode())) {
Collection<Session> sessions = Collection<ClientSession> sessions =
sessionManager.getSessions(probee.getNode()); sessionManager.getSessions(probee.getNode());
for (Session session : sessions) { for (ClientSession session : sessions) {
Presence presencePacket = session.getPresence().createCopy(); Presence presencePacket = session.getPresence().createCopy();
presencePacket.setFrom(session.getAddress()); presencePacket.setFrom(session.getAddress());
try { try {
...@@ -317,7 +306,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -317,7 +306,7 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
presence.setType(Presence.Type.probe); presence.setType(Presence.Type.probe);
presence.setFrom(server.createJID(prober, "")); presence.setFrom(server.createJID(prober, ""));
presence.setTo(probee); presence.setTo(probee);
component.processPacket(presence); component.process(presence);
} }
else { else {
Presence presence = (Presence) foreignUserCache.get(probee.toBareJID()); Presence presence = (Presence) foreignUserCache.get(probee.toBareJID());
...@@ -345,9 +334,9 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager ...@@ -345,9 +334,9 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
public void probePresence(JID prober, JID probee) { public void probePresence(JID prober, JID probee) {
try { try {
if (server.isLocal(probee)) { if (server.isLocal(probee)) {
Collection<Session> sessions = Collection<ClientSession> sessions =
sessionManager.getSessions(probee.getNode()); sessionManager.getSessions(probee.getNode());
for (Session session : sessions) { for (ClientSession session : sessions) {
Presence presencePacket = session.getPresence().createCopy(); Presence presencePacket = session.getPresence().createCopy();
presencePacket.setFrom(session.getAddress()); presencePacket.setFrom(session.getAddress());
try { try {
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
// Get the session & address objects // Get the session & address objects
SessionManager sessionManager = webManager.getSessionManager(); SessionManager sessionManager = webManager.getSessionManager();
JID address = new JID(jid); JID address = new JID(jid);
Session currentSess = sessionManager.getSession(address); ClientSession currentSess = sessionManager.getSession(address);
boolean isAnonymous = address.getNode() == null || "".equals(address.getNode()); boolean isAnonymous = address.getNode() == null || "".equals(address.getNode());
// Get a presence manager // Get a presence manager
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
} }
// See if there are multiple sessions for this user: // See if there are multiple sessions for this user:
Collection<Session> sessions = null; Collection<ClientSession> sessions = null;
int sessionCount = sessionManager.getSessionCount(address.getNode()); int sessionCount = sessionManager.getSessionCount(address.getNode());
if (!isAnonymous && sessionCount > 1) { if (!isAnonymous && sessionCount > 1) {
sessions = sessionManager.getSessions(address.getNode()); sessions = sessionManager.getSessions(address.getNode());
...@@ -279,7 +279,7 @@ user <b><%= address.getNode() %></b> has multiple sessions open, they will appea ...@@ -279,7 +279,7 @@ user <b><%= address.getNode() %></b> has multiple sessions open, they will appea
<% int count = 0; <% int count = 0;
String linkURL = "session-details.jsp"; String linkURL = "session-details.jsp";
for (Session sess : sessions) { for (ClientSession sess : sessions) {
count++; count++;
boolean current = sess.getAddress().equals(address); boolean current = sess.getAddress().equals(address);
%> %>
......
...@@ -130,7 +130,7 @@ Below is a list of sessions on this server. ...@@ -130,7 +130,7 @@ Below is a list of sessions on this server.
SessionResultFilter filter = new SessionResultFilter(); SessionResultFilter filter = new SessionResultFilter();
filter.setStartIndex(start); filter.setStartIndex(start);
filter.setNumResults(range); filter.setNumResults(range);
Collection<Session> sessions = sessionManager.getSessions(filter); Collection<ClientSession> sessions = sessionManager.getSessions(filter);
if (sessions.isEmpty()) { if (sessions.isEmpty()) {
%> %>
<tr> <tr>
...@@ -146,7 +146,7 @@ Below is a list of sessions on this server. ...@@ -146,7 +146,7 @@ Below is a list of sessions on this server.
<% int count = start; <% int count = start;
boolean current = false; // needed in session-row.jspf boolean current = false; // needed in session-row.jspf
String linkURL = "session-details.jsp"; String linkURL = "session-details.jsp";
for (Session sess : sessions) { for (ClientSession sess : sessions) {
count++; count++;
%> %>
<%@ include file="session-row.jspf" %> <%@ include file="session-row.jspf" %>
......
...@@ -105,13 +105,13 @@ ...@@ -105,13 +105,13 @@
// Get all sessions associated with this user: // Get all sessions associated with this user:
int numSessions = -1; int numSessions = -1;
Session sess = null; ClientSession sess = null;
Collection<Session> sessions = null; Collection<ClientSession> sessions = null;
if (user != null) { if (user != null) {
numSessions = sessionManager.getSessionCount(user.getUsername()); numSessions = sessionManager.getSessionCount(user.getUsername());
sessions = sessionManager.getSessions(user.getUsername()); sessions = sessionManager.getSessions(user.getUsername());
if (numSessions == 1) { if (numSessions == 1) {
sess = (Session)sessions.iterator().next(); sess = sessions.iterator().next();
} }
} }
%> %>
...@@ -205,9 +205,9 @@ function updateSelect(el) { ...@@ -205,9 +205,9 @@ function updateSelect(el) {
<select size="2" name="jid" multiple> <select size="2" name="jid" multiple>
<% Iterator iter = sessions.iterator(); <% Iterator<ClientSession> iter = sessions.iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
sess = (Session)iter.next(); sess = iter.next();
%> %>
<option value="<%= sess.getAddress().toString() %>"><%= sess.getAddress().toString() %></option> <option value="<%= sess.getAddress().toString() %>"><%= sess.getAddress().toString() %></option>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment