diff --git a/src/java/com/threerings/presents/server/ClientManager.java b/src/java/com/threerings/presents/server/ClientManager.java
new file mode 100644
index 000000000..ec5fc9af5
--- /dev/null
+++ b/src/java/com/threerings/presents/server/ClientManager.java
@@ -0,0 +1,60 @@
+//
+// $Id: ClientManager.java,v 1.1 2001/06/01 22:12:03 mdb Exp $
+
+package com.threerings.cocktail.cher.server;
+
+import java.io.IOException;
+
+import com.threerings.cocktail.cher.Log;
+import com.threerings.cocktail.cher.server.net.*;
+
+/**
+ * The client manager is responsible for managing the clients (surprise,
+ * surprise) which are slightly more than just connections. Clients
+ * persist in the absence of connections in case a user goes bye bye
+ * unintentionally and wants to reconnect and continue their session.
+ */
+public class ClientManager implements ConnectionObserver
+{
+ public ClientManager (ConnectionManager conmgr)
+ {
+ // register ourselves as a connection observer
+ conmgr.addConnectionObserver(this);
+ }
+
+ /**
+ * Called when a new connection is established with the connection
+ * manager. Only fully authenticated connections will be passed on to
+ * the connection observer.
+ *
+ * @param conn The newly established connection.
+ */
+ public void connectionEstablished (Connection conn)
+ {
+ Log.info("Connection established: " + conn);
+ }
+
+ /**
+ * Called if a connection fails for any reason. If a connection fails,
+ * connectionClosed will not be called. This call to
+ * connectionFailed is the last the observers will hear
+ * about it.
+ *
+ * @param conn The connection in that failed.
+ * @param fault The exception associated with the failure.
+ */
+ public void connectionFailed (Connection conn, IOException fault)
+ {
+ Log.info("Connection failed: " + conn + ": " + fault);
+ }
+
+ /**
+ * Called when a connection has been closed in an orderly manner.
+ *
+ * @param conn The recently closed connection.
+ */
+ public void connectionClosed (Connection conn)
+ {
+ Log.info("Connection closed: " + conn);
+ }
+}
diff --git a/src/java/com/threerings/presents/server/PresentsServer.java b/src/java/com/threerings/presents/server/PresentsServer.java
index 2ff9452a4..8b247734a 100644
--- a/src/java/com/threerings/presents/server/PresentsServer.java
+++ b/src/java/com/threerings/presents/server/PresentsServer.java
@@ -1,5 +1,5 @@
//
-// $Id: PresentsServer.java,v 1.3 2001/06/01 20:35:39 mdb Exp $
+// $Id: PresentsServer.java,v 1.4 2001/06/01 22:12:03 mdb Exp $
package com.threerings.cocktail.cher.server;
@@ -18,7 +18,10 @@ public class CherServer
public static AuthManager authmgr;
/** The manager of network connections. */
- public static ConnectionManager cmgr;
+ public static ConnectionManager conmgr;
+
+ /** The manager of clients. */
+ public static ClientManager clmgr;
/** The distributed object manager. */
public static DObjectManager omgr;
@@ -32,7 +35,9 @@ public class CherServer
// create our authentication manager
authmgr = new AuthManager(new DummyAuthenticator());
// create our connection manager
- cmgr = new ConnectionManager(authmgr);
+ conmgr = new ConnectionManager(authmgr);
+ // create our client manager
+ clmgr = new ClientManager(conmgr);
// create our distributed object manager
omgr = new CherDObjectMgr();
@@ -51,7 +56,7 @@ public class CherServer
// start up the auth manager
authmgr.start();
// start up the connection manager
- cmgr.start();
+ conmgr.start();
// invoke the dobjmgr event loop
((CherDObjectMgr)omgr).run();
}
diff --git a/src/java/com/threerings/presents/server/net/AuthManager.java b/src/java/com/threerings/presents/server/net/AuthManager.java
index 0d3a2ba67..8584a9412 100644
--- a/src/java/com/threerings/presents/server/net/AuthManager.java
+++ b/src/java/com/threerings/presents/server/net/AuthManager.java
@@ -1,5 +1,5 @@
//
-// $Id: AuthManager.java,v 1.2 2001/05/30 23:58:31 mdb Exp $
+// $Id: AuthManager.java,v 1.3 2001/06/01 22:12:03 mdb Exp $
package com.threerings.cocktail.cher.server.net;
@@ -39,6 +39,16 @@ public class AuthManager extends LoopingThread
_authq.append(aconn);
}
+ /**
+ * The connection manager introduces itself to the auth manager so
+ * that the auth manager can let it know when it has authorized
+ * connections.
+ */
+ public void setConnectionManager (ConnectionManager conmgr)
+ {
+ _conmgr = conmgr;
+ }
+
/**
* Process auth requests.
*/
@@ -54,6 +64,10 @@ public class AuthManager extends LoopingThread
// now ship the response back
aconn.postMessage(rsp);
+ // if the authentication request was granted, let the
+ // connection manager know that we just authed a connection
+ _conmgr.connectionDidAuthenticate(aconn);
+
} catch (Exception e) {
Log.warning("Failure processing authreq [conn=" + aconn + "].");
Log.logStackTrace(e);
@@ -61,5 +75,6 @@ public class AuthManager extends LoopingThread
}
protected Authenticator _author;
+ protected ConnectionManager _conmgr;
protected Queue _authq = new Queue();
}
diff --git a/src/java/com/threerings/presents/server/net/Connection.java b/src/java/com/threerings/presents/server/net/Connection.java
index 7db51fd8f..82be5235e 100644
--- a/src/java/com/threerings/presents/server/net/Connection.java
+++ b/src/java/com/threerings/presents/server/net/Connection.java
@@ -1,5 +1,5 @@
//
-// $Id: Connection.java,v 1.2 2001/05/30 23:58:31 mdb Exp $
+// $Id: Connection.java,v 1.3 2001/06/01 22:12:03 mdb Exp $
package com.threerings.cocktail.cher.server.net;
@@ -62,6 +62,15 @@ public abstract class Connection implements NetEventHandler
return _out;
}
+ /**
+ * Returns the non-blocking socket object used to construct this
+ * connection.
+ */
+ public NonblockingSocket getSocket ()
+ {
+ return _socket;
+ }
+
/**
* Called when our client socket has data available for reading.
*/
diff --git a/src/java/com/threerings/presents/server/net/ConnectionManager.java b/src/java/com/threerings/presents/server/net/ConnectionManager.java
index 8bda0ed65..244b6c95a 100644
--- a/src/java/com/threerings/presents/server/net/ConnectionManager.java
+++ b/src/java/com/threerings/presents/server/net/ConnectionManager.java
@@ -1,10 +1,11 @@
//
-// $Id: ConnectionManager.java,v 1.2 2001/05/30 23:58:31 mdb Exp $
+// $Id: ConnectionManager.java,v 1.3 2001/06/01 22:12:03 mdb Exp $
package com.threerings.cocktail.cher.server.net;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
import ninja2.core.io_core.nbio.*;
import com.samskivert.util.LoopingThread;
@@ -40,6 +41,8 @@ public class ConnectionManager extends LoopingThread
// keep a handle on our authentication manager
_authmgr = authmgr;
+ // complete the introductions
+ _authmgr.setConnectionManager(this);
// we use this to wait for activity on our sockets
_selset = new SelectSet();
@@ -69,6 +72,61 @@ public class ConnectionManager extends LoopingThread
return _authmgr;
}
+ /**
+ * Adds the specified connection observer to the observers list.
+ * Connection observers will be notified of connection-related
+ * events. An observer will not be added to the list twice.
+ *
+ * @see ConnectionObserver
+ */
+ public void addConnectionObserver (ConnectionObserver observer)
+ {
+ synchronized (_observers) {
+ if (!_observers.contains(observer)) {
+ _observers.add(observer);
+ }
+ }
+ }
+
+ /**
+ * Removes the specified connection observer from the observers list.
+ */
+ public void removeConnectionObserver (ConnectionObserver observer)
+ {
+ synchronized (_observers) {
+ _observers.remove(observer);
+ }
+ }
+
+ /**
+ * Notifies the connection observers of a connection event. Used
+ * internally.
+ */
+ protected void notifyObservers (int code, Connection conn,
+ IOException cause)
+ {
+ synchronized (_observers) {
+ for (int i = 0; i < _observers.size(); i++) {
+ ConnectionObserver obs =
+ (ConnectionObserver)_observers.get(i);
+ switch (code) {
+ case CONNECTION_ESTABLISHED:
+ obs.connectionEstablished(conn);
+ break;
+ case CONNECTION_FAILED:
+ obs.connectionFailed(conn, cause);
+ break;
+ case CONNECTION_CLOSED:
+ obs.connectionClosed(conn);
+ break;
+ default:
+ throw new RuntimeException("Invalid code supplied to " +
+ "notifyObservers: " + code);
+ }
+ }
+ }
+ }
+
protected void willStart ()
{
Log.info("Connection Manager thread running.");
@@ -95,6 +153,30 @@ public class ConnectionManager extends LoopingThread
}
}
+ // check for connections that have completed authentication
+ Connection conn;
+ while ((conn = (Connection)_authq.getNonBlocking()) != null) {
+ // remove the old connection from the select set
+ _selset.remove(conn.getSelectItem());
+
+ // construct a new running connection to handle this
+ // connections network traffic from here on out
+ try {
+ RunningConnection rconn =
+ new RunningConnection(this, conn.getSocket());
+ // wire this connection up to receive network events
+ _selset.add(rconn.getSelectItem());
+
+ // and let our observers know about our new connection
+ notifyObservers(CONNECTION_ESTABLISHED, rconn, null);
+
+ } catch (IOException ioe) {
+ Log.warning("Failure upgrading authing connection to " +
+ "running connection.");
+ Log.logStackTrace(ioe);
+ }
+ }
+
// check for incoming network events
int ecount = _selset.select(SELECT_LOOP_TIME);
if (ecount == 0) {
@@ -185,6 +267,7 @@ public class ConnectionManager extends LoopingThread
_selset.remove(conn.getSelectItem());
// let our observers know what's up
+ notifyObservers(CONNECTION_FAILED, conn, ioe);
}
/**
@@ -198,6 +281,17 @@ public class ConnectionManager extends LoopingThread
_selset.remove(conn.getSelectItem());
// let our observers know what's up
+ notifyObservers(CONNECTION_CLOSED, conn, null);
+ }
+
+ /**
+ * Called by the auth manager to indicate that a connection was
+ * successfully authenticated.
+ */
+ void connectionDidAuthenticate (Connection conn)
+ {
+ // slap this sucker onto the authenticated connections queue
+ _authq.append(conn);
}
protected AuthManager _authmgr;
@@ -210,6 +304,10 @@ public class ConnectionManager extends LoopingThread
protected FramingOutputStream _framer;
protected DataOutputStream _dout;
+ protected Queue _authq = new Queue();
+
+ protected ArrayList _observers = new ArrayList();
+
/** The default port on which we listen for connections. */
protected static final int DEFAULT_CM_PORT = 4007;
@@ -219,6 +317,11 @@ public class ConnectionManager extends LoopingThread
*/
protected static final int SELECT_LOOP_TIME = 30 * 1000;
+ // codes for notifyObservers()
+ protected static final int CONNECTION_ESTABLISHED = 0;
+ protected static final int CONNECTION_FAILED = 1;
+ protected static final int CONNECTION_CLOSED = 2;
+
// register our shared objects
static {
Registry.registerTypedObjects();
diff --git a/src/java/com/threerings/presents/server/net/ConnectionObserver.java b/src/java/com/threerings/presents/server/net/ConnectionObserver.java
index 47855fa87..950f83907 100644
--- a/src/java/com/threerings/presents/server/net/ConnectionObserver.java
+++ b/src/java/com/threerings/presents/server/net/ConnectionObserver.java
@@ -1,5 +1,5 @@
//
-// $Id: ConnectionObserver.java,v 1.2 2001/05/30 23:58:31 mdb Exp $
+// $Id: ConnectionObserver.java,v 1.3 2001/06/01 22:12:03 mdb Exp $
package com.threerings.cocktail.cher.server.net;
@@ -19,7 +19,8 @@ public interface ConnectionObserver
{
/**
* Called when a new connection is established with the connection
- * manager.
+ * manager. Only fully authenticated connections will be passed on to
+ * the connection observer.
*
* @param conn The newly established connection.
*/
@@ -28,7 +29,7 @@ public interface ConnectionObserver
/**
* Called if a connection fails for any reason. If a connection fails,
* connectionClosed will not be called. This call to
- * connectionFailued is the last the observers will hear
+ * connectionFailed is the last the observers will hear
* about it.
*
* @param conn The connection in that failed.