http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/ASN1Object.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/ASN1Object.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/ASN1Object.java deleted file mode 100644 index 1d32a40..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/ASN1Object.java +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.sshd.common.util.io.der; - -import java.io.EOFException; -import java.io.IOException; -import java.io.Serializable; -import java.io.StreamCorruptedException; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.NumberUtils; -import org.apache.sshd.common.util.buffer.BufferUtils; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class ASN1Object implements Serializable, Cloneable { - // Constructed Flag - public static final byte CONSTRUCTED = 0x20; - - private static final long serialVersionUID = 4687581744706127265L; - - private ASN1Class objClass; - private ASN1Type objType; - private boolean constructed; - private int length; - private byte[] value; - - public ASN1Object() { - super(); - } - - /* - * <P>The first byte in DER encoding is made of following fields</P> - * <pre> - *------------------------------------------------- - *|Bit 8|Bit 7|Bit 6|Bit 5|Bit 4|Bit 3|Bit 2|Bit 1| - *------------------------------------------------- - *| Class | CF | Type | - *------------------------------------------------- - * </pre> - */ - public ASN1Object(byte tag, int len, byte... data) { - this(ASN1Class.fromDERValue(tag), ASN1Type.fromDERValue(tag), (tag & CONSTRUCTED) == CONSTRUCTED, len, data); - } - - public ASN1Object(ASN1Class c, ASN1Type t, boolean ctored, int len, byte... data) { - objClass = c; - objType = t; - constructed = ctored; - length = len; - value = data; - } - - public ASN1Class getObjClass() { - return objClass; - } - - public void setObjClass(ASN1Class c) { - objClass = c; - } - - public ASN1Type getObjType() { - return objType; - } - - public void setObjType(ASN1Type y) { - objType = y; - } - - public boolean isConstructed() { - return constructed; - } - - public void setConstructed(boolean c) { - constructed = c; - } - - public int getLength() { - return length; - } - - public void setLength(int l) { - length = l; - } - - public byte[] getValue() { - return value; - } - - // if length is less than value.length then returns copy of it - public byte[] getPureValueBytes() { - byte[] bytes = getValue(); - int available = getLength(); - int numBytes = NumberUtils.length(bytes); - if (numBytes == available) { - return bytes; - } - - if (available == 0) { - return GenericUtils.EMPTY_BYTE_ARRAY; - } - - byte[] pure = new byte[available]; - System.arraycopy(bytes, 0, pure, 0, available); - return pure; - } - - public void setValue(byte[] v) { - value = v; - } - - public DERParser createParser() { - return new DERParser(getValue(), 0, getLength()); - } - - public Object asObject() throws IOException { - ASN1Type type = getObjType(); - if (type == null) { - throw new IOException("No type set"); - } - - switch (type) { - case INTEGER: - return asInteger(); - - case NUMERIC_STRING: - case PRINTABLE_STRING: - case VIDEOTEX_STRING: - case IA5_STRING: - case GRAPHIC_STRING: - case ISO646_STRING: - case GENERAL_STRING: - case BMP_STRING: - case UTF8_STRING: - return asString(); - - case OBJECT_IDENTIFIER: - return asOID(); - - case SEQUENCE : - return getValue(); - - default: - throw new IOException("Invalid DER: unsupported type: " + type); - } - } - - /** - * Get the value as {@link BigInteger} - * @return BigInteger - * @throws IOException if type not an {@link ASN1Type#INTEGER} - */ - public BigInteger asInteger() throws IOException { - ASN1Type typeValue = getObjType(); - if (ASN1Type.INTEGER.equals(typeValue)) { - return toInteger(); - } else { - throw new IOException("Invalid DER: object is not integer: " + typeValue); - } - } - - // does not check if this is an integer - public BigInteger toInteger() { - return new BigInteger(getPureValueBytes()); - } - - /** - * Get value as string. Most strings are treated as Latin-1. - * @return Java string - * @throws IOException if - */ - public String asString() throws IOException { - ASN1Type type = getObjType(); - if (type == null) { - throw new IOException("No type set"); - } - - final String encoding; - switch (type) { - // Not all are Latin-1 but it's the closest thing - case NUMERIC_STRING: - case PRINTABLE_STRING: - case VIDEOTEX_STRING: - case IA5_STRING: - case GRAPHIC_STRING: - case ISO646_STRING: - case GENERAL_STRING: - encoding = "ISO-8859-1"; - break; - - case BMP_STRING: - encoding = "UTF-16BE"; - break; - - case UTF8_STRING: - encoding = "UTF-8"; - break; - - case UNIVERSAL_STRING: - throw new IOException("Invalid DER: can't handle UCS-4 string"); - - default: - throw new IOException("Invalid DER: object is not a string: " + type); - } - - return new String(getValue(), 0, getLength(), encoding); - } - - public List<Integer> asOID() throws IOException { - ASN1Type typeValue = getObjType(); - if (ASN1Type.OBJECT_IDENTIFIER.equals(typeValue)) { - return toOID(); - } else { - throw new StreamCorruptedException("Invalid DER: object is not an OID: " + typeValue); - } - } - - // Does not check that type is OID - public List<Integer> toOID() throws IOException { - int vLen = getLength(); - if (vLen <= 0) { - throw new EOFException("Not enough data for an OID"); - } - - List<Integer> oid = new ArrayList<>(vLen + 1); - byte[] bytes = getValue(); - int val1 = bytes[0] & 0xFF; - oid.add(Integer.valueOf(val1 / 40)); - oid.add(Integer.valueOf(val1 % 40)); - - for (int curPos = 1; curPos < vLen; curPos++) { - int v = bytes[curPos] & 0xFF; - if (v <= 0x7F) { // short form - oid.add(Integer.valueOf(v)); - continue; - } - - long curVal = v & 0x7F; - curPos++; - - for (int subLen = 1;; subLen++, curPos++) { - if (curPos >= vLen) { - throw new EOFException("Incomplete OID value"); - } - - if (subLen > 5) { // 32 bit values can span at most 5 octets - throw new StreamCorruptedException("OID component encoding beyond 5 bytes"); - } - - v = bytes[curPos] & 0xFF; - curVal = ((curVal << 7) & 0xFFFFFFFF80L) | (v & 0x7FL); - if (curVal > Integer.MAX_VALUE) { - throw new StreamCorruptedException("OID value exceeds 32 bits: " + curVal); - } - - if (v <= 0x7F) { // found last octet ? - break; - } - } - - oid.add(Integer.valueOf((int) (curVal & 0x7FFFFFFFL))); - } - - return oid; - } - - @Override - public int hashCode() { - return Objects.hash(getObjClass(), getObjType()) - + Boolean.hashCode(isConstructed()) - + getLength() - + NumberUtils.hashCode(getValue(), 0, getLength()); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (this == obj) { - return true; - } - if (getClass() != obj.getClass()) { - return false; - } - - ASN1Object other = (ASN1Object) obj; - return Objects.equals(this.getObjClass(), other.getObjClass()) - && Objects.equals(this.getObjType(), other.getObjType()) - && (this.isConstructed() == other.isConstructed()) - && (this.getLength() == other.getLength()) - && (NumberUtils.diffOffset(this.getValue(), 0, other.getValue(), 0, this.getLength()) < 0); - } - - @Override - public ASN1Object clone() { - try { - ASN1Object cpy = getClass().cast(super.clone()); - byte[] data = cpy.getValue(); - if (data != null) { - cpy.setValue(data.clone()); - } - return cpy; - } catch (CloneNotSupportedException e) { - throw new IllegalStateException("Unexpected clone failure: " + e.getMessage(), e); - } - } - - @Override - public String toString() { - return Objects.toString(getObjClass()) - + "/" + getObjType() - + "/" + isConstructed() - + "[" + getLength() + "]" - + ": " + BufferUtils.toHex(getValue(), 0, getLength(), ':'); - } -}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/ASN1Type.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/ASN1Type.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/ASN1Type.java deleted file mode 100644 index 3dd13ca..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/ASN1Type.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.sshd.common.util.io.der; - -import java.util.Collections; -import java.util.EnumSet; -import java.util.Set; - -import org.apache.sshd.common.util.GenericUtils; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public enum ASN1Type { - ANY((byte) 0x00), - BOOLEAN((byte) 0x01), - INTEGER((byte) 0x02), - BIT_STRING((byte) 0x03), - OCTET_STRING((byte) 0x04), - NULL((byte) 0x05), - OBJECT_IDENTIFIER((byte) 0x06), - REAL((byte) 0x09), - ENUMERATED((byte) 0x0a), - RELATIVE_OID((byte) 0x0d), - SEQUENCE((byte) 0x10), - SET((byte) 0x11), - NUMERIC_STRING((byte) 0x12), - PRINTABLE_STRING((byte) 0x13), - T61_STRING((byte) 0x14), - VIDEOTEX_STRING((byte) 0x15), - IA5_STRING((byte) 0x16), - GRAPHIC_STRING((byte) 0x19), - ISO646_STRING((byte) 0x1A), - GENERAL_STRING((byte) 0x1B), - UTF8_STRING((byte) 0x0C), - UNIVERSAL_STRING((byte) 0x1C), - BMP_STRING((byte) 0x1E), - UTC_TIME((byte) 0x17), - GENERALIZED_TIME((byte) 0x18); - - public static final Set<ASN1Type> VALUES = - Collections.unmodifiableSet(EnumSet.allOf(ASN1Type.class)); - - private final byte typeValue; - - ASN1Type(byte typeVal) { - typeValue = typeVal; - } - - public byte getTypeValue() { - return typeValue; - } - - public static ASN1Type fromName(String s) { - if (GenericUtils.isEmpty(s)) { - return null; - } - - for (ASN1Type t : VALUES) { - if (s.equalsIgnoreCase(t.name())) { - return t; - } - } - - return null; - } - - /** - * <P>The first byte in DER encoding is made of following fields</P> - * <pre> - *------------------------------------------------- - *|Bit 8|Bit 7|Bit 6|Bit 5|Bit 4|Bit 3|Bit 2|Bit 1| - *------------------------------------------------- - *| Class | CF | Type | - *------------------------------------------------- - * </pre> - * @param value The original DER encoded byte - * @return The {@link ASN1Type} value - {@code null} if no match found - * @see #fromTypeValue(int) - */ - public static ASN1Type fromDERValue(int value) { - return fromTypeValue(value & 0x1F); - } - - /** - * @param value The "pure" type value - with no extra bits set - * @return The {@link ASN1Type} value - {@code null} if no match found - */ - public static ASN1Type fromTypeValue(int value) { - if ((value < 0) || (value > 0x1F)) { // only 5 bits are used - return null; - } - - for (ASN1Type t : VALUES) { - if (t.getTypeValue() == value) { - return t; - } - } - - return null; - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/DERParser.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/DERParser.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/DERParser.java deleted file mode 100644 index 5f37bd7..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/DERParser.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.sshd.common.util.io.der; - -import java.io.ByteArrayInputStream; -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.StreamCorruptedException; -import java.math.BigInteger; -import java.util.Arrays; - -import org.apache.sshd.common.util.NumberUtils; -import org.apache.sshd.common.util.buffer.BufferUtils; - -/** - * A bare minimum DER parser - just enough to be able to decode - * signatures and private keys - * - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class DERParser extends FilterInputStream { - /** - * Maximum size of data allowed by {@link #readLength()} - it is a bit - * arbitrary since one can encode 32-bit length data, but it is good - * enough for the keys - */ - public static final int MAX_DER_VALUE_LENGTH = 2 * Short.MAX_VALUE; - - private final byte[] lenBytes = new byte[Integer.BYTES]; - - public DERParser(byte... bytes) { - this(bytes, 0, NumberUtils.length(bytes)); - } - - public DERParser(byte[] bytes, int offset, int len) { - this(new ByteArrayInputStream(bytes, offset, len)); - } - - public DERParser(InputStream s) { - super(s); - } - - /** - * Decode the length of the field. Can only support length - * encoding up to 4 octets. In BER/DER encoding, length can - * be encoded in 2 forms: - * <ul> - * <li><p> - * Short form - One octet. Bit 8 has value "0" and bits 7-1 - * give the length. - * </p></li> - * - * <li><p> - * Long form - Two to 127 octets (only 4 is supported here). - * Bit 8 of first octet has value "1" and bits 7-1 give the - * number of additional length octets. Second and following - * octets give the length, base 256, most significant digit - * first. - * </p></li> - * </ul> - * - * @return The length as integer - * @throws IOException If invalid format found - */ - public int readLength() throws IOException { - int i = read(); - if (i == -1) { - throw new StreamCorruptedException("Invalid DER: length missing"); - } - - // A single byte short length - if ((i & ~0x7F) == 0) { - return i; - } - - int num = i & 0x7F; - // TODO We can't handle length longer than 4 bytes - if ((i >= 0xFF) || (num > lenBytes.length)) { - throw new StreamCorruptedException("Invalid DER: length field too big: " + i); - } - - // place the read bytes last so that the 1st ones are zeroes as big endian - Arrays.fill(lenBytes, (byte) 0); - int n = read(lenBytes, 4 - num, num); - if (n < num) { - throw new StreamCorruptedException("Invalid DER: length data too short: expected=" + num + ", actual=" + n); - } - - long len = BufferUtils.getUInt(lenBytes); - if (len < 0x7FL) { // according to standard: "the shortest possible length encoding must be used" - throw new StreamCorruptedException("Invalid DER: length not in shortest form: " + len); - } - - if (len > MAX_DER_VALUE_LENGTH) { - throw new StreamCorruptedException("Invalid DER: data length too big: " + len + " (max=" + MAX_DER_VALUE_LENGTH + ")"); - } - - // we know the cast is safe since it is less than MAX_DER_VALUE_LENGTH which is ~64K - return (int) len; - } - - public ASN1Object readObject() throws IOException { - int tag = read(); - if (tag == -1) { - return null; - } - - int length = readLength(); - byte[] value = new byte[length]; - int n = read(value); - if (n < length) { - throw new StreamCorruptedException("Invalid DER: stream too short, missing value: read " + n + " out of required " + length); - } - - return new ASN1Object((byte) tag, length, value); - } - - public BigInteger readBigInteger() throws IOException { - int type = read(); - if (type != 0x02) { - throw new StreamCorruptedException("Invalid DER: data type is not an INTEGER: 0x" + Integer.toHexString(type)); - } - - int len = readLength(); - byte[] value = new byte[len]; - int n = read(value); - if (n < len) { - throw new StreamCorruptedException("Invalid DER: stream too short, missing value: read " + n + " out of required " + len); - } - - return new BigInteger(value); - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/DERWriter.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/DERWriter.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/DERWriter.java deleted file mode 100644 index bc603ee..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/io/der/DERWriter.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.sshd.common.util.io.der; - -import java.io.ByteArrayOutputStream; -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.StreamCorruptedException; -import java.math.BigInteger; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.sshd.common.util.NumberUtils; -import org.apache.sshd.common.util.ValidateUtils; -import org.apache.sshd.common.util.buffer.BufferUtils; -import org.apache.sshd.common.util.buffer.ByteArrayBuffer; - -/** - * A bare-minimum DER encoder - just enough so we can encoder signatures - * and keys data - * - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class DERWriter extends FilterOutputStream { - private final byte[] lenBytes = new byte[Integer.BYTES]; - - public DERWriter() { - this(ByteArrayBuffer.DEFAULT_SIZE); - } - - public DERWriter(int initialSize) { - this(new ByteArrayOutputStream(initialSize)); - } - - public DERWriter(OutputStream stream) { - super(Objects.requireNonNull(stream, "No output stream")); - } - - public DERWriter startSequence() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - AtomicBoolean dataWritten = new AtomicBoolean(false); - @SuppressWarnings("resource") - DERWriter encloser = this; - return new DERWriter(baos) { - @Override - public void close() throws IOException { - baos.close(); - - if (!dataWritten.getAndSet(true)) { // detect repeated calls and write this only once - encloser.writeObject(new ASN1Object(ASN1Class.UNIVERSAL, ASN1Type.SEQUENCE, false, baos.size(), baos.toByteArray())); - } - } - }; - } - - public void writeBigInteger(BigInteger value) throws IOException { - writeBigInteger(Objects.requireNonNull(value, "No value").toByteArray()); - } - - /** - * The integer is always considered to be positive, so if the first byte is < 0, - * we pad with a zero to make it positive - * - * @param bytes {@link BigInteger} bytes - * @throws IOException If failed to write the bytes - */ - public void writeBigInteger(byte... bytes) throws IOException { - writeBigInteger(bytes, 0, NumberUtils.length(bytes)); - } - - /** - * The integer is always considered to be positive, so if the first byte is < 0, - * we pad with a zero to make it positive - * - * @param bytes {@link BigInteger} bytes - * @param off Offset in bytes data - * @param len Number of bytes to write - * @throws IOException If failed to write the bytes - */ - public void writeBigInteger(byte[] bytes, int off, int len) throws IOException { - // Strip leading zeroes - while (len > 1 && bytes[off] == 0 && isPositive(bytes[off + 1])) { - off++; - len--; - } - // indicate it is an INTEGER - write(0x02); - // Pad with a zero if needed - if (isPositive(bytes[off])) { - writeLength(len); - } else { - writeLength(len + 1); - write(0); - } - // Write data - write(bytes, off, len); - } - - private boolean isPositive(byte b) { - return (b & 0x80) == 0; - } - - public void writeObject(ASN1Object obj) throws IOException { - Objects.requireNonNull(obj, "No ASN.1 object"); - - ASN1Type type = obj.getObjType(); - byte typeValue = type.getTypeValue(); - ASN1Class clazz = obj.getObjClass(); - byte classValue = clazz.getClassValue(); - byte tagValue = (byte) (((classValue << 6) & 0xC0) | (typeValue & 0x1F)); - writeObject(tagValue, obj.getLength(), obj.getValue()); - } - - public void writeObject(byte tag, int len, byte... data) throws IOException { - write(tag & 0xFF); - writeLength(len); - write(data, 0, len); - } - - public void writeLength(int len) throws IOException { - ValidateUtils.checkTrue(len >= 0, "Invalid length: %d", len); - - // short form - MSBit is zero - if (len <= 127) { - write(len); - return; - } - - BufferUtils.putUInt(len, lenBytes); - - int nonZeroPos = 0; - for (; nonZeroPos < lenBytes.length; nonZeroPos++) { - if (lenBytes[nonZeroPos] != 0) { - break; - } - } - - if (nonZeroPos >= lenBytes.length) { - throw new StreamCorruptedException("All zeroes length representation for len=" + len); - } - - int bytesLen = lenBytes.length - nonZeroPos; - write(0x80 | bytesLen); // indicate number of octets - write(lenBytes, nonZeroPos, bytesLen); - } - - public byte[] toByteArray() throws IOException { - if (this.out instanceof ByteArrayOutputStream) { - return ((ByteArrayOutputStream) this.out).toByteArray(); - } else { - throw new IOException("The underlying stream is not a byte[] stream"); - } - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/util/io/functors/IOFunction.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/functors/IOFunction.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/functors/IOFunction.java deleted file mode 100644 index a55ac2e..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/io/functors/IOFunction.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.sshd.common.util.io.functors; - -import java.io.IOException; -import java.util.Objects; - -/** - * Invokes some I/O function on the input returning some output - * and potentially throwing an {@link IOException} in the process - * - * @param <T> Type of input - * @param <R> Type of output - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -@FunctionalInterface -public interface IOFunction<T, R> { - R apply(T t) throws IOException; - - /** - * Returns a composed function that first applies the {@code before} - * function to its input, and then applies this function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param <V> the type of input to the {@code before} function, and to the - * composed function - * @param before the function to apply before this function is applied - * @return a composed function that first applies the {@code before} - * function and then applies this function - * @throws NullPointerException if before is null - * - * @see #andThen(IOFunction) - */ - default <V> IOFunction<V, R> compose(IOFunction<? super V, ? extends T> before) { - Objects.requireNonNull(before, "No composing function provided"); - return (V v) -> apply(before.apply(v)); - } - - /** - * Returns a composed function that first applies this function to - * its input, and then applies the {@code after} function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param <V> the type of output of the {@code after} function, and of the - * composed function - * @param after the function to apply after this function is applied - * @return a composed function that first applies this function and then - * applies the {@code after} function - * @throws NullPointerException if after is null - * - * @see #compose(IOFunction) - */ - default <V> IOFunction<T, V> andThen(IOFunction<? super R, ? extends V> after) { - Objects.requireNonNull(after, "No composing function provided"); - return (T t) -> after.apply(apply(t)); - } - - /** - * Returns a function that always returns its input argument. - * - * @param <T> the type of the input and output objects to the function - * @return a function that always returns its input argument - */ - static <T> IOFunction<T, T> identity() { - return t -> t; - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/util/logging/AbstractLoggingBean.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/logging/AbstractLoggingBean.java b/sshd-core/src/main/java/org/apache/sshd/common/util/logging/AbstractLoggingBean.java deleted file mode 100644 index 27fef2f..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/logging/AbstractLoggingBean.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.sshd.common.util.logging; - -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.sshd.common.util.GenericUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Serves as a common base class for the vast majority of classes that require - * some kind of logging. Facilitates quick and easy replacement of the actual used - * logger from one framework to another - * - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public abstract class AbstractLoggingBean { - protected final Logger log; - private final AtomicReference<SimplifiedLog> simplifiedLog = new AtomicReference<>(); - - /** - * Default constructor - creates a logger using the full class name - */ - protected AbstractLoggingBean() { - this(""); - } - - /** - * Create a logger for instances of the same class for which we might - * want to have a "discriminator" for them - * - * @param discriminator The discriminator value - ignored if {@code null} - * or empty - */ - protected AbstractLoggingBean(String discriminator) { - String name = getClass().getName(); - if (GenericUtils.length(discriminator) > 0) { - name += "[" + discriminator + "]"; - } - log = LoggerFactory.getLogger(name); - } - - protected SimplifiedLog getSimplifiedLogger() { - SimplifiedLog logger; - synchronized (simplifiedLog) { - logger = simplifiedLog.get(); - if (logger == null) { - logger = LoggingUtils.wrap(log); - } - } - - return logger; - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/util/logging/LoggingUtils.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/logging/LoggingUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/logging/LoggingUtils.java deleted file mode 100644 index 674ed1a..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/logging/LoggingUtils.java +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.sshd.common.util.logging; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.NavigableMap; -import java.util.Objects; -import java.util.TreeMap; -import java.util.function.Consumer; -import java.util.function.Predicate; -import java.util.logging.Level; - -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.NumberUtils; -import org.apache.sshd.common.util.ReflectionUtils; -import org.slf4j.Logger; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public final class LoggingUtils { - - private LoggingUtils() { - throw new UnsupportedOperationException("No instance"); - } - - /** - * Scans using reflection API for all fields that are {@code public static final} - * that start with the given common prefix (case <U>sensitive</U>) and are of type - * {@link Number}. - * - * @param clazz The {@link Class} to query - * @param commonPrefix The expected common prefix - * @return A {@link NavigableMap} of all the matching fields, where key=the field's {@link Integer} - * value and mapping=the field's name - * @see #generateMnemonicMap(Class, Predicate) - */ - public static NavigableMap<Integer, String> generateMnemonicMap(Class<?> clazz, final String commonPrefix) { - return generateMnemonicMap(clazz, f -> { - String name = f.getName(); - return name.startsWith(commonPrefix); - }); - } - - /** - * Scans using reflection API for all <U>numeric {@code public static final}</U> fields - * that are also accepted by the predicate. Any field that is not such or fail to retrieve - * its value, or has a duplicate value is <U>silently</U> skipped. - * - * @param clazz The {@link Class} to query - * @param acceptor The {@link Predicate} used to decide whether to process the {@link Field} - * (besides being a {@link Number} and {@code public static final}). - * @return A {@link NavigableMap} of all the matching fields, where key=the field's {@link Integer} - * value and mapping=the field's name - * @see #getMnemonicFields(Class, Predicate) - */ - public static NavigableMap<Integer, String> generateMnemonicMap(Class<?> clazz, Predicate<? super Field> acceptor) { - Collection<Field> fields = getMnemonicFields(clazz, acceptor); - if (GenericUtils.isEmpty(fields)) { - return Collections.emptyNavigableMap(); - } - - NavigableMap<Integer, String> result = new TreeMap<>(Comparator.naturalOrder()); - for (Field f : fields) { - String name = f.getName(); - try { - Number value = (Number) f.get(null); - String prev = result.put(NumberUtils.toInteger(value), name); - if (prev != null) { - //noinspection UnnecessaryContinue - continue; // debug breakpoint - } - } catch (Exception e) { - //noinspection UnnecessaryContinue - continue; // debug breakpoint - } - } - - return result; - } - - /** - * Scans using reflection API for all <U>numeric {@code public static final}</U> fields - * that have a common prefix and whose value is used by several of the other - * matching fields - * - * @param clazz The {@link Class} to query - * @param commonPrefix The expected common prefix - * @return A {@link Map} of all the mnemonic fields names whose value is the same as other - * fields in this map. The key is the field's name and value is its associated opcode. - * @see #getAmbiguousMenmonics(Class, Predicate) - */ - public static Map<String, Integer> getAmbiguousMenmonics(Class<?> clazz, String commonPrefix) { - return getAmbiguousMenmonics(clazz, f -> { - String name = f.getName(); - return name.startsWith(commonPrefix); - }); - } - - /** - * Scans using reflection API for all <U>numeric {@code public static final}</U> fields - * that are also accepted by the predicate and whose value is used by several of the other - * matching fields - * - * @param clazz The {@link Class} to query - * @param acceptor The {@link Predicate} used to decide whether to process the {@link Field} - * (besides being a {@link Number} and {@code public static final}). - * @return A {@link Map} of all the mnemonic fields names whose value is the same as other - * fields in this map. The key is the field's name and value is its associated opcode. - * @see #getMnemonicFields(Class, Predicate) - */ - public static Map<String, Integer> getAmbiguousMenmonics(Class<?> clazz, Predicate<? super Field> acceptor) { - Collection<Field> fields = getMnemonicFields(clazz, acceptor); - if (GenericUtils.isEmpty(fields)) { - return Collections.emptyMap(); - } - - Map<String, Integer> result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - Map<Integer, List<String>> opcodesMap = new TreeMap<>(Comparator.naturalOrder()); - for (Field f : fields) { - String name = f.getName(); - try { - Number value = (Number) f.get(null); - Integer key = NumberUtils.toInteger(value); - List<String> nameList = opcodesMap.get(key); - if (nameList == null) { - nameList = new ArrayList<>(); - opcodesMap.put(key, nameList); - } - nameList.add(name); - - int numOpcodes = nameList.size(); - if (numOpcodes > 1) { - result.put(name, key); - if (numOpcodes == 2) { // add the 1st name as well - result.put(nameList.get(0), key); - } - } - } catch (Exception e) { - continue; // debug breakpoint - } - } - - return result; - } - - /** - * Scans using reflection API for all <U>numeric {@code public static final}</U> fields - * that are also accepted by the predicate. - * - * @param clazz The {@link Class} to query - * @param acceptor The {@link Predicate} used to decide whether to process the {@link Field} - * (besides being a {@link Number} and {@code public static final}). - * @return A {@link Collection} of all the fields that have satisfied all conditions - */ - public static Collection<Field> getMnemonicFields(Class<?> clazz, Predicate<? super Field> acceptor) { - return ReflectionUtils.getMatchingFields(clazz, f -> { - int mods = f.getModifiers(); - if ((!Modifier.isPublic(mods)) || (!Modifier.isStatic(mods)) || (!Modifier.isFinal(mods))) { - return false; - } - - Class<?> type = f.getType(); - if (!NumberUtils.isNumericClass(type)) { - return false; - } - - return acceptor.test(f); - }); - } - - /** - * Verifies if the given level is above the required threshold for logging. - * - * @param level The {@link Level} to evaluate - * @param threshold The threshold {@link Level} - * @return {@code true} if the evaluated level is above the required - * threshold. - * <P> - * <B>Note(s):</B> - * </P> - * <UL> - * <LI><P> - * If either argument is {@code null} then result is {@code false}. - * </P></LI> - * - * <LI><P> - * If the evaluated level is {@link Level#OFF} then result is {@code false} - * regardless of the threshold. - * </P></LI> - * - * <LI><P> - * If the threshold is {@link Level#ALL} and the evaluated level is - * <U>not</U> {@link Level#OFF} the result is {@code true}. - * </P></LI> - * - * <LI><P> - * Otherwise, the evaluated level {@link Level#intValue()} must be - * greater or equal to the threshold. - * </P></LI> - * </UL> - */ - public static boolean isLoggable(Level level, Level threshold) { - if ((level == null) || (threshold == null)) { - return false; - } else if (Level.OFF.equals(level) || Level.OFF.equals(threshold)) { - return false; - } else if (Level.ALL.equals(threshold)) { - return true; - } else { - return level.intValue() >= threshold.intValue(); - } - } - - public static SimplifiedLog wrap(final Logger logger) { - if (logger == null) { - return SimplifiedLog.EMPTY; - } else { - return new SimplifiedLog() { - @Override - public void log(Level level, Object message, Throwable t) { - if (isEnabled(level)) { - logMessage(logger, level, message, t); - } - - } - - @Override - public boolean isEnabled(Level level) { - return isLoggable(logger, level); - } - }; - } - } - - // NOTE: assume that level enabled has been checked !!! - public static void logMessage(Logger logger, Level level, Object message, Throwable t) { - if ((logger == null) || (level == null) || Level.OFF.equals(level)) { - return; - } else if (Level.SEVERE.equals(level)) { - logger.error(Objects.toString(message), t); - } else if (Level.WARNING.equals(level)) { - logger.warn(Objects.toString(message), t); - } else if (Level.INFO.equals(level) || Level.ALL.equals(level)) { - logger.info(Objects.toString(message), t); - } else if (Level.CONFIG.equals(level) || Level.FINE.equals(level)) { - logger.debug(Objects.toString(message), t); - } else { - logger.trace(Objects.toString(message), t); - } - } - - /** - * @param logger The {@link Logger} instance - ignored if {@code null} - * @param level The validate log {@link Level} - ignored if {@code null} - * @return <P>{@code true} if the level is enabled for the logger. The - * mapping of the level to the logger is as follows:</P> - * <UL> - * <LI>{@link Level#OFF} always returns {@code false}</LI> - * <LI>{@link Level#SEVERE} returns {@link Logger#isErrorEnabled()}</LI> - * <LI>{@link Level#WARNING} returns {@link Logger#isWarnEnabled()}</LI> - * <LI>{@link Level#INFO} and {@link Level#ALL} returns {@link Logger#isInfoEnabled()}</LI> - * <LI>{@link Level#CONFIG} and {@link Level#FINE} returns {@link Logger#isDebugEnabled()}</LI> - * <LI>All other levels return {@link Logger#isTraceEnabled()}</LI> - * </UL> - */ - public static boolean isLoggable(Logger logger, Level level) { - if ((logger == null) || (level == null) || Level.OFF.equals(level)) { - return false; - } else if (Level.SEVERE.equals(level)) { - return logger.isErrorEnabled(); - } else if (Level.WARNING.equals(level)) { - return logger.isWarnEnabled(); - } else if (Level.INFO.equals(level) || Level.ALL.equals(level)) { - return logger.isInfoEnabled(); - } else if (Level.CONFIG.equals(level) || Level.FINE.equals(level)) { - return logger.isDebugEnabled(); - } else { - return logger.isTraceEnabled(); - } - } - - /** - * @param <T> Generic message type consumer - * @param logger The {@link Logger} instance to use - * @param level The log {@link Level} mapped as follows:</BR> - * - * <UL> - * <LI>{@link Level#OFF} - {@link #nologClosure(Logger)}</LI> - * <LI>{@link Level#SEVERE} - {@link #errorClosure(Logger)}</LI> - * <LI>{@link Level#WARNING} - {@link #warnClosure(Logger)}</LI> - * <LI>{@link Level#INFO}/{@link Level#ALL} - {@link #infoClosure(Logger)}</LI> - * <LI>{@link Level#CONFIG}/{@link Level#FINE} - {@link #debugClosure(Logger)}</LI> - * <LI>All others - {@link #traceClosure(Logger)}</LI> - * </UL> - * @return A consumer whose {@link Consumer#accept(Object)} method logs the - * {@link String#valueOf(Object)} value of its argument if the specific level is enabled - */ - public static <T> Consumer<T> loggingClosure(Logger logger, Level level) { - return loggingClosure(logger, level, null); - } - - public static <T> Consumer<T> loggingClosure(Logger logger, Level level, Throwable t) { - Objects.requireNonNull(level, "No level provided"); - - if (Level.OFF.equals(level)) { - return nologClosure(logger); - } else if (Level.SEVERE.equals(level)) { - return errorClosure(logger, t); - } else if (Level.WARNING.equals(level)) { - return warnClosure(logger, t); - } else if (Level.INFO.equals(level) || Level.ALL.equals(level)) { - return infoClosure(logger, t); - } else if (Level.CONFIG.equals(level) || Level.FINE.equals(level)) { - return debugClosure(logger, t); - } else { - return traceClosure(logger, t); - } - } - - /** - * @param <T> Generic message type consumer - * @param logger The {@link Logger} instance to use - * @return A consumer whose {@link Consumer#accept(Object)} method logs nothing when invoked - */ - public static <T> Consumer<T> nologClosure(Logger logger) { - Objects.requireNonNull(logger, "No logger provided"); - return t -> { /* do nothing */ }; - } - - /** - * @param <T> Generic message type consumer - * @param logger The {@link Logger} instance to use - * @return A consumer whose {@link Consumer#accept(Object)} method logs the - * {@link String#valueOf(Object)} value of its argument if {@link Logger#isErrorEnabled()} - */ - public static <T> Consumer<T> errorClosure(Logger logger) { - return errorClosure(logger, null); - } - - /** - * @param <T> Generic message type consumer - * @param logger The {@link Logger} instance to use - * @param thrown A {@link Throwable} to attach to the message - ignored if {@code null} - * @return A consumer whose {@link Consumer#accept(Object)} method logs the - * {@link String#valueOf(Object)} value of its argument if {@link Logger#isErrorEnabled()} - */ - public static <T> Consumer<T> errorClosure(Logger logger, Throwable thrown) { - Objects.requireNonNull(logger, "No logger provided"); - return new Consumer<T>() { - @Override - public void accept(T input) { - if (logger.isErrorEnabled()) { - String msg = String.valueOf(input); - if (thrown == null) { - logger.error(msg); - } else { - logger.error(msg, thrown); - } - } - } - - @Override - public String toString() { - return "ERROR"; - } - }; - } - - /** - * @param <T> Generic message type consumer - * @param logger The {@link Logger} instance to use - * @return A consumer whose {@link Consumer#accept(Object)} method logs the - * {@link String#valueOf(Object)} value of its argument if {@link Logger#isWarnEnabled()} - */ - public static <T> Consumer<T> warnClosure(Logger logger) { - return warnClosure(logger, null); - } - - /** - * @param <T> Generic message type consumer - * @param logger The {@link Logger} instance to use - * @param thrown A {@link Throwable} to attach to the message - ignored if {@code null} - * @return A consumer whose {@link Consumer#accept(Object)} method logs the {@link String#valueOf(Object)} - * value of its argument if {@link Logger#isWarnEnabled()} - */ - public static <T> Consumer<T> warnClosure(Logger logger, Throwable thrown) { - Objects.requireNonNull(logger, "No logger provided"); - return new Consumer<T>() { - @Override - public void accept(T input) { - if (logger.isWarnEnabled()) { - String msg = String.valueOf(input); - if (thrown == null) { - logger.warn(msg); - } else { - logger.warn(msg, thrown); - } - } - } - - @Override - public String toString() { - return "WARN"; - } - }; - } - - /** - * @param <T> Generic message type consumer - * @param logger The {@link Logger} instance to use - * @return A consumer whose {@link Consumer#accept(Object)} method logs the {@link String#valueOf(Object)} - * value of its argument if {@link Logger#isInfoEnabled()} - */ - public static <T> Consumer<T> infoClosure(Logger logger) { - return infoClosure(logger, null); - } - - /** - * @param <T> Generic message type consumer - * @param logger The {@link Logger} instance to use - * @param thrown A {@link Throwable} to attach to the message - ignored if {@code null} - * @return A consumer whose {@link Consumer#accept(Object)} method logs the - * {@link String#valueOf(Object)} value of its argument if {@link Logger#isInfoEnabled()} - */ - public static <T> Consumer<T> infoClosure(Logger logger, Throwable thrown) { - Objects.requireNonNull(logger, "No logger provided"); - return new Consumer<T>() { - @Override - public void accept(T input) { - if (logger.isInfoEnabled()) { - String msg = String.valueOf(input); - if (thrown == null) { - logger.info(msg); - } else { - logger.info(msg, thrown); - } - } - } - - @Override - public String toString() { - return "INFO"; - } - }; - } - - /** - * @param <T> Generic message type consumer - * @param logger The {@link Logger} instance to use - * @return A consumer whose {@link Consumer#accept(Object)} method logs the - * {@link String#valueOf(Object)} value of its argument if {@link Logger#isDebugEnabled()} - */ - public static <T> Consumer<T> debugClosure(Logger logger) { - return debugClosure(logger, null); - } - - /** - * @param <T> Generic message type consumer - * @param logger The {@link Logger} instance to use - * @param thrown A {@link Throwable} to attach to the message - ignored if {@code null} - * @return A consumer whose {@link Consumer#accept(Object)} method logs the - * {@link String#valueOf(Object)} value of its argument if {@link Logger#isDebugEnabled()} - */ - public static <T> Consumer<T> debugClosure(Logger logger, Throwable thrown) { - Objects.requireNonNull(logger, "No logger provided"); - return new Consumer<T>() { - @Override - public void accept(T input) { - if (logger.isDebugEnabled()) { - String msg = String.valueOf(input); - if (thrown == null) { - logger.debug(msg); - } else { - logger.debug(msg, thrown); - } - } - } - - @Override - public String toString() { - return "DEBUG"; - } - }; - } - - /** - * @param <T> Generic message type consumer - * @param logger The {@link Logger} instance to use - * @return A consumer whose {@link Consumer#accept(Object)} method logs the - * {@link String#valueOf(Object)} value of its argument if {@link Logger#isTraceEnabled()} - */ - public static <T> Consumer<T> traceClosure(Logger logger) { - return traceClosure(logger, null); - } - - /** - * @param <T> Generic message type consumer - * @param logger The {@link Logger} instance to use - * @param thrown A {@link Throwable} to attach to the message - ignored if {@code null} - * @return A consumer whose {@link Consumer#accept(Object)} method logs the - * {@link String#valueOf(Object)} value of its argument if {@link Logger#isTraceEnabled()} - */ - public static <T> Consumer<T> traceClosure(Logger logger, Throwable thrown) { - Objects.requireNonNull(logger, "No logger provided"); - return new Consumer<T>() { - @Override - public void accept(T input) { - if (logger.isTraceEnabled()) { - String msg = String.valueOf(input); - if (thrown == null) { - logger.trace(msg); - } else { - logger.trace(msg, thrown); - } - } - } - - @Override - public String toString() { - return "TRACE"; - } - }; - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/util/logging/SimplifiedLog.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/logging/SimplifiedLog.java b/sshd-core/src/main/java/org/apache/sshd/common/util/logging/SimplifiedLog.java deleted file mode 100644 index 58d58ee..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/logging/SimplifiedLog.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.sshd.common.util.logging; - -import java.util.logging.Level; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public interface SimplifiedLog { - - /** - * An "empty" {@link SimplifiedLog} that does nothing - */ - SimplifiedLog EMPTY = new SimplifiedLog() { - @Override - public boolean isEnabled(Level level) { - return false; - } - - @Override - public void log(Level level, Object message, Throwable t) { - // ignored - } - - @Override - public String toString() { - return "EMPTY"; - } - }; - - boolean isEnabled(Level level); - - default void log(Level level, Object message) { - log(level, message, null); - } - - void log(Level level, Object message, Throwable t); -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/util/net/NetworkConnector.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/net/NetworkConnector.java b/sshd-core/src/main/java/org/apache/sshd/common/util/net/NetworkConnector.java deleted file mode 100644 index df7683a..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/net/NetworkConnector.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.sshd.common.util.net; - -import java.util.concurrent.TimeUnit; - -import org.apache.sshd.common.util.logging.AbstractLoggingBean; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class NetworkConnector extends AbstractLoggingBean { - public static final String DEFAULT_HOST = SshdSocketAddress.LOCALHOST_IPV4; - public static final long DEFAULT_CONNECT_TIMEOUT = TimeUnit.SECONDS.toMillis(5L); - public static final long DEFAULT_READ_TIMEOUT = TimeUnit.SECONDS.toMillis(15L); - - private String protocol; - private String host = DEFAULT_HOST; - private int port; - private long connectTimeout = DEFAULT_CONNECT_TIMEOUT; - private long readTimeout = DEFAULT_READ_TIMEOUT; - - public NetworkConnector() { - super(); - } - - public String getProtocol() { - return protocol; - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - public long getConnectTimeout() { - return connectTimeout; - } - - public void setConnectTimeout(long connectTimeout) { - this.connectTimeout = connectTimeout; - } - - public long getReadTimeout() { - return readTimeout; - } - - public void setReadTimeout(long readTimeout) { - this.readTimeout = readTimeout; - } - - @Override - public String toString() { - return getProtocol() + "://" + getHost() + ":" + getPort() - + ";connect=" + getConnectTimeout() - + ";read=" + getReadTimeout(); - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-core/src/main/java/org/apache/sshd/common/util/net/SshdSocketAddress.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/net/SshdSocketAddress.java b/sshd-core/src/main/java/org/apache/sshd/common/util/net/SshdSocketAddress.java deleted file mode 100644 index b465d14..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/net/SshdSocketAddress.java +++ /dev/null @@ -1,639 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.sshd.common.util.net; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.NetworkInterface; -import java.net.SocketAddress; -import java.net.SocketException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Enumeration; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.NumberUtils; -import org.apache.sshd.common.util.ValidateUtils; - -/** - * <P>A simple socket address holding the host name and port number. The reason - * it does not extend {@link InetSocketAddress} is twofold:</P> - * <OL> - * <LI><P> - * The {@link InetSocketAddress} performs a DNS resolution on the - * provided host name - which we don't want do use until we want to - * create a connection using this address (thus the {@link #toInetSocketAddress()} - * call which executes this query - * </P></LI> - * - * <LI><P> - * If empty host name is provided we replace it with the <I>any</I> - * address of 0.0.0.0 - * </P></LI> - * </OL> - * - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class SshdSocketAddress extends SocketAddress { - public static final String LOCALHOST_NAME = "localhost"; - public static final String LOCALHOST_IPV4 = "127.0.0.1"; - public static final String IPV4_ANYADDR = "0.0.0.0"; - - public static final Set<String> WELL_KNOWN_IPV4_ADDRESSES = - Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(LOCALHOST_IPV4, IPV4_ANYADDR))); - - // 10.0.0.0 - 10.255.255.255 - public static final String PRIVATE_CLASS_A_PREFIX = "10."; - // 172.16.0.0 - 172.31.255.255 - public static final String PRIVATE_CLASS_B_PREFIX = "172."; - // 192.168.0.0 - 192.168.255.255 - public static final String PRIVATE_CLASS_C_PREFIX = "192.168."; - // 100.64.0.0 - 100.127.255.255 - public static final String CARRIER_GRADE_NAT_PREFIX = "100."; - // The IPv4 broadcast address - public static final String BROADCAST_ADDRESS = "255.255.255.255"; - - /** Max. number of hex groups (separated by ":") in an IPV6 address */ - public static final int IPV6_MAX_HEX_GROUPS = 8; - - /** Max. hex digits in each IPv6 group */ - public static final int IPV6_MAX_HEX_DIGITS_PER_GROUP = 4; - - public static final String IPV6_LONG_ANY_ADDRESS = "0:0:0:0:0:0:0:0"; - public static final String IPV6_SHORT_ANY_ADDRESS = "::"; - - public static final String IPV6_LONG_LOCALHOST = "0:0:0:0:0:0:0:1"; - public static final String IPV6_SHORT_LOCALHOST = "::1"; - - public static final Set<String> WELL_KNOWN_IPV6_ADDRESSES = - Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList( - IPV6_LONG_LOCALHOST, IPV6_SHORT_LOCALHOST, - IPV6_LONG_ANY_ADDRESS, IPV6_SHORT_ANY_ADDRESS))); - - /** - * A dummy placeholder that can be used instead of {@code null}s - */ - public static final SshdSocketAddress LOCALHOST_ADDRESS = new SshdSocketAddress(LOCALHOST_IPV4, 0); - - /** - * Compares {@link InetAddress}-es according to their {@link InetAddress#getHostAddress()} - * value case <U>insensitive</U> - * - * @see #toAddressString(InetAddress) - */ - public static final Comparator<InetAddress> BY_HOST_ADDRESS = (a1, a2) -> { - String n1 = GenericUtils.trimToEmpty(toAddressString(a1)); - String n2 = GenericUtils.trimToEmpty(toAddressString(a2)); - return String.CASE_INSENSITIVE_ORDER.compare(n1, n2); - }; - - /** - * Compares {@link SocketAddress}-es according to their host case <U>insensitive</U> - * and if equals, then according to their port value (if any) - * - * @see #toAddressString(SocketAddress) - * @see #toAddressPort(SocketAddress) - */ - public static final Comparator<SocketAddress> BY_HOST_AND_PORT = (a1, a2) -> { - String n1 = GenericUtils.trimToEmpty(toAddressString(a1)); - String n2 = GenericUtils.trimToEmpty(toAddressString(a2)); - int nRes = String.CASE_INSENSITIVE_ORDER.compare(n1, n2); - if (nRes != 0) { - return nRes; - } - - int p1 = toAddressPort(a1); - int p2 = toAddressPort(a2); - nRes = Integer.compare(p1, p2); - if (nRes != 0) { - return nRes; - } - - return 0; - }; - - private static final long serialVersionUID = 6461645947151952729L; - - private final String hostName; - private final int port; - - public SshdSocketAddress(int port) { - this(IPV4_ANYADDR, port); - } - - public SshdSocketAddress(InetSocketAddress addr) { - Objects.requireNonNull(addr, "No address provided"); - - String host = addr.getHostString(); - hostName = GenericUtils.isEmpty(host) ? IPV4_ANYADDR : host; - port = addr.getPort(); - ValidateUtils.checkTrue(port >= 0, "Port must be >= 0: %d", port); - } - - public SshdSocketAddress(String hostName, int port) { - Objects.requireNonNull(hostName, "Host name may not be null"); - this.hostName = GenericUtils.isEmpty(hostName) ? IPV4_ANYADDR : hostName; - - ValidateUtils.checkTrue(port >= 0, "Port must be >= 0: %d", port); - this.port = port; - } - - public String getHostName() { - return hostName; - } - - public int getPort() { - return port; - } - - public InetSocketAddress toInetSocketAddress() { - return new InetSocketAddress(getHostName(), getPort()); - } - - @Override - public String toString() { - return getHostName() + ":" + getPort(); - } - - protected boolean isEquivalent(SshdSocketAddress that) { - if (that == null) { - return false; - } else if (that == this) { - return true; - } else { - return (this.getPort() == that.getPort()) - && (GenericUtils.safeCompare(this.getHostName(), that.getHostName(), false) == 0); - } - } - - @Override - public boolean equals(Object o) { - if (o == null) { - return false; - } - if (getClass() != o.getClass()) { - return false; - } - return isEquivalent((SshdSocketAddress) o); - } - - @Override - public int hashCode() { - return GenericUtils.hashCode(getHostName(), Boolean.FALSE) + getPort(); - } - - - /** - * Returns the first external network address assigned to this - * machine or null if one is not found. - * @return Inet4Address associated with an external interface - * DevNote: We actually return InetAddress here, as Inet4Addresses are final and cannot be mocked. - */ - public static InetAddress getFirstExternalNetwork4Address() { - List<? extends InetAddress> addresses = getExternalNetwork4Addresses(); - return (GenericUtils.size(addresses) > 0) ? addresses.get(0) : null; - } - - /** - * @return a {@link List} of local network addresses which are not multicast - * or localhost sorted according to {@link #BY_HOST_ADDRESS} - */ - public static List<InetAddress> getExternalNetwork4Addresses() { - List<InetAddress> addresses = new ArrayList<>(); - try { - for (Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces(); (nets != null) && nets.hasMoreElements();) { - NetworkInterface netint = nets.nextElement(); - /* TODO - uncomment when 1.5 compatibility no longer required - if (!netint.isUp()) { - continue; // ignore non-running interfaces - } - */ - - for (Enumeration<InetAddress> inetAddresses = netint.getInetAddresses(); (inetAddresses != null) && inetAddresses.hasMoreElements();) { - InetAddress inetAddress = inetAddresses.nextElement(); - if (isValidHostAddress(inetAddress)) { - addresses.add(inetAddress); - } - } - } - } catch (SocketException e) { - // swallow - } - - if (GenericUtils.size(addresses) > 1) { - Collections.sort(addresses, BY_HOST_ADDRESS); - } - - return addresses; - } - - /** - * @param addr The {@link InetAddress} to be verified - * @return <P><code>true</code> if the address is:</P></BR> - * <UL> - * <LI>Not {@code null}</LI> - * <LI>An {@link Inet4Address}</LI> - * <LI>Not link local</LI> - * <LI>Not a multicast</LI> - * <LI>Not a loopback</LI> - * </UL> - * @see InetAddress#isLinkLocalAddress() - * @see InetAddress#isMulticastAddress() - * @see InetAddress#isMulticastAddress() - */ - public static boolean isValidHostAddress(InetAddress addr) { - if (addr == null) { - return false; - } - - if (addr.isLinkLocalAddress()) { - return false; - } - - if (addr.isMulticastAddress()) { - return false; - } - - if (!(addr instanceof Inet4Address)) { - return false; // TODO add support for IPv6 - see SSHD-746 - } - - return !isLoopback(addr); - - } - - /** - * @param addr The {@link InetAddress} to be considered - * @return <code>true</code> if the address is a loopback one. - * <B>Note:</B> if {@link InetAddress#isLoopbackAddress()} - * returns <code>false</code> the address <U>string</U> is checked - * @see #toAddressString(InetAddress) - * @see #isLoopback(String) - */ - public static boolean isLoopback(InetAddress addr) { - if (addr == null) { - return false; - } - - if (addr.isLoopbackAddress()) { - return true; - } - - String ip = toAddressString(addr); - return isLoopback(ip); - } - - /** - * @param ip IP value to be tested - * @return <code>true</code> if the IP is "localhost" or - * "127.x.x.x". - */ - public static boolean isLoopback(String ip) { - if (GenericUtils.isEmpty(ip)) { - return false; - } - - if (LOCALHOST_NAME.equals(ip) || LOCALHOST_IPV4.equals(ip)) { - return true; - } - - // TODO add support for IPv6 - see SSHD-746 - String[] values = GenericUtils.split(ip, '.'); - if (GenericUtils.length(values) != 4) { - return false; - } - - for (int index = 0; index < values.length; index++) { - String val = values[index]; - if (!isValidIPv4AddressComponent(val)) { - return false; - } - - if (index == 0) { - int number = Integer.parseInt(val); - if (number != 127) { - return false; - } - } - } - - return true; - } - - public static SshdSocketAddress toSshdSocketAddress(SocketAddress addr) { - if (addr == null) { - return null; - } else if (addr instanceof SshdSocketAddress) { - return (SshdSocketAddress) addr; - } else if (addr instanceof InetSocketAddress) { - InetSocketAddress isockAddress = (InetSocketAddress) addr; - return new SshdSocketAddress(isockAddress.getHostName(), isockAddress.getPort()); - } else { - throw new UnsupportedOperationException("Cannot convert " + addr.getClass().getSimpleName() - + "=" + addr + " to " + SshdSocketAddress.class.getSimpleName()); - } - } - - public static String toAddressString(SocketAddress addr) { - if (addr == null) { - return null; - } else if (addr instanceof InetSocketAddress) { - return ((InetSocketAddress) addr).getHostString(); - } else if (addr instanceof SshdSocketAddress) { - return ((SshdSocketAddress) addr).getHostName(); - } else { - return addr.toString(); - } - } - - /** - * Attempts to resolve the port value - * - * @param addr The {@link SocketAddress} to examine - * @return The associated port value - negative if failed to resolve - */ - public static int toAddressPort(SocketAddress addr) { - if (addr instanceof InetSocketAddress) { - return ((InetSocketAddress) addr).getPort(); - } else if (addr instanceof SshdSocketAddress) { - return ((SshdSocketAddress) addr).getPort(); - } else { - return -1; - } - } - - /** - * <P>Converts a {@code SocketAddress} into an {@link InetSocketAddress} if possible:</P></BR> - * <UL> - * <LI>If already an {@link InetSocketAddress} then cast it as such</LI> - * <LI>If an {@code SshdSocketAddress} then invoke {@link #toInetSocketAddress()}</LI> - * <LI>Otherwise, throw an exception</LI> - * </UL> - * - * @param remoteAddress The {@link SocketAddress} - ignored if {@code null} - * @return The {@link InetSocketAddress} instance - * @throws ClassCastException if argument is not already an {@code InetSocketAddress} - * or a {@code SshdSocketAddress} - */ - public static InetSocketAddress toInetSocketAddress(SocketAddress remoteAddress) { - if (remoteAddress == null) { - return null; - } else if (remoteAddress instanceof InetSocketAddress) { - return (InetSocketAddress) remoteAddress; - } else if (remoteAddress instanceof SshdSocketAddress) { - return ((SshdSocketAddress) remoteAddress).toInetSocketAddress(); - } else { - throw new ClassCastException("Unknown remote address type: " + remoteAddress); - } - } - - public static String toAddressString(InetAddress addr) { - String ip = (addr == null) ? null : addr.toString(); - if (GenericUtils.isEmpty(ip)) { - return null; - } else { - return ip.replaceAll(".*/", ""); - } - } - - public static boolean isIPv4Address(String addr) { - addr = GenericUtils.trimToEmpty(addr); - if (GenericUtils.isEmpty(addr)) { - return false; - } - - if (WELL_KNOWN_IPV4_ADDRESSES.contains(addr)) { - return true; - } - - String[] comps = GenericUtils.split(addr, '.'); - if (GenericUtils.length(comps) != 4) { - return false; - } - - for (String c : comps) { - if (!isValidIPv4AddressComponent(c)) { - return false; - } - } - - return true; - } - - /** - * Checks if the address is one of the allocated private blocks - * @param addr The address string - * @return {@code true} if this is one of the allocated private - * blocks. <B>Note:</B> it assumes that the address string is - * indeed an IPv4 address - * @see #isIPv4Address(String) - * @see #PRIVATE_CLASS_A_PREFIX - * @see #PRIVATE_CLASS_B_PREFIX - * @see #PRIVATE_CLASS_C_PREFIX - * @see <A HREF="http://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces">Wiki page</A> - */ - public static boolean isPrivateIPv4Address(String addr) { - if (GenericUtils.isEmpty(addr)) { - return false; - } - - if (addr.startsWith(PRIVATE_CLASS_A_PREFIX) || addr.startsWith(PRIVATE_CLASS_C_PREFIX)) { - return true; - } - - // for 172.x.x.x we need further checks - if (!addr.startsWith(PRIVATE_CLASS_B_PREFIX)) { - return false; - } - - int nextCompPos = addr.indexOf('.', PRIVATE_CLASS_B_PREFIX.length()); - if (nextCompPos <= PRIVATE_CLASS_B_PREFIX.length()) { - return false; - } - - String value = addr.substring(PRIVATE_CLASS_B_PREFIX.length(), nextCompPos); - if (!isValidIPv4AddressComponent(value)) { - return false; - } - - int v = Integer.parseInt(value); - return (v >= 16) && (v <= 31); - } - - /** - * @param addr The address to be checked - * @return {@code true} if the address is in the 100.64.0.0/10 range - * @see <A HREF="http://tools.ietf.org/html/rfc6598">RFC6598</A> - */ - public static boolean isCarrierGradeNatIPv4Address(String addr) { - if (GenericUtils.isEmpty(addr)) { - return false; - } - - if (!addr.startsWith(CARRIER_GRADE_NAT_PREFIX)) { - return false; - } - - int nextCompPos = addr.indexOf('.', CARRIER_GRADE_NAT_PREFIX.length()); - if (nextCompPos <= CARRIER_GRADE_NAT_PREFIX.length()) { - return false; - } - - String value = addr.substring(CARRIER_GRADE_NAT_PREFIX.length(), nextCompPos); - if (!isValidIPv4AddressComponent(value)) { - return false; - } - - int v = Integer.parseInt(value); - return (v >= 64) && (v <= 127); - } - - /** - * <P>Checks if the provided argument is a valid IPv4 address component:</P></BR> - * <UL> - * <LI>Not {@code null}/empty</LI> - * <LI>Has at most 3 <U>digits</U></LI> - * <LI>Its value is ≤ 255</LI> - * </UL> - * @param c The {@link CharSequence} to be validate - * @return {@code true} if valid IPv4 address component - */ - public static boolean isValidIPv4AddressComponent(CharSequence c) { - if (GenericUtils.isEmpty(c) || (c.length() > 3)) { - return false; - } - - char ch = c.charAt(0); - if ((ch < '0') || (ch > '9')) { - return false; - } - - if (!NumberUtils.isIntegerNumber(c)) { - return false; - } - - int v = Integer.parseInt(c.toString()); - return (v >= 0) && (v <= 255); - } - - // Based on org.apache.commons.validator.routines.InetAddressValidator#isValidInet6Address - public static boolean isIPv6Address(String address) { - address = GenericUtils.trimToEmpty(address); - if (GenericUtils.isEmpty(address)) { - return false; - } - - if (WELL_KNOWN_IPV6_ADDRESSES.contains(address)) { - return true; - } - - boolean containsCompressedZeroes = address.contains("::"); - if (containsCompressedZeroes && (address.indexOf("::") != address.lastIndexOf("::"))) { - return false; - } - - if (((address.indexOf(':') == 0) && (!address.startsWith("::"))) - || (address.endsWith(":") && (!address.endsWith("::")))) { - return false; - } - - String[] splitOctets = GenericUtils.split(address, ':'); - List<String> octetList = new ArrayList<>(Arrays.asList(splitOctets)); - if (containsCompressedZeroes) { - if (address.endsWith("::")) { - // String.split() drops ending empty segments - octetList.add(""); - } else if (address.startsWith("::") && (!octetList.isEmpty())) { - octetList.remove(0); - } - } - - int numOctests = octetList.size(); - if (numOctests > IPV6_MAX_HEX_GROUPS) { - return false; - } - - int validOctets = 0; - int emptyOctets = 0; // consecutive empty chunks - for (int index = 0; index < numOctests; index++) { - String octet = octetList.get(index); - int pos = octet.indexOf('%'); // is it a zone index - if (pos >= 0) { - // zone index must come last - if (index != (numOctests - 1)) { - return false; - } - - octet = (pos > 0) ? octet.substring(0, pos) : ""; - } - - int octetLength = octet.length(); - if (octetLength == 0) { - emptyOctets++; - if (emptyOctets > 1) { - return false; - } - - validOctets++; - continue; - } - - emptyOctets = 0; - - // Is last chunk an IPv4 address? - if ((index == (numOctests - 1)) && (octet.indexOf('.') > 0)) { - if (!isIPv4Address(octet)) { - return false; - } - validOctets += 2; - continue; - } - - if (octetLength > IPV6_MAX_HEX_DIGITS_PER_GROUP) { - return false; - } - - int octetInt = 0; - try { - octetInt = Integer.parseInt(octet, 16); - } catch (NumberFormatException e) { - return false; - } - - if ((octetInt < 0) || (octetInt > 0x000ffff)) { - return false; - } - - validOctets++; - } - - if ((validOctets > IPV6_MAX_HEX_GROUPS) - || ((validOctets < IPV6_MAX_HEX_GROUPS) && (!containsCompressedZeroes))) { - return false; - } - return true; - } -}
