jint netty_unix_filedescriptor_JNI_OnLoad(JNIEnv* env, const char* nettyPackagePrefix) {
    void* mem = malloc(1);
    if (mem == NULL) {
        netty_unix_errors_throwOutOfMemoryError(env);
        return JNI_ERR;
    }
    jobject directBuffer = (*env)->NewDirectByteBuffer(env, mem, 1);
    if (directBuffer == NULL) {
        free(mem);

        netty_unix_errors_throwOutOfMemoryError(env);
        return JNI_ERR;
    }
    if ((*env)->GetDirectBufferAddress(env, directBuffer) == NULL) {
        free(mem);

        netty_unix_errors_throwRuntimeException(env, "failed to get direct buffer address");
        return JNI_ERR;
    }

    jclass cls = (*env)->GetObjectClass(env, directBuffer);

    // Get the method id for Buffer.position() and Buffer.limit(). These are used as fallback if
    // it is not possible to obtain the position and limit using the fields directly.
    posId = (*env)->GetMethodID(env, cls, "position", "()I");
    if (posId == NULL) {
        free(mem);

        // position method was not found.. something is wrong so bail out
        netty_unix_errors_throwRuntimeException(env, "failed to get method ID: ByteBuffer.position()");
        return JNI_ERR;
    }

    limitId = (*env)->GetMethodID(env, cls, "limit", "()I");
    if (limitId == NULL) {
        free(mem);

        // limit method was not found.. something is wrong so bail out
        netty_unix_errors_throwRuntimeException(env, "failed to get method ID: ByteBuffer.limit()");
        return JNI_ERR;
    }
    // Try to get the ids of the position and limit fields. We later then check if we was able
    // to find them and if so use them get the position and limit of the buffer. This is
    // much faster then call back into java via (*env)->CallIntMethod(...).
    posFieldId = (*env)->GetFieldID(env, cls, "position", "I");
    if (posFieldId == NULL) {
        // this is ok as we can still use the method so just clear the exception
        (*env)->ExceptionClear(env);
    }
    limitFieldId = (*env)->GetFieldID(env, cls, "limit", "I");
    if (limitFieldId == NULL) {
        // this is ok as we can still use the method so just clear the exception
        (*env)->ExceptionClear(env);
    }

    free(mem);
}
jint netty_kqueue_bsdsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
    // Register the methods which are not referenced by static member variables
    JNINativeMethod* dynamicMethods = createDynamicMethodsTable(packagePrefix);
    if (netty_unix_util_register_natives(env,
            packagePrefix,
            "io/netty/channel/kqueue/BsdSocket",
            dynamicMethods,
            dynamicMethodsTableSize()) != 0) {
        freeDynamicMethodsTable(dynamicMethods);
        return JNI_ERR;
    }
    freeDynamicMethodsTable(dynamicMethods);
    dynamicMethods = NULL;

    // Initialize this module
    char* nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/DefaultFileRegion");
    jclass fileRegionCls = (*env)->FindClass(env, nettyClassName);
    free(nettyClassName);
    nettyClassName = NULL;
    if (fileRegionCls == NULL) {
        return JNI_ERR;
    }
    fileChannelFieldId = (*env)->GetFieldID(env, fileRegionCls, "file", "Ljava/nio/channels/FileChannel;");
    if (fileChannelFieldId == NULL) {
        netty_unix_errors_throwRuntimeException(env, "failed to get field ID: DefaultFileRegion.file");
        return JNI_ERR;
    }
    transferredFieldId = (*env)->GetFieldID(env, fileRegionCls, "transferred", "J");
    if (transferredFieldId == NULL) {
        netty_unix_errors_throwRuntimeException(env, "failed to get field ID: DefaultFileRegion.transferred");
        return JNI_ERR;
    }

    jclass fileChannelCls = (*env)->FindClass(env, "sun/nio/ch/FileChannelImpl");
    if (fileChannelCls == NULL) {
        // pending exception...
        return JNI_ERR;
    }
    fileDescriptorFieldId = (*env)->GetFieldID(env, fileChannelCls, "fd", "Ljava/io/FileDescriptor;");
    if (fileDescriptorFieldId == NULL) {
        netty_unix_errors_throwRuntimeException(env, "failed to get field ID: FileChannelImpl.fd");
        return JNI_ERR;
    }

    jclass fileDescriptorCls = (*env)->FindClass(env, "java/io/FileDescriptor");
    if (fileDescriptorCls == NULL) {
        // pending exception...
        return JNI_ERR;
    }
    fdFieldId = (*env)->GetFieldID(env, fileDescriptorCls, "fd", "I");
    if (fdFieldId == NULL) {
        netty_unix_errors_throwRuntimeException(env, "failed to get field ID: FileDescriptor.fd");
        return JNI_ERR;
    }
    stringCls = (*env)->FindClass(env, "java/lang/String");
    if (stringCls == NULL) {
        // pending exception...
        return JNI_ERR;
    }

    nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/unix/PeerCredentials");
    jclass localPeerCredsClass = (*env)->FindClass(env, nettyClassName);
    free(nettyClassName);
    nettyClassName = NULL;
    if (localPeerCredsClass == NULL) {
        // pending exception...
        return JNI_ERR;
    }
    peerCredentialsClass = (jclass) (*env)->NewGlobalRef(env, localPeerCredsClass);
    if (peerCredentialsClass == NULL) {
        // out-of-memory!
        netty_unix_errors_throwOutOfMemoryError(env);
        return JNI_ERR;
    }
    peerCredentialsMethodId = (*env)->GetMethodID(env, peerCredentialsClass, "<init>", "(II[I)V");
    if (peerCredentialsMethodId == NULL) {
        netty_unix_errors_throwRuntimeException(env, "failed to get method ID: PeerCredentials.<init>(int, int, int[])");
        return JNI_ERR;
    }

    return NETTY_JNI_VERSION;
}