Improved memory/gc usage, replaced generic hashmaps with implementation
specific versions.
This commit is contained in:
parent
4d87ba10c1
commit
dc54c9b226
|
@ -2,7 +2,9 @@
|
|||
|
||||
package dorkbox.network.dns;
|
||||
|
||||
import java.util.HashMap;
|
||||
import com.esotericsoftware.kryo.util.IntMap;
|
||||
|
||||
import dorkbox.util.collections.ObjectIntMap;
|
||||
|
||||
/**
|
||||
* A utility class for converting between numeric codes and mnemonics
|
||||
|
@ -13,29 +15,21 @@ import java.util.HashMap;
|
|||
public
|
||||
class Mnemonic {
|
||||
|
||||
private static Integer cachedInts[] = new Integer[64];
|
||||
/* Strings are case-sensitive. */
|
||||
public static final int CASE_SENSITIVE = 1;
|
||||
/* Strings will be stored/searched for in uppercase. */
|
||||
public static final int CASE_UPPER = 2;
|
||||
/* Strings will be stored/searched for in lowercase. */
|
||||
public static final int CASE_LOWER = 3;
|
||||
|
||||
|
||||
private HashMap<String, Integer> strings;
|
||||
private HashMap<Integer, String> values;
|
||||
private static final int INVALID_VALUE = -1;
|
||||
private ObjectIntMap<String> strings;
|
||||
private IntMap<String> values;
|
||||
private String description;
|
||||
private int wordcase;
|
||||
private String prefix;
|
||||
private int max;
|
||||
private boolean numericok;
|
||||
|
||||
static {
|
||||
for (int i = 0; i < cachedInts.length; i++) {
|
||||
cachedInts[i] = new Integer(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Mnemonic table.
|
||||
*
|
||||
|
@ -48,8 +42,8 @@ class Mnemonic {
|
|||
Mnemonic(String description, int wordcase) {
|
||||
this.description = description;
|
||||
this.wordcase = wordcase;
|
||||
strings = new HashMap();
|
||||
values = new HashMap();
|
||||
strings = new ObjectIntMap<String>();
|
||||
values = new IntMap<String>();
|
||||
max = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
|
@ -93,29 +87,17 @@ class Mnemonic {
|
|||
/**
|
||||
* Defines the text representation of a numeric value.
|
||||
*
|
||||
* @param val The numeric value
|
||||
* @param value The numeric value
|
||||
* @param string The text string
|
||||
*/
|
||||
public
|
||||
void add(int val, String string) {
|
||||
check(val);
|
||||
Integer value = toInteger(val);
|
||||
void add(int value, String string) {
|
||||
check(value);
|
||||
string = sanitize(string);
|
||||
strings.put(string, value);
|
||||
values.put(value, string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an int into a possibly cached Integer.
|
||||
*/
|
||||
public static
|
||||
Integer toInteger(int val) {
|
||||
if (val >= 0 && val < cachedInts.length) {
|
||||
return (cachedInts[val]);
|
||||
}
|
||||
return new Integer(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a numeric value is within the range [0..max]
|
||||
*/
|
||||
|
@ -130,13 +112,12 @@ class Mnemonic {
|
|||
* Defines an additional text representation of a numeric value. This will
|
||||
* be used by getValue(), but not getText().
|
||||
*
|
||||
* @param val The numeric value
|
||||
* @param value The numeric value
|
||||
* @param string The text string
|
||||
*/
|
||||
public
|
||||
void addAlias(int val, String string) {
|
||||
check(val);
|
||||
Integer value = toInteger(val);
|
||||
void addAlias(int value, String string) {
|
||||
check(value);
|
||||
string = sanitize(string);
|
||||
strings.put(string, value);
|
||||
}
|
||||
|
@ -154,6 +135,7 @@ class Mnemonic {
|
|||
if (wordcase != source.wordcase) {
|
||||
throw new IllegalArgumentException(source.description + ": wordcases do not match");
|
||||
}
|
||||
|
||||
strings.putAll(source.strings);
|
||||
values.putAll(source.values);
|
||||
}
|
||||
|
@ -161,18 +143,19 @@ class Mnemonic {
|
|||
/**
|
||||
* Gets the text mnemonic corresponding to a numeric value.
|
||||
*
|
||||
* @param val The numeric value
|
||||
* @param value The numeric value
|
||||
*
|
||||
* @return The corresponding text mnemonic.
|
||||
*/
|
||||
public
|
||||
String getText(int val) {
|
||||
check(val);
|
||||
String str = (String) values.get(toInteger(val));
|
||||
String getText(int value) {
|
||||
check(value);
|
||||
String str = values.get(value);
|
||||
if (str != null) {
|
||||
return str;
|
||||
}
|
||||
str = Integer.toString(val);
|
||||
|
||||
str = Integer.toString(value);
|
||||
if (prefix != null) {
|
||||
return prefix + str;
|
||||
}
|
||||
|
@ -189,9 +172,10 @@ class Mnemonic {
|
|||
public
|
||||
int getValue(String str) {
|
||||
str = sanitize(str);
|
||||
Integer value = (Integer) strings.get(str);
|
||||
if (value != null) {
|
||||
return value.intValue();
|
||||
int value = strings.get(str, INVALID_VALUE);
|
||||
|
||||
if (value != INVALID_VALUE) {
|
||||
return value;
|
||||
}
|
||||
if (prefix != null) {
|
||||
if (str.startsWith(prefix)) {
|
||||
|
@ -204,7 +188,8 @@ class Mnemonic {
|
|||
if (numericok) {
|
||||
return parseNumeric(str);
|
||||
}
|
||||
return -1;
|
||||
|
||||
return INVALID_VALUE;
|
||||
}
|
||||
|
||||
private
|
||||
|
@ -214,9 +199,9 @@ class Mnemonic {
|
|||
if (val >= 0 && val <= max) {
|
||||
return val;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
|
||||
package dorkbox.network.dns.constants;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import dorkbox.network.dns.Mnemonic;
|
||||
import dorkbox.network.dns.exceptions.InvalidTypeException;
|
||||
import dorkbox.network.dns.records.DnsRecord;
|
||||
import dorkbox.network.dns.records.DnsTypeProtoAssignment;
|
||||
import dorkbox.util.collections.IntMap;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
/**
|
||||
|
@ -449,25 +448,26 @@ class DnsRecordType {
|
|||
|
||||
public static
|
||||
class TypeMnemonic extends Mnemonic {
|
||||
private HashMap objects;
|
||||
private IntMap<DnsRecord> objects;
|
||||
|
||||
public
|
||||
TypeMnemonic() {
|
||||
super("DnsRecordType", CASE_UPPER);
|
||||
setPrefix("TYPE");
|
||||
objects = new HashMap();
|
||||
objects = new IntMap<DnsRecord>();
|
||||
}
|
||||
|
||||
public
|
||||
void add(int val, String str, DnsRecord proto) {
|
||||
super.add(val, str);
|
||||
objects.put(Mnemonic.toInteger(val), proto);
|
||||
void add(int value, String str, DnsRecord proto) {
|
||||
super.add(value, str);
|
||||
objects.put(value, proto);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public
|
||||
<T extends DnsRecord> T getProto(int val) {
|
||||
check(val);
|
||||
return (T) objects.get(toInteger(val));
|
||||
<T extends DnsRecord> T getProto(int value) {
|
||||
check(value);
|
||||
return (T) objects.get(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -5,16 +5,14 @@ package dorkbox.network.dns.records;
|
|||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import com.esotericsoftware.kryo.util.ObjectMap;
|
||||
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsClass;
|
||||
|
@ -32,6 +30,7 @@ import dorkbox.util.Base64Fast;
|
|||
* @see TSIGRecord
|
||||
*/
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public
|
||||
class TSIG {
|
||||
|
||||
|
@ -72,9 +71,10 @@ class TSIG {
|
|||
*/
|
||||
public static final Name HMAC_SHA512 = Name.fromConstantString("hmac-sha512.");
|
||||
|
||||
private static Map algMap;
|
||||
private static final ObjectMap<Name, String> algMap = new ObjectMap<Name, String>();
|
||||
|
||||
/**
|
||||
* The default fudge value for outgoing packets. Can be overriden by the
|
||||
* The default fudge value for outgoing packets. Can be overridden by the
|
||||
* tsigfudge option.
|
||||
*/
|
||||
public static final short FUDGE = 300;
|
||||
|
@ -82,14 +82,12 @@ class TSIG {
|
|||
private Mac hmac;
|
||||
|
||||
static {
|
||||
Map out = new HashMap();
|
||||
out.put(HMAC_MD5, "HmacMD5");
|
||||
out.put(HMAC_SHA1, "HmacSHA1");
|
||||
out.put(HMAC_SHA224, "HmacSHA224");
|
||||
out.put(HMAC_SHA256, "HmacSHA256");
|
||||
out.put(HMAC_SHA384, "HmacSHA384");
|
||||
out.put(HMAC_SHA512, "HmacSHA512");
|
||||
algMap = Collections.unmodifiableMap(out);
|
||||
algMap.put(HMAC_MD5, "HmacMD5");
|
||||
algMap.put(HMAC_SHA1, "HmacSHA1");
|
||||
algMap.put(HMAC_SHA224, "HmacSHA224");
|
||||
algMap.put(HMAC_SHA256, "HmacSHA256");
|
||||
algMap.put(HMAC_SHA384, "HmacSHA384");
|
||||
algMap.put(HMAC_SHA512, "HmacSHA512");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -143,7 +141,7 @@ class TSIG {
|
|||
|
||||
public static
|
||||
String nameToAlgorithm(Name name) {
|
||||
String alg = (String) algMap.get(name);
|
||||
String alg = algMap.get(name);
|
||||
if (alg != null) {
|
||||
return alg;
|
||||
}
|
||||
|
@ -177,14 +175,13 @@ class TSIG {
|
|||
|
||||
public static
|
||||
Name algorithmToName(String alg) {
|
||||
Iterator it = algMap.entrySet()
|
||||
.iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
if (alg.equalsIgnoreCase((String) entry.getValue())) {
|
||||
return (Name) entry.getKey();
|
||||
}
|
||||
|
||||
// false identity check because it's string comparisons.
|
||||
Name foundKey = algMap.findKey(alg, false);
|
||||
if (foundKey != null) {
|
||||
return foundKey;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown algorithm");
|
||||
}
|
||||
|
||||
|
|
|
@ -15,59 +15,66 @@ import java.util.TreeSet;
|
|||
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Mnemonic;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.exceptions.WireParseException;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.util.collections.IntMap;
|
||||
import dorkbox.util.collections.IntMap.Keys;
|
||||
|
||||
final
|
||||
class TypeBitmap implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -125354057735389003L;
|
||||
|
||||
private TreeSet types;
|
||||
private IntMap<Boolean> types;
|
||||
|
||||
public
|
||||
TypeBitmap(int[] array) {
|
||||
this();
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
DnsRecordType.check(array[i]);
|
||||
types.add(new Integer(array[i]));
|
||||
types.put(array[i], Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
private
|
||||
TypeBitmap() {
|
||||
types = new TreeSet();
|
||||
types = new IntMap<Boolean>();
|
||||
}
|
||||
|
||||
public
|
||||
TypeBitmap(DnsInput in) throws WireParseException {
|
||||
this();
|
||||
int lastbase = -1;
|
||||
|
||||
while (in.remaining() > 0) {
|
||||
if (in.remaining() < 2) {
|
||||
throw new WireParseException("invalid bitmap descriptor");
|
||||
}
|
||||
|
||||
int mapbase = in.readU8();
|
||||
if (mapbase < lastbase) {
|
||||
throw new WireParseException("invalid ordering");
|
||||
}
|
||||
|
||||
int maplength = in.readU8();
|
||||
if (maplength > in.remaining()) {
|
||||
throw new WireParseException("invalid bitmap");
|
||||
}
|
||||
|
||||
for (int i = 0; i < maplength; i++) {
|
||||
int current = in.readU8();
|
||||
if (current == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if ((current & (1 << (7 - j))) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int typecode = mapbase * 256 + +i * 8 + j;
|
||||
types.add(Mnemonic.toInteger(typecode));
|
||||
types.put(typecode, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,54 +83,71 @@ class TypeBitmap implements Serializable {
|
|||
public
|
||||
TypeBitmap(Tokenizer st) throws IOException {
|
||||
this();
|
||||
|
||||
while (true) {
|
||||
Tokenizer.Token t = st.get();
|
||||
if (!t.isString()) {
|
||||
break;
|
||||
}
|
||||
|
||||
int typecode = DnsRecordType.value(t.value);
|
||||
if (typecode < 0) {
|
||||
throw st.exception("Invalid type: " + t.value);
|
||||
}
|
||||
types.add(Mnemonic.toInteger(typecode));
|
||||
|
||||
types.put(typecode, Boolean.TRUE);
|
||||
}
|
||||
st.unget();
|
||||
}
|
||||
|
||||
public
|
||||
int[] toArray() {
|
||||
int[] array = new int[types.size()];
|
||||
int[] array = new int[types.size];
|
||||
int n = 0;
|
||||
for (Iterator it = types.iterator(); it.hasNext(); ) {
|
||||
array[n++] = ((Integer) it.next()).intValue();
|
||||
|
||||
|
||||
Keys keys = types.keys();
|
||||
while (keys.hasNext) {
|
||||
array[n++] = keys.next();
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Iterator it = types.iterator(); it.hasNext(); ) {
|
||||
int t = ((Integer) it.next()).intValue();
|
||||
sb.append(DnsRecordType.string(t));
|
||||
if (it.hasNext()) {
|
||||
sb.append(' ');
|
||||
}
|
||||
|
||||
Keys keys = types.keys();
|
||||
while (keys.hasNext) {
|
||||
int t = keys.next();
|
||||
sb.append(DnsRecordType.string(t))
|
||||
.append(' ');
|
||||
}
|
||||
|
||||
// remove the last ' '
|
||||
int length = sb.length();
|
||||
if (length > 1) {
|
||||
sb.delete(length - 1, length);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public
|
||||
void toWire(DnsOutput out) {
|
||||
if (types.size() == 0) {
|
||||
if (types.size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int mapbase = -1;
|
||||
TreeSet map = new TreeSet();
|
||||
|
||||
for (Iterator it = types.iterator(); it.hasNext(); ) {
|
||||
int t = ((Integer) it.next()).intValue();
|
||||
Keys keys = types.keys();
|
||||
while (keys.hasNext) {
|
||||
int t = keys.next();
|
||||
|
||||
int base = t >> 8;
|
||||
if (base != mapbase) {
|
||||
if (map.size() > 0) {
|
||||
|
@ -134,20 +158,27 @@ class TypeBitmap implements Serializable {
|
|||
}
|
||||
map.add(new Integer(t));
|
||||
}
|
||||
|
||||
mapToWire(out, map, mapbase);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param map this must be an ordered data structure!
|
||||
*/
|
||||
private static
|
||||
void mapToWire(DnsOutput out, TreeSet map, int mapbase) {
|
||||
int arraymax = (((Integer) map.last()).intValue()) & 0xFF;
|
||||
int arraylength = (arraymax / 8) + 1;
|
||||
int[] array = new int[arraylength];
|
||||
|
||||
out.writeU8(mapbase);
|
||||
out.writeU8(arraylength);
|
||||
|
||||
for (Iterator it = map.iterator(); it.hasNext(); ) {
|
||||
int typecode = ((Integer) it.next()).intValue();
|
||||
array[(typecode & 0xFF) / 8] |= (1 << (7 - typecode % 8));
|
||||
}
|
||||
|
||||
for (int j = 0; j < arraylength; j++) {
|
||||
out.writeU8(array[j]);
|
||||
}
|
||||
|
@ -155,12 +186,11 @@ class TypeBitmap implements Serializable {
|
|||
|
||||
public
|
||||
boolean empty() {
|
||||
return types.isEmpty();
|
||||
return types.size == 0;
|
||||
}
|
||||
|
||||
public
|
||||
boolean contains(int typecode) {
|
||||
return types.contains(Mnemonic.toInteger(typecode));
|
||||
return types.containsKey(typecode);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -54,39 +54,12 @@ class MnemonicTest extends TestCase {
|
|||
m_mn = new Mnemonic(MnemonicTest.class.getName() + " UPPER", Mnemonic.CASE_UPPER);
|
||||
}
|
||||
|
||||
public
|
||||
void test_toInteger() {
|
||||
Integer i = Mnemonic.toInteger(64);
|
||||
assertEquals(new Integer(64), i);
|
||||
Integer i2 = Mnemonic.toInteger(64);
|
||||
assertEquals(i, i2);
|
||||
assertNotSame(i, i2);
|
||||
|
||||
i = Mnemonic.toInteger(-1);
|
||||
assertEquals(new Integer(-1), i);
|
||||
i2 = Mnemonic.toInteger(-1);
|
||||
assertEquals(i, i2);
|
||||
assertNotSame(i, i2);
|
||||
|
||||
i = Mnemonic.toInteger(0);
|
||||
assertEquals(new Integer(0), i);
|
||||
i2 = Mnemonic.toInteger(0);
|
||||
assertEquals(i, i2);
|
||||
assertSame(i, i2);
|
||||
|
||||
i = Mnemonic.toInteger(63);
|
||||
assertEquals(new Integer(63), i);
|
||||
i2 = Mnemonic.toInteger(63);
|
||||
assertEquals(i, i2);
|
||||
assertSame(i, i2);
|
||||
}
|
||||
|
||||
public
|
||||
void test_no_maximum() {
|
||||
try {
|
||||
m_mn.check(-1);
|
||||
fail("IllegalArgumentException not thrown");
|
||||
} catch (IllegalArgumentException e) {
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
try {
|
||||
m_mn.check(0);
|
||||
|
@ -117,7 +90,7 @@ class MnemonicTest extends TestCase {
|
|||
try {
|
||||
m_mn.check(-1);
|
||||
fail("IllegalArgumentException not thrown");
|
||||
} catch (IllegalArgumentException e) {
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
try {
|
||||
m_mn.check(0);
|
||||
|
@ -132,7 +105,7 @@ class MnemonicTest extends TestCase {
|
|||
try {
|
||||
m_mn.check(16);
|
||||
fail("IllegalArgumentException not thrown");
|
||||
} catch (IllegalArgumentException e) {
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
// need numericok to exercise the usage of max in parseNumeric
|
||||
|
|
Loading…
Reference in New Issue
Block a user