]> git.basschouten.com Git - openhab-addons.git/blob
7850a432f1dd6bbfd608d53ff4f0a186f26b44cf
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.ntp.server;
14
15 import java.io.IOException;
16 import java.net.DatagramPacket;
17 import java.net.DatagramSocket;
18 import java.net.SocketException;
19
20 import org.apache.commons.net.ntp.NtpV3Impl;
21 import org.apache.commons.net.ntp.NtpV3Packet;
22 import org.apache.commons.net.ntp.TimeStamp;
23 import org.openhab.binding.ntp.test.NtpOSGiTest;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * This is a simple NTP server which provides timestamps to the {@link NtpOSGiTest} tests.
29  * Its main purpose is to remove the dependence on a remote ntp server because it is hosted locally.
30  *
31  * @author Erdoan Hadzhiyusein - Initial Contribution
32  *
33  */
34 public class SimpleNTPServer {
35
36     private DatagramSocket socket;
37     private int port;
38     private volatile boolean isRunning;
39     private byte[] array = new byte[48];
40     private final DatagramPacket request = new DatagramPacket(array, array.length);
41     private Logger logger = LoggerFactory.getLogger(SimpleNTPServer.class);
42
43     /**
44      * The server must use an available port to be able to start.
45      * According to RFC 793, the port is a 16 bit unsigned int.
46      *
47      * @param port
48      */
49     public SimpleNTPServer(int port) {
50         if (port > 0 && port < 65535) {
51             this.port = port;
52         } else {
53             throw new IllegalArgumentException(
54                     "Please choose an available port! This port cannot be used at the moment" + port);
55         }
56     }
57
58     /**
59      * This method opens a new socket and receives requests calling handleRequest() for each one.
60      */
61     public void startServer() {
62         isRunning = true;
63
64         new Thread() {
65             @Override
66             public void run() {
67                 try {
68                     socket = new DatagramSocket(port);
69                 } catch (SocketException e) {
70                     logger.error("Occured an error {}. Couldn't open a socket on this port:", port, e);
71                 }
72                 while (isRunning) {
73                     try {
74                         socket.receive(request);
75                         handleRequest(request);
76                     } catch (IOException e) {
77                         logger.error("There was an error {} while processing the request!", request, e);
78                     }
79                 }
80             }
81         }.start();
82     }
83
84     /**
85      * Stopping the server which causes closing the socket too
86      */
87     public void stopServer() {
88         isRunning = false;
89         if (socket != null) {
90             socket.close(); // force closing of the socket
91             socket = null;
92         }
93     }
94
95     private void handleRequest(DatagramPacket requestPacket) throws IOException {
96         final long receivedTime = System.currentTimeMillis();
97         NtpV3Packet responsePacket = new NtpV3Impl();
98         responsePacket.setMode(NtpV3Packet.MODE_SERVER);
99         responsePacket.setTransmitTime(TimeStamp.getNtpTime(receivedTime));
100         DatagramPacket dataPacket = responsePacket.getDatagramPacket();
101         dataPacket.setPort(requestPacket.getPort());
102         dataPacket.setAddress(requestPacket.getAddress());
103         socket.send(dataPacket);
104     }
105 }