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:
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user