static jint netty_epoll_native_epollCreate(JNIEnv* env, jclass clazz) { jint efd; if (epoll_create1) { efd = epoll_create1(EPOLL_CLOEXEC); } else { // size will be ignored anyway but must be positive efd = epoll_create(126); } if (efd < 0) { int err = errno; if (epoll_create1) { netty_unix_errors_throwChannelExceptionErrorNo(env, "epoll_create1() failed: ", err); } else { netty_unix_errors_throwChannelExceptionErrorNo(env, "epoll_create() failed: ", err); } return efd; } if (!epoll_create1) { if (fcntl(efd, F_SETFD, FD_CLOEXEC) < 0) { int err = errno; close(efd); netty_unix_errors_throwChannelExceptionErrorNo(env, "fcntl() failed: ", err); return err; } } return efd; }
static void netty_epoll_native_eventFdWrite(JNIEnv* env, jclass clazz, jint fd, jlong value) { jint eventFD = eventfd_write(fd, (eventfd_t) value); if (eventFD < 0) { netty_unix_errors_throwChannelExceptionErrorNo(env, "eventfd_write() failed: ", errno); } }
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); } }
JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_eventFdWrite(JNIEnv* env, jclass clazz, jint fd, jlong value) { jint eventFD = eventfd_write(fd, (eventfd_t) value); if (eventFD < 0) { int err = errno; netty_unix_errors_throwChannelExceptionErrorNo(env, "eventfd_write() failed: ", err); } }
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; }
JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_setTrafficClass(JNIEnv* env, jclass clazz, jint fd, jint optval) { netty_unix_socket_setOption(env, fd, IPPROTO_IP, IP_TOS, &optval, sizeof(optval)); /* Try to set the ipv6 equivalent, but don't throw if this is an ipv4 only socket. */ int rc = setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &optval, sizeof(optval)); if (rc < 0 && errno != ENOPROTOOPT) { netty_unix_errors_throwChannelExceptionErrorNo(env, "setting ipv6 dscp failed: ", errno); } }
JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_eventFd(JNIEnv* env, jclass clazz) { jint eventFD = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); if (eventFD < 0) { int err = errno; netty_unix_errors_throwChannelExceptionErrorNo(env, "eventfd() failed: ", err); } return eventFD; }
static jobjectArray netty_kqueue_bsdsocket_getAcceptFilter(JNIEnv* env, jclass clazz, jint fd) { #ifdef SO_ACCEPTFILTER struct accept_filter_arg af; if (netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, sizeof(af)) == -1) { netty_unix_errors_throwChannelExceptionErrorNo(env, "getsockopt() failed: ", errno); return NULL; } jobjectArray resultArray = (*env)->NewObjectArray(env, 2, stringCls, NULL); (*env)->SetObjectArrayElement(env, resultArray, 0, (*env)->NewStringUTF(env, &af.af_name[0])); (*env)->SetObjectArrayElement(env, resultArray, 1, (*env)->NewStringUTF(env, &af.af_arg[0])); return resultArray; #else // No know replacement on MacOS // Don't throw here because this is used when getting a list of all options. return NULL; #endif }
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); } // JNI Registered Methods Begin static jint netty_epoll_native_eventFd(JNIEnv* env, jclass clazz) { jint eventFD = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); if (eventFD < 0) { netty_unix_errors_throwChannelExceptionErrorNo(env, "eventfd() failed: ", errno); } return eventFD; }
static jint netty_epoll_native_epollWait0(JNIEnv* env, jclass clazz, jint efd, jlong address, jint len, jint timerFd, jint tvSec, jint tvNsec) { struct epoll_event *ev = (struct epoll_event*) (intptr_t) address; int result, err; if (tvSec == 0 && tvNsec == 0) { // Zeros = poll (aka return immediately). do { result = epoll_wait(efd, ev, len, 0); if (result >= 0) { return result; } } while((err = errno) == EINTR); } else { // 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; } } do { result = epoll_wait(efd, ev, len, -1); if (result > 0) { // Detect timeout, and preserve the epoll_wait API. if (result == 1 && ev[0].data.fd == timerFd) { // We assume that timerFD is in ET mode. So we must consume this event to ensure we are notified // of future timer events because ET mode only notifies a single time until the event is consumed. uint64_t timerFireCount; // We don't care what the result is. We just want to consume the wakeup event and reset ET. result = read(timerFd, &timerFireCount, sizeof(uint64_t)); return 0; } return result; } } while((err = errno) == EINTR); } return -err; }
static void netty_kqueue_bsdsocket_setAcceptFilter(JNIEnv* env, jclass clazz, jint fd, jstring afName, jstring afArg) { #ifdef SO_ACCEPTFILTER struct accept_filter_arg af; const char* tmpString = NULL; af.af_name[0] = af.af_arg[0] ='\0'; tmpString = (*env)->GetStringUTFChars(env, afName, NULL); strncat(af.af_name, tmpString, sizeof(af.af_name) / sizeof(af.af_name[0])); (*env)->ReleaseStringUTFChars(env, afName, tmpString); tmpString = (*env)->GetStringUTFChars(env, afArg, NULL); strncat(af.af_arg, tmpString, sizeof(af.af_arg) / sizeof(af.af_arg[0])); (*env)->ReleaseStringUTFChars(env, afArg, tmpString); netty_unix_socket_setOption(env, fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, sizeof(af)); #else // No know replacement on MacOS netty_unix_errors_throwChannelExceptionErrorNo(env, "setsockopt() failed: ", EINVAL); #endif }
JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_setTcpMd5Sig0(JNIEnv* env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jbyteArray key) { struct sockaddr_storage addr; if (netty_unix_socket_initSockaddr(env, address, scopeId, 0, &addr) == -1) { return; } struct tcp_md5sig md5sig; memset(&md5sig, 0, sizeof(md5sig)); md5sig.tcpm_addr.ss_family = addr.ss_family; struct sockaddr_in* ipaddr; struct sockaddr_in6* ip6addr; switch (addr.ss_family) { case AF_INET: ipaddr = (struct sockaddr_in*) &addr; memcpy(&((struct sockaddr_in *) &md5sig.tcpm_addr)->sin_addr, &ipaddr->sin_addr, sizeof(ipaddr->sin_addr)); break; case AF_INET6: ip6addr = (struct sockaddr_in6*) &addr; memcpy(&((struct sockaddr_in6 *) &md5sig.tcpm_addr)->sin6_addr, &ip6addr->sin6_addr, sizeof(ip6addr->sin6_addr)); break; } if (key != NULL) { md5sig.tcpm_keylen = (*env)->GetArrayLength(env, key); (*env)->GetByteArrayRegion(env, key, 0, md5sig.tcpm_keylen, (void *) &md5sig.tcpm_key); if ((*env)->ExceptionCheck(env) == JNI_TRUE) { return; } } if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof(md5sig)) < 0) { netty_unix_errors_throwChannelExceptionErrorNo(env, "setsockopt() failed: ", errno); } }