1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.app.time.cts; 18 19 import android.util.Log; 20 21 import java.io.IOException; 22 import java.net.DatagramPacket; 23 import java.net.DatagramSocket; 24 import java.net.InetAddress; 25 import java.net.SocketException; 26 import java.util.Arrays; 27 28 /** 29 * Simple Sntp Server implementation for testing purpose. 30 * This is copied from {@code SntpClientTest}. 31 */ 32 class SntpTestServer { 33 private static final String TAG = SntpTestServer.class.getSimpleName(); 34 private static final int ORIGINATE_TIME_OFFSET = 24; 35 private static final int TRANSMIT_TIME_OFFSET = 40; 36 37 private final Object mLock = new Object(); 38 private final DatagramSocket mSocket; 39 private final InetAddress mAddress; 40 private final int mPort; 41 private byte[] mReply; 42 private boolean mGenerateValidOriginateTimestamp = true; 43 private int mRcvd; 44 private int mSent; 45 private final Thread mListeningThread; 46 SntpTestServer()47 SntpTestServer() { 48 mSocket = makeSocket(); 49 mAddress = mSocket.getLocalAddress(); 50 mPort = mSocket.getLocalPort(); 51 Log.d(TAG, "testing server listening on (" + mAddress + ", " + mPort + ")"); 52 53 mListeningThread = new Thread() { 54 public void run() { 55 while (true) { 56 byte[] buffer = new byte[512]; 57 DatagramPacket ntpMsg = new DatagramPacket(buffer, buffer.length); 58 try { 59 mSocket.receive(ntpMsg); 60 } catch (IOException e) { 61 Log.e(TAG, "datagram receive error: " + e); 62 break; 63 } 64 synchronized (mLock) { 65 mRcvd++; 66 if (mReply == null) { 67 continue; 68 } 69 if (mGenerateValidOriginateTimestamp) { 70 // Copy the transmit timestamp into originate timestamp: This is 71 // validated by well-behaved clients. 72 System.arraycopy(ntpMsg.getData(), TRANSMIT_TIME_OFFSET, 73 mReply, ORIGINATE_TIME_OFFSET, 8); 74 } else { 75 // Fill it with junk instead. 76 Arrays.fill(mReply, ORIGINATE_TIME_OFFSET, 77 ORIGINATE_TIME_OFFSET + 8, (byte) 0xFF); 78 } 79 ntpMsg.setData(mReply); 80 ntpMsg.setLength(mReply.length); 81 try { 82 mSocket.send(ntpMsg); 83 } catch (IOException e) { 84 Log.e(TAG, "datagram send error: " + e); 85 break; 86 } 87 mSent++; 88 } 89 } 90 mSocket.close(); 91 } 92 }; 93 mListeningThread.start(); 94 } 95 makeSocket()96 private DatagramSocket makeSocket() { 97 DatagramSocket socket; 98 try { 99 socket = new DatagramSocket(0, InetAddress.getLoopbackAddress()); 100 } catch (SocketException e) { 101 Log.e(TAG, "Failed to create test server socket: " + e); 102 throw new RuntimeException("Failed to create test server socket", e); 103 } 104 return socket; 105 } 106 clearServerReply()107 public void clearServerReply() { 108 setServerReply(null); 109 } 110 setServerReply(byte[] reply)111 public void setServerReply(byte[] reply) { 112 synchronized (mLock) { 113 mReply = reply; 114 mRcvd = 0; 115 mSent = 0; 116 } 117 } 118 119 /** 120 * Controls the test server's behavior of copying the client's transmit timestamp into the 121 * response's originate timestamp (which is required of a real server). 122 */ setGenerateValidOriginateTimestamp(boolean enabled)123 public void setGenerateValidOriginateTimestamp(boolean enabled) { 124 synchronized (mLock) { 125 mGenerateValidOriginateTimestamp = enabled; 126 } 127 } 128 getAddress()129 public InetAddress getAddress() { 130 return mAddress; 131 } 132 getPort()133 public int getPort() { 134 return mPort; 135 } 136 numRequestsReceived()137 public int numRequestsReceived() { 138 synchronized (mLock) { 139 return mRcvd; 140 } 141 } 142 numRepliesSent()143 public int numRepliesSent() { 144 synchronized (mLock) { 145 return mSent; 146 } 147 } 148 } 149