package com.ronsoft.books.nio.channels; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.DatagramChannel; import java.net.SocketAddress; import java.net.InetSocketAddress; import java.net.SocketException; /** * Provide RFC 868 time service (http://www.ietf.org/rfc/rfc0868.txt). * This code implements an RFC 868 listener to provide time * service. The defined port for time service is 37. On most * unix systems, root privilege is required to bind to ports * below 1024. You can either run this code as root or * provide another port number on the command line. Use * "-p port#" with TimeClient if you choose an alternate port. * * Note: The familiar rdate command on unix will probably not work * with this server. Most versions of rdate use TCP rather than UDP * to request the time. * * Created: April 2002 * @author Ron Hitchens (ron@ronsoft.com) * @version $Id: TimeServer.java,v 1.1 2002/04/28 22:07:43 ron Exp $ */ public class TimeServer { private static final int DEFAULT_TIME_PORT = 37; private static final long DIFF_1900 = 2208988800L; // -------------------------------------------------------------- protected DatagramChannel channel; public TimeServer (int port) throws Exception { this.channel = DatagramChannel.open(); this.channel.socket().bind (new InetSocketAddress (port)); System.out.println ("Listening on port " + port + " for time requests"); } public void listen() throws Exception { // allocate a buffer to hold a long value ByteBuffer longBuffer = ByteBuffer.allocate (8); // assure big-endian (network) byte order longBuffer.order (ByteOrder.BIG_ENDIAN); // zero the whole buffer to be sure longBuffer.putLong (0, 0); // position to first byte of the low-order 32 bits longBuffer.position (4); // slice the buffer, gives view of the low-order 32 bits ByteBuffer buffer = longBuffer.slice(); while (true) { buffer.clear(); SocketAddress sa = this.channel.receive (buffer); if (sa == null) { continue; // defensive programming } // ignore content of recived datagram per rfc 868 System.out.println ("Time request from " + sa); buffer.clear(); // sets pos/limit correctly // set 64-bit value, slice buffer sees low 32 bits longBuffer.putLong (0, (System.currentTimeMillis() / 1000) + DIFF_1900); this.channel.send (buffer, sa); } } // -------------------------------------------------------------- public static void main (String [] argv) throws Exception { int port = DEFAULT_TIME_PORT; if (argv.length > 0) { port = Integer.parseInt (argv [0]); } try { TimeServer server = new TimeServer (port); server.listen(); } catch (SocketException e) { System.out.println ("Can't bind to port " + port + ", try a different one"); } } }