diff --git a/assembly/pom.xml b/assembly/pom.xml
index 9656989..954ba88 100644
--- a/assembly/pom.xml
+++ b/assembly/pom.xml
@@ -26,6 +26,12 @@
org.ps5jb
xlet
${xlet.version}
+
+
+ *
+ *
+
+
diff --git a/sdk/src/main/java/org/ps5jb/sdk/core/AbstractPointer.java b/sdk/src/main/java/org/ps5jb/sdk/core/AbstractPointer.java
new file mode 100644
index 0000000..a9a5c26
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/core/AbstractPointer.java
@@ -0,0 +1,386 @@
+package org.ps5jb.sdk.core;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+
+/**
+ * Root parent for any class that implements a pointer to a memory.
+ */
+public abstract class AbstractPointer {
+ /**
+ * Wrap the given pointer in a non-null check. Returns the same pointer if it is not NULL.
+ *
+ * @param pointer Pointer to verify.
+ * @param errorMessage Error message assigned to the exception if the pointer is NULL.
+ * @return Same pointer
value if it is not NULL.
+ * @throws NullPointerException If the input pointer is NULL or points to the address 0.
+ */
+ public static AbstractPointer nonNull(AbstractPointer pointer, String errorMessage) {
+ if (pointer == null || pointer.addr() == 0) {
+ throw new NullPointerException(errorMessage);
+ }
+ return pointer;
+ }
+
+ /**
+ * Check that the pointer operation will result in an overflow.
+ *
+ * @param pointer Pointer to verify.
+ * @param offset Offset at which the pointer operation is started.
+ * @param size Size of the pointer operation.
+ * @throws IndexOutOfBoundsException If the operation is out of bounds.
+ */
+ public static void overflow(AbstractPointer pointer, long offset, long size) {
+ // All overflow checks are disabled when size is unknown
+ if (pointer.size != null) {
+ if (offset < 0) {
+ throw new IndexOutOfBoundsException(Long.toString(offset));
+ }
+
+ if (((offset + size) > pointer.size.longValue())) {
+ throw new IndexOutOfBoundsException(Long.toString(offset + size));
+ }
+ }
+ }
+
+ /** Native memory address pointed to by this instance. */
+ protected long addr;
+
+ /** Size of the memory pointed to by this instance. May be null if the size is unknown. */
+ protected Long size;
+
+ /**
+ * Constructor of a pointer without a known size.
+ *
+ * @param addr Memory address of the pointer.
+ */
+ protected AbstractPointer(long addr) {
+ this(addr, null);
+ }
+
+ /**
+ * Constructor of a pointer where the size is known.
+ *
+ * @param addr Memory address of the pointer.
+ * @param size Size of the memory.
+ */
+ protected AbstractPointer(long addr, Long size) {
+ this.addr = addr;
+ this.size = size;
+ }
+
+ /**
+ * Read 1 byte at the specified offset from the pointer.
+ *
+ * @param offset Offset relative to {@link #addr}.
+ * @return Value read from the memory.
+ */
+ public abstract byte read1(long offset);
+
+ /**
+ * Read 1 byte from the address pointed to by this pointer instance.
+ *
+ * @return Value read from the memory.
+ */
+ public byte read1() {
+ return read1(0);
+ }
+
+ /**
+ * Read 2 bytes at the specified offset from the pointer.
+ *
+ * @param offset Offset relative to {@link #addr}.
+ * @return Value read from the memory.
+ */
+ public abstract short read2(long offset);
+
+ /**
+ * Read 2 bytes from the address pointed to by this pointer instance.
+ *
+ * @return Value read from the memory.
+ */
+ public short read2() {
+ return read2(0);
+ }
+
+ /**
+ * Read 4 bytes at the specified offset from the pointer.
+ *
+ * @param offset Offset relative to {@link #addr}.
+ * @return Value read from the memory.
+ */
+ public abstract int read4(long offset);
+
+ /**
+ * Read 4 bytes from the address pointed to by this pointer instance.
+ *
+ * @return Value read from the memory.
+ */
+ public int read4() {
+ return read4(0);
+ }
+
+ /**
+ * Read 8 bytes at the specified offset from the pointer.
+ *
+ * @param offset Offset relative to {@link #addr}.
+ * @return Value read from the memory.
+ */
+ public abstract long read8(long offset);
+
+ /**
+ * Read 8 bytes from the address pointed to by this pointer instance.
+ *
+ * @return Value read from the memory.
+ */
+ public long read8() {
+ return read8(0);
+ }
+
+ /**
+ * Read the given number of bytes from the address pointed to by this pointer instance.
+ *
+ * @param size Number of bytes to read.
+ * @return Value read from the memory as an array of bytes.
+ */
+ public byte[] read(int size) {
+ byte[] result = new byte[size];
+ read(0, result, 0, size);
+ return result;
+ }
+
+ /**
+ * Read the given number of bytes at the specified offset from the pointer.
+ *
+ * @param offset Offset relative to {@link #addr}.
+ * @param value Buffer to read the value into.
+ * @param valueOffset Offset in the buffer where to place the read value.
+ * @param size Number of bytes to read.
+ * @throws IndexOutOfBoundsException If the buffer is not large enough to hold the value
+ * of the specified size.
+ */
+ public void read(long offset, byte[] value, int valueOffset, int size) {
+ // TODO: This can be implemented more efficiently
+ for (int i = 0; i < size; ++i) {
+ value[valueOffset + i] = read1(offset + i);
+ }
+ }
+
+ /**
+ * Read the data at the specified offset from the pointer assuming it is a native
+ * null-terminated string.
+ *
+ * @param offset Offset relative to {@link #addr}.
+ * @param maxLength Maximum number of bytes to read. If null
,
+ * the memory will be read until the null character is encountered.
+ * @param charset Charset to use to convert the native string into a Java
+ * string.
+ * @return Value of the memory as a Java string.
+ * @throws SdkRuntimeException If the string could not be read, for example
+ * if the bytes cannot be converted to the target charset.
+ */
+ public String readString(long offset, Integer maxLength, String charset) {
+ try {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ try {
+ long curSize = 0;
+ byte c = read1(offset);
+ while (c != 0 && (maxLength == null || maxLength.intValue() > curSize)) {
+ buf.write(c);
+ ++curSize;
+ c = read1(offset + curSize);
+ }
+ } finally {
+ buf.close();
+ }
+ return buf.toString(charset);
+ } catch (IOException e) {
+ throw new SdkRuntimeException(e);
+ }
+ }
+
+ /**
+ * Read the current value of the pointer assuming the data is a native
+ * null-terminated string. The bytes in the native memory are converted to
+ * Java string using the system default charset.
+ *
+ * @param maxLength Maximum number of bytes to read. If null
,
+ * the memory will be read until the null character is encountered.
+ * @return Value of the memory as a Java string.
+ */
+ public String readString(Integer maxLength) {
+ return readString(0, maxLength, Charset.defaultCharset().name());
+ }
+
+ /**
+ * Write 1 byte at the specified offset from the pointer.
+ *
+ * @param offset Offset relative to {@link #addr}.
+ * @param value Value to write.
+ */
+ public abstract void write1(long offset, byte value);
+
+ /**
+ * Write 1 byte to the address pointed to by this pointer instance.
+ *
+ * @param value Value to write.
+ */
+ public void write1(byte value) {
+ write1(0, value);
+ }
+
+ /**
+ * Write 2 bytes at the specified offset from the pointer.
+ *
+ * @param offset Offset relative to {@link #addr}.
+ * @param value Value to write.
+ */
+ public abstract void write2(long offset, short value);
+
+ /**
+ * Write 2 bytes to the address pointed to by this pointer instance.
+ *
+ * @param value Value to write.
+ */
+ public void write2(short value) {
+ write2(0, value);
+ }
+
+ /**
+ * Write 4 bytes at the specified offset from the pointer.
+ *
+ * @param offset Offset relative to {@link #addr}.
+ * @param value Value to write.
+ */
+ public abstract void write4(long offset, int value);
+
+ /**
+ * Write 4 bytes to the address pointed to by this pointer instance.
+ *
+ * @param value Value to write.
+ */
+ public void write4(int value) {
+ write4(0, value);
+ }
+
+ /**
+ * Write 8 bytes at the specified offset from the pointer.
+ *
+ * @param offset Offset relative to {@link #addr}.
+ * @param value Value to write.
+ */
+ public abstract void write8(long offset, long value);
+
+ /**
+ * Write 8 bytes to the address pointed to by this pointer instance.
+ *
+ * @param value Value to write.
+ */
+ public void write8(long value) {
+ write8(0, value);
+ }
+
+ /**
+ * Write the given number of bytes to the address pointed to by this pointer instance.
+ *
+ * @param value Value to write.
+ */
+ public void write(byte[] value) {
+ this.write(0, value, 0, value.length);
+ }
+
+ /**
+ * Write the given number of bytes at the specified offset from the pointer.
+ *
+ * @param offset Offset relative to {@link #addr}.
+ * @param value Buffer to write.
+ * @param valueOffset Offset in the buffer from which to start writing.
+ * @param count Number of bytes to write.
+ * @throws IndexOutOfBoundsException If the buffer or the native memory
+ * are not large enough for the given values of offset
,
+ * valueOffset
and count
.
+ */
+ public void write(long offset, byte[] value, int valueOffset, int count) {
+ // TODO: This can be implemented more efficiently
+ for (int i = 0; i < count - valueOffset; ++i) {
+ write1(this.addr + offset + i, value[valueOffset + i]);
+ }
+ }
+
+ /**
+ * Write a given Java string at the specified offset from the pointer as
+ * a native null-terminated string.
+ *
+ * @param offset Offset relative to {@link #addr}.
+ * @param string String value to write.
+ * @param charset Charset to use to convert the native string into a Java
+ * string.
+ * @throws SdkRuntimeException If the string could not be written, for example
+ * if the bytes cannot be converted to the target charset.
+ * @throws IndexOutOfBoundsException If the write beyond the pointer size occurs.
+ */
+ public void writeString(long offset, String string, String charset) {
+ byte[] stringBuffer;
+ try {
+ stringBuffer = string.getBytes(charset);
+ } catch (UnsupportedEncodingException e) {
+ throw new SdkRuntimeException(e);
+ }
+
+ write(offset, stringBuffer, 0, stringBuffer.length);
+ write1(offset + stringBuffer.length, (byte) 0);
+ }
+
+ public void writeString(String string) {
+ writeString(0, string, Charset.defaultCharset().name());
+ }
+
+ /**
+ * Get the native memory address of this pointer.
+ *
+ * @return Native memory address of this pointer.
+ */
+ public long addr() {
+ return this.addr;
+ }
+
+ /**
+ * Get the size of the allocated native memory pointed to by this instance.
+ *
+ * @return Size of the memory pointed to by this pointer. May be null if the size is unknown.
+ */
+ public Long size() {
+ return this.size;
+ }
+
+ /**
+ * Compares the address of this pointer with the address of another pointer.
+ * Note that size does not play a role in equality of two pointers.
+ *
+ * @param obj Other pointer to compare this pointer to.
+ * If this object is not a pointer, the comparison returns false
.
+ * @return True if obj
is a pointer and its address is the same
+ * as this instance's address.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ boolean result = false;
+ if (obj instanceof AbstractPointer) {
+ // Size is not considered when evaluating equality
+ result = ((AbstractPointer) obj).addr == this.addr;
+ }
+ return result;
+ }
+
+ /**
+ * Computes a hashcode for this pointer.
+ *
+ * @return This pointer's hashcode.
+ */
+ @Override
+ public int hashCode() {
+ return (new Long(this.addr)).hashCode();
+ }
+}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/core/Pointer.java b/sdk/src/main/java/org/ps5jb/sdk/core/Pointer.java
index a837a3b..e04f986 100644
--- a/sdk/src/main/java/org/ps5jb/sdk/core/Pointer.java
+++ b/sdk/src/main/java/org/ps5jb/sdk/core/Pointer.java
@@ -1,7 +1,5 @@
package org.ps5jb.sdk.core;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.Charset;
@@ -10,9 +8,9 @@
import jdk.internal.misc.Unsafe;
/**
- * Abstraction over memory pointer operations.
+ * Abstraction over memory pointer operations in user-space.
*/
-public class Pointer {
+public class Pointer extends AbstractPointer {
/**
* Helper class to obtain an instance of Unsafe in a thread-safe manner.
*/
@@ -145,42 +143,6 @@ static Pointer addrOf(Object object) {
return Pointer.valueOf(getUnsafe().getLong(val, getLongValueOffset()));
}
- /**
- * Wrap the given pointer in a non-null check. Returns the same pointer if it is not NULL.
- *
- * @param pointer Pointer to verify.
- * @param errorMessage Error message assigned to the exception if the pointer is NULL.
- * @return Same pointer
value if it is not NULL.
- * @throws NullPointerException If the input pointer is NULL or points to the address 0.
- */
- public static Pointer nonNull(Pointer pointer, String errorMessage) {
- if (pointer == null || pointer.addr() == 0) {
- throw new NullPointerException(errorMessage);
- }
- return pointer;
- }
-
- /**
- * Check that the pointer operation will result in an overflow.
- *
- * @param pointer Pointer to verify.
- * @param offset Offset at which the pointer operation is started.
- * @param size Size of the pointer operation.
- * @throws IndexOutOfBoundsException If the operation is out of bounds.
- */
- public static void overflow(Pointer pointer, long offset, long size) {
- // All overflow checks are disabled when size is unknown
- if (pointer.size != null) {
- if (offset < 0) {
- throw new IndexOutOfBoundsException(Long.toString(offset));
- }
-
- if (((offset + size) > pointer.size.longValue())) {
- throw new IndexOutOfBoundsException(Long.toString(offset + size));
- }
- }
- }
-
/**
* Returns a pointer instance equivalent to the given native memory address.
*
@@ -194,322 +156,82 @@ public static Pointer valueOf(long addr) {
/** Static constant for NULL pointer. */
public static final Pointer NULL = new Pointer(0);
- /** Native memory address pointed to by this instance. */
- private long addr;
-
- /** Size of the memory pointed to by this instance. May be null if the size is unknown. */
- private Long size;
-
- /**
- * Constructor of a pointer without a known size.
- *
- * @param addr Memory address of the pointer.
- */
public Pointer(long addr) {
- this(addr, null);
+ super(addr);
}
- /**
- * Constructor of a pointer where the size is known.
- *
- * @param addr Memory address of the pointer.
- * @param size Size of the memory.
- */
public Pointer(long addr, Long size) {
- this.addr = addr;
- this.size = size;
+ super(addr, size);
}
- /**
- * Read 1 byte at the specified offset from the pointer.
- *
- * @param offset Offset relative to {@link #addr}.
- * @return Value read from the memory.
- */
+ @Override
public byte read1(long offset) {
overflow(this, offset, 1);
return getUnsafe().getByte(this.addr + offset);
}
- /**
- * Read 1 byte from the address pointed to by this pointer instance.
- *
- * @return Value read from the memory.
- */
- public byte read1() {
- return read1(0);
- }
-
- /**
- * Read 2 bytes at the specified offset from the pointer.
- *
- * @param offset Offset relative to {@link #addr}.
- * @return Value read from the memory.
- */
+ @Override
public short read2(long offset) {
overflow(this, offset, 2);
return getUnsafe().getShort(this.addr + offset);
}
- /**
- * Read 2 bytes from the address pointed to by this pointer instance.
- *
- * @return Value read from the memory.
- */
- public short read2() {
- return read2(0);
- }
-
- /**
- * Read 4 bytes at the specified offset from the pointer.
- *
- * @param offset Offset relative to {@link #addr}.
- * @return Value read from the memory.
- */
+ @Override
public int read4(long offset) {
overflow(this, offset, 4);
return getUnsafe().getInt(this.addr + offset);
}
- /**
- * Read 4 bytes from the address pointed to by this pointer instance.
- *
- * @return Value read from the memory.
- */
- public int read4() {
- return read4(0);
- }
-
- /**
- * Read 8 bytes at the specified offset from the pointer.
- *
- * @param offset Offset relative to {@link #addr}.
- * @return Value read from the memory.
- */
+ @Override
public long read8(long offset) {
overflow(this, offset, 8);
return getUnsafe().getLong(this.addr + offset);
}
- /**
- * Read 8 bytes from the address pointed to by this pointer instance.
- *
- * @return Value read from the memory.
- */
- public long read8() {
- return read8(0);
- }
-
- /**
- * Read the given number of bytes from the address pointed to by this pointer instance.
- *
- * @param size Number of bytes to read.
- * @return Value read from the memory as an array of bytes.
- */
- public byte[] read(int size) {
- byte[] result = new byte[size];
- read(0, result, 0, size);
- return result;
- }
-
- /**
- * Read the given number of bytes at the specified offset from the pointer.
- *
- * @param offset Offset relative to {@link #addr}.
- * @param value Buffer to read the value into.
- * @param valueOffset Offset in the buffer where to place the read value.
- * @param size Number of bytes to read.
- * @throws IndexOutOfBoundsException If the buffer is not large enough to hold the value
- * of the specified size.
- */
+ @Override
public void read(long offset, byte[] value, int valueOffset, int size) {
overflow(this, offset, size);
- for (int i = 0; i < size; ++i) {
- value[valueOffset + i] = read1(offset + i);
- }
- }
- /**
- * Read the data at the specified offset from the pointer assuming it is a native
- * null-terminated string.
- *
- * @param offset Offset relative to {@link #addr}.
- * @param maxLength Maximum number of bytes to read. If null
,
- * the memory will be read until the null character is encountered.
- * @param charset Charset to use to convert the native string into a Java
- * string.
- * @return Value of the memory as a Java string.
- * @throws SdkRuntimeException If the string could not be read, for example
- * if the bytes cannot be converted to the target charset.
- */
- public String readString(long offset, Integer maxLength, String charset) {
- try {
- ByteArrayOutputStream buf = new ByteArrayOutputStream();
- try {
- long curSize = 0;
- byte c = read1(offset);
- while (c != 0 && (maxLength == null || maxLength.intValue() > curSize)) {
- buf.write(c);
- ++curSize;
- c = read1(offset + curSize);
- }
- } finally {
- buf.close();
- }
- return buf.toString(charset);
- } catch (IOException e) {
- throw new SdkRuntimeException(e);
+ // TODO: This can be implemented more efficiently
+ for (int i = 0; i < size; ++i) {
+ value[valueOffset + i] = getUnsafe().getByte(this.addr + offset + i);
}
}
- /**
- * Read the current value of the pointer assuming the data is a native
- * null-terminated string. The bytes in the native memory are converted to
- * Java string using the system default charset.
- *
- * @param maxLength Maximum number of bytes to read. If null
,
- * the memory will be read until the null character is encountered.
- * @return Value of the memory as a Java string.
- */
- public String readString(Integer maxLength) {
- return readString(0, maxLength, Charset.defaultCharset().name());
- }
-
- /**
- * Write 1 byte at the specified offset from the pointer.
- *
- * @param offset Offset relative to {@link #addr}.
- * @param value Value to write.
- */
+ @Override
public void write1(long offset, byte value) {
overflow(this, offset, 1);
getUnsafe().putByte(this.addr + offset, value);
}
- /**
- * Write 1 byte to the address pointed to by this pointer instance.
- *
- * @param value Value to write.
- */
- public void write1(byte value) {
- write1(0, value);
- }
-
- /**
- * Write 2 bytes at the specified offset from the pointer.
- *
- * @param offset Offset relative to {@link #addr}.
- * @param value Value to write.
- */
+ @Override
public void write2(long offset, short value) {
overflow(this, offset, 2);
getUnsafe().putShort(this.addr + offset, value);
}
- /**
- * Write 2 bytes to the address pointed to by this pointer instance.
- *
- * @param value Value to write.
- */
- public void write2(short value) {
- write2(0, value);
- }
-
- /**
- * Write 4 bytes at the specified offset from the pointer.
- *
- * @param offset Offset relative to {@link #addr}.
- * @param value Value to write.
- */
+ @Override
public void write4(long offset, int value) {
overflow(this, offset, 4);
getUnsafe().putInt(this.addr + offset, value);
}
- /**
- * Write 4 bytes to the address pointed to by this pointer instance.
- *
- * @param value Value to write.
- */
- public void write4(int value) {
- write4(0, value);
- }
-
- /**
- * Write 8 bytes at the specified offset from the pointer.
- *
- * @param offset Offset relative to {@link #addr}.
- * @param value Value to write.
- */
+ @Override
public void write8(long offset, long value) {
overflow(this, offset, 8);
getUnsafe().putLong(this.addr + offset, value);
}
- /**
- * Write 8 bytes to the address pointed to by this pointer instance.
- *
- * @param value Value to write.
- */
- public void write8(long value) {
- write8(0, value);
- }
-
- /**
- * Write the given number of bytes to the address pointed to by this pointer instance.
- *
- * @param value Value to write.
- */
- public void write(byte[] value) {
- this.write(0, value, 0, value.length);
- }
-
- /**
- * Write the given number of bytes at the specified offset from the pointer.
- *
- * @param offset Offset relative to {@link #addr}.
- * @param value Buffer to write.
- * @param valueOffset Offset in the buffer from which to start writing.
- * @param count Number of bytes to write.
- * @throws IndexOutOfBoundsException If the buffer or the native memory
- * are not large enough for the given values of offset
,
- * valueOffset
and count
.
- */
+ @Override
public void write(long offset, byte[] value, int valueOffset, int count) {
overflow(this, offset, count);
+
+ // TODO: This can be implemented more efficiently
for (int i = 0; i < count - valueOffset; ++i) {
getUnsafe().putByte(this.addr + offset + i, value[valueOffset + i]);
}
}
- /**
- * Write a given Java string at the specified offset from the pointer as
- * a native null-terminated string.
- *
- * @param offset Offset relative to {@link #addr}.
- * @param string String value to write.
- * @param charset Charset to use to convert the native string into a Java
- * string.
- * @throws SdkRuntimeException If the string could not be written, for example
- * if the bytes cannot be converted to the target charset.
- * @throws IndexOutOfBoundsException If the write beyond the pointer size occurs.
- */
- public void writeString(long offset, String string, String charset) {
- byte[] stringBuffer;
- try {
- stringBuffer = string.getBytes(charset);
- } catch (UnsupportedEncodingException e) {
- throw new SdkRuntimeException(e);
- }
-
- write(offset, stringBuffer, 0, stringBuffer.length);
- write1(offset + stringBuffer.length, (byte) 0);
- }
-
- public void writeString(String string) {
- writeString(0, string, Charset.defaultCharset().name());
- }
-
/**
* Copies values in native memory associated with this pointer to a pointer specified by dest
.
*
@@ -536,24 +258,6 @@ public void free() {
this.size = null;
}
- /**
- * Get the native memory address of this pointer.
- *
- * @return Native memory address of this pointer.
- */
- public long addr() {
- return this.addr;
- }
-
- /**
- * Get the size of the allocated native memory pointed to by this instance.
- *
- * @return Size of the memory pointed to by this pointer. May be null if the size is unknown.
- */
- public Long size() {
- return this.size;
- }
-
/**
* Increment the pointer by a given offset. The delta
parameter may be negative.
*
@@ -565,33 +269,4 @@ public Pointer inc(long delta) {
// Size is intentionally left unknown
return Pointer.valueOf(this.addr + delta);
}
-
- /**
- * Compares the address of this pointer with the address of another pointer.
- * Note that size does not play a role in equality of two pointers.
- *
- * @param obj Other pointer to compare this pointer to.
- * If this object is not a pointer, the comparison returns false
.
- * @return True if obj
is a pointer and its address is the same
- * as this instance's address.
- */
- @Override
- public boolean equals(Object obj) {
- boolean result = false;
- if (obj instanceof Pointer) {
- // Size is not considered when evaluating equality
- result = ((Pointer) obj).addr == this.addr;
- }
- return result;
- }
-
- /**
- * Computes a hashcode for this pointer.
- *
- * @return This pointer's hashcode.
- */
- @Override
- public int hashCode() {
- return (new Long(this.addr)).hashCode();
- }
}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelAccessor.java b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelAccessor.java
new file mode 100644
index 0000000..85b80e5
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelAccessor.java
@@ -0,0 +1,17 @@
+package org.ps5jb.sdk.core.kernel;
+
+/**
+ * Interface for accessing Kernel memory. Various exploits able to
+ * do so should implement this interface.
+ */
+public interface KernelAccessor {
+ byte read1(long kernelAddress);
+ short read2(long kernelAddress);
+ int read4(long kernelAddress);
+ long read8(long kernelAddress);
+
+ void write1(long kernelAddress, byte value);
+ void write2(long kernelAddress, short value);
+ void write4(long kernelAddress, int value);
+ void write8(long kernelAddress, long value);
+}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelAccessorIPv6.java b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelAccessorIPv6.java
new file mode 100644
index 0000000..7e72157
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelAccessorIPv6.java
@@ -0,0 +1,262 @@
+package org.ps5jb.sdk.core.kernel;
+
+import org.ps5jb.sdk.core.Pointer;
+import org.ps5jb.sdk.core.SdkException;
+import org.ps5jb.sdk.core.SdkRuntimeException;
+import org.ps5jb.sdk.include.UniStd;
+import org.ps5jb.sdk.include.inet.in.ProtocolType;
+import org.ps5jb.sdk.include.netinet6.in6.OptionIPv6;
+import org.ps5jb.sdk.include.sys.Socket;
+import org.ps5jb.sdk.include.sys.socket.AddressFamilyType;
+import org.ps5jb.sdk.include.sys.socket.SocketType;
+import org.ps5jb.sdk.lib.LibKernel;
+
+/**
+ * Kernel read/write accessor which uses IPv6 sockets.
+ * Implementation inspired from SpecterDev.
+ * Requires an existing kernel accessor on creation.
+ */
+public class KernelAccessorIPv6 implements KernelAccessor {
+ private final Pointer master_target_buffer;
+ private final Pointer slave_buffer;
+ private final Pointer pipemap_buffer;
+ private final Pointer krw_qword_store;
+
+ private final int master_sock;
+ private final int victim_sock;
+
+ private final LibKernel libKernel;
+ private final Socket socket;
+
+ private final int[] pipe_fd;
+ private final KernelPointer pipe_addr;
+
+ /**
+ * Constructor for kernel IPv6 accessor.
+ *
+ * @param ofilesAddress Address of "fdt_ofiles" structure from the "proc" structure of the current process.
+ * @throws SdkException If an error occurs during accessor creation.
+ */
+ public KernelAccessorIPv6(KernelPointer ofilesAddress) throws SdkException {
+ this.libKernel = new LibKernel();
+ this.socket = new Socket(this.libKernel);
+
+ final long sock_opt_size = 0x14;
+ master_target_buffer = Pointer.calloc(sock_opt_size);
+ slave_buffer = Pointer.calloc(sock_opt_size);
+ pipemap_buffer = Pointer.calloc(sock_opt_size);
+ krw_qword_store = Pointer.calloc(0x8);
+
+ master_sock = socket.createSocket(AddressFamilyType.AF_INET6, SocketType.SOCK_DGRAM, ProtocolType.IPPROTO_UDP);
+ victim_sock = socket.createSocket(AddressFamilyType.AF_INET6, SocketType.SOCK_DGRAM, ProtocolType.IPPROTO_UDP);
+ socket.setSocketOptionsIPv6(master_sock, OptionIPv6.IPV6_PKTINFO, master_target_buffer);
+ socket.setSocketOptionsIPv6(victim_sock, OptionIPv6.IPV6_PKTINFO, slave_buffer);
+
+ // Find sockets and get pktopts-based r/w
+ KernelPointer master_sock_filedescent_addr = ofilesAddress.inc(master_sock * 0x30L);
+ KernelPointer victim_sock_filedescent_addr = ofilesAddress.inc(victim_sock * 0x30L);
+
+ KernelPointer master_sock_file_addr = KernelPointer.valueOf(master_sock_filedescent_addr.read8());
+ KernelPointer victim_sock_file_addr = KernelPointer.valueOf(victim_sock_filedescent_addr.read8());
+
+ KernelPointer master_sock_socket_addr = KernelPointer.valueOf(master_sock_file_addr.read8());
+ KernelPointer victim_sock_socket_addr = KernelPointer.valueOf(victim_sock_file_addr.read8());
+
+ KernelPointer master_pcb = KernelPointer.valueOf(master_sock_socket_addr.read8(0x18));
+ KernelPointer slave_pcb = KernelPointer.valueOf(victim_sock_socket_addr.read8(0x18));
+
+ KernelPointer master_pktopts = KernelPointer.valueOf(master_pcb.read8(0x120));
+ KernelPointer slave_pktopts = KernelPointer.valueOf(slave_pcb.read8(0x120));
+
+ master_pktopts.write8(0x10, slave_pktopts.inc(0x10).addr());
+
+ // Create pipe pair
+ final UniStd uniStd = new UniStd(this.libKernel);
+ pipe_fd = uniStd.pipe();
+ int pipe_read = pipe_fd[0];
+ KernelPointer pipe_filedescent = ofilesAddress.inc(pipe_read * 0x30L);
+ KernelPointer pipe_file = KernelPointer.valueOf(ipv6_kread8(pipe_filedescent));
+ pipe_addr = KernelPointer.valueOf(ipv6_kread8(pipe_file));
+
+ // Increase refcounts on socket fds which we corrupt
+ inc_socket_refcount(master_sock, ofilesAddress);
+ inc_socket_refcount(victim_sock, ofilesAddress);
+ }
+
+ public int getMasterSock() {
+ return master_sock;
+ }
+
+ public int getVictimSock() {
+ return victim_sock;
+ }
+
+ /**
+ * Frees resources in use by this accessor. After calling this method
+ * this instance should not be used.
+ */
+ public synchronized void free() {
+ if (master_target_buffer != null) {
+ master_target_buffer.free();
+ }
+ if (slave_buffer != null) {
+ slave_buffer.free();
+ }
+ if (pipemap_buffer != null) {
+ pipemap_buffer.free();
+ }
+ if (krw_qword_store != null) {
+ krw_qword_store.free();
+ }
+ if (pipe_fd[0] != -1) {
+ this.libKernel.close(pipe_fd[0]);
+ }
+ if (pipe_fd[1] != -1) {
+ this.libKernel.close(pipe_fd[1]);
+ }
+
+ libKernel.closeLibrary();
+ }
+
+ private void write_to_victim(KernelPointer kernelAddress) throws SdkException {
+ master_target_buffer.write8(0, kernelAddress.addr());
+ master_target_buffer.write8(0x08, 0);
+ master_target_buffer.write4(0x10, 0);
+ socket.setSocketOptionsIPv6(master_sock, OptionIPv6.IPV6_PKTINFO, master_target_buffer);
+ }
+
+ private void ipv6_kread(KernelPointer kernelAddress, Pointer buffer) throws SdkException {
+ write_to_victim(kernelAddress);
+ socket.getSocketOptionsIPv6(victim_sock, OptionIPv6.IPV6_PKTINFO, buffer);
+ }
+
+ private void ipv6_kwrite(KernelPointer kernelAddress, Pointer buffer) throws SdkException {
+ write_to_victim(kernelAddress);
+ socket.setSocketOptionsIPv6(victim_sock, OptionIPv6.IPV6_PKTINFO, buffer);
+ }
+
+ private long ipv6_kread8(KernelPointer kernelAddress) throws SdkException {
+ ipv6_kread(kernelAddress, slave_buffer);
+ return slave_buffer.read8();
+ }
+
+ private synchronized long copyout(long src, Pointer dest, long length) throws SdkException {
+ final long value0 = 0x4000000040000000L;
+ final long value1 = 0x4000000000000000L;
+
+ pipemap_buffer.write8(value0);
+ pipemap_buffer.write8(0x8, value1);
+ pipemap_buffer.write4(0x10, 0);
+ ipv6_kwrite(pipe_addr, pipemap_buffer);
+
+ pipemap_buffer.write8(src);
+ pipemap_buffer.write8(0x8, 0);
+ pipemap_buffer.write4(0x10, 0);
+ ipv6_kwrite(pipe_addr.inc(0x10), pipemap_buffer);
+
+ return this.libKernel.read(pipe_fd[0], dest, length);
+ }
+
+ private synchronized long copyin(Pointer src, long dest, long length) throws SdkException {
+ final long value = 0x4000000000000000L;
+
+ pipemap_buffer.write8(0);
+ pipemap_buffer.write8(0x8, value);
+ pipemap_buffer.write4(0x10, 0);
+ ipv6_kwrite(pipe_addr, pipemap_buffer);
+
+ pipemap_buffer.write8(dest);
+ pipemap_buffer.write8(0x8, 0);
+ pipemap_buffer.write4(0x10, 0);
+ ipv6_kwrite(pipe_addr.inc(0x10), pipemap_buffer);
+
+ return this.libKernel.write(pipe_fd[1], src, length);
+ }
+
+ private void inc_socket_refcount(int target_fd, KernelPointer ofilesAddress) {
+ KernelPointer filedescent_addr = ofilesAddress.inc(target_fd * 0x30L);
+ KernelPointer file_addr = KernelPointer.valueOf(filedescent_addr.read8(0x00));
+ KernelPointer file_data_addr = KernelPointer.valueOf(file_addr.read8(0x00));
+ file_data_addr.write4(0x100);
+ }
+
+ @Override
+ public byte read1(long kernelAddress) {
+ try {
+ copyout(kernelAddress, krw_qword_store, 0x1);
+ return krw_qword_store.read1();
+ } catch (SdkException e) {
+ throw new SdkRuntimeException(e);
+ }
+ }
+
+ @Override
+ public short read2(long kernelAddress) {
+ try {
+ copyout(kernelAddress, krw_qword_store, 0x2);
+ return krw_qword_store.read2();
+ } catch (SdkException e) {
+ throw new SdkRuntimeException(e);
+ }
+ }
+
+ @Override
+ public int read4(long kernelAddress) {
+ try {
+ copyout(kernelAddress, krw_qword_store, 0x4);
+ return krw_qword_store.read4();
+ } catch (SdkException e) {
+ throw new SdkRuntimeException(e);
+ }
+ }
+
+ @Override
+ public long read8(long kernelAddress) {
+ try {
+ copyout(kernelAddress, krw_qword_store, 0x8);
+ return krw_qword_store.read8();
+ } catch (SdkException e) {
+ throw new SdkRuntimeException(e);
+ }
+ }
+
+ @Override
+ public void write1(long kernelAddress, byte value) {
+ try {
+ krw_qword_store.write1(value);
+ copyin(krw_qword_store, kernelAddress, 0x1);
+ } catch (SdkException e) {
+ throw new SdkRuntimeException(e);
+ }
+ }
+
+ @Override
+ public void write2(long kernelAddress, short value) {
+ try {
+ krw_qword_store.write2(value);
+ copyin(krw_qword_store, kernelAddress, 0x2);
+ } catch (SdkException e) {
+ throw new SdkRuntimeException(e);
+ }
+ }
+
+ @Override
+ public void write4(long kernelAddress, int value) {
+ try {
+ krw_qword_store.write4(value);
+ copyin(krw_qword_store, kernelAddress, 0x4);
+ } catch (SdkException e) {
+ throw new SdkRuntimeException(e);
+ }
+ }
+
+ @Override
+ public void write8(long kernelAddress, long value) {
+ try {
+ krw_qword_store.write8(value);
+ copyin(krw_qword_store, kernelAddress, 0x8);
+ } catch (SdkException e) {
+ throw new SdkRuntimeException(e);
+ }
+ }
+}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelPointer.java b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelPointer.java
new file mode 100644
index 0000000..81763a0
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelPointer.java
@@ -0,0 +1,130 @@
+package org.ps5jb.sdk.core.kernel;
+
+import org.ps5jb.sdk.core.AbstractPointer;
+
+/**
+ * Abstraction over memory pointer operations in kernel-space.
+ * This class is only usable if a global kernel accessor has been installed
+ * by calling {@link KernelReadWrite#setAccessor(KernelAccessor)}.
+ */
+public class KernelPointer extends AbstractPointer {
+ /**
+ * Returns a pointer instance equivalent to the given native memory address.
+ *
+ * @param addr Address to convert to a Pointer instance.
+ * @return Pointer instance representing the given native memory address.
+ */
+ public static KernelPointer valueOf(long addr) {
+ return addr == 0 ? NULL : new KernelPointer(addr);
+ }
+
+ /** Static constant for NULL pointer. */
+ public static final KernelPointer NULL = new KernelPointer(0);
+
+ public KernelPointer(long addr) {
+ super(addr);
+ }
+
+ public KernelPointer(long addr, Long size) {
+ super(addr, size);
+ }
+
+ @Override
+ public byte read1(long offset) {
+ overflow(this, offset, 1);
+ return KernelReadWrite.getAccessor().read1(this.addr + offset);
+ }
+
+ @Override
+ public short read2(long offset) {
+ overflow(this, offset, 2);
+ return KernelReadWrite.getAccessor().read2(this.addr + offset);
+ }
+
+ @Override
+ public int read4(long offset) {
+ overflow(this, offset, 4);
+ return KernelReadWrite.getAccessor().read4(this.addr + offset);
+ }
+
+ @Override
+ public long read8(long offset) {
+ overflow(this, offset, 8);
+ return KernelReadWrite.getAccessor().read8(this.addr + offset);
+ }
+
+ @Override
+ public void read(long offset, byte[] value, int valueOffset, int size) {
+ overflow(this, offset, size);
+
+ // TODO: This can be implemented more efficiently
+ final KernelAccessor accessor = KernelReadWrite.getAccessor();
+ for (int i = 0; i < size; ++i) {
+ value[valueOffset + i] = accessor.read1(this.addr + offset + i);
+ }
+ }
+
+ @Override
+ public void write1(long offset, byte value) {
+ overflow(this, offset, 1);
+ KernelReadWrite.getAccessor().write1(this.addr + offset, value);
+ }
+
+ @Override
+ public void write2(long offset, short value) {
+ overflow(this, offset, 2);
+ KernelReadWrite.getAccessor().write2(this.addr + offset, value);
+ }
+
+ @Override
+ public void write4(long offset, int value) {
+ overflow(this, offset, 4);
+ KernelReadWrite.getAccessor().write4(this.addr + offset, value);
+ }
+
+ @Override
+ public void write8(long offset, long value) {
+ overflow(this, offset, 8);
+ KernelReadWrite.getAccessor().write8(this.addr + offset, value);
+ }
+
+ @Override
+ public void write(long offset, byte[] value, int valueOffset, int count) {
+ overflow(this, offset, count);
+
+ // TODO: This can be implemented more efficiently
+ final KernelAccessor accessor = KernelReadWrite.getAccessor();
+ for (int i = 0; i < count - valueOffset; ++i) {
+ accessor.write1(this.addr + offset + i, value[valueOffset + i]);
+ }
+ }
+
+ /**
+ * Copies values in kernel memory associated with this pointer to a pointer specified by dest
.
+ *
+ * @param dest Pointer to copy the data to. The data will always be copied starting at offset 0 in dest
.
+ * @param offset Offset in this memory to read the data from.
+ * @param size Size of data to copy.
+ * @throws IndexOutOfBoundsException If the read or the write beyond one of the two pointers' sizes occurs.
+ */
+ public void copyTo(KernelPointer dest, long offset, int size) {
+ overflow(this, offset, size);
+ overflow(dest, 0, size);
+
+ byte[] data = new byte[size];
+ read(offset, data, 0, size);
+ dest.write(0, data, 0, size);
+ }
+
+ /**
+ * Increment the pointer by a given offset. The delta
parameter may be negative.
+ *
+ * @param delta Offset from the current address of this pointer.
+ * @return New pointer instance whose size is unknown and whose address is the address of
+ * this pointer shifted by delta
bytes.
+ */
+ public KernelPointer inc(long delta) {
+ // Size is intentionally left unknown
+ return KernelPointer.valueOf(this.addr + delta);
+ }
+}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelReadWrite.java b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelReadWrite.java
new file mode 100644
index 0000000..e9643f2
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelReadWrite.java
@@ -0,0 +1,35 @@
+package org.ps5jb.sdk.core.kernel;
+
+/**
+ * Class managing capability of SDK to read/write the kernel memory.
+ */
+public final class KernelReadWrite {
+ // Note: is "volatile" enough? Probably better to do synchronized methods.
+ private static volatile KernelAccessor kernelAccessor;
+
+ /**
+ * Default constructor
+ */
+ private KernelReadWrite() {
+ }
+
+ /**
+ * Register a global instance of a kernel accessor, responsible for
+ * reading and writing kernel memory.
+ *
+ * @param kernelAccessor New accessor instance.
+ */
+ public static void setAccessor(KernelAccessor kernelAccessor) {
+ KernelReadWrite.kernelAccessor = kernelAccessor;
+ }
+
+ /**
+ * Retrieve a global instance of a kernel accessor. May be null
+ * if none are installed.
+ *
+ * @return Instance of a kernel accessor or null.
+ */
+ public static KernelAccessor getAccessor() {
+ return KernelReadWrite.kernelAccessor;
+ }
+}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/core/kernel/package-info.java b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/package-info.java
new file mode 100644
index 0000000..1f220c7
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * This package contains various classes related to Kernel access.
+ * Normally, any of the classes in this package are only usable if
+ * a global kernel accessor has been installed using
+ * {@link org.ps5jb.sdk.core.kernel.KernelReadWrite#setAccessor(org.ps5jb.sdk.core.kernel.KernelAccessor)}
+ */
+package org.ps5jb.sdk.core.kernel;
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/inet/in/ProtocolType.java b/sdk/src/main/java/org/ps5jb/sdk/include/inet/in/ProtocolType.java
new file mode 100644
index 0000000..959cb40
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/inet/in/ProtocolType.java
@@ -0,0 +1,111 @@
+package org.ps5jb.sdk.include.inet.in;
+
+import org.ps5jb.sdk.res.ErrorMessages;
+
+/**
+ * Protocol types. Note that currently not all constants from FreeBSD are mapped.
+ */
+public final class ProtocolType implements Comparable {
+ /* Protocols common to RFC 1700, POSIX, and X/Open. */
+
+ /** dummy for IP. */
+ public static final ProtocolType IPPROTO_IP = new ProtocolType(0, "IPPROTO_IP");
+ /** control message protocol. */
+ public static final ProtocolType IPPROTO_ICMP = new ProtocolType(1, "IPPROTO_ICMP");
+ /** tcp. */
+ public static final ProtocolType IPPROTO_TCP = new ProtocolType(6, "IPPROTO_TCP");
+ /** user datagram protocol. */
+ public static final ProtocolType IPPROTO_UDP = new ProtocolType(17, "IPPROTO_UDP");
+
+ /** IP6 header. */
+ public static final ProtocolType IPPROTO_IPV6 = new ProtocolType(41, "IPPROTO_IPV6");
+ /** Raw IP packet. */
+ public static final ProtocolType IPPROTO_RAW = new ProtocolType(255, "IPPROTO_RAW");
+
+ /** All possible ProtocolType values. */
+ private static final ProtocolType[] values = new ProtocolType[] {
+ IPPROTO_IP,
+ IPPROTO_ICMP,
+ IPPROTO_TCP,
+ IPPROTO_UDP,
+ IPPROTO_IPV6,
+ IPPROTO_RAW
+ };
+
+ private int value;
+
+ private String name;
+
+ /**
+ * Default constructor. This class should not be instantiated manually,
+ * use provided constants instead.
+ *
+ * @param value Numeric value of this instance.
+ * @param name String representation of the constant.
+ */
+ private ProtocolType(int value, String name) {
+ this.value = value;
+ this.name = name;
+ }
+
+ /**
+ * Get all possible values for ProtocolType.
+ *
+ * @return Array of ProtocolType possible values.
+ */
+ public static ProtocolType[] values() {
+ return values;
+ }
+
+ /**
+ * Convert a numeric value into a ProtocolType constant.
+ *
+ * @param value Number to convert
+ * @return ProtocolType constant corresponding to the given value.
+ * @throws IllegalArgumentException If value does not correspond to any ProtocolType.
+ */
+ public static ProtocolType valueOf(int value) {
+ for (ProtocolType protocolType : values) {
+ if (value == protocolType.value()) {
+ return protocolType;
+ }
+ }
+
+ throw new IllegalArgumentException(ErrorMessages.getClassErrorMessage(ProtocolType.class,"invalidValue", Integer.toString(value)));
+ }
+
+ /**
+ * Numeric value of this instance.
+ *
+ * @return Numeric value of the instance.
+ */
+ public int value() {
+ return this.value;
+ }
+
+ @Override
+ public int compareTo(Object o) {
+ return this.value - ((ProtocolType) o).value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ boolean result;
+ if (o instanceof ProtocolType) {
+ result = value == ((ProtocolType) o).value;
+ } else {
+ result = false;
+ }
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/inet/in/package-info.java b/sdk/src/main/java/org/ps5jb/sdk/include/inet/in/package-info.java
new file mode 100644
index 0000000..1060822
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/inet/in/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains wrappers around FreeBSD headers inside include/inet/in
directory.
+ */
+package org.ps5jb.sdk.include.inet.in;
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/inet/package-info.java b/sdk/src/main/java/org/ps5jb/sdk/include/inet/package-info.java
new file mode 100644
index 0000000..06e7c59
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/inet/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains wrappers around FreeBSD headers inside include/inet
directory.
+ */
+package org.ps5jb.sdk.include.inet;
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/machine/package-info.java b/sdk/src/main/java/org/ps5jb/sdk/include/machine/package-info.java
new file mode 100644
index 0000000..20b69ba
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/machine/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains wrappers around FreeBSD headers inside include/machine
directory.
+ */
+package org.ps5jb.sdk.include.machine;
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/netinet6/in6/OptionIPv6.java b/sdk/src/main/java/org/ps5jb/sdk/include/netinet6/in6/OptionIPv6.java
new file mode 100644
index 0000000..d45a3dc
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/netinet6/in6/OptionIPv6.java
@@ -0,0 +1,97 @@
+package org.ps5jb.sdk.include.netinet6.in6;
+
+import org.ps5jb.sdk.res.ErrorMessages;
+
+/**
+ * Options for use with getsockopt/setsockopt at the IPV6 level.
+ * Note that currently not all constants from FreeBSD are mapped.
+ */
+public final class OptionIPv6 implements Comparable {
+ /** buf/ip6_opts; set/get IP6 options. */
+ public static final OptionIPv6 IPV6_OPTIONS = new OptionIPv6(1, "IPV6_OPTIONS");
+ /** in6_pktinfo; send if, src addr. */
+ public static final OptionIPv6 IPV6_PKTINFO = new OptionIPv6(46, "IPV6_PKTINFO");
+
+ /** All possible OptionsIPv6 values. */
+ private static final OptionIPv6[] values = new OptionIPv6[] {
+ IPV6_OPTIONS,
+ IPV6_PKTINFO
+ };
+
+ private int value;
+
+ private String name;
+
+ /**
+ * Default constructor. This class should not be instantiated manually,
+ * use provided constants instead.
+ *
+ * @param value Numeric value of this instance.
+ * @param name String representation of the constant.
+ */
+ private OptionIPv6(int value, String name) {
+ this.value = value;
+ this.name = name;
+ }
+
+ /**
+ * Get all possible values for OptionIPv6.
+ *
+ * @return Array of OptionIPv6 possible values.
+ */
+ public static OptionIPv6[] values() {
+ return values;
+ }
+
+ /**
+ * Convert a numeric value into a OptionIPv6 constant.
+ *
+ * @param value Number to convert
+ * @return OptionIPv6 constant corresponding to the given value.
+ * @throws IllegalArgumentException If value does not correspond to any OptionIPv6.
+ */
+ public static OptionIPv6 valueOf(int value) {
+ for (OptionIPv6 opt : values) {
+ if (value == opt.value()) {
+ return opt;
+ }
+ }
+
+ throw new IllegalArgumentException(ErrorMessages.getClassErrorMessage(OptionIPv6.class,"invalidValue", Integer.toString(value)));
+ }
+
+ /**
+ * Numeric value of this instance.
+ *
+ * @return Numeric value of the instance.
+ */
+ public int value() {
+ return this.value;
+ }
+
+ @Override
+ public int compareTo(Object o) {
+ return this.value - ((OptionIPv6) o).value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ boolean result;
+ if (o instanceof OptionIPv6) {
+ result = value == ((OptionIPv6) o).value;
+ } else {
+ result = false;
+ }
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/netinet6/in6/package-info.java b/sdk/src/main/java/org/ps5jb/sdk/include/netinet6/in6/package-info.java
new file mode 100644
index 0000000..bd3b0ef
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/netinet6/in6/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains wrappers around FreeBSD headers inside include/netinet6/in6
directory.
+ */
+package org.ps5jb.sdk.include.netinet6.in6;
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/netinet6/package-info.java b/sdk/src/main/java/org/ps5jb/sdk/include/netinet6/package-info.java
new file mode 100644
index 0000000..2471c1c
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/netinet6/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains wrappers around FreeBSD headers inside include/netinet6
directory.
+ */
+package org.ps5jb.sdk.include.netinet6;
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/sys/Socket.java b/sdk/src/main/java/org/ps5jb/sdk/include/sys/Socket.java
new file mode 100644
index 0000000..c1175ac
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/sys/Socket.java
@@ -0,0 +1,60 @@
+package org.ps5jb.sdk.include.sys;
+
+import org.ps5jb.sdk.core.Pointer;
+import org.ps5jb.sdk.core.SdkException;
+import org.ps5jb.sdk.include.inet.in.ProtocolType;
+import org.ps5jb.sdk.include.netinet6.in6.OptionIPv6;
+import org.ps5jb.sdk.include.sys.rtprio.RtPrioType;
+import org.ps5jb.sdk.include.sys.socket.AddressFamilyType;
+import org.ps5jb.sdk.include.sys.socket.SocketType;
+import org.ps5jb.sdk.lib.LibKernel;
+
+/**
+ * This class represents include/sys/socket.h
from FreeBSD source.
+ */
+public class Socket {
+ private final LibKernel libKernel;
+ private final ErrNo errNo;
+
+ /**
+ * Constructor.
+ *
+ * @param libKernel Instance of the 'libkernel' native library wrapper.
+ */
+ public Socket(LibKernel libKernel) {
+ this.libKernel = libKernel;
+ this.errNo = new ErrNo(this.libKernel);
+ }
+
+ public int createSocket(AddressFamilyType domain, SocketType socketType, ProtocolType protocol) throws SdkException {
+ int ret = libKernel.socket(domain.value(), socketType.value(), protocol.value());
+ if (ret == -1) {
+ throw errNo.getLastException(getClass(), "createSocket");
+ }
+ return ret;
+ }
+
+ public void setSocketOptionsIPv6(int socket, OptionIPv6 optionName, Pointer optionValue) throws SdkException {
+ int ret = libKernel.setsockopt(socket, ProtocolType.IPPROTO_IPV6.value(), optionName.value(), optionValue, optionValue.size());
+ if (ret == -1) {
+ throw errNo.getLastException(getClass(), "setRtPrio");
+ }
+ }
+
+ public Pointer getSocketOptionsIPv6(int socket, OptionIPv6 optionName, Pointer optionValue) throws SdkException {
+ Pointer optlen = Pointer.calloc(0x4);
+ try {
+ optlen.write4(optionValue.size().intValue());
+
+ int ret = libKernel.getsockopt(socket, ProtocolType.IPPROTO_IPV6.value(), optionName.value(), optionValue, optlen);
+ if (ret == -1) {
+ throw errNo.getLastException(getClass(), "setRtPrio");
+ }
+
+ int newLen = optlen.read4();
+ return (newLen == optionValue.size().intValue()) ? optionValue : new Pointer(optionValue.addr(), new Long(newLen));
+ } finally {
+ optlen.free();
+ }
+ }
+}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/sys/mman/MappingFlag.java b/sdk/src/main/java/org/ps5jb/sdk/include/sys/mman/MappingFlag.java
index caeebe1..175e7d9 100644
--- a/sdk/src/main/java/org/ps5jb/sdk/include/sys/mman/MappingFlag.java
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/sys/mman/MappingFlag.java
@@ -87,9 +87,9 @@ public static MappingFlag[] values() {
* @throws IllegalArgumentException If value does not correspond to any MappingFlag.
*/
public static MappingFlag valueOf(int value) {
- for (MappingFlag openFlag : values) {
- if (value == openFlag.value()) {
- return openFlag;
+ for (MappingFlag mappingFlag : values) {
+ if (value == mappingFlag.value()) {
+ return mappingFlag;
}
}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/sys/mman/ProtectionFlag.java b/sdk/src/main/java/org/ps5jb/sdk/include/sys/mman/ProtectionFlag.java
index d6616e0..6c5730f 100644
--- a/sdk/src/main/java/org/ps5jb/sdk/include/sys/mman/ProtectionFlag.java
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/sys/mman/ProtectionFlag.java
@@ -56,9 +56,9 @@ public static ProtectionFlag[] values() {
* @throws IllegalArgumentException If value does not correspond to any ProtectionFlag.
*/
public static ProtectionFlag valueOf(int value) {
- for (ProtectionFlag openFlag : values) {
- if (value == openFlag.value()) {
- return openFlag;
+ for (ProtectionFlag protectionFlag : values) {
+ if (value == protectionFlag.value()) {
+ return protectionFlag;
}
}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/sys/pthreadtypes/PThreadType.java b/sdk/src/main/java/org/ps5jb/sdk/include/sys/pthreadtypes/PThreadType.java
index b0a1fac..91a8a8f 100644
--- a/sdk/src/main/java/org/ps5jb/sdk/include/sys/pthreadtypes/PThreadType.java
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/sys/pthreadtypes/PThreadType.java
@@ -9,7 +9,7 @@ public class PThreadType {
private Pointer pthread;
/**
- * DirEnt constructor.
+ * PThreadType constructor.
*
* @param pthread Native address of pthread_t
structure.
*/
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/sys/rtprio/RtPrioType.java b/sdk/src/main/java/org/ps5jb/sdk/include/sys/rtprio/RtPrioType.java
index 2cebdeb..ac04fb3 100644
--- a/sdk/src/main/java/org/ps5jb/sdk/include/sys/rtprio/RtPrioType.java
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/sys/rtprio/RtPrioType.java
@@ -53,7 +53,7 @@ public static RtPrioType[] values() {
*
* @param value Number to convert
* @return RtPrioType constant corresponding to the given value.
- * @throws IllegalArgumentException If value does not correspond to any CpuWhichType.
+ * @throws IllegalArgumentException If value does not correspond to any RtPrioType.
*/
public static RtPrioType valueOf(short value) {
for (RtPrioType rtPrioType : values) {
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/sys/socket/AddressFamilyType.java b/sdk/src/main/java/org/ps5jb/sdk/include/sys/socket/AddressFamilyType.java
new file mode 100644
index 0000000..59da839
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/sys/socket/AddressFamilyType.java
@@ -0,0 +1,105 @@
+package org.ps5jb.sdk.include.sys.socket;
+
+import org.ps5jb.sdk.res.ErrorMessages;
+
+/**
+ * Address families. Note that currently not all constants from FreeBSD are mapped.
+ */
+public final class AddressFamilyType implements Comparable {
+ /** Unspecified. */
+ public static final AddressFamilyType AF_UNSPEC = new AddressFamilyType(0, "AF_UNSPEC");
+ /** Standardized name for {@link #AF_LOCAL}. */
+ public static final AddressFamilyType AF_UNIX = new AddressFamilyType(1, "AF_UNIX");
+ /** Local to host (pipes, portals). */
+ public static final AddressFamilyType AF_LOCAL = new AddressFamilyType(AF_UNIX.value, "AF_LOCAL");
+ /** Internetwork: UDP, TCP, etc. */
+ public static final AddressFamilyType AF_INET = new AddressFamilyType(2, "AF_INET");
+ /** IPv6. */
+ public static final AddressFamilyType AF_INET6 = new AddressFamilyType(28, "AF_INET6");
+
+ /** All possible AddressFamilyType values. */
+ private static final AddressFamilyType[] values = new AddressFamilyType[] {
+ AF_UNSPEC,
+ AF_UNIX,
+ AF_LOCAL,
+ AF_INET,
+ AF_INET6
+ };
+
+ private final int value;
+
+ private final String name;
+
+ /**
+ * Default constructor. This class should not be instantiated manually,
+ * use provided constants instead.
+ *
+ * @param value Numeric value of this instance.
+ * @param name String representation of the constant.
+ */
+ private AddressFamilyType(int value, String name) {
+ this.value = value;
+ this.name = name;
+ }
+
+ /**
+ * Get all possible values for AddressFamilyType.
+ *
+ * @return Array of AddressFamilyType possible values.
+ */
+ public static AddressFamilyType[] values() {
+ return values;
+ }
+
+ /**
+ * Convert a numeric value into a AddressFamilyType constant.
+ *
+ * @param value Number to convert
+ * @return AddressFamilyType constant corresponding to the given value.
+ * @throws IllegalArgumentException If value does not correspond to any AddressFamilyType.
+ */
+ public static AddressFamilyType valueOf(short value) {
+ for (AddressFamilyType rtPrioType : values) {
+ if (value == rtPrioType.value()) {
+ return rtPrioType;
+ }
+ }
+
+ throw new IllegalArgumentException(ErrorMessages.getClassErrorMessage(AddressFamilyType.class,"invalidValue", Integer.toString(value)));
+ }
+
+ /**
+ * Numeric value of this instance.
+ *
+ * @return Numeric value of the instance.
+ */
+ public int value() {
+ return this.value;
+ }
+
+ @Override
+ public int compareTo(Object o) {
+ return this.value - ((AddressFamilyType) o).value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ boolean result;
+ if (o instanceof AddressFamilyType) {
+ result = value == ((AddressFamilyType) o).value;
+ } else {
+ result = false;
+ }
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/sys/socket/SocketType.java b/sdk/src/main/java/org/ps5jb/sdk/include/sys/socket/SocketType.java
new file mode 100644
index 0000000..c5f5859
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/sys/socket/SocketType.java
@@ -0,0 +1,105 @@
+package org.ps5jb.sdk.include.sys.socket;
+
+import org.ps5jb.sdk.res.ErrorMessages;
+
+/**
+ * Socket types
+ */
+public final class SocketType implements Comparable {
+ /** Stream socket. */
+ public static final SocketType SOCK_STREAM = new SocketType(1, "SOCK_STREAM");
+ /** Datagram socket. */
+ public static final SocketType SOCK_DGRAM = new SocketType(2, "SOCK_DGRAM");
+ /** Raw-protocol interface. */
+ public static final SocketType SOCK_RAW = new SocketType(3, "SOCK_RAW");
+ /** Reliably-delivered message. */
+ public static final SocketType SOCK_RDM = new SocketType(4, "SOCK_RDM");
+ /** Sequenced packet stream. */
+ public static final SocketType SOCK_SEQPACKET = new SocketType(5, "SOCK_SEQPACKET");
+
+ /** All possible SocketType values. */
+ private static final SocketType[] values = new SocketType[] {
+ SOCK_STREAM,
+ SOCK_DGRAM,
+ SOCK_RAW,
+ SOCK_RDM,
+ SOCK_SEQPACKET
+ };
+
+ private final int value;
+
+ private final String name;
+
+ /**
+ * Default constructor. This class should not be instantiated manually,
+ * use provided constants instead.
+ *
+ * @param value Numeric value of this instance.
+ * @param name String representation of the constant.
+ */
+ private SocketType(int value, String name) {
+ this.value = value;
+ this.name = name;
+ }
+
+ /**
+ * Get all possible values for SocketType.
+ *
+ * @return Array of SocketType possible values.
+ */
+ public static SocketType[] values() {
+ return values;
+ }
+
+ /**
+ * Convert a numeric value into a SocketType constant.
+ *
+ * @param value Number to convert
+ * @return SocketType constant corresponding to the given value.
+ * @throws IllegalArgumentException If value does not correspond to any SocketType.
+ */
+ public static SocketType valueOf(int value) {
+ for (SocketType socketType : values) {
+ if (value == socketType.value()) {
+ return socketType;
+ }
+ }
+
+ throw new IllegalArgumentException(ErrorMessages.getClassErrorMessage(SocketType.class,"invalidValue", Integer.toString(value)));
+ }
+
+ /**
+ * Numeric value of this instance.
+ *
+ * @return Numeric value of the instance.
+ */
+ public int value() {
+ return this.value;
+ }
+
+ @Override
+ public int compareTo(Object o) {
+ return this.value - ((SocketType) o).value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ boolean result;
+ if (o instanceof SocketType) {
+ result = value == ((SocketType) o).value;
+ } else {
+ result = false;
+ }
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/sys/socket/package-info.java b/sdk/src/main/java/org/ps5jb/sdk/include/sys/socket/package-info.java
new file mode 100644
index 0000000..8e4d038
--- /dev/null
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/sys/socket/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains Java data type wrappers for C types declared in FreeBSD include/sys/socket.h
header.
+ */
+package org.ps5jb.sdk.include.sys.socket;
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/sys/uio/UioReadWrite.java b/sdk/src/main/java/org/ps5jb/sdk/include/sys/uio/UioReadWrite.java
index 741861c..ad60fec 100644
--- a/sdk/src/main/java/org/ps5jb/sdk/include/sys/uio/UioReadWrite.java
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/sys/uio/UioReadWrite.java
@@ -50,9 +50,9 @@ public static UioReadWrite[] values() {
* @throws IllegalArgumentException If value does not correspond to any UioReadWrite.
*/
public static UioReadWrite valueOf(int value) {
- for (UioReadWrite segFlag : values) {
- if (value == segFlag.value()) {
- return segFlag;
+ for (UioReadWrite urw : values) {
+ if (value == urw.value()) {
+ return urw;
}
}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/sys/umtx/UmtxOpcodeType.java b/sdk/src/main/java/org/ps5jb/sdk/include/sys/umtx/UmtxOpcodeType.java
index df003f5..b18030f 100644
--- a/sdk/src/main/java/org/ps5jb/sdk/include/sys/umtx/UmtxOpcodeType.java
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/sys/umtx/UmtxOpcodeType.java
@@ -50,9 +50,9 @@ public static UmtxOpcodeType[] values() {
* @throws IllegalArgumentException If value does not correspond to any UmtxOpcodeType.
*/
public static UmtxOpcodeType valueOf(int value) {
- for (UmtxOpcodeType priorityType : values) {
- if (value == priorityType.value()) {
- return priorityType;
+ for (UmtxOpcodeType opcodeType : values) {
+ if (value == opcodeType.value()) {
+ return opcodeType;
}
}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/include/sys/umtx/UmtxShmFlag.java b/sdk/src/main/java/org/ps5jb/sdk/include/sys/umtx/UmtxShmFlag.java
index d40f365..ad10109 100644
--- a/sdk/src/main/java/org/ps5jb/sdk/include/sys/umtx/UmtxShmFlag.java
+++ b/sdk/src/main/java/org/ps5jb/sdk/include/sys/umtx/UmtxShmFlag.java
@@ -65,9 +65,9 @@ public static UmtxShmFlag[] values() {
* @throws IllegalArgumentException If value does not correspond to any UmtxShmFlag.
*/
public static UmtxShmFlag valueOf(long value) {
- for (UmtxShmFlag openFlag : values) {
- if (value == openFlag.value()) {
- return openFlag;
+ for (UmtxShmFlag shmFlag : values) {
+ if (value == shmFlag.value()) {
+ return shmFlag;
}
}
diff --git a/sdk/src/main/java/org/ps5jb/sdk/lib/LibKernel.java b/sdk/src/main/java/org/ps5jb/sdk/lib/LibKernel.java
index 6618c26..9044087 100644
--- a/sdk/src/main/java/org/ps5jb/sdk/lib/LibKernel.java
+++ b/sdk/src/main/java/org/ps5jb/sdk/lib/LibKernel.java
@@ -54,6 +54,9 @@ public class LibKernel extends Library {
private Pointer sched_yield;
private Pointer sceKernelGetCurrentCpu;
private Pointer sceKernelGetProsperoSystemSwVersion;
+ private Pointer socket;
+ private Pointer setsockopt;
+ private Pointer getsockopt;
/**
* Constructor.
@@ -403,6 +406,30 @@ public long write(int fd, Pointer buf, long nbytes) {
return call(write, fd, buf.addr(), nbytes);
}
+ public int socket(int domain, int type, int protocol) {
+ if (socket == null) {
+ socket = addrOf("socket");
+ }
+
+ return (int) call(socket, domain, type, protocol);
+ }
+
+ public int getsockopt(int s, int level, int optname, Pointer optval, Pointer optlen) {
+ if (getsockopt == null) {
+ getsockopt = addrOf("getsockopt");
+ }
+
+ return (int) call(getsockopt, s, level, optname, optval.addr(), optlen.addr());
+ }
+
+ public int setsockopt(int s, int level, int optname, Pointer optval, long optlen) {
+ if (setsockopt == null) {
+ setsockopt = addrOf("setsockopt");
+ }
+
+ return (int) call(setsockopt, s, level, optname, optval.addr(), optlen);
+ }
+
public int _umtx_op(Pointer obj, int op, long val, Pointer uaddr, Pointer uaddr2) {
if (_umtx_op == null) {
_umtx_op = addrOf("_umtx_op");