Rewritten to use the Java NIO library rather than the Berkeley NBIO

library. 100% pure baby! At least for the moment.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1958 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2002-11-18 18:53:10 +00:00
parent d6b84eb0b8
commit 45fb96c4f2
6 changed files with 270 additions and 180 deletions
@@ -1,16 +1,15 @@
//
// $Id: Communicator.java,v 1.24 2002/10/31 18:44:34 mdb Exp $
// $Id: Communicator.java,v 1.25 2002/11/18 18:53:10 mdb Exp $
package com.threerings.presents.client;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.net.InetAddress;
import java.net.Socket;
import com.samskivert.io.NestableIOException;
import com.samskivert.util.Interval;
@@ -26,6 +25,7 @@ import com.threerings.io.ObjectOutputStream;
import com.threerings.presents.Log;
import com.threerings.presents.dobj.DObjectManager;
import com.threerings.presents.net.*;
import java.net.InetSocketAddress;
/**
* The client performs all network I/O on separate threads (one for
@@ -106,7 +106,7 @@ public class Communicator
{
// if our socket is already closed, we've already taken care of
// this business
if (_socket == null) {
if (_channel == null) {
return;
}
@@ -186,7 +186,7 @@ public class Communicator
{
// make sure the socket isn't already closed down (meaning we've
// already dealt with the failed connection)
if (_socket == null) {
if (_channel == null) {
return;
}
@@ -208,7 +208,7 @@ public class Communicator
{
// make sure the socket isn't already closed down (meaning we've
// already dealt with the closed connection)
if (_socket == null) {
if (_channel == null) {
return;
}
@@ -246,11 +246,11 @@ public class Communicator
// our socket and let the client know that the logoff process has
// completed
try {
_socket.close();
} catch (IOException cle) {
Log.warning("Error closing failed socket: " + cle);
_channel.close();
} catch (IOException ioe) {
Log.warning("Error closing failed socket: " + ioe);
}
_socket = null;
_channel = null;
// clear these out because they are probably large and in charge
_oin = null;
@@ -278,7 +278,20 @@ public class Communicator
_oout.flush();
// then write the framed message to actual output stream
_fout.writeFrameAndReset(_out);
try {
ByteBuffer buffer = _fout.frameAndReturnBuffer();
int wrote = _channel.write(buffer);
if (wrote != buffer.limit()) {
Log.warning("Aiya! Couldn't write entire message [msg=" + msg +
", size=" + buffer.limit() +
", wrote=" + wrote + "].");
// } else {
// Log.info("Wrote " + wrote + " bytes.");
}
} finally {
_fout.resetFrame();
}
// make a note of our most recent write time
updateWriteStamp();
@@ -315,7 +328,7 @@ public class Communicator
// which case we simply call it again because we can't do anything
// until it has a whole frame; it will throw an exception if it
// hits EOF or if something goes awry)
while (!_fin.readFrame(_in));
while (!_fin.readFrame(_channel));
try {
DownstreamMessage msg = (DownstreamMessage)_oin.readObject();
@@ -359,6 +372,7 @@ public class Communicator
} catch (Exception e) {
Log.debug("Logon failed: " + e);
Log.logStackTrace(e);
// let the observers know that we've failed
_client.notifyObservers(Client.CLIENT_FAILED_TO_LOGON, e);
// and terminate our communicator thread
@@ -370,7 +384,7 @@ public class Communicator
throws IOException
{
// if we're already connected, we freak out
if (_socket != null) {
if (_channel != null) {
throw new IOException("Already connected.");
}
@@ -379,13 +393,9 @@ public class Communicator
int port = _client.getPort();
// establish a socket connection to said server
Log.debug("Connecting to server [host=" + host +
", port=" + port + "].");
_socket = new Socket(host, port);
// get a handle on our input and output streams
_in = _socket.getInputStream();
_out = _socket.getOutputStream();
Log.debug("Connecting [host=" + host + ", port=" + port + "].");
_channel = SocketChannel.open(new InetSocketAddress(host, port));
_channel.configureBlocking(true);
// our messages are framed (preceded by their length), so we
// use these helper streams to manage the framing
@@ -477,7 +487,7 @@ public class Communicator
// we want to interrupt the reader thread as it may be blocked
// listening to the socket; this is only called if the reader
// thread doesn't shut itself down
interrupt();
// interrupt();
}
}
@@ -541,9 +551,7 @@ public class Communicator
protected Reader _reader;
protected Writer _writer;
protected Socket _socket;
protected InputStream _in;
protected OutputStream _out;
protected SocketChannel _channel;
protected Queue _msgq = new Queue();
protected int _piid;
@@ -1,10 +1,12 @@
//
// $Id: AuthingConnection.java,v 1.8 2002/10/29 23:51:26 mdb Exp $
// $Id: AuthingConnection.java,v 1.9 2002/11/18 18:53:10 mdb Exp $
package com.threerings.presents.server.net;
import java.io.IOException;
import ninja2.core.io_core.nbio.NonblockingSocket;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import com.samskivert.util.StringUtil;
import com.threerings.presents.Log;
@@ -23,11 +25,11 @@ public class AuthingConnection extends Connection
* Creates a new authing connection object that will manage the
* authentication process for the suppled client socket.
*/
public AuthingConnection (ConnectionManager cmgr,
NonblockingSocket socket)
public AuthingConnection (ConnectionManager cmgr, SelectionKey selkey,
SocketChannel channel)
throws IOException
{
super(cmgr, socket, System.currentTimeMillis());
super(cmgr, selkey, channel, System.currentTimeMillis());
// we are our own message handler
setMessageHandler(this);
@@ -80,10 +82,13 @@ public class AuthingConnection extends Connection
_authrsp = authrsp;
}
/**
* Generates a string representation of this instance.
*/
public String toString ()
{
return "[mode=AUTHING, addr=" +
StringUtil.toString(_socket.getInetAddress()) + "]";
StringUtil.toString(_channel.socket().getInetAddress()) + "]";
}
protected AuthRequest _authreq;
@@ -1,5 +1,5 @@
//
// $Id: Connection.java,v 1.12 2002/11/06 21:05:13 shaper Exp $
// $Id: Connection.java,v 1.13 2002/11/18 18:53:10 mdb Exp $
package com.threerings.presents.server.net;
@@ -7,9 +7,11 @@ import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketTimeoutException;
import ninja2.core.io_core.nbio.*;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import com.samskivert.io.NestableIOException;
@@ -37,24 +39,20 @@ public abstract class Connection implements NetEventHandler
*
* @param cmgr The connection manager with which this connection is
* associated.
* @param socket The socket from which we'll be reading messages.
* @param selkey the key used by the NIO code to track this
* connection.
* @param channel The socket channel from which we'll be reading
* messages.
* @param createStamp The time at which this connection was created.
*/
public Connection (ConnectionManager cmgr, NonblockingSocket socket,
long createStamp)
public Connection (ConnectionManager cmgr, SelectionKey selkey,
SocketChannel channel, long createStamp)
throws IOException
{
_cmgr = cmgr;
_socket = socket;
_selkey = selkey;
_channel = channel;
_lastEvent = createStamp;
// create a select item that will allow us to be incorporated into
// the main event polling loop
_selitem = new SelectItem(_socket, this, Selectable.READ_READY);
// get a handle on our socket streams
_in = _socket.getInputStream();
_out = _socket.getOutputStream();
}
/**
@@ -68,20 +66,20 @@ public abstract class Connection implements NetEventHandler
}
/**
* Returns the select item associated with this connection.
* Returns the selection key associated with our socket channel.
*/
public SelectItem getSelectItem ()
public SelectionKey getSelectionKey ()
{
return _selitem;
return _selkey;
}
/**
* Returns the non-blocking socket object used to construct this
* connection.
*/
public NonblockingSocket getSocket ()
public SocketChannel getChannel ()
{
return _socket;
return _channel;
}
/**
@@ -89,7 +87,7 @@ public abstract class Connection implements NetEventHandler
*/
public boolean isClosed ()
{
return (_socket == null);
return (_channel == null);
}
/**
@@ -133,15 +131,6 @@ public abstract class Connection implements NetEventHandler
closeSocket();
}
/**
* Returns the output stream associated with this connection. This
* should only be used by the connection manager.
*/
protected OutputStream getOutputStream ()
{
return _out;
}
/**
* Returns the object input stream associated with this connection.
* This should only be used by the connection manager.
@@ -197,23 +186,26 @@ public abstract class Connection implements NetEventHandler
*/
protected void closeSocket ()
{
if (_socket != null) {
if (_channel != null) {
Log.debug("Closing channel " + this + ".");
try {
_socket.close();
_channel.close();
} catch (IOException ioe) {
Log.warning("Error closing connection [conn=" + this +
", error=" + ioe + "].");
}
// clear out our socket reference to prevent repeat closings
_socket = null;
// clear out our references to prevent repeat closings
_selkey = null;
_channel = null;
}
}
/**
* Called when our client socket has data available for reading.
*/
public int handleEvent (long when, Selectable source, short events)
public int handleEvent (long when)
{
// make a note that we received an event as of this time
_lastEvent = when;
@@ -228,8 +220,9 @@ public abstract class Connection implements NetEventHandler
_oin = new ObjectInputStream(_fin);
}
// read the available data and see if we have a whole frame
if (_fin.readFrame(_in)) {
// there may be more than one frame in the buffer, so we keep
// reading them until we run out of data
while (_fin.readFrame(_channel)) {
// make a note of how many bytes are in this frame
// (including the frame length bytes which aren't reported
// in available())
@@ -246,14 +239,14 @@ public abstract class Connection implements NetEventHandler
} catch (ClassNotFoundException cnfe) {
Log.warning("Error reading message from socket " +
"[socket=" + _socket + ", error=" + cnfe + "].");
"[channel=" + _channel + ", error=" + cnfe + "].");
// deal with the failure
handleFailure(new NestableIOException(
"Unable to decode incoming message.", cnfe));
} catch (IOException ioe) {
Log.warning("Error reading message from socket " +
"[socket=" + _socket + ", error=" + ioe + "].");
"[channel=" + _channel + ", error=" + ioe + "].");
// deal with the failure
handleFailure(ioe);
}
@@ -262,18 +255,18 @@ public abstract class Connection implements NetEventHandler
}
// documentation inherited from interface
public void checkIdle (long now)
public boolean checkIdle (long now)
{
long idleMillis = now - _lastEvent;
if (idleMillis < PingRequest.PING_INTERVAL + LATENCY_GRACE) {
return;
return false;
}
if (isClosed()) {
return;
return false;
}
Log.info("Disconnecting idle client [conn=" + this +
Log.info("Disconnecting non-communicative client [conn=" + this +
", idle=" + idleMillis + "ms].");
handleFailure(new SocketTimeoutException("Idle too long"));
return true;
}
/**
@@ -288,16 +281,14 @@ public abstract class Connection implements NetEventHandler
}
protected ConnectionManager _cmgr;
protected NonblockingSocket _socket;
protected SelectItem _selitem;
protected SelectionKey _selkey;
protected SocketChannel _channel;
protected long _lastEvent;
protected InputStream _in;
protected FramedInputStream _fin;
protected ObjectInputStream _oin;
protected OutputStream _out;
protected ObjectOutputStream _oout;
protected MessageHandler _handler;
@@ -1,13 +1,26 @@
//
// $Id: ConnectionManager.java,v 1.24 2002/11/05 02:17:56 mdb Exp $
// $Id: ConnectionManager.java,v 1.25 2002/11/18 18:53:10 mdb Exp $
package com.threerings.presents.server.net;
import java.io.IOException;
import java.net.SocketException;
import java.util.ArrayList;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import ninja2.core.io_core.nbio.*;
import com.samskivert.util.*;
import com.threerings.io.FramingOutputStream;
@@ -41,34 +54,42 @@ public class ConnectionManager extends LoopingThread
throws IOException
{
_port = port;
_selset = new SelectSet();
_selector = SelectorProvider.provider().openSelector();
// register as a "state of server" reporter
PresentsServer.registerReporter(this);
try {
// create our listening socket and add it to the select set
_listener = new NonblockingServerSocket(_port);
} catch (SocketException se) {
_listener = ServerSocketChannel.open();
_listener.configureBlocking(false);
InetAddress lh = InetAddress.getLocalHost();
InetSocketAddress isa = new InetSocketAddress(lh, _port);
_listener.socket().bind(isa);
Log.info("Server listening on " + isa + ".");
} catch (IOException ioe) {
Log.warning("Failure creating listen socket " +
"[port=" + _port + "].");
throw se;
throw ioe;
}
_litem = new SelectItem(_listener, Selectable.ACCEPT_READY);
// when an ACCEPT_READY event happens, we do this:
_litem.obj = new NetEventHandler() {
public int handleEvent (long when, Selectable item, short events) {
// register our listening socket and map its select key to a net
// event handler that will accept new connections
SelectionKey lkey =
_listener.register(_selector, SelectionKey.OP_ACCEPT);
_handlers.put(lkey, new NetEventHandler() {
public int handleEvent (long when) {
acceptConnection();
// there's no easy way to measure bytes read when
// accepting a connection, so we claim nothing
return 0;
}
public void checkIdle (long now) {
// we're never idle
public boolean checkIdle (long now) {
return false; // we're never idle
}
};
_selset.add(_litem);
});
// we'll use this for sending messages to clients
_framer = new FramingOutputStream();
@@ -217,18 +238,22 @@ public class ConnectionManager extends LoopingThread
}
}
// close any connections that have seen no network traffic for too
// long
int ccount = _selset.size();
for (int ii = 0; ii < ccount; ii++) {
((NetEventHandler)_selset.elementAt(ii).getObj()).
checkIdle(iterStamp);
// close connections that have had no network traffic for too long
Iterator hiter = _handlers.values().iterator();
while (hiter.hasNext()) {
NetEventHandler handler = (NetEventHandler)hiter.next();
if (handler.checkIdle(iterStamp)) {
// this will queue the connection up for closure on our
// next tick
closeConnection(((Connection)handler));
}
}
// 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
@@ -249,10 +274,27 @@ public class ConnectionManager extends LoopingThread
oout.flush();
// then write framed message to real output stream
int out = _framer.writeFrameAndReset(conn.getOutputStream());
synchronized (this) {
_bytesOut += out;
_msgsOut++;
try {
ByteBuffer buffer = _framer.frameAndReturnBuffer();
int wrote = conn.getChannel().write(buffer);
if (wrote != buffer.limit()) {
Log.warning("Aiya! Failed to write complete message " +
"[conn=" + conn + ", wrote=" + wrote +
", needed=" + buffer.limit() + "].");
// TODO: give them the boot
// } else {
// Log.info("Sent [msg=" + outmsg +
// ", size=" + wrote + "].");
}
int out = buffer.limit();
synchronized (this) {
_bytesOut += wrote;
_msgsOut++;
}
} finally {
_framer.resetFrame();
}
} catch (IOException ioe) {
@@ -264,20 +306,21 @@ public class ConnectionManager extends LoopingThread
// check for connections that have completed authentication
AuthingConnection conn;
while ((conn = (AuthingConnection)_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(), iterStamp);
// construct a new running connection to handle this
// connections network traffic from here on out
SelectionKey selkey = conn.getSelectionKey();
RunningConnection rconn = new RunningConnection(
this, selkey, conn.getChannel(), iterStamp);
// we need to keep using the same object input and output
// streams from the beginning of the session because they
// have contextual state that needs to be preserved
rconn.inheritStreams(conn);
// wire this connection up to receive network events
_selset.add(rconn.getSelectItem());
// replace the mapping in the handlers table from the old
// connection with the new one
_handlers.put(selkey, rconn);
// and let our observers know about our new connection
notifyObservers(CONNECTION_ESTABLISHED, rconn,
@@ -290,20 +333,47 @@ public class ConnectionManager extends LoopingThread
}
}
// check for incoming network events
int ecount = _selset.select(SELECT_LOOP_TIME);
if (ecount == 0) {
Set ready = null;
try {
// check for incoming network events
// Log.debug("Selecting from " +
// StringUtil.toString(_selector.keys()) + " (" +
// SELECT_LOOP_TIME + ").");
int ecount = _selector.select(SELECT_LOOP_TIME);
ready = _selector.selectedKeys();
if (ecount == 0) {
if (ready.size() == 0) {
return;
} else {
Log.warning("select() returned no selected sockets, " +
"but there are " + ready.size() +
" in the ready set.");
}
}
} catch (IOException ioe) {
Log.warning("Failure select()ing [ioe=" + ioe + "].");
return;
}
// process those events
SelectItem[] active = _selset.getEvents();
for (int i = 0; i < active.length; i++) {
// Log.info("Ready set " + StringUtil.toString(ready) + ".");
Iterator siter = ready.iterator();
while (siter.hasNext()) {
SelectionKey selkey = (SelectionKey)siter.next();
try {
SelectItem item = active[i];
NetEventHandler handler = (NetEventHandler)item.obj;
int got = handler.handleEvent(
iterStamp, item.getSelectable(), item.revents);
NetEventHandler handler = (NetEventHandler)
_handlers.get(selkey);
if (handler == null) {
Log.warning("Received network event but have no " +
"registered handler [selkey=" + selkey + "].");
continue;
}
// Log.info("Got event [selkey=" + selkey +
// ", handler=" + handler + "].");
int got = handler.handleEvent(iterStamp);
if (got != 0) {
synchronized (this) {
_bytesIn += got;
@@ -319,6 +389,7 @@ public class ConnectionManager extends LoopingThread
Log.logStackTrace(e);
}
}
ready.clear();
}
// documentation inherited
@@ -341,34 +412,48 @@ public class ConnectionManager extends LoopingThread
*/
protected void acceptConnection ()
{
NonblockingSocket socket = null;
SocketChannel channel = null;
try {
socket = _listener.nbAccept();
if (socket == null) {
channel = _listener.accept();
if (channel == null) {
// in theory this shouldn't happen because we got an
// ACCEPT_READY event, but better safe than sorry
// Log.info("Psych! Got ACCEPT_READY, but no connection.");
Log.info("Psych! Got ACCEPT_READY, but no connection.");
return;
}
// create a new authing connection object to manage the
// authentication of this client connection
AuthingConnection acon = new AuthingConnection(this, socket);
if (!(channel instanceof SelectableChannel)) {
Log.warning("Provided with un-selectable socket as " +
"result of accept(), can't cope " +
"[channel=" + channel + "].");
// stick a fork in the socket
channel.socket().close();
return;
}
// wire this connection into the select set
_selset.add(acon.getSelectItem());
Log.debug("Accepted connection " + channel + ".");
// create a new authing connection object to manage the
// authentication of this client connection and register it
// with our selection set
SelectableChannel selchan = (SelectableChannel)channel;
selchan.configureBlocking(false);
SelectionKey selkey = selchan.register(
_selector, SelectionKey.OP_READ);
_handlers.put(selkey, new AuthingConnection(this, selkey, channel));
return;
} catch (IOException ioe) {
Log.warning("Failure accepting new connection: " + ioe);
}
// make sure we don't leak a socket if something went awry
if (socket != null) {
try {
socket.close();
} catch (IOException ioe2) {
Log.warning("Failed closing aborted connection: " + ioe2);
}
// make sure we don't leak a socket if something went awry
if (channel != null) {
try {
channel.socket().close();
} catch (IOException ioe) {
Log.warning("Failed closing aborted connection: " + ioe);
}
}
}
@@ -395,8 +480,9 @@ public class ConnectionManager extends LoopingThread
*/
void connectionFailed (Connection conn, IOException ioe)
{
// remove this connection from the select set
_selset.remove(conn.getSelectItem());
// remove this connection from our mapping (it is automatically
// removed from the Selector when the socket is closed)
_handlers.remove(conn.getSelectionKey());
// let our observers know what's up
notifyObservers(CONNECTION_FAILED, conn, ioe, null);
@@ -407,8 +493,9 @@ public class ConnectionManager extends LoopingThread
*/
void connectionClosed (Connection conn)
{
// remove this connection from the select set
_selset.remove(conn.getSelectItem());
// remove this connection from our mapping (it is automatically
// removed from the Selector when the socket is closed)
_handlers.remove(conn.getSelectionKey());
// let our observers know what's up
notifyObservers(CONNECTION_CLOSED, conn, null, null);
@@ -416,10 +503,11 @@ public class ConnectionManager extends LoopingThread
protected int _port;
protected Authenticator _author;
protected SelectSet _selset;
protected Selector _selector;
protected ServerSocketChannel _listener;
protected NonblockingServerSocket _listener;
protected SelectItem _litem;
/** Maps selection keys to network event handlers. */
protected HashMap _handlers = new HashMap();
protected Queue _deathq = new Queue();
protected Queue _authq = new Queue();
@@ -437,12 +525,12 @@ public class ConnectionManager extends LoopingThread
/**
* How long we wait for network events before checking our running
* flag to see if we should still be running.
* flag to see if we should still be running. We don't want to loop
* too tightly, but we need to make sure we don't sit around listening
* for incoming network events too long when there are outgoing
* messages in the queue.
*/
// protected static final int SELECT_LOOP_TIME = 30 * 1000;
// while we're testing, use a short loop time
protected static final int SELECT_LOOP_TIME = 10;
protected static final int SELECT_LOOP_TIME = 100;
// codes for notifyObservers()
protected static final int CONNECTION_ESTABLISHED = 0;
@@ -1,36 +1,36 @@
//
// $Id: NetEventHandler.java,v 1.5 2002/11/05 02:17:56 mdb Exp $
// $Id: NetEventHandler.java,v 1.6 2002/11/18 18:53:10 mdb Exp $
package com.threerings.presents.server.net;
import ninja2.core.io_core.nbio.Selectable;
/**
* When a network event arrives on a particular <code>Selectable</code>,
* the connection manager calls the net event handler associated with that
* selectable to process the event. There are only a few handlers (and
* probably only ever will be): the one that accepts new connections, the
* one that deals with a connection while the client is authenticating and
* the one that processes messages from authenticated connections.
* Providing this interface prevents us from having to do a bunch of
* When a network event occurs, the connection manager calls the net event
* handler associated with that channel to process the event. There are
* only a few handlers (and probably only ever will be): the one that
* accepts new connections, the one that deals with a connection while the
* client is authenticating and the one that processes messages from
* authenticated connections.
*
* <p> Utilising this interface prevents us from having to do a bunch of
* inefficient and ugly comparisons; instead we can simply call through an
* interface method to the proper code.
*/
public interface NetEventHandler
{
/**
* Called when a network event has occurred on the supplied source.
* The <code>events</code> parameter indicates which event or events
* have occurred.
* Called when a network event has occurred on this handler's source.
*
* @return the number of bytes read from the network as a result of
* handling this event.
*/
public int handleEvent (long when, Selectable source, short events);
public int handleEvent (long when);
/**
* Called to ensure that this selectable has not been idle for longer
* Called to ensure that this channel has not been idle for longer
* than is possible in happily operating circumstances.
*
* @return true if the handler is idle (in which case it will be
* closed shortly), false if it is not.
*/
public void checkIdle (long now);
public boolean checkIdle (long now);
}
@@ -1,10 +1,12 @@
//
// $Id: RunningConnection.java,v 1.8 2002/10/29 23:51:26 mdb Exp $
// $Id: RunningConnection.java,v 1.9 2002/11/18 18:53:10 mdb Exp $
package com.threerings.presents.server.net;
import java.io.IOException;
import ninja2.core.io_core.nbio.NonblockingSocket;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import com.samskivert.util.StringUtil;
import com.threerings.presents.net.UpstreamMessage;
@@ -19,12 +21,11 @@ public class RunningConnection extends Connection
* Constructs a new running connection object to manage the supplied
* client socket.
*/
public RunningConnection (ConnectionManager cmgr,
NonblockingSocket socket,
long createStamp)
public RunningConnection (ConnectionManager cmgr, SelectionKey selkey,
SocketChannel channel, long createStamp)
throws IOException
{
super(cmgr, socket, createStamp);
super(cmgr, selkey, channel, createStamp);
}
/**
@@ -36,12 +37,9 @@ public class RunningConnection extends Connection
public String toString ()
{
if (_socket != null) {
return "[mode=RUNNING, id=" + (hashCode() % 1000) +
", addr=" + StringUtil.toString(_socket.getInetAddress()) + "]";
} else {
return "[mode=RUNNING, id=" + (hashCode() % 1000) +
", addr=<disconnected>]";
}
String addr = (_channel == null) ? "<disconnected>" :
StringUtil.toString(_channel.socket().getInetAddress());
return "[mode=RUNNING, id=" + (hashCode() % 1000) +
", addr=" + addr + "]";
}
}