All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tis.ratis-thirdparty-misc.1.0.4.source-code.netty_kqueue_native.c Maven / Gradle / Ivy

There is a newer version: 1.0.6
Show newest version
/*
 * Copyright 2016 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "netty_kqueue_bsdsocket.h"
#include "netty_kqueue_eventarray.h"
#include "netty_unix_buffer.h"
#include "netty_unix_errors.h"
#include "netty_unix_filedescriptor.h"
#include "netty_unix_jni.h"
#include "netty_unix_limits.h"
#include "netty_unix_socket.h"
#include "netty_unix_util.h"
#include "netty_unix.h"

// Add define if NETTY_BUILD_STATIC is defined so it is picked up in netty_jni_util.c
#ifdef NETTY_BUILD_STATIC
#define NETTY_JNI_UTIL_BUILD_STATIC
#endif

#define STATICALLY_CLASSNAME "io/netty/channel/kqueue/KQueueStaticallyReferencedJniMethods"
#define NATIVE_CLASSNAME "io/netty/channel/kqueue/Native"

// Currently only macOS supports EVFILT_SOCK, and it is currently only available in internal APIs.
// To make compiling easier we redefine the values here if they are not present.
#ifdef __APPLE__
#ifndef EVFILT_SOCK
#define EVFILT_SOCK -13
#endif /* EVFILT_SOCK */
#ifndef NOTE_CONNRESET
#define NOTE_CONNRESET 0x00000001
#endif /* NOTE_CONNRESET */
#ifndef NOTE_READCLOSED
#define NOTE_READCLOSED 0x00000002
#endif /* NOTE_READCLOSED */
#ifndef NOTE_DISCONNECTED
#define NOTE_DISCONNECTED 0x00001000
#endif /* NOTE_DISCONNECTED */
#ifndef CONNECT_RESUME_ON_READ_WRITE
#define CONNECT_RESUME_ON_READ_WRITE 0x1
#endif /* CONNECT_RESUME_ON_READ_WRITE */
#ifndef CONNECT_DATA_IDEMPOTENT
#define CONNECT_DATA_IDEMPOTENT 0x2
#endif /* CONNECT_DATA_IDEMPOTENT */
#else
#ifndef EVFILT_SOCK
#define EVFILT_SOCK 0 // Disabled
#endif /* EVFILT_SOCK */
#ifndef NOTE_CONNRESET
#define NOTE_CONNRESET 0
#endif /* NOTE_CONNRESET */
#ifndef NOTE_READCLOSED
#define NOTE_READCLOSED 0
#endif /* NOTE_READCLOSED */
#ifndef NOTE_DISCONNECTED
#define NOTE_DISCONNECTED 0
#endif /* NOTE_DISCONNECTED */
#ifndef CONNECT_RESUME_ON_READ_WRITE
#define CONNECT_RESUME_ON_READ_WRITE 0
#endif /* CONNECT_RESUME_ON_READ_WRITE */
#ifndef CONNECT_DATA_IDEMPOTENT
#define CONNECT_DATA_IDEMPOTENT 0
#endif /* CONNECT_DATA_IDEMPOTENT */
#endif /* __APPLE__ */

static clockid_t waitClockId = 0; // initialized by netty_unix_util_initialize_wait_clock
static const char* staticPackagePrefix = NULL;
static int register_unix_called = 0;

static jint netty_kqueue_native_kqueueCreate(JNIEnv* env, jclass clazz) {
    jint kq = kqueue();
    if (kq < 0) {
      netty_unix_errors_throwChannelExceptionErrorNo(env, "kqueue() failed: ", errno);
    }
    return kq;
}

static jint netty_kqueue_native_keventChangeSingleUserEvent(jint kqueueFd, struct kevent* userEvent) {
    int result, err;
    result = kevent(kqueueFd, userEvent, 1, NULL, 0, NULL);
    if (result < 0) {
        // https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
        // When kevent() call fails with EINTR error, all changes in the changelist have been applied.
        return (err = errno) == EINTR ? 0 : -err;
    }

    return result;
}

static jint netty_kqueue_native_keventTriggerUserEvent(JNIEnv* env, jclass clazz, jint kqueueFd, jint ident) {
    struct kevent userEvent;
    EV_SET(&userEvent, ident, EVFILT_USER, 0, NOTE_TRIGGER | NOTE_FFNOP, 0, NULL);
    return netty_kqueue_native_keventChangeSingleUserEvent(kqueueFd, &userEvent);
}

static jint netty_kqueue_native_keventAddUserEvent(JNIEnv* env, jclass clazz, jint kqueueFd, jint ident) {
    struct kevent userEvent;
    EV_SET(&userEvent, ident, EVFILT_USER, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_FFNOP, 0, NULL);
    return netty_kqueue_native_keventChangeSingleUserEvent(kqueueFd, &userEvent);
}

static jint netty_kqueue_native_keventWait(JNIEnv* env, jclass clazz, jint kqueueFd, jlong changeListAddress, jint changeListLength,
                                           jlong eventListAddress, jint eventListLength, jint tvSec, jint tvNsec) {
    struct kevent* changeList = (struct kevent*) changeListAddress;
    struct kevent* eventList = (struct kevent*) eventListAddress;
    struct timespec beforeTs, nowTs, timeoutTs;
    int result, err;

    timeoutTs.tv_sec = tvSec;
    timeoutTs.tv_nsec = tvNsec;

    if (tvSec == 0 && tvNsec == 0) {
        // Zeros = poll (aka return immediately).
        for (;;) {
            result = kevent(kqueueFd, changeList, changeListLength, eventList, eventListLength, &timeoutTs);
            if (result >= 0) {
                return result;
            }
            if ((err = errno) != EINTR) {
                return -err;
            }

            // https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
            // When kevent() call fails with EINTR error, all changes in the changelist have been applied.
            changeListLength = 0;
        }
    }

    // Wait with a timeout value.
    netty_unix_util_clock_gettime(waitClockId, &beforeTs);
    for (;;) {
        result = kevent(kqueueFd, changeList, changeListLength, eventList, eventListLength, &timeoutTs);
        if (result >= 0) {
            return result;
        }
        if ((err = errno) != EINTR) {
            return -err;
        }

        netty_unix_util_clock_gettime(waitClockId, &nowTs);
        if (netty_unix_util_timespec_subtract_ns(&timeoutTs,
              netty_unix_util_timespec_elapsed_ns(&beforeTs, &nowTs))) {
            return 0;
        }

        beforeTs = nowTs;
        // https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
        // When kevent() call fails with EINTR error, all changes in the changelist have been applied.
        changeListLength = 0;
    }
}

static jint netty_kqueue_native_registerUnix(JNIEnv* env, jclass clazz) {
    register_unix_called = 1;
    return netty_unix_register(env, staticPackagePrefix);
}

static jint netty_kqueue_native_sizeofKEvent(JNIEnv* env, jclass clazz) {
    return sizeof(struct kevent);
}

static jint netty_kqueue_native_offsetofKEventIdent(JNIEnv* env, jclass clazz) {
    return offsetof(struct kevent, ident);
}

static jint netty_kqueue_native_offsetofKEventFlags(JNIEnv* env, jclass clazz) {
    return offsetof(struct kevent, flags);
}

static jint netty_kqueue_native_offsetofKEventFilter(JNIEnv* env, jclass clazz) {
    return offsetof(struct kevent, filter);
}

static jint netty_kqueue_native_offsetofKEventFFlags(JNIEnv* env, jclass clazz) {
    return offsetof(struct kevent, fflags);
}

static jint netty_kqueue_native_offsetofKeventData(JNIEnv* env, jclass clazz) {
    return offsetof(struct kevent, data);
}

static jshort netty_kqueue_native_evfiltRead(JNIEnv* env, jclass clazz) {
    return EVFILT_READ;
}

static jshort netty_kqueue_native_evfiltWrite(JNIEnv* env, jclass clazz) {
    return EVFILT_WRITE;
}

static jshort netty_kqueue_native_evfiltUser(JNIEnv* env, jclass clazz) {
    return EVFILT_USER;
}

static jshort netty_kqueue_native_evfiltSock(JNIEnv* env, jclass clazz) {
    return EVFILT_SOCK;
}

static jshort netty_kqueue_native_evAdd(JNIEnv* env, jclass clazz) {
   return EV_ADD;
}

static jshort netty_kqueue_native_evEnable(JNIEnv* env, jclass clazz) {
   return EV_ENABLE;
}

static jshort netty_kqueue_native_evDisable(JNIEnv* env, jclass clazz) {
   return EV_DISABLE;
}

static jshort netty_kqueue_native_evDelete(JNIEnv* env, jclass clazz) {
   return EV_DELETE;
}

static jshort netty_kqueue_native_evClear(JNIEnv* env, jclass clazz) {
   return EV_CLEAR;
}

static jshort netty_kqueue_native_evEOF(JNIEnv* env, jclass clazz) {
   return EV_EOF;
}

static jshort netty_kqueue_native_evError(JNIEnv* env, jclass clazz) {
   return EV_ERROR;
}

static jshort netty_kqueue_native_noteConnReset(JNIEnv* env, jclass clazz) {
   return NOTE_CONNRESET;
}

static jshort netty_kqueue_native_noteReadClosed(JNIEnv* env, jclass clazz) {
   return NOTE_READCLOSED;
}

static jshort netty_kqueue_native_noteDisconnected(JNIEnv* env, jclass clazz) {
   return NOTE_DISCONNECTED;
}

static jint netty_kqueue_bsdsocket_connectResumeOnReadWrite(JNIEnv *env, jclass clazz) {
    return CONNECT_RESUME_ON_READ_WRITE;
}

static jint netty_kqueue_bsdsocket_connectDataIdempotent(JNIEnv *env, jclass clazz) {
    return CONNECT_DATA_IDEMPOTENT;
}

static jint netty_kqueue_bsdsocket_fastOpenClient(JNIEnv *env, jclass clazz) {
#ifdef __APPLE__
    unsigned int value = 0;
    size_t len = sizeof(value);
    if (sysctlbyname("net.inet.tcp.fastopen", &value, &len, NULL, 0) != 0) {
        int err = errno;
        netty_unix_errors_throwRuntimeExceptionErrorNo(env, "sysctlbyname failed", err);
        return -err;
    }
    if ((value & 2) == 2) {
        return 1;
    }
    return 0;
#else
    unsigned int value = 0;
    size_t len = sizeof(value);
    if (sysctlbyname("net.inet.tcp.fastopen.client_enable", &value, &len, NULL, 0) != 0) {
        int err = errno;
        netty_unix_errors_throwRuntimeExceptionErrorNo(env, "sysctlbyname failed", err);
        return -err;
    }
    if (value) {
        return 1;
    }
    return 0;
#endif // __APPLE__
}

static jint netty_kqueue_bsdsocket_fastOpenServer(JNIEnv *env, jclass clazz) {
#ifdef __APPLE__
    unsigned int value = 0;
    size_t len = sizeof(value);
    if (sysctlbyname("net.inet.tcp.fastopen", &value, &len, NULL, 0) != 0) {
        int err = errno;
        netty_unix_errors_throwRuntimeExceptionErrorNo(env, "sysctlbyname failed", err);
        return -err;
    }
    if ((value & 1) == 1) {
        return 1;
    }
    return 0;
#else
    unsigned int value = 0;
    size_t len = sizeof(value);
    if (sysctlbyname("net.inet.tcp.fastopen.server_enable", &value, &len, NULL, 0) != 0) {
        int err = errno;
        netty_unix_errors_throwRuntimeExceptionErrorNo(env, "sysctlbyname failed", err);
        return -err;
    }
    if (value) {
        return 1;
    }
    return 0;
#endif // __APPLE__
}

// JNI Method Registration Table Begin
static const JNINativeMethod statically_referenced_fixed_method_table[] = {
  { "evfiltRead", "()S", (void *) netty_kqueue_native_evfiltRead },
  { "evfiltWrite", "()S", (void *) netty_kqueue_native_evfiltWrite },
  { "evfiltUser", "()S", (void *) netty_kqueue_native_evfiltUser },
  { "evfiltSock", "()S", (void *) netty_kqueue_native_evfiltSock },
  { "evAdd", "()S", (void *) netty_kqueue_native_evAdd },
  { "evEnable", "()S", (void *) netty_kqueue_native_evEnable },
  { "evDisable", "()S", (void *) netty_kqueue_native_evDisable },
  { "evDelete", "()S", (void *) netty_kqueue_native_evDelete },
  { "evClear", "()S", (void *) netty_kqueue_native_evClear },
  { "evEOF", "()S", (void *) netty_kqueue_native_evEOF },
  { "evError", "()S", (void *) netty_kqueue_native_evError },
  { "noteReadClosed", "()S", (void *) netty_kqueue_native_noteReadClosed },
  { "noteConnReset", "()S", (void *) netty_kqueue_native_noteConnReset },
  { "noteDisconnected", "()S", (void *) netty_kqueue_native_noteDisconnected },
  { "connectResumeOnReadWrite", "()I", (void *) netty_kqueue_bsdsocket_connectResumeOnReadWrite },
  { "connectDataIdempotent", "()I", (void *) netty_kqueue_bsdsocket_connectDataIdempotent },
  { "fastOpenClient", "()I", (void *) netty_kqueue_bsdsocket_fastOpenClient },
  { "fastOpenServer", "()I", (void *) netty_kqueue_bsdsocket_fastOpenServer }
};
static const jint statically_referenced_fixed_method_table_size = sizeof(statically_referenced_fixed_method_table) / sizeof(statically_referenced_fixed_method_table[0]);
static const JNINativeMethod fixed_method_table[] = {
  { "kqueueCreate", "()I", (void *) netty_kqueue_native_kqueueCreate },
  { "keventTriggerUserEvent", "(II)I", (void *) netty_kqueue_native_keventTriggerUserEvent },
  { "keventAddUserEvent", "(II)I", (void *) netty_kqueue_native_keventAddUserEvent },
  { "keventWait", "(IJIJIII)I", (void *) netty_kqueue_native_keventWait },
  { "sizeofKEvent", "()I", (void *) netty_kqueue_native_sizeofKEvent },
  { "offsetofKEventIdent", "()I", (void *) netty_kqueue_native_offsetofKEventIdent },
  { "offsetofKEventFlags", "()I", (void *) netty_kqueue_native_offsetofKEventFlags },
  { "offsetofKEventFFlags", "()I", (void *) netty_kqueue_native_offsetofKEventFFlags },
  { "offsetofKEventFilter", "()I", (void *) netty_kqueue_native_offsetofKEventFilter },
  { "offsetofKeventData", "()I", (void *) netty_kqueue_native_offsetofKeventData },
  { "registerUnix", "()I", (void *) netty_kqueue_native_registerUnix }
};
static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(fixed_method_table[0]);
// JNI Method Registration Table End

// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
//            Native to reflect that.
static jint netty_kqueue_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
    int staticallyRegistered = 0;
    int nativeRegistered = 0;
    int bsdsocketOnLoadCalled = 0;
    int eventarrayOnLoadCalled = 0;

    // We must register the statically referenced methods first!
    if (netty_jni_util_register_natives(env,
            packagePrefix,
            STATICALLY_CLASSNAME,
            statically_referenced_fixed_method_table,
            statically_referenced_fixed_method_table_size) != 0) {
        goto error;
    }
    staticallyRegistered = 1;

    // Register the methods which are not referenced by static member variables
    if (netty_jni_util_register_natives(env, packagePrefix, NATIVE_CLASSNAME, fixed_method_table, fixed_method_table_size) != 0) {
        goto error;
    }
    nativeRegistered = 1;

    if (netty_kqueue_bsdsocket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
        goto error;
    }
    bsdsocketOnLoadCalled = 1;

    if (netty_kqueue_eventarray_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
        goto error;
    }
    eventarrayOnLoadCalled = 1;

    // Initialize this module

    if (!netty_unix_util_initialize_wait_clock(&waitClockId)) {
        fprintf(stderr, "FATAL: could not find a clock for clock_gettime!\n");
        fflush(stderr);
        goto error;
    }

    staticPackagePrefix = packagePrefix;
    return NETTY_JNI_UTIL_JNI_VERSION;
error:
   if (staticallyRegistered == 1) {
        netty_jni_util_unregister_natives(env, packagePrefix, STATICALLY_CLASSNAME);
   }
   if (nativeRegistered == 1) {
        netty_jni_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME);
   }
   if (bsdsocketOnLoadCalled == 1) {
       netty_kqueue_bsdsocket_JNI_OnUnLoad(env, packagePrefix);
   }
   if (eventarrayOnLoadCalled == 1) {
       netty_kqueue_eventarray_JNI_OnUnLoad(env, packagePrefix);
   }
   return JNI_ERR;
}

static void netty_kqueue_native_JNI_OnUnload(JNIEnv* env) {
    netty_kqueue_bsdsocket_JNI_OnUnLoad(env, staticPackagePrefix);
    netty_kqueue_eventarray_JNI_OnUnLoad(env, staticPackagePrefix);

    if (register_unix_called == 1) {
        register_unix_called = 0;
        netty_unix_unregister(env, staticPackagePrefix);
    }

    netty_jni_util_unregister_natives(env, staticPackagePrefix, STATICALLY_CLASSNAME);
    netty_jni_util_unregister_natives(env, staticPackagePrefix, NATIVE_CLASSNAME);

    if (staticPackagePrefix != NULL) {
        free((void *) staticPackagePrefix);
        staticPackagePrefix = NULL;
    }
}

// We build with -fvisibility=hidden so ensure we mark everything that needs to be visible with JNIEXPORT
// https://mail.openjdk.java.net/pipermail/core-libs-dev/2013-February/014549.html

// Invoked by the JVM when statically linked
JNIEXPORT jint JNI_OnLoad_netty_transport_native_kqueue(JavaVM* vm, void* reserved) {
    return netty_jni_util_JNI_OnLoad(vm, reserved, "netty_transport_native_kqueue", netty_kqueue_native_JNI_OnLoad);
}

// Invoked by the JVM when statically linked
JNIEXPORT void JNI_OnUnload_netty_transport_native_kqueue(JavaVM* vm, void* reserved) {
    netty_jni_util_JNI_OnUnload(vm, reserved, netty_kqueue_native_JNI_OnUnload);
}

#ifndef NETTY_BUILD_STATIC
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    return netty_jni_util_JNI_OnLoad(vm, reserved, "netty_transport_native_kqueue", netty_kqueue_native_JNI_OnLoad);
}

JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved) {
    netty_jni_util_JNI_OnUnload(vm, reserved, netty_kqueue_native_JNI_OnUnload);
}
#endif /* NETTY_BUILD_STATIC */




© 2015 - 2024 Weber Informatics LLC | Privacy Policy