Revamped the basic Presents client to support attempts to connect to the server

on multiple ports, falling back from one to the next as appropriate.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4158 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2006-05-30 22:12:15 +00:00
parent a3dfc741c6
commit 77adfc15ec
18 changed files with 128 additions and 112 deletions
@@ -42,9 +42,9 @@ import com.threerings.presents.net.PongResponse;
*/
public class Client
{
/** The default port on which the server listens for client
/** The default ports on which the server listens for client
* connections. */
public static final int DEFAULT_SERVER_PORT = 47624;
public static final int[] DEFAULT_SERVER_PORTS = { 47624 };
/**
* Constructs a client object with the supplied credentials and
@@ -115,15 +115,15 @@ public class Client
}
/**
* Configures the client to communicate with the server on the
* supplied hostname/port combination.
* Configures the client to communicate with the server on the supplied
* hostname and set of ports (which will be tried in succession).
*
* @see #logon
*/
public void setServer (String hostname, int port)
public void setServer (String hostname, int[] ports)
{
_hostname = hostname;
_port = port;
_ports = ports;
}
/**
@@ -148,9 +148,9 @@ public class Client
* Returns the port on which this client is currently configured to
* connect to the server.
*/
public int getPort ()
public int[] getPorts ()
{
return _port;
return _ports;
}
/**
@@ -519,6 +519,19 @@ public class Client
}
}
/**
* Called by the {@link Communicator} if it is experiencing trouble logging
* on but is still trying fallback strategies.
*/
protected void reportLogonTribulations (final LogonException cause)
{
_runQueue.postRunnable(new Runnable() {
public void run () {
notifyObservers(CLIENT_FAILED_TO_LOGON, cause);
}
});
}
/**
* Called by the invocation director when it successfully subscribes
* to the client object immediately following logon.
@@ -731,8 +744,8 @@ public class Client
/** The game server host. */
protected String _hostname;
/** The port on which we connect to the game server. */
protected int _port;
/** The ports on which we connect to the game server. */
protected int[] _ports;
/** Our list of client observers. */
protected ObserverList _observers =
@@ -1,5 +1,5 @@
//
// $Id: ClientObserver.java,v 1.9 2004/08/27 02:20:18 mdb Exp $
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
@@ -53,6 +53,14 @@ public interface ClientObserver extends SessionObserver
* Called if anything fails during the logon attempt. This could be a
* network failure, authentication failure or otherwise. The exception
* provided will indicate the cause of the failure.
*
* @param cause an exception indicating the cause of the logon failure.
* <em>Note:</em> this may be a {@link LogonException} and if so, the
* caller <em>must</em> check {@link LogonException#isStillInProgress} to
* find out if the logon process has totally failed or if we are simply
* reporting intermediate status (we might be falling back to an
* alternative port or delaying our auto-retry attempt due to server
* overload).
*/
public void clientFailedToLogon (Client client, Exception cause);
@@ -27,10 +27,12 @@ import java.io.InterruptedIOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import com.samskivert.swing.RuntimeAdjust;
import com.samskivert.util.IntListUtil;
import com.samskivert.util.LoopingThread;
import com.samskivert.util.Queue;
import com.samskivert.util.StringUtil;
@@ -41,6 +43,7 @@ import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream;
import com.threerings.presents.Log;
import com.threerings.presents.data.AuthCodes;
import com.threerings.presents.dobj.DObjectManager;
import com.threerings.presents.net.AuthRequest;
import com.threerings.presents.net.AuthResponse;
@@ -429,17 +432,34 @@ public class Communicator
// look up the address of the target server
InetAddress host = InetAddress.getByName(_client.getHostname());
int port = _client.getPort();
// establish a socket connection to said server
Log.debug("Connecting [host=" + host + ", port=" + port + "].");
InetSocketAddress addr = new InetSocketAddress(host, port);
try {
_channel = SocketChannel.open(addr);
} catch (IOException ioe) {
Log.warning("Error opening [addr=" + addr + "].");
throw ioe; // rethrow
// obtain the list of available ports on which to attempt our
// client connection and determine our preferred port
String pportKey = _client.getHostname() + ".preferred_port";
int[] ports = _client.getPorts();
int pport = PresentsPrefs.config.getValue(pportKey, ports[0]);
int ppidx = Math.max(0, IntListUtil.indexOf(ports, pport));
// try connecting on each of the ports in succession
for (int ii = 0; ii < ports.length; ii++) {
int port = ports[(ii+ppidx)%ports.length];
Log.info("Connecting [host=" + host + ", port=" + port + "].");
InetSocketAddress addr = new InetSocketAddress(host, port);
try {
_channel = SocketChannel.open(addr);
PresentsPrefs.config.setValue(pportKey, port);
break;
} catch (IOException ioe) {
if (ioe instanceof ConnectException && ii < ports.length) {
_client.reportLogonTribulations(
new LogonException(
AuthCodes.TRYING_NEXT_PORT, true));
continue; // try the next port
}
throw ioe;
}
}
_channel.configureBlocking(true);
// our messages are framed (preceded by their length), so we
@@ -1,5 +1,5 @@
//
// $Id: LogonException.java,v 1.4 2004/08/27 02:20:18 mdb Exp $
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
@@ -33,6 +33,34 @@ public class LogonException extends Exception
*/
public LogonException (String code)
{
super(code);
this(code, false);
}
/**
* Constructs a logon exception with the supplied logon failure code.
*
* @param stillInProgress indicates that the logon attempt has not totally
* failed, rather we are still trying but want to report that our initial
* attempt did not work and that we're falling back to alternative methods.
*/
public LogonException (String code, boolean stillInProgress)
{
super(code);
_stillInProgress = stillInProgress;
}
/**
* Returns true if this exception is reporting an intermediate status
* rather than total logon failure. The client may be falling back to an
* alternative port or delaying an auto-retry attempt due to server
* overload. If this method returns true, the client <em>should not</em>
* allow additional calls to {@link Client#logon} as the current attempt is
* still in progress.
*/
public boolean isStillInProgress ()
{
return _stillInProgress;
}
protected boolean _stillInProgress;
}