summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
authoreea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1997-07-25 20:46:18 +0000
committereea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1997-07-25 20:46:18 +0000
commit4e86e97b7da359d9135dcd5a248f2260777cd32a (patch)
tree653e990f6f71579ccd0791b8e54760146c8eacfa /java
parentaa495bcca4b6cfff953a61a75477b6a9d950652d (diff)
downloadATCD-4e86e97b7da359d9135dcd5a248f2260777cd32a.tar.gz
This is the first version of the JACE Time Service. Clerk and Server
are drivers in case someone needs to run it without the Service Configurator. It is based on Prashant's earlier test version, but adds support for reconnecting to time servers, etc. The main difference between this and the C++ version is that apps on a machine will have to use sockets to communicate with the time clerk -- you can't use shared memory in Java.
Diffstat (limited to 'java')
-rwxr-xr-xjava/netsvcs/Time/Clerk.java23
-rwxr-xr-xjava/netsvcs/Time/ClientTest.java94
-rwxr-xr-xjava/netsvcs/Time/Server.java23
-rwxr-xr-xjava/netsvcs/Time/TSClerkHandler.java293
-rwxr-xr-xjava/netsvcs/Time/TSClerkProcessor.java267
-rwxr-xr-xjava/netsvcs/Time/TSRequestAcceptor.java142
-rwxr-xr-xjava/netsvcs/Time/TSRequestHandler.java106
-rwxr-xr-xjava/netsvcs/Time/TSServerAcceptor.java100
-rwxr-xr-xjava/netsvcs/Time/TSServerHandler.java99
9 files changed, 1147 insertions, 0 deletions
diff --git a/java/netsvcs/Time/Clerk.java b/java/netsvcs/Time/Clerk.java
new file mode 100755
index 00000000000..f29e08e06f8
--- /dev/null
+++ b/java/netsvcs/Time/Clerk.java
@@ -0,0 +1,23 @@
+// ============================================================================
+//
+// = PACKAGE
+// netsvcs.Time
+//
+// = FILENAME
+// Clerk.java
+//
+// = AUTHOR
+// Prashant Jain
+//
+// ============================================================================
+package netsvcs.Time;
+
+// Test driver for the time server clerk
+public class Clerk
+{
+ public static void main (String [] args)
+ {
+ TSClerkProcessor clerk = new TSClerkProcessor ();
+ clerk.init (args);
+ }
+}
diff --git a/java/netsvcs/Time/ClientTest.java b/java/netsvcs/Time/ClientTest.java
new file mode 100755
index 00000000000..e5453d69243
--- /dev/null
+++ b/java/netsvcs/Time/ClientTest.java
@@ -0,0 +1,94 @@
+package netsvcs.Time;
+
+import JACE.SOCK_SAP.*;
+import java.io.*;
+import java.net.*;
+import JACE.OS.*;
+
+public class ClientTest {
+
+ public static void main(String args[])
+ {
+ // Don't worry about processing command line right now
+
+ int port = 7990;
+
+ String host = new String("flamenco.cs.wustl.edu");
+ // Why isn't the default defined?
+
+
+ SOCKStream cli_stream = new SOCKStream();
+
+ INETAddr remote_addr;
+ try {
+ remote_addr = new INETAddr(port, host);
+ } catch (UnknownHostException uhe) {
+ ACE.ERROR("UnknownHostException " + uhe);
+ return;
+ }
+
+ SOCKConnector con = new SOCKConnector();
+
+ ACE.DEBUG("Starting connect...");
+
+ // Can't do non-blocking connect in Java! Yippee!
+
+ try {
+
+ con.connect(cli_stream, remote_addr);
+
+ } catch (SocketException se) {
+
+ ACE.ERROR("Socket Exception " + se);
+ return;
+
+ } catch (IOException ie) {
+
+ ACE.ERROR("IOException " + ie);
+ return;
+ }
+
+ String input; // need new string here?
+ BufferedReader in
+ = new BufferedReader(new InputStreamReader(System.in));
+
+ try {
+
+ do {
+
+ input = in.readLine();
+
+ if (input.equals("quit"))
+ break;
+
+ cli_stream.send(new StringBuffer(input + "\n"));
+
+ StringBuffer result = new StringBuffer();
+ int chars = cli_stream.recv(result);
+ if (chars == -1)
+ System.out.println("Evil!");
+ else
+ System.out.println(result);
+
+ } while (true);
+
+ // No close_writer, etc...
+ cli_stream.close();
+
+ } catch (IOException ie) {
+
+ ACE.ERROR("IOException, loop: " + ie);
+ return;
+ }
+ }
+};
+
+
+
+
+
+
+
+
+
+
diff --git a/java/netsvcs/Time/Server.java b/java/netsvcs/Time/Server.java
new file mode 100755
index 00000000000..6b44ddf8d9f
--- /dev/null
+++ b/java/netsvcs/Time/Server.java
@@ -0,0 +1,23 @@
+// ============================================================================
+//
+// = PACKAGE
+// netsvcs.Time
+//
+// = FILENAME
+// Server.java
+//
+// = AUTHOR
+// Prashant Jain
+//
+// ============================================================================
+package netsvcs.Time;
+
+// Test driver for the time service server
+public class Server
+{
+ public static void main (String [] args)
+ {
+ TSServerAcceptor server = new TSServerAcceptor ();
+ server.init (args);
+ }
+}
diff --git a/java/netsvcs/Time/TSClerkHandler.java b/java/netsvcs/Time/TSClerkHandler.java
new file mode 100755
index 00000000000..37f7629b44a
--- /dev/null
+++ b/java/netsvcs/Time/TSClerkHandler.java
@@ -0,0 +1,293 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Time
+ *
+ * = FILENAME
+ * TS_Clerk_Handler.java
+ *
+ *@author Prashant Jain, Everett Anderson
+ *
+ *************************************************/
+package netsvcs.Time;
+
+import java.io.*;
+import java.util.Date;
+import JACE.OS.*;
+import JACE.Connection.*;
+import JACE.Reactor.*;
+import JACE.ASX.TimeValue;
+
+/**
+ * <hr>
+ * <p><h2>SYNOPSIS</h2>
+ *
+ * <blockquote>Requests the remote time on a server at regular
+ * intervals.</blockquote>
+ *
+ * <p><h2>DESCRIPTION</h2>
+ *
+ * <blockquote>TSClerkHandlers are created by a TSClerkProcessor. There
+ * is one handler for each server that the Clerk Processor factors into
+ * its calculations.</blockquote>
+ */
+public class TSClerkHandler extends SvcHandler
+{
+ /**
+ * Constructor. TSClerkProcessor specifies the server machine and
+ * port, as well as the interval at which to make the query.
+ */
+ public TSClerkHandler (String hostname,
+ int port,
+ TimerQueue tq,
+ int timeout,
+ TSClerkProcessor parent)
+ {
+
+ this.hostname_ = hostname;
+ this.port_ = port;
+ this.tq_ = tq;
+ this.timeout_ = timeout;
+
+ this.initialTimeout_ = timeout;
+ this.processor_ = parent;
+
+ this.sendMsg_ = new String ("TIME_UPDATE_REQUEST\n");
+ }
+
+ /**
+ * Called to start this handler in a new thread. This only
+ * does it when the state of the handler is INITIALIZING.
+ */
+ public int open (Object obj)
+ {
+ if (this.state_ != RECONNECTING) {
+
+ Thread test = new Thread(this);
+
+ new Thread (this).start ();
+
+ }
+ return 0;
+ }
+
+ /**
+ * Accessor - return the host name of the server
+ */
+ public String hostname ()
+ {
+ return this.hostname_;
+ }
+
+ /**
+ * Accessor - return the port used to contact the server
+ */
+ public int port ()
+ {
+ return this.port_;
+ }
+
+ /**
+ * Accessor - returns the difference between the local time and
+ * the remote server.
+ */
+ public long delta ()
+ {
+ return this.delta_;
+ }
+
+ /**
+ * Called when the thread starts. Schedules itself with the
+ * timer queue.
+ */
+ public void run ()
+ {
+ this.timerId_ = this.tq_.scheduleTimer (this,
+ null,
+ new TimeValue (this.timeout_),
+ new TimeValue (this.timeout_));
+
+ }
+
+ /**
+ * Accessor - return the state
+ */
+ public int state()
+ {
+ return this.state_;
+ }
+
+ /**
+ * Sets the state of the handler
+ */
+ public void state(int newState)
+ {
+ this.state_ = newState;
+ }
+
+ /**
+ * Provides a new time out interval (exponentially increasing) so
+ * that if the server doesn't respond, we don't keep trying to
+ * reconnect as often. Maximum value is 5 minutes.
+ */
+ public int recalculateTimeout()
+ {
+ this.timeout_ *= 2;
+
+ if (this.timeout_ > this.max_timeout_)
+ this.timeout_ = max_timeout_;
+
+ return this.timeout_;
+ }
+
+ /**
+ * Start the recovery from a server disconnection by closing the
+ * port and recalculating the timeout value.
+ */
+ protected void errorRecovery()
+ {
+ ACE.DEBUG("Time Service failure with server " + this.hostname_);
+
+ this.timeout_ = this.recalculateTimeout();
+
+ this.reschedule();
+ }
+
+ /**
+ * Removes this handler from the timer queue, and reschedules it
+ * (presumably with a new timeout value)
+ */
+ public void reschedule()
+ {
+ this.tq_.cancelTimer(this);
+
+ this.timerId_ = this.tq_.scheduleTimer (this,
+ null,
+ new TimeValue (this.timeout_),
+ new TimeValue (this.timeout_));
+ }
+
+ /**
+ * Called back by the timer queue. If the handler isn't connected,
+ * it tries to reconnect to the server. Otherwise, it requests
+ * the remote time. The server is said to have disconnected when
+ * an exception is thrown in the socket system, or the result is
+ * a string with length <= 0.
+ */
+ public int handleTimeout (TimeValue tv, Object obj)
+ {
+ if (this.state_ != CONNECTED) {
+
+ this.processor_.initiateConnection(this);
+
+ // If still not connected
+ if (this.state_ != CONNECTED) {
+
+ // used to set state to reconnecting here
+ this.state_ = RECONNECTING;
+
+ // Reschedule to try again later
+ this.errorRecovery();
+ return 0;
+ }
+
+ // If connected, poll the server at the requested intervals
+ this.resetTimeout();
+ }
+
+ StringBuffer ack = new StringBuffer ();
+ int ackLen;
+ try
+ {
+ // Used to calculate the turn-around time
+ long sendTime = System.currentTimeMillis();
+
+ this.peer ().send (this.sendMsg_);
+ ackLen = this.peer ().recv (ack);
+
+ long recvTime = System.currentTimeMillis();
+
+ if (ackLen <= 0) {
+ this.state_ = DISCONNECTED;
+ return -1;
+
+ } else {
+
+ long delta = (new Long(ack.toString())).longValue() - recvTime;
+
+ delta += (recvTime - sendTime) / 2;
+
+ this.delta_ = delta;
+ }
+
+ }
+ catch (NullPointerException e)
+ {
+ ACE.ERROR ("connection reset by peer");
+ this.state_ = DISCONNECTED;
+ return -1;
+ }
+ catch (IOException e)
+ {
+ ACE.ERROR (e);
+ this.state_ = DISCONNECTED;
+ return -1;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Resets the timer interval to be the one supplied to the
+ * constructor.
+ */
+ public void resetTimeout()
+ {
+ this.timeout_ = this.initialTimeout_;
+
+ this.reschedule();
+ }
+
+ private TSClerkProcessor processor_;
+ // Reference used to re-establish connections
+
+ public static final int MAX_RETRY_TIMEOUT = 300;
+ // Wait at most 5 minutes before trying to reconnect
+
+ // States
+ public static final int CONNECTED = 0;
+ public static final int DISCONNECTED = 1;
+ public static final int RECONNECTING = 2;
+
+ // If there has been a failure, try reconnecting
+ // at least every MAX_RETRY_TIMEOUT seconds
+ private int max_timeout_ = MAX_RETRY_TIMEOUT;
+
+ // State of the handler
+ private int state_ = DISCONNECTED;
+
+ // Difference between the remote time and the local time.
+ private long delta_ = 0;
+
+ // Name of the remote host
+ private String hostname_;
+
+ // Port used for the connection
+ private int port_;
+
+ // Current timer interval
+ private int timeout_;
+
+ // Reference to the Clerk Processor's timer queue
+ private TimerQueue tq_;
+
+ // Message to send for a time update
+ private String sendMsg_;
+
+ // ID of the handler in the queue
+ private int timerId_;
+
+ // Desired time interval to receive updates
+ private int initialTimeout_;
+
+}
diff --git a/java/netsvcs/Time/TSClerkProcessor.java b/java/netsvcs/Time/TSClerkProcessor.java
new file mode 100755
index 00000000000..d7b1773cc9e
--- /dev/null
+++ b/java/netsvcs/Time/TSClerkProcessor.java
@@ -0,0 +1,267 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Time
+ *
+ * = FILENAME
+ * TSClerkProcessor.java
+ *
+ *@author Prashant Jain, Everett Anderson
+ *
+ *************************************************/
+package netsvcs.Time;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import JACE.OS.*;
+import JACE.Misc.*;
+import JACE.Connection.*;
+import JACE.Reactor.*;
+import JACE.ASX.TimeValue;
+
+/**
+ *
+ * <hr>
+ * <p><h2>SYNOPSIS</h2>
+ *
+ * <blockquote>Monitors a specified port (default 7989) and launches
+ * TSClerkHandlers when connections are made. The handlers communicate
+ * with servers and calculate the difference between the server time
+ * and local time. The Clerk Processor averages these differences
+ * and reports them to clients.</blockquote>
+ *
+ * <p><h2>DESCRIPTION</h2>
+ *
+ * <blockquote>This doesn't actually change the system clock, but it
+ * provides the average of the differences of the local and server
+ * times. A client could use this information to adjust the clock, or
+ * just use the midpoint to determine the correct network time.</blockquote>
+ *
+ */
+public class TSClerkProcessor extends Connector implements Runnable
+{
+ /**
+ * Default constructor
+ */
+ public TSClerkProcessor ()
+ {
+ this.serverArray_ = new Vector ();
+
+ }
+
+ /**
+ * Parse the command line, setup the TSRequestAcceptor, and run
+ * the Clerk Processor in its own thread.
+ */
+ public int init (String [] args)
+ {
+ // Parse arguments
+ this.parseArgs (args);
+
+ TSRequestAcceptor ra = new TSRequestAcceptor (this);
+ ra.init (args);
+
+ // Run in own thread of control so that we don't block the caller
+ new Thread (this).start ();
+ return 0;
+ }
+
+
+ /**
+ * Makes connections to the servers, schedules itself for intervals
+ * to update the delta time.
+ */
+ public void run ()
+ {
+
+ // Set up connections with all servers
+ Enumeration table = this.serverArray_.elements ();
+ while (table.hasMoreElements ())
+ {
+ this.initiateConnection((TSClerkHandler)table.nextElement());
+ }
+
+ // Set up timer
+ this.timer_id_ = this.tq_.scheduleTimer (this,
+ null,
+ new TimeValue (this.timeout_),
+ new TimeValue (this.timeout_));
+ }
+
+ /**
+ * Makes connections to the servers.
+ */
+ public void initiateConnection (TSClerkHandler handler)
+ {
+ this.open (handler.hostname(), handler.port());
+
+ try
+ {
+ // Connect to the server
+ this.connect (handler);
+
+ // Set the state of the Clerk Handler so it queries the
+ // server at intervals.
+ handler.state(TSClerkHandler.CONNECTED);
+
+ }
+ catch (UnknownHostException e)
+ {
+ ACE.ERROR (e);
+ }
+ catch (SocketException e)
+ {
+ ACE.ERROR ("Connection refused");
+ }
+ catch (InstantiationException e)
+ {
+ ACE.ERROR (e);
+ }
+ catch (IllegalAccessException e)
+ {
+ ACE.ERROR (e);
+ }
+ catch (IOException e)
+ {
+ ACE.ERROR (e);
+ }
+ }
+
+
+ /**
+ *
+ * Called by the timer queue. Calls updateTime().
+ */
+ public int handleTimeout (TimeValue tv, Object obj)
+ {
+ return this.updateTime ();
+ }
+
+ /**
+ * Calculates the delta time by averaging the results from
+ * Clerk Handler delta()'s. It only includes handlers whose
+ * state is currently CONNECTED. If they're not connected, it
+ * reschedules them to begin the error correction process of
+ * trying to reconnect to the server (possible synch problems?).
+ */
+ protected int updateTime ()
+ {
+ TSClerkHandler handler;
+ int count = 0;
+ long totalDeltaTime = 0;
+
+ Enumeration table = this.serverArray_.elements ();
+
+ while (table.hasMoreElements ())
+ {
+ handler = (TSClerkHandler) table.nextElement ();
+
+ if (handler.state() != TSClerkHandler.CONNECTED) {
+
+ // Reconnecting state means we don't need to put
+ // it in the timer queue again
+ if (handler.state() == TSClerkHandler.RECONNECTING)
+ continue;
+ else
+ if (handler.state() == TSClerkHandler.DISCONNECTED)
+ handler.state(TSClerkHandler.RECONNECTING);
+
+ handler.errorRecovery();
+ continue;
+ }
+
+ long delta = handler.delta();
+
+ ACE.DEBUG(handler.hostname() + ": " + delta);
+
+ totalDeltaTime += delta;
+ count++;
+ }
+
+ if (count > 0) {
+
+ this.timeDelta_ = totalDeltaTime / count;
+
+ ACE.DEBUG("Average deviation: " + totalDeltaTime/count);
+
+ } else
+
+ this.timeDelta_ = 0;
+
+ return 0;
+ }
+
+ /**
+ * Return the delta time.
+ */
+ public long getDelta()
+ {
+ return this.timeDelta_;
+ }
+
+ /**
+ * Parse the command line. Watches for -t <time> and
+ * -h <machine:port> switches. Must specify time
+ * value before host switches!
+ */
+ protected void parseArgs (String args[])
+ {
+ String s;
+ GetOpt opt = new GetOpt (args, "t:h:");
+ for (int c; (c = opt.next ()) != -1; )
+ {
+ switch (c)
+ {
+ case 't':
+ s = opt.optarg ();
+ this.timeout_ = (new Integer (s)).intValue ();
+ break;
+ case 'h':
+ s = opt.optarg ();
+ this.addNewHandler (s);
+ break;
+ default:
+ ACE.ERROR ("Bad command line argument: " + c);
+
+ ACE.ERROR ("Valid arguments: -t <timeout> -h <hostname>:<port> -h ...");
+ break;
+ }
+ }
+ }
+
+ /**
+ *
+ * Creates a new Clerk Handler and adds it to the serverArray_
+ */
+ private void addNewHandler (String s)
+ {
+ StringTokenizer tokens = new StringTokenizer (s, ":");
+ String hostname = tokens.nextToken ();
+
+ int port = (new Integer (tokens.nextToken ())).intValue ();
+
+ // Create new handler and add it to array of servers
+ this.serverArray_.addElement (new TSClerkHandler (hostname,
+ port,
+ this.tq_,
+ this.timeout_,
+ this));
+ }
+
+ // Vector of TSClerkHandlers, one for each server
+ private Vector serverArray_;
+
+ // Default interval at which to update the time
+ private int timeout_ = 1000;
+
+ // Timer queue which calls handleTimeout when the Clerk Processor
+ // is supposed to update the time.
+ private TimerQueue tq_ = new TimerQueue (true);
+
+ // Clerk Processor ID in the timer queue
+ private int timer_id_;
+
+ // Average of the differences of the local and server times.
+ private long timeDelta_;
+}
diff --git a/java/netsvcs/Time/TSRequestAcceptor.java b/java/netsvcs/Time/TSRequestAcceptor.java
new file mode 100755
index 00000000000..e02b0b261ba
--- /dev/null
+++ b/java/netsvcs/Time/TSRequestAcceptor.java
@@ -0,0 +1,142 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Time
+ *
+ * = FILENAME
+ * TSRequestAcceptor.java
+ *
+ *@author Prashant Jain, Everett Anderson
+ *
+ *************************************************/
+package netsvcs.Time;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import JACE.OS.*;
+import JACE.Misc.*;
+import JACE.Connection.*;
+import JACE.Reactor.*;
+
+/**
+ * <hr>
+ * <p><h2>SYNOPSIS</h2>
+ *
+ * <blockquote>Monitors a specified port (default 7990) and launches
+ * TSRequestHandlers when connections are made. The handlers
+ * report the average deviation from the local time when input
+ * is received to their sockets.</blockquote>
+ *
+ * <p><h2>DESCRIPTION</h2>
+ * <blockquote>This is in place of the shared memory system used in C++ ACE.
+ * The clients need to request the correct time range from the Clerk, so
+ * they can do it with <a href="ACE.SOCK_SAP.SOCKStream.html#_top_">
+ * <tt>sockets</tt></a>. An instance of TSRequestAcceptor is created
+ * and initialized in TSClerkProcessor init(). This should be the
+ * only place it's used.</blockquote>
+ *
+ * @see ACE.SOCK_SAP.SOCKAcceptor,ACE.netsvcs.Time.TSClerkProcessor
+ */
+
+public class TSRequestAcceptor extends Acceptor implements Runnable
+{
+ /**
+ * Create an instance of TSRequestAcceptor. Default constructor.
+ */
+ public TSRequestAcceptor (TSClerkProcessor parent)
+ {
+ this.parent_ = parent;
+ }
+
+ /**
+ *
+ * Process command line arguments (port), and start this instance
+ * in its own thread.
+ *
+ */
+ public int init(String [] args)
+ {
+ this.parseArgs (args);
+
+ new Thread (this).start();
+ return 0;
+ }
+
+ /**
+ *
+ * Called when the thread starts. Open the port and accept
+ * connections.
+ */
+ public void run ()
+ {
+ try {
+ this.open (this.port_);
+ while (true)
+ this.accept();
+ }
+ catch (SocketException e)
+ {
+ ACE.ERROR (e);
+ }
+ catch (InstantiationException e)
+ {
+ ACE.ERROR (e);
+ }
+ catch (IllegalAccessException e)
+ {
+ ACE.ERROR (e);
+ }
+ catch (IOException e)
+ {
+ ACE.ERROR (e);
+ }
+
+ System.err.println("Stopped accepting");
+ }
+
+ /**
+ *
+ * Parse the command line. This only looks for -p <port number>.
+ *
+ */
+ protected void parseArgs (String args[])
+ {
+ String s;
+ GetOpt opt = new GetOpt (args, "p:");
+
+ for (int c; (c = opt.next ()) != -1; )
+ {
+ switch (c)
+ {
+ case 'p':
+ s = opt.optarg ();
+ this.port_ = (new Integer (s)).intValue ();
+ break;
+ default:
+ ACE.ERROR("Invalid argument: " + c);
+ break;
+ }
+ }
+ }
+
+ /**
+ *
+ * Modifies to behavior of Acceptor accept() so the TSClerkProcessor
+ * reference can be passed to the TSRequestHandler.
+ *
+ */
+
+ protected SvcHandler makeSvcHandler ()
+ throws InstantiationException, IllegalAccessException
+ {
+ return (SvcHandler) new TSRequestHandler(parent_);
+ }
+
+ // Port to monitor
+ private int port_ = 7990;
+
+ // Reference to the Clerk Processor (which holds the time value)
+ private TSClerkProcessor parent_;
+};
+
diff --git a/java/netsvcs/Time/TSRequestHandler.java b/java/netsvcs/Time/TSRequestHandler.java
new file mode 100755
index 00000000000..dbeded22250
--- /dev/null
+++ b/java/netsvcs/Time/TSRequestHandler.java
@@ -0,0 +1,106 @@
+package netsvcs.Time;
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Time
+ *
+ * = FILENAME
+ * TSRequestHandler.java
+ *
+ *@author Prashant Jain, Everett Anderson
+ *
+ *************************************************/
+import java.io.*;
+import java.util.*;
+import JACE.OS.*;
+import JACE.Connection.*;
+import JACE.Reactor.*;
+
+/**
+ * <hr>
+ * <p><h2>SYNOPSIS</h2>
+ *
+ * <blockquote>Handles giving the client the average difference between
+ * the local time and the server times.</blockquote>
+ *
+ * <p><h2>DESCRIPTION</h2>
+ *
+ * <blockquote>Whenever the RequestHandler receives input to the port, it
+ * sends the current delta (average difference time) in return as a string.
+ * Instances of this class are created by TSRequestAcceptor.</blockquote>
+ */
+public class TSRequestHandler extends SvcHandler
+{
+ /**
+ * Constructor. Takes in a reference to the Clerk Processor
+ * so it can call TSClerkProcessor getDelta().
+ */
+ public TSRequestHandler (TSClerkProcessor processor)
+ {
+ this.processor_ = processor;
+ }
+
+ /**
+ *
+ * Run this in a separate thread.
+ */
+ public int open (Object obj)
+ {
+ new Thread (this).start ();
+ return 0;
+ }
+
+ /**
+ *
+ * Called when the thread starts. This is the main code -- whenever
+ * input comes to the socket, it sends out the current delta time
+ * as a string.
+ */
+ public void run ()
+ {
+ int msgLen;
+ try
+ {
+ while (true)
+ {
+ StringBuffer msg = new StringBuffer ();
+
+ msgLen = this.peer ().recv (msg);
+
+ if (msgLen < 0)
+ break;
+ else {
+
+ // No matter what was sent in, send the average difference back
+
+ String msgOut = new String("" + this.processor_.getDelta() + '\n');
+ this.peer ().send (msgOut);
+
+ }
+ }
+ }
+ catch (NullPointerException e)
+ {
+ ACE.ERROR ("Connection reset by peer");
+ }
+ catch (IOException e)
+ {
+ ACE.ERROR (e);
+ }
+ finally
+ {
+ try
+ {
+ this.peer ().close ();
+ }
+ catch (IOException e)
+ {
+ ACE.ERROR (e);
+ }
+ }
+ }
+
+
+ // Reference to the Clerk Processor to call getDelta()
+ TSClerkProcessor processor_;
+}
diff --git a/java/netsvcs/Time/TSServerAcceptor.java b/java/netsvcs/Time/TSServerAcceptor.java
new file mode 100755
index 00000000000..2d54f7b740b
--- /dev/null
+++ b/java/netsvcs/Time/TSServerAcceptor.java
@@ -0,0 +1,100 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Time
+ *
+ * = FILENAME
+ * TS_Server_Acceptor.java
+ *
+ *@author Prashant Jain
+ *
+ *************************************************/
+package netsvcs.Time;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import JACE.OS.*;
+import JACE.Misc.*;
+import JACE.Connection.*;
+import JACE.Reactor.*;
+
+/**
+ * <hr>
+ * <p><h2>DESCRIPTION</h2>
+ *
+ * Acceptor: listens to a port and launches TSServerHandlers
+ * when connections are made.
+ *
+ * @see netsvcs.Time.TSServerHandler, JACE.Connection.Acceptor
+ */
+public class TSServerAcceptor extends Acceptor implements Runnable
+{
+ // Run this in its own thread
+ public int init (String [] args)
+ {
+ // Parse arguments
+ this.parseArgs (args);
+
+ // Run in own thread of control so that we don't block the caller
+ new Thread (this).start ();
+ return 0;
+ }
+
+ // Create a TSServerHandler for each client that wants to connect
+ public void run ()
+ {
+ try
+ {
+ this.setHandlerFactory (Class.forName ("netsvcs.Time.TSServerHandler"));
+ this.open (this.port_);
+ while (true)
+ this.accept ();
+ }
+ catch (ClassNotFoundException e)
+ {
+ ACE.ERROR (e);
+ }
+ catch (SocketException e)
+ {
+ ACE.ERROR ("Socket Exception: " + e);
+ }
+ catch (InstantiationException e)
+ {
+ ACE.ERROR (e);
+ }
+ catch (IllegalAccessException e)
+ {
+ ACE.ERROR (e);
+ }
+ catch (IOException e)
+ {
+ ACE.ERROR (e);
+ }
+
+ System.err.println("Stopped accepting");
+ }
+
+ // Process the command line
+ protected void parseArgs (String args[])
+ {
+ String s;
+ GetOpt opt = new GetOpt (args, "p:");
+ for (int c; (c = opt.next ()) != -1; )
+ {
+ switch (c)
+ {
+ case 'p':
+ s = opt.optarg ();
+ this.port_ = (new Integer (s)).intValue ();
+ break;
+ default:
+ ACE.ERROR ("Unknown argument: " + c);
+ break;
+ }
+ }
+ }
+
+ private int port_ = 7989;
+}
+
diff --git a/java/netsvcs/Time/TSServerHandler.java b/java/netsvcs/Time/TSServerHandler.java
new file mode 100755
index 00000000000..0fa940d2388
--- /dev/null
+++ b/java/netsvcs/Time/TSServerHandler.java
@@ -0,0 +1,99 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Time
+ *
+ * = FILENAME
+ * TS_Server_Handler.java
+ *
+ *@author Prashant Jain, Everett Anderson
+ *
+ *************************************************/
+package netsvcs.Time;
+
+import java.io.*;
+import java.util.*;
+import JACE.OS.*;
+import JACE.Connection.*;
+import JACE.Reactor.*;
+
+/**
+ * <hr>
+ * <p><h2>DESCRIPTION</h2>
+ *
+ * <blockquote>Handles requests from a TSClerkHandler and sends
+ * back the current local time.</blockquote>
+ *
+ * @see netsvcs.Time.TSClerkHandler. netsvcs.Time.TSServerAcceptor
+ */
+
+public class TSServerHandler extends SvcHandler
+{
+ // Constructor
+ public TSServerHandler ()
+ {
+ }
+
+ // Start this handler in its own thread
+ public int open (Object obj)
+ {
+
+ new Thread (this).start ();
+ return 0;
+ }
+
+ // Wait for messages from the Client and send the current local
+ // time back as a string.
+ public void run ()
+ {
+ int msgLen;
+ try
+ {
+ while (true)
+ {
+ // Use a new one each time since recv appends
+ StringBuffer msg = new StringBuffer ();
+
+ // Get the message from the client (blocks)
+ msgLen = this.peer ().recv (msg);
+
+ // Just keep waiting if there's a problem
+ if (msgLen <= 0)
+ break;
+
+ // Is the message for the right thing?
+ if (msg.toString().compareTo ("TIME_UPDATE_REQUEST") != 0) {
+ System.err.println("Unknown message: \"" + msg + '\"');
+ this.peer().send("\n"); // send so other side isn't stuck
+ break;
+ }
+
+ // Get local time
+ long time = System.currentTimeMillis();
+
+ // Send as a string
+ this.peer ().send ("" + time + '\n');
+
+ ACE.DEBUG("Time: " + new Date(time));
+ }
+ }
+ catch (NullPointerException e)
+ {
+ ACE.ERROR ("Connection reset by peer");
+ }
+ catch (IOException e)
+ {
+ ACE.ERROR (e);
+ }
+ finally
+ {
+ try
+ {
+ this.peer ().close ();
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+}