org.safs.sockets
Class SocketProtocol

java.lang.Object
  extended by org.safs.sockets.SocketProtocol
Direct Known Subclasses:
DroidSocketProtocol

public class SocketProtocol
extends java.lang.Object

This class implements a TCP protocol needed for Sockets control of remote processes through TCP String messages character encoded in UTF-8.

The class implements both the "local" controller side and the "remote" ServerSocket side in order to keep the protocol implementation for both sides correct.

This class is not normally used directly, but thru subclasses of AbstractProtocolRunner which provides the necessary separate Threading required for the SocketProtocol.

Currently, this protocol expects remote TCP services to be running and accepting connections on port DEFAULT_REMOTE_PORT at the first, if port DEFAULT_REMOTE_PORT is no available, remote TCP services will try to run on 2412, 2414 ... with augmentation of pace 2, the maximum possible port is MAX_SERVER_PORT. By trying a broad range of ports, it can prevent conflicts with other system resources. Currently, this protocol lets local controller to contact and attempt a connection to those remote TCP services. As those TCP services can choose port dynamically, the local controller doesn't know which remote port to use for the connection. It will try to connect to port DEFAULT_REMOTE_PORT, if fail it will try to connect to port 2412, 2414 ... with augmentation of pace 2, the maximum possible port is MAX_SERVER_PORT.

If there is no need for the local controller's port to be specific--such as using port forwarding to local emulators appearing as remote machines--then the local controller port really could be any port at all.

There is an initial handshake or verification that occurs between the local and remote SocketProtocol instances to confirm the device port owners are both SocketProtocol implementations.

See Also:
(LeiWang) SEP 29, 2012 Fix a connection problem for mobile-device connected by USB (portForwarding is used)

Field Summary
 boolean _debugEnabled
          set to false to disable debug logging and improve performance.
protected  int controllerPort
          port to use for a local controller Runner.
protected  java.net.Socket controllerRunner
          local controller Socket connection.
protected static java.lang.String debugprefix
           
static int DEFAULT_CONTROLLER_PORT
           
static int DEFAULT_REMOTE_PORT
           
static java.lang.String DEFAULT_SERVER
           
static java.lang.String ENV_KEY_REMOTE_PORT
           
protected  java.lang.String EOM
          "[!_!]" Case-Insensitive End-Of-Message marker for all character messages exchanged between local and remote runners.
Normally, this is never changed.
static int MAX_SERVER_PORT
           
static java.lang.String MSG_PROTOCOL_VERSION_QUERY
          "PROTOCOLVERSION" Prompt and partial response for initial handshake between the local protocol runner and a remote protocol runner.
static int NEXT_SERVER_PORT_PACE
           
protected  java.lang.String remoteHostname
          Hostname to contact for a remote client Runner.
protected  int remotePort
          port to contact for a remote client Runner.
static int STATUS_SHUTDOWN_CONTROLLER
          Indicates the Socket is being shutdown because from the controller side.
static int STATUS_SHUTDOWN_NORMAL
          Indicates the Socket is being shutdown normally.
static int STATUS_SHUTDOWN_REMOTE_CLIENT
          Indicates the Socket is being shutdown abnormally no remote client connection will be possible.
static int STATUS_SHUTDOWN_REMOTE_SERVICE
          Indicates the Socket is being shutdown abnormally because no remote service connection will be possible.
protected static java.lang.String[] STATUS_STRINGS
          String representations of the STATUS_SHUTDOWN causes.
 java.lang.String TAG
           
 
Constructor Summary
SocketProtocol()
          Default no-op constructor using all defaults.
SocketProtocol(NamedListener listener)
          Constructor using all defaults while registering a NamedListener.
SocketProtocol(NamedListener listener, boolean local_mode)
          Constructor using all defaults while registering a NamedListener and setting the local or remote mode of the instance.
 
Method Summary
 boolean acceptProtocolVersion(int protocol)
          By default, this class only accepts connections from instances using the same protocol version.
 boolean addListener(NamedListener listener)
          Register a DebugListener/ConnectionListener.
protected  void bindToRemoteServer()
          Create the Socket object according to server name and port.
 void closeProtocolRunners()
          Simply callse closeStreams
 boolean connectProtocolRunners()
          Attempt to create appropriate local or remote socket connections and attempt to connect with the other side.
protected  void debug(java.lang.String text)
          Convenience routine for logging debug messages.
 int getClientConnectTimeout()
          Default is set at 60 seconds.
 int getConnectedProtocol()
           
 int getControllerPort()
          The default port currently used for outgoing controller Socket connections is 2411.
 java.lang.String getEOM()
           
 boolean getKeepAlive()
          By default keepAlive is TRUE unless changed.
 int getNextPort(int prevPort)
          Try to augment the port number by 2
 java.lang.String getRemoteHostname()
          The default remote hostname is/was typically the "localhost".
 int getRemotePort()
          The default port currently used for remote client connections--typically port 2410.
static java.lang.String getShutdownCauseDescription(int cause)
           
 boolean isConnected()
           
 boolean isLocalMode()
           
 boolean removeListener(NamedListener listener)
           
 boolean sendResponse(java.lang.String message)
          Send UTF-8 encoded message to the connected instance, if any.
 void setClientConnectTimeout(int clientConnectTimeout)
          Default is set at 60 seconds.
 void setControllerPort(int port)
          Provide an alternate port on which the local controller should open a Socket.
 void setEOM(java.lang.String marker)
           
 void setKeepAlive(boolean keepAlive)
          By default keepAlive is TRUE unless changed.
 void setLocalMode(boolean local_mode)
          Set the mode of this instance.
 void setRemoteHostname(java.lang.String hostname)
          The default remote hostname is/was typically the "localhost".
 void setRemotePort(int port)
          Provide an alternate port on which the remote client is accepting connections.
 java.lang.String waitForInput(long msTimeout)
          Listen for UTF-8 encoded content from the connected instance and return it to the caller if it is deemed valid.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

TAG

public java.lang.String TAG

DEFAULT_SERVER

public static final java.lang.String DEFAULT_SERVER
See Also:
Constant Field Values

DEFAULT_REMOTE_PORT

public static final int DEFAULT_REMOTE_PORT
See Also:
Constant Field Values

DEFAULT_CONTROLLER_PORT

public static final int DEFAULT_CONTROLLER_PORT
See Also:
Constant Field Values

MAX_SERVER_PORT

public static final int MAX_SERVER_PORT
See Also:
Constant Field Values

NEXT_SERVER_PORT_PACE

public static final int NEXT_SERVER_PORT_PACE
See Also:
Constant Field Values

MSG_PROTOCOL_VERSION_QUERY

public static final java.lang.String MSG_PROTOCOL_VERSION_QUERY
"PROTOCOLVERSION" Prompt and partial response for initial handshake between the local protocol runner and a remote protocol runner. The local runner will send this prompt terminated with the EOM marker and expects to receive a response in the format of "PROTOCOLVERSION=N"--an Integer representing the remote runner's protocol version. Currently, only "PROTOCOLVERSION=1" showing version 1 is supported. The response String is expected to be terminated with the EOM marker.

See Also:
Constant Field Values

ENV_KEY_REMOTE_PORT

public static final java.lang.String ENV_KEY_REMOTE_PORT
See Also:
Constant Field Values

STATUS_SHUTDOWN_NORMAL

public static final int STATUS_SHUTDOWN_NORMAL
Indicates the Socket is being shutdown normally.

See Also:
#shutdownThread, shutdownCause, Constant Field Values

STATUS_SHUTDOWN_REMOTE_CLIENT

public static final int STATUS_SHUTDOWN_REMOTE_CLIENT
Indicates the Socket is being shutdown abnormally no remote client connection will be possible. All attempts have been exhausted.

See Also:
#shutdownThread, shutdownCause, Constant Field Values

STATUS_SHUTDOWN_REMOTE_SERVICE

public static final int STATUS_SHUTDOWN_REMOTE_SERVICE
Indicates the Socket is being shutdown abnormally because no remote service connection will be possible. All attempts have been exhausted.

See Also:
#shutdownThread, shutdownCause, Constant Field Values

STATUS_SHUTDOWN_CONTROLLER

public static final int STATUS_SHUTDOWN_CONTROLLER
Indicates the Socket is being shutdown because from the controller side.

See Also:
#shutdownThread, shutdownCause, Constant Field Values

STATUS_STRINGS

protected static final java.lang.String[] STATUS_STRINGS
String representations of the STATUS_SHUTDOWN causes.


EOM

protected java.lang.String EOM
"[!_!]" Case-Insensitive End-Of-Message marker for all character messages exchanged between local and remote runners.
Normally, this is never changed. The local and remote runner implementations--coded together (or this same class)--share in an implied contract of what this marker shall be since both ends of the protocol must use it.


remoteHostname

protected java.lang.String remoteHostname
Hostname to contact for a remote client Runner.


remotePort

protected int remotePort
port to contact for a remote client Runner.


controllerPort

protected int controllerPort
port to use for a local controller Runner.


controllerRunner

protected java.net.Socket controllerRunner
local controller Socket connection.


_debugEnabled

public boolean _debugEnabled
set to false to disable debug logging and improve performance.


debugprefix

protected static final java.lang.String debugprefix
See Also:
Constant Field Values
Constructor Detail

SocketProtocol

public SocketProtocol()
Default no-op constructor using all defaults. The user should change any desired remote settings and add any DebugListeners and ConnectionListerners prior to starting the full use of the instance.


SocketProtocol

public SocketProtocol(NamedListener listener)
Constructor using all defaults while registering a NamedListener. The user should change any desired remote hostname/port settings prior to starting the full use of the instance.

Parameters:
listener - NamedListener (DebugListener, ConnectionListener, etc...) to register with the new instance. Ideally, the listener should implement both DebugListener and ConnectionListener interfaces.

SocketProtocol

public SocketProtocol(NamedListener listener,
                      boolean local_mode)
Constructor using all defaults while registering a NamedListener and setting the local or remote mode of the instance.

By default, the class is setup to run in local controller mode. Users would normally only call this constructor to make local_mode = false and run in remote client mode.

The user should change any desired remote hostname/port settings prior to starting the full use of the instance.

Parameters:
listener - NamedListener to register with the new instance. Ideally, the listener should implement both DebugListener and ConnectionListener interfaces.
Method Detail

setLocalMode

public void setLocalMode(boolean local_mode)
                  throws java.lang.IllegalThreadStateException
Set the mode of this instance. True for local controller mode and false for remote client mode. By default, the class is setup to run in local controller mode.

Parameters:
local_mode - true to run in local protocol controller mode (ex: port 2411). false to run in remote protocal client mode (ex: port 2410).
Throws:
java.lang.IllegalThreadStateException - if a call attempts to set/change this while the instance is already connected or running.

isLocalMode

public boolean isLocalMode()
Returns:
true if the Runner is set for local controller mode. false for remote client mode.

addListener

public boolean addListener(NamedListener listener)
Register a DebugListener/ConnectionListener. If no DebugListener is registered then our debug output, if enabled, will go to System.out.println.

Parameters:
listener - to register to receive notifications.
Returns:
true if the listener was new and was successfully added
See Also:
notifyConnection(), notifyLocalShutdown(int), notifyRemoteShutdown(int)

removeListener

public boolean removeListener(NamedListener listener)
Parameters:
listener -
Returns:
true if the listener was found and was successfully removed

debug

protected void debug(java.lang.String text)
Convenience routine for logging debug messages. Simply forwards the call to notifyDebug(String).

Parameters:
text -
See Also:
notifyDebug(String)

getShutdownCauseDescription

public static java.lang.String getShutdownCauseDescription(int cause)
Parameters:
cause - -- int STATUS_SHUTDOWN_xxx cause to describe.
Returns:
A String description of the cause of the shutdown. This is deduced from the shutdownCause int being used as a String[] lookup in STATUS_STRINGS.
See Also:
STATUS_STRINGS

getEOM

public java.lang.String getEOM()
Returns:
the current Case-insensitive End-Of-Message marker String ending all character messages in the protocol.
Normally, this is never changed. The local and remote runner implementations--coded together (or this same class)--share in an implied contract of what this marker shall be since both ends of the protocol must use it.

setEOM

public void setEOM(java.lang.String marker)
            throws java.lang.IllegalArgumentException
Parameters:
Case-insensitive - End-Of-Message marker String to use for terminating all String messages in the protocol. Normally, this is never changed. The local and remote runner implementations--coded together (or this same class)--share in an implied contract of what this marker shall be since both ends of the protocol must use it.
Throws:
java.lang.IllegalArgumentException - if the supplied marker argument is null, zero-length, or appears to be case-sensitive when comparing calls for toUpperCase() and toLowerCase().

bindToRemoteServer

protected void bindToRemoteServer()
                           throws java.io.IOException
Create the Socket object according to server name and port.

Throws:
java.io.IOException

getNextPort

public int getNextPort(int prevPort)
Try to augment the port number by 2

Parameters:
prevPort - int, the previous port number
Returns:
int, the next port number
Throws:
IllegalStateException, - if the next port number exceeds the max port number.

isConnected

public boolean isConnected()
Returns:
true if we have a validated 2-way connection.

acceptProtocolVersion

public boolean acceptProtocolVersion(int protocol)
By default, this class only accepts connections from instances using the same protocol version. It is possible future subclasses will want to override this behavior to accept other--typically older known protocol versions.

Parameters:
protocol -
Returns:
true if our supported protocol version matches the requested version.

closeProtocolRunners

public void closeProtocolRunners()
Simply callse closeStreams

See Also:
closeStreams()

waitForInput

public java.lang.String waitForInput(long msTimeout)
                              throws java.io.InvalidObjectException
Listen for UTF-8 encoded content from the connected instance and return it to the caller if it is deemed valid.

String content is not considered valid unless/until the End-Of-Message marker is received. Without receiving the EOM within the timeout period the routine will consider any received content invalid and will subsequently return a null value upon timeout.

Parameters:
msTimeout - timeout in milliseconds
Returns:
received input or null if no input stream available or no valid input received in timeout period. The EOM will have already been stripped from the message.
Throws:
java.io.InvalidObjectException - if we have no InputStream connected.
See Also:
EOM

sendResponse

public boolean sendResponse(java.lang.String message)
                     throws java.io.InvalidObjectException
Send UTF-8 encoded message to the connected instance, if any. This routine automatically adds the End-Of-Message marker to the message before sending it. Thus, callers should not put any End-of_message marker on the message to be sent.

Parameters:
message -
Returns:
true if we sent the message to the connected socket stream without error. This should NOT be considered any kind of confirmation that the remote TCP client received the message.
Throws:
java.io.InvalidObjectException - if we have no OutputStream connected.
See Also:
EOM

connectProtocolRunners

public boolean connectProtocolRunners()
Attempt to create appropriate local or remote socket connections and attempt to connect with the other side.

Returns:
results of call to isConnected()
See Also:
isConnected(), createRemoteServerSocket(), acceptControllerConnection(int), createRemoteClientConnection(int)

getKeepAlive

public boolean getKeepAlive()
By default keepAlive is TRUE unless changed.

Returns:
the keepAlive

setKeepAlive

public void setKeepAlive(boolean keepAlive)
By default keepAlive is TRUE unless changed.

Parameters:
keepAlive - the keepAlive to set

getRemoteHostname

public java.lang.String getRemoteHostname()
The default remote hostname is/was typically the "localhost". This is because the initial use and implementation for this protocol was for talking with simulators and emulators acting as remote devices on the local machine. Other uses may actually use a remote hostname that is NOT on the local machine.

Returns:
the server hostname on which we expect remote clients to accept connections.

setRemoteHostname

public void setRemoteHostname(java.lang.String hostname)
The default remote hostname is/was typically the "localhost". This is because the initial use and implementation for this protocol was for talking with simulators and emulators acting as remote devices on the local machine. Other uses may actually use a remote hostname that is NOT on the local machine.

Parameters:
the - server hostname on which we expect remote clients to accept connections.

getRemotePort

public int getRemotePort()
The default port currently used for remote client connections--typically port 2410.

Returns:
the server port on which we expect remote clients to accept connections.

setRemotePort

public void setRemotePort(int port)
Provide an alternate port on which the remote client is accepting connections. The default port currently used for remote client connections is 2410. In the future a broader set of predefined port numbers needs to be established to avoid resource contention.

Parameters:
remote - server port on which the remote client is accepting connections.

getControllerPort

public int getControllerPort()
The default port currently used for outgoing controller Socket connections is 2411.

Typically Sockets can normally communicate on "any available port". However the initial use and implementation for this protocol was for talking with simulators and emulators acting as remote devices on the local machine. Thus, it was necessary to be able to do port forwarding to specifically forward a known local controller port to the known remote client port.

Returns:
the port on which we expect local controller Socket to communicate.

setControllerPort

public void setControllerPort(int port)
Provide an alternate port on which the local controller should open a Socket. The default port currently used for local controller communications is 2411. Typically Sockets can normally communicate on "any available port". The initial use and implementation for this protocol was for talking with simulators and emulators acting as remote devices on the local machine. Thus, it was necessary to be able to do port forwarding to specifically forward a known local controller port to the known remote client port.

Parameters:
the - port on which the local controller Socket will attempt to communicate.

getConnectedProtocol

public int getConnectedProtocol()
                         throws java.io.InvalidObjectException
Returns:
the protocol version for the remote connection. Currently, only version 1 is known or supported.
Throws:
java.io.InvalidObjectException - if we have not successfully connected to a remote client.

getClientConnectTimeout

public int getClientConnectTimeout()
Default is set at 60 seconds. This value is typically used internally for the call to createRemoteClientConnection(int)

Returns:
the current clientConnectTimeout setting.

setClientConnectTimeout

public void setClientConnectTimeout(int clientConnectTimeout)
Default is set at 60 seconds. This value is typically used internally for the call to createRemoteClientConnection(int)

Parameters:
clientConnectTimeout - in seconds