log.com.unbound.common.Log Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of unbound-java-provider Show documentation
Show all versions of unbound-java-provider Show documentation
This is a collection of JAVA libraries that implement Unbound cryptographic classes for JAVA provider, PKCS11 wrapper, cryptoki, and advapi
package com.unbound.common;
import javax.crypto.ShortBufferException;
import java.io.*;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.nio.charset.StandardCharsets;
import java.time.*;
import java.util.HashMap;
public class Log
{
private native static boolean jniEnabled();
private native static long jniEnter(String name);
private native static void jniEnterOut(long ctx);
private native static void jniPrint(String label);
private native static void jniLeave(int rv);
private native static void jniDataInt(String name, long value, int flags);
private native static void jniDataChars(String name, char[] value, int offset, int length);
private native static void jniDataBytes(String name, byte[] value, int offset, int length);
private native static void jniDataInts(String name, int[] value, int offset, int length);
private native static void jniDataShorts(String name, short[] value, int offset, int length);
private native static void jniDataLongs(String name, long[] value, int offset, int length);
public static Log func(String name)
{
Log log = getInstance();
log.beginFunc(name);
return log;
}
public void failed(Exception e)
{
this.failed = e;
}
public Log leavePrint()
{
if (failed==null) return this;
String message = failed.getMessage();
if (message==null) message = failed.toString();
log("Error", message);
end();
return disabled;
}
public void leave()
{
leavePrint().end();
}
public static Log print(String label)
{
Log log = getInstance();
log.beginPrint(label);
return log;
}
public Log log(String name, boolean value) { return logLong(name, value ? 1 : 0, false); }
public Log log(String name, Boolean value) { return value==null ? this : log(name, value.booleanValue()); }
public Log log(String name, long value) { return logLong(name, value, false); }
public Log logHex(String name, long value) { return logLong(name, value, true); }
public Log log(String name, Long value) { return value==null ? this : log(name, value.longValue()); }
public Log logHex(String name, Long value) { return value==null ? this : log(name, value.longValue()); }
public Log log(String name, int value) { return logLong(name, ((long)value) & 0xffffffffL, false); }
public Log logHex(String name, int value) { return logLong(name, ((long)value) & 0xffffffffL, true); }
public Log log(String name, Integer value) { return value==null ? this : log(name, value.intValue()); }
public Log logHex(String name, Integer value) { return value==null ? this : log(name, value.intValue()); }
public Log log(String name, short value) { return logLong(name, ((long)value) & 0xffff, false); }
public Log logHex(String name, short value) { return logLong(name, ((long)value) & 0xffff, true); }
public Log log(String name, Short value) { return value==null ? this : log(name, value.shortValue()); }
public Log logHex(String name, Short value) { return value==null ? this : log(name, value.shortValue()); }
public Log log(String name, byte value) { return logLong(name, ((long)value) & 0xff, false); }
public Log logHex(String name, byte value) { return logLong(name, ((long)value) & 0xff, true); }
public Log log(String name, Byte value) { return value==null ? this : log(name, value.byteValue()); }
public Log logHex(String name, Byte value) { return value==null ? this : log(name, value.byteValue()); }
public Log log(String name, String value)
{
if (!enabled) return disabled;
byte[] bytes = value==null ? null : value.getBytes(StandardCharsets.UTF_8);
return logBytes(name, bytes, true);
}
public Log log(String name, byte[] value) { return logBytes(name, value, false); }
public Log logLen(String name, byte[] value) { return value==null ? this : log(name, value.length); }
//---------------------- implementation ----------------------
private static final class DisabledLog extends Log
{
@Override public void failed(Exception e) { }
@Override public Log log(String name, long value) { return this; }
@Override public Log logHex(String name, long value) { return this; }
@Override public Log log(String name, int value) { return this; }
@Override public Log log(String name, boolean value) { return this; }
@Override public Log log(String name, short value) { return this; }
@Override public Log log(String name, byte value) { return this; }
@Override public Log logHex(String name, short value) { return this; }
@Override public Log logHex(String name, byte value) { return this; }
@Override public Log logHex(String name, int value) { return this; }
@Override public Log log(String name, byte[] value) { return this; }
@Override public Log log(String name, short[] value) { return this; }
@Override public Log log(String name, int[] value) { return this; }
@Override public Log log(String name, char[] value) { return this; }
@Override public Log log(String name, String value) { return this; }
@Override protected void beginPrint(String label) {}
@Override protected void beginFunc(String name) {}
@Override public Log leavePrint() { return this; }
@Override public Log end() { return this; }
}
//---------------------- implementation ----------------------
private static final class NativeLog extends Log
{
private static final int HEX = 0x01000000;
private Exception failed = null;
private long context = 0;
private String printLabel = null;
@Override public void failed(Exception e) { failed = e; }
@Override public Log log(String name, boolean value) { Log.jniDataInt(name, value ? 1 : 0, 4); return this; }
@Override public Log log(String name, byte value) { Log.jniDataInt(name, value, 1); return this; }
@Override public Log log(String name, short value) { Log.jniDataInt(name, value, 2); return this; }
@Override public Log log(String name, int value) { Log.jniDataInt(name, value, 4); return this; }
@Override public Log log(String name, long value) { Log.jniDataInt(name, value, 8); return this; }
@Override public Log logHex(String name, byte value) { Log.jniDataInt(name, value, 1|HEX); return this; }
@Override public Log logHex(String name, short value) { Log.jniDataInt(name, value, 2|HEX); return this; }
@Override public Log logHex(String name, int value) { Log.jniDataInt(name, value, 4|HEX); return this; }
@Override public Log logHex(String name, long value) { Log.jniDataInt(name, value, 8|HEX); return this; }
@Override public Log log(String name, byte[] value) { Log.jniDataBytes (name, value, 0, value==null ? 0 : value.length); return this; }
@Override public Log log(String name, short[] value) { Log.jniDataShorts(name, value, 0, value==null ? 0 : value.length); return this; }
@Override public Log log(String name, int[] value) { Log.jniDataInts (name, value, 0, value==null ? 0 : value.length); return this; }
@Override public Log log(String name, char[] value) { Log.jniDataChars (name, value, 0, value==null ? 0 : value.length); return this; }
@Override public Log log(String name, String value)
{
char[] chars = value==null ? null : value.toCharArray();
Log.jniDataChars(name, chars, 0, chars==null ? 0 : chars.length);
return this;
}
@Override protected void beginPrint(String label) { printLabel = label; }
@Override protected void beginFunc(String name) { context = Log.jniEnter(name); }
// @Override public Log leavePrint() { return this; }
@Override public Log end()
{
if (context!=0) { Log.jniEnterOut(context); context=0; }
else if (printLabel!=null) { Log.jniPrint(printLabel); printLabel=null; }
else
{
Log.jniLeave(Log.exceptionToRv(failed));
failed = null;
}
return this;
}
}
private static boolean enabled = false;
private static Log disabled = new DisabledLog();
private static final ThreadLocal thread = new ThreadLocal<>();
private static Clock clock = Clock.systemUTC();
private static final int DYLOG_SIGNATURE = 0X6E877B21;
private static final int DYLOG_BLOCK_CONTROL = 0;
private static final int DYLOG_BLOCK_ENTER = 1;
private static final int DYLOG_BLOCK_LEAVE = 2;
private static final int DYLOG_BLOCK_PRINT = 3;
private static final int DYLOG_CTRL_STRING = 0;
private static final int DYLOG_CTRL_LABEL = 1;
private static final int DYLOG_DEC = 0;
private static final int DYLOG_HEX = 1;
private static final int DYLOG_CHARS = 2;
private static final int DYLOG_ARR_1 = 3;
private static final int DYLOG_ARR_2 = 4;
private static final int DYLOG_ARR_4 = 5;
private static final int DYLOG_CHARS_ID = 6;
private static String dir;
private static long pid;
private static boolean isNative = false;
static
{
try
{
try
{
System.loadLibrary("dylog");
isNative = true;
}
catch (Throwable e) {}
if (isNative)
{
enabled = jniEnabled();
}
else
{
String e = System.getenv("DYLOG_ENABLED");
enabled = (e==null) ? Config.getBool("log", "enabled") : e.equals("1");
if (enabled)
{
RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
String root = Config.isWindows ? "C:\\Windows\\Temp" : "/tmp";
dir = root + "/dy.log";
new File(dir).mkdirs();
// Get name representing the running Java virtual machine.
// It returns something like 6460@AURORA. Where the value
// before the @ symbol is the PID.
String jvmName = runtime.getName();
pid = Long.parseLong(jvmName.split("@")[0]);
}
}
}
catch (Exception e)
{
enabled = false;
}
}
private FileOutputStream file;
private long timerMs;
private long timerMsDiff;
private HashMap strings = new HashMap<>();
private byte[] paramsBuf = new byte[64];
private int paramsLength = 0;
private int stringsCount = 0;
private byte[] tempBuf = new byte[32];
private int tempBufLength = 0;
private int printId = 0;
private int funcId = 0;
private Exception failed = null;
protected void init() throws Exception
{
if (isNative) return;
String path = dir + "/java_P" + pid + "_T" + Thread.currentThread().getId() + ".dylog";
file = new FileOutputStream(path);
Instant now = Instant.now();
ZoneOffset offset = ZoneOffset.systemDefault().getRules().getOffset(now);
long localTimeMs = now.toEpochMilli() + offset.getTotalSeconds()*1000;
timerMs = clock.millis();
timerMsDiff = System.nanoTime() - timerMs*1000000;
outLabel(localTimeMs);
}
private void setParamsCapacity(int capacity)
{
if (capacity<= paramsLength) return;
if (capacity< paramsLength *2) capacity = paramsLength *2;
byte[] newBuf = new byte[capacity];
System.arraycopy(paramsBuf, 0, newBuf, 0, paramsLength);
paramsBuf = newBuf;
}
private static int getValueLengthCode(int value)
{
if (value < 0) return 3;
if (value==0x00000000) return 0;
if (value<=0x000000ff) return 1;
if (value<=0x0000ffff) return 2;
return 3;
}
private void outByte(byte value)
{
tempBuf[tempBufLength++] = value;
}
private void outValue(int value)
{
if (value<0 || value>=65536) { outByte((byte)(value>>24)); outByte((byte)(value>>16)); }
if (value<0 || value>=256) outByte((byte)(value>>8));
if (value!=0) outByte((byte)value);
}
private void outBlockHeader(int code, int length, int id, int timer)
{
byte header = (byte)(
(code << 6) |
(getValueLengthCode(length) << 4) |
(getValueLengthCode(id) << 2) |
getValueLengthCode(timer));
tempBufLength = 0;
outByte(header);
outValue(length);
outValue(id);
outValue(timer);
out(tempBuf, tempBufLength);
}
private void out(byte[] in, int length)
{
try { file.write(in, 0, length); }
catch (Exception e) { }
}
private void outLabel(long localTimeMs)
{
outBlockHeader(DYLOG_BLOCK_CONTROL, 8, DYLOG_CTRL_LABEL, DYLOG_SIGNATURE);
Converter.setBE8(tempBuf, 0, localTimeMs); out(tempBuf, 8);
}
private void outString(String str)
{
byte[] data = str.getBytes(StandardCharsets.UTF_8);
outBlockHeader(DYLOG_BLOCK_CONTROL, data.length, DYLOG_CTRL_STRING, 0);
out(data, data.length);
}
private void outFuncEnter(long newTimerMs, int id)
{
outBlockHeader(DYLOG_BLOCK_ENTER, paramsLength, id, (int)(newTimerMs - timerMs));
out(paramsBuf, paramsLength);
}
private void outFuncLeave(long newTimerMs, int rv)
{
outBlockHeader(DYLOG_BLOCK_LEAVE, paramsLength, rv, (int)(newTimerMs - timerMs));
out(paramsBuf, paramsLength);
}
private void outPrint(long newTimerMs, int id)
{
outBlockHeader(DYLOG_BLOCK_PRINT, paramsLength, id, (int)(newTimerMs - timerMs));
out(paramsBuf, paramsLength);
}
private int getStringId(String str)
{
Integer i = strings.get(str);
if (i!=null) return i;
stringsCount++;
strings.put(str, stringsCount);
outString(str);
return stringsCount;
}
private void cleanParams() { paramsLength = 0; }
private static Log getInstance()
{
if (!enabled) return disabled;
Log log = thread.get();
if (log == null)
{
if (isNative) log = new NativeLog();
else
{
log = new Log();
try { log.init(); }
catch (Exception e) { log = disabled; }
}
thread.set(log);
}
return log;
}
protected void beginFunc(String name)
{
funcId = getStringId(name);
}
protected void beginPrint(String label)
{
printId = getStringId(label);
}
public Log end()
{
long newTimerMs = (System.nanoTime()-timerMsDiff) / 1000000;
if (funcId!=0)
{
outFuncEnter(newTimerMs, funcId);
funcId = 0;
}
else if (printId!=0)
{
outPrint(newTimerMs, printId);
printId = 0;
}
else
{
outFuncLeave(newTimerMs, exceptionToRv(failed));
}
failed = null;
timerMs = newTimerMs;
cleanParams();
return this;
}
//-------------------------------------- data -------------------------------------
private int getParamLengthCode(int length)
{
if (length<=5) return length;
if (length<=255) return 6;
return 7;
}
private int getParamValueLength(long value)
{
int length = 0;
while (value!=0)
{
length++;
value>>>=8;
}
return length;
}
private void outParamValue(long value)
{
int length = 0;
while (value!=0)
{
tempBuf[length++] = (byte)(value);
value>>>=8;
}
while (length!=0) paramsBuf[paramsLength++] = tempBuf[--length];
}
private void outParamByte(byte value)
{
setParamsCapacity(paramsLength + 1);
paramsBuf[paramsLength++] = value;
}
private void outParamHeader(int code, int length, int id)
{
int paramLengthCode = getParamLengthCode(length);
int idLengthCode = getValueLengthCode(id);
byte header =(byte)(
(code << 5) |
(paramLengthCode << 2) |
idLengthCode);
outParamByte(header);
if (length>5)
{
if (length>=0x000000ff) outParamByte((byte)(length>>8));
outParamByte((byte)length);
}
if (id>0x0000ffff || id<0)
{
outParamByte((byte)(id>>24));
outParamByte((byte)(length>>16));
}
if (id>0x000000ff) outParamByte((byte)(id>>8));
if (id>0) outParamByte((byte)(id));
}
private Log logLong(String name, long value, boolean hex)
{
int id = getStringId(name);
if (value==0) hex = false;
int code = hex ? DYLOG_HEX : DYLOG_DEC;
int outLength = getParamValueLength(value);
outParamHeader(code, outLength, id);
setParamsCapacity(paramsLength + outLength);
outParamValue(value);
return this;
}
private Log logBytes(String name, byte[] value, boolean chars)
{
if (value==null) return logLong(name, 0, false);
int id = getStringId(name);
int code = chars ? DYLOG_CHARS : DYLOG_ARR_1;
outParamHeader(code, value.length, id);
setParamsCapacity(paramsLength + value.length);
System.arraycopy(value, 0, paramsBuf, paramsLength, value.length);
paramsLength += value.length;
return this;
}
public Log log(String name, short[] value)
{
if (value==null) return logLong(name, 0, false);
int id = getStringId(name);
outParamHeader(DYLOG_ARR_2, value.length*2, id);
setParamsCapacity(paramsLength + value.length*2);
for (short v : value)
{
paramsBuf[paramsLength++] = (byte)(v>>8);
paramsBuf[paramsLength++] = (byte)v;
}
return this;
}
public Log log(String name, int[] value)
{
if (value==null) return logLong(name, 0, false);
int id = getStringId(name);
outParamHeader(DYLOG_ARR_4, value.length*4, id);
setParamsCapacity(paramsLength + value.length*4);
for (int v : value)
{
paramsBuf[paramsLength++] = (byte)(v>>24);
paramsBuf[paramsLength++] = (byte)(v>>16);
paramsBuf[paramsLength++] = (byte)(v>>8);
paramsBuf[paramsLength++] = (byte)v;
}
return this;
}
public Log log(String name, char[] value)
{
if (value==null) return logLong(name, 0, false);
int id = getStringId(name);
outParamHeader(DYLOG_CHARS, value.length, id);
setParamsCapacity(paramsLength + value.length);
for (char v : value) paramsBuf[paramsLength++] = (byte)v;
return this;
}
private static final int E_GENERAL = 0xff010001;
private static final int E_BADARG = 0xff010002;
private static final int E_TOO_SMALL = 0xff010008;
private static int exceptionToRv(Exception e)
{
if (e==null) return 0;
if (e instanceof IllegalArgumentException) return E_BADARG;
if (e instanceof ShortBufferException) return E_TOO_SMALL;
return E_GENERAL;
}
}