/* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.management.jdp; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.EOFException; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * JdpPacketReader responsible for reading a packet <p>This class gets a byte * array as it came from a Net, validates it and breaks a part </p> */ public final class JdpPacketReader { private final DataInputStream pkt; private Map<String, String> pmap = null; /** * Create packet reader, extract and check magic and version * * @param packet - packet received from a Net * @throws JdpException */ public JdpPacketReader(byte[] packet) throws JdpException { ByteArrayInputStream bais = new ByteArrayInputStream(packet); pkt = new DataInputStream(bais); try { int magic = pkt.readInt(); JdpGenericPacket.checkMagic(magic); } catch (IOException e) { throw new JdpException("Invalid JDP packet received, bad magic"); } try { short version = pkt.readShort(); JdpGenericPacket.checkVersion(version); } catch (IOException e) { throw new JdpException("Invalid JDP packet received, bad protocol version"); } } /** * Get next entry from packet * * @return the entry * @throws EOFException * @throws JdpException */ public String getEntry() throws EOFException, JdpException { try { short len = pkt.readShort(); // Artificial setting the "len" field to Short.MAX_VALUE may cause a reader to allocate // to much memory. Prevent this possible DOS attack. if (len < 1 && len > pkt.available()) { throw new JdpException("Broken JDP packet. Invalid entry length field."); } byte[] b = new byte[len]; if (pkt.read(b) != len) { throw new JdpException("Broken JDP packet. Unable to read entry."); } return new String(b, "UTF-8"); } catch (EOFException e) { throw e; } catch (UnsupportedEncodingException ex) { throw new JdpException("Broken JDP packet. Unable to decode entry."); } catch (IOException e) { throw new JdpException("Broken JDP packet. Unable to read entry."); } } /** * return packet content as a key/value map * * @return map containing packet entries pair of entries treated as * key,value * @throws IOException * @throws JdpException */ public Map<String, String> getDiscoveryDataAsMap() throws JdpException { // return cached map if possible if (pmap != null) { return pmap; } String key = null, value = null; final Map<String, String> tmpMap = new HashMap<>(); try { while (true) { key = getEntry(); value = getEntry(); tmpMap.put(key, value); } } catch (EOFException e) { // EOF reached on reading value, report broken packet // otherwise ignore it. if (value == null) { throw new JdpException("Broken JDP packet. Key without value." + key); } } pmap = Collections.unmodifiableMap(tmpMap); return pmap; } }