Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Alexander--/f3173d4425d7a3461dcd6b71b356ec0f to your computer and use it in GitHub Desktop.
Save Alexander--/f3173d4425d7a3461dcd6b71b356ec0f to your computer and use it in GitHub Desktop.
mucking with nio channels
JNIEXPORT jint JNICALL Java_io_netty_channel_android_JNI_bind(JNIEnv *env, jclass type, jint a1, jint a2, jint a3, jint a4, jint port, jint fd) {
struct sockaddr* address;
socklen_t size;
if (a1 == 0 && a2 == 0 && a3 == 0xff) {
size = sizeof(struct sockaddr_in);
struct sockaddr_in* ip4 = alloca(size);
*ip4 = (struct sockaddr_in) {
.sin_family = AF_INET,
.sin_port = htons((uint16_t) port),
};
uint32_t* a = (uint32_t*) (&ip4->sin_addr.s_addr);
*a = *(uint32_t*) &a4;
address = (struct sockaddr*)(void*) ip4;
} else {
size = sizeof(struct sockaddr_in6);
struct sockaddr_in6* ip6 = alloca(size);
*ip6 = (struct sockaddr_in6) {
.sin6_family = AF_INET6,
.sin6_port = htons((uint16_t) port),
};
uint32_t* a = (uint32_t*) (&ip6->sin6_addr.s6_addr);
a[0] = *(uint32_t*) &a1;
a[1] = *(uint32_t*) &a2;
a[2] = *(uint32_t*) &a3;
a[3] = *(uint32_t*) &a4;
address = (struct sockaddr*)(void*) ip6;
}
return bind(fd, address, size) == -1 ? -errno : 0;
}
JNIEXPORT jint JNICALL Java_io_netty_channel_android_JNI_connect(JNIEnv *env, jclass type, jint a1, jint a2, jint a3, jint a4, jint port, jint fd) {
struct sockaddr* address;
socklen_t size;
if (a1 == 0 && a2 == 0 && a3 == 0xff) {
size = sizeof(struct sockaddr_in);
struct sockaddr_in* ip4 = alloca(size);
*ip4 = (struct sockaddr_in) {
.sin_family = AF_INET,
.sin_port = htons((uint16_t) port),
};
uint32_t* a = (uint32_t*) (&ip4->sin_addr.s_addr);
a[0] = *(uint32_t*) &a4;
address = (struct sockaddr*)(void*) ip4;
} else {
size = sizeof(struct sockaddr_in6);
struct sockaddr_in6* ip6 = alloca(size);
*ip6 = (struct sockaddr_in6) {
.sin6_family = AF_INET6,
.sin6_port = htons((uint16_t) port),
};
uint32_t* a = (uint32_t*) (&ip6->sin6_addr.s6_addr);
a[0] = *(uint32_t*) &a1;
a[1] = *(uint32_t*) &a2;
a[2] = *(uint32_t*) &a3;
a[3] = *(uint32_t*) &a4;
address = (struct sockaddr*)(void*) ip6;
}
int res = connect(fd, address, size);
if (res != -1) {
return 0;
}
int err = errno;
return err == EINPROGRESS ? 1 : -err;
}
JNIEXPORT jint JNICALL Java_io_netty_channel_android_JNI_dw(JNIEnv *env, jclass type, jobject direct, jint fd, jint position, jint amount) {
char* bytes = (*env)->GetDirectBufferAddress(env, direct);
ssize_t res = write(fd, bytes + position, (size_t) amount);
return (jint) (res == -1 ? -errno : res);
}
JNIEXPORT jint JNICALL Java_io_netty_channel_android_JNI_hw(JNIEnv *env, jclass type, jbyteArray array_, jint fd, jint pos, jint amount) {
jbyte *array = (*env)->GetPrimitiveArrayCritical(env, array_, NULL);
ssize_t res = write(fd, array + pos, (size_t) amount);
(*env)->ReleasePrimitiveArrayCritical(env, array_, array, 0);
return (jint) (res == -1 ? -errno : res);
}
JNIEXPORT jint JNICALL Java_io_netty_channel_android_JNI_dr(JNIEnv *env, jclass type, jobject direct, jint position, jint amount, jint fd) {
char* bytes = (*env)->GetDirectBufferAddress(env, direct);
if (bytes == NULL) {
return ERR_NO_DIRECT;
}
ssize_t res = read(fd, bytes + position, (size_t) amount);
return (jint) (res == -1 ? -errno : res);
}
JNIEXPORT jint JNICALL Java_io_netty_channel_android_JNI_hr(JNIEnv *env, jclass type, jbyteArray array_, jint position, jint amount, jint fd) {
jbyte *array = (*env)->GetPrimitiveArrayCritical(env, array_, NULL);
ssize_t res = read(fd, array + position, (size_t) amount);
(*env)->ReleasePrimitiveArrayCritical(env, array_, array, 0);
return (jint) (res == -1 ? -errno : res);
}
JNIEXPORT jint JNICALL Java_io_netty_channel_android_JNI_ds(JNIEnv *env, jclass type,
jobject b1, jobject b2, jobject b3, jobject b4, jobject b5,
jint buffers,
jint o1, jint o2, jint o3, jint o4, jint o5,
jint c1, jint c2, jint c3, jint c4, jint c5,
jint fd) {
struct iovec* iov = alloca(sizeof(struct iovec) * buffers);
const jobject targets[] = { b1, b2, b3, b4, b5 };
const jint offsets[] = { o1, o2, o3, o4, o5 };
const jint counts[] = { c1, c2, c3, c4, c5 };
for (int i = 0; i < buffers; ++i) {
char* base = (*env)->GetDirectBufferAddress(env, targets[i]);
if (base == NULL) {
return ERR_NO_DIRECT;
}
iov[i].iov_base = base + offsets[i];
iov[i].iov_len = (__kernel_size_t) counts[i];
}
ssize_t res = (jint) writev(fd, iov, buffers);
return (jint) (res == -1 ? -errno : res);
}
JNIEXPORT jint JNICALL Java_io_netty_channel_android_JNI_hs(JNIEnv *env, jclass type,
jbyteArray b1_, jbyteArray b2_, jbyteArray b3_, jbyteArray b4_, jbyteArray b5_,
jint buffers,
jint o1, jint o2, jint o3, jint o4, jint o5,
jint c1, jint c2, jint c3, jint c4, jint c5,
jint fd) {
struct iovec* iov = alloca(sizeof(struct iovec) * buffers);
const jobject targets[] = { b1_, b2_, b3_, b4_, b5_ };
const jint offsets[] = { o1, o2, o3, o4, o5 };
const jint counts[] = { c1, c2, c3, c4, c5 };
for (int i = 0; i < buffers; ++i) {
char* ptr = (*env)->GetPrimitiveArrayCritical(env, targets[i], NULL);
iov[i].iov_base = ptr + offsets[i];
iov[i].iov_len = (__kernel_size_t) counts[i];
}
ssize_t res = writev(fd, iov, buffers);
for (int i = 0; i < buffers; ++i) {
(*env)->ReleasePrimitiveArrayCritical(env, targets[i], iov[i].iov_base, 0);
}
return (jint) (res == -1 ? -errno : res);
}
JNIEXPORT jint JNICALL Java_io_netty_channel_android_JNI_dg(JNIEnv *env, jclass type,
jobject b1, jobject b2, jobject b3, jobject b4, jobject b5,
jint buffers,
jint o1, jint o2, jint o3, jint o4, jint o5,
jint c1, jint c2, jint c3, jint c4, jint c5,
jint fd) {
struct iovec* iov = alloca(sizeof(struct iovec) * buffers);
const jobject targets[] = { b1, b2, b3, b4, b5 };
const jint offsets[] = { o1, o2, o3, o4, o5 };
const jint counts[] = { c1, c2, c3, c4, c5 };
for (int i = 0; i < buffers; ++i) {
char* base = (*env)->GetDirectBufferAddress(env, targets[i]);
if (base == NULL) {
return ERR_NO_DIRECT;
}
iov[i].iov_base = base + offsets[i];
iov[i].iov_len = (__kernel_size_t) counts[i];
}
ssize_t res = (jint) readv(fd, iov, buffers);
return (jint) (res == -1 ? -errno : res);
}
JNIEXPORT jint JNICALL Java_io_netty_channel_android_JNI_hg(JNIEnv *env, jclass type,
jbyteArray b1_, jbyteArray b2_, jbyteArray b3_, jbyteArray b4_, jbyteArray b5_,
jint buffers,
jint o1, jint o2, jint o3, jint o4, jint o5,
jint c1, jint c2, jint c3, jint c4, jint c5,
jint fd) {
struct iovec* iov = alloca(sizeof(struct iovec) * buffers);
const jobject targets[] = { b1_, b2_, b3_, b4_, b5_ };
const jint offsets[] = { o1, o2, o3, o4, o5 };
const jint counts[] = { c1, c2, c3, c4, c5 };
for (int i = 0; i < buffers; ++i) {
char* ptr = (*env)->GetPrimitiveArrayCritical(env, targets[i], NULL);
iov[i].iov_base = ptr + offsets[i];
iov[i].iov_len = (__kernel_size_t) counts[i];
}
ssize_t res = readv(fd, iov, buffers);
for (int i = 0; i < buffers; ++i) {
(*env)->ReleasePrimitiveArrayCritical(env, targets[i], iov[i].iov_base, 0);
}
return (jint) (res == -1 ? -errno : res);
}
package io.netty.channel.android;
import android.support.annotation.NonNull;
import java.nio.ByteBuffer;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
final class FdNioChannel implements ScatteringByteChannel, GatheringByteChannel {
private final int fd;
FdNioChannel(int fd) {
this.fd = fd;
}
private int heapScatter(@NonNull ByteBuffer[] srcs, int offset, int length) throws java.io.IOException {
byte[] a1, a2, a3 = null, a4 = null, a5 = null;
int o1, o2, o3 = 0, o4 = 0, o5 = 0;
int c1, c2, c3 = 0, c4 = 0, c5 = 0;
switch (length) {
default:
length = 5;
ByteBuffer b5 = srcs[offset + 4];
a5 = b5.array();
o5 = b5.position() + b5.arrayOffset();
c5 = b5.remaining();
case 4:
ByteBuffer b4 = srcs[offset + 3];
a4 = b4.array();
o4 = b4.position() + b4.arrayOffset();
c4 = b4.remaining();
case 3:
ByteBuffer b3 = srcs[offset + 2];
a3 = b3.array();
o3 = b3.position() + b3.arrayOffset();
c3 = b3.remaining();
case 2:
ByteBuffer b2 = srcs[offset + 1];
a2 = b2.array();
o2 = b2.position() + b2.arrayOffset();
c2 = b2.remaining();
ByteBuffer b1 = srcs[offset];
a1 = b1.array();
o1 = b1.position() + b1.arrayOffset();
c1 = b1.remaining();
}
return JNI.hs(a1, a2, a3, a4, a5, length, o1, o2, o3, o4, o5, c1, c2, c3, c4, c5, fd);
}
private int directScatter(@NonNull ByteBuffer[] srcs, int offset, int length) throws java.io.IOException {
ByteBuffer b1, b2, b3 = null, b4 = null, b5 = null;
int o1, o2, o3 = 0, o4 = 0, o5 = 0;
int c1, c2, c3 = 0, c4 = 0, c5 = 0;
switch (length) {
default:
length = 5;
b5 = srcs[offset + 4];
o5 = b5.position();
c5 = b5.remaining();
case 4:
b4 = srcs[offset + 3];
o4 = b4.position();
c4 = b4.remaining();
case 3:
b3 = srcs[offset + 2];
o3 = b3.position();
c3 = b3.remaining();
case 2:
b2 = srcs[offset + 1];
o2 = b2.position();
c2 = b2.remaining();
b1 = srcs[offset];
o1 = b1.position();
c1 = b1.remaining();
}
return JNI.ds(b1, b2, b3, b4, b5, length, o1, o2, o3, o4, o5, c1, c2, c3, c4, c5, fd);
}
private int heapGather(@NonNull ByteBuffer[] srcs, int offset, int length) throws java.io.IOException {
byte[] a1, a2, a3 = null, a4 = null, a5 = null;
int o1, o2, o3 = 0, o4 = 0, o5 = 0;
int c1, c2, c3 = 0, c4 = 0, c5 = 0;
switch (length) {
default:
length = 5;
ByteBuffer b5 = srcs[offset + 4];
a5 = b5.array();
o5 = b5.position() + b5.arrayOffset();
c5 = b5.remaining();
case 4:
ByteBuffer b4 = srcs[offset + 3];
a4 = b4.array();
o4 = b4.position() + b4.arrayOffset();
c4 = b4.remaining();
case 3:
ByteBuffer b3 = srcs[offset + 2];
a3 = b3.array();
o3 = b3.position() + b3.arrayOffset();
c3 = b3.remaining();
case 2:
ByteBuffer b2 = srcs[offset + 1];
a2 = b2.array();
o2 = b2.position() + b2.arrayOffset();
c2 = b2.remaining();
ByteBuffer b1 = srcs[offset];
a1 = b1.array();
o1 = b1.position() + b1.arrayOffset();
c1 = b1.remaining();
}
return JNI.hg(a1, a2, a3, a4, a5, length, o1, o2, o3, o4, o5, c1, c2, c3, c4, c5, fd);
}
private int directGather(@NonNull ByteBuffer[] srcs, int offset, int length) throws java.io.IOException {
ByteBuffer b1, b2, b3 = null, b4 = null, b5 = null;
int o1, o2, o3 = 0, o4 = 0, o5 = 0;
int c1, c2, c3 = 0, c4 = 0, c5 = 0;
switch (length) {
default:
length = 5;
b5 = srcs[offset + 4];
o5 = b5.position();
c5 = b5.remaining();
case 4:
b4 = srcs[offset + 3];
o4 = b4.position();
c4 = b4.remaining();
case 3:
b3 = srcs[offset + 2];
o3 = b3.position();
c3 = b3.remaining();
case 2:
b2 = srcs[offset + 1];
o2 = b2.position();
c2 = b2.remaining();
b1 = srcs[offset];
o1 = b1.position();
c1 = b1.remaining();
}
return JNI.dg(b1, b2, b3, b4, b5, length, o1, o2, o3, o4, o5, c1, c2, c3, c4, c5, fd);
}
@Override
public long write(@NonNull ByteBuffer[] srcs, int offset, int length) throws java.io.IOException {
switch (length) {
default:
int total = srcs[offset].isDirect()
? directScatter(srcs, offset, length)
: heapScatter(srcs, offset, length);
Utils.checkErrno(total);
int written = total;
for (int i = offset; i < offset + length; ++i) {
ByteBuffer b = srcs[i];
int remaining = b.remaining();
if (remaining >= written) {
b.position(b.position() + written);
break;
} else {
b.position(b.limit());
written -= remaining;
}
}
return total;
case 1:
return write(srcs[offset]);
case 0:
return 0;
}
}
@Override
public long read(@NonNull ByteBuffer[] dsts, int offset, int length) throws java.io.IOException {
switch (length) {
default:
int total = dsts[offset].isDirect()
? directGather(dsts, offset, length)
: heapGather(dsts, offset, length);
Utils.checkErrno(total);
int read = total;
for (int i = offset; i < offset + length; ++i) {
ByteBuffer b = dsts[i];
int remaining = b.remaining();
if (remaining >= read) {
b.position(b.position() + read);
break;
} else {
b.position(b.limit());
read -= remaining;
}
}
return total;
case 1:
return read(dsts[offset]);
case 0:
return 0;
}
}
@Override
public long write(@NonNull ByteBuffer[] srcs) throws java.io.IOException {
return write(srcs, 0, srcs.length);
}
@Override
public long read(@NonNull ByteBuffer[] dsts) throws java.io.IOException {
return write(dsts, 0, dsts.length);
}
@Override
public int write(@NonNull ByteBuffer src) throws java.io.IOException {
int written = src.isDirect() ? writeDirect(src) : writeHeap(src);
Utils.checkErrno(written);
src.position(src.position() + written);
return written;
}
@Override
public int read(ByteBuffer dst) throws java.io.IOException {
int read = dst.isDirect() ? readDirect(dst) : readHeap(dst);
Utils.checkErrno(read);
dst.position(dst.position() + read);
return read;
}
private int writeDirect(ByteBuffer direct) throws IOException {
return JNI.dw(direct, direct.position(), direct.remaining(), fd);
}
private int writeHeap(ByteBuffer heap) throws IOException {
return JNI.hw(heap.array(), heap.position() + heap.arrayOffset(), heap.remaining(), fd);
}
private int readDirect(ByteBuffer direct) throws IOException {
return JNI.dr(direct, direct.position(), direct.remaining(), fd);
}
private int readHeap(ByteBuffer heap) throws IOException {
return JNI.hr(heap.array(), heap.position() + heap.arrayOffset(), heap.remaining(), fd);
}
@Override
public boolean isOpen() {
return true;
}
@Override
public void close() {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment