1 /* 2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /** 25 * A JVM with JDP on should send multicast JDP packets regularly. 26 * Look at JdpOnTestCase.java and JdpOffTestCase.java 27 */ 28 29 30 import sun.management.jdp.JdpJmxPacket; 31 32 import java.io.IOException; 33 import java.io.UnsupportedEncodingException; 34 import java.net.DatagramPacket; 35 import java.net.MulticastSocket; 36 import java.net.SocketTimeoutException; 37 import java.util.Arrays; 38 import java.util.Map; 39 import java.util.logging.Level; 40 import java.util.logging.Logger; 41 42 public abstract class JdpTestCase { 43 final Logger log = Logger.getLogger("sun.management.jdp"); 44 final int MAGIC = 0xC0FFEE42; // Jdp magic number. 45 private static final int BUFFER_LENGTH = 64 * 1024; // max UDP size, except for IPv6 jumbograms. 46 private final int TIME_OUT_FACTOR = 10; // Socket times out after 10 times the jdp pause. 47 protected int timeOut; 48 private long startTime; 49 protected ClientConnection connection; 50 JdpTestCase(ClientConnection connection)51 public JdpTestCase(ClientConnection connection) { 52 this.connection = connection; 53 JdpTestUtil.enableConsoleLogging(log, Level.ALL); 54 } 55 run()56 public void run() throws Exception { 57 log.fine("Test started."); 58 log.fine("Listening for multicast packets at " + connection.address.getHostAddress() 59 + ":" + String.valueOf(connection.port)); 60 log.fine(initialLogMessage()); 61 log.fine("Pause in between packets is: " + connection.pauseInSeconds + " seconds."); 62 63 startTime = System.currentTimeMillis(); 64 timeOut = connection.pauseInSeconds * TIME_OUT_FACTOR; 65 log.fine("Timeout set to " + String.valueOf(timeOut) + " seconds."); 66 67 MulticastSocket socket = connection.connectWithTimeout(timeOut * 1000); 68 69 byte[] buffer = new byte[BUFFER_LENGTH]; 70 DatagramPacket datagram = new DatagramPacket(buffer, buffer.length); 71 72 do { 73 try { 74 socket.receive(datagram); 75 onReceived(extractUDPpayload(datagram)); 76 } catch (SocketTimeoutException e) { 77 onSocketTimeOut(e); 78 } 79 80 if (hasTestLivedLongEnough()) { 81 shutdown(); 82 } 83 84 } while (shouldContinue()); 85 log.fine("Test ended successfully."); 86 } 87 88 /** 89 * Subclasses: JdpOnTestCase and JdpOffTestCase have different messages. 90 */ initialLogMessage()91 protected abstract String initialLogMessage(); 92 93 94 /** 95 * Executed when the socket receives a UDP packet. 96 */ onReceived(byte[] packet)97 private void onReceived(byte[] packet) throws Exception { 98 if (isJDP(packet)) { 99 Map<String, String> payload = checkStructure(packet); 100 jdpPacketReceived(payload); 101 } else { 102 log.fine("Non JDP packet received, ignoring it."); 103 } 104 } 105 106 /** 107 * Determine whether the test should end. 108 * 109 * @return 110 */ shouldContinue()111 abstract protected boolean shouldContinue(); 112 113 /** 114 * This method is executed when the socket has not received any packet for timeOut seconds. 115 */ onSocketTimeOut(SocketTimeoutException e)116 abstract protected void onSocketTimeOut(SocketTimeoutException e) throws Exception; 117 118 /** 119 * This method is executed after a correct Jdp packet has been received. 120 * 121 * @param payload A dictionary containing the data if the received Jdp packet. 122 */ jdpPacketReceived(Map<String, String> payload)123 private void jdpPacketReceived(Map<String, String> payload) throws Exception { 124 final String instanceName = payload.get("INSTANCE_NAME"); 125 if (instanceName.equals(connection.instanceName)) { 126 packetFromThisVMReceived(payload); 127 } else { 128 packetFromOtherVMReceived(payload); 129 } 130 } 131 132 /** 133 * This method is executed after a correct Jdp packet, coming from this VM has been received. 134 * 135 * @param payload A dictionary containing the data if the received Jdp packet. 136 */ packetFromThisVMReceived(Map<String, String> payload)137 protected abstract void packetFromThisVMReceived(Map<String, String> payload) throws Exception; 138 139 140 /** 141 * This method is executed after a correct Jdp packet, coming from another VM has been received. 142 * 143 * @param payload A dictionary containing the data if the received Jdp packet. 144 */ packetFromOtherVMReceived(Map<String, String> payload)145 protected void packetFromOtherVMReceived(Map<String, String> payload) { 146 final String jdpName = payload.get("INSTANCE_NAME"); 147 log.fine("Ignoring JDP packet sent by other VM, jdp.name=" + jdpName); 148 } 149 150 151 /** 152 * The test should stop if it has been 12 times the jdp.pause. 153 * jdp.pause is how many seconds in between packets. 154 * <p/> 155 * This timeout (12 times)is slightly longer than the socket timeout (10 times) on purpose. 156 * In the off test case, the socket should time out first. 157 * 158 * @return 159 */ hasTestLivedLongEnough()160 protected boolean hasTestLivedLongEnough() { 161 long now = System.currentTimeMillis(); 162 boolean haslivedLongEnough = (now - startTime) > (timeOut * 1.2 * 1000); 163 return haslivedLongEnough; 164 } 165 166 /** 167 * This exit condition arises when we receive UDP packets but they are not valid Jdp. 168 */ shutdown()169 protected void shutdown() throws Exception { 170 log.severe("Shutting down the test."); 171 throw new Exception("Not enough JDP packets received before timeout!"); 172 } 173 174 /** 175 * Assert that this Jdp packet contains the required two keys. 176 * <p/> 177 * We expect zero packet corruption and thus fail on the first corrupted packet. 178 * This might need revision. 179 */ checkStructure(byte[] packet)180 protected Map<String, String> checkStructure(byte[] packet) throws UnsupportedEncodingException { 181 Map<String, String> payload = JdpTestUtil.readPayload(packet); 182 assertTrue(payload.size() >= 2, "JDP should have minimun 2 entries."); 183 assertTrue(payload.get(JdpJmxPacket.UUID_KEY).length() > 0); 184 assertTrue(payload.get(JdpJmxPacket.JMX_SERVICE_URL_KEY).length() > 0); 185 return payload; 186 } 187 188 189 /** 190 * Check if packet has correct JDP magic number. 191 * 192 * @param packet 193 * @return 194 * @throws IOException 195 */ isJDP(byte[] packet)196 private boolean isJDP(byte[] packet) throws IOException { 197 int magic = JdpTestUtil.decode4ByteInt(packet, 0); 198 return (magic == MAGIC); 199 } 200 extractUDPpayload(DatagramPacket datagram)201 private byte[] extractUDPpayload(DatagramPacket datagram) { 202 byte[] data = Arrays.copyOf(datagram.getData(), datagram.getLength()); 203 return data; 204 } 205 206 /** 207 * Hack until I find a way to use TestNG's assertions. 208 */ assertTrue(boolean assertion, String message)209 private void assertTrue(boolean assertion, String message) { 210 if (assertion == false) { 211 log.severe(message); 212 assert (false); 213 } 214 } 215 assertTrue(boolean assertion)216 private void assertTrue(boolean assertion) { 217 assertTrue(assertion, ""); 218 } 219 220 } 221