From 45fb96c4f260f350d9f819f285850c760dfb5898 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Mon, 18 Nov 2002 18:53:10 +0000 Subject: [PATCH] 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 --- .../presents/client/Communicator.java | 58 +++-- .../server/net/AuthingConnection.java | 17 +- .../presents/server/net/Connection.java | 87 +++---- .../server/net/ConnectionManager.java | 232 ++++++++++++------ .../presents/server/net/NetEventHandler.java | 32 +-- .../server/net/RunningConnection.java | 24 +- 6 files changed, 270 insertions(+), 180 deletions(-) diff --git a/src/java/com/threerings/presents/client/Communicator.java b/src/java/com/threerings/presents/client/Communicator.java index 970973112..ec49c9ad9 100644 --- a/src/java/com/threerings/presents/client/Communicator.java +++ b/src/java/com/threerings/presents/client/Communicator.java @@ -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; diff --git a/src/java/com/threerings/presents/server/net/AuthingConnection.java b/src/java/com/threerings/presents/server/net/AuthingConnection.java index 1ba547dae..129d9cf97 100644 --- a/src/java/com/threerings/presents/server/net/AuthingConnection.java +++ b/src/java/com/threerings/presents/server/net/AuthingConnection.java @@ -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; diff --git a/src/java/com/threerings/presents/server/net/Connection.java b/src/java/com/threerings/presents/server/net/Connection.java index 3d1ac1794..5e19576a8 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.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; diff --git a/src/java/com/threerings/presents/server/net/ConnectionManager.java b/src/java/com/threerings/presents/server/net/ConnectionManager.java index 4c0823299..2fd1bfee9 100644 --- a/src/java/com/threerings/presents/server/net/ConnectionManager.java +++ b/src/java/com/threerings/presents/server/net/ConnectionManager.java @@ -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; diff --git a/src/java/com/threerings/presents/server/net/NetEventHandler.java b/src/java/com/threerings/presents/server/net/NetEventHandler.java index 96b232a58..d67f149b7 100644 --- a/src/java/com/threerings/presents/server/net/NetEventHandler.java +++ b/src/java/com/threerings/presents/server/net/NetEventHandler.java @@ -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 Selectable, - * 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. + * + *

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 events 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); } diff --git a/src/java/com/threerings/presents/server/net/RunningConnection.java b/src/java/com/threerings/presents/server/net/RunningConnection.java index b5d13533f..f2c802851 100644 --- a/src/java/com/threerings/presents/server/net/RunningConnection.java +++ b/src/java/com/threerings/presents/server/net/RunningConnection.java @@ -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=]"; - } + String addr = (_channel == null) ? "" : + StringUtil.toString(_channel.socket().getInetAddress()); + return "[mode=RUNNING, id=" + (hashCode() % 1000) + + ", addr=" + addr + "]"; } }