JNIEXPORT jlong JNICALL Java_io_netty_channel_epoll_Native_sendfile0(JNIEnv* env, jclass clazz, jint fd, jobject fileRegion, jlong base_off, jlong off, jlong len) {
    jobject fileChannel = (*env)->GetObjectField(env, fileRegion, fileChannelFieldId);
    if (fileChannel == NULL) {
        netty_unix_errors_throwRuntimeException(env, "failed to get DefaultFileRegion.file");
        return -1;
    }
    jobject fileDescriptor = (*env)->GetObjectField(env, fileChannel, fileDescriptorFieldId);
    if (fileDescriptor == NULL) {
        netty_unix_errors_throwRuntimeException(env, "failed to get FileChannelImpl.fd");
        return -1;
    }
    jint srcFd = (*env)->GetIntField(env, fileDescriptor, fdFieldId);
    if (srcFd == -1) {
        netty_unix_errors_throwRuntimeException(env, "failed to get FileDescriptor.fd");
        return -1;
    }
    ssize_t res;
    off_t offset = base_off + off;
    int err;
    do {
      res = sendfile(fd, srcFd, &offset, (size_t) len);
    } while (res == -1 && ((err = errno) == EINTR));
    if (res < 0) {
        return -err;
    }
    if (res > 0) {
        // update the transfered field in DefaultFileRegion
        (*env)->SetLongField(env, fileRegion, transferedFieldId, off + res);
    }

    return res;
}
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_eventarray_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
    JNINativeMethod* dynamicMethods = createDynamicMethodsTable(packagePrefix);
    if (netty_unix_util_register_natives(env,
            packagePrefix,
            "io/netty/channel/kqueue/KQueueEventArray",
            dynamicMethods,
            dynamicMethodsTableSize()) != 0) {
        freeDynamicMethodsTable(dynamicMethods);
        return JNI_ERR;
    }
    freeDynamicMethodsTable(dynamicMethods);
    dynamicMethods = NULL;

    char* nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/kqueue/AbstractKQueueChannel");
    jclass kqueueChannelCls = (*env)->FindClass(env, nettyClassName);
    free(nettyClassName);
    nettyClassName = NULL;
    if (kqueueChannelCls == NULL) {
        return JNI_ERR;
    }

    kqueueJniPtrFieldId = (*env)->GetFieldID(env, kqueueChannelCls, "jniSelfPtr", "J");
    if (kqueueJniPtrFieldId == NULL) {
        netty_unix_errors_throwRuntimeException(env, "failed to get field ID: AbstractKQueueChannel.jniSelfPtr");
        return JNI_ERR;
    }

    return JNI_VERSION_1_6;
}
Beispiel #4
0
static void netty_epoll_native_eventFdRead(JNIEnv* env, jclass clazz, jint fd) {
    uint64_t eventfd_t;

    if (eventfd_read(fd, &eventfd_t) != 0) {
        // something is serious wrong
        netty_unix_errors_throwRuntimeException(env, "eventfd_read() failed");
    }
}
JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_eventFdRead(JNIEnv* env, jclass clazz, jint fd) {
    uint64_t eventfd_t;

    if (eventfd_read(fd, &eventfd_t) != 0) {
        // something is serious wrong
        netty_unix_errors_throwRuntimeException(env, "eventfd_read() failed");
    }
}
// JNI Registered Methods Begin
static jlong netty_kqueue_bsdsocket_sendFile(JNIEnv* env, jclass clazz, jint socketFd, jobject fileRegion, jlong base_off, jlong off, jlong len) {
    jobject fileChannel = (*env)->GetObjectField(env, fileRegion, fileChannelFieldId);
    if (fileChannel == NULL) {
        netty_unix_errors_throwRuntimeException(env, "failed to get DefaultFileRegion.file");
        return -1;
    }
    jobject fileDescriptor = (*env)->GetObjectField(env, fileChannel, fileDescriptorFieldId);
    if (fileDescriptor == NULL) {
        netty_unix_errors_throwRuntimeException(env, "failed to get FileChannelImpl.fd");
        return -1;
    }
    jint srcFd = (*env)->GetIntField(env, fileDescriptor, fdFieldId);
    if (srcFd == -1) {
        netty_unix_errors_throwRuntimeException(env, "failed to get FileDescriptor.fd");
        return -1;
    }
    const jlong lenBefore = len;
    off_t sbytes;
    int res, err;
    do {
#ifdef __APPLE__
      // sbytes is an input (how many to write) and output (how many were written) parameter.
      sbytes = len;
      res = sendfile(srcFd, socketFd, base_off + off, &sbytes, NULL, 0);
#else
      sbytes = 0;
      res = sendfile(srcFd, socketFd, base_off + off, len, NULL, &sbytes, 0);
#endif
      len -= sbytes;
    } while (res < 0 && ((err = errno) == EINTR));
    sbytes = lenBefore - len;
    if (sbytes > 0) {
        // update the transferred field in DefaultFileRegion
        (*env)->SetLongField(env, fileRegion, transferredFieldId, off + sbytes);
        return sbytes;
    }
    return res < 0 ? -err : 0;
}
Beispiel #7
0
static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
    int limitsOnLoadCalled = 0;
    int errorsOnLoadCalled = 0;
    int filedescriptorOnLoadCalled = 0;
    int socketOnLoadCalled = 0;
    int bufferOnLoadCalled = 0;
    int linuxsocketOnLoadCalled = 0;

    // We must register the statically referenced methods first!
    if (netty_unix_util_register_natives(env,
            packagePrefix,
            "io/netty/channel/epoll/NativeStaticallyReferencedJniMethods",
            statically_referenced_fixed_method_table,
            statically_referenced_fixed_method_table_size) != 0) {
        goto error;
    }
    // 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/epoll/Native",
            dynamicMethods,
            dynamicMethodsTableSize()) != 0) {
        freeDynamicMethodsTable(dynamicMethods);
        goto error;
    }
    freeDynamicMethodsTable(dynamicMethods);
    dynamicMethods = NULL;
    // Load all c modules that we depend upon
    if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
        goto error;
    }
    limitsOnLoadCalled = 1;

    if (netty_unix_errors_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
        goto error;
    }
    errorsOnLoadCalled = 1;

    if (netty_unix_filedescriptor_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
        goto error;
    }
    filedescriptorOnLoadCalled = 1;

    if (netty_unix_socket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
        goto error;
    }
    socketOnLoadCalled = 1;

    if (netty_unix_buffer_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
        goto error;
    }
    bufferOnLoadCalled = 1;

    if (netty_epoll_linuxsocket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
        goto error;
    }
    linuxsocketOnLoadCalled = 1;

    // Initialize this module
    char* nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket");
    jclass nativeDatagramPacketCls = (*env)->FindClass(env, nettyClassName);
    free(nettyClassName);
    nettyClassName = NULL;
    if (nativeDatagramPacketCls == NULL) {
        // pending exception...
        goto error;
    }

    packetAddrFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "addr", "[B");
    if (packetAddrFieldId == NULL) {
        netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.addr");
        goto error;
    }
    packetScopeIdFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "scopeId", "I");
    if (packetScopeIdFieldId == NULL) {
        netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.scopeId");
        goto error;
    }
    packetPortFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "port", "I");
    if (packetPortFieldId == NULL) {
        netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.port");
        goto error;
    }
    packetMemoryAddressFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "memoryAddress", "J");
    if (packetMemoryAddressFieldId == NULL) {
        netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.memoryAddress");
        goto error;
    }

    packetCountFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "count", "I");
    if (packetCountFieldId == NULL) {
        netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.count");
        goto error;
    }

    return NETTY_JNI_VERSION;

error:
   if (limitsOnLoadCalled == 1) {
       netty_unix_limits_JNI_OnUnLoad(env);
   }
   if (errorsOnLoadCalled == 1) {
       netty_unix_errors_JNI_OnUnLoad(env);
   }
   if (filedescriptorOnLoadCalled == 1) {
       netty_unix_filedescriptor_JNI_OnUnLoad(env);
   }
   if (socketOnLoadCalled == 1) {
       netty_unix_socket_JNI_OnUnLoad(env);
   }
   if (bufferOnLoadCalled == 1) {
       netty_unix_buffer_JNI_OnUnLoad(env);
   }
   if (linuxsocketOnLoadCalled == 1) {
       netty_epoll_linuxsocket_JNI_OnUnLoad(env);
   }
   packetAddrFieldId = NULL;
   packetScopeIdFieldId = NULL;
   packetPortFieldId = NULL;
   packetMemoryAddressFieldId = NULL;
   packetCountFieldId = NULL;

   return JNI_ERR;
}
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;
}
static inline jint epollCtl(JNIEnv* env, jint efd, int op, jint fd, jint flags) {
    uint32_t events = flags;
    struct epoll_event ev = {
        .data.fd = fd,
        .events = events
    };

    return epoll_ctl(efd, op, fd, &ev);
}
// util methods end

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env;
    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    } else {
        // Load the prefix to use when looking for Netty classes
        jclass systemCls = (*env)->FindClass(env, "java/lang/System");
        if (systemCls == NULL) {
            return JNI_ERR;
        }
        jmethodID getPropertyMethod = (*env)->GetStaticMethodID(env, systemCls, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;");
        if (getPropertyMethod == NULL) {
            return JNI_ERR;
        }
        jstring propertyName = (*env)->NewStringUTF(env, "io.netty.native.epoll.nettyPackagePrefix");
        nettyPackagePrefixJString = (*env)->CallStaticObjectMethod(env, systemCls, getPropertyMethod, propertyName);
        if (nettyPackagePrefixJString != NULL) {
            nettyPackagePrefix = (*env)->GetStringUTFChars(env, nettyPackagePrefixJString, 0);
        }

        if (netty_unix_errors_JNI_OnLoad(env, nettyPackagePrefix) == JNI_ERR) {
            return JNI_ERR;
        }
        if (netty_unix_filedescriptor_JNI_OnLoad(env, nettyPackagePrefix) == JNI_ERR) {
            return JNI_ERR;
        }
        if (netty_unix_socket_JNI_OnLoad(env, nettyPackagePrefix) == JNI_ERR) {
            return JNI_ERR;
        }

        nettyClassName = netty_unix_util_prepend(nettyPackagePrefix, "io/netty/channel/DefaultFileRegion");
        jclass fileRegionCls = (*env)->FindClass(env, nettyClassName);
        free(nettyClassName);
        nettyClassName = NULL;
        if (fileRegionCls == NULL) {
            // pending exception...
            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;
        }
        transferedFieldId = (*env)->GetFieldID(env, fileRegionCls, "transfered", "J");
        if (transferedFieldId == NULL) {
            netty_unix_errors_throwRuntimeException(env, "failed to get field ID: DefaultFileRegion.transfered");
            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;
        }

        nettyClassName = netty_unix_util_prepend(nettyPackagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket");
        jclass nativeDatagramPacketCls = (*env)->FindClass(env, nettyClassName);
        free(nettyClassName);
        nettyClassName = NULL;
        if (nativeDatagramPacketCls == NULL) {
            // pending exception...
            return JNI_ERR;
        }

        packetAddrFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "addr", "[B");
        if (packetAddrFieldId == NULL) {
            netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.addr");
            return JNI_ERR;
        }
        packetScopeIdFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "scopeId", "I");
        if (packetScopeIdFieldId == NULL) {
            netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.scopeId");
            return JNI_ERR;
        }
        packetPortFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "port", "I");
        if (packetPortFieldId == NULL) {
            netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.port");
            return JNI_ERR;
        }
        packetMemoryAddressFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "memoryAddress", "J");
        if (packetMemoryAddressFieldId == NULL) {
            netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.memoryAddress");
            return JNI_ERR;
        }

        packetCountFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "count", "I");
        if (packetCountFieldId == NULL) {
            netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.count");
            return JNI_ERR;
        }

        if (nettyPackagePrefixJString != NULL) {
            (*env)->ReleaseStringUTFChars(env, nettyPackagePrefixJString, nettyPackagePrefix);
            nettyPackagePrefix = NULL;
            nettyPackagePrefixJString = NULL;
        }

        return JNI_VERSION_1_6;
    }
}