Checking in some work I did on getting listening on port 443 working by

inheriting a socket channel inetd style. It doesn't actually work for annoying
reasons, but I figured I'd get the code in there and the type safety fixes and
maybe Sun will fix their stupid bug at some point (I should create a test case
and actually submit a bug report...).


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4230 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2006-06-27 17:33:06 +00:00
parent 755d9326fe
commit 01e9b0457d
@@ -23,6 +23,7 @@ package com.threerings.presents.server.net;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.Channel;
import java.nio.channels.SelectableChannel; import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey; import java.nio.channels.SelectionKey;
import java.nio.channels.Selector; import java.nio.channels.Selector;
@@ -99,7 +100,7 @@ public class ConnectionManager extends LoopingThread
* anything on those methods that will conflict with activities on the * anything on those methods that will conflict with activities on the
* dobjmgr thread, etc. * dobjmgr thread, etc.
*/ */
public void setStartupListener (ResultListener rl) public void setStartupListener (ResultListener<Object> rl)
{ {
_startlist = rl; _startlist = rl;
} }
@@ -149,9 +150,7 @@ public class ConnectionManager extends LoopingThread
_stats.deathQueueSize[_stats.current] = _deathq.size(); _stats.deathQueueSize[_stats.current] = _deathq.size();
_stats.outQueueSize[_stats.current] = _outq.size(); _stats.outQueueSize[_stats.current] = _outq.size();
if (_oflowqs.size() > 0) { if (_oflowqs.size() > 0) {
Iterator oqiter = _oflowqs.values().iterator(); for (OverflowQueue oq : _oflowqs.values()) {
while (oqiter.hasNext()) {
OverflowQueue oq = (OverflowQueue)oqiter.next();
_stats.overQueueSize[_stats.current] += oq.size(); _stats.overQueueSize[_stats.current] += oq.size();
} }
} }
@@ -242,9 +241,7 @@ public class ConnectionManager extends LoopingThread
int code, Connection conn, Object arg1, Object arg2) int code, Connection conn, Object arg1, Object arg2)
{ {
synchronized (_observers) { synchronized (_observers) {
for (int i = 0; i < _observers.size(); i++) { for (ConnectionObserver obs : _observers) {
ConnectionObserver obs =
(ConnectionObserver)_observers.get(i);
switch (code) { switch (code) {
case CONNECTION_ESTABLISHED: case CONNECTION_ESTABLISHED:
obs.connectionEstablished(conn, (AuthRequest)arg1, obs.connectionEstablished(conn, (AuthRequest)arg1,
@@ -272,29 +269,14 @@ public class ConnectionManager extends LoopingThread
for (int ii = 0; ii < _ports.length; ii++) { for (int ii = 0; ii < _ports.length; ii++) {
try { try {
// create a listening socket and add it to the select set // create a listening socket and add it to the select set
final ServerSocketChannel listener = ServerSocketChannel.open(); ServerSocketChannel listener = ServerSocketChannel.open();
listener.configureBlocking(false); listener.configureBlocking(false);
InetSocketAddress isa = new InetSocketAddress(_ports[ii]); InetSocketAddress isa = new InetSocketAddress(_ports[ii]);
listener.socket().bind(isa); listener.socket().bind(isa);
Log.info("Server listening on " + isa + "."); registerChannel(listener);
// register this 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(listener);
// there's no easy way to measure bytes read when
// accepting a connection, so we claim nothing
return 0;
}
public boolean checkIdle (long now) {
return false; // we're never idle
}
});
successes++; successes++;
Log.info("Server listening on " + isa + ".");
} catch (IOException ioe) { } catch (IOException ioe) {
Log.warning("Failure listening to socket on " + Log.warning("Failure listening to socket on " +
@@ -304,6 +286,34 @@ public class ConnectionManager extends LoopingThread
} }
} }
// NOTE: this is not currently working; it works but for whatever
// inscrutable reason the inherited channel claims to be readable
// immediately every time through the select() loop which causes the
// server to consume 100% of the CPU repeatedly ignoring the inherited
// channel (except when an actual connection comes in in which case it
// does the right thing)
// // now look to see if we were passed a socket inetd style by a
// // privileged parent process
// try {
// Channel inherited = System.inheritedChannel();
// if (inherited instanceof ServerSocketChannel) {
// ServerSocketChannel listener = (ServerSocketChannel)inherited;
// listener.configureBlocking(false);
// registerChannel(listener);
// successes++;
// Log.info("Server listening on " +
// listener.socket().getInetAddress() + ":" +
// listener.socket().getLocalPort() + ".");
// } else if (inherited != null) {
// Log.warning("Inherited non-server-socket channel " +
// inherited + ".");
// }
// } catch (IOException ioe) {
// Log.warning("Failed to check for inherited channel.");
// }
// if we failed to listen on at least one port, give up the ghost // if we failed to listen on at least one port, give up the ghost
if (successes == 0) { if (successes == 0) {
if (_startlist != null) { if (_startlist != null) {
@@ -321,6 +331,26 @@ public class ConnectionManager extends LoopingThread
} }
} }
/** Helper function for {@link #willStart}. */
protected void registerChannel (final ServerSocketChannel listener)
throws IOException
{
// register this listening socket and map its select key to a net event
// handler that will accept new connections
SelectionKey sk = listener.register(_selector, SelectionKey.OP_ACCEPT);
_handlers.put(sk, new NetEventHandler() {
public int handleEvent (long when) {
acceptConnection(listener);
// there's no easy way to measure bytes read when accepting a
// connection, so we claim nothing
return 0;
}
public boolean checkIdle (long now) {
return false; // we're never idle
}
});
}
/** /**
* Performs the select loop. This is the body of the conmgr thread. * Performs the select loop. This is the body of the conmgr thread.
*/ */
@@ -340,21 +370,18 @@ public class ConnectionManager extends LoopingThread
} }
// close connections that have had no network traffic for too long // close connections that have had no network traffic for too long
Iterator hiter = _handlers.values().iterator(); for (NetEventHandler handler : _handlers.values()) {
while (hiter.hasNext()) {
NetEventHandler handler = (NetEventHandler)hiter.next();
if (handler.checkIdle(iterStamp)) { if (handler.checkIdle(iterStamp)) {
// this will queue the connection up for closure on our // this will queue the connection for closure on our next tick
// next tick
closeConnection((Connection)handler); closeConnection((Connection)handler);
} }
} }
// attempt to send any messages waiting on the overflow queues // attempt to send any messages waiting on the overflow queues
if (_oflowqs.size() > 0) { if (_oflowqs.size() > 0) {
Iterator oqiter = _oflowqs.values().iterator(); Iterator<OverflowQueue> oqiter = _oflowqs.values().iterator();
while (oqiter.hasNext()) { while (oqiter.hasNext()) {
OverflowQueue oq = (OverflowQueue)oqiter.next(); OverflowQueue oq = oqiter.next();
try { try {
// try writing the messages in this overflow queue // try writing the messages in this overflow queue
if (oq.writeOverflowMessages(iterStamp)) { if (oq.writeOverflowMessages(iterStamp)) {
@@ -376,7 +403,7 @@ public class ConnectionManager extends LoopingThread
// if an overflow queue exists for this client, go ahead and // if an overflow queue exists for this client, go ahead and
// slap the message on there because we can't send it until // slap the message on there because we can't send it until
// all other messages in their queue have gone out // all other messages in their queue have gone out
OverflowQueue oqueue = (OverflowQueue)_oflowqs.get(conn); OverflowQueue oqueue = _oflowqs.get(conn);
if (oqueue != null) { if (oqueue != null) {
int size = oqueue.size(); int size = oqueue.size();
if ((size > 500) && (size % 50 == 0)) { if ((size > 500) && (size % 50 == 0)) {
@@ -412,7 +439,7 @@ public class ConnectionManager extends LoopingThread
_handlers.put(selkey, rconn); _handlers.put(selkey, rconn);
// transfer any overflow queue for that connection // transfer any overflow queue for that connection
Object oflowHandler = _oflowqs.remove(conn); OverflowQueue oflowHandler = _oflowqs.remove(conn);
if (oflowHandler != null) { if (oflowHandler != null) {
_oflowqs.put(rconn, oflowHandler); _oflowqs.put(rconn, oflowHandler);
} }
@@ -428,7 +455,7 @@ public class ConnectionManager extends LoopingThread
} }
} }
Set ready = null; Set<SelectionKey> ready = null;
try { try {
// check for incoming network events // check for incoming network events
// Log.debug("Selecting from " + // Log.debug("Selecting from " +
@@ -472,12 +499,10 @@ public class ConnectionManager extends LoopingThread
// process those events // process those events
// Log.info("Ready set " + StringUtil.toString(ready) + "."); // Log.info("Ready set " + StringUtil.toString(ready) + ".");
Iterator siter = ready.iterator(); for (SelectionKey selkey : ready) {
while (siter.hasNext()) {
SelectionKey selkey = (SelectionKey)siter.next();
NetEventHandler handler = null; NetEventHandler handler = null;
try { try {
handler = (NetEventHandler)_handlers.get(selkey); handler = _handlers.get(selkey);
if (handler == null) { if (handler == null) {
Log.warning("Received network event but have no " + Log.warning("Received network event but have no " +
"registered handler [selkey=" + selkey + "]."); "registered handler [selkey=" + selkey + "].");
@@ -664,7 +689,8 @@ public class ConnectionManager extends LoopingThread
return; return;
} catch (IOException ioe) { } catch (IOException ioe) {
Log.warning("Failure accepting new connection: " + ioe); // Log.warning("Failure accepting new connection: " + ioe);
// ioe.printStackTrace(System.err);
} }
// make sure we don't leak a socket if something went awry // make sure we don't leak a socket if something went awry
@@ -856,13 +882,14 @@ public class ConnectionManager extends LoopingThread
protected int[] _ports; protected int[] _ports;
protected Authenticator _author; protected Authenticator _author;
protected Selector _selector; protected Selector _selector;
protected ResultListener _startlist; protected ResultListener<Object> _startlist;
/** Counts consecutive runtime errors in select(). */ /** Counts consecutive runtime errors in select(). */
protected int _runtimeExceptionCount; protected int _runtimeExceptionCount;
/** Maps selection keys to network event handlers. */ /** Maps selection keys to network event handlers. */
protected HashMap _handlers = new HashMap(); protected HashMap<SelectionKey,NetEventHandler> _handlers =
new HashMap<SelectionKey,NetEventHandler>();
protected Queue _deathq = new Queue(); protected Queue _deathq = new Queue();
protected Queue _authq = new Queue(); protected Queue _authq = new Queue();
@@ -871,9 +898,11 @@ public class ConnectionManager extends LoopingThread
protected FramingOutputStream _framer; protected FramingOutputStream _framer;
protected ByteBuffer _outbuf = ByteBuffer.allocateDirect(64 * 1024); protected ByteBuffer _outbuf = ByteBuffer.allocateDirect(64 * 1024);
protected HashMap _oflowqs = new HashMap(); protected HashMap<Connection,OverflowQueue> _oflowqs =
new HashMap<Connection,OverflowQueue>();
protected ArrayList _observers = new ArrayList(); protected ArrayList<ConnectionObserver> _observers =
new ArrayList<ConnectionObserver>();
/** Bytes in and out in the last reporting period. */ /** Bytes in and out in the last reporting period. */
protected long _bytesIn, _bytesOut; protected long _bytesIn, _bytesOut;