Commit ee43a017 authored by Matt Tucker's avatar Matt Tucker Committed by matt

Removed use of UnauthorizedException, cleaned up connection logic, start of...

Removed use of UnauthorizedException, cleaned up connection logic, start of work on TLS, Javadoc improvements.


git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@1200 b35dd754-fafc-0310-a699-88a17e54d16e
parent 576e8962
......@@ -11,8 +11,8 @@
package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.Packet;
import org.jivesoftware.messenger.auth.UnauthorizedException;
/**
* Interface to handle packets delivered by Channels.
......@@ -25,8 +25,7 @@ public interface ChannelHandler<T extends Packet> {
* Process an XMPP packet.
*
* @param packet a packet to process.
* @throws UnauthorizedException thrown if the packet's sender lacks authorization
* to access resources (will result in uniform unauthorized access error reply).
* @throws UnauthorizedException if not allowed to process the packet.
* @throws PacketException thrown if the packet is malformed (results in the sender's
* session being shutdown).
*/
......
......@@ -178,7 +178,7 @@ public class ComponentSession extends Session {
super(serverName, conn, id);
}
public void process(Packet packet) throws UnauthorizedException, PacketException {
public void process(Packet packet) throws PacketException {
// Since ComponentSessions are not being stored in the RoutingTable this messages is very
// unlikely to be sent
component.processPacket(packet);
......@@ -209,12 +209,7 @@ public class ComponentSession extends Session {
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
try {
conn.close();
}
catch (UnauthorizedException e1) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e1);
}
conn.close();
}
}
}
......
......@@ -16,23 +16,25 @@ import java.util.Iterator;
import org.xmlpull.v1.XmlPullParserException;
/**
* <p>Coordinates connections (accept, read, termination) on the server.</p>
* Coordinates connections (accept, read, termination) on the server.
*
* @author Iain Shigeoka
*/
public interface ConnectionManager {
/**
* <p>Obtain an array of the ports managed by this connection manager.</p>
* Returns an array of the ports managed by this connection manager.
*
* @return Iterator of the ports managed by this connection manager (can be an empty but never null)
* @return an iterator of the ports managed by this connection manager
* (can be an empty but never null).
*/
public Iterator<ServerPort> getPorts();
/**
* <p>Adds a socket to be managed by the connection manager.</p>
* Adds a socket to be managed by the connection manager.
*
* @param sock The socket to add to this manager for management
* @param isSecure True if this is a secure connection
* @param socket the socket to add to this manager for management.
* @param isSecure true if the connection is secure.
*/
public void addSocket(Socket sock, boolean isSecure) throws XmlPullParserException;
public void addSocket(Socket socket, boolean isSecure) throws XmlPullParserException;
}
......@@ -12,7 +12,6 @@
package org.jivesoftware.messenger;
import org.dom4j.Element;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.handler.IQHandler;
import org.jivesoftware.util.LocaleUtils;
......@@ -215,33 +214,23 @@ public class IQRouter extends BasicModule {
Log.info("Packet sent to unreachable address " + packet);
Session session = sessionManager.getSession(packet.getFrom());
if (session != null) {
try {
IQ reply = IQ.createResultIQ(packet);
reply.setChildElement(packet.getChildElement().createCopy());
reply.setError(PacketError.Condition.service_unavailable);
session.getConnection().deliver(reply);
}
catch (UnauthorizedException ex) {
Log.error(LocaleUtils.getLocalizedString("admin.error.routing"), e);
}
IQ reply = IQ.createResultIQ(packet);
reply.setChildElement(packet.getChildElement().createCopy());
reply.setError(PacketError.Condition.service_unavailable);
session.getConnection().deliver(reply);
}
}
}
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error.routing"), e);
try {
Session session = sessionManager.getSession(packet.getFrom());
if (session != null) {
Connection conn = session.getConnection();
if (conn != null) {
conn.close();
}
Session session = sessionManager.getSession(packet.getFrom());
if (session != null) {
Connection conn = session.getConnection();
if (conn != null) {
conn.close();
}
}
catch (UnauthorizedException e1) {
// do nothing
}
}
}
......
......@@ -255,7 +255,7 @@ public class InternalComponentManager implements ComponentManager, RoutableChann
*
* @param packet the packet to process.
*/
public void process(Packet packet) throws UnauthorizedException, PacketException {
public void process(Packet packet) throws PacketException {
Component component = getComponent(packet.getFrom().getDomain());
// Only process packets that were sent by registered components
if (component != null) {
......@@ -293,7 +293,7 @@ public class InternalComponentManager implements ComponentManager, RoutableChann
return jid;
}
public void process(Packet packet) throws UnauthorizedException, PacketException {
public void process(Packet packet) throws PacketException {
component.processPacket(packet);
}
}
......
......@@ -11,8 +11,8 @@
package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.Packet;
import org.jivesoftware.messenger.auth.UnauthorizedException;
/**
* Delivers packets to locally connected streams. This is the opposite
......@@ -29,8 +29,8 @@ public interface PacketDeliverer {
* Be careful to enforce concurrency DbC of concurrent by synchronizing
* any accesses to class resources.
*
* @param packet The packet to route
* @throws java.lang.NullPointerException If the packet is null or the packet could not be routed
* @param packet the packet to route
* @throws PacketException if the packet is null or the packet could not be routed.
*/
public void deliver(Packet packet) throws UnauthorizedException, PacketException;
}
......@@ -112,18 +112,13 @@ public class PresenceRouter extends BasicModule {
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error.routing"), e);
try {
Session session = sessionManager.getSession(packet.getFrom());
if (session != null) {
Connection conn = session.getConnection();
if (conn != null) {
conn.close();
}
Session session = sessionManager.getSession(packet.getFrom());
if (session != null) {
Connection conn = session.getConnection();
if (conn != null) {
conn.close();
}
}
catch (UnauthorizedException e1) {
// do nothing
}
}
}
......
......@@ -36,8 +36,8 @@ public interface DiscoItemsProvider {
* case that the sender of the disco request is not authorized to discover items an
* UnauthorizedException will be thrown.
*
* @param name the recipient JID's name.
* @param node the requested disco node.
* @param name the recipient JID's name.
* @param node the requested disco node.
* @param senderJID the XMPPAddress of user that sent the disco items request.
* @return an Iterator (of Element) with the target entity's items or null if none.
* @throws UnauthorizedException if the senderJID is not authorized to discover items.
......
......@@ -246,5 +246,4 @@ public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProv
};
return discoItemsProvider;
}
}
}
\ No newline at end of file
......@@ -42,7 +42,7 @@ public abstract class IQHandler extends BasicModule implements ChannelHandler {
super(moduleName);
}
public void process(Packet packet) throws UnauthorizedException, PacketException {
public void process(Packet packet) throws PacketException {
IQ iq = (IQ) packet;
try {
iq = handleIQ(iq);
......
......@@ -18,7 +18,6 @@ import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.roster.Roster;
import org.jivesoftware.messenger.roster.RosterItem;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.*;
import org.xmpp.packet.Presence;
import org.xmpp.packet.Packet;
......@@ -82,7 +81,7 @@ public class PresenceSubscribeHandler extends BasicModule implements ChannelHand
super("Presence subscription handler");
}
public void process(Packet xmppPacket) throws UnauthorizedException, PacketException {
public void process(Packet xmppPacket) throws PacketException {
Presence presence = (Presence)xmppPacket;
try {
JID senderJID = presence.getFrom();
......
......@@ -62,21 +62,14 @@ public class SSLSocketAcceptThread extends Thread {
* Creates an instance using the default port, TLS transport security, and
* JVM defaults for all security settings.
*
* @param connManager The connection manager that will manage connections generated by this thread
* @throws IOException If there was trouble initializing the SSL configuration
* @param connManager the connection manager that will manage connections
* generated by this thread
* @throws IOException if there was trouble initializing the SSL configuration.
*/
public SSLSocketAcceptThread(ConnectionManager connManager)
throws IOException {
super("SSL accept");
public SSLSocketAcceptThread(ConnectionManager connManager) throws IOException {
super("Secure Socket Listener");
this.connManager = connManager;
int port = SSLSocketAcceptThread.DEFAULT_PORT;
String portName = JiveGlobals.getProperty("xmpp.socket.ssl.port");
if (portName != null) {
int portValue = Integer.parseInt(portName);
if (portValue > 0) {
port = Integer.parseInt(portName);
}
}
int port = JiveGlobals.getIntProperty("xmpp.socket.ssl.port", DEFAULT_PORT);
String interfaceName = JiveGlobals.getProperty("xmpp.socket.ssl.interface");
bindInterface = null;
......
......@@ -57,7 +57,7 @@ public class SocketAcceptThread extends Thread {
private ConnectionManager connManager;
public SocketAcceptThread(ConnectionManager connManager) {
super("SAT accept");
super("Socket Listener");
this.connManager = connManager;
port = JiveGlobals.getIntProperty("xmpp.socket.plain.port", DEFAULT_PORT);
String interfaceName = JiveGlobals.getProperty("xmpp.socket.plain.interface");
......
......@@ -12,13 +12,10 @@
package org.jivesoftware.messenger.net;
import org.dom4j.io.XMLWriter;
import org.jivesoftware.messenger.PacketDeliverer;
import org.jivesoftware.messenger.PacketException;
import org.jivesoftware.messenger.Session;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.interceptor.InterceptorManager;
import org.jivesoftware.messenger.interceptor.PacketRejectedException;
import org.jivesoftware.messenger.spi.BasicConnection;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.xmpp.packet.Packet;
......@@ -29,48 +26,47 @@ import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
/**
* An object to track the state of a Jabber client-server session.
* An object to track the state of a XMPP client-server session.
* Currently this class contains the socket channel connecting the
* client and server.
*
* @author Iain Shigeoka
*/
public class SocketConnection extends BasicConnection {
public class SocketConnection implements Connection {
/**
* The socket this session represents
*/
private Socket sock;
private Map listeners = new HashMap();
private Socket socket;
/**
* The utf-8 charset for decoding and encoding Jabber packet streams.
* The utf-8 charset for decoding and encoding XMPP packet streams.
*/
private String charset = "UTF-8";
/**
* The writer used to send outgoing data.
*/
private Writer writer;
/**
* The packet deliverer for local packets
*/
private PacketDeliverer deliverer;
private Session session;
private boolean secure;
private XMLWriter xmlSerializer;
private boolean flashClient = false;
private int majorVersion = 1;
private int minorVersion = 0;
private String language = null;
/**
* Create a new session using the supplied socket.
*
* @param deliverer The packet deliverer this connection will use
* @param socket The socket to represent
* @param isSecure True if this is a secure connection
* @throws NullPointerException If the socket is null
* @param deliverer the packet deliverer this connection will use.
* @param socket the socket to represent.
* @param isSecure true if this is a secure connection.
* @throws NullPointerException if the socket is null.
*/
public SocketConnection(PacketDeliverer deliverer, Socket socket, boolean isSecure)
throws IOException
......@@ -80,8 +76,8 @@ public class SocketConnection extends BasicConnection {
}
this.secure = isSecure;
sock = socket;
writer = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream(), charset));
this.socket = socket;
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), charset));
this.deliverer = deliverer;
xmlSerializer = new XMLWriter(writer);
}
......@@ -107,26 +103,32 @@ public class SocketConnection extends BasicConnection {
session = owner;
}
public InetAddress getInetAddress() throws UnauthorizedException {
return sock.getInetAddress();
public Object registerCloseListener(ConnectionCloseListener listener, Object handbackMessage) {
Object status = null;
if (isClosed()) {
listener.onConnectionClose(handbackMessage);
}
else {
status = listeners.put(listener, handbackMessage);
}
return status;
}
public XMLWriter getSerializer() throws UnauthorizedException {
return xmlSerializer;
public Object removeCloseListener(ConnectionCloseListener listener) {
return listeners.remove(listener);
}
public Writer getWriter() throws UnauthorizedException {
public InetAddress getInetAddress() {
return socket.getInetAddress();
}
public Writer getWriter() {
return writer;
}
/**
* Retrieve the closed state of the Session.
*
* @return true if the session is closed.
*/
public boolean isClosed() {
if (session == null) {
return sock.isClosed();
return socket.isClosed();
}
return session.getStatus() == Session.STATUS_CLOSED;
}
......@@ -135,6 +137,56 @@ public class SocketConnection extends BasicConnection {
return secure;
}
public int getMajorXMPPVersion() {
return majorVersion;
}
public int getMinorXMPPVersion() {
return minorVersion;
}
/**
* Sets the XMPP version information. In most cases, the version should be "1.0".
* However, older clients using the "Jabber" protocol do not set a version. In that
* case, the version is "0.0".
*
* @param majorVersion the major version.
* @param minorVersion the minor version.
*/
public void setXMPPVersion(int majorVersion, int minorVersion) {
this.majorVersion = majorVersion;
this.minorVersion = minorVersion;
}
public String getLanguage() {
return language;
}
/**
* Sets the language code that should be used for this connection (e.g. "en").
*
* @param language the language code.
*/
public void setLanaguage(String language) {
this.language = language;
}
public boolean isFlashClient() {
return flashClient;
}
/**
* Sets whether the connected client is a flash client. Flash clients need to
* receive a special character (i.e. \0) at the end of each xml packet. Flash
* clients may send the character \0 in incoming packets and may start a
* connection using another openning tag such as: "flash:client".
*
* @param flashClient true if the if the connection is a flash client.
*/
public void setFlashClient(boolean flashClient) {
this.flashClient = flashClient;
}
public synchronized void close() {
if (!isClosed()) {
try {
......@@ -156,7 +208,7 @@ public class SocketConnection extends BasicConnection {
// Do nothing
}
try {
sock.close();
socket.close();
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error.close")
......@@ -166,12 +218,6 @@ public class SocketConnection extends BasicConnection {
}
}
/**
* Delivers the packet to this XMPPAddress without checking the recipient.
* The method essentially calls <tt>packet.send(serializer,version)</tt>.
*
* @param packet The packet to deliver.
*/
public void deliver(Packet packet) throws UnauthorizedException, PacketException {
if (isClosed()) {
deliverer.deliver(packet);
......@@ -203,11 +249,17 @@ public class SocketConnection extends BasicConnection {
}
}
public void setFlashClient(boolean flashClient) {
this.flashClient = flashClient;
}
public boolean isFlashClient() {
return flashClient;
/**
* Notifies all close listeners that the connection has been closed.
* Used by subclasses to properly finish closing the connection.
*/
private void notifyCloseListeners() {
synchronized (listeners) {
Iterator itr = listeners.keySet().iterator();
while (itr.hasNext()) {
ConnectionCloseListener listener = (ConnectionCloseListener)itr.next();
listener.onConnectionClose(listeners.get(listener));
}
}
}
}
\ No newline at end of file
......@@ -47,9 +47,9 @@ public class SocketReadThread extends Thread {
*/
private static XmlPullParserFactory factory = null;
private Socket sock;
private Socket socket;
private Session session;
private Connection connection;
private SocketConnection connection;
private String serverName;
/**
* Router used to route incoming packets to the correct channels.
......@@ -67,21 +67,22 @@ public class SocketReadThread extends Thread {
}
}
/**
* Create dedicated read thread for this socket.
* Creates a dedicated read thread for a socket.
*
* @param router The router for sending packets that were read
* @param serverName The name of the server this socket is working for
* @param sock The socket to read from
* @param conn The connection being read
* @param router the router for sending packets that were read.
* @param serverName the name of the server this socket is working for.
* @param socket the socket to read from.
* @param connection the connection being read.
*/
public SocketReadThread(PacketRouter router, String serverName, Socket sock, Connection conn) {
public SocketReadThread(PacketRouter router, String serverName, Socket socket,
SocketConnection connection)
{
super("SRT reader");
this.serverName = serverName;
this.router = router;
this.connection = conn;
this.sock = sock;
this.connection = connection;
this.socket = socket;
}
/**
......@@ -93,7 +94,7 @@ public class SocketReadThread extends Thread {
reader = new XPPPacketReader();
reader.setXPPFactory(factory);
reader.getXPPParser().setInput(new InputStreamReader(sock.getInputStream(),
reader.getXPPParser().setInput(new InputStreamReader(socket.getInputStream(),
CHARSET));
// Read in the opening tag and prepare for packet stream
......@@ -109,8 +110,8 @@ public class SocketReadThread extends Thread {
// Normal disconnect
}
catch (SocketException se) {
// The socket was closed. The server may close the connection for several reasons (e.g.
// user requested to remove his account). Do nothing here.
// The socket was closed. The server may close the connection for several
// reasons (e.g. user requested to remove his account). Do nothing here.
}
catch (XmlPullParserException ie) {
// Check if the user abruptly cut the connection without sending previously an
......@@ -131,9 +132,9 @@ public class SocketReadThread extends Thread {
}
}
// It is normal for clients to abruptly cut a connection
// rather than closing the stream document
// Since this is normal behavior, we won't log it as an error
// Log.error(LocaleUtils.getLocalizedString("admin.disconnect"),ie);
// rather than closing the stream document. Since this is
// normal behavior, we won't log it as an error.
// Log.error(LocaleUtils.getLocalizedString("admin.disconnect"),ie);
}
catch (Exception e) {
if (session != null) {
......@@ -152,31 +153,26 @@ public class SocketReadThread extends Thread {
}
catch (Exception e) {
Log.warn(LocaleUtils.getLocalizedString("admin.error.connection")
+ "\n" + sock.toString());
+ "\n" + socket.toString());
}
}
else {
Log.error(LocaleUtils.getLocalizedString("admin.error.connection")
+ "\n" + sock.toString());
+ "\n" + socket.toString());
}
}
}
/**
* Read the incoming stream until it ends. Much of the reading
* will actually be done in the channel handlers as they run the
* XPP through the data. This method mostly handles the idle waiting
* for incoming data. To prevent clients from stalling channel handlers,
* a watch dog timer is used. Packets that take longer than the watch
* dog limit to read will cause the session to be closed.
* Read the incoming stream until it ends.
*/
private void readStream() throws Exception {
while (true) {
Element doc = reader.parseDocument().getRootElement();
if (doc == null) {
// Stop reading the stream since the client has sent an end of stream element and
// probably closed the connection
// Stop reading the stream since the client has sent an end of
// stream element and probably closed the connection.
return;
}
......@@ -187,7 +183,7 @@ public class SocketReadThread extends Thread {
packet = new Message(doc);
}
catch(IllegalArgumentException e) {
// The original packet contains a malformed JID so answer an error
// The original packet contains a malformed JID so answer with an error.
Message reply = new Message();
reply.setID(doc.attributeValue("id"));
reply.setTo(session.getAddress());
......@@ -298,7 +294,8 @@ public class SocketReadThread extends Thread {
}
}
else {
throw new XmlPullParserException(LocaleUtils.getLocalizedString("admin.error.packet.tag") + tag);
throw new XmlPullParserException(LocaleUtils.getLocalizedString(
"admin.error.packet.tag") + tag);
}
}
}
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.Connection;
import org.jivesoftware.messenger.ConnectionCloseListener;
import org.jivesoftware.messenger.Session;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Connection helper base class. Automates common connection management
* tasks without specific knowledge of the underlying connection provider.
*
* @author Iain Shigeoka
*/
abstract public class BasicConnection implements Connection {
private Map listeners = new HashMap();
public void init(Session session) {
}
public Object registerCloseListener(ConnectionCloseListener listener, Object handbackMessage) {
Object status = null;
if (isClosed()) {
listener.onConnectionClose(handbackMessage);
}
else {
status = listeners.put(listener, handbackMessage);
}
return status;
}
public Object removeCloseListener(ConnectionCloseListener listener) {
return listeners.remove(listener);
}
/**
* Notifies all close listeners that the connection has been closed.
* Used by subclasses to properly finish closing the connection.
*/
protected void notifyCloseListeners() {
synchronized (listeners) {
Iterator itr = listeners.keySet().iterator();
while (itr.hasNext()) {
ConnectionCloseListener listener = (ConnectionCloseListener)itr.next();
listener.onConnectionClose(listeners.get(listener));
}
}
}
}
......@@ -107,7 +107,7 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
public void addSocket(Socket sock, boolean isSecure) {
try {
// the order of these calls is critical (stupid huh?)
Connection conn = new SocketConnection(deliverer, sock, isSecure);
SocketConnection conn = new SocketConnection(deliverer, sock, isSecure);
SocketReadThread reader = new SocketReadThread(router, serverName, sock, conn);
reader.setDaemon(true);
reader.start();
......
......@@ -60,9 +60,6 @@ public class TransportHandler extends BasicModule implements ChannelHandler {
try {
deliverer.deliver(packet);
}
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
catch (PacketException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
......
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