Cleaned up connection handling code so that it deals more robustly and

gracefully with failures; also no longer attempt to send messages to a
connection that has already been closed.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1565 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2002-07-10 01:23:45 +00:00
parent 6b77216df1
commit 3be1d56ae7
2 changed files with 74 additions and 18 deletions
@@ -1,5 +1,5 @@
//
// $Id: Connection.java,v 1.6 2001/10/11 04:07:53 mdb Exp $
// $Id: Connection.java,v 1.7 2002/07/10 01:23:45 mdb Exp $
package com.threerings.presents.server.net;
@@ -81,6 +81,14 @@ public abstract class Connection implements NetEventHandler
return _socket;
}
/**
* Returns true if this connection is closed.
*/
public boolean isClosed ()
{
return (_socket == null);
}
/**
* Closes this connection and unregisters it from the connection
* manager. This should only be called from the conmgr thread.
@@ -88,8 +96,9 @@ public abstract class Connection implements NetEventHandler
public void close ()
{
// we shouldn't be closed twice
if (_socket == null) {
Log.warning("Attempted to re-close connection.");
if (isClosed()) {
Log.warning("Attempted to re-close connection " + this + ".");
Thread.dumpStack();
return;
}
@@ -97,15 +106,48 @@ public abstract class Connection implements NetEventHandler
_cmgr.connectionClosed(this);
// close our socket
try {
_socket.close();
} catch (IOException ioe) {
Log.warning("Error closing connection [conn=" + this +
", error=" + ioe + "].");
closeSocket();
}
/**
* Called when there is a failure reading or writing on this
* connection. We notify the connection manager and close ourselves
* down.
*/
public void handleFailure (IOException ioe)
{
// if we're already closed, then something is seriously funny
if (isClosed()) {
Log.warning("Failure reported on closed connection " + this + ".");
Thread.dumpStack();
return;
}
// clear out our socket reference to prevent repeat closings
_socket = null;
// let the connection manager know we're hosed
_cmgr.connectionFailed(this, ioe);
// and close our socket
closeSocket();
}
/**
* Closes the socket associated with this connection. This happens
* when we receive EOF, are requested to close down or when our
* connection fails.
*/
protected void closeSocket ()
{
if (_socket != null) {
try {
_socket.close();
} catch (IOException ioe) {
Log.warning("Error closing connection [conn=" + this +
", error=" + ioe + "].");
}
// clear out our socket reference to prevent repeat closings
_socket = null;
}
}
/**
@@ -122,15 +164,14 @@ public abstract class Connection implements NetEventHandler
}
} catch (EOFException eofe) {
// let the connection manager know that we done went away
_cmgr.connectionClosed(this);
// close down the socket gracefully
close();
} catch (IOException ioe) {
Log.warning("Error reading message from socket " +
"[socket=" + _socket + ", error=" + ioe + "].");
Log.logStackTrace(ioe);
// let the connection manager know that something when awry
_cmgr.connectionFailed(this, ioe);
// deal with the failure
handleFailure(ioe);
}
}
@@ -1,5 +1,5 @@
//
// $Id: ConnectionManager.java,v 1.18 2002/03/28 22:32:32 mdb Exp $
// $Id: ConnectionManager.java,v 1.19 2002/07/10 01:23:45 mdb Exp $
package com.threerings.presents.server.net;
@@ -173,13 +173,27 @@ public class ConnectionManager extends LoopingThread
// close any connections that have been queued up to die
Connection dconn;
while ((dconn = (Connection)_deathq.getNonBlocking()) != null) {
dconn.close();
// it's possible that we caught an EOF trying to read from
// this connection even after it was queued up for death, so
// let's avoid trying to close it twice
if (!dconn.isClosed()) {
dconn.close();
}
}
// send any messages that are waiting on the outgoing queue
Tuple tup;
while ((tup = (Tuple)_outq.getNonBlocking()) != null) {
Connection conn = (Connection)tup.left;
// if the connection to which this message is destined is
// closed, drop the message and move along quietly; this is
// perfectly legal, a user can logoff whenever they like, even
// if we still have things to tell them; such is life in a
// fully asynchronous distributed system
if (conn.isClosed()) {
continue;
}
DownstreamMessage outmsg = (DownstreamMessage)tup.right;
try {
// first flatten the message (and frame it)
@@ -188,7 +202,8 @@ public class ConnectionManager extends LoopingThread
_framer.writeFrameAndReset(conn.getOutputStream());
} catch (IOException ioe) {
connectionFailed(conn, ioe);
// instruct the connection to deal with its failure
conn.handleFailure(ioe);
}
}