1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.net.time;
19
20 import java.io.DataOutputStream;
21 import java.io.IOException;
22 import java.net.ServerSocket;
23 import java.net.Socket;
24
25 import org.apache.commons.io.IOUtils;
26
27 /**
28 * The TimetSimpleServer class is a simple TCP implementation of a server for the Time Protocol described in RFC 868.
29 * <p>
30 * Listens for TCP socket connections on the time protocol port and writes the local time to socket outputStream as 32-bit integer of seconds since midnight on
31 * 1 January 1900 GMT. See <A HREF="ftp://ftp.rfc-editor.org/in-notes/rfc868.txt"> the spec </A> for details.
32 * <p>
33 * Note this is for <B>debugging purposes only</B> and not meant to be run as a realiable time service.
34 */
35 public class TimeTestSimpleServer implements Runnable {
36
37 /**
38 * baseline time 1900-01-01T00:00:00 UTC
39 */
40 public static final long SECONDS_1900_TO_1970 = 2208988800L;
41
42 /** The default time port. It is set to 37 according to RFC 868. */
43 public static final int DEFAULT_PORT = 37;
44
45 public static void main(final String[] args) {
46 final TimeTestSimpleServer server = new TimeTestSimpleServer();
47 try {
48 server.start();
49 } catch (final IOException e) {
50 // ignored
51 }
52 }
53
54 private ServerSocket server;
55 private final int port;
56
57 private boolean running;
58
59 public TimeTestSimpleServer() {
60 port = DEFAULT_PORT;
61 }
62
63 public TimeTestSimpleServer(final int port) {
64 this.port = port;
65 }
66
67 public void connect() throws IOException {
68 if (server == null) {
69 server = new ServerSocket(port);
70 }
71 }
72
73 public int getPort() {
74 return server == null ? port : server.getLocalPort();
75 }
76
77 public boolean isRunning() {
78 return running;
79 }
80
81 @Override
82 public void run() {
83 Socket socket = null;
84 while (running) {
85 try {
86 socket = server.accept();
87 final DataOutputStream os = new DataOutputStream(socket.getOutputStream());
88 // add 500 ms to round off to nearest second
89 final int time = (int) ((System.currentTimeMillis() + 500) / 1000 + SECONDS_1900_TO_1970);
90 os.writeInt(time);
91 os.flush();
92 } catch (final IOException e) {
93 // ignored
94 } finally {
95 IOUtils.closeQuietly(socket, e -> System.err.println("close socket error: " + e));
96 }
97 }
98 }
99
100 /*
101 * Start time service and provide time to client connections.
102 */
103 public void start() throws IOException {
104 if (server == null) {
105 connect();
106 }
107 if (!running) {
108 running = true;
109 new Thread(this).start();
110 }
111 }
112
113 /*
114 * Close server socket.
115 */
116 public void stop() {
117 running = false;
118 if (server != null) {
119 IOUtils.closeQuietly(server, e -> System.err.println("close socket error: " + e));
120 server = null;
121 }
122 }
123
124 }