Decouple Unix from Linux in Native Transport
Motivation: transport-native-epoll is designed to be specific to Linux. However there is native code that can be extracted out and made to work on more Unix like distributions. There are a few steps to be completely decoupled but the first step is to extract out code that can run in a more general Unix environment from the Linux specific code base. Modifications: - Move all non-Linux specific stuff from Native.java into the io.netty.channel.unix package. - io.netty.channel.unix.FileDescriptor will inherit all the native methods that are specific to file descriptors. - io_netty_channel_epoll_Native.[c|h] will only have code that is specific to Linux. Result: Code is decoupled and design is streamlined in FileDescriptor.
This commit is contained in:
parent
1c93e04bdc
commit
e319a37a8b
File diff suppressed because it is too large
Load Diff
@ -41,48 +41,16 @@ jint Java_io_netty_channel_epoll_Native_epollWait0(JNIEnv* env, jclass clazz, ji
|
|||||||
jint Java_io_netty_channel_epoll_Native_epollCtlAdd0(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags);
|
jint Java_io_netty_channel_epoll_Native_epollCtlAdd0(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags);
|
||||||
jint Java_io_netty_channel_epoll_Native_epollCtlMod0(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags);
|
jint Java_io_netty_channel_epoll_Native_epollCtlMod0(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags);
|
||||||
jint Java_io_netty_channel_epoll_Native_epollCtlDel0(JNIEnv* env, jclass clazz, jint efd, jint fd);
|
jint Java_io_netty_channel_epoll_Native_epollCtlDel0(JNIEnv* env, jclass clazz, jint efd, jint fd);
|
||||||
jint Java_io_netty_channel_epoll_Native_write0(JNIEnv* env, jclass clazz, jint fd, jobject jbuffer, jint pos, jint limit);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_writeAddress0(JNIEnv* env, jclass clazz, jint fd, jlong address, jint pos, jint limit);
|
|
||||||
jlong Java_io_netty_channel_epoll_Native_writev0(JNIEnv* env, jclass clazz, jint fd, jobjectArray buffers, jint offset, jint length);
|
|
||||||
jlong Java_io_netty_channel_epoll_Native_writevAddresses0(JNIEnv* env, jclass clazz, jint fd, jlong memoryAddress, jint length);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_sendTo(JNIEnv* env, jclass clazz, jint fd, jobject jbuffer, jint pos, jint limit, jbyteArray address, jint scopeId, jint port);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_sendToAddress(JNIEnv* env, jclass clazz, jint fd, jlong memoryAddress, jint pos, jint limit, jbyteArray address, jint scopeId, jint port);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_sendToAddresses(JNIEnv* env, jclass clazz, jint fd, jlong memoryAddress, jint length, jbyteArray address, jint scopeId, jint port);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_sendmmsg(JNIEnv* env, jclass clazz, jint fd, jobjectArray packets, jint offset, jint len);
|
jint Java_io_netty_channel_epoll_Native_sendmmsg(JNIEnv* env, jclass clazz, jint fd, jobjectArray packets, jint offset, jint len);
|
||||||
|
|
||||||
jint Java_io_netty_channel_epoll_Native_read0(JNIEnv* env, jclass clazz, jint fd, jobject jbuffer, jint pos, jint limit);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_readAddress0(JNIEnv* env, jclass clazz, jint fd, jlong address, jint pos, jint limit);
|
|
||||||
jobject Java_io_netty_channel_epoll_Native_recvFrom(JNIEnv* env, jclass clazz, jint fd, jobject jbuffer, jint pos, jint limit);
|
|
||||||
jobject Java_io_netty_channel_epoll_Native_recvFromAddress(JNIEnv* env, jclass clazz, jint fd, jlong address, jint pos, jint limit);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_close0(JNIEnv* env, jclass clazz, jint fd);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_shutdown0(JNIEnv* env, jclass clazz, jint fd, jboolean read, jboolean write);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_socketStream(JNIEnv* env, jclass clazz);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_socketDgram(JNIEnv* env, jclass clazz);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_socketDomain(JNIEnv* env, jclass clazz);
|
|
||||||
|
|
||||||
jint Java_io_netty_channel_epoll_Native_bind(JNIEnv* env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jint port);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_bindDomainSocket(JNIEnv* env, jclass clazz, jint fd, jstring address);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_recvFd0(JNIEnv* env, jclass clazz, jint fd);
|
jint Java_io_netty_channel_epoll_Native_recvFd0(JNIEnv* env, jclass clazz, jint fd);
|
||||||
jint Java_io_netty_channel_epoll_Native_sendFd0(JNIEnv* env, jclass clazz, jint socketFd, jint fd);
|
jint Java_io_netty_channel_epoll_Native_sendFd0(JNIEnv* env, jclass clazz, jint socketFd, jint fd);
|
||||||
|
|
||||||
jint Java_io_netty_channel_epoll_Native_listen0(JNIEnv* env, jclass clazz, jint fd, jint backlog);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_connect(JNIEnv* env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jint port);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_connectDomainSocket(JNIEnv* env, jclass clazz, jint fd, jstring address);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_finishConnect0(JNIEnv* env, jclass clazz, jint fd);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_accept0(JNIEnv* env, jclass clazz, jint fd, jbyteArray acceptedAddress);
|
|
||||||
jlong Java_io_netty_channel_epoll_Native_sendfile0(JNIEnv* env, jclass clazz, jint fd, jobject fileRegion, jlong base_off, jlong off, jlong len);
|
jlong Java_io_netty_channel_epoll_Native_sendfile0(JNIEnv* env, jclass clazz, jint fd, jobject fileRegion, jlong base_off, jlong off, jlong len);
|
||||||
jbyteArray Java_io_netty_channel_epoll_Native_remoteAddress0(JNIEnv* env, jclass clazz, jint fd);
|
|
||||||
jbyteArray Java_io_netty_channel_epoll_Native_localAddress0(JNIEnv* env, jclass clazz, jint fd);
|
|
||||||
void Java_io_netty_channel_epoll_Native_setReuseAddress(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
void Java_io_netty_channel_epoll_Native_setReuseAddress(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
||||||
void Java_io_netty_channel_epoll_Native_setReusePort(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
void Java_io_netty_channel_epoll_Native_setReusePort(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
||||||
void Java_io_netty_channel_epoll_Native_setTcpNoDelay(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
|
||||||
void Java_io_netty_channel_epoll_Native_setReceiveBufferSize(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
|
||||||
void Java_io_netty_channel_epoll_Native_setSendBufferSize(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
|
||||||
void Java_io_netty_channel_epoll_Native_setKeepAlive(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
|
||||||
void Java_io_netty_channel_epoll_Native_setTcpCork(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
|
||||||
void Java_io_netty_channel_epoll_Native_setTcpFastopen(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
void Java_io_netty_channel_epoll_Native_setTcpFastopen(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
||||||
void Java_io_netty_channel_epoll_Native_setTcpNotSentLowAt(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
void Java_io_netty_channel_epoll_Native_setTcpNotSentLowAt(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
||||||
void Java_io_netty_channel_epoll_Native_setSoLinger(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
|
||||||
void Java_io_netty_channel_epoll_Native_setTrafficClass(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
void Java_io_netty_channel_epoll_Native_setTrafficClass(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
||||||
void Java_io_netty_channel_epoll_Native_setBroadcast(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
void Java_io_netty_channel_epoll_Native_setBroadcast(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
||||||
void Java_io_netty_channel_epoll_Native_setTcpKeepIdle(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
void Java_io_netty_channel_epoll_Native_setTcpKeepIdle(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
||||||
@ -92,19 +60,14 @@ void Java_io_netty_channel_epoll_Native_setIpFreeBind(JNIEnv* env, jclass clazz,
|
|||||||
|
|
||||||
jint Java_io_netty_channel_epoll_Native_isReuseAddresss(JNIEnv* env, jclass clazz, jint fd);
|
jint Java_io_netty_channel_epoll_Native_isReuseAddresss(JNIEnv* env, jclass clazz, jint fd);
|
||||||
jint Java_io_netty_channel_epoll_Native_isReusePort(JNIEnv* env, jclass clazz, jint fd);
|
jint Java_io_netty_channel_epoll_Native_isReusePort(JNIEnv* env, jclass clazz, jint fd);
|
||||||
jint Java_io_netty_channel_epoll_Native_isTcpNoDelay(JNIEnv* env, jclass clazz, jint fd);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_getReceiveBufferSize(JNIEnv* env, jclass clazz, jint fd);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_getSendBufferSize(JNIEnv* env, jclass clazz, jint fd);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_isTcpCork(JNIEnv* env, jclass clazz, jint fd);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_getTcpNotSentLowAt(JNIEnv* env, jclass clazz, jint fd);
|
jint Java_io_netty_channel_epoll_Native_getTcpNotSentLowAt(JNIEnv* env, jclass clazz, jint fd);
|
||||||
jint Java_io_netty_channel_epoll_Native_getSoLinger(JNIEnv* env, jclass clazz, jint fd);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_getTrafficClass(JNIEnv* env, jclass clazz, jint fd);
|
jint Java_io_netty_channel_epoll_Native_getTrafficClass(JNIEnv* env, jclass clazz, jint fd);
|
||||||
jint Java_io_netty_channel_epoll_Native_isBroadcast(JNIEnv* env, jclass clazz, jint fd);
|
jint Java_io_netty_channel_epoll_Native_isBroadcast(JNIEnv* env, jclass clazz, jint fd);
|
||||||
jint Java_io_netty_channel_epoll_Native_getTcpKeepIdle(JNIEnv* env, jclass clazz, jint fd);
|
jint Java_io_netty_channel_epoll_Native_getTcpKeepIdle(JNIEnv* env, jclass clazz, jint fd);
|
||||||
jint Java_io_netty_channel_epoll_Native_getTcpKeepIntvl(JNIEnv* env, jclass clazz, jint fd);
|
jint Java_io_netty_channel_epoll_Native_getTcpKeepIntvl(JNIEnv* env, jclass clazz, jint fd);
|
||||||
jint Java_io_netty_channel_epoll_Native_getTcpKeepCnt(JNIEnv* env, jclass clazz, jint fd);
|
jint Java_io_netty_channel_epoll_Native_getTcpKeepCnt(JNIEnv* env, jclass clazz, jint fd);
|
||||||
jint Java_io_netty_channel_epoll_Native_getSoError(JNIEnv* env, jclass clazz, jint fd);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_isIpFreeBind(JNIEnv* env, jclass clazz, jint fd);
|
jint Java_io_netty_channel_epoll_Native_isIpFreeBind(JNIEnv* env, jclass clazz, jint fd);
|
||||||
|
void Java_io_netty_channel_epoll_Native_tcpInfo0(JNIEnv* env, jclass clazz, jint fd, jintArray array);
|
||||||
|
|
||||||
jstring Java_io_netty_channel_epoll_Native_kernelVersion(JNIEnv* env, jclass clazz);
|
jstring Java_io_netty_channel_epoll_Native_kernelVersion(JNIEnv* env, jclass clazz);
|
||||||
jint Java_io_netty_channel_epoll_Native_iovMax(JNIEnv* env, jclass clazz);
|
jint Java_io_netty_channel_epoll_Native_iovMax(JNIEnv* env, jclass clazz);
|
||||||
@ -113,15 +76,6 @@ jlong Java_io_netty_channel_epoll_Native_ssizeMax(JNIEnv* env, jclass clazz);
|
|||||||
jboolean Java_io_netty_channel_epoll_Native_isSupportingSendmmsg(JNIEnv* env, jclass clazz);
|
jboolean Java_io_netty_channel_epoll_Native_isSupportingSendmmsg(JNIEnv* env, jclass clazz);
|
||||||
jboolean Java_io_netty_channel_epoll_Native_isSupportingTcpFastopen(JNIEnv* env, jclass clazz);
|
jboolean Java_io_netty_channel_epoll_Native_isSupportingTcpFastopen(JNIEnv* env, jclass clazz);
|
||||||
|
|
||||||
jint Java_io_netty_channel_epoll_Native_errnoENOTCONN(JNIEnv* env, jclass clazz);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_errnoEBADF(JNIEnv* env, jclass clazz);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_errnoEPIPE(JNIEnv* env, jclass clazz);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_errnoECONNRESET(JNIEnv* env, jclass clazz);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_errnoEAGAIN(JNIEnv* env, jclass clazz);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_errnoEWOULDBLOCK(JNIEnv* env, jclass clazz);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_errnoEINPROGRESS(JNIEnv* env, jclass clazz);
|
|
||||||
jstring Java_io_netty_channel_epoll_Native_strError(JNIEnv* env, jclass clazz, jint err);
|
|
||||||
|
|
||||||
jint Java_io_netty_channel_epoll_Native_epollin(JNIEnv* env, jclass clazz);
|
jint Java_io_netty_channel_epoll_Native_epollin(JNIEnv* env, jclass clazz);
|
||||||
jint Java_io_netty_channel_epoll_Native_epollout(JNIEnv* env, jclass clazz);
|
jint Java_io_netty_channel_epoll_Native_epollout(JNIEnv* env, jclass clazz);
|
||||||
jint Java_io_netty_channel_epoll_Native_epollrdhup(JNIEnv* env, jclass clazz);
|
jint Java_io_netty_channel_epoll_Native_epollrdhup(JNIEnv* env, jclass clazz);
|
||||||
@ -130,7 +84,6 @@ jint Java_io_netty_channel_epoll_Native_epollerr(JNIEnv* env, jclass clazz);
|
|||||||
jint Java_io_netty_channel_epoll_Native_sizeofEpollEvent(JNIEnv* env, jclass clazz);
|
jint Java_io_netty_channel_epoll_Native_sizeofEpollEvent(JNIEnv* env, jclass clazz);
|
||||||
jint Java_io_netty_channel_epoll_Native_offsetofEpollData(JNIEnv* env, jclass clazz);
|
jint Java_io_netty_channel_epoll_Native_offsetofEpollData(JNIEnv* env, jclass clazz);
|
||||||
|
|
||||||
jlong Java_io_netty_channel_epoll_Native_pipe0(JNIEnv* env, jclass clazz);
|
|
||||||
jint Java_io_netty_channel_epoll_Native_splice0(JNIEnv* env, jclass clazz, jint fd, jlong offIn, jint fdOut, jlong offOut, jlong len);
|
jint Java_io_netty_channel_epoll_Native_splice0(JNIEnv* env, jclass clazz, jint fd, jlong offIn, jint fdOut, jlong offOut, jlong len);
|
||||||
|
|
||||||
jint Java_io_netty_channel_epoll_Native_tcpMd5SigMaxKeyLen(JNIEnv* env, jclass clazz);
|
jint Java_io_netty_channel_epoll_Native_tcpMd5SigMaxKeyLen(JNIEnv* env, jclass clazz);
|
||||||
|
191
transport-native-epoll/src/main/c/io_netty_channel_unix_Errors.c
Normal file
191
transport-native-epoll/src/main/c/io_netty_channel_unix_Errors.c
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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.
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "netty_unix_errors.h"
|
||||||
|
#include "io_netty_channel_unix_Errors.h"
|
||||||
|
|
||||||
|
static jclass runtimeExceptionClass = NULL;
|
||||||
|
static jclass channelExceptionClass = NULL;
|
||||||
|
static jclass ioExceptionClass = NULL;
|
||||||
|
static jclass closedChannelExceptionClass = NULL;
|
||||||
|
static jmethodID closedChannelExceptionMethodId = NULL;
|
||||||
|
|
||||||
|
/** Notice: every usage of exceptionMessage needs to release the allocated memory for the sequence of char */
|
||||||
|
static char* exceptionMessage(char* msg, int error) {
|
||||||
|
if (error < 0) {
|
||||||
|
// some functions return negative values
|
||||||
|
// and it's hard to keep track of when to send -error and when not
|
||||||
|
// this will just take care when things are forgotten
|
||||||
|
// what would generate a proper error
|
||||||
|
error = error * -1;
|
||||||
|
}
|
||||||
|
//strerror is returning a constant, so no need to free anything coming from strerror
|
||||||
|
char* err = strerror(error);
|
||||||
|
char* result = malloc(strlen(msg) + strlen(err) + 1);
|
||||||
|
strcpy(result, msg);
|
||||||
|
strcat(result, err);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exported C methods
|
||||||
|
void netty_unix_errors_throwRuntimeException(JNIEnv* env, char* message) {
|
||||||
|
(*env)->ThrowNew(env, runtimeExceptionClass, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void netty_unix_errors_throwRuntimeExceptionErrorNo(JNIEnv* env, char* message, int errorNumber) {
|
||||||
|
char* allocatedMessage = exceptionMessage(message, errorNumber);
|
||||||
|
(*env)->ThrowNew(env, runtimeExceptionClass, allocatedMessage);
|
||||||
|
free(allocatedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void netty_unix_errors_throwChannelExceptionErrorNo(JNIEnv* env, char* message, int errorNumber) {
|
||||||
|
char* allocatedMessage = exceptionMessage(message, errorNumber);
|
||||||
|
(*env)->ThrowNew(env, channelExceptionClass, allocatedMessage);
|
||||||
|
free(allocatedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void netty_unix_errors_throwIOException(JNIEnv* env, char* message) {
|
||||||
|
(*env)->ThrowNew(env, ioExceptionClass, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void netty_unix_errors_throwIOExceptionErrorNo(JNIEnv* env, char* message, int errorNumber) {
|
||||||
|
char* allocatedMessage = exceptionMessage(message, errorNumber);
|
||||||
|
(*env)->ThrowNew(env, ioExceptionClass, allocatedMessage);
|
||||||
|
free(allocatedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void netty_unix_errors_throwClosedChannelException(JNIEnv* env) {
|
||||||
|
jobject exception = (*env)->NewObject(env, closedChannelExceptionClass, closedChannelExceptionMethodId);
|
||||||
|
(*env)->Throw(env, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
void netty_unix_errors_throwOutOfMemoryError(JNIEnv* env) {
|
||||||
|
jclass exceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
|
||||||
|
(*env)->ThrowNew(env, exceptionClass, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
jint netty_unix_errors_JNI_OnLoad(JNIEnv* env) {
|
||||||
|
jclass localRuntimeExceptionClass = (*env)->FindClass(env, "java/lang/RuntimeException");
|
||||||
|
if (localRuntimeExceptionClass == NULL) {
|
||||||
|
// pending exception...
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
runtimeExceptionClass = (jclass) (*env)->NewGlobalRef(env, localRuntimeExceptionClass);
|
||||||
|
if (runtimeExceptionClass == NULL) {
|
||||||
|
// out-of-memory!
|
||||||
|
netty_unix_errors_throwOutOfMemoryError(env);
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
jclass localChannelExceptionClass = (*env)->FindClass(env, "io/netty/channel/ChannelException");
|
||||||
|
if (localChannelExceptionClass == NULL) {
|
||||||
|
// pending exception...
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
channelExceptionClass = (jclass) (*env)->NewGlobalRef(env, localChannelExceptionClass);
|
||||||
|
if (channelExceptionClass == NULL) {
|
||||||
|
// out-of-memory!
|
||||||
|
netty_unix_errors_throwOutOfMemoryError(env);
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cache classes that are used within other jni methods for performance reasons
|
||||||
|
jclass localClosedChannelExceptionClass = (*env)->FindClass(env, "java/nio/channels/ClosedChannelException");
|
||||||
|
if (localClosedChannelExceptionClass == NULL) {
|
||||||
|
// pending exception...
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
closedChannelExceptionClass = (jclass) (*env)->NewGlobalRef(env, localClosedChannelExceptionClass);
|
||||||
|
if (closedChannelExceptionClass == NULL) {
|
||||||
|
// out-of-memory!
|
||||||
|
netty_unix_errors_throwOutOfMemoryError(env);
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
closedChannelExceptionMethodId = (*env)->GetMethodID(env, closedChannelExceptionClass, "<init>", "()V");
|
||||||
|
if (closedChannelExceptionMethodId == NULL) {
|
||||||
|
netty_unix_errors_throwRuntimeException(env, "failed to get method ID: ClosedChannelException.<init>()");
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
jclass localIoExceptionClass = (*env)->FindClass(env, "java/io/IOException");
|
||||||
|
if (localIoExceptionClass == NULL) {
|
||||||
|
// pending exception...
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
ioExceptionClass = (jclass) (*env)->NewGlobalRef(env, localIoExceptionClass);
|
||||||
|
if (ioExceptionClass == NULL) {
|
||||||
|
// out-of-memory!
|
||||||
|
netty_unix_errors_throwOutOfMemoryError(env);
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JNI_VERSION_1_6;
|
||||||
|
}
|
||||||
|
|
||||||
|
void netty_unix_errors_JNI_OnUnLoad(JNIEnv* env) {
|
||||||
|
// delete global references so the GC can collect them
|
||||||
|
if (runtimeExceptionClass != NULL) {
|
||||||
|
(*env)->DeleteGlobalRef(env, runtimeExceptionClass);
|
||||||
|
runtimeExceptionClass = NULL;
|
||||||
|
}
|
||||||
|
if (channelExceptionClass != NULL) {
|
||||||
|
(*env)->DeleteGlobalRef(env, channelExceptionClass);
|
||||||
|
channelExceptionClass = NULL;
|
||||||
|
}
|
||||||
|
if (ioExceptionClass != NULL) {
|
||||||
|
(*env)->DeleteGlobalRef(env, ioExceptionClass);
|
||||||
|
ioExceptionClass = NULL;
|
||||||
|
}
|
||||||
|
if (closedChannelExceptionClass != NULL) {
|
||||||
|
(*env)->DeleteGlobalRef(env, closedChannelExceptionClass);
|
||||||
|
closedChannelExceptionClass = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exported JNI Methods
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Errors_errnoENOTCONN(JNIEnv* env, jclass clazz) {
|
||||||
|
return ENOTCONN;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Errors_errnoEBADF(JNIEnv* env, jclass clazz) {
|
||||||
|
return EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Errors_errnoEPIPE(JNIEnv* env, jclass clazz) {
|
||||||
|
return EPIPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Errors_errnoECONNRESET(JNIEnv* env, jclass clazz) {
|
||||||
|
return ECONNRESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Errors_errnoEAGAIN(JNIEnv* env, jclass clazz) {
|
||||||
|
return EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Errors_errnoEWOULDBLOCK(JNIEnv* env, jclass clazz) {
|
||||||
|
return EWOULDBLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Errors_errnoEINPROGRESS(JNIEnv* env, jclass clazz) {
|
||||||
|
return EINPROGRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jstring JNICALL Java_io_netty_channel_unix_Errors_strError(JNIEnv* env, jclass clazz, jint error) {
|
||||||
|
return (*env)->NewStringUTF(env, strerror(error));
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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.
|
||||||
|
*/
|
||||||
|
#ifndef IO_NETTY_ERROR_UNIX_H_
|
||||||
|
#define IO_NETTY_ERROR_UNIX_H_
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
// Exported JNI methods
|
||||||
|
jint Java_io_netty_channel_unix_Errors_errnoENOTCONN(JNIEnv* env, jclass clazz);
|
||||||
|
jint Java_io_netty_channel_unix_Errors_errnoEBADF(JNIEnv* env, jclass clazz);
|
||||||
|
jint Java_io_netty_channel_unix_Errors_errnoEPIPE(JNIEnv* env, jclass clazz);
|
||||||
|
jint Java_io_netty_channel_unix_Errors_errnoECONNRESET(JNIEnv* env, jclass clazz);
|
||||||
|
jint Java_io_netty_channel_unix_Errors_errnoEAGAIN(JNIEnv* env, jclass clazz);
|
||||||
|
jint Java_io_netty_channel_unix_Errors_errnoEWOULDBLOCK(JNIEnv* env, jclass clazz);
|
||||||
|
jint Java_io_netty_channel_unix_Errors_errnoEINPROGRESS(JNIEnv* env, jclass clazz);
|
||||||
|
jstring Java_io_netty_channel_unix_Errors_strError(JNIEnv* env, jclass clazz, jint error);
|
||||||
|
|
||||||
|
#endif /* IO_NETTY_ERROR_UNIX_H_ */
|
@ -13,12 +13,126 @@
|
|||||||
* License for the specific language governing permissions and limitations
|
* License for the specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
#include <jni.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
|
#include "netty_unix_errors.h"
|
||||||
|
#include "netty_unix_filedescriptor.h"
|
||||||
#include "io_netty_channel_unix_FileDescriptor.h"
|
#include "io_netty_channel_unix_FileDescriptor.h"
|
||||||
|
|
||||||
|
static jmethodID posId = NULL;
|
||||||
|
static jmethodID limitId = NULL;
|
||||||
|
static jfieldID posFieldId = NULL;
|
||||||
|
static jfieldID limitFieldId = NULL;
|
||||||
|
|
||||||
|
// Optional external methods
|
||||||
|
extern int pipe2(int pipefd[2], int flags) __attribute__((weak));
|
||||||
|
|
||||||
|
static jint _write(JNIEnv* env, jclass clazz, jint fd, void* buffer, jint pos, jint limit) {
|
||||||
|
ssize_t res;
|
||||||
|
int err;
|
||||||
|
do {
|
||||||
|
res = write(fd, buffer + pos, (size_t) (limit - pos));
|
||||||
|
// keep on writing if it was interrupted
|
||||||
|
} while (res == -1 && ((err = errno) == EINTR));
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
return -err;
|
||||||
|
}
|
||||||
|
return (jint) res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jlong _writev(JNIEnv* env, jclass clazz, jint fd, struct iovec* iov, jint length) {
|
||||||
|
ssize_t res;
|
||||||
|
int err;
|
||||||
|
do {
|
||||||
|
res = writev(fd, iov, length);
|
||||||
|
// keep on writing if it was interrupted
|
||||||
|
} while (res == -1 && ((err = errno) == EINTR));
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
return -err;
|
||||||
|
}
|
||||||
|
return (jlong) res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jint _read(JNIEnv* env, jclass clazz, jint fd, void* buffer, jint pos, jint limit) {
|
||||||
|
ssize_t res;
|
||||||
|
int err;
|
||||||
|
do {
|
||||||
|
res = read(fd, buffer + pos, (size_t) (limit - pos));
|
||||||
|
// Keep on reading if we was interrupted
|
||||||
|
} while (res == -1 && ((err = errno) == EINTR));
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
return -err;
|
||||||
|
}
|
||||||
|
return (jint) res;
|
||||||
|
}
|
||||||
|
|
||||||
|
jint netty_unix_filedescriptor_JNI_OnLoad(JNIEnv* env) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void netty_unix_filedescriptor_JNI_OnUnLoad(JNIEnv* env) { }
|
||||||
|
|
||||||
JNIEXPORT int JNICALL Java_io_netty_channel_unix_FileDescriptor_close(JNIEnv* env, jclass clazz, jint fd) {
|
JNIEXPORT int JNICALL Java_io_netty_channel_unix_FileDescriptor_close(JNIEnv* env, jclass clazz, jint fd) {
|
||||||
if (close(fd) < 0) {
|
if (close(fd) < 0) {
|
||||||
return -errno;
|
return -errno;
|
||||||
@ -27,7 +141,6 @@ JNIEXPORT int JNICALL Java_io_netty_channel_unix_FileDescriptor_close(JNIEnv* en
|
|||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT int JNICALL Java_io_netty_channel_unix_FileDescriptor_open(JNIEnv* env, jclass clazz, jstring path) {
|
JNIEXPORT int JNICALL Java_io_netty_channel_unix_FileDescriptor_open(JNIEnv* env, jclass clazz, jstring path) {
|
||||||
|
|
||||||
const char* f_path = (*env)->GetStringUTFChars(env, path, 0);
|
const char* f_path = (*env)->GetStringUTFChars(env, path, 0);
|
||||||
|
|
||||||
int res = open(f_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
int res = open(f_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||||
@ -38,3 +151,95 @@ JNIEXPORT int JNICALL Java_io_netty_channel_unix_FileDescriptor_open(JNIEnv* env
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_FileDescriptor_write(JNIEnv* env, jclass clazz, jint fd, jobject jbuffer, jint pos, jint limit) {
|
||||||
|
// We check that GetDirectBufferAddress will not return NULL in OnLoad
|
||||||
|
return _write(env, clazz, fd, (*env)->GetDirectBufferAddress(env, jbuffer), pos, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_FileDescriptor_writeAddress(JNIEnv* env, jclass clazz, jint fd, jlong address, jint pos, jint limit) {
|
||||||
|
return _write(env, clazz, fd, (void*) address, pos, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JNIEXPORT jlong JNICALL Java_io_netty_channel_unix_FileDescriptor_writevAddresses(JNIEnv* env, jclass clazz, jint fd, jlong memoryAddress, jint length) {
|
||||||
|
struct iovec* iov = (struct iovec*) memoryAddress;
|
||||||
|
return _writev(env, clazz, fd, iov, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jlong JNICALL Java_io_netty_channel_unix_FileDescriptor_writev(JNIEnv* env, jclass clazz, jint fd, jobjectArray buffers, jint offset, jint length) {
|
||||||
|
struct iovec iov[length];
|
||||||
|
int iovidx = 0;
|
||||||
|
int i;
|
||||||
|
int num = offset + length;
|
||||||
|
for (i = offset; i < num; i++) {
|
||||||
|
jobject bufObj = (*env)->GetObjectArrayElement(env, buffers, i);
|
||||||
|
jint pos;
|
||||||
|
// Get the current position using the (*env)->GetIntField if possible and fallback
|
||||||
|
// to slower (*env)->CallIntMethod(...) if needed
|
||||||
|
if (posFieldId == NULL) {
|
||||||
|
pos = (*env)->CallIntMethod(env, bufObj, posId, NULL);
|
||||||
|
} else {
|
||||||
|
pos = (*env)->GetIntField(env, bufObj, posFieldId);
|
||||||
|
}
|
||||||
|
jint limit;
|
||||||
|
// Get the current limit using the (*env)->GetIntField if possible and fallback
|
||||||
|
// to slower (*env)->CallIntMethod(...) if needed
|
||||||
|
if (limitFieldId == NULL) {
|
||||||
|
limit = (*env)->CallIntMethod(env, bufObj, limitId, NULL);
|
||||||
|
} else {
|
||||||
|
limit = (*env)->GetIntField(env, bufObj, limitFieldId);
|
||||||
|
}
|
||||||
|
void* buffer = (*env)->GetDirectBufferAddress(env, bufObj);
|
||||||
|
// We check that GetDirectBufferAddress will not return NULL in OnLoad
|
||||||
|
iov[iovidx].iov_base = buffer + pos;
|
||||||
|
iov[iovidx].iov_len = (size_t) (limit - pos);
|
||||||
|
iovidx++;
|
||||||
|
|
||||||
|
// Explicit delete local reference as otherwise the local references will only be released once the native method returns.
|
||||||
|
// Also there may be a lot of these and JNI specification only specify that 16 must be able to be created.
|
||||||
|
//
|
||||||
|
// See https://github.com/netty/netty/issues/2623
|
||||||
|
(*env)->DeleteLocalRef(env, bufObj);
|
||||||
|
}
|
||||||
|
return _writev(env, clazz, fd, iov, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_FileDescriptor_read(JNIEnv* env, jclass clazz, jint fd, jobject jbuffer, jint pos, jint limit) {
|
||||||
|
// We check that GetDirectBufferAddress will not return NULL in OnLoad
|
||||||
|
return _read(env, clazz, fd, (*env)->GetDirectBufferAddress(env, jbuffer), pos, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_FileDescriptor_readAddress(JNIEnv* env, jclass clazz, jint fd, jlong address, jint pos, jint limit) {
|
||||||
|
return _read(env, clazz, fd, (void*) address, pos, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jlong JNICALL Java_io_netty_channel_unix_FileDescriptor_newPipe(JNIEnv* env, jclass clazz) {
|
||||||
|
int fd[2];
|
||||||
|
if (pipe2) {
|
||||||
|
// we can just use pipe2 and so save extra syscalls;
|
||||||
|
if (pipe2(fd, O_NONBLOCK) != 0) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (pipe(fd) == 0) {
|
||||||
|
if (fcntl(fd[0], F_SETFD, O_NONBLOCK) < 0) {
|
||||||
|
int err = errno;
|
||||||
|
close(fd[0]);
|
||||||
|
close(fd[1]);
|
||||||
|
return -err;
|
||||||
|
}
|
||||||
|
if (fcntl(fd[1], F_SETFD, O_NONBLOCK) < 0) {
|
||||||
|
int err = errno;
|
||||||
|
close(fd[0]);
|
||||||
|
close(fd[1]);
|
||||||
|
return -err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode the fds into a 64 bit value
|
||||||
|
return (((jlong) fd[0]) << 32) | fd[1];
|
||||||
|
}
|
||||||
|
@ -15,5 +15,16 @@
|
|||||||
*/
|
*/
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
|
||||||
int Java_io_netty_channel_unix_FileDescriptor_close(JNIEnv* env, jclass clazz, jint fd);
|
// Exported JNI Methods
|
||||||
int Java_io_netty_channel_unix_FileDescriptor_open(JNIEnv* env, jclass clazz, jstring path);
|
jint Java_io_netty_channel_unix_FileDescriptor_close(JNIEnv* env, jclass clazz, jint fd);
|
||||||
|
jint Java_io_netty_channel_unix_FileDescriptor_open(JNIEnv* env, jclass clazz, jstring path);
|
||||||
|
|
||||||
|
jlong Java_io_netty_channel_unix_FileDescriptor_newPipe(JNIEnv* env, jclass clazz);
|
||||||
|
|
||||||
|
jint Java_io_netty_channel_unix_FileDescriptor_write(JNIEnv* env, jclass clazz, jint fd, jobject jbuffer, jint pos, jint limit);
|
||||||
|
jint Java_io_netty_channel_unix_FileDescriptor_writeAddress(JNIEnv* env, jclass clazz, jint fd, jlong address, jint pos, jint limit);
|
||||||
|
jlong Java_io_netty_channel_unix_FileDescriptor_writev(JNIEnv* env, jclass clazz, jint fd, jobjectArray buffers, jint offset, jint length);
|
||||||
|
jlong Java_io_netty_channel_unix_FileDescriptor_writevAddresses(JNIEnv* env, jclass clazz, jint fd, jlong memoryAddress, jint length);
|
||||||
|
|
||||||
|
jint Java_io_netty_channel_unix_FileDescriptor_read(JNIEnv* env, jclass clazz, jint fd, jobject jbuffer, jint pos, jint limit);
|
||||||
|
jint Java_io_netty_channel_unix_FileDescriptor_readAddress(JNIEnv* env, jclass clazz, jint fd, jlong address, jint pos, jint limit);
|
||||||
|
715
transport-native-epoll/src/main/c/io_netty_channel_unix_Socket.c
Normal file
715
transport-native-epoll/src/main/c/io_netty_channel_unix_Socket.c
Normal file
@ -0,0 +1,715 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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.
|
||||||
|
*/
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
|
||||||
|
#include "netty_unix_errors.h"
|
||||||
|
#include "netty_unix_socket.h"
|
||||||
|
#include "io_netty_channel_unix_Socket.h"
|
||||||
|
|
||||||
|
static jclass datagramSocketAddressClass = NULL;
|
||||||
|
static jmethodID datagramSocketAddrMethodId = NULL;
|
||||||
|
static jmethodID inetSocketAddrMethodId = NULL;
|
||||||
|
static jclass inetSocketAddressClass = NULL;
|
||||||
|
static jclass netUtilClass = NULL;
|
||||||
|
static jmethodID netUtilClassIpv4PreferredMethodId = NULL;
|
||||||
|
static int socketType;
|
||||||
|
static const char* ip4prefix = "::ffff:";
|
||||||
|
|
||||||
|
// Optional external methods
|
||||||
|
extern int accept4(int sockFd, struct sockaddr* addr, socklen_t* addrlen, int flags) __attribute__((weak));
|
||||||
|
|
||||||
|
// macro to calculate the length of a sockaddr_un struct for a given path length.
|
||||||
|
// see sys/un.h#SUN_LEN, this is modified to allow nul bytes
|
||||||
|
#define _UNIX_ADDR_LENGTH(path_len) (uintptr_t) (((struct sockaddr_un *) 0)->sun_path) + path_len
|
||||||
|
|
||||||
|
static jobject createDatagramSocketAddress(JNIEnv* env, const struct sockaddr_storage* addr, int len) {
|
||||||
|
char ipstr[INET6_ADDRSTRLEN];
|
||||||
|
int port;
|
||||||
|
jstring ipString;
|
||||||
|
if (addr->ss_family == AF_INET) {
|
||||||
|
struct sockaddr_in* s = (struct sockaddr_in*) addr;
|
||||||
|
port = ntohs(s->sin_port);
|
||||||
|
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
|
||||||
|
ipString = (*env)->NewStringUTF(env, ipstr);
|
||||||
|
} else {
|
||||||
|
struct sockaddr_in6* s = (struct sockaddr_in6*) addr;
|
||||||
|
port = ntohs(s->sin6_port);
|
||||||
|
inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
|
||||||
|
|
||||||
|
if (strncasecmp(ipstr, ip4prefix, 7) == 0) {
|
||||||
|
// IPv4-mapped-on-IPv6.
|
||||||
|
// Cut of ::ffff: prefix to workaround performance issues when parsing these
|
||||||
|
// addresses in InetAddress.getByName(...).
|
||||||
|
//
|
||||||
|
// See https://github.com/netty/netty/issues/2867
|
||||||
|
ipString = (*env)->NewStringUTF(env, &ipstr[7]);
|
||||||
|
} else {
|
||||||
|
ipString = (*env)->NewStringUTF(env, ipstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jobject socketAddr = (*env)->NewObject(env, datagramSocketAddressClass, datagramSocketAddrMethodId, ipString, port, len);
|
||||||
|
return socketAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int addressLength(const struct sockaddr_storage* addr) {
|
||||||
|
if (addr->ss_family == AF_INET) {
|
||||||
|
return 8;
|
||||||
|
} else {
|
||||||
|
struct sockaddr_in6* s = (struct sockaddr_in6*) addr;
|
||||||
|
if (s->sin6_addr.s6_addr[0] == 0x00 && s->sin6_addr.s6_addr[1] == 0x00 && s->sin6_addr.s6_addr[2] == 0x00 && s->sin6_addr.s6_addr[3] == 0x00 && s->sin6_addr.s6_addr[4] == 0x00
|
||||||
|
&& s->sin6_addr.s6_addr[5] == 0x00 && s->sin6_addr.s6_addr[6] == 0x00 && s->sin6_addr.s6_addr[7] == 0x00 && s->sin6_addr.s6_addr[8] == 0x00 && s->sin6_addr.s6_addr[9] == 0x00
|
||||||
|
&& s->sin6_addr.s6_addr[10] == 0xff && s->sin6_addr.s6_addr[11] == 0xff) {
|
||||||
|
// IPv4-mapped-on-IPv6
|
||||||
|
return 8;
|
||||||
|
} else {
|
||||||
|
return 24;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initInetSocketAddressArray(JNIEnv* env, const struct sockaddr_storage* addr, jbyteArray bArray, int offset, int len) {
|
||||||
|
int port;
|
||||||
|
if (addr->ss_family == AF_INET) {
|
||||||
|
struct sockaddr_in* s = (struct sockaddr_in*) addr;
|
||||||
|
port = ntohs(s->sin_port);
|
||||||
|
|
||||||
|
// Encode address and port into the array
|
||||||
|
unsigned char a[4];
|
||||||
|
a[0] = port >> 24;
|
||||||
|
a[1] = port >> 16;
|
||||||
|
a[2] = port >> 8;
|
||||||
|
a[3] = port;
|
||||||
|
(*env)->SetByteArrayRegion(env, bArray, offset, 4, (jbyte*) &s->sin_addr.s_addr);
|
||||||
|
(*env)->SetByteArrayRegion(env, bArray, offset + 4, 4, (jbyte*) &a);
|
||||||
|
} else {
|
||||||
|
struct sockaddr_in6* s = (struct sockaddr_in6*) addr;
|
||||||
|
port = ntohs(s->sin6_port);
|
||||||
|
|
||||||
|
if (len == 8) {
|
||||||
|
// IPv4-mapped-on-IPv6
|
||||||
|
// Encode port into the array and write it into the jbyteArray
|
||||||
|
unsigned char a[4];
|
||||||
|
a[0] = port >> 24;
|
||||||
|
a[1] = port >> 16;
|
||||||
|
a[2] = port >> 8;
|
||||||
|
a[3] = port;
|
||||||
|
|
||||||
|
// we only need the last 4 bytes for mapped address
|
||||||
|
(*env)->SetByteArrayRegion(env, bArray, offset, 4, (jbyte*) &(s->sin6_addr.s6_addr[12]));
|
||||||
|
(*env)->SetByteArrayRegion(env, bArray, offset + 4, 4, (jbyte*) &a);
|
||||||
|
} else {
|
||||||
|
// Encode scopeid and port into the array
|
||||||
|
unsigned char a[8];
|
||||||
|
a[0] = s->sin6_scope_id >> 24;
|
||||||
|
a[1] = s->sin6_scope_id >> 16;
|
||||||
|
a[2] = s->sin6_scope_id >> 8;
|
||||||
|
a[3] = s->sin6_scope_id;
|
||||||
|
a[4] = port >> 24;
|
||||||
|
a[5] = port >> 16;
|
||||||
|
a[6] = port >> 8;
|
||||||
|
a[7] = port;
|
||||||
|
|
||||||
|
(*env)->SetByteArrayRegion(env, bArray, offset, 16, (jbyte*) &(s->sin6_addr.s6_addr));
|
||||||
|
(*env)->SetByteArrayRegion(env, bArray, offset + 16, 8, (jbyte*) &a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static jbyteArray createInetSocketAddressArray(JNIEnv* env, const struct sockaddr_storage* addr) {
|
||||||
|
int len = addressLength(addr);
|
||||||
|
jbyteArray bArray = (*env)->NewByteArray(env, len);
|
||||||
|
|
||||||
|
initInetSocketAddressArray(env, addr, bArray, 0, len);
|
||||||
|
return bArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jobject createInetSocketAddress(JNIEnv* env, const struct sockaddr_storage* addr) {
|
||||||
|
char ipstr[INET6_ADDRSTRLEN];
|
||||||
|
int port;
|
||||||
|
jstring ipString;
|
||||||
|
if (addr->ss_family == AF_INET) {
|
||||||
|
struct sockaddr_in* s = (struct sockaddr_in*) addr;
|
||||||
|
port = ntohs(s->sin_port);
|
||||||
|
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
|
||||||
|
ipString = (*env)->NewStringUTF(env, ipstr);
|
||||||
|
} else {
|
||||||
|
struct sockaddr_in6* s = (struct sockaddr_in6*) addr;
|
||||||
|
port = ntohs(s->sin6_port);
|
||||||
|
inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
|
||||||
|
if (strncasecmp(ipstr, ip4prefix, 7) == 0) {
|
||||||
|
// IPv4-mapped-on-IPv6.
|
||||||
|
// Cut of ::ffff: prefix to workaround performance issues when parsing these
|
||||||
|
// addresses in InetAddress.getByName(...).
|
||||||
|
//
|
||||||
|
// See https://github.com/netty/netty/issues/2867
|
||||||
|
ipString = (*env)->NewStringUTF(env, &ipstr[7]);
|
||||||
|
} else {
|
||||||
|
ipString = (*env)->NewStringUTF(env, ipstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jobject socketAddr = (*env)->NewObject(env, inetSocketAddressClass, inetSocketAddrMethodId, ipString, port);
|
||||||
|
return socketAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int socket_type(JNIEnv* env) {
|
||||||
|
jboolean ipv4Preferred = (*env)->CallStaticBooleanMethod(env, netUtilClass, netUtilClassIpv4PreferredMethodId);
|
||||||
|
|
||||||
|
if (ipv4Preferred) {
|
||||||
|
// User asked to use ipv4 explicitly.
|
||||||
|
return AF_INET;
|
||||||
|
}
|
||||||
|
int fd = socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
||||||
|
if (fd == -1) {
|
||||||
|
if (errno == EAFNOSUPPORT) {
|
||||||
|
return AF_INET;
|
||||||
|
}
|
||||||
|
return AF_INET6;
|
||||||
|
} else {
|
||||||
|
close(fd);
|
||||||
|
return AF_INET6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static jint _socket(JNIEnv* env, jclass clazz, int type) {
|
||||||
|
int fd = socket(socketType, type | SOCK_NONBLOCK, 0);
|
||||||
|
if (fd == -1) {
|
||||||
|
return -errno;
|
||||||
|
} else if (socketType == AF_INET6) {
|
||||||
|
// Allow to listen /connect ipv4 and ipv6
|
||||||
|
int optval = 0;
|
||||||
|
if (netty_unix_socket_setOption(env, fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)) < 0) {
|
||||||
|
// Something went wrong so close the fd and return here. setOption(...) itself throws the exception already.
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int netty_unix_socket_initSockaddr(JNIEnv* env, jbyteArray address, jint scopeId, jint jport, const struct sockaddr_storage* addr) {
|
||||||
|
uint16_t port = htons((uint16_t) jport);
|
||||||
|
// Use GetPrimitiveArrayCritical and ReleasePrimitiveArrayCritical to signal the VM that we really would like
|
||||||
|
// to not do a memory copy here. This is ok as we not do any blocking action here anyway.
|
||||||
|
// This is important as the VM may suspend GC for the time!
|
||||||
|
jbyte* addressBytes = (*env)->GetPrimitiveArrayCritical(env, address, 0);
|
||||||
|
if (addressBytes == NULL) {
|
||||||
|
// No memory left ?!?!?
|
||||||
|
netty_unix_errors_throwOutOfMemoryError(env);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (socketType == AF_INET6) {
|
||||||
|
struct sockaddr_in6* ip6addr = (struct sockaddr_in6*) addr;
|
||||||
|
ip6addr->sin6_family = AF_INET6;
|
||||||
|
ip6addr->sin6_port = port;
|
||||||
|
|
||||||
|
if (scopeId != 0) {
|
||||||
|
ip6addr->sin6_scope_id = (uint32_t) scopeId;
|
||||||
|
}
|
||||||
|
memcpy(&(ip6addr->sin6_addr.s6_addr), addressBytes, 16);
|
||||||
|
} else {
|
||||||
|
struct sockaddr_in* ipaddr = (struct sockaddr_in*) addr;
|
||||||
|
ipaddr->sin_family = AF_INET;
|
||||||
|
ipaddr->sin_port = port;
|
||||||
|
memcpy(&(ipaddr->sin_addr.s_addr), addressBytes + 12, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
(*env)->ReleasePrimitiveArrayCritical(env, address, addressBytes, JNI_ABORT);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jint _sendTo(JNIEnv* env, jint fd, void* buffer, jint pos, jint limit, jbyteArray address, jint scopeId, jint port) {
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
if (netty_unix_socket_initSockaddr(env, address, scopeId, port, &addr) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t res;
|
||||||
|
int err;
|
||||||
|
do {
|
||||||
|
res = sendto(fd, buffer + pos, (size_t) (limit - pos), 0, (struct sockaddr*) &addr, sizeof(struct sockaddr_storage));
|
||||||
|
// keep on writing if it was interrupted
|
||||||
|
} while (res == -1 && ((err = errno) == EINTR));
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
return -err;
|
||||||
|
}
|
||||||
|
return (jint) res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jobject _recvFrom(JNIEnv* env, jint fd, void* buffer, jint pos, jint limit) {
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
socklen_t addrlen = sizeof(addr);
|
||||||
|
ssize_t res;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
do {
|
||||||
|
res = recvfrom(fd, buffer + pos, (size_t) (limit - pos), 0, (struct sockaddr*) &addr, &addrlen);
|
||||||
|
// Keep on reading if we was interrupted
|
||||||
|
} while (res == -1 && ((err = errno) == EINTR));
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
if (err == EAGAIN || err == EWOULDBLOCK) {
|
||||||
|
// Nothing left to read
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (err == EBADF) {
|
||||||
|
netty_unix_errors_throwClosedChannelException(env);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
netty_unix_errors_throwIOExceptionErrorNo(env, "recvfrom() failed: ", err);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return createDatagramSocketAddress(env, &addr, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
int netty_unix_socket_getOption(JNIEnv* env, jint fd, int level, int optname, void* optval, socklen_t optlen) {
|
||||||
|
int rc = getsockopt(fd, level, optname, optval, &optlen);
|
||||||
|
if (rc < 0) {
|
||||||
|
netty_unix_errors_throwChannelExceptionErrorNo(env, "getsockopt() failed: ", errno);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int netty_unix_socket_setOption(JNIEnv* env, jint fd, int level, int optname, const void* optval, socklen_t len) {
|
||||||
|
int rc = setsockopt(fd, level, optname, optval, len);
|
||||||
|
if (rc < 0) {
|
||||||
|
netty_unix_errors_throwChannelExceptionErrorNo(env, "setsockopt() failed: ", errno);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
jint netty_unix_socket_JNI_OnLoad(JNIEnv* env) {
|
||||||
|
jclass localDatagramSocketAddressClass = (*env)->FindClass(env, "io/netty/channel/unix/DatagramSocketAddress");
|
||||||
|
if (localDatagramSocketAddressClass == NULL) {
|
||||||
|
// pending exception...
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
datagramSocketAddressClass = (jclass) (*env)->NewGlobalRef(env, localDatagramSocketAddressClass);
|
||||||
|
if (datagramSocketAddressClass == NULL) {
|
||||||
|
// out-of-memory!
|
||||||
|
netty_unix_errors_throwOutOfMemoryError(env);
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
datagramSocketAddrMethodId = (*env)->GetMethodID(env, datagramSocketAddressClass, "<init>", "(Ljava/lang/String;II)V");
|
||||||
|
if (datagramSocketAddrMethodId == NULL) {
|
||||||
|
netty_unix_errors_throwRuntimeException(env, "failed to get method ID: DatagramSocketAddress.<init>(String, int, int)");
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
jclass localInetSocketAddressClass = (*env)->FindClass(env, "java/net/InetSocketAddress");
|
||||||
|
if (localInetSocketAddressClass == NULL) {
|
||||||
|
// pending exception...
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
inetSocketAddressClass = (jclass) (*env)->NewGlobalRef(env, localInetSocketAddressClass);
|
||||||
|
if (inetSocketAddressClass == NULL) {
|
||||||
|
// out-of-memory!
|
||||||
|
netty_unix_errors_throwOutOfMemoryError(env);
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
inetSocketAddrMethodId = (*env)->GetMethodID(env, inetSocketAddressClass, "<init>", "(Ljava/lang/String;I)V");
|
||||||
|
if (inetSocketAddrMethodId == NULL) {
|
||||||
|
netty_unix_errors_throwRuntimeException(env, "failed to get method ID: InetSocketAddress.<init>(String, int)");
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
jclass localNetUtilClass = (*env)->FindClass(env, "io/netty/util/NetUtil" );
|
||||||
|
if (localNetUtilClass == NULL) {
|
||||||
|
// pending exception...
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
netUtilClass = (jclass) (*env)->NewGlobalRef(env, localNetUtilClass);
|
||||||
|
if (netUtilClass == NULL) {
|
||||||
|
// out-of-memory!
|
||||||
|
netty_unix_errors_throwOutOfMemoryError(env);
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
netUtilClassIpv4PreferredMethodId = (*env)->GetStaticMethodID(env, netUtilClass, "isIpV4StackPreferred", "()Z" );
|
||||||
|
if (netUtilClassIpv4PreferredMethodId == NULL) {
|
||||||
|
// position method was not found.. something is wrong so bail out
|
||||||
|
netty_unix_errors_throwRuntimeException(env, "failed to get method ID: NetUild.isIpV4StackPreferred()");
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
free(mem);
|
||||||
|
|
||||||
|
socketType = socket_type(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
void netty_unix_socket_JNI_OnUnLoad(JNIEnv* env) {
|
||||||
|
if (datagramSocketAddressClass != NULL) {
|
||||||
|
(*env)->DeleteGlobalRef(env, datagramSocketAddressClass);
|
||||||
|
datagramSocketAddressClass = NULL;
|
||||||
|
}
|
||||||
|
if (inetSocketAddressClass != NULL) {
|
||||||
|
(*env)->DeleteGlobalRef(env, inetSocketAddressClass);
|
||||||
|
inetSocketAddressClass = NULL;
|
||||||
|
}
|
||||||
|
if (netUtilClass != NULL) {
|
||||||
|
(*env)->DeleteGlobalRef(env, netUtilClass);
|
||||||
|
netUtilClass = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_shutdown(JNIEnv* env, jclass clazz, jint fd, jboolean read, jboolean write) {
|
||||||
|
int mode;
|
||||||
|
if (read && write) {
|
||||||
|
mode = SHUT_RDWR;
|
||||||
|
} else if (read) {
|
||||||
|
mode = SHUT_RD;
|
||||||
|
} else if (write) {
|
||||||
|
mode = SHUT_WR;
|
||||||
|
} else {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (shutdown(fd, mode) < 0) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_bind(JNIEnv* env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jint port) {
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
if (netty_unix_socket_initSockaddr(env, address, scopeId, port, &addr) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(fd, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_listen(JNIEnv* env, jclass clazz, jint fd, jint backlog) {
|
||||||
|
if (listen(fd, backlog) == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_connect(JNIEnv* env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jint port) {
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
if (netty_unix_socket_initSockaddr(env, address, scopeId, port, &addr) == -1) {
|
||||||
|
// A runtime exception was thrown
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res;
|
||||||
|
int err;
|
||||||
|
do {
|
||||||
|
res = connect(fd, (struct sockaddr*) &addr, sizeof(addr));
|
||||||
|
} while (res == -1 && ((err = errno) == EINTR));
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
return -err;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_finishConnect(JNIEnv* env, jclass clazz, jint fd) {
|
||||||
|
// connect may be done
|
||||||
|
// return true if connection finished successfully
|
||||||
|
// return false if connection is still in progress
|
||||||
|
// throw exception if connection failed
|
||||||
|
int optval;
|
||||||
|
int res = netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_ERROR, &optval, sizeof(optval));
|
||||||
|
if (res != 0) {
|
||||||
|
// getOption failed
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (optval == 0) {
|
||||||
|
// connect succeeded
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -optval;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_accept(JNIEnv* env, jclass clazz, jint fd, jbyteArray acceptedAddress) {
|
||||||
|
jint socketFd;
|
||||||
|
int err;
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
socklen_t address_len = sizeof(addr);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (accept4) {
|
||||||
|
socketFd = accept4(fd, (struct sockaddr*) &addr, &address_len, SOCK_NONBLOCK | SOCK_CLOEXEC);
|
||||||
|
} else {
|
||||||
|
socketFd = accept(fd, (struct sockaddr*) &addr, &address_len);
|
||||||
|
}
|
||||||
|
} while (socketFd == -1 && ((err = errno) == EINTR));
|
||||||
|
|
||||||
|
if (socketFd == -1) {
|
||||||
|
return -err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = addressLength(&addr);
|
||||||
|
|
||||||
|
// Fill in remote address details
|
||||||
|
(*env)->SetByteArrayRegion(env, acceptedAddress, 0, 4, (jbyte*) &len);
|
||||||
|
initInetSocketAddressArray(env, &addr, acceptedAddress, 1, len);
|
||||||
|
|
||||||
|
if (accept4) {
|
||||||
|
return socketFd;
|
||||||
|
} else {
|
||||||
|
// accept4 was not present so need two more sys-calls ...
|
||||||
|
if (fcntl(socketFd, F_SETFD, FD_CLOEXEC) == -1 || fcntl(socketFd, F_SETFL, O_NONBLOCK) == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return socketFd;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jbyteArray JNICALL Java_io_netty_channel_unix_Socket_remoteAddress(JNIEnv* env, jclass clazz, jint fd) {
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
socklen_t len = sizeof(addr);
|
||||||
|
if (getpeername(fd, (struct sockaddr*) &addr, &len) == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return createInetSocketAddressArray(env, &addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jbyteArray JNICALL Java_io_netty_channel_unix_Socket_localAddress(JNIEnv* env, jclass clazz, jint fd) {
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
socklen_t len = sizeof(addr);
|
||||||
|
if (getsockname(fd, (struct sockaddr*) &addr, &len) == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return createInetSocketAddressArray(env, &addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_newSocketDgramFd(JNIEnv* env, jclass clazz) {
|
||||||
|
return _socket(env, clazz, SOCK_DGRAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_newSocketStreamFd(JNIEnv* env, jclass clazz) {
|
||||||
|
return _socket(env, clazz, SOCK_STREAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_newSocketDomainFd(JNIEnv* env, jclass clazz) {
|
||||||
|
int fd = socket(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
||||||
|
if (fd == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_sendTo(JNIEnv* env, jclass clazz, jint fd, jobject jbuffer, jint pos, jint limit, jbyteArray address, jint scopeId, jint port) {
|
||||||
|
// We check that GetDirectBufferAddress will not return NULL in OnLoad
|
||||||
|
return _sendTo(env, fd, (*env)->GetDirectBufferAddress(env, jbuffer), pos, limit, address, scopeId, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_sendToAddress(JNIEnv* env, jclass clazz, jint fd, jlong memoryAddress, jint pos, jint limit ,jbyteArray address, jint scopeId, jint port) {
|
||||||
|
return _sendTo(env, fd, (void*) memoryAddress, pos, limit, address, scopeId, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_sendToAddresses(JNIEnv* env, jclass clazz, jint fd, jlong memoryAddress, jint length, jbyteArray address, jint scopeId, jint port) {
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
|
||||||
|
if (netty_unix_socket_initSockaddr(env, address, scopeId, port, &addr) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct msghdr m;
|
||||||
|
m.msg_name = (void*) &addr;
|
||||||
|
m.msg_namelen = (socklen_t) sizeof(struct sockaddr_storage);
|
||||||
|
m.msg_iov = (struct iovec*) memoryAddress;
|
||||||
|
m.msg_iovlen = length;
|
||||||
|
|
||||||
|
ssize_t res;
|
||||||
|
int err;
|
||||||
|
do {
|
||||||
|
res = sendmsg(fd, &m, 0);
|
||||||
|
// keep on writing if it was interrupted
|
||||||
|
} while (res == -1 && ((err = errno) == EINTR));
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
return -err;
|
||||||
|
}
|
||||||
|
return (jint) res;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobject JNICALL Java_io_netty_channel_unix_Socket_recvFrom(JNIEnv* env, jclass clazz, jint fd, jobject jbuffer, jint pos, jint limit) {
|
||||||
|
// We check that GetDirectBufferAddress will not return NULL in OnLoad
|
||||||
|
return _recvFrom(env, fd, (*env)->GetDirectBufferAddress(env, jbuffer), pos, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobject JNICALL Java_io_netty_channel_unix_Socket_recvFromAddress(JNIEnv* env, jclass clazz, jint fd, jlong address, jint pos, jint limit) {
|
||||||
|
return _recvFrom(env, fd, (void*) address, pos, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_bindDomainSocket(JNIEnv* env, jclass clazz, jint fd, jbyteArray socketPath) {
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
|
||||||
|
jbyte* socket_path = (*env)->GetByteArrayElements(env, socketPath, 0);
|
||||||
|
jint socket_path_len = (*env)->GetArrayLength(env, socketPath);
|
||||||
|
if (socket_path_len > sizeof(addr.sun_path)) {
|
||||||
|
socket_path_len = sizeof(addr.sun_path);
|
||||||
|
}
|
||||||
|
memcpy(addr.sun_path, socket_path, socket_path_len);
|
||||||
|
|
||||||
|
if (unlink(socket_path) == -1 && errno != ENOENT) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = bind(fd, (struct sockaddr*) &addr, _UNIX_ADDR_LENGTH(socket_path_len));
|
||||||
|
(*env)->ReleaseByteArrayElements(env, socketPath, socket_path, 0);
|
||||||
|
|
||||||
|
if (res == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_connectDomainSocket(JNIEnv* env, jclass clazz, jint fd, jbyteArray socketPath) {
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
jint socket_path_len;
|
||||||
|
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
|
||||||
|
jbyte* socket_path = (*env)->GetByteArrayElements(env, socketPath, 0);
|
||||||
|
socket_path_len = (*env)->GetArrayLength(env, socketPath);
|
||||||
|
if (socket_path_len > sizeof(addr.sun_path)) {
|
||||||
|
socket_path_len = sizeof(addr.sun_path);
|
||||||
|
}
|
||||||
|
memcpy(addr.sun_path, socket_path, socket_path_len);
|
||||||
|
|
||||||
|
int res;
|
||||||
|
int err;
|
||||||
|
do {
|
||||||
|
res = connect(fd, (struct sockaddr*) &addr, _UNIX_ADDR_LENGTH(socket_path_len));
|
||||||
|
} while (res == -1 && ((err = errno) == EINTR));
|
||||||
|
|
||||||
|
(*env)->ReleaseByteArrayElements(env, socketPath, socket_path, 0);
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
return -err;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_io_netty_channel_unix_Socket_setTcpNoDelay(JNIEnv* env, jclass clazz, jint fd, jint optval) {
|
||||||
|
netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_io_netty_channel_unix_Socket_setReceiveBufferSize(JNIEnv* env, jclass clazz, jint fd, jint optval) {
|
||||||
|
netty_unix_socket_setOption(env, fd, SOL_SOCKET, SO_RCVBUF, &optval, sizeof(optval));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_io_netty_channel_unix_Socket_setSendBufferSize(JNIEnv* env, jclass clazz, jint fd, jint optval) {
|
||||||
|
netty_unix_socket_setOption(env, fd, SOL_SOCKET, SO_SNDBUF, &optval, sizeof(optval));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_io_netty_channel_unix_Socket_setKeepAlive(JNIEnv* env, jclass clazz, jint fd, jint optval) {
|
||||||
|
netty_unix_socket_setOption(env, fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_io_netty_channel_unix_Socket_setTcpCork(JNIEnv* env, jclass clazz, jint fd, jint optval) {
|
||||||
|
netty_unix_socket_setOption(env, fd, IPPROTO_TCP, TCP_CORK, &optval, sizeof(optval));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_io_netty_channel_unix_Socket_setSoLinger(JNIEnv* env, jclass clazz, jint fd, jint optval) {
|
||||||
|
struct linger solinger;
|
||||||
|
if (optval < 0) {
|
||||||
|
solinger.l_onoff = 0;
|
||||||
|
solinger.l_linger = 0;
|
||||||
|
} else {
|
||||||
|
solinger.l_onoff = 1;
|
||||||
|
solinger.l_linger = optval;
|
||||||
|
}
|
||||||
|
netty_unix_socket_setOption(env, fd, SOL_SOCKET, SO_LINGER, &solinger, sizeof(solinger));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_isTcpNoDelay(JNIEnv* env, jclass clazz, jint fd) {
|
||||||
|
int optval;
|
||||||
|
if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return optval;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_getReceiveBufferSize(JNIEnv* env, jclass clazz, jint fd) {
|
||||||
|
int optval;
|
||||||
|
if (netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_RCVBUF, &optval, sizeof(optval)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return optval;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_getSendBufferSize(JNIEnv* env, jclass clazz, jint fd) {
|
||||||
|
int optval;
|
||||||
|
if (netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_SNDBUF, &optval, sizeof(optval)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return optval;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_isTcpCork(JNIEnv* env, jclass clazz, jint fd) {
|
||||||
|
int optval;
|
||||||
|
if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_CORK, &optval, sizeof(optval)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return optval;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_getSoLinger(JNIEnv* env, jclass clazz, jint fd) {
|
||||||
|
struct linger optval;
|
||||||
|
if (netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_LINGER, &optval, sizeof(optval)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (optval.l_onoff == 0) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return optval.l_linger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_io_netty_channel_unix_Socket_getSoError(JNIEnv* env, jclass clazz, jint fd) {
|
||||||
|
int optval;
|
||||||
|
if (netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_ERROR, &optval, sizeof(optval)) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return optval;
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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.
|
||||||
|
*/
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
// Exported JNI Methods
|
||||||
|
jint Java_io_netty_channel_unix_Socket_shutdown(JNIEnv* env, jclass clazz, jint fd, jboolean read, jboolean write);
|
||||||
|
|
||||||
|
jint Java_io_netty_channel_unix_Socket_newSocketStreamFd(JNIEnv* env, jclass clazz);
|
||||||
|
jint Java_io_netty_channel_unix_Socket_newSocketDgramFd(JNIEnv* env, jclass clazz);
|
||||||
|
jint Java_io_netty_channel_unix_Socket_newSocketDomainFd(JNIEnv* env, jclass clazz);
|
||||||
|
|
||||||
|
jint Java_io_netty_channel_unix_Socket_sendTo(JNIEnv* env, jclass clazz, jint fd, jobject jbuffer, jint pos, jint limit, jbyteArray address, jint scopeId, jint port);
|
||||||
|
jint Java_io_netty_channel_unix_Socket_sendToAddress(JNIEnv* env, jclass clazz, jint fd, jlong memoryAddress, jint pos, jint limit, jbyteArray address, jint scopeId, jint port);
|
||||||
|
jint Java_io_netty_channel_unix_Socket_sendToAddresses(JNIEnv* env, jclass clazz, jint fd, jlong memoryAddress, jint length, jbyteArray address, jint scopeId, jint port);
|
||||||
|
|
||||||
|
jobject Java_io_netty_channel_unix_Socket_recvFrom(JNIEnv* env, jclass clazz, jint fd, jobject jbuffer, jint pos, jint limit);
|
||||||
|
jobject Java_io_netty_channel_unix_Socket_recvFromAddress(JNIEnv* env, jclass clazz, jint fd, jlong address, jint pos, jint limit);
|
||||||
|
|
||||||
|
jint Java_io_netty_channel_unix_Socket_bind(JNIEnv* env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jint port);
|
||||||
|
jint Java_io_netty_channel_unix_Socket_bindDomainSocket(JNIEnv* env, jclass clazz, jint fd, jstring address);
|
||||||
|
jint Java_io_netty_channel_unix_Socket_listen(JNIEnv* env, jclass clazz, jint fd, jint backlog);
|
||||||
|
jint Java_io_netty_channel_unix_Socket_accept(JNIEnv* env, jclass clazz, jint fd, jbyteArray acceptedAddress);
|
||||||
|
|
||||||
|
jint Java_io_netty_channel_unix_Socket_connect(JNIEnv* env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jint port);
|
||||||
|
jint Java_io_netty_channel_unix_Socket_connectDomainSocket(JNIEnv* env, jclass clazz, jint fd, jstring address);
|
||||||
|
jint Java_io_netty_channel_unix_Socket_finishConnect(JNIEnv* env, jclass clazz, jint fd);
|
||||||
|
|
||||||
|
jbyteArray Java_io_netty_channel_unix_Socket_remoteAddress(JNIEnv* env, jclass clazz, jint fd);
|
||||||
|
jbyteArray Java_io_netty_channel_unix_Socket_localAddress(JNIEnv* env, jclass clazz, jint fd);
|
||||||
|
|
||||||
|
void Java_io_netty_channel_unix_Socket_setTcpNoDelay(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
||||||
|
void Java_io_netty_channel_unix_Socket_setReceiveBufferSize(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
||||||
|
void Java_io_netty_channel_unix_Socket_setSendBufferSize(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
||||||
|
void Java_io_netty_channel_unix_Socket_setKeepAlive(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
||||||
|
void Java_io_netty_channel_unix_Socket_setTcpCork(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
||||||
|
void Java_io_netty_channel_unix_Socket_setSoLinger(JNIEnv* env, jclass clazz, jint fd, jint optval);
|
||||||
|
|
||||||
|
jint Java_io_netty_channel_unix_Socket_isTcpNoDelay(JNIEnv* env, jclass clazz, jint fd);
|
||||||
|
jint Java_io_netty_channel_unix_Socket_getReceiveBufferSize(JNIEnv* env, jclass clazz, jint fd);
|
||||||
|
jint Java_io_netty_channel_unix_Socket_getSendBufferSize(JNIEnv* env, jclass clazz, jint fd);
|
||||||
|
jint Java_io_netty_channel_unix_Socket_isTcpCork(JNIEnv* env, jclass clazz, jint fd);
|
||||||
|
jint Java_io_netty_channel_unix_Socket_getSoLinger(JNIEnv* env, jclass clazz, jint fd);
|
||||||
|
jint Java_io_netty_channel_unix_Socket_getSoError(JNIEnv* env, jclass clazz, jint fd);
|
33
transport-native-epoll/src/main/c/netty_unix_errors.h
Normal file
33
transport-native-epoll/src/main/c/netty_unix_errors.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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.
|
||||||
|
*/
|
||||||
|
#ifndef NETTY_UNIX_ERRORS_H_
|
||||||
|
#define NETTY_UNIX_ERRORS_H_
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
void netty_unix_errors_throwRuntimeException(JNIEnv* env, char* message);
|
||||||
|
void netty_unix_errors_throwRuntimeExceptionErrorNo(JNIEnv* env, char* message, int errorNumber);
|
||||||
|
void netty_unix_errors_throwChannelExceptionErrorNo(JNIEnv* env, char* message, int errorNumber);
|
||||||
|
void netty_unix_errors_throwIOException(JNIEnv* env, char* message);
|
||||||
|
void netty_unix_errors_throwIOExceptionErrorNo(JNIEnv* env, char* message, int errorNumber);
|
||||||
|
void netty_unix_errors_throwClosedChannelException(JNIEnv* env);
|
||||||
|
void netty_unix_errors_throwOutOfMemoryError(JNIEnv* env);
|
||||||
|
|
||||||
|
// JNI initialization hooks. Users of this file are responsible for calling these in the JNI_OnLoad and JNI_OnUnload methods.
|
||||||
|
jint netty_unix_errors_JNI_OnLoad(JNIEnv* env);
|
||||||
|
void netty_unix_errors_JNI_OnUnLoad(JNIEnv* env);
|
||||||
|
|
||||||
|
#endif /* NETTY_UNIX_ERRORS_H_ */
|
@ -13,12 +13,13 @@
|
|||||||
* License for the specific language governing permissions and limitations
|
* License for the specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
#ifndef NETTY_UNIX_FILEDESCRIPTOR_H_
|
||||||
|
#define NETTY_UNIX_FILEDESCRIPTOR_H_
|
||||||
|
|
||||||
void throwRuntimeException(JNIEnv* env, char* message);
|
#include <jni.h>
|
||||||
void throwRuntimeExceptionErrorNo(JNIEnv* env, char* message, int errorNumber);
|
|
||||||
void throwChannelExceptionErrorNo(JNIEnv* env, char* message, int errorNumber);
|
// JNI initialization hooks. Users of this file are responsible for calling these in the JNI_OnLoad and JNI_OnUnload methods.
|
||||||
void throwIOException(JNIEnv* env, char* message);
|
jint netty_unix_filedescriptor_JNI_OnLoad(JNIEnv* env);
|
||||||
void throwIOExceptionErrorNo(JNIEnv* env, char* message, int errorNumber);
|
void netty_unix_filedescriptor_JNI_OnUnLoad(JNIEnv* env);
|
||||||
void throwClosedChannelException(JNIEnv* env);
|
|
||||||
void throwOutOfMemoryError(JNIEnv* env);
|
#endif /* NETTY_UNIX_FILEDESCRIPTOR_H_ */
|
||||||
char* exceptionMessage(char* msg, int error);
|
|
31
transport-native-epoll/src/main/c/netty_unix_socket.h
Normal file
31
transport-native-epoll/src/main/c/netty_unix_socket.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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.
|
||||||
|
*/
|
||||||
|
#ifndef NETTY_UNIX_SOCKET_H_
|
||||||
|
#define NETTY_UNIX_SOCKET_H_
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
// External C methods
|
||||||
|
int netty_unix_socket_initSockaddr(JNIEnv* env, jbyteArray address, jint scopeId, jint jport, const struct sockaddr_storage* addr);
|
||||||
|
int netty_unix_socket_getOption(JNIEnv* env, jint fd, int level, int optname, void* optval, socklen_t optlen);
|
||||||
|
int netty_unix_socket_setOption(JNIEnv* env, jint fd, int level, int optname, const void* optval, socklen_t len);
|
||||||
|
|
||||||
|
// JNI initialization hooks. Users of this file are responsible for calling these in the JNI_OnLoad and JNI_OnUnload methods.
|
||||||
|
jint netty_unix_socket_JNI_OnLoad(JNIEnv* env);
|
||||||
|
void netty_unix_socket_JNI_OnUnLoad(JNIEnv* env);
|
||||||
|
|
||||||
|
#endif /* NETTY_UNIX_SOCKET_H_ */
|
@ -27,6 +27,7 @@ import io.netty.channel.EventLoop;
|
|||||||
import io.netty.channel.RecvByteBufAllocator;
|
import io.netty.channel.RecvByteBufAllocator;
|
||||||
import io.netty.channel.socket.ChannelInputShutdownEvent;
|
import io.netty.channel.socket.ChannelInputShutdownEvent;
|
||||||
import io.netty.channel.unix.FileDescriptor;
|
import io.netty.channel.unix.FileDescriptor;
|
||||||
|
import io.netty.channel.unix.Socket;
|
||||||
import io.netty.channel.unix.UnixChannel;
|
import io.netty.channel.unix.UnixChannel;
|
||||||
import io.netty.util.ReferenceCountUtil;
|
import io.netty.util.ReferenceCountUtil;
|
||||||
import io.netty.util.internal.OneTimeTask;
|
import io.netty.util.internal.OneTimeTask;
|
||||||
@ -36,32 +37,27 @@ import java.net.InetSocketAddress;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.UnresolvedAddressException;
|
import java.nio.channels.UnresolvedAddressException;
|
||||||
|
|
||||||
|
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||||
|
|
||||||
abstract class AbstractEpollChannel extends AbstractChannel implements UnixChannel {
|
abstract class AbstractEpollChannel extends AbstractChannel implements UnixChannel {
|
||||||
private static final ChannelMetadata METADATA = new ChannelMetadata(false);
|
private static final ChannelMetadata METADATA = new ChannelMetadata(false);
|
||||||
private final int readFlag;
|
private final int readFlag;
|
||||||
private final FileDescriptor fileDescriptor;
|
private final Socket fileDescriptor;
|
||||||
protected int flags = Native.EPOLLET;
|
protected int flags = Native.EPOLLET;
|
||||||
|
|
||||||
protected volatile boolean active;
|
protected volatile boolean active;
|
||||||
private volatile boolean inputShutdown;
|
private volatile boolean inputShutdown;
|
||||||
|
|
||||||
AbstractEpollChannel(int fd, int flag) {
|
AbstractEpollChannel(Socket fd, int flag) {
|
||||||
this(null, fd, flag, false);
|
this(null, fd, flag, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractEpollChannel(Channel parent, int fd, int flag, boolean active) {
|
AbstractEpollChannel(Channel parent, Socket fd, int flag, boolean active) {
|
||||||
this(parent, new FileDescriptor(fd), flag, active);
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractEpollChannel(Channel parent, FileDescriptor fd, int flag, boolean active) {
|
|
||||||
super(parent);
|
super(parent);
|
||||||
if (fd == null) {
|
fileDescriptor = checkNotNull(fd, "fd");
|
||||||
throw new NullPointerException("fd");
|
|
||||||
}
|
|
||||||
readFlag = flag;
|
readFlag = flag;
|
||||||
flags |= flag;
|
flags |= flag;
|
||||||
this.active = active;
|
this.active = active;
|
||||||
fileDescriptor = fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setFlag(int flag) throws IOException {
|
void setFlag(int flag) throws IOException {
|
||||||
@ -83,7 +79,7 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final FileDescriptor fd() {
|
public final Socket fd() {
|
||||||
return fileDescriptor;
|
return fileDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +105,11 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann
|
|||||||
// deregister from epoll now and shutdown the socket.
|
// deregister from epoll now and shutdown the socket.
|
||||||
doDeregister();
|
doDeregister();
|
||||||
if (active) {
|
if (active) {
|
||||||
shutdown(fd.intValue());
|
try {
|
||||||
|
fd().shutdown(true, true);
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
// The FD will be closed, so if shutdown fails there is nothing we can do.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// Ensure the file descriptor is closed in all cases.
|
// Ensure the file descriptor is closed in all cases.
|
||||||
@ -117,14 +117,6 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Called on {@link #doClose()} before the actual {@link FileDescriptor} is closed.
|
|
||||||
* This implementation does nothing.
|
|
||||||
*/
|
|
||||||
protected void shutdown(int fd) throws IOException {
|
|
||||||
// NOOP
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doDisconnect() throws Exception {
|
protected void doDisconnect() throws Exception {
|
||||||
doClose();
|
doClose();
|
||||||
@ -252,11 +244,10 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann
|
|||||||
int localReadAmount;
|
int localReadAmount;
|
||||||
unsafe().recvBufAllocHandle().attemptedBytesRead(byteBuf.writableBytes());
|
unsafe().recvBufAllocHandle().attemptedBytesRead(byteBuf.writableBytes());
|
||||||
if (byteBuf.hasMemoryAddress()) {
|
if (byteBuf.hasMemoryAddress()) {
|
||||||
localReadAmount = Native.readAddress(
|
localReadAmount = fileDescriptor.readAddress(byteBuf.memoryAddress(), writerIndex, byteBuf.capacity());
|
||||||
fileDescriptor.intValue(), byteBuf.memoryAddress(), writerIndex, byteBuf.capacity());
|
|
||||||
} else {
|
} else {
|
||||||
ByteBuffer buf = byteBuf.internalNioBuffer(writerIndex, byteBuf.writableBytes());
|
ByteBuffer buf = byteBuf.internalNioBuffer(writerIndex, byteBuf.writableBytes());
|
||||||
localReadAmount = Native.read(fileDescriptor.intValue(), buf, buf.position(), buf.limit());
|
localReadAmount = fileDescriptor.read(buf, buf.position(), buf.limit());
|
||||||
}
|
}
|
||||||
if (localReadAmount > 0) {
|
if (localReadAmount > 0) {
|
||||||
byteBuf.writerIndex(writerIndex + localReadAmount);
|
byteBuf.writerIndex(writerIndex + localReadAmount);
|
||||||
@ -272,8 +263,7 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann
|
|||||||
int readerIndex = buf.readerIndex();
|
int readerIndex = buf.readerIndex();
|
||||||
int writerIndex = buf.writerIndex();
|
int writerIndex = buf.writerIndex();
|
||||||
for (int i = writeSpinCount - 1; i >= 0; i--) {
|
for (int i = writeSpinCount - 1; i >= 0; i--) {
|
||||||
int localFlushedAmount = Native.writeAddress(
|
int localFlushedAmount = fileDescriptor.writeAddress(memoryAddress, readerIndex, writerIndex);
|
||||||
fileDescriptor.intValue(), memoryAddress, readerIndex, writerIndex);
|
|
||||||
if (localFlushedAmount > 0) {
|
if (localFlushedAmount > 0) {
|
||||||
writtenBytes += localFlushedAmount;
|
writtenBytes += localFlushedAmount;
|
||||||
if (writtenBytes == readableBytes) {
|
if (writtenBytes == readableBytes) {
|
||||||
@ -294,7 +284,7 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann
|
|||||||
for (int i = writeSpinCount - 1; i >= 0; i--) {
|
for (int i = writeSpinCount - 1; i >= 0; i--) {
|
||||||
int pos = nioBuf.position();
|
int pos = nioBuf.position();
|
||||||
int limit = nioBuf.limit();
|
int limit = nioBuf.limit();
|
||||||
int localFlushedAmount = Native.write(fileDescriptor.intValue(), nioBuf, pos, limit);
|
int localFlushedAmount = fileDescriptor.write(nioBuf, pos, limit);
|
||||||
if (localFlushedAmount > 0) {
|
if (localFlushedAmount > 0) {
|
||||||
nioBuf.position(pos + localFlushedAmount);
|
nioBuf.position(pos + localFlushedAmount);
|
||||||
writtenBytes += localFlushedAmount;
|
writtenBytes += localFlushedAmount;
|
||||||
@ -381,7 +371,7 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann
|
|||||||
if (isOpen()) {
|
if (isOpen()) {
|
||||||
if (Boolean.TRUE.equals(config().getOption(ChannelOption.ALLOW_HALF_CLOSURE))) {
|
if (Boolean.TRUE.equals(config().getOption(ChannelOption.ALLOW_HALF_CLOSURE))) {
|
||||||
try {
|
try {
|
||||||
Native.shutdown(fd().intValue(), true, false);
|
fd().shutdown(true, false);
|
||||||
clearEpollIn0();
|
clearEpollIn0();
|
||||||
pipeline().fireUserEventTriggered(ChannelInputShutdownEvent.INSTANCE);
|
pipeline().fireUserEventTriggered(ChannelInputShutdownEvent.INSTANCE);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -25,6 +25,7 @@ import io.netty.channel.EventLoop;
|
|||||||
import io.netty.channel.RecvByteBufAllocator;
|
import io.netty.channel.RecvByteBufAllocator;
|
||||||
import io.netty.channel.ServerChannel;
|
import io.netty.channel.ServerChannel;
|
||||||
import io.netty.channel.unix.FileDescriptor;
|
import io.netty.channel.unix.FileDescriptor;
|
||||||
|
import io.netty.channel.unix.Socket;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
@ -32,12 +33,31 @@ import java.net.SocketAddress;
|
|||||||
public abstract class AbstractEpollServerChannel extends AbstractEpollChannel implements ServerChannel {
|
public abstract class AbstractEpollServerChannel extends AbstractEpollChannel implements ServerChannel {
|
||||||
private static final ChannelMetadata METADATA = new ChannelMetadata(false, 16);
|
private static final ChannelMetadata METADATA = new ChannelMetadata(false, 16);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #AbstractEpollServerChannel(Socket, boolean)}.
|
||||||
|
*/
|
||||||
protected AbstractEpollServerChannel(int fd) {
|
protected AbstractEpollServerChannel(int fd) {
|
||||||
super(fd, Native.EPOLLIN);
|
this(new Socket(fd), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #AbstractEpollServerChannel(Socket, boolean)}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
protected AbstractEpollServerChannel(FileDescriptor fd) {
|
protected AbstractEpollServerChannel(FileDescriptor fd) {
|
||||||
super(null, fd, Native.EPOLLIN, Native.getSoError(fd.intValue()) == 0);
|
this(new Socket(fd.intValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #AbstractEpollServerChannel(Socket, boolean)}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
protected AbstractEpollServerChannel(Socket fd) {
|
||||||
|
this(fd, fd.getSoError() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractEpollServerChannel(Socket fd, boolean active) {
|
||||||
|
super(null, fd, Native.EPOLLIN, active);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -109,7 +129,7 @@ public abstract class AbstractEpollServerChannel extends AbstractEpollChannel im
|
|||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
do {
|
do {
|
||||||
int socketFd = Native.accept(fd().intValue(), acceptedAddress);
|
int socketFd = fd().accept(acceptedAddress);
|
||||||
if (socketFd == -1) {
|
if (socketFd == -1) {
|
||||||
// this means everything was handled for now
|
// this means everything was handled for now
|
||||||
break;
|
break;
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.channel.epoll;
|
package io.netty.channel.epoll;
|
||||||
|
|
||||||
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufAllocator;
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
import io.netty.buffer.CompositeByteBuf;
|
import io.netty.buffer.CompositeByteBuf;
|
||||||
@ -31,6 +30,7 @@ import io.netty.channel.DefaultFileRegion;
|
|||||||
import io.netty.channel.EventLoop;
|
import io.netty.channel.EventLoop;
|
||||||
import io.netty.channel.RecvByteBufAllocator;
|
import io.netty.channel.RecvByteBufAllocator;
|
||||||
import io.netty.channel.unix.FileDescriptor;
|
import io.netty.channel.unix.FileDescriptor;
|
||||||
|
import io.netty.channel.unix.Socket;
|
||||||
import io.netty.util.internal.EmptyArrays;
|
import io.netty.util.internal.EmptyArrays;
|
||||||
import io.netty.util.internal.MpscLinkedQueueNode;
|
import io.netty.util.internal.MpscLinkedQueueNode;
|
||||||
import io.netty.util.internal.OneTimeTask;
|
import io.netty.util.internal.OneTimeTask;
|
||||||
@ -47,6 +47,9 @@ import java.util.Queue;
|
|||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static io.netty.channel.unix.FileDescriptor.pipe;
|
||||||
|
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||||
|
|
||||||
public abstract class AbstractEpollStreamChannel extends AbstractEpollChannel {
|
public abstract class AbstractEpollStreamChannel extends AbstractEpollChannel {
|
||||||
|
|
||||||
private static final String EXPECTED_TYPES =
|
private static final String EXPECTED_TYPES =
|
||||||
@ -71,33 +74,53 @@ public abstract class AbstractEpollStreamChannel extends AbstractEpollChannel {
|
|||||||
private volatile boolean outputShutdown;
|
private volatile boolean outputShutdown;
|
||||||
|
|
||||||
// Lazy init these if we need to splice(...)
|
// Lazy init these if we need to splice(...)
|
||||||
private int pipeIn = -1;
|
private FileDescriptor pipeIn;
|
||||||
private int pipeOut = -1;
|
private FileDescriptor pipeOut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #AbstractEpollStreamChannel(Channel, Socket)}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
protected AbstractEpollStreamChannel(Channel parent, int fd) {
|
protected AbstractEpollStreamChannel(Channel parent, int fd) {
|
||||||
|
this(parent, new Socket(fd));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #AbstractEpollStreamChannel(Socket, boolean)}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
protected AbstractEpollStreamChannel(int fd) {
|
||||||
|
this(new Socket(fd));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #AbstractEpollStreamChannel(Socket, boolean)}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
protected AbstractEpollStreamChannel(FileDescriptor fd) {
|
||||||
|
this(new Socket(fd.intValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #AbstractEpollStreamChannel(Socket, boolean)}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
protected AbstractEpollStreamChannel(Socket fd) {
|
||||||
|
this(fd, fd.getSoError() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractEpollStreamChannel(Channel parent, Socket fd) {
|
||||||
super(parent, fd, Native.EPOLLIN, true);
|
super(parent, fd, Native.EPOLLIN, true);
|
||||||
// Add EPOLLRDHUP so we are notified once the remote peer close the connection.
|
// Add EPOLLRDHUP so we are notified once the remote peer close the connection.
|
||||||
flags |= Native.EPOLLRDHUP;
|
flags |= Native.EPOLLRDHUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AbstractEpollStreamChannel(int fd) {
|
protected AbstractEpollStreamChannel(Socket fd, boolean active) {
|
||||||
super(fd, Native.EPOLLIN);
|
super(null, fd, Native.EPOLLIN, active);
|
||||||
// Add EPOLLRDHUP so we are notified once the remote peer close the connection.
|
// Add EPOLLRDHUP so we are notified once the remote peer close the connection.
|
||||||
flags |= Native.EPOLLRDHUP;
|
flags |= Native.EPOLLRDHUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AbstractEpollStreamChannel(FileDescriptor fd) {
|
|
||||||
super(null, fd, Native.EPOLLIN, Native.getSoError(fd.intValue()) == 0);
|
|
||||||
|
|
||||||
// Add EPOLLRDHUP so we are notified once the remote peer close the connection.
|
|
||||||
flags |= Native.EPOLLRDHUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void shutdown(int fd) throws IOException {
|
|
||||||
Native.shutdown(fd, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AbstractEpollUnsafe newUnsafe() {
|
protected AbstractEpollUnsafe newUnsafe() {
|
||||||
return new EpollStreamUnsafe();
|
return new EpollStreamUnsafe();
|
||||||
@ -262,7 +285,7 @@ public abstract class AbstractEpollStreamChannel extends AbstractEpollChannel {
|
|||||||
int offset = 0;
|
int offset = 0;
|
||||||
int end = offset + cnt;
|
int end = offset + cnt;
|
||||||
for (int i = writeSpinCount - 1; i >= 0; i--) {
|
for (int i = writeSpinCount - 1; i >= 0; i--) {
|
||||||
long localWrittenBytes = Native.writevAddresses(fd().intValue(), array.memoryAddress(offset), cnt);
|
long localWrittenBytes = fd().writevAddresses(array.memoryAddress(offset), cnt);
|
||||||
if (localWrittenBytes == 0) {
|
if (localWrittenBytes == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -301,7 +324,7 @@ public abstract class AbstractEpollStreamChannel extends AbstractEpollChannel {
|
|||||||
int offset = 0;
|
int offset = 0;
|
||||||
int end = offset + nioBufferCnt;
|
int end = offset + nioBufferCnt;
|
||||||
for (int i = writeSpinCount - 1; i >= 0; i--) {
|
for (int i = writeSpinCount - 1; i >= 0; i--) {
|
||||||
long localWrittenBytes = Native.writev(fd().intValue(), nioBuffers, offset, nioBufferCnt);
|
long localWrittenBytes = fd().writev(nioBuffers, offset, nioBufferCnt);
|
||||||
if (localWrittenBytes == 0) {
|
if (localWrittenBytes == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -511,7 +534,7 @@ public abstract class AbstractEpollStreamChannel extends AbstractEpollChannel {
|
|||||||
|
|
||||||
protected void shutdownOutput0(final ChannelPromise promise) {
|
protected void shutdownOutput0(final ChannelPromise promise) {
|
||||||
try {
|
try {
|
||||||
Native.shutdown(fd().intValue(), false, true);
|
fd().shutdown(false, true);
|
||||||
outputShutdown = true;
|
outputShutdown = true;
|
||||||
promise.setSuccess();
|
promise.setSuccess();
|
||||||
} catch (Throwable cause) {
|
} catch (Throwable cause) {
|
||||||
@ -558,12 +581,12 @@ public abstract class AbstractEpollStreamChannel extends AbstractEpollChannel {
|
|||||||
*/
|
*/
|
||||||
protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
|
protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
|
||||||
if (localAddress != null) {
|
if (localAddress != null) {
|
||||||
Native.bind(fd().intValue(), localAddress);
|
fd().bind(localAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
try {
|
try {
|
||||||
boolean connected = Native.connect(fd().intValue(), remoteAddress);
|
boolean connected = fd().connect(remoteAddress);
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
setFlag(Native.EPOLLOUT);
|
setFlag(Native.EPOLLOUT);
|
||||||
}
|
}
|
||||||
@ -576,10 +599,10 @@ public abstract class AbstractEpollStreamChannel extends AbstractEpollChannel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void safeClosePipe(int pipe) {
|
private void safeClosePipe(FileDescriptor fd) {
|
||||||
if (pipe != -1) {
|
if (fd != null) {
|
||||||
try {
|
try {
|
||||||
Native.close(pipe);
|
fd.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (logger.isWarnEnabled()) {
|
if (logger.isWarnEnabled()) {
|
||||||
logger.warn("Error while closing a pipe", e);
|
logger.warn("Error while closing a pipe", e);
|
||||||
@ -735,7 +758,7 @@ public abstract class AbstractEpollStreamChannel extends AbstractEpollChannel {
|
|||||||
* Finish the connect
|
* Finish the connect
|
||||||
*/
|
*/
|
||||||
private boolean doFinishConnect() throws Exception {
|
private boolean doFinishConnect() throws Exception {
|
||||||
if (Native.finishConnect(fd().intValue())) {
|
if (fd().finishConnect()) {
|
||||||
clearFlag(Native.EPOLLOUT);
|
clearFlag(Native.EPOLLOUT);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -840,13 +863,13 @@ public abstract class AbstractEpollStreamChannel extends AbstractEpollChannel {
|
|||||||
|
|
||||||
abstract boolean spliceIn(RecvByteBufAllocator.Handle handle) throws IOException;
|
abstract boolean spliceIn(RecvByteBufAllocator.Handle handle) throws IOException;
|
||||||
|
|
||||||
protected final int spliceIn(int pipeOut, RecvByteBufAllocator.Handle handle) throws IOException {
|
protected final int spliceIn(FileDescriptor pipeOut, RecvByteBufAllocator.Handle handle) throws IOException {
|
||||||
// calculate the maximum amount of data we are allowed to splice
|
// calculate the maximum amount of data we are allowed to splice
|
||||||
int length = Math.min(handle.guess(), len);
|
int length = Math.min(handle.guess(), len);
|
||||||
int splicedIn = 0;
|
int splicedIn = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Splicing until there is nothing left to splice.
|
// Splicing until there is nothing left to splice.
|
||||||
int localSplicedIn = Native.splice(fd().intValue(), -1, pipeOut, -1, length);
|
int localSplicedIn = Native.splice(fd().intValue(), -1, pipeOut.intValue(), -1, length);
|
||||||
if (localSplicedIn == 0) {
|
if (localSplicedIn == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -885,12 +908,12 @@ public abstract class AbstractEpollStreamChannel extends AbstractEpollChannel {
|
|||||||
// We create the pipe on the target channel as this will allow us to just handle pending writes
|
// We create the pipe on the target channel as this will allow us to just handle pending writes
|
||||||
// later in a correct fashion without get into any ordering issues when spliceTo(...) is called
|
// later in a correct fashion without get into any ordering issues when spliceTo(...) is called
|
||||||
// on multiple Channels pointing to one target Channel.
|
// on multiple Channels pointing to one target Channel.
|
||||||
int pipeOut = ch.pipeOut;
|
FileDescriptor pipeOut = ch.pipeOut;
|
||||||
if (pipeOut == -1) {
|
if (pipeOut == null) {
|
||||||
// Create a new pipe as non was created before.
|
// Create a new pipe as non was created before.
|
||||||
long fds = Native.pipe();
|
FileDescriptor[] pipe = pipe();
|
||||||
ch.pipeIn = (int) (fds >> 32);
|
ch.pipeIn = pipe[0];
|
||||||
pipeOut = ch.pipeOut = (int) fds;
|
pipeOut = ch.pipeOut = pipe[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
int splicedIn = spliceIn(pipeOut, handle);
|
int splicedIn = spliceIn(pipeOut, handle);
|
||||||
@ -946,7 +969,7 @@ public abstract class AbstractEpollStreamChannel extends AbstractEpollChannel {
|
|||||||
public boolean spliceOut() throws Exception {
|
public boolean spliceOut() throws Exception {
|
||||||
assert ch.eventLoop().inEventLoop();
|
assert ch.eventLoop().inEventLoop();
|
||||||
try {
|
try {
|
||||||
int splicedOut = Native.splice(ch.pipeIn, -1, ch.fd().intValue(), -1, len);
|
int splicedOut = Native.splice(ch.pipeIn.intValue(), -1, ch.fd().intValue(), -1, len);
|
||||||
len -= splicedOut;
|
len -= splicedOut;
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
if (autoRead) {
|
if (autoRead) {
|
||||||
@ -991,35 +1014,34 @@ public abstract class AbstractEpollStreamChannel extends AbstractEpollChannel {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pipeIn = -1;
|
|
||||||
int pipeOut = -1;
|
|
||||||
try {
|
try {
|
||||||
long fds = Native.pipe();
|
FileDescriptor[] pipe = pipe();
|
||||||
pipeIn = (int) (fds >> 32);
|
FileDescriptor pipeIn = pipe[0];
|
||||||
pipeOut = (int) fds;
|
FileDescriptor pipeOut = pipe[1];
|
||||||
|
try {
|
||||||
int splicedIn = spliceIn(pipeOut, handle);
|
int splicedIn = spliceIn(pipeOut, handle);
|
||||||
if (splicedIn > 0) {
|
if (splicedIn > 0) {
|
||||||
// Integer.MAX_VALUE is a special value which will result in splice forever.
|
// Integer.MAX_VALUE is a special value which will result in splice forever.
|
||||||
if (len != Integer.MAX_VALUE) {
|
if (len != Integer.MAX_VALUE) {
|
||||||
len -= splicedIn;
|
len -= splicedIn;
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
int splicedOut = Native.splice(pipeIn, -1, fd.intValue(), offset, splicedIn);
|
int splicedOut = Native.splice(pipeIn.intValue(), -1, fd.intValue(), offset, splicedIn);
|
||||||
splicedIn -= splicedOut;
|
splicedIn -= splicedOut;
|
||||||
} while (splicedIn > 0);
|
} while (splicedIn > 0);
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
promise.setSuccess();
|
promise.setSuccess();
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
safeClosePipe(pipeIn);
|
||||||
|
safeClosePipe(pipeOut);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
} catch (Throwable cause) {
|
} catch (Throwable cause) {
|
||||||
promise.setFailure(cause);
|
promise.setFailure(cause);
|
||||||
return true;
|
return true;
|
||||||
} finally {
|
|
||||||
safeClosePipe(pipeIn);
|
|
||||||
safeClosePipe(pipeOut);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.channel.epoll;
|
package io.netty.channel.epoll;
|
||||||
|
|
||||||
|
import io.netty.channel.unix.FileDescriptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if <a href="http://netty.io/wiki/native-transports.html">{@code netty-transport-native-epoll}</a> is supported.
|
* Tells if <a href="http://netty.io/wiki/native-transports.html">{@code netty-transport-native-epoll}</a> is supported.
|
||||||
*/
|
*/
|
||||||
@ -24,24 +26,24 @@ public final class Epoll {
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
Throwable cause = null;
|
Throwable cause = null;
|
||||||
int epollFd = -1;
|
FileDescriptor epollFd = null;
|
||||||
int eventFd = -1;
|
FileDescriptor eventFd = null;
|
||||||
try {
|
try {
|
||||||
epollFd = Native.epollCreate();
|
epollFd = Native.newEpollCreate();
|
||||||
eventFd = Native.eventFd();
|
eventFd = Native.newEventFd();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
cause = t;
|
cause = t;
|
||||||
} finally {
|
} finally {
|
||||||
if (epollFd != -1) {
|
if (epollFd != null) {
|
||||||
try {
|
try {
|
||||||
Native.close(epollFd);
|
epollFd.close();
|
||||||
} catch (Exception ignore) {
|
} catch (Exception ignore) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (eventFd != -1) {
|
if (eventFd != null) {
|
||||||
try {
|
try {
|
||||||
Native.close(eventFd);
|
eventFd.close();
|
||||||
} catch (Exception ignore) {
|
} catch (Exception ignore) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,9 @@ import io.netty.channel.RecvByteBufAllocator;
|
|||||||
import io.netty.channel.socket.DatagramChannel;
|
import io.netty.channel.socket.DatagramChannel;
|
||||||
import io.netty.channel.socket.DatagramChannelConfig;
|
import io.netty.channel.socket.DatagramChannelConfig;
|
||||||
import io.netty.channel.socket.DatagramPacket;
|
import io.netty.channel.socket.DatagramPacket;
|
||||||
|
import io.netty.channel.unix.DatagramSocketAddress;
|
||||||
import io.netty.channel.unix.FileDescriptor;
|
import io.netty.channel.unix.FileDescriptor;
|
||||||
|
import io.netty.channel.unix.Socket;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import io.netty.util.internal.StringUtil;
|
import io.netty.util.internal.StringUtil;
|
||||||
|
|
||||||
@ -45,6 +47,8 @@ import java.nio.channels.NotYetConnectedException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static io.netty.channel.unix.Socket.newSocketDgram;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link DatagramChannel} implementation that uses linux EPOLL Edge-Triggered Mode for
|
* {@link DatagramChannel} implementation that uses linux EPOLL Edge-Triggered Mode for
|
||||||
* maximal performance.
|
* maximal performance.
|
||||||
@ -64,20 +68,24 @@ public final class EpollDatagramChannel extends AbstractEpollChannel implements
|
|||||||
private final EpollDatagramChannelConfig config;
|
private final EpollDatagramChannelConfig config;
|
||||||
|
|
||||||
public EpollDatagramChannel() {
|
public EpollDatagramChannel() {
|
||||||
super(Native.socketDgramFd(), Native.EPOLLIN);
|
super(newSocketDgram(), Native.EPOLLIN);
|
||||||
config = new EpollDatagramChannelConfig(this);
|
config = new EpollDatagramChannelConfig(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link EpollDatagramChannel} from the given {@link FileDescriptor}.
|
* @deprecated Use {@link #EpollDatagramChannel(Socket)}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public EpollDatagramChannel(FileDescriptor fd) {
|
public EpollDatagramChannel(FileDescriptor fd) {
|
||||||
super(null, fd, Native.EPOLLIN, true);
|
this(new Socket(fd.intValue()));
|
||||||
config = new EpollDatagramChannelConfig(this);
|
}
|
||||||
|
|
||||||
|
public EpollDatagramChannel(Socket fd) {
|
||||||
|
super(null, fd, Native.EPOLLIN, true);
|
||||||
// As we create an EpollDatagramChannel from a FileDescriptor we should try to obtain the remote and local
|
// As we create an EpollDatagramChannel from a FileDescriptor we should try to obtain the remote and local
|
||||||
// address from it. This is needed as the FileDescriptor may be bound already.
|
// address from it. This is needed as the FileDescriptor may be bound already.
|
||||||
local = Native.localAddress(fd.intValue());
|
local = fd.localAddress();
|
||||||
|
config = new EpollDatagramChannelConfig(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -276,9 +284,8 @@ public final class EpollDatagramChannel extends AbstractEpollChannel implements
|
|||||||
protected void doBind(SocketAddress localAddress) throws Exception {
|
protected void doBind(SocketAddress localAddress) throws Exception {
|
||||||
InetSocketAddress addr = (InetSocketAddress) localAddress;
|
InetSocketAddress addr = (InetSocketAddress) localAddress;
|
||||||
checkResolvable(addr);
|
checkResolvable(addr);
|
||||||
int fd = fd().intValue();
|
fd().bind(addr);
|
||||||
Native.bind(fd, addr);
|
local = fd().localAddress();
|
||||||
local = Native.localAddress(fd);
|
|
||||||
active = true;
|
active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,18 +379,18 @@ public final class EpollDatagramChannel extends AbstractEpollChannel implements
|
|||||||
final int writtenBytes;
|
final int writtenBytes;
|
||||||
if (data.hasMemoryAddress()) {
|
if (data.hasMemoryAddress()) {
|
||||||
long memoryAddress = data.memoryAddress();
|
long memoryAddress = data.memoryAddress();
|
||||||
writtenBytes = Native.sendToAddress(fd().intValue(), memoryAddress, data.readerIndex(), data.writerIndex(),
|
writtenBytes = fd().sendToAddress(memoryAddress, data.readerIndex(), data.writerIndex(),
|
||||||
remoteAddress.getAddress(), remoteAddress.getPort());
|
remoteAddress.getAddress(), remoteAddress.getPort());
|
||||||
} else if (data instanceof CompositeByteBuf) {
|
} else if (data instanceof CompositeByteBuf) {
|
||||||
IovArray array = IovArrayThreadLocal.get((CompositeByteBuf) data);
|
IovArray array = IovArrayThreadLocal.get((CompositeByteBuf) data);
|
||||||
int cnt = array.count();
|
int cnt = array.count();
|
||||||
assert cnt != 0;
|
assert cnt != 0;
|
||||||
|
|
||||||
writtenBytes = Native.sendToAddresses(fd().intValue(), array.memoryAddress(0),
|
writtenBytes = fd().sendToAddresses(array.memoryAddress(0),
|
||||||
cnt, remoteAddress.getAddress(), remoteAddress.getPort());
|
cnt, remoteAddress.getAddress(), remoteAddress.getPort());
|
||||||
} else {
|
} else {
|
||||||
ByteBuffer nioData = data.internalNioBuffer(data.readerIndex(), data.readableBytes());
|
ByteBuffer nioData = data.internalNioBuffer(data.readerIndex(), data.readableBytes());
|
||||||
writtenBytes = Native.sendTo(fd().intValue(), nioData, nioData.position(), nioData.limit(),
|
writtenBytes = fd().sendTo(nioData, nioData.position(), nioData.limit(),
|
||||||
remoteAddress.getAddress(), remoteAddress.getPort());
|
remoteAddress.getAddress(), remoteAddress.getPort());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,7 +497,7 @@ public final class EpollDatagramChannel extends AbstractEpollChannel implements
|
|||||||
|
|
||||||
checkResolvable(remoteAddress);
|
checkResolvable(remoteAddress);
|
||||||
EpollDatagramChannel.this.remote = remoteAddress;
|
EpollDatagramChannel.this.remote = remoteAddress;
|
||||||
EpollDatagramChannel.this.local = Native.localAddress(fd().intValue());
|
EpollDatagramChannel.this.local = fd().localAddress();
|
||||||
success = true;
|
success = true;
|
||||||
|
|
||||||
// Regardless if the connection attempt was cancelled, channelActive() event should be triggered,
|
// Regardless if the connection attempt was cancelled, channelActive() event should be triggered,
|
||||||
@ -543,12 +550,11 @@ public final class EpollDatagramChannel extends AbstractEpollChannel implements
|
|||||||
final DatagramSocketAddress remoteAddress;
|
final DatagramSocketAddress remoteAddress;
|
||||||
if (data.hasMemoryAddress()) {
|
if (data.hasMemoryAddress()) {
|
||||||
// has a memory address so use optimized call
|
// has a memory address so use optimized call
|
||||||
remoteAddress = Native.recvFromAddress(
|
remoteAddress = fd().recvFromAddress(data.memoryAddress(), data.writerIndex(),
|
||||||
fd().intValue(), data.memoryAddress(), data.writerIndex(), data.capacity());
|
data.capacity());
|
||||||
} else {
|
} else {
|
||||||
ByteBuffer nioData = data.internalNioBuffer(data.writerIndex(), data.writableBytes());
|
ByteBuffer nioData = data.internalNioBuffer(data.writerIndex(), data.writableBytes());
|
||||||
remoteAddress = Native.recvFrom(
|
remoteAddress = fd().recvFrom(nioData, nioData.position(), nioData.limit());
|
||||||
fd().intValue(), nioData, nioData.position(), nioData.limit());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remoteAddress == null) {
|
if (remoteAddress == null) {
|
||||||
@ -558,7 +564,7 @@ public final class EpollDatagramChannel extends AbstractEpollChannel implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
allocHandle.incMessagesRead(1);
|
allocHandle.incMessagesRead(1);
|
||||||
allocHandle.lastBytesRead(remoteAddress.receivedAmount);
|
allocHandle.lastBytesRead(remoteAddress.receivedAmount());
|
||||||
data.writerIndex(data.writerIndex() + allocHandle.lastBytesRead());
|
data.writerIndex(data.writerIndex() + allocHandle.lastBytesRead());
|
||||||
readPending = false;
|
readPending = false;
|
||||||
|
|
||||||
@ -598,21 +604,4 @@ public final class EpollDatagramChannel extends AbstractEpollChannel implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Act as special {@link InetSocketAddress} to be able to easily pass all needed data from JNI without the need
|
|
||||||
* to create more objects then needed.
|
|
||||||
*/
|
|
||||||
static final class DatagramSocketAddress extends InetSocketAddress {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1348596211215015739L;
|
|
||||||
|
|
||||||
// holds the amount of received bytes
|
|
||||||
final int receivedAmount;
|
|
||||||
|
|
||||||
DatagramSocketAddress(String addr, int port, int receivedAmount) {
|
|
||||||
super(addr, port);
|
|
||||||
this.receivedAmount = receivedAmount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -186,23 +186,23 @@ public final class EpollDatagramChannelConfig extends EpollChannelConfig impleme
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSendBufferSize() {
|
public int getSendBufferSize() {
|
||||||
return Native.getSendBufferSize(datagramChannel.fd().intValue());
|
return datagramChannel.fd().getSendBufferSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EpollDatagramChannelConfig setSendBufferSize(int sendBufferSize) {
|
public EpollDatagramChannelConfig setSendBufferSize(int sendBufferSize) {
|
||||||
Native.setSendBufferSize(datagramChannel.fd().intValue(), sendBufferSize);
|
datagramChannel.fd().setSendBufferSize(sendBufferSize);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getReceiveBufferSize() {
|
public int getReceiveBufferSize() {
|
||||||
return Native.getReceiveBufferSize(datagramChannel.fd().intValue());
|
return datagramChannel.fd().getReceiveBufferSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EpollDatagramChannelConfig setReceiveBufferSize(int receiveBufferSize) {
|
public EpollDatagramChannelConfig setReceiveBufferSize(int receiveBufferSize) {
|
||||||
Native.setReceiveBufferSize(datagramChannel.fd().intValue(), receiveBufferSize);
|
datagramChannel.fd().setReceiveBufferSize(receiveBufferSize);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,10 +22,12 @@ import io.netty.channel.ChannelPipeline;
|
|||||||
import io.netty.channel.unix.DomainSocketAddress;
|
import io.netty.channel.unix.DomainSocketAddress;
|
||||||
import io.netty.channel.unix.DomainSocketChannel;
|
import io.netty.channel.unix.DomainSocketChannel;
|
||||||
import io.netty.channel.unix.FileDescriptor;
|
import io.netty.channel.unix.FileDescriptor;
|
||||||
import io.netty.util.internal.OneTimeTask;
|
import io.netty.channel.unix.Socket;
|
||||||
|
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
|
import static io.netty.channel.unix.Socket.newSocketDomain;
|
||||||
|
|
||||||
public final class EpollDomainSocketChannel extends AbstractEpollStreamChannel implements DomainSocketChannel {
|
public final class EpollDomainSocketChannel extends AbstractEpollStreamChannel implements DomainSocketChannel {
|
||||||
private final EpollDomainSocketChannelConfig config = new EpollDomainSocketChannelConfig(this);
|
private final EpollDomainSocketChannelConfig config = new EpollDomainSocketChannelConfig(this);
|
||||||
|
|
||||||
@ -33,22 +35,36 @@ public final class EpollDomainSocketChannel extends AbstractEpollStreamChannel i
|
|||||||
private volatile DomainSocketAddress remote;
|
private volatile DomainSocketAddress remote;
|
||||||
|
|
||||||
public EpollDomainSocketChannel() {
|
public EpollDomainSocketChannel() {
|
||||||
super(Native.socketDomainFd());
|
super(newSocketDomain(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #EpollDomainSocketChannel(Channel, Socket)}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public EpollDomainSocketChannel(Channel parent, FileDescriptor fd) {
|
public EpollDomainSocketChannel(Channel parent, FileDescriptor fd) {
|
||||||
super(parent, fd.intValue());
|
super(parent, new Socket(fd.intValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #EpollDomainSocketChannel(Socket, boolean)}.
|
||||||
|
* <p>
|
||||||
|
* Creates a new {@link EpollDomainSocketChannel} from an existing {@link FileDescriptor}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public EpollDomainSocketChannel(FileDescriptor fd) {
|
||||||
|
super(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EpollDomainSocketChannel(Channel parent, Socket fd) {
|
||||||
|
super(parent, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link EpollDomainSocketChannel} from an existing {@link FileDescriptor}
|
* Creates a new {@link EpollDomainSocketChannel} from an existing {@link FileDescriptor}
|
||||||
*/
|
*/
|
||||||
public EpollDomainSocketChannel(FileDescriptor fd) {
|
public EpollDomainSocketChannel(Socket fd, boolean active) {
|
||||||
super(fd);
|
super(fd, active);
|
||||||
}
|
|
||||||
|
|
||||||
EpollDomainSocketChannel(Channel parent, int fd) {
|
|
||||||
super(parent, fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -68,7 +84,7 @@ public final class EpollDomainSocketChannel extends AbstractEpollStreamChannel i
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doBind(SocketAddress localAddress) throws Exception {
|
protected void doBind(SocketAddress localAddress) throws Exception {
|
||||||
Native.bind(fd().intValue(), localAddress);
|
fd().bind(localAddress);
|
||||||
local = (DomainSocketAddress) localAddress;
|
local = (DomainSocketAddress) localAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import io.netty.channel.EventLoop;
|
|||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
import io.netty.channel.SingleThreadEventLoop;
|
import io.netty.channel.SingleThreadEventLoop;
|
||||||
import io.netty.channel.epoll.AbstractEpollChannel.AbstractEpollUnsafe;
|
import io.netty.channel.epoll.AbstractEpollChannel.AbstractEpollUnsafe;
|
||||||
|
import io.netty.channel.unix.FileDescriptor;
|
||||||
import io.netty.util.collection.IntObjectHashMap;
|
import io.netty.util.collection.IntObjectHashMap;
|
||||||
import io.netty.util.collection.IntObjectMap;
|
import io.netty.util.collection.IntObjectMap;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
@ -49,8 +50,8 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
WAKEN_UP_UPDATER = updater;
|
WAKEN_UP_UPDATER = updater;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final int epollFd;
|
private final FileDescriptor epollFd;
|
||||||
private final int eventFd;
|
private final FileDescriptor eventFd;
|
||||||
private final IntObjectMap<AbstractEpollChannel> channels = new IntObjectHashMap<AbstractEpollChannel>(4096);
|
private final IntObjectMap<AbstractEpollChannel> channels = new IntObjectHashMap<AbstractEpollChannel>(4096);
|
||||||
private final boolean allowGrowing;
|
private final boolean allowGrowing;
|
||||||
private final EpollEventArray events;
|
private final EpollEventArray events;
|
||||||
@ -68,29 +69,29 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
events = new EpollEventArray(maxEvents);
|
events = new EpollEventArray(maxEvents);
|
||||||
}
|
}
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
int epollFd = -1;
|
FileDescriptor epollFd = null;
|
||||||
int eventFd = -1;
|
FileDescriptor eventFd = null;
|
||||||
try {
|
try {
|
||||||
this.epollFd = epollFd = Native.epollCreate();
|
this.epollFd = epollFd = Native.newEpollCreate();
|
||||||
this.eventFd = eventFd = Native.eventFd();
|
this.eventFd = eventFd = Native.newEventFd();
|
||||||
try {
|
try {
|
||||||
Native.epollCtlAdd(epollFd, eventFd, Native.EPOLLIN);
|
Native.epollCtlAdd(epollFd.intValue(), eventFd.intValue(), Native.EPOLLIN);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalStateException("Unable to add eventFd filedescriptor to epoll", e);
|
throw new IllegalStateException("Unable to add eventFd filedescriptor to epoll", e);
|
||||||
}
|
}
|
||||||
success = true;
|
success = true;
|
||||||
} finally {
|
} finally {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
if (epollFd != -1) {
|
if (epollFd != null) {
|
||||||
try {
|
try {
|
||||||
Native.close(epollFd);
|
epollFd.close();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (eventFd != -1) {
|
if (eventFd != null) {
|
||||||
try {
|
try {
|
||||||
Native.close(eventFd);
|
eventFd.close();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
@ -103,7 +104,7 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
protected void wakeup(boolean inEventLoop) {
|
protected void wakeup(boolean inEventLoop) {
|
||||||
if (!inEventLoop && WAKEN_UP_UPDATER.compareAndSet(this, 0, 1)) {
|
if (!inEventLoop && WAKEN_UP_UPDATER.compareAndSet(this, 0, 1)) {
|
||||||
// write to the evfd which will then wake-up epoll_wait(...)
|
// write to the evfd which will then wake-up epoll_wait(...)
|
||||||
Native.eventFdWrite(eventFd, 1L);
|
Native.eventFdWrite(eventFd.intValue(), 1L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +114,7 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
void add(AbstractEpollChannel ch) throws IOException {
|
void add(AbstractEpollChannel ch) throws IOException {
|
||||||
assert inEventLoop();
|
assert inEventLoop();
|
||||||
int fd = ch.fd().intValue();
|
int fd = ch.fd().intValue();
|
||||||
Native.epollCtlAdd(epollFd, fd, ch.flags);
|
Native.epollCtlAdd(epollFd.intValue(), fd, ch.flags);
|
||||||
channels.put(fd, ch);
|
channels.put(fd, ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +123,7 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
*/
|
*/
|
||||||
void modify(AbstractEpollChannel ch) throws IOException {
|
void modify(AbstractEpollChannel ch) throws IOException {
|
||||||
assert inEventLoop();
|
assert inEventLoop();
|
||||||
Native.epollCtlMod(epollFd, ch.fd().intValue(), ch.flags);
|
Native.epollCtlMod(epollFd.intValue(), ch.fd().intValue(), ch.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -136,7 +137,7 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
if (channels.remove(fd) != null) {
|
if (channels.remove(fd) != null) {
|
||||||
// Remove the epoll. This is only needed if it's still open as otherwise it will be automatically
|
// Remove the epoll. This is only needed if it's still open as otherwise it will be automatically
|
||||||
// removed once the file-descriptor is closed.
|
// removed once the file-descriptor is closed.
|
||||||
Native.epollCtlDel(epollFd, ch.fd().intValue());
|
Native.epollCtlDel(epollFd.intValue(), ch.fd().intValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,7 +174,7 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
long timeoutMillis = (selectDeadLineNanos - currentTimeNanos + 500000L) / 1000000L;
|
long timeoutMillis = (selectDeadLineNanos - currentTimeNanos + 500000L) / 1000000L;
|
||||||
if (timeoutMillis <= 0) {
|
if (timeoutMillis <= 0) {
|
||||||
if (selectCnt == 0) {
|
if (selectCnt == 0) {
|
||||||
int ready = Native.epollWait(epollFd, events, 0);
|
int ready = Native.epollWait(epollFd.intValue(), events, 0);
|
||||||
if (ready > 0) {
|
if (ready > 0) {
|
||||||
return ready;
|
return ready;
|
||||||
}
|
}
|
||||||
@ -181,7 +182,7 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int selectedKeys = Native.epollWait(epollFd, events, (int) timeoutMillis);
|
int selectedKeys = Native.epollWait(epollFd.intValue(), events, (int) timeoutMillis);
|
||||||
selectCnt ++;
|
selectCnt ++;
|
||||||
|
|
||||||
if (selectedKeys != 0 || oldWakenUp || wakenUp == 1 || hasTasks() || hasScheduledTasks()) {
|
if (selectedKeys != 0 || oldWakenUp || wakenUp == 1 || hasTasks() || hasScheduledTasks()) {
|
||||||
@ -203,7 +204,7 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
int ready;
|
int ready;
|
||||||
if (hasTasks()) {
|
if (hasTasks()) {
|
||||||
// Non blocking just return what is ready directly without block
|
// Non blocking just return what is ready directly without block
|
||||||
ready = Native.epollWait(epollFd, events, 0);
|
ready = Native.epollWait(epollFd.intValue(), events, 0);
|
||||||
} else {
|
} else {
|
||||||
ready = epollWait(oldWakenUp);
|
ready = epollWait(oldWakenUp);
|
||||||
|
|
||||||
@ -236,7 +237,7 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
// (OK - no wake-up required).
|
// (OK - no wake-up required).
|
||||||
|
|
||||||
if (wakenUp == 1) {
|
if (wakenUp == 1) {
|
||||||
Native.eventFdWrite(eventFd, 1L);
|
Native.eventFdWrite(eventFd.intValue(), 1L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,7 +285,7 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
|
|
||||||
private void closeAll() {
|
private void closeAll() {
|
||||||
try {
|
try {
|
||||||
Native.epollWait(epollFd, events, 0);
|
Native.epollWait(epollFd.intValue(), events, 0);
|
||||||
} catch (IOException ignore) {
|
} catch (IOException ignore) {
|
||||||
// ignore on close
|
// ignore on close
|
||||||
}
|
}
|
||||||
@ -302,9 +303,9 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
private void processReady(EpollEventArray events, int ready) {
|
private void processReady(EpollEventArray events, int ready) {
|
||||||
for (int i = 0; i < ready; i ++) {
|
for (int i = 0; i < ready; i ++) {
|
||||||
final int fd = events.fd(i);
|
final int fd = events.fd(i);
|
||||||
if (fd == eventFd) {
|
if (fd == eventFd.intValue()) {
|
||||||
// consume wakeup event
|
// consume wakeup event
|
||||||
Native.eventFdRead(eventFd);
|
Native.eventFdRead(eventFd.intValue());
|
||||||
} else {
|
} else {
|
||||||
final long ev = events.events(i);
|
final long ev = events.events(i);
|
||||||
|
|
||||||
@ -348,7 +349,7 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
} else {
|
} else {
|
||||||
// We received an event for an fd which we not use anymore. Remove it from the epoll_event set.
|
// We received an event for an fd which we not use anymore. Remove it from the epoll_event set.
|
||||||
try {
|
try {
|
||||||
Native.epollCtlDel(epollFd, fd);
|
Native.epollCtlDel(epollFd.intValue(), fd);
|
||||||
} catch (IOException ignore) {
|
} catch (IOException ignore) {
|
||||||
// This can happen but is nothing we need to worry about as we only try to delete
|
// This can happen but is nothing we need to worry about as we only try to delete
|
||||||
// the fd from the epoll set as we not found it in our mappings. So this call to
|
// the fd from the epoll set as we not found it in our mappings. So this call to
|
||||||
@ -364,12 +365,12 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
|||||||
protected void cleanup() {
|
protected void cleanup() {
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
Native.close(epollFd);
|
epollFd.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("Failed to close the epoll fd.", e);
|
logger.warn("Failed to close the epoll fd.", e);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Native.close(eventFd);
|
eventFd.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("Failed to close the event fd.", e);
|
logger.warn("Failed to close the event fd.", e);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
package io.netty.channel.epoll;
|
package io.netty.channel.epoll;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBufAllocator;
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
import io.netty.channel.Channel;
|
|
||||||
import io.netty.channel.ChannelOption;
|
import io.netty.channel.ChannelOption;
|
||||||
import io.netty.channel.MessageSizeEstimator;
|
import io.netty.channel.MessageSizeEstimator;
|
||||||
import io.netty.channel.RecvByteBufAllocator;
|
import io.netty.channel.RecvByteBufAllocator;
|
||||||
@ -96,11 +95,11 @@ public class EpollServerChannelConfig extends EpollChannelConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getReceiveBufferSize() {
|
public int getReceiveBufferSize() {
|
||||||
return Native.getReceiveBufferSize(channel.fd().intValue());
|
return channel.fd().getReceiveBufferSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public EpollServerChannelConfig setReceiveBufferSize(int receiveBufferSize) {
|
public EpollServerChannelConfig setReceiveBufferSize(int receiveBufferSize) {
|
||||||
Native.setReceiveBufferSize(channel.fd().intValue(), receiveBufferSize);
|
channel.fd().setReceiveBufferSize(receiveBufferSize);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,12 +19,15 @@ import io.netty.channel.Channel;
|
|||||||
import io.netty.channel.unix.DomainSocketAddress;
|
import io.netty.channel.unix.DomainSocketAddress;
|
||||||
import io.netty.channel.unix.FileDescriptor;
|
import io.netty.channel.unix.FileDescriptor;
|
||||||
import io.netty.channel.unix.ServerDomainSocketChannel;
|
import io.netty.channel.unix.ServerDomainSocketChannel;
|
||||||
|
import io.netty.channel.unix.Socket;
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
|
import static io.netty.channel.unix.Socket.newSocketDomain;
|
||||||
|
|
||||||
|
|
||||||
public final class EpollServerDomainSocketChannel extends AbstractEpollServerChannel
|
public final class EpollServerDomainSocketChannel extends AbstractEpollServerChannel
|
||||||
implements ServerDomainSocketChannel {
|
implements ServerDomainSocketChannel {
|
||||||
@ -35,19 +38,31 @@ public final class EpollServerDomainSocketChannel extends AbstractEpollServerCha
|
|||||||
private volatile DomainSocketAddress local;
|
private volatile DomainSocketAddress local;
|
||||||
|
|
||||||
public EpollServerDomainSocketChannel() {
|
public EpollServerDomainSocketChannel() {
|
||||||
super(Native.socketDomainFd());
|
super(newSocketDomain(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated Use {@link #EpollServerDomainSocketChannel(Socket, boolean)}.
|
||||||
* Creates a new {@link EpollServerDomainSocketChannel} from an existing {@link FileDescriptor}.
|
* Creates a new {@link EpollServerDomainSocketChannel} from an existing {@link FileDescriptor}.
|
||||||
*/
|
*/
|
||||||
public EpollServerDomainSocketChannel(FileDescriptor fd) {
|
public EpollServerDomainSocketChannel(FileDescriptor fd) {
|
||||||
super(fd);
|
super(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #EpollServerDomainSocketChannel(Socket, boolean)}.
|
||||||
|
*/
|
||||||
|
public EpollServerDomainSocketChannel(Socket fd) {
|
||||||
|
super(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EpollServerDomainSocketChannel(Socket fd, boolean active) {
|
||||||
|
super(fd, active);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Channel newChildChannel(int fd, byte[] addr, int offset, int len) throws Exception {
|
protected Channel newChildChannel(int fd, byte[] addr, int offset, int len) throws Exception {
|
||||||
return new EpollDomainSocketChannel(this, fd);
|
return new EpollDomainSocketChannel(this, new Socket(fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -57,9 +72,8 @@ public final class EpollServerDomainSocketChannel extends AbstractEpollServerCha
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doBind(SocketAddress localAddress) throws Exception {
|
protected void doBind(SocketAddress localAddress) throws Exception {
|
||||||
int fd = fd().intValue();
|
fd().bind(localAddress);
|
||||||
Native.bind(fd, localAddress);
|
fd().listen(config.getBacklog());
|
||||||
Native.listen(fd, config.getBacklog());
|
|
||||||
local = (DomainSocketAddress) localAddress;
|
local = (DomainSocketAddress) localAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import io.netty.channel.Channel;
|
|||||||
import io.netty.channel.EventLoop;
|
import io.netty.channel.EventLoop;
|
||||||
import io.netty.channel.socket.ServerSocketChannel;
|
import io.netty.channel.socket.ServerSocketChannel;
|
||||||
import io.netty.channel.unix.FileDescriptor;
|
import io.netty.channel.unix.FileDescriptor;
|
||||||
|
import io.netty.channel.unix.Socket;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
@ -27,6 +28,9 @@ import java.util.Collection;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static io.netty.channel.unix.NativeInetAddress.address;
|
||||||
|
import static io.netty.channel.unix.Socket.newSocketStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ServerSocketChannel} implementation that uses linux EPOLL Edge-Triggered Mode for
|
* {@link ServerSocketChannel} implementation that uses linux EPOLL Edge-Triggered Mode for
|
||||||
* maximal performance.
|
* maximal performance.
|
||||||
@ -38,20 +42,40 @@ public final class EpollServerSocketChannel extends AbstractEpollServerChannel i
|
|||||||
private volatile Collection<InetAddress> tcpMd5SigAddresses = Collections.emptyList();
|
private volatile Collection<InetAddress> tcpMd5SigAddresses = Collections.emptyList();
|
||||||
|
|
||||||
public EpollServerSocketChannel() {
|
public EpollServerSocketChannel() {
|
||||||
super(Native.socketStreamFd());
|
super(newSocketStream(), false);
|
||||||
config = new EpollServerSocketChannelConfig(this);
|
config = new EpollServerSocketChannelConfig(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated Use {@link #EpollServerSocketChannel(Socket, boolean)}.
|
||||||
* Creates a new {@link EpollServerSocketChannel} from an existing {@link FileDescriptor}.
|
* Creates a new {@link EpollServerSocketChannel} from an existing {@link FileDescriptor}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public EpollServerSocketChannel(FileDescriptor fd) {
|
public EpollServerSocketChannel(FileDescriptor fd) {
|
||||||
super(fd);
|
// Must call this constructor to ensure this object's local address is configured correctly.
|
||||||
config = new EpollServerSocketChannelConfig(this);
|
// The local address can only be obtained from a Socket object.
|
||||||
|
this(new Socket(fd.intValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #EpollServerSocketChannel(Socket, boolean)}.
|
||||||
|
* Creates a new {@link EpollServerSocketChannel} from an existing {@link Socket}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public EpollServerSocketChannel(Socket fd) {
|
||||||
|
super(fd);
|
||||||
// As we create an EpollServerSocketChannel from a FileDescriptor we should try to obtain the remote and local
|
// As we create an EpollServerSocketChannel from a FileDescriptor we should try to obtain the remote and local
|
||||||
// address from it. This is needed as the FileDescriptor may be bound already.
|
// address from it. This is needed as the FileDescriptor may be bound already.
|
||||||
local = Native.localAddress(fd.intValue());
|
local = fd.localAddress();
|
||||||
|
config = new EpollServerSocketChannelConfig(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EpollServerSocketChannel(Socket fd, boolean active) {
|
||||||
|
super(fd, active);
|
||||||
|
// As we create an EpollServerSocketChannel from a FileDescriptor we should try to obtain the remote and local
|
||||||
|
// address from it. This is needed as the FileDescriptor may be bound already.
|
||||||
|
local = fd.localAddress();
|
||||||
|
config = new EpollServerSocketChannelConfig(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -63,13 +87,12 @@ public final class EpollServerSocketChannel extends AbstractEpollServerChannel i
|
|||||||
protected void doBind(SocketAddress localAddress) throws Exception {
|
protected void doBind(SocketAddress localAddress) throws Exception {
|
||||||
InetSocketAddress addr = (InetSocketAddress) localAddress;
|
InetSocketAddress addr = (InetSocketAddress) localAddress;
|
||||||
checkResolvable(addr);
|
checkResolvable(addr);
|
||||||
int fd = fd().intValue();
|
fd().bind(addr);
|
||||||
Native.bind(fd, addr);
|
local = fd().localAddress();
|
||||||
local = Native.localAddress(fd);
|
|
||||||
if (Native.IS_SUPPORTING_TCP_FASTOPEN && config.getTcpFastopen() > 0) {
|
if (Native.IS_SUPPORTING_TCP_FASTOPEN && config.getTcpFastopen() > 0) {
|
||||||
Native.setTcpFastopen(fd, config.getTcpFastopen());
|
Native.setTcpFastopen(fd().intValue(), config.getTcpFastopen());
|
||||||
}
|
}
|
||||||
Native.listen(fd, config.getBacklog());
|
fd().listen(config.getBacklog());
|
||||||
active = true;
|
active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +118,7 @@ public final class EpollServerSocketChannel extends AbstractEpollServerChannel i
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Channel newChildChannel(int fd, byte[] address, int offset, int len) throws Exception {
|
protected Channel newChildChannel(int fd, byte[] address, int offset, int len) throws Exception {
|
||||||
return new EpollSocketChannel(this, fd, Native.address(address, offset, len));
|
return new EpollSocketChannel(this, new Socket(fd), address(address, offset, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<InetAddress> tcpMd5SigAddresses() {
|
Collection<InetAddress> tcpMd5SigAddresses() {
|
||||||
|
@ -22,6 +22,7 @@ import io.netty.channel.EventLoop;
|
|||||||
import io.netty.channel.socket.ServerSocketChannel;
|
import io.netty.channel.socket.ServerSocketChannel;
|
||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
import io.netty.channel.unix.FileDescriptor;
|
import io.netty.channel.unix.FileDescriptor;
|
||||||
|
import io.netty.channel.unix.Socket;
|
||||||
import io.netty.util.concurrent.GlobalEventExecutor;
|
import io.netty.util.concurrent.GlobalEventExecutor;
|
||||||
import io.netty.util.internal.OneTimeTask;
|
import io.netty.util.internal.OneTimeTask;
|
||||||
|
|
||||||
@ -33,6 +34,8 @@ import java.util.Collections;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import static io.netty.channel.unix.Socket.newSocketStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link SocketChannel} implementation that uses linux EPOLL Edge-Triggered Mode for
|
* {@link SocketChannel} implementation that uses linux EPOLL Edge-Triggered Mode for
|
||||||
* maximal performance.
|
* maximal performance.
|
||||||
@ -45,13 +48,13 @@ public final class EpollSocketChannel extends AbstractEpollStreamChannel impleme
|
|||||||
private volatile InetSocketAddress remote;
|
private volatile InetSocketAddress remote;
|
||||||
private volatile Collection<InetAddress> tcpMd5SigAddresses = Collections.emptyList();
|
private volatile Collection<InetAddress> tcpMd5SigAddresses = Collections.emptyList();
|
||||||
|
|
||||||
EpollSocketChannel(Channel parent, int fd, InetSocketAddress remote) {
|
EpollSocketChannel(Channel parent, Socket fd, InetSocketAddress remote) {
|
||||||
super(parent, fd);
|
super(parent, fd);
|
||||||
config = new EpollSocketChannelConfig(this);
|
config = new EpollSocketChannelConfig(this);
|
||||||
// Directly cache the remote and local addresses
|
// Directly cache the remote and local addresses
|
||||||
// See https://github.com/netty/netty/issues/2359
|
// See https://github.com/netty/netty/issues/2359
|
||||||
this.remote = remote;
|
this.remote = remote;
|
||||||
local = Native.localAddress(fd);
|
local = fd.localAddress();
|
||||||
|
|
||||||
if (parent instanceof EpollServerSocketChannel) {
|
if (parent instanceof EpollServerSocketChannel) {
|
||||||
tcpMd5SigAddresses = ((EpollServerSocketChannel) parent).tcpMd5SigAddresses();
|
tcpMd5SigAddresses = ((EpollServerSocketChannel) parent).tcpMd5SigAddresses();
|
||||||
@ -59,21 +62,33 @@ public final class EpollSocketChannel extends AbstractEpollStreamChannel impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
public EpollSocketChannel() {
|
public EpollSocketChannel() {
|
||||||
super(Native.socketStreamFd());
|
super(newSocketStream(), false);
|
||||||
|
config = new EpollSocketChannelConfig(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #EpollSocketChannel(Socket, boolean)}.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public EpollSocketChannel(FileDescriptor fd) {
|
||||||
|
super(fd);
|
||||||
|
// As we create an EpollSocketChannel from a FileDescriptor we should try to obtain the remote and local
|
||||||
|
// address from it. This is needed as the FileDescriptor may be bound/connected already.
|
||||||
|
remote = fd().remoteAddress();
|
||||||
|
local = fd().localAddress();
|
||||||
config = new EpollSocketChannelConfig(this);
|
config = new EpollSocketChannelConfig(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link EpollSocketChannel} from an existing {@link FileDescriptor}.
|
* Creates a new {@link EpollSocketChannel} from an existing {@link FileDescriptor}.
|
||||||
*/
|
*/
|
||||||
public EpollSocketChannel(FileDescriptor fd) {
|
public EpollSocketChannel(Socket fd, boolean active) {
|
||||||
super(fd);
|
super(fd, active);
|
||||||
config = new EpollSocketChannelConfig(this);
|
|
||||||
|
|
||||||
// As we create an EpollSocketChannel from a FileDescriptor we should try to obtain the remote and local
|
// As we create an EpollSocketChannel from a FileDescriptor we should try to obtain the remote and local
|
||||||
// address from it. This is needed as the FileDescriptor may be bound/connected already.
|
// address from it. This is needed as the FileDescriptor may be bound/connected already.
|
||||||
remote = Native.remoteAddress(fd.intValue());
|
remote = fd.remoteAddress();
|
||||||
local = Native.localAddress(fd.intValue());
|
local = fd.localAddress();
|
||||||
|
config = new EpollSocketChannelConfig(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,7 +126,7 @@ public final class EpollSocketChannel extends AbstractEpollStreamChannel impleme
|
|||||||
protected SocketAddress remoteAddress0() {
|
protected SocketAddress remoteAddress0() {
|
||||||
if (remote == null) {
|
if (remote == null) {
|
||||||
// Remote address not know, try to get it now.
|
// Remote address not know, try to get it now.
|
||||||
InetSocketAddress address = Native.remoteAddress(fd().intValue());
|
InetSocketAddress address = fd().remoteAddress();
|
||||||
if (address != null) {
|
if (address != null) {
|
||||||
remote = address;
|
remote = address;
|
||||||
}
|
}
|
||||||
@ -123,9 +138,8 @@ public final class EpollSocketChannel extends AbstractEpollStreamChannel impleme
|
|||||||
@Override
|
@Override
|
||||||
protected void doBind(SocketAddress local) throws Exception {
|
protected void doBind(SocketAddress local) throws Exception {
|
||||||
InetSocketAddress localAddress = (InetSocketAddress) local;
|
InetSocketAddress localAddress = (InetSocketAddress) local;
|
||||||
int fd = fd().intValue();
|
fd().bind(localAddress);
|
||||||
Native.bind(fd, localAddress);
|
this.local = fd().localAddress();
|
||||||
this.local = Native.localAddress(fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -190,7 +204,6 @@ public final class EpollSocketChannel extends AbstractEpollStreamChannel impleme
|
|||||||
checkResolvable((InetSocketAddress) localAddress);
|
checkResolvable((InetSocketAddress) localAddress);
|
||||||
}
|
}
|
||||||
checkResolvable((InetSocketAddress) remoteAddress);
|
checkResolvable((InetSocketAddress) remoteAddress);
|
||||||
int fd = fd().intValue();
|
|
||||||
boolean connected = super.doConnect(remoteAddress, localAddress);
|
boolean connected = super.doConnect(remoteAddress, localAddress);
|
||||||
if (connected) {
|
if (connected) {
|
||||||
remote = (InetSocketAddress) remoteAddress;
|
remote = (InetSocketAddress) remoteAddress;
|
||||||
@ -199,7 +212,7 @@ public final class EpollSocketChannel extends AbstractEpollStreamChannel impleme
|
|||||||
// We always need to set the localAddress even if not connected yet
|
// We always need to set the localAddress even if not connected yet
|
||||||
//
|
//
|
||||||
// See https://github.com/netty/netty/issues/3463
|
// See https://github.com/netty/netty/issues/3463
|
||||||
local = Native.localAddress(fd);
|
local = fd().localAddress();
|
||||||
return connected;
|
return connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,17 +147,17 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getReceiveBufferSize() {
|
public int getReceiveBufferSize() {
|
||||||
return Native.getReceiveBufferSize(channel.fd().intValue());
|
return channel.fd().getReceiveBufferSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSendBufferSize() {
|
public int getSendBufferSize() {
|
||||||
return Native.getSendBufferSize(channel.fd().intValue());
|
return channel.fd().getSendBufferSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSoLinger() {
|
public int getSoLinger() {
|
||||||
return Native.getSoLinger(channel.fd().intValue());
|
return channel.fd().getSoLinger();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -167,7 +167,7 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isKeepAlive() {
|
public boolean isKeepAlive() {
|
||||||
return Native.isKeepAlive(channel.fd().intValue()) == 1;
|
return channel.fd().isKeepAlive();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -177,14 +177,14 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTcpNoDelay() {
|
public boolean isTcpNoDelay() {
|
||||||
return Native.isTcpNoDelay(channel.fd().intValue()) == 1;
|
return channel.fd().isTcpNoDelay();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the {@code TCP_CORK} option on the socket. See {@code man 7 tcp} for more details.
|
* Get the {@code TCP_CORK} option on the socket. See {@code man 7 tcp} for more details.
|
||||||
*/
|
*/
|
||||||
public boolean isTcpCork() {
|
public boolean isTcpCork() {
|
||||||
return Native.isTcpCork(channel.fd().intValue()) == 1;
|
return channel.fd().isTcpCork();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -225,7 +225,7 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EpollSocketChannelConfig setKeepAlive(boolean keepAlive) {
|
public EpollSocketChannelConfig setKeepAlive(boolean keepAlive) {
|
||||||
Native.setKeepAlive(channel.fd().intValue(), keepAlive ? 1 : 0);
|
channel.fd().setKeepAlive(keepAlive);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +237,7 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EpollSocketChannelConfig setReceiveBufferSize(int receiveBufferSize) {
|
public EpollSocketChannelConfig setReceiveBufferSize(int receiveBufferSize) {
|
||||||
Native.setReceiveBufferSize(channel.fd().intValue(), receiveBufferSize);
|
channel.fd().setReceiveBufferSize(receiveBufferSize);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,19 +249,19 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EpollSocketChannelConfig setSendBufferSize(int sendBufferSize) {
|
public EpollSocketChannelConfig setSendBufferSize(int sendBufferSize) {
|
||||||
Native.setSendBufferSize(channel.fd().intValue(), sendBufferSize);
|
channel.fd().setSendBufferSize(sendBufferSize);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EpollSocketChannelConfig setSoLinger(int soLinger) {
|
public EpollSocketChannelConfig setSoLinger(int soLinger) {
|
||||||
Native.setSoLinger(channel.fd().intValue(), soLinger);
|
channel.fd().setSoLinger(soLinger);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EpollSocketChannelConfig setTcpNoDelay(boolean tcpNoDelay) {
|
public EpollSocketChannelConfig setTcpNoDelay(boolean tcpNoDelay) {
|
||||||
Native.setTcpNoDelay(channel.fd().intValue(), tcpNoDelay ? 1 : 0);
|
channel.fd().setTcpNoDelay(tcpNoDelay);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,7 +269,7 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement
|
|||||||
* Set the {@code TCP_CORK} option on the socket. See {@code man 7 tcp} for more details.
|
* Set the {@code TCP_CORK} option on the socket. See {@code man 7 tcp} for more details.
|
||||||
*/
|
*/
|
||||||
public EpollSocketChannelConfig setTcpCork(boolean tcpCork) {
|
public EpollSocketChannelConfig setTcpCork(boolean tcpCork) {
|
||||||
Native.setTcpCork(channel.fd().intValue(), tcpCork ? 1 : 0);
|
channel.fd().setTcpCork(tcpCork);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,34 +15,31 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.channel.epoll;
|
package io.netty.channel.epoll;
|
||||||
|
|
||||||
|
|
||||||
import io.netty.channel.ChannelException;
|
|
||||||
import io.netty.channel.DefaultFileRegion;
|
import io.netty.channel.DefaultFileRegion;
|
||||||
import io.netty.channel.unix.DomainSocketAddress;
|
import io.netty.channel.unix.Errors.NativeIoException;
|
||||||
import io.netty.util.CharsetUtil;
|
import io.netty.channel.unix.FileDescriptor;
|
||||||
import io.netty.util.internal.EmptyArrays;
|
import io.netty.channel.unix.NativeInetAddress;
|
||||||
import io.netty.util.internal.NativeLibraryLoader;
|
import io.netty.util.internal.NativeLibraryLoader;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import io.netty.util.internal.SystemPropertyUtil;
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.ConnectException;
|
|
||||||
import java.net.Inet6Address;
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.SocketAddress;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.channels.ClosedChannelException;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import static io.netty.channel.unix.Errors.ERRNO_EAGAIN_NEGATIVE;
|
||||||
|
import static io.netty.channel.unix.Errors.ERRNO_EPIPE_NEGATIVE;
|
||||||
|
import static io.netty.channel.unix.Errors.ERRNO_EWOULDBLOCK_NEGATIVE;
|
||||||
|
import static io.netty.channel.unix.Errors.ioResult;
|
||||||
|
import static io.netty.channel.unix.Errors.newConnectionResetException;
|
||||||
|
import static io.netty.channel.unix.Errors.newIOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Native helper methods
|
* Native helper methods
|
||||||
*
|
*
|
||||||
* <strong>Internal usage only!</strong>
|
* <strong>Internal usage only!</strong>
|
||||||
*/
|
*/
|
||||||
public final class Native {
|
public final class Native {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
String name = SystemPropertyUtil.get("os.name").toLowerCase(Locale.UK).trim();
|
String name = SystemPropertyUtil.get("os.name").toLowerCase(Locale.UK).trim();
|
||||||
if (!name.startsWith("linux")) {
|
if (!name.startsWith("linux")) {
|
||||||
@ -65,95 +62,33 @@ public final class Native {
|
|||||||
public static final long SSIZE_MAX = ssizeMax();
|
public static final long SSIZE_MAX = ssizeMax();
|
||||||
public static final int TCP_MD5SIG_MAXKEYLEN = tcpMd5SigMaxKeyLen();
|
public static final int TCP_MD5SIG_MAXKEYLEN = tcpMd5SigMaxKeyLen();
|
||||||
|
|
||||||
private static final byte[] IPV4_MAPPED_IPV6_PREFIX = {
|
private static final NativeIoException CONNECTION_RESET_EXCEPTION_SENDFILE;
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff };
|
private static final NativeIoException CONNECTION_RESET_EXCEPTION_SENDMMSG;
|
||||||
|
private static final NativeIoException CONNECTION_RESET_EXCEPTION_SPLICE;
|
||||||
// As all our JNI methods return -errno on error we need to compare with the negative errno codes.
|
|
||||||
private static final int ERRNO_ENOTCONN_NEGATIVE = -errnoENOTCONN();
|
|
||||||
private static final int ERRNO_EBADF_NEGATIVE = -errnoEBADF();
|
|
||||||
private static final int ERRNO_EPIPE_NEGATIVE = -errnoEPIPE();
|
|
||||||
private static final int ERRNO_ECONNRESET_NEGATIVE = -errnoECONNRESET();
|
|
||||||
private static final int ERRNO_EAGAIN_NEGATIVE = -errnoEAGAIN();
|
|
||||||
private static final int ERRNO_EWOULDBLOCK_NEGATIVE = -errnoEWOULDBLOCK();
|
|
||||||
private static final int ERRNO_EINPROGRESS_NEGATIVE = -errnoEINPROGRESS();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds the mappings for errno codes to String messages.
|
|
||||||
* This eliminates the need to call back into JNI to get the right String message on an exception
|
|
||||||
* and thus is faster.
|
|
||||||
*
|
|
||||||
* The array length of 1024 should be more then enough because errno.h only holds < 200 codes.
|
|
||||||
*/
|
|
||||||
private static final String[] ERRORS = new String[1024];
|
|
||||||
|
|
||||||
// Pre-instantiated exceptions which does not need any stacktrace and
|
|
||||||
// can be thrown multiple times for performance reasons.
|
|
||||||
private static final ClosedChannelException CLOSED_CHANNEL_EXCEPTION;
|
|
||||||
private static final IOException CONNECTION_RESET_EXCEPTION_WRITE;
|
|
||||||
private static final IOException CONNECTION_RESET_EXCEPTION_WRITEV;
|
|
||||||
private static final IOException CONNECTION_RESET_EXCEPTION_READ;
|
|
||||||
private static final IOException CONNECTION_RESET_EXCEPTION_SENDFILE;
|
|
||||||
private static final IOException CONNECTION_RESET_EXCEPTION_SENDTO;
|
|
||||||
private static final IOException CONNECTION_RESET_EXCEPTION_SENDMSG;
|
|
||||||
private static final IOException CONNECTION_RESET_EXCEPTION_SENDMMSG;
|
|
||||||
private static final IOException CONNECTION_RESET_EXCEPTION_SPLICE;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
for (int i = 0; i < ERRORS.length; i++) {
|
|
||||||
// This is ok as strerror returns 'Unknown error i' when the message is not known.
|
|
||||||
ERRORS[i] = strError(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
CONNECTION_RESET_EXCEPTION_READ = newConnectionResetException("syscall:read(...)",
|
|
||||||
ERRNO_ECONNRESET_NEGATIVE);
|
|
||||||
CONNECTION_RESET_EXCEPTION_WRITE = newConnectionResetException("syscall:write(...)",
|
|
||||||
ERRNO_EPIPE_NEGATIVE);
|
|
||||||
CONNECTION_RESET_EXCEPTION_WRITEV = newConnectionResetException("syscall:writev(...)",
|
|
||||||
ERRNO_EPIPE_NEGATIVE);
|
|
||||||
CONNECTION_RESET_EXCEPTION_SENDFILE = newConnectionResetException("syscall:sendfile(...)",
|
CONNECTION_RESET_EXCEPTION_SENDFILE = newConnectionResetException("syscall:sendfile(...)",
|
||||||
ERRNO_EPIPE_NEGATIVE);
|
ERRNO_EPIPE_NEGATIVE);
|
||||||
CONNECTION_RESET_EXCEPTION_SENDTO = newConnectionResetException("syscall:sendto(...)",
|
|
||||||
ERRNO_EPIPE_NEGATIVE);
|
|
||||||
CONNECTION_RESET_EXCEPTION_SENDMSG = newConnectionResetException("syscall:sendmsg(...)",
|
|
||||||
ERRNO_EPIPE_NEGATIVE);
|
|
||||||
CONNECTION_RESET_EXCEPTION_SENDMMSG = newConnectionResetException("syscall:sendmmsg(...)",
|
CONNECTION_RESET_EXCEPTION_SENDMMSG = newConnectionResetException("syscall:sendmmsg(...)",
|
||||||
ERRNO_EPIPE_NEGATIVE);
|
ERRNO_EPIPE_NEGATIVE);
|
||||||
CONNECTION_RESET_EXCEPTION_SPLICE = newConnectionResetException("syscall:splice(...)",
|
CONNECTION_RESET_EXCEPTION_SPLICE = newConnectionResetException("syscall:splice(...)",
|
||||||
ERRNO_EPIPE_NEGATIVE);
|
ERRNO_EPIPE_NEGATIVE);
|
||||||
CLOSED_CHANNEL_EXCEPTION = new ClosedChannelException();
|
|
||||||
CLOSED_CHANNEL_EXCEPTION.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IOException newConnectionResetException(String method, int errnoNegative) {
|
public static FileDescriptor newEventFd() {
|
||||||
IOException exception = newIOException(method, errnoNegative);
|
return new FileDescriptor(eventFd());
|
||||||
exception.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
|
|
||||||
return exception;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IOException newIOException(String method, int err) {
|
private static native int eventFd();
|
||||||
return new IOException(method + "() failed: " + ERRORS[-err]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int ioResult(String method, int err, IOException resetCause) throws IOException {
|
|
||||||
// network stack saturated... try again later
|
|
||||||
if (err == ERRNO_EAGAIN_NEGATIVE || err == ERRNO_EWOULDBLOCK_NEGATIVE) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (err == ERRNO_EPIPE_NEGATIVE || err == ERRNO_ECONNRESET_NEGATIVE) {
|
|
||||||
throw resetCause;
|
|
||||||
}
|
|
||||||
if (err == ERRNO_EBADF_NEGATIVE || err == ERRNO_ENOTCONN_NEGATIVE) {
|
|
||||||
throw CLOSED_CHANNEL_EXCEPTION;
|
|
||||||
}
|
|
||||||
// TODO: We could even go futher and use a pre-instanced IOException for the other error codes, but for
|
|
||||||
// all other errors it may be better to just include a stacktrace.
|
|
||||||
throw newIOException(method, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static native int eventFd();
|
|
||||||
public static native void eventFdWrite(int fd, long value);
|
public static native void eventFdWrite(int fd, long value);
|
||||||
public static native void eventFdRead(int fd);
|
public static native void eventFdRead(int fd);
|
||||||
public static native int epollCreate();
|
|
||||||
|
public static FileDescriptor newEpollCreate() {
|
||||||
|
return new FileDescriptor(epollCreate());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native int epollCreate();
|
||||||
|
|
||||||
public static int epollWait(int efd, EpollEventArray events, int timeout) throws IOException {
|
public static int epollWait(int efd, EpollEventArray events, int timeout) throws IOException {
|
||||||
int ready = epollWait0(efd, events.memoryAddress(), events.length(), timeout);
|
int ready = epollWait0(efd, events.memoryAddress(), events.length(), timeout);
|
||||||
if (ready < 0) {
|
if (ready < 0) {
|
||||||
@ -187,26 +122,7 @@ public final class Native {
|
|||||||
}
|
}
|
||||||
private static native int epollCtlDel0(int efd, final int fd);
|
private static native int epollCtlDel0(int efd, final int fd);
|
||||||
|
|
||||||
private static native int errnoEBADF();
|
|
||||||
private static native int errnoEPIPE();
|
|
||||||
private static native int errnoECONNRESET();
|
|
||||||
private static native int errnoENOTCONN();
|
|
||||||
|
|
||||||
private static native int errnoEAGAIN();
|
|
||||||
private static native int errnoEWOULDBLOCK();
|
|
||||||
private static native int errnoEINPROGRESS();
|
|
||||||
private static native String strError(int err);
|
|
||||||
|
|
||||||
// File-descriptor operations
|
// File-descriptor operations
|
||||||
public static void close(int fd) throws IOException {
|
|
||||||
int res = close0(fd);
|
|
||||||
if (res < 0) {
|
|
||||||
throw newIOException("close", res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int close0(int fd);
|
|
||||||
|
|
||||||
public static int splice(int fd, long offIn, int fdOut, long offOut, long len) throws IOException {
|
public static int splice(int fd, long offIn, int fdOut, long offOut, long len) throws IOException {
|
||||||
int res = splice0(fd, offIn, fdOut, offOut, len);
|
int res = splice0(fd, offIn, fdOut, offOut, len);
|
||||||
if (res >= 0) {
|
if (res >= 0) {
|
||||||
@ -217,83 +133,6 @@ public final class Native {
|
|||||||
|
|
||||||
private static native int splice0(int fd, long offIn, int fdOut, long offOut, long len);
|
private static native int splice0(int fd, long offIn, int fdOut, long offOut, long len);
|
||||||
|
|
||||||
public static long pipe() throws IOException {
|
|
||||||
long res = pipe0();
|
|
||||||
if (res >= 0) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
throw newIOException("pipe", (int) res);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native long pipe0();
|
|
||||||
|
|
||||||
public static int write(int fd, ByteBuffer buf, int pos, int limit) throws IOException {
|
|
||||||
int res = write0(fd, buf, pos, limit);
|
|
||||||
if (res >= 0) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return ioResult("write", res, CONNECTION_RESET_EXCEPTION_WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int write0(int fd, ByteBuffer buf, int pos, int limit);
|
|
||||||
|
|
||||||
public static int writeAddress(int fd, long address, int pos, int limit) throws IOException {
|
|
||||||
int res = writeAddress0(fd, address, pos, limit);
|
|
||||||
if (res >= 0) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return ioResult("writeAddress", res, CONNECTION_RESET_EXCEPTION_WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int writeAddress0(int fd, long address, int pos, int limit);
|
|
||||||
|
|
||||||
public static long writev(int fd, ByteBuffer[] buffers, int offset, int length) throws IOException {
|
|
||||||
long res = writev0(fd, buffers, offset, length);
|
|
||||||
if (res >= 0) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return ioResult("writev", (int) res, CONNECTION_RESET_EXCEPTION_WRITEV);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native long writev0(int fd, ByteBuffer[] buffers, int offset, int length);
|
|
||||||
|
|
||||||
public static long writevAddresses(int fd, long memoryAddress, int length)
|
|
||||||
throws IOException {
|
|
||||||
long res = writevAddresses0(fd, memoryAddress, length);
|
|
||||||
if (res >= 0) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return ioResult("writevAddresses", (int) res, CONNECTION_RESET_EXCEPTION_WRITEV);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native long writevAddresses0(int fd, long memoryAddress, int length);
|
|
||||||
|
|
||||||
public static int read(int fd, ByteBuffer buf, int pos, int limit) throws IOException {
|
|
||||||
int res = read0(fd, buf, pos, limit);
|
|
||||||
if (res > 0) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
if (res == 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return ioResult("read", res, CONNECTION_RESET_EXCEPTION_READ);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int read0(int fd, ByteBuffer buf, int pos, int limit);
|
|
||||||
|
|
||||||
public static int readAddress(int fd, long address, int pos, int limit) throws IOException {
|
|
||||||
int res = readAddress0(fd, address, pos, limit);
|
|
||||||
if (res > 0) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
if (res == 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return ioResult("readAddress", res, CONNECTION_RESET_EXCEPTION_READ);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int readAddress0(int fd, long address, int pos, int limit);
|
|
||||||
|
|
||||||
public static long sendfile(
|
public static long sendfile(
|
||||||
int dest, DefaultFileRegion src, long baseOffset, long offset, long length) throws IOException {
|
int dest, DefaultFileRegion src, long baseOffset, long offset, long length) throws IOException {
|
||||||
// Open the file-region as it may be created via the lazy constructor. This is needed as we directly access
|
// Open the file-region as it may be created via the lazy constructor. This is needed as we directly access
|
||||||
@ -310,84 +149,6 @@ public final class Native {
|
|||||||
private static native long sendfile0(
|
private static native long sendfile0(
|
||||||
int dest, DefaultFileRegion src, long baseOffset, long offset, long length) throws IOException;
|
int dest, DefaultFileRegion src, long baseOffset, long offset, long length) throws IOException;
|
||||||
|
|
||||||
public static int sendTo(
|
|
||||||
int fd, ByteBuffer buf, int pos, int limit, InetAddress addr, int port) throws IOException {
|
|
||||||
// just duplicate the toNativeInetAddress code here to minimize object creation as this method is expected
|
|
||||||
// to be called frequently
|
|
||||||
byte[] address;
|
|
||||||
int scopeId;
|
|
||||||
if (addr instanceof Inet6Address) {
|
|
||||||
address = addr.getAddress();
|
|
||||||
scopeId = ((Inet6Address) addr).getScopeId();
|
|
||||||
} else {
|
|
||||||
// convert to ipv4 mapped ipv6 address;
|
|
||||||
scopeId = 0;
|
|
||||||
address = ipv4MappedIpv6Address(addr.getAddress());
|
|
||||||
}
|
|
||||||
int res = sendTo0(fd, buf, pos, limit, address, scopeId, port);
|
|
||||||
if (res >= 0) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return ioResult("sendTo", res, CONNECTION_RESET_EXCEPTION_SENDTO);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int sendTo0(
|
|
||||||
int fd, ByteBuffer buf, int pos, int limit, byte[] address, int scopeId, int port);
|
|
||||||
|
|
||||||
public static int sendToAddress(
|
|
||||||
int fd, long memoryAddress, int pos, int limit, InetAddress addr, int port) throws IOException {
|
|
||||||
// just duplicate the toNativeInetAddress code here to minimize object creation as this method is expected
|
|
||||||
// to be called frequently
|
|
||||||
byte[] address;
|
|
||||||
int scopeId;
|
|
||||||
if (addr instanceof Inet6Address) {
|
|
||||||
address = addr.getAddress();
|
|
||||||
scopeId = ((Inet6Address) addr).getScopeId();
|
|
||||||
} else {
|
|
||||||
// convert to ipv4 mapped ipv6 address;
|
|
||||||
scopeId = 0;
|
|
||||||
address = ipv4MappedIpv6Address(addr.getAddress());
|
|
||||||
}
|
|
||||||
int res = sendToAddress0(fd, memoryAddress, pos, limit, address, scopeId, port);
|
|
||||||
if (res >= 0) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return ioResult("sendToAddress", res, CONNECTION_RESET_EXCEPTION_SENDTO);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int sendToAddress0(
|
|
||||||
int fd, long memoryAddress, int pos, int limit, byte[] address, int scopeId, int port);
|
|
||||||
|
|
||||||
public static int sendToAddresses(
|
|
||||||
int fd, long memoryAddress, int length, InetAddress addr, int port) throws IOException {
|
|
||||||
// just duplicate the toNativeInetAddress code here to minimize object creation as this method is expected
|
|
||||||
// to be called frequently
|
|
||||||
byte[] address;
|
|
||||||
int scopeId;
|
|
||||||
if (addr instanceof Inet6Address) {
|
|
||||||
address = addr.getAddress();
|
|
||||||
scopeId = ((Inet6Address) addr).getScopeId();
|
|
||||||
} else {
|
|
||||||
// convert to ipv4 mapped ipv6 address;
|
|
||||||
scopeId = 0;
|
|
||||||
address = ipv4MappedIpv6Address(addr.getAddress());
|
|
||||||
}
|
|
||||||
int res = sendToAddresses(fd, memoryAddress, length, address, scopeId, port);
|
|
||||||
if (res >= 0) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return ioResult("sendToAddresses", res, CONNECTION_RESET_EXCEPTION_SENDMSG);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int sendToAddresses(
|
|
||||||
int fd, long memoryAddress, int length, byte[] address, int scopeId, int port);
|
|
||||||
|
|
||||||
public static native EpollDatagramChannel.DatagramSocketAddress recvFrom(
|
|
||||||
int fd, ByteBuffer buf, int pos, int limit) throws IOException;
|
|
||||||
|
|
||||||
public static native EpollDatagramChannel.DatagramSocketAddress recvFromAddress(
|
|
||||||
int fd, long memoryAddress, int pos, int limit) throws IOException;
|
|
||||||
|
|
||||||
public static int sendmmsg(
|
public static int sendmmsg(
|
||||||
int fd, NativeDatagramPacketArray.NativeDatagramPacket[] msgs, int offset, int len) throws IOException {
|
int fd, NativeDatagramPacketArray.NativeDatagramPacket[] msgs, int offset, int len) throws IOException {
|
||||||
int res = sendmmsg0(fd, msgs, offset, len);
|
int res = sendmmsg0(fd, msgs, offset, len);
|
||||||
@ -403,188 +164,6 @@ public final class Native {
|
|||||||
private static native boolean isSupportingSendmmsg();
|
private static native boolean isSupportingSendmmsg();
|
||||||
private static native boolean isSupportingTcpFastopen();
|
private static native boolean isSupportingTcpFastopen();
|
||||||
|
|
||||||
// socket operations
|
|
||||||
public static int socketStreamFd() {
|
|
||||||
int res = socketStream();
|
|
||||||
if (res < 0) {
|
|
||||||
throw new ChannelException(newIOException("socketStreamFd", res));
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int socketDgramFd() {
|
|
||||||
int res = socketDgram();
|
|
||||||
if (res < 0) {
|
|
||||||
throw new ChannelException(newIOException("socketDgramFd", res));
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int socketDomainFd() {
|
|
||||||
int res = socketDomain();
|
|
||||||
if (res < 0) {
|
|
||||||
throw new ChannelException(newIOException("socketDomain", res));
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int socketStream();
|
|
||||||
private static native int socketDgram();
|
|
||||||
private static native int socketDomain();
|
|
||||||
|
|
||||||
public static void bind(int fd, SocketAddress socketAddress) throws IOException {
|
|
||||||
if (socketAddress instanceof InetSocketAddress) {
|
|
||||||
InetSocketAddress addr = (InetSocketAddress) socketAddress;
|
|
||||||
NativeInetAddress address = toNativeInetAddress(addr.getAddress());
|
|
||||||
int res = bind(fd, address.address, address.scopeId, addr.getPort());
|
|
||||||
if (res < 0) {
|
|
||||||
throw newIOException("bind", res);
|
|
||||||
}
|
|
||||||
} else if (socketAddress instanceof DomainSocketAddress) {
|
|
||||||
DomainSocketAddress addr = (DomainSocketAddress) socketAddress;
|
|
||||||
int res = bindDomainSocket(fd, addr.path().getBytes(CharsetUtil.UTF_8));
|
|
||||||
if (res < 0) {
|
|
||||||
throw newIOException("bind", res);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new Error("Unexpected SocketAddress implementation " + socketAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int bind(int fd, byte[] address, int scopeId, int port);
|
|
||||||
private static native int bindDomainSocket(int fd, byte[] path);
|
|
||||||
|
|
||||||
public static void listen(int fd, int backlog) throws IOException {
|
|
||||||
int res = listen0(fd, backlog);
|
|
||||||
if (res < 0) {
|
|
||||||
throw newIOException("listen", res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int listen0(int fd, int backlog);
|
|
||||||
|
|
||||||
public static boolean connect(int fd, SocketAddress socketAddress) throws IOException {
|
|
||||||
int res;
|
|
||||||
if (socketAddress instanceof InetSocketAddress) {
|
|
||||||
InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
|
|
||||||
NativeInetAddress address = toNativeInetAddress(inetSocketAddress.getAddress());
|
|
||||||
res = connect(fd, address.address, address.scopeId, inetSocketAddress.getPort());
|
|
||||||
} else if (socketAddress instanceof DomainSocketAddress) {
|
|
||||||
DomainSocketAddress unixDomainSocketAddress = (DomainSocketAddress) socketAddress;
|
|
||||||
res = connectDomainSocket(fd, unixDomainSocketAddress.path().getBytes(CharsetUtil.UTF_8));
|
|
||||||
} else {
|
|
||||||
throw new Error("Unexpected SocketAddress implementation " + socketAddress);
|
|
||||||
}
|
|
||||||
if (res < 0) {
|
|
||||||
if (res == ERRNO_EINPROGRESS_NEGATIVE) {
|
|
||||||
// connect not complete yet need to wait for EPOLLOUT event
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
throw newConnectException("connect", res);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int connect(int fd, byte[] address, int scopeId, int port);
|
|
||||||
private static native int connectDomainSocket(int fd, byte[] path);
|
|
||||||
|
|
||||||
public static boolean finishConnect(int fd) throws IOException {
|
|
||||||
int res = finishConnect0(fd);
|
|
||||||
if (res < 0) {
|
|
||||||
if (res == ERRNO_EINPROGRESS_NEGATIVE) {
|
|
||||||
// connect still in progress
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
throw newConnectException("finishConnect", res);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int finishConnect0(int fd);
|
|
||||||
|
|
||||||
private static ConnectException newConnectException(String method, int err) {
|
|
||||||
return new ConnectException(method + "() failed: " + ERRORS[-err]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InetSocketAddress remoteAddress(int fd) {
|
|
||||||
byte[] addr = remoteAddress0(fd);
|
|
||||||
// addr may be null if getpeername failed.
|
|
||||||
// See https://github.com/netty/netty/issues/3328
|
|
||||||
if (addr == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return address(addr, 0, addr.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InetSocketAddress localAddress(int fd) {
|
|
||||||
byte[] addr = localAddress0(fd);
|
|
||||||
// addr may be null if getpeername failed.
|
|
||||||
// See https://github.com/netty/netty/issues/3328
|
|
||||||
if (addr == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return address(addr, 0, addr.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
static InetSocketAddress address(byte[] addr, int offset, int len) {
|
|
||||||
// The last 4 bytes are always the port
|
|
||||||
final int port = decodeInt(addr, offset + len - 4);
|
|
||||||
final InetAddress address;
|
|
||||||
|
|
||||||
try {
|
|
||||||
switch (len) {
|
|
||||||
// 8 bytes:
|
|
||||||
// - 4 == ipaddress
|
|
||||||
// - 4 == port
|
|
||||||
case 8:
|
|
||||||
byte[] ipv4 = new byte[4];
|
|
||||||
System.arraycopy(addr, offset, ipv4, 0, 4);
|
|
||||||
address = InetAddress.getByAddress(ipv4);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// 24 bytes:
|
|
||||||
// - 16 == ipaddress
|
|
||||||
// - 4 == scopeId
|
|
||||||
// - 4 == port
|
|
||||||
case 24:
|
|
||||||
byte[] ipv6 = new byte[16];
|
|
||||||
System.arraycopy(addr, offset, ipv6, 0, 16);
|
|
||||||
int scopeId = decodeInt(addr, offset + len - 8);
|
|
||||||
address = Inet6Address.getByAddress(null, ipv6, scopeId);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error();
|
|
||||||
}
|
|
||||||
return new InetSocketAddress(address, port);
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
throw new Error("Should never happen", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int decodeInt(byte[] addr, int index) {
|
|
||||||
return (addr[index] & 0xff) << 24 |
|
|
||||||
(addr[index + 1] & 0xff) << 16 |
|
|
||||||
(addr[index + 2] & 0xff) << 8 |
|
|
||||||
addr[index + 3] & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native byte[] remoteAddress0(int fd);
|
|
||||||
private static native byte[] localAddress0(int fd);
|
|
||||||
|
|
||||||
public static int accept(int fd, byte[] addr) throws IOException {
|
|
||||||
int res = accept0(fd, addr);
|
|
||||||
if (res >= 0) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
if (res == ERRNO_EAGAIN_NEGATIVE || res == ERRNO_EWOULDBLOCK_NEGATIVE) {
|
|
||||||
// Everything consumed so just return -1 here.
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
throw newIOException("accept", res);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int accept0(int fd, byte[] addr);
|
|
||||||
|
|
||||||
public static int recvFd(int fd) throws IOException {
|
public static int recvFd(int fd) throws IOException {
|
||||||
int res = recvFd0(fd);
|
int res = recvFd0(fd);
|
||||||
if (res > 0) {
|
if (res > 0) {
|
||||||
@ -617,44 +196,22 @@ public final class Native {
|
|||||||
|
|
||||||
private static native int sendFd0(int socketFd, int fd);
|
private static native int sendFd0(int socketFd, int fd);
|
||||||
|
|
||||||
public static void shutdown(int fd, boolean read, boolean write) throws IOException {
|
|
||||||
int res = shutdown0(fd, read, write);
|
|
||||||
if (res < 0) {
|
|
||||||
throw newIOException("shutdown", res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int shutdown0(int fd, boolean read, boolean write);
|
|
||||||
|
|
||||||
// Socket option operations
|
// Socket option operations
|
||||||
public static native int getReceiveBufferSize(int fd);
|
|
||||||
public static native int getSendBufferSize(int fd);
|
|
||||||
public static native int isKeepAlive(int fd);
|
|
||||||
public static native int isReuseAddress(int fd);
|
public static native int isReuseAddress(int fd);
|
||||||
public static native int isReusePort(int fd);
|
public static native int isReusePort(int fd);
|
||||||
public static native int isTcpNoDelay(int fd);
|
|
||||||
public static native int isTcpCork(int fd);
|
|
||||||
public static native int getTcpNotSentLowAt(int fd);
|
public static native int getTcpNotSentLowAt(int fd);
|
||||||
public static native int getSoLinger(int fd);
|
|
||||||
public static native int getTrafficClass(int fd);
|
public static native int getTrafficClass(int fd);
|
||||||
public static native int isBroadcast(int fd);
|
public static native int isBroadcast(int fd);
|
||||||
public static native int getTcpKeepIdle(int fd);
|
public static native int getTcpKeepIdle(int fd);
|
||||||
public static native int getTcpKeepIntvl(int fd);
|
public static native int getTcpKeepIntvl(int fd);
|
||||||
public static native int getTcpKeepCnt(int fd);
|
public static native int getTcpKeepCnt(int fd);
|
||||||
public static native int getTcpUserTimeout(int milliseconds);
|
public static native int getTcpUserTimeout(int milliseconds);
|
||||||
public static native int getSoError(int fd);
|
|
||||||
public static native int isIpFreeBind(int fd);
|
public static native int isIpFreeBind(int fd);
|
||||||
|
|
||||||
public static native void setKeepAlive(int fd, int keepAlive);
|
|
||||||
public static native void setReceiveBufferSize(int fd, int receiveBufferSize);
|
|
||||||
public static native void setReuseAddress(int fd, int reuseAddress);
|
public static native void setReuseAddress(int fd, int reuseAddress);
|
||||||
public static native void setReusePort(int fd, int reuseAddress);
|
public static native void setReusePort(int fd, int reuseAddress);
|
||||||
public static native void setSendBufferSize(int fd, int sendBufferSize);
|
|
||||||
public static native void setTcpNoDelay(int fd, int tcpNoDelay);
|
|
||||||
public static native void setTcpCork(int fd, int tcpCork);
|
|
||||||
public static native void setTcpFastopen(int fd, int tcpFastopenBacklog);
|
public static native void setTcpFastopen(int fd, int tcpFastopenBacklog);
|
||||||
public static native void setTcpNotSentLowAt(int fd, int tcpNotSentLowAt);
|
public static native void setTcpNotSentLowAt(int fd, int tcpNotSentLowAt);
|
||||||
public static native void setSoLinger(int fd, int soLinger);
|
|
||||||
public static native void setTrafficClass(int fd, int tcpNoDelay);
|
public static native void setTrafficClass(int fd, int tcpNoDelay);
|
||||||
public static native void setBroadcast(int fd, int broadcast);
|
public static native void setBroadcast(int fd, int broadcast);
|
||||||
public static native void setTcpKeepIdle(int fd, int seconds);
|
public static native void setTcpKeepIdle(int fd, int seconds);
|
||||||
@ -669,43 +226,12 @@ public final class Native {
|
|||||||
private static native void tcpInfo0(int fd, int[] array);
|
private static native void tcpInfo0(int fd, int[] array);
|
||||||
|
|
||||||
public static void setTcpMd5Sig(int fd, InetAddress address, byte[] key) {
|
public static void setTcpMd5Sig(int fd, InetAddress address, byte[] key) {
|
||||||
final NativeInetAddress a = toNativeInetAddress(address);
|
final NativeInetAddress a = NativeInetAddress.newInstance(address);
|
||||||
setTcpMd5Sig0(fd, a.address, a.scopeId, key);
|
setTcpMd5Sig0(fd, a.address(), a.scopeId(), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void setTcpMd5Sig0(int fd, byte[] address, int scopeId, byte[] key);
|
private static native void setTcpMd5Sig0(int fd, byte[] address, int scopeId, byte[] key);
|
||||||
|
|
||||||
private static NativeInetAddress toNativeInetAddress(InetAddress addr) {
|
|
||||||
byte[] bytes = addr.getAddress();
|
|
||||||
if (addr instanceof Inet6Address) {
|
|
||||||
return new NativeInetAddress(bytes, ((Inet6Address) addr).getScopeId());
|
|
||||||
} else {
|
|
||||||
// convert to ipv4 mapped ipv6 address;
|
|
||||||
return new NativeInetAddress(ipv4MappedIpv6Address(bytes));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static byte[] ipv4MappedIpv6Address(byte[] ipv4) {
|
|
||||||
byte[] address = new byte[16];
|
|
||||||
System.arraycopy(IPV4_MAPPED_IPV6_PREFIX, 0, address, 0, IPV4_MAPPED_IPV6_PREFIX.length);
|
|
||||||
System.arraycopy(ipv4, 0, address, 12, ipv4.length);
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class NativeInetAddress {
|
|
||||||
final byte[] address;
|
|
||||||
final int scopeId;
|
|
||||||
|
|
||||||
NativeInetAddress(byte[] address, int scopeId) {
|
|
||||||
this.address = address;
|
|
||||||
this.scopeId = scopeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
NativeInetAddress(byte[] address) {
|
|
||||||
this(address, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static native String kernelVersion();
|
public static native String kernelVersion();
|
||||||
|
|
||||||
private static native int iovMax();
|
private static native int iovMax();
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.channel.epoll;
|
package io.netty.channel.epoll;
|
||||||
|
|
||||||
|
import static io.netty.channel.unix.NativeInetAddress.ipv4MappedIpv6Address;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelOutboundBuffer;
|
import io.netty.channel.ChannelOutboundBuffer;
|
||||||
import io.netty.channel.socket.DatagramPacket;
|
import io.netty.channel.socket.DatagramPacket;
|
||||||
@ -148,7 +149,7 @@ final class NativeDatagramPacketArray implements ChannelOutboundBuffer.MessagePr
|
|||||||
addr = address.getAddress();
|
addr = address.getAddress();
|
||||||
scopeId = ((Inet6Address) address).getScopeId();
|
scopeId = ((Inet6Address) address).getScopeId();
|
||||||
} else {
|
} else {
|
||||||
addr = Native.ipv4MappedIpv6Address(address.getAddress());
|
addr = ipv4MappedIpv6Address(address.getAddress());
|
||||||
scopeId = 0;
|
scopeId = 0;
|
||||||
}
|
}
|
||||||
port = recipient.getPort();
|
port = recipient.getPort();
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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.
|
||||||
|
*/
|
||||||
|
package io.netty.channel.unix;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Act as special {@link InetSocketAddress} to be able to easily pass all needed data from JNI without the need
|
||||||
|
* to create more objects then needed.
|
||||||
|
* <p>
|
||||||
|
* <strong>Internal usage only!</strong>
|
||||||
|
*/
|
||||||
|
public final class DatagramSocketAddress extends InetSocketAddress {
|
||||||
|
private static final long serialVersionUID = 3094819287843178401L;
|
||||||
|
|
||||||
|
// holds the amount of received bytes
|
||||||
|
private final int receivedAmount;
|
||||||
|
|
||||||
|
DatagramSocketAddress(String addr, int port, int receivedAmount) {
|
||||||
|
super(addr, port);
|
||||||
|
this.receivedAmount = receivedAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int receivedAmount() {
|
||||||
|
return receivedAmount;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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.
|
||||||
|
*/
|
||||||
|
package io.netty.channel.unix;
|
||||||
|
|
||||||
|
import io.netty.util.internal.EmptyArrays;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ConnectException;
|
||||||
|
import java.nio.channels.ClosedChannelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <strong>Internal usage only!</strong>
|
||||||
|
*/
|
||||||
|
public final class Errors {
|
||||||
|
// As all our JNI methods return -errno on error we need to compare with the negative errno codes.
|
||||||
|
public static final int ERRNO_ENOTCONN_NEGATIVE = -errnoENOTCONN();
|
||||||
|
public static final int ERRNO_EBADF_NEGATIVE = -errnoEBADF();
|
||||||
|
public static final int ERRNO_EPIPE_NEGATIVE = -errnoEPIPE();
|
||||||
|
public static final int ERRNO_ECONNRESET_NEGATIVE = -errnoECONNRESET();
|
||||||
|
public static final int ERRNO_EAGAIN_NEGATIVE = -errnoEAGAIN();
|
||||||
|
public static final int ERRNO_EWOULDBLOCK_NEGATIVE = -errnoEWOULDBLOCK();
|
||||||
|
public static final int ERRNO_EINPROGRESS_NEGATIVE = -errnoEINPROGRESS();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds the mappings for errno codes to String messages.
|
||||||
|
* This eliminates the need to call back into JNI to get the right String message on an exception
|
||||||
|
* and thus is faster.
|
||||||
|
*
|
||||||
|
* The array length of 512 should be more then enough because errno.h only holds < 200 codes.
|
||||||
|
*/
|
||||||
|
private static final String[] ERRORS = new String[512];
|
||||||
|
|
||||||
|
// Pre-instantiated exceptions which does not need any stacktrace and
|
||||||
|
// can be thrown multiple times for performance reasons.
|
||||||
|
static final ClosedChannelException CLOSED_CHANNEL_EXCEPTION;
|
||||||
|
static final NativeIoException CONNECTION_NOT_CONNECTED_SHUTDOWN_EXCEPTION;
|
||||||
|
static final NativeIoException CONNECTION_RESET_EXCEPTION_WRITE;
|
||||||
|
static final NativeIoException CONNECTION_RESET_EXCEPTION_WRITEV;
|
||||||
|
static final NativeIoException CONNECTION_RESET_EXCEPTION_READ;
|
||||||
|
static final NativeIoException CONNECTION_RESET_EXCEPTION_SENDTO;
|
||||||
|
static final NativeIoException CONNECTION_RESET_EXCEPTION_SENDMSG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <strong>Internal usage only!</strong>
|
||||||
|
*/
|
||||||
|
public static final class NativeIoException extends IOException {
|
||||||
|
private static final long serialVersionUID = 8222160204268655526L;
|
||||||
|
private final int expectedErr;
|
||||||
|
public NativeIoException(String method, int expectedErr) {
|
||||||
|
super(method);
|
||||||
|
this.expectedErr = expectedErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int expectedErr() {
|
||||||
|
return expectedErr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (int i = 0; i < ERRORS.length; i++) {
|
||||||
|
// This is ok as strerror returns 'Unknown error i' when the message is not known.
|
||||||
|
ERRORS[i] = strError(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
CONNECTION_RESET_EXCEPTION_READ = newConnectionResetException("syscall:read(...)",
|
||||||
|
ERRNO_ECONNRESET_NEGATIVE);
|
||||||
|
CONNECTION_RESET_EXCEPTION_WRITE = newConnectionResetException("syscall:write(...)",
|
||||||
|
ERRNO_EPIPE_NEGATIVE);
|
||||||
|
CONNECTION_RESET_EXCEPTION_WRITEV = newConnectionResetException("syscall:writev(...)",
|
||||||
|
ERRNO_EPIPE_NEGATIVE);
|
||||||
|
CONNECTION_RESET_EXCEPTION_SENDTO = newConnectionResetException("syscall:sendto(...)",
|
||||||
|
ERRNO_EPIPE_NEGATIVE);
|
||||||
|
CONNECTION_RESET_EXCEPTION_SENDMSG = newConnectionResetException("syscall:sendmsg(...)",
|
||||||
|
ERRNO_EPIPE_NEGATIVE);
|
||||||
|
CONNECTION_NOT_CONNECTED_SHUTDOWN_EXCEPTION = newConnectionResetException("syscall:shutdown(...)",
|
||||||
|
ERRNO_ENOTCONN_NEGATIVE);
|
||||||
|
CLOSED_CHANNEL_EXCEPTION = new ClosedChannelException();
|
||||||
|
CLOSED_CHANNEL_EXCEPTION.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ConnectException newConnectException(String method, int err) {
|
||||||
|
return new ConnectException(method + "() failed: " + ERRORS[-err]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NativeIoException newConnectionResetException(String method, int errnoNegative) {
|
||||||
|
NativeIoException exception = newIOException(method, errnoNegative);
|
||||||
|
exception.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
|
||||||
|
return exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NativeIoException newIOException(String method, int err) {
|
||||||
|
return new NativeIoException(method + "() failed: " + ERRORS[-err], err);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ioResult(String method, int err, NativeIoException resetCause) throws IOException {
|
||||||
|
// network stack saturated... try again later
|
||||||
|
if (err == ERRNO_EAGAIN_NEGATIVE || err == ERRNO_EWOULDBLOCK_NEGATIVE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (err == resetCause.expectedErr()) {
|
||||||
|
throw resetCause;
|
||||||
|
}
|
||||||
|
if (err == ERRNO_EBADF_NEGATIVE || err == ERRNO_ENOTCONN_NEGATIVE) {
|
||||||
|
throw CLOSED_CHANNEL_EXCEPTION;
|
||||||
|
}
|
||||||
|
// TODO: We could even go further and use a pre-instantiated IOException for the other error codes, but for
|
||||||
|
// all other errors it may be better to just include a stack trace.
|
||||||
|
throw newIOException(method, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native int errnoEBADF();
|
||||||
|
private static native int errnoEPIPE();
|
||||||
|
private static native int errnoECONNRESET();
|
||||||
|
private static native int errnoENOTCONN();
|
||||||
|
private static native int errnoEAGAIN();
|
||||||
|
private static native int errnoEWOULDBLOCK();
|
||||||
|
private static native int errnoEINPROGRESS();
|
||||||
|
private static native String strError(int err);
|
||||||
|
|
||||||
|
private Errors() { }
|
||||||
|
}
|
@ -15,11 +15,15 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.channel.unix;
|
package io.netty.channel.unix;
|
||||||
|
|
||||||
import io.netty.channel.epoll.Native;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import static io.netty.channel.unix.Errors.CONNECTION_RESET_EXCEPTION_READ;
|
||||||
|
import static io.netty.channel.unix.Errors.CONNECTION_RESET_EXCEPTION_WRITE;
|
||||||
|
import static io.netty.channel.unix.Errors.CONNECTION_RESET_EXCEPTION_WRITEV;
|
||||||
|
import static io.netty.channel.unix.Errors.ioResult;
|
||||||
|
import static io.netty.channel.unix.Errors.newIOException;
|
||||||
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,7 +31,6 @@ import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
|||||||
* {@link FileDescriptor} for it.
|
* {@link FileDescriptor} for it.
|
||||||
*/
|
*/
|
||||||
public class FileDescriptor {
|
public class FileDescriptor {
|
||||||
|
|
||||||
private final int fd;
|
private final int fd;
|
||||||
private volatile boolean open = true;
|
private volatile boolean open = true;
|
||||||
|
|
||||||
@ -50,7 +53,10 @@ public class FileDescriptor {
|
|||||||
*/
|
*/
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
open = false;
|
open = false;
|
||||||
close(fd);
|
int res = close(fd);
|
||||||
|
if (res < 0) {
|
||||||
|
throw newIOException("close", res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,6 +66,60 @@ public class FileDescriptor {
|
|||||||
return open;
|
return open;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final int write(ByteBuffer buf, int pos, int limit) throws IOException {
|
||||||
|
int res = write(fd, buf, pos, limit);
|
||||||
|
if (res >= 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return ioResult("write", res, CONNECTION_RESET_EXCEPTION_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int writeAddress(long address, int pos, int limit) throws IOException {
|
||||||
|
int res = writeAddress(fd, address, pos, limit);
|
||||||
|
if (res >= 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return ioResult("writeAddress", res, CONNECTION_RESET_EXCEPTION_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final long writev(ByteBuffer[] buffers, int offset, int length) throws IOException {
|
||||||
|
long res = writev(fd, buffers, offset, length);
|
||||||
|
if (res >= 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return ioResult("writev", (int) res, CONNECTION_RESET_EXCEPTION_WRITEV);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final long writevAddresses(long memoryAddress, int length) throws IOException {
|
||||||
|
long res = writevAddresses(fd, memoryAddress, length);
|
||||||
|
if (res >= 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return ioResult("writevAddresses", (int) res, CONNECTION_RESET_EXCEPTION_WRITEV);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int read(ByteBuffer buf, int pos, int limit) throws IOException {
|
||||||
|
int res = read(fd, buf, pos, limit);
|
||||||
|
if (res > 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (res == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ioResult("read", res, CONNECTION_RESET_EXCEPTION_READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int readAddress(long address, int pos, int limit) throws IOException {
|
||||||
|
int res = readAddress(fd, address, pos, limit);
|
||||||
|
if (res > 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (res == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ioResult("readAddress", res, CONNECTION_RESET_EXCEPTION_READ);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "FileDescriptor{" +
|
return "FileDescriptor{" +
|
||||||
@ -84,8 +144,6 @@ public class FileDescriptor {
|
|||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native int close(int fd);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a new {@link FileDescriptor} for the given path.
|
* Open a new {@link FileDescriptor} for the given path.
|
||||||
*/
|
*/
|
||||||
@ -93,7 +151,7 @@ public class FileDescriptor {
|
|||||||
checkNotNull(path, "path");
|
checkNotNull(path, "path");
|
||||||
int res = open(path);
|
int res = open(path);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
throw Native.newIOException("open", res);
|
throw newIOException("open", res);
|
||||||
}
|
}
|
||||||
return new FileDescriptor(res);
|
return new FileDescriptor(res);
|
||||||
}
|
}
|
||||||
@ -105,5 +163,27 @@ public class FileDescriptor {
|
|||||||
return from(checkNotNull(file, "file").getPath());
|
return from(checkNotNull(file, "file").getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return [0] = read end, [1] = write end
|
||||||
|
*/
|
||||||
|
public static FileDescriptor[] pipe() throws IOException {
|
||||||
|
long res = newPipe();
|
||||||
|
if (res < 0) {
|
||||||
|
throw newIOException("newPipe", (int) res);
|
||||||
|
}
|
||||||
|
return new FileDescriptor[]{new FileDescriptor((int) (res >>> 32)), new FileDescriptor((int) res)};
|
||||||
|
}
|
||||||
|
|
||||||
private static native int open(String path);
|
private static native int open(String path);
|
||||||
|
private static native int close(int fd);
|
||||||
|
|
||||||
|
private static native int write(int fd, ByteBuffer buf, int pos, int limit);
|
||||||
|
private static native int writeAddress(int fd, long address, int pos, int limit);
|
||||||
|
private static native long writev(int fd, ByteBuffer[] buffers, int offset, int length);
|
||||||
|
private static native long writevAddresses(int fd, long memoryAddress, int length);
|
||||||
|
|
||||||
|
private static native int read(int fd, ByteBuffer buf, int pos, int limit);
|
||||||
|
private static native int readAddress(int fd, long address, int pos, int limit);
|
||||||
|
|
||||||
|
private static native long newPipe();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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.
|
||||||
|
*/
|
||||||
|
package io.netty.channel.unix;
|
||||||
|
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <strong>Internal usage only!</strong>
|
||||||
|
*/
|
||||||
|
public final class NativeInetAddress {
|
||||||
|
private static final byte[] IPV4_MAPPED_IPV6_PREFIX = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff };
|
||||||
|
final byte[] address;
|
||||||
|
final int scopeId;
|
||||||
|
|
||||||
|
public static NativeInetAddress newInstance(InetAddress addr) {
|
||||||
|
byte[] bytes = addr.getAddress();
|
||||||
|
if (addr instanceof Inet6Address) {
|
||||||
|
return new NativeInetAddress(bytes, ((Inet6Address) addr).getScopeId());
|
||||||
|
} else {
|
||||||
|
// convert to ipv4 mapped ipv6 address;
|
||||||
|
return new NativeInetAddress(ipv4MappedIpv6Address(bytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public NativeInetAddress(byte[] address, int scopeId) {
|
||||||
|
this.address = address;
|
||||||
|
this.scopeId = scopeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NativeInetAddress(byte[] address) {
|
||||||
|
this(address, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] address() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int scopeId() {
|
||||||
|
return scopeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] ipv4MappedIpv6Address(byte[] ipv4) {
|
||||||
|
byte[] address = new byte[16];
|
||||||
|
System.arraycopy(IPV4_MAPPED_IPV6_PREFIX, 0, address, 0, IPV4_MAPPED_IPV6_PREFIX.length);
|
||||||
|
System.arraycopy(ipv4, 0, address, 12, ipv4.length);
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InetSocketAddress address(byte[] addr, int offset, int len) {
|
||||||
|
// The last 4 bytes are always the port
|
||||||
|
final int port = decodeInt(addr, offset + len - 4);
|
||||||
|
final InetAddress address;
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (len) {
|
||||||
|
// 8 bytes:
|
||||||
|
// - 4 == ipaddress
|
||||||
|
// - 4 == port
|
||||||
|
case 8:
|
||||||
|
byte[] ipv4 = new byte[4];
|
||||||
|
System.arraycopy(addr, offset, ipv4, 0, 4);
|
||||||
|
address = InetAddress.getByAddress(ipv4);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 24 bytes:
|
||||||
|
// - 16 == ipaddress
|
||||||
|
// - 4 == scopeId
|
||||||
|
// - 4 == port
|
||||||
|
case 24:
|
||||||
|
byte[] ipv6 = new byte[16];
|
||||||
|
System.arraycopy(addr, offset, ipv6, 0, 16);
|
||||||
|
int scopeId = decodeInt(addr, offset + len - 8);
|
||||||
|
address = Inet6Address.getByAddress(null, ipv6, scopeId);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
return new InetSocketAddress(address, port);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
throw new Error("Should never happen", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int decodeInt(byte[] addr, int index) {
|
||||||
|
return (addr[index] & 0xff) << 24 |
|
||||||
|
(addr[index + 1] & 0xff) << 16 |
|
||||||
|
(addr[index + 2] & 0xff) << 8 |
|
||||||
|
addr[index + 3] & 0xff;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,359 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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.
|
||||||
|
*/
|
||||||
|
package io.netty.channel.unix;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelException;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import static io.netty.channel.unix.Errors.CONNECTION_NOT_CONNECTED_SHUTDOWN_EXCEPTION;
|
||||||
|
import static io.netty.channel.unix.Errors.CONNECTION_RESET_EXCEPTION_SENDMSG;
|
||||||
|
import static io.netty.channel.unix.Errors.CONNECTION_RESET_EXCEPTION_SENDTO;
|
||||||
|
import static io.netty.channel.unix.Errors.ERRNO_EAGAIN_NEGATIVE;
|
||||||
|
import static io.netty.channel.unix.Errors.ERRNO_EINPROGRESS_NEGATIVE;
|
||||||
|
import static io.netty.channel.unix.Errors.ERRNO_EWOULDBLOCK_NEGATIVE;
|
||||||
|
import static io.netty.channel.unix.Errors.ioResult;
|
||||||
|
import static io.netty.channel.unix.Errors.newConnectException;
|
||||||
|
import static io.netty.channel.unix.Errors.newIOException;
|
||||||
|
import static io.netty.channel.unix.NativeInetAddress.address;
|
||||||
|
import static io.netty.channel.unix.NativeInetAddress.ipv4MappedIpv6Address;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a JNI bridge to native socket operations.
|
||||||
|
* <strong>Internal usage only!</strong>
|
||||||
|
*/
|
||||||
|
public final class Socket extends FileDescriptor {
|
||||||
|
private volatile boolean inputShutdown;
|
||||||
|
private volatile boolean outputShutdown;
|
||||||
|
|
||||||
|
public Socket(int fd) {
|
||||||
|
super(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown(boolean read, boolean write) throws IOException {
|
||||||
|
inputShutdown = read || inputShutdown;
|
||||||
|
outputShutdown = write || outputShutdown;
|
||||||
|
int res = shutdown(intValue(), read, write);
|
||||||
|
if (res < 0) {
|
||||||
|
ioResult("shutdown", res, CONNECTION_NOT_CONNECTED_SHUTDOWN_EXCEPTION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShutdown() {
|
||||||
|
return isInputShutdown() && isOutputShutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInputShutdown() {
|
||||||
|
return inputShutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOutputShutdown() {
|
||||||
|
return outputShutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int sendTo(ByteBuffer buf, int pos, int limit, InetAddress addr, int port) throws IOException {
|
||||||
|
// just duplicate the toNativeInetAddress code here to minimize object creation as this method is expected
|
||||||
|
// to be called frequently
|
||||||
|
byte[] address;
|
||||||
|
int scopeId;
|
||||||
|
if (addr instanceof Inet6Address) {
|
||||||
|
address = addr.getAddress();
|
||||||
|
scopeId = ((Inet6Address) addr).getScopeId();
|
||||||
|
} else {
|
||||||
|
// convert to ipv4 mapped ipv6 address;
|
||||||
|
scopeId = 0;
|
||||||
|
address = ipv4MappedIpv6Address(addr.getAddress());
|
||||||
|
}
|
||||||
|
int res = sendTo(intValue(), buf, pos, limit, address, scopeId, port);
|
||||||
|
if (res >= 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return ioResult("sendTo", res, CONNECTION_RESET_EXCEPTION_SENDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int sendToAddress(long memoryAddress, int pos, int limit, InetAddress addr, int port)
|
||||||
|
throws IOException {
|
||||||
|
// just duplicate the toNativeInetAddress code here to minimize object creation as this method is expected
|
||||||
|
// to be called frequently
|
||||||
|
byte[] address;
|
||||||
|
int scopeId;
|
||||||
|
if (addr instanceof Inet6Address) {
|
||||||
|
address = addr.getAddress();
|
||||||
|
scopeId = ((Inet6Address) addr).getScopeId();
|
||||||
|
} else {
|
||||||
|
// convert to ipv4 mapped ipv6 address;
|
||||||
|
scopeId = 0;
|
||||||
|
address = ipv4MappedIpv6Address(addr.getAddress());
|
||||||
|
}
|
||||||
|
int res = sendToAddress(intValue(), memoryAddress, pos, limit, address, scopeId, port);
|
||||||
|
if (res >= 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return ioResult("sendToAddress", res, CONNECTION_RESET_EXCEPTION_SENDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int sendToAddresses(long memoryAddress, int length, InetAddress addr, int port) throws IOException {
|
||||||
|
// just duplicate the toNativeInetAddress code here to minimize object creation as this method is expected
|
||||||
|
// to be called frequently
|
||||||
|
byte[] address;
|
||||||
|
int scopeId;
|
||||||
|
if (addr instanceof Inet6Address) {
|
||||||
|
address = addr.getAddress();
|
||||||
|
scopeId = ((Inet6Address) addr).getScopeId();
|
||||||
|
} else {
|
||||||
|
// convert to ipv4 mapped ipv6 address;
|
||||||
|
scopeId = 0;
|
||||||
|
address = ipv4MappedIpv6Address(addr.getAddress());
|
||||||
|
}
|
||||||
|
int res = sendToAddresses(intValue(), memoryAddress, length, address, scopeId, port);
|
||||||
|
if (res >= 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return ioResult("sendToAddresses", res, CONNECTION_RESET_EXCEPTION_SENDMSG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatagramSocketAddress recvFrom(ByteBuffer buf, int pos, int limit) throws IOException {
|
||||||
|
return recvFrom(intValue(), buf, pos, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatagramSocketAddress recvFromAddress(long memoryAddress, int pos, int limit) throws IOException {
|
||||||
|
return recvFromAddress(intValue(), memoryAddress, pos, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean connect(SocketAddress socketAddress) throws IOException {
|
||||||
|
int res;
|
||||||
|
if (socketAddress instanceof InetSocketAddress) {
|
||||||
|
InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
|
||||||
|
NativeInetAddress address = NativeInetAddress.newInstance(inetSocketAddress.getAddress());
|
||||||
|
res = connect(intValue(), address.address, address.scopeId, inetSocketAddress.getPort());
|
||||||
|
} else if (socketAddress instanceof DomainSocketAddress) {
|
||||||
|
DomainSocketAddress unixDomainSocketAddress = (DomainSocketAddress) socketAddress;
|
||||||
|
res = connectDomainSocket(intValue(), unixDomainSocketAddress.path().getBytes(CharsetUtil.UTF_8));
|
||||||
|
} else {
|
||||||
|
throw new Error("Unexpected SocketAddress implementation " + socketAddress);
|
||||||
|
}
|
||||||
|
if (res < 0) {
|
||||||
|
if (res == ERRNO_EINPROGRESS_NEGATIVE) {
|
||||||
|
// connect not complete yet need to wait for EPOLLOUT event
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
throw newConnectException("connect", res);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean finishConnect() throws IOException {
|
||||||
|
int res = finishConnect(intValue());
|
||||||
|
if (res < 0) {
|
||||||
|
if (res == ERRNO_EINPROGRESS_NEGATIVE) {
|
||||||
|
// connect still in progress
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
throw newConnectException("finishConnect", res);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bind(SocketAddress socketAddress) throws IOException {
|
||||||
|
if (socketAddress instanceof InetSocketAddress) {
|
||||||
|
InetSocketAddress addr = (InetSocketAddress) socketAddress;
|
||||||
|
NativeInetAddress address = NativeInetAddress.newInstance(addr.getAddress());
|
||||||
|
int res = bind(intValue(), address.address, address.scopeId, addr.getPort());
|
||||||
|
if (res < 0) {
|
||||||
|
throw newIOException("bind", res);
|
||||||
|
}
|
||||||
|
} else if (socketAddress instanceof DomainSocketAddress) {
|
||||||
|
DomainSocketAddress addr = (DomainSocketAddress) socketAddress;
|
||||||
|
int res = bindDomainSocket(intValue(), addr.path().getBytes(CharsetUtil.UTF_8));
|
||||||
|
if (res < 0) {
|
||||||
|
throw newIOException("bind", res);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error("Unexpected SocketAddress implementation " + socketAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void listen(int backlog) throws IOException {
|
||||||
|
int res = listen(intValue(), backlog);
|
||||||
|
if (res < 0) {
|
||||||
|
throw newIOException("listen", res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int accept(byte[] addr) throws IOException {
|
||||||
|
int res = accept(intValue(), addr);
|
||||||
|
if (res >= 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (res == ERRNO_EAGAIN_NEGATIVE || res == ERRNO_EWOULDBLOCK_NEGATIVE) {
|
||||||
|
// Everything consumed so just return -1 here.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
throw newIOException("accept", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InetSocketAddress remoteAddress() {
|
||||||
|
byte[] addr = remoteAddress(intValue());
|
||||||
|
// addr may be null if getpeername failed.
|
||||||
|
// See https://github.com/netty/netty/issues/3328
|
||||||
|
if (addr == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return address(addr, 0, addr.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InetSocketAddress localAddress() {
|
||||||
|
byte[] addr = localAddress(intValue());
|
||||||
|
// addr may be null if getpeername failed.
|
||||||
|
// See https://github.com/netty/netty/issues/3328
|
||||||
|
if (addr == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return address(addr, 0, addr.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getReceiveBufferSize() {
|
||||||
|
return getReceiveBufferSize(intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSendBufferSize() {
|
||||||
|
return getSendBufferSize(intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isKeepAlive() {
|
||||||
|
return isKeepAlive(intValue()) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTcpNoDelay() {
|
||||||
|
return isTcpNoDelay(intValue()) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTcpCork() {
|
||||||
|
return isTcpCork(intValue()) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSoLinger() {
|
||||||
|
return getSoLinger(intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSoError() {
|
||||||
|
return getSoError(intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeepAlive(boolean keepAlive) {
|
||||||
|
setKeepAlive(intValue(), keepAlive ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReceiveBufferSize(int receiveBufferSize) {
|
||||||
|
setReceiveBufferSize(intValue(), receiveBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSendBufferSize(int sendBufferSize) {
|
||||||
|
setSendBufferSize(intValue(), sendBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTcpNoDelay(boolean tcpNoDelay) {
|
||||||
|
setTcpNoDelay(intValue(), tcpNoDelay ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTcpCork(boolean tcpCork) {
|
||||||
|
setTcpCork(intValue(), tcpCork ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSoLinger(int soLinger) {
|
||||||
|
setSoLinger(intValue(), soLinger);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Socket{" +
|
||||||
|
"fd=" + intValue() +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Socket newSocketStream() {
|
||||||
|
int res = newSocketStreamFd();
|
||||||
|
if (res < 0) {
|
||||||
|
throw new ChannelException(newIOException("newSocketStream", res));
|
||||||
|
}
|
||||||
|
return new Socket(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Socket newSocketDgram() {
|
||||||
|
int res = newSocketDgramFd();
|
||||||
|
if (res < 0) {
|
||||||
|
throw new ChannelException(newIOException("newSocketDgram", res));
|
||||||
|
}
|
||||||
|
return new Socket(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Socket newSocketDomain() {
|
||||||
|
int res = newSocketDomainFd();
|
||||||
|
if (res < 0) {
|
||||||
|
throw new ChannelException(newIOException("newSocketDomain", res));
|
||||||
|
}
|
||||||
|
return new Socket(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native int shutdown(int fd, boolean read, boolean write);
|
||||||
|
private static native int connect(int fd, byte[] address, int scopeId, int port);
|
||||||
|
private static native int connectDomainSocket(int fd, byte[] path);
|
||||||
|
private static native int finishConnect(int fd);
|
||||||
|
private static native int bind(int fd, byte[] address, int scopeId, int port);
|
||||||
|
private static native int bindDomainSocket(int fd, byte[] path);
|
||||||
|
private static native int listen(int fd, int backlog);
|
||||||
|
private static native int accept(int fd, byte[] addr);
|
||||||
|
|
||||||
|
private static native byte[] remoteAddress(int fd);
|
||||||
|
private static native byte[] localAddress(int fd);
|
||||||
|
|
||||||
|
private static native int sendTo(
|
||||||
|
int fd, ByteBuffer buf, int pos, int limit, byte[] address, int scopeId, int port);
|
||||||
|
private static native int sendToAddress(
|
||||||
|
int fd, long memoryAddress, int pos, int limit, byte[] address, int scopeId, int port);
|
||||||
|
private static native int sendToAddresses(
|
||||||
|
int fd, long memoryAddress, int length, byte[] address, int scopeId, int port);
|
||||||
|
|
||||||
|
private static native DatagramSocketAddress recvFrom(
|
||||||
|
int fd, ByteBuffer buf, int pos, int limit) throws IOException;
|
||||||
|
private static native DatagramSocketAddress recvFromAddress(
|
||||||
|
int fd, long memoryAddress, int pos, int limit) throws IOException;
|
||||||
|
|
||||||
|
private static native int newSocketStreamFd();
|
||||||
|
private static native int newSocketDgramFd();
|
||||||
|
private static native int newSocketDomainFd();
|
||||||
|
|
||||||
|
private static native int getReceiveBufferSize(int fd);
|
||||||
|
private static native int getSendBufferSize(int fd);
|
||||||
|
private static native int isKeepAlive(int fd);
|
||||||
|
private static native int isTcpNoDelay(int fd);
|
||||||
|
private static native int isTcpCork(int fd);
|
||||||
|
private static native int getSoLinger(int fd);
|
||||||
|
private static native int getSoError(int fd);
|
||||||
|
|
||||||
|
private static native void setKeepAlive(int fd, int keepAlive);
|
||||||
|
private static native void setReceiveBufferSize(int fd, int receiveBufferSize);
|
||||||
|
private static native void setSendBufferSize(int fd, int sendBufferSize);
|
||||||
|
private static native void setTcpNoDelay(int fd, int tcpNoDelay);
|
||||||
|
private static native void setTcpCork(int fd, int tcpCork);
|
||||||
|
private static native void setSoLinger(int fd, int soLinger);
|
||||||
|
}
|
@ -145,7 +145,6 @@ public class EpollSocketChannelTest {
|
|||||||
Bootstrap b = new Bootstrap();
|
Bootstrap b = new Bootstrap();
|
||||||
b.group(group);
|
b.group(group);
|
||||||
b.channel(channelClass);
|
b.channel(channelClass);
|
||||||
b.option(ChannelOption.SO_KEEPALIVE, true);
|
|
||||||
b.remoteAddress(serverChannel.localAddress());
|
b.remoteAddress(serverChannel.localAddress());
|
||||||
b.handler(new MyInitializer());
|
b.handler(new MyInitializer());
|
||||||
clientChannel = b.connect().syncUninterruptibly().channel();
|
clientChannel = b.connect().syncUninterruptibly().channel();
|
||||||
|
@ -23,6 +23,8 @@ import java.net.Inet6Address;
|
|||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import static io.netty.channel.unix.NativeInetAddress.address;
|
||||||
|
|
||||||
public class NativeTest {
|
public class NativeTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -32,7 +34,7 @@ public class NativeTest {
|
|||||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||||
buffer.put(inetAddress.getAddress().getAddress());
|
buffer.put(inetAddress.getAddress().getAddress());
|
||||||
buffer.putInt(inetAddress.getPort());
|
buffer.putInt(inetAddress.getPort());
|
||||||
Assert.assertEquals(inetAddress, Native.address(buffer.array(), 0, bytes.length));
|
Assert.assertEquals(inetAddress, address(buffer.array(), 0, bytes.length));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -44,6 +46,6 @@ public class NativeTest {
|
|||||||
buffer.put(address.getAddress());
|
buffer.put(address.getAddress());
|
||||||
buffer.putInt(address.getScopeId());
|
buffer.putInt(address.getScopeId());
|
||||||
buffer.putInt(inetAddress.getPort());
|
buffer.putInt(inetAddress.getPort());
|
||||||
Assert.assertEquals(inetAddress, Native.address(buffer.array(), 0, bytes.length));
|
Assert.assertEquals(inetAddress, address(buffer.array(), 0, bytes.length));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user