2014-02-15 22:26:36 +01:00
|
|
|
/*
|
|
|
|
* Copyright 2013 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:
|
|
|
|
*
|
|
|
|
* http://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.
|
|
|
|
*/
|
2014-09-12 21:30:50 +02:00
|
|
|
#define _GNU_SOURCE
|
2014-02-15 22:26:36 +01:00
|
|
|
#include <jni.h>
|
2016-01-12 21:59:00 +01:00
|
|
|
#include <stdint.h>
|
2014-02-15 22:26:36 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/epoll.h>
|
|
|
|
#include <sys/eventfd.h>
|
2015-01-14 16:38:46 +01:00
|
|
|
#include <sys/un.h>
|
2014-02-15 22:26:36 +01:00
|
|
|
#include <netinet/in.h>
|
2017-01-19 17:31:34 +01:00
|
|
|
#include <netinet/tcp.h>
|
2014-02-15 22:26:36 +01:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
2017-08-02 09:15:18 +02:00
|
|
|
#include <sys/timerfd.h>
|
2014-02-15 22:26:36 +01:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <fcntl.h>
|
2014-04-11 15:54:31 +02:00
|
|
|
#include <sys/utsname.h>
|
2015-02-02 11:51:19 +01:00
|
|
|
#include <stddef.h>
|
2015-05-12 14:04:32 +02:00
|
|
|
#include <limits.h>
|
2015-09-30 15:04:06 +02:00
|
|
|
#include <inttypes.h>
|
2016-01-30 20:47:12 +01:00
|
|
|
#include <link.h>
|
2016-06-06 23:51:05 +02:00
|
|
|
#include <time.h>
|
2019-11-23 21:12:24 +01:00
|
|
|
// Needed to be able to use syscalls directly and so not depend on newer GLIBC versions
|
|
|
|
#include <linux/net.h>
|
|
|
|
#include <sys/syscall.h>
|
2017-06-21 20:06:08 +02:00
|
|
|
|
|
|
|
#include "netty_epoll_linuxsocket.h"
|
2018-08-29 19:36:33 +02:00
|
|
|
#include "netty_unix_buffer.h"
|
2017-06-21 20:06:08 +02:00
|
|
|
#include "netty_unix_errors.h"
|
2015-10-07 04:00:59 +02:00
|
|
|
#include "netty_unix_filedescriptor.h"
|
2017-06-21 20:06:08 +02:00
|
|
|
#include "netty_unix_jni.h"
|
|
|
|
#include "netty_unix_limits.h"
|
2015-10-07 04:00:59 +02:00
|
|
|
#include "netty_unix_socket.h"
|
2016-01-15 07:58:38 +01:00
|
|
|
#include "netty_unix_util.h"
|
2015-06-02 21:17:32 +02:00
|
|
|
|
2015-10-07 04:00:59 +02:00
|
|
|
// TCP_FASTOPEN is defined in linux 3.7. We define this here so older kernels can compile.
|
2015-09-05 00:03:10 +02:00
|
|
|
#ifndef TCP_FASTOPEN
|
2015-10-07 04:00:59 +02:00
|
|
|
#define TCP_FASTOPEN 23
|
2015-09-05 00:03:10 +02:00
|
|
|
#endif
|
|
|
|
|
2014-02-15 22:26:36 +01:00
|
|
|
// optional
|
2014-04-04 07:45:23 +02:00
|
|
|
extern int epoll_create1(int flags) __attribute__((weak));
|
2014-09-12 21:30:50 +02:00
|
|
|
|
|
|
|
#ifndef __USE_GNU
|
2014-09-03 14:54:44 +02:00
|
|
|
struct mmsghdr {
|
|
|
|
struct msghdr msg_hdr; /* Message header */
|
|
|
|
unsigned int msg_len; /* Number of bytes transmitted */
|
|
|
|
};
|
2014-09-12 21:30:50 +02:00
|
|
|
#endif
|
2019-11-23 21:12:24 +01:00
|
|
|
|
|
|
|
// All linux syscall numbers are stable so this is safe.
|
|
|
|
#ifndef SYS_recvmmsg
|
2019-12-05 09:01:59 +01:00
|
|
|
// Only support SYS_recvmmsg for __x86_64__ / __i386__ for now
|
|
|
|
#if defined(__x86_64__)
|
|
|
|
// See https://github.com/torvalds/linux/blob/v5.4/arch/x86/entry/syscalls/syscall_64.tbl
|
2019-11-23 21:12:24 +01:00
|
|
|
#define SYS_recvmmsg 299
|
2019-12-05 09:01:59 +01:00
|
|
|
#elif defined(__i386__)
|
|
|
|
// See https://github.com/torvalds/linux/blob/v5.4/arch/x86/entry/syscalls/syscall_32.tbl
|
|
|
|
#define SYS_recvmmsg 337
|
|
|
|
#else
|
|
|
|
#define SYS_recvmmsg -1
|
2019-11-23 21:12:24 +01:00
|
|
|
#endif
|
2019-12-05 09:01:59 +01:00
|
|
|
#endif // SYS_recvmmsg
|
2019-11-23 21:12:24 +01:00
|
|
|
|
|
|
|
#ifndef SYS_sendmmsg
|
2019-12-05 09:01:59 +01:00
|
|
|
// Only support SYS_sendmmsg for __x86_64__ / __i386__ for now
|
|
|
|
#if defined(__x86_64__)
|
|
|
|
// See https://github.com/torvalds/linux/blob/v5.4/arch/x86/entry/syscalls/syscall_64.tbl
|
2019-11-23 21:12:24 +01:00
|
|
|
#define SYS_sendmmsg 307
|
2019-12-05 09:01:59 +01:00
|
|
|
#elif defined(__i386__)
|
|
|
|
// See https://github.com/torvalds/linux/blob/v5.4/arch/x86/entry/syscalls/syscall_32.tbl
|
|
|
|
#define SYS_sendmmsg 345
|
|
|
|
#else
|
|
|
|
#define SYS_sendmmsg -1
|
2014-09-12 21:30:50 +02:00
|
|
|
#endif
|
2019-12-05 09:01:59 +01:00
|
|
|
#endif // SYS_sendmmsg
|
2014-02-15 22:26:36 +01:00
|
|
|
|
|
|
|
// Those are initialized in the init(...) method and cached for performance reasons
|
2018-08-21 07:53:45 +02:00
|
|
|
static jfieldID packetAddrFieldId = NULL;
|
2019-09-06 13:54:29 +02:00
|
|
|
static jfieldID packetAddrLenFieldId = NULL;
|
2018-08-21 07:53:45 +02:00
|
|
|
static jfieldID packetScopeIdFieldId = NULL;
|
|
|
|
static jfieldID packetPortFieldId = NULL;
|
|
|
|
static jfieldID packetMemoryAddressFieldId = NULL;
|
|
|
|
static jfieldID packetCountFieldId = NULL;
|
2014-09-03 14:54:44 +02:00
|
|
|
|
2014-02-15 22:26:36 +01:00
|
|
|
// util methods
|
2015-09-05 00:03:10 +02:00
|
|
|
static int getSysctlValue(const char * property, int* returnValue) {
|
|
|
|
int rc = -1;
|
|
|
|
FILE *fd=fopen(property, "r");
|
|
|
|
if (fd != NULL) {
|
|
|
|
char buf[32] = {0x0};
|
|
|
|
if (fgets(buf, 32, fd) != NULL) {
|
|
|
|
*returnValue = atoi(buf);
|
|
|
|
rc = 0;
|
|
|
|
}
|
|
|
|
fclose(fd);
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2015-02-05 12:58:34 +01:00
|
|
|
static inline jint epollCtl(JNIEnv* env, jint efd, int op, jint fd, jint flags) {
|
2015-02-02 11:51:19 +01:00
|
|
|
uint32_t events = flags;
|
2014-02-15 22:26:36 +01:00
|
|
|
struct epoll_event ev = {
|
2015-02-02 11:51:19 +01:00
|
|
|
.data.fd = fd,
|
|
|
|
.events = events
|
2014-02-15 22:26:36 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
return epoll_ctl(efd, op, fd, &ev);
|
|
|
|
}
|
2016-01-30 20:47:12 +01:00
|
|
|
// JNI Registered Methods Begin
|
|
|
|
static jint netty_epoll_native_eventFd(JNIEnv* env, jclass clazz) {
|
2015-10-07 04:00:59 +02:00
|
|
|
jint eventFD = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
2014-02-15 22:26:36 +01:00
|
|
|
|
|
|
|
if (eventFD < 0) {
|
2017-08-02 09:15:18 +02:00
|
|
|
netty_unix_errors_throwChannelExceptionErrorNo(env, "eventfd() failed: ", errno);
|
2014-02-15 22:26:36 +01:00
|
|
|
}
|
|
|
|
return eventFD;
|
|
|
|
}
|
|
|
|
|
2017-08-02 09:15:18 +02:00
|
|
|
static jint netty_epoll_native_timerFd(JNIEnv* env, jclass clazz) {
|
|
|
|
jint timerFD = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
|
|
|
|
|
|
|
|
if (timerFD < 0) {
|
|
|
|
netty_unix_errors_throwChannelExceptionErrorNo(env, "timerfd_create() failed: ", errno);
|
|
|
|
}
|
|
|
|
return timerFD;
|
|
|
|
}
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
static void netty_epoll_native_eventFdWrite(JNIEnv* env, jclass clazz, jint fd, jlong value) {
|
2019-05-31 06:59:39 +02:00
|
|
|
uint64_t val;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
jint ret = eventfd_write(fd, (eventfd_t) value);
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
// We need to read before we can write again, let's try to read and then write again and if this
|
|
|
|
// fails we will bail out.
|
|
|
|
//
|
|
|
|
// See http://man7.org/linux/man-pages/man2/eventfd.2.html.
|
|
|
|
if (errno == EAGAIN) {
|
|
|
|
if (eventfd_read(fd, &val) == 0 || errno == EAGAIN) {
|
|
|
|
// Try again
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
netty_unix_errors_throwChannelExceptionErrorNo(env, "eventfd_read(...) failed: ", errno);
|
|
|
|
} else {
|
|
|
|
netty_unix_errors_throwChannelExceptionErrorNo(env, "eventfd_write(...) failed: ", errno);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2014-02-15 22:26:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
static void netty_epoll_native_eventFdRead(JNIEnv* env, jclass clazz, jint fd) {
|
2014-02-15 22:26:36 +01:00
|
|
|
uint64_t eventfd_t;
|
|
|
|
|
|
|
|
if (eventfd_read(fd, &eventfd_t) != 0) {
|
|
|
|
// something is serious wrong
|
2015-10-07 04:00:59 +02:00
|
|
|
netty_unix_errors_throwRuntimeException(env, "eventfd_read() failed");
|
2014-02-15 22:26:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-02 09:15:18 +02:00
|
|
|
static void netty_epoll_native_timerFdRead(JNIEnv* env, jclass clazz, jint fd) {
|
|
|
|
uint64_t timerFireCount;
|
|
|
|
|
|
|
|
if (read(fd, &timerFireCount, sizeof(uint64_t)) < 0) {
|
|
|
|
// it is expected that this is only called where there is known to be activity, so this is an error.
|
|
|
|
netty_unix_errors_throwChannelExceptionErrorNo(env, "read() failed: ", errno);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
static jint netty_epoll_native_epollCreate(JNIEnv* env, jclass clazz) {
|
2014-04-04 07:45:23 +02:00
|
|
|
jint efd;
|
|
|
|
if (epoll_create1) {
|
|
|
|
efd = epoll_create1(EPOLL_CLOEXEC);
|
|
|
|
} else {
|
|
|
|
// size will be ignored anyway but must be positive
|
|
|
|
efd = epoll_create(126);
|
|
|
|
}
|
2014-02-15 22:26:36 +01:00
|
|
|
if (efd < 0) {
|
|
|
|
int err = errno;
|
2014-07-28 22:31:26 +02:00
|
|
|
if (epoll_create1) {
|
2015-10-07 04:00:59 +02:00
|
|
|
netty_unix_errors_throwChannelExceptionErrorNo(env, "epoll_create1() failed: ", err);
|
2014-07-28 22:31:26 +02:00
|
|
|
} else {
|
2015-10-07 04:00:59 +02:00
|
|
|
netty_unix_errors_throwChannelExceptionErrorNo(env, "epoll_create() failed: ", err);
|
2014-07-28 22:31:26 +02:00
|
|
|
}
|
|
|
|
return efd;
|
2014-02-15 22:26:36 +01:00
|
|
|
}
|
2014-04-04 07:45:23 +02:00
|
|
|
if (!epoll_create1) {
|
|
|
|
if (fcntl(efd, F_SETFD, FD_CLOEXEC) < 0) {
|
|
|
|
int err = errno;
|
|
|
|
close(efd);
|
2015-10-07 04:00:59 +02:00
|
|
|
netty_unix_errors_throwChannelExceptionErrorNo(env, "fcntl() failed: ", err);
|
2014-04-04 07:45:23 +02:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
2014-02-15 22:26:36 +01:00
|
|
|
return efd;
|
|
|
|
}
|
|
|
|
|
2019-09-27 09:55:44 +02:00
|
|
|
static jint netty_epoll_native_epollWait(JNIEnv* env, jclass clazz, jint efd, jlong address, jint len, jint timeout) {
|
2016-01-12 21:59:00 +01:00
|
|
|
struct epoll_event *ev = (struct epoll_event*) (intptr_t) address;
|
2017-08-02 09:15:18 +02:00
|
|
|
int result, err;
|
|
|
|
|
2019-09-27 09:55:44 +02:00
|
|
|
do {
|
|
|
|
result = epoll_wait(efd, ev, len, timeout);
|
|
|
|
if (result >= 0) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
} while((err = errno) == EINTR);
|
|
|
|
return -err;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This method is deprecated!
|
|
|
|
static jint netty_epoll_native_epollWait0(JNIEnv* env, jclass clazz, jint efd, jlong address, jint len, jint timerFd, jint tvSec, jint tvNsec) {
|
2017-08-02 09:15:18 +02:00
|
|
|
if (tvSec == 0 && tvNsec == 0) {
|
|
|
|
// Zeros = poll (aka return immediately).
|
2019-09-27 09:55:44 +02:00
|
|
|
return netty_epoll_native_epollWait(env, clazz, efd, address, len, 0);
|
2017-08-02 09:15:18 +02:00
|
|
|
}
|
2019-09-27 09:55:44 +02:00
|
|
|
// only reschedule the timer if there is a newer event.
|
|
|
|
// -1 is a special value used by EpollEventLoop.
|
|
|
|
if (tvSec != ((jint) -1) && tvNsec != ((jint) -1)) {
|
|
|
|
struct itimerspec ts;
|
|
|
|
memset(&ts.it_interval, 0, sizeof(struct timespec));
|
|
|
|
ts.it_value.tv_sec = tvSec;
|
|
|
|
ts.it_value.tv_nsec = tvNsec;
|
|
|
|
if (timerfd_settime(timerFd, 0, &ts, NULL) < 0) {
|
|
|
|
netty_unix_errors_throwChannelExceptionErrorNo(env, "timerfd_settime() failed: ", errno);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return netty_epoll_native_epollWait(env, clazz, efd, address, len, -1);
|
2014-02-15 22:26:36 +01:00
|
|
|
}
|
|
|
|
|
2018-09-28 22:52:00 +02:00
|
|
|
static inline void cpu_relax() {
|
|
|
|
#if defined(__x86_64__)
|
|
|
|
asm volatile("pause\n": : :"memory");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static jint netty_epoll_native_epollBusyWait0(JNIEnv* env, jclass clazz, jint efd, jlong address, jint len) {
|
|
|
|
struct epoll_event *ev = (struct epoll_event*) (intptr_t) address;
|
|
|
|
int result, err;
|
|
|
|
|
|
|
|
// Zeros = poll (aka return immediately).
|
|
|
|
do {
|
|
|
|
result = epoll_wait(efd, ev, len, 0);
|
|
|
|
if (result == 0) {
|
|
|
|
// Since we're always polling epoll_wait with no timeout,
|
|
|
|
// signal CPU that we're in a busy loop
|
|
|
|
cpu_relax();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result >= 0) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
} while((err = errno) == EINTR);
|
|
|
|
|
|
|
|
return -err;
|
|
|
|
}
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
static jint netty_epoll_native_epollCtlAdd0(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags) {
|
2015-04-30 09:38:35 +02:00
|
|
|
int res = epollCtl(env, efd, EPOLL_CTL_ADD, fd, flags);
|
|
|
|
if (res < 0) {
|
|
|
|
return -errno;
|
2014-02-15 22:26:36 +01:00
|
|
|
}
|
2015-04-30 09:38:35 +02:00
|
|
|
return res;
|
2014-02-15 22:26:36 +01:00
|
|
|
}
|
2016-01-30 20:47:12 +01:00
|
|
|
static jint netty_epoll_native_epollCtlMod0(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags) {
|
2015-04-30 09:38:35 +02:00
|
|
|
int res = epollCtl(env, efd, EPOLL_CTL_MOD, fd, flags);
|
|
|
|
if (res < 0) {
|
|
|
|
return -errno;
|
2014-02-15 22:26:36 +01:00
|
|
|
}
|
2015-04-30 09:38:35 +02:00
|
|
|
return res;
|
2014-02-15 22:26:36 +01:00
|
|
|
}
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
static jint netty_epoll_native_epollCtlDel0(JNIEnv* env, jclass clazz, jint efd, jint fd) {
|
2014-02-15 22:26:36 +01:00
|
|
|
// Create an empty event to workaround a bug in older kernels which can not handle NULL.
|
|
|
|
struct epoll_event event = { 0 };
|
2015-04-30 09:38:35 +02:00
|
|
|
int res = epoll_ctl(efd, EPOLL_CTL_DEL, fd, &event);
|
|
|
|
if (res < 0) {
|
|
|
|
return -errno;
|
2014-02-15 22:26:36 +01:00
|
|
|
}
|
2015-04-30 09:38:35 +02:00
|
|
|
return res;
|
2014-02-15 22:26:36 +01:00
|
|
|
}
|
|
|
|
|
2019-04-08 20:13:39 +02:00
|
|
|
static jint netty_epoll_native_sendmmsg0(JNIEnv* env, jclass clazz, jint fd, jboolean ipv6, jobjectArray packets, jint offset, jint len) {
|
2014-09-03 14:54:44 +02:00
|
|
|
struct mmsghdr msg[len];
|
2016-05-11 06:20:28 +02:00
|
|
|
struct sockaddr_storage addr[len];
|
2017-01-19 17:31:34 +01:00
|
|
|
socklen_t addrSize;
|
2014-09-03 14:54:44 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
memset(msg, 0, sizeof(msg));
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
|
|
|
jobject packet = (*env)->GetObjectArrayElement(env, packets, i + offset);
|
|
|
|
jbyteArray address = (jbyteArray) (*env)->GetObjectField(env, packet, packetAddrFieldId);
|
2019-09-06 20:57:04 +02:00
|
|
|
jint addrLen = (*env)->GetIntField(env, packet, packetAddrLenFieldId);
|
2014-09-03 14:54:44 +02:00
|
|
|
|
2019-09-06 20:57:04 +02:00
|
|
|
if (addrLen != 0) {
|
|
|
|
jint scopeId = (*env)->GetIntField(env, packet, packetScopeIdFieldId);
|
|
|
|
jint port = (*env)->GetIntField(env, packet, packetPortFieldId);
|
2014-09-03 14:54:44 +02:00
|
|
|
|
2019-09-06 20:57:04 +02:00
|
|
|
if (netty_unix_socket_initSockaddr(env, ipv6, address, scopeId, port, &addr[i], &addrSize) == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
msg[i].msg_hdr.msg_name = &addr[i];
|
|
|
|
msg[i].msg_hdr.msg_namelen = addrSize;
|
|
|
|
}
|
2014-09-03 14:54:44 +02:00
|
|
|
|
2016-01-12 21:59:00 +01:00
|
|
|
msg[i].msg_hdr.msg_iov = (struct iovec*) (intptr_t) (*env)->GetLongField(env, packet, packetMemoryAddressFieldId);
|
2019-09-03 08:40:17 +02:00
|
|
|
msg[i].msg_hdr.msg_iovlen = (*env)->GetIntField(env, packet, packetCountFieldId);
|
2014-09-03 14:54:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t res;
|
|
|
|
int err;
|
|
|
|
do {
|
2019-11-23 21:12:24 +01:00
|
|
|
// We directly use the syscall to prevent depending on GLIBC 2.14.
|
|
|
|
res = syscall(SYS_sendmmsg, fd, msg, len, 0);
|
2014-09-03 14:54:44 +02:00
|
|
|
// keep on writing if it was interrupted
|
2014-12-30 04:20:43 +01:00
|
|
|
} while (res == -1 && ((err = errno) == EINTR));
|
2014-09-03 14:54:44 +02:00
|
|
|
|
|
|
|
if (res < 0) {
|
2014-12-30 04:20:43 +01:00
|
|
|
return -err;
|
2014-09-03 14:54:44 +02:00
|
|
|
}
|
|
|
|
return (jint) res;
|
|
|
|
}
|
|
|
|
|
2019-09-03 08:40:17 +02:00
|
|
|
static jint netty_epoll_native_recvmmsg0(JNIEnv* env, jclass clazz, jint fd, jboolean ipv6, jobjectArray packets, jint offset, jint len) {
|
|
|
|
struct mmsghdr msg[len];
|
|
|
|
memset(msg, 0, sizeof(msg));
|
|
|
|
struct sockaddr_storage addr[len];
|
|
|
|
int addrSize = sizeof(addr);
|
|
|
|
memset(addr, 0, addrSize);
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
jobject packet = (*env)->GetObjectArrayElement(env, packets, i + offset);
|
|
|
|
msg[i].msg_hdr.msg_iov = (struct iovec*) (intptr_t) (*env)->GetLongField(env, packet, packetMemoryAddressFieldId);
|
|
|
|
msg[i].msg_hdr.msg_iovlen = (*env)->GetIntField(env, packet, packetCountFieldId);
|
|
|
|
|
|
|
|
msg[i].msg_hdr.msg_name = addr + i;
|
|
|
|
msg[i].msg_hdr.msg_namelen = (socklen_t) addrSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t res;
|
|
|
|
int err;
|
|
|
|
do {
|
2019-11-23 21:12:24 +01:00
|
|
|
// We directly use the syscall to prevent depending on GLIBC 2.12.
|
|
|
|
res = syscall(SYS_recvmmsg, fd, &msg, len, 0, NULL);
|
|
|
|
|
|
|
|
// keep on reading if it was interrupted
|
2019-09-03 08:40:17 +02:00
|
|
|
} while (res == -1 && ((err = errno) == EINTR));
|
|
|
|
|
|
|
|
if (res < 0) {
|
|
|
|
return -err;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < res; i++) {
|
|
|
|
jobject packet = (*env)->GetObjectArrayElement(env, packets, i + offset);
|
|
|
|
jbyteArray address = (jbyteArray) (*env)->GetObjectField(env, packet, packetAddrFieldId);
|
|
|
|
|
|
|
|
(*env)->SetIntField(env, packet, packetCountFieldId, msg[i].msg_len);
|
|
|
|
|
|
|
|
struct sockaddr_storage* addr = (struct sockaddr_storage*) msg[i].msg_hdr.msg_name;
|
|
|
|
|
|
|
|
if (addr->ss_family == AF_INET) {
|
|
|
|
struct sockaddr_in* ipaddr = (struct sockaddr_in*) addr;
|
|
|
|
|
|
|
|
(*env)->SetByteArrayRegion(env, address, 0, 4, (jbyte*) &ipaddr->sin_addr.s_addr);
|
2019-09-06 13:54:29 +02:00
|
|
|
(*env)->SetIntField(env, packet, packetAddrLenFieldId, 4);
|
2019-09-03 08:40:17 +02:00
|
|
|
(*env)->SetIntField(env, packet, packetScopeIdFieldId, 0);
|
|
|
|
(*env)->SetIntField(env, packet, packetPortFieldId, ntohs(ipaddr->sin_port));
|
|
|
|
} else {
|
2019-09-06 13:54:29 +02:00
|
|
|
int addrLen = netty_unix_socket_ipAddressLength(addr);
|
2019-09-03 08:40:17 +02:00
|
|
|
struct sockaddr_in6* ip6addr = (struct sockaddr_in6*) addr;
|
|
|
|
|
2019-09-06 13:54:29 +02:00
|
|
|
if (addrLen == 4) {
|
|
|
|
// IPV4 mapped IPV6 address
|
|
|
|
(*env)->SetByteArrayRegion(env, address, 12, 4, (jbyte*) &ip6addr->sin6_addr.s6_addr);
|
|
|
|
} else {
|
|
|
|
(*env)->SetByteArrayRegion(env, address, 0, 16, (jbyte*) &ip6addr->sin6_addr.s6_addr);
|
|
|
|
}
|
|
|
|
(*env)->SetIntField(env, packet, packetAddrLenFieldId, addrLen);
|
2019-09-03 08:40:17 +02:00
|
|
|
(*env)->SetIntField(env, packet, packetScopeIdFieldId, ip6addr->sin6_scope_id);
|
|
|
|
(*env)->SetIntField(env, packet, packetPortFieldId, ntohs(ip6addr->sin6_port));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (jint) res;
|
|
|
|
}
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
static jstring netty_epoll_native_kernelVersion(JNIEnv* env, jclass clazz) {
|
2014-04-11 15:54:31 +02:00
|
|
|
struct utsname name;
|
|
|
|
|
|
|
|
int res = uname(&name);
|
|
|
|
if (res == 0) {
|
|
|
|
return (*env)->NewStringUTF(env, name.release);
|
|
|
|
}
|
2017-08-02 09:15:18 +02:00
|
|
|
netty_unix_errors_throwRuntimeExceptionErrorNo(env, "uname() failed: ", errno);
|
2014-04-11 15:54:31 +02:00
|
|
|
return NULL;
|
2014-04-17 21:41:04 +02:00
|
|
|
}
|
2016-01-30 20:47:12 +01:00
|
|
|
static jboolean netty_epoll_native_isSupportingSendmmsg(JNIEnv* env, jclass clazz) {
|
2019-12-05 09:01:59 +01:00
|
|
|
if (SYS_sendmmsg == -1) {
|
|
|
|
return JNI_FALSE;
|
|
|
|
}
|
2019-11-23 21:12:24 +01:00
|
|
|
if (syscall(SYS_sendmmsg, -1, NULL, 0, 0) == -1) {
|
|
|
|
if (errno == ENOSYS) {
|
|
|
|
return JNI_FALSE;
|
|
|
|
}
|
2014-09-03 14:54:44 +02:00
|
|
|
}
|
2019-11-23 21:12:24 +01:00
|
|
|
return JNI_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static jboolean netty_epoll_native_isSupportingRecvmmsg(JNIEnv* env, jclass clazz) {
|
2019-12-05 09:01:59 +01:00
|
|
|
if (SYS_recvmmsg == -1) {
|
|
|
|
return JNI_FALSE;
|
|
|
|
}
|
2019-11-23 21:12:24 +01:00
|
|
|
if (syscall(SYS_recvmmsg, -1, NULL, 0, 0, NULL) == -1) {
|
|
|
|
if (errno == ENOSYS) {
|
|
|
|
return JNI_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return JNI_TRUE;
|
2014-09-03 14:54:44 +02:00
|
|
|
}
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
static jboolean netty_epoll_native_isSupportingTcpFastopen(JNIEnv* env, jclass clazz) {
|
2015-09-05 00:03:10 +02:00
|
|
|
int fastopen = 0;
|
|
|
|
getSysctlValue("/proc/sys/net/ipv4/tcp_fastopen", &fastopen);
|
|
|
|
if (fastopen > 0) {
|
|
|
|
return JNI_TRUE;
|
|
|
|
}
|
|
|
|
return JNI_FALSE;
|
|
|
|
}
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
static jint netty_epoll_native_epollet(JNIEnv* env, jclass clazz) {
|
2015-02-02 11:51:19 +01:00
|
|
|
return EPOLLET;
|
|
|
|
}
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
static jint netty_epoll_native_epollin(JNIEnv* env, jclass clazz) {
|
2015-02-02 11:51:19 +01:00
|
|
|
return EPOLLIN;
|
|
|
|
}
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
static jint netty_epoll_native_epollout(JNIEnv* env, jclass clazz) {
|
2015-02-02 11:51:19 +01:00
|
|
|
return EPOLLOUT;
|
|
|
|
}
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
static jint netty_epoll_native_epollrdhup(JNIEnv* env, jclass clazz) {
|
2015-02-02 11:51:19 +01:00
|
|
|
return EPOLLRDHUP;
|
|
|
|
}
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
static jint netty_epoll_native_epollerr(JNIEnv* env, jclass clazz) {
|
2015-06-01 21:17:51 +02:00
|
|
|
return EPOLLERR;
|
|
|
|
}
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
static jint netty_epoll_native_sizeofEpollEvent(JNIEnv* env, jclass clazz) {
|
2015-02-02 11:51:19 +01:00
|
|
|
return sizeof(struct epoll_event);
|
|
|
|
}
|
2015-01-15 14:38:14 +01:00
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
static jint netty_epoll_native_offsetofEpollData(JNIEnv* env, jclass clazz) {
|
2015-02-02 11:51:19 +01:00
|
|
|
return offsetof(struct epoll_event, data);
|
2015-02-06 07:34:54 +01:00
|
|
|
}
|
2015-04-14 06:54:20 +02:00
|
|
|
|
2015-05-12 14:04:32 +02:00
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
static jint netty_epoll_native_tcpMd5SigMaxKeyLen(JNIEnv* env, jclass clazz) {
|
2015-08-30 12:11:41 +02:00
|
|
|
struct tcp_md5sig md5sig;
|
|
|
|
|
|
|
|
// Defensive size check
|
|
|
|
if (sizeof(md5sig.tcpm_key) < TCP_MD5SIG_MAXKEYLEN) {
|
|
|
|
return sizeof(md5sig.tcpm_key);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TCP_MD5SIG_MAXKEYLEN;
|
|
|
|
}
|
2016-01-30 20:47:12 +01:00
|
|
|
// JNI Registered Methods End
|
|
|
|
|
|
|
|
// JNI Method Registration Table Begin
|
|
|
|
static const JNINativeMethod statically_referenced_fixed_method_table[] = {
|
|
|
|
{ "epollet", "()I", (void *) netty_epoll_native_epollet },
|
|
|
|
{ "epollin", "()I", (void *) netty_epoll_native_epollin },
|
|
|
|
{ "epollout", "()I", (void *) netty_epoll_native_epollout },
|
|
|
|
{ "epollrdhup", "()I", (void *) netty_epoll_native_epollrdhup },
|
|
|
|
{ "epollerr", "()I", (void *) netty_epoll_native_epollerr },
|
|
|
|
{ "tcpMd5SigMaxKeyLen", "()I", (void *) netty_epoll_native_tcpMd5SigMaxKeyLen },
|
|
|
|
{ "isSupportingSendmmsg", "()Z", (void *) netty_epoll_native_isSupportingSendmmsg },
|
2019-11-23 21:12:24 +01:00
|
|
|
{ "isSupportingRecvmmsg", "()Z", (void *) netty_epoll_native_isSupportingRecvmmsg },
|
2016-01-30 20:47:12 +01:00
|
|
|
{ "isSupportingTcpFastopen", "()Z", (void *) netty_epoll_native_isSupportingTcpFastopen },
|
|
|
|
{ "kernelVersion", "()Ljava/lang/String;", (void *) netty_epoll_native_kernelVersion }
|
|
|
|
};
|
|
|
|
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[] = {
|
|
|
|
{ "eventFd", "()I", (void *) netty_epoll_native_eventFd },
|
2017-08-02 09:15:18 +02:00
|
|
|
{ "timerFd", "()I", (void *) netty_epoll_native_timerFd },
|
2016-01-30 20:47:12 +01:00
|
|
|
{ "eventFdWrite", "(IJ)V", (void *) netty_epoll_native_eventFdWrite },
|
|
|
|
{ "eventFdRead", "(I)V", (void *) netty_epoll_native_eventFdRead },
|
2017-08-02 09:15:18 +02:00
|
|
|
{ "timerFdRead", "(I)V", (void *) netty_epoll_native_timerFdRead },
|
2016-01-30 20:47:12 +01:00
|
|
|
{ "epollCreate", "()I", (void *) netty_epoll_native_epollCreate },
|
2019-09-27 09:55:44 +02:00
|
|
|
{ "epollWait0", "(IJIIII)I", (void *) netty_epoll_native_epollWait0 }, // This method is deprecated!
|
|
|
|
{ "epollWait", "(IJII)I", (void *) netty_epoll_native_epollWait },
|
2018-09-28 22:52:00 +02:00
|
|
|
{ "epollBusyWait0", "(IJI)I", (void *) netty_epoll_native_epollBusyWait0 },
|
2016-01-30 20:47:12 +01:00
|
|
|
{ "epollCtlAdd0", "(III)I", (void *) netty_epoll_native_epollCtlAdd0 },
|
|
|
|
{ "epollCtlMod0", "(III)I", (void *) netty_epoll_native_epollCtlMod0 },
|
|
|
|
{ "epollCtlDel0", "(II)I", (void *) netty_epoll_native_epollCtlDel0 },
|
|
|
|
// "sendmmsg0" has a dynamic signature
|
|
|
|
{ "sizeofEpollEvent", "()I", (void *) netty_epoll_native_sizeofEpollEvent },
|
2019-12-01 18:07:37 +01:00
|
|
|
{ "offsetofEpollData", "()I", (void *) netty_epoll_native_offsetofEpollData }
|
2016-01-30 20:47:12 +01:00
|
|
|
};
|
|
|
|
static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(fixed_method_table[0]);
|
|
|
|
|
|
|
|
static jint dynamicMethodsTableSize() {
|
2019-09-03 08:40:17 +02:00
|
|
|
return fixed_method_table_size + 2; // 2 is for the dynamic method signatures.
|
2016-01-30 20:47:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static JNINativeMethod* createDynamicMethodsTable(const char* packagePrefix) {
|
2019-09-24 07:18:35 +02:00
|
|
|
char* dynamicTypeName = NULL;
|
|
|
|
size_t size = sizeof(JNINativeMethod) * dynamicMethodsTableSize();
|
|
|
|
JNINativeMethod* dynamicMethods = malloc(size);
|
|
|
|
if (dynamicMethods == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
memset(dynamicMethods, 0, size);
|
2016-01-30 20:47:12 +01:00
|
|
|
memcpy(dynamicMethods, fixed_method_table, sizeof(fixed_method_table));
|
2019-09-24 07:18:35 +02:00
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
JNINativeMethod* dynamicMethod = &dynamicMethods[fixed_method_table_size];
|
2019-09-24 07:18:35 +02:00
|
|
|
NETTY_PREPEND(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket;II)I", dynamicTypeName, error);
|
|
|
|
NETTY_PREPEND("(IZ[L", dynamicTypeName, dynamicMethod->signature, error);
|
2016-01-30 20:47:12 +01:00
|
|
|
dynamicMethod->name = "sendmmsg0";
|
|
|
|
dynamicMethod->fnPtr = (void *) netty_epoll_native_sendmmsg0;
|
2019-09-24 07:18:35 +02:00
|
|
|
netty_unix_util_free_dynamic_name(&dynamicTypeName);
|
2019-09-03 08:40:17 +02:00
|
|
|
|
2019-09-24 07:18:35 +02:00
|
|
|
++dynamicMethod;
|
|
|
|
NETTY_PREPEND(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket;II)I", dynamicTypeName, error);
|
|
|
|
NETTY_PREPEND("(IZ[L", dynamicTypeName, dynamicMethod->signature, error);
|
2019-09-03 08:40:17 +02:00
|
|
|
dynamicMethod->name = "recvmmsg0";
|
|
|
|
dynamicMethod->fnPtr = (void *) netty_epoll_native_recvmmsg0;
|
2019-09-24 07:18:35 +02:00
|
|
|
netty_unix_util_free_dynamic_name(&dynamicTypeName);
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
return dynamicMethods;
|
2019-09-24 07:18:35 +02:00
|
|
|
error:
|
|
|
|
free(dynamicTypeName);
|
|
|
|
netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
|
|
|
|
return NULL;
|
2016-01-30 20:47:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// JNI Method Registration Table End
|
|
|
|
|
|
|
|
static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
2019-09-24 07:18:35 +02:00
|
|
|
int ret = JNI_ERR;
|
2018-08-30 06:56:42 +02:00
|
|
|
int limitsOnLoadCalled = 0;
|
|
|
|
int errorsOnLoadCalled = 0;
|
|
|
|
int filedescriptorOnLoadCalled = 0;
|
|
|
|
int socketOnLoadCalled = 0;
|
|
|
|
int bufferOnLoadCalled = 0;
|
|
|
|
int linuxsocketOnLoadCalled = 0;
|
2019-09-24 07:18:35 +02:00
|
|
|
char* nettyClassName = NULL;
|
|
|
|
jclass nativeDatagramPacketCls = NULL;
|
2019-10-08 09:57:41 +02:00
|
|
|
JNINativeMethod* dynamicMethods = NULL;
|
2018-08-30 06:56:42 +02:00
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
// 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) {
|
2019-09-24 07:18:35 +02:00
|
|
|
goto done;
|
2016-01-30 20:47:12 +01:00
|
|
|
}
|
|
|
|
// Register the methods which are not referenced by static member variables
|
2019-10-08 09:57:41 +02:00
|
|
|
dynamicMethods = createDynamicMethodsTable(packagePrefix);
|
2019-09-24 07:18:35 +02:00
|
|
|
if (dynamicMethods == NULL) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
if (netty_unix_util_register_natives(env,
|
|
|
|
packagePrefix,
|
|
|
|
"io/netty/channel/epoll/Native",
|
|
|
|
dynamicMethods,
|
|
|
|
dynamicMethodsTableSize()) != 0) {
|
2019-09-24 07:18:35 +02:00
|
|
|
goto done;
|
2016-01-30 20:47:12 +01:00
|
|
|
}
|
|
|
|
// Load all c modules that we depend upon
|
2017-01-19 17:31:34 +01:00
|
|
|
if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
2019-09-24 07:18:35 +02:00
|
|
|
goto done;
|
2017-01-19 17:31:34 +01:00
|
|
|
}
|
2018-08-30 06:56:42 +02:00
|
|
|
limitsOnLoadCalled = 1;
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
if (netty_unix_errors_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
2019-09-24 07:18:35 +02:00
|
|
|
goto done;
|
2016-01-30 20:47:12 +01:00
|
|
|
}
|
2018-08-30 06:56:42 +02:00
|
|
|
errorsOnLoadCalled = 1;
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
if (netty_unix_filedescriptor_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
2019-09-24 07:18:35 +02:00
|
|
|
goto done;
|
2016-01-30 20:47:12 +01:00
|
|
|
}
|
2018-08-30 06:56:42 +02:00
|
|
|
filedescriptorOnLoadCalled = 1;
|
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
if (netty_unix_socket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
2019-09-24 07:18:35 +02:00
|
|
|
goto done;
|
2016-01-30 20:47:12 +01:00
|
|
|
}
|
2018-08-30 06:56:42 +02:00
|
|
|
socketOnLoadCalled = 1;
|
|
|
|
|
2018-08-29 19:36:33 +02:00
|
|
|
if (netty_unix_buffer_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
2019-09-24 07:18:35 +02:00
|
|
|
goto done;
|
2018-08-29 19:36:33 +02:00
|
|
|
}
|
2018-08-30 06:56:42 +02:00
|
|
|
bufferOnLoadCalled = 1;
|
|
|
|
|
2017-01-19 17:31:34 +01:00
|
|
|
if (netty_epoll_linuxsocket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
2019-09-24 07:18:35 +02:00
|
|
|
goto done;
|
2017-01-19 17:31:34 +01:00
|
|
|
}
|
2018-08-30 06:56:42 +02:00
|
|
|
linuxsocketOnLoadCalled = 1;
|
2017-01-19 17:31:34 +01:00
|
|
|
|
2016-01-30 20:47:12 +01:00
|
|
|
// Initialize this module
|
2019-09-24 07:18:35 +02:00
|
|
|
NETTY_PREPEND(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket", nettyClassName, done);
|
|
|
|
NETTY_FIND_CLASS(env, nativeDatagramPacketCls, nettyClassName, done);
|
|
|
|
netty_unix_util_free_dynamic_name(&nettyClassName);
|
2016-01-30 20:47:12 +01:00
|
|
|
|
2019-09-24 07:18:35 +02:00
|
|
|
NETTY_GET_FIELD(env, nativeDatagramPacketCls, packetAddrFieldId, "addr", "[B", done);
|
|
|
|
NETTY_GET_FIELD(env, nativeDatagramPacketCls, packetAddrLenFieldId, "addrLen", "I", done);
|
|
|
|
NETTY_GET_FIELD(env, nativeDatagramPacketCls, packetScopeIdFieldId, "scopeId", "I", done);
|
|
|
|
NETTY_GET_FIELD(env, nativeDatagramPacketCls, packetPortFieldId, "port", "I", done);
|
|
|
|
NETTY_GET_FIELD(env, nativeDatagramPacketCls, packetMemoryAddressFieldId, "memoryAddress", "J", done);
|
|
|
|
NETTY_GET_FIELD(env, nativeDatagramPacketCls, packetCountFieldId, "count", "I", done);
|
2016-01-30 20:47:12 +01:00
|
|
|
|
2019-09-24 07:18:35 +02:00
|
|
|
ret = NETTY_JNI_VERSION;
|
|
|
|
done:
|
2016-01-30 20:47:12 +01:00
|
|
|
|
2019-09-24 07:18:35 +02:00
|
|
|
netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
|
|
|
|
free(nettyClassName);
|
2018-08-30 06:56:42 +02:00
|
|
|
|
2019-09-24 07:18:35 +02:00
|
|
|
if (ret == JNI_ERR) {
|
|
|
|
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;
|
|
|
|
packetAddrLenFieldId = NULL;
|
|
|
|
packetScopeIdFieldId = NULL;
|
|
|
|
packetPortFieldId = NULL;
|
|
|
|
packetMemoryAddressFieldId = NULL;
|
|
|
|
packetCountFieldId = NULL;
|
|
|
|
}
|
|
|
|
return ret;
|
2016-01-30 20:47:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void netty_epoll_native_JNI_OnUnLoad(JNIEnv* env) {
|
2017-01-19 17:31:34 +01:00
|
|
|
netty_unix_limits_JNI_OnUnLoad(env);
|
2016-01-30 20:47:12 +01:00
|
|
|
netty_unix_errors_JNI_OnUnLoad(env);
|
|
|
|
netty_unix_filedescriptor_JNI_OnUnLoad(env);
|
|
|
|
netty_unix_socket_JNI_OnUnLoad(env);
|
2018-08-29 19:36:33 +02:00
|
|
|
netty_unix_buffer_JNI_OnUnLoad(env);
|
2017-01-19 17:31:34 +01:00
|
|
|
netty_epoll_linuxsocket_JNI_OnUnLoad(env);
|
2018-08-30 06:56:42 +02:00
|
|
|
|
|
|
|
packetAddrFieldId = NULL;
|
2019-09-06 13:54:29 +02:00
|
|
|
packetAddrLenFieldId = NULL;
|
2018-08-30 06:56:42 +02:00
|
|
|
packetScopeIdFieldId = NULL;
|
|
|
|
packetPortFieldId = NULL;
|
|
|
|
packetMemoryAddressFieldId = NULL;
|
|
|
|
packetCountFieldId = NULL;
|
2016-01-30 20:47:12 +01:00
|
|
|
}
|
|
|
|
|
2017-06-21 20:06:08 +02:00
|
|
|
// Invoked by the JVM when statically linked
|
2018-08-21 07:53:45 +02:00
|
|
|
static jint JNI_OnLoad_netty_transport_native_epoll0(JavaVM* vm, void* reserved) {
|
2016-01-30 20:47:12 +01:00
|
|
|
JNIEnv* env;
|
2017-06-21 20:06:08 +02:00
|
|
|
if ((*vm)->GetEnv(vm, (void**) &env, NETTY_JNI_VERSION) != JNI_OK) {
|
2016-01-30 20:47:12 +01:00
|
|
|
return JNI_ERR;
|
|
|
|
}
|
2017-06-21 20:06:08 +02:00
|
|
|
char* packagePrefix = NULL;
|
2017-08-17 21:30:36 +02:00
|
|
|
#ifndef NETTY_BUILD_STATIC
|
2016-01-30 20:47:12 +01:00
|
|
|
Dl_info dlinfo;
|
|
|
|
jint status = 0;
|
2016-02-05 20:17:20 +01:00
|
|
|
// We need to use an address of a function that is uniquely part of this library, so choose a static
|
|
|
|
// function. See https://github.com/netty/netty/issues/4840.
|
2017-01-19 17:31:34 +01:00
|
|
|
if (!dladdr((void*) netty_epoll_native_JNI_OnUnLoad, &dlinfo)) {
|
2016-02-05 20:17:20 +01:00
|
|
|
fprintf(stderr, "FATAL: transport-native-epoll JNI call to dladdr failed!\n");
|
2016-01-30 20:47:12 +01:00
|
|
|
return JNI_ERR;
|
|
|
|
}
|
2017-08-14 09:11:07 +02:00
|
|
|
packagePrefix = netty_unix_util_parse_package_prefix(dlinfo.dli_fname, "netty_transport_native_epoll", &status);
|
2016-01-30 20:47:12 +01:00
|
|
|
if (status == JNI_ERR) {
|
2016-02-05 20:17:20 +01:00
|
|
|
fprintf(stderr, "FATAL: transport-native-epoll JNI encountered unexpected dlinfo.dli_fname: %s\n", dlinfo.dli_fname);
|
2016-01-30 20:47:12 +01:00
|
|
|
return JNI_ERR;
|
|
|
|
}
|
2017-08-17 21:30:36 +02:00
|
|
|
#endif /* NETTY_BUILD_STATIC */
|
2016-01-30 20:47:12 +01:00
|
|
|
jint ret = netty_epoll_native_JNI_OnLoad(env, packagePrefix);
|
|
|
|
|
2019-09-24 07:18:35 +02:00
|
|
|
free(packagePrefix);
|
2016-01-30 20:47:12 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-08-21 07:53:45 +02:00
|
|
|
static void JNI_OnUnload_netty_transport_native_epoll0(JavaVM* vm, void* reserved) {
|
2016-01-30 20:47:12 +01:00
|
|
|
JNIEnv* env;
|
2017-06-21 20:06:08 +02:00
|
|
|
if ((*vm)->GetEnv(vm, (void**) &env, NETTY_JNI_VERSION) != JNI_OK) {
|
2016-01-30 20:47:12 +01:00
|
|
|
// Something is wrong but nothing we can do about this :(
|
|
|
|
return;
|
|
|
|
}
|
2016-02-08 16:49:13 +01:00
|
|
|
netty_epoll_native_JNI_OnUnLoad(env);
|
2016-01-30 20:47:12 +01:00
|
|
|
}
|
2017-06-21 20:06:08 +02:00
|
|
|
|
2018-08-21 07:53:45 +02:00
|
|
|
// We build with -fvisibility=hidden so ensure we mark everything that needs to be visible with JNIEXPORT
|
|
|
|
// http://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_epoll(JavaVM* vm, void* reserved) {
|
|
|
|
return JNI_OnLoad_netty_transport_native_epoll0(vm, reserved);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Invoked by the JVM when statically linked
|
|
|
|
JNIEXPORT void JNI_OnUnload_netty_transport_native_epoll(JavaVM* vm, void* reserved) {
|
|
|
|
JNI_OnUnload_netty_transport_native_epoll0(vm, reserved);
|
|
|
|
}
|
|
|
|
|
2017-08-17 21:30:36 +02:00
|
|
|
#ifndef NETTY_BUILD_STATIC
|
2018-08-21 07:53:45 +02:00
|
|
|
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
|
|
|
return JNI_OnLoad_netty_transport_native_epoll0(vm, reserved);
|
|
|
|
}
|
|
|
|
|
2017-08-18 21:58:35 +02:00
|
|
|
JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved) {
|
2018-08-21 07:53:45 +02:00
|
|
|
JNI_OnUnload_netty_transport_native_epoll0(vm, reserved);
|
2017-06-21 20:06:08 +02:00
|
|
|
}
|
2017-08-17 21:30:36 +02:00
|
|
|
#endif /* NETTY_BUILD_STATIC */
|