Move generic unix classes/interfaces out of epoll package

Motivation:

As we plan to have other native transports soon (like a kqueue transport) we should move unix classes/interfaces out of the epoll package so we
introduce other implementations without breaking stuff before the next stable release.

Modifications:

Create a new io.netty.channel.unix package and move stuff over there.

Result:

Possible to introduce other native impls beside epoll.
This commit is contained in:
Norman Maurer 2015-02-12 20:44:36 +01:00
parent d83700bd0a
commit 98925a1fa4
23 changed files with 279 additions and 75 deletions

View File

@ -0,0 +1,26 @@
/*
* 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>
#include <unistd.h>
#include <errno.h>
#include "io_netty_channel_unix_FileDescriptor.h"
JNIEXPORT int JNICALL Java_io_netty_channel_unix_FileDescriptor_close(JNIEnv* env, jclass clazz, jint fd) {
if (close(fd) < 0) {
return -errno;
}
return 0;
}

View File

@ -0,0 +1,18 @@
/*
* Copyright 2014 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>
int Java_io_netty_channel_unix_FileDescriptor_close(JNIEnv* env, jclass clazz, jint fd);

View File

@ -23,7 +23,8 @@ import io.netty.channel.AbstractChannel;
import io.netty.channel.Channel;
import io.netty.channel.ChannelMetadata;
import io.netty.channel.EventLoop;
import io.netty.channel.FileDescriptor;
import io.netty.channel.unix.FileDescriptor;
import io.netty.channel.unix.UnixChannel;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.internal.OneTimeTask;
@ -31,7 +32,7 @@ import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.UnresolvedAddressException;
abstract class AbstractEpollChannel extends AbstractChannel {
abstract class AbstractEpollChannel extends AbstractChannel implements UnixChannel {
private static final ChannelMetadata DATA = new ChannelMetadata(false);
private final int readFlag;
private volatile FileDescriptor fileDescriptor;
@ -44,7 +45,7 @@ abstract class AbstractEpollChannel extends AbstractChannel {
}
AbstractEpollChannel(Channel parent, int fd, int flag, boolean active) {
this(parent, new NativeFileDescriptor(fd), flag, active);
this(parent, new FileDescriptor(fd), flag, active);
}
AbstractEpollChannel(Channel parent, FileDescriptor fd, int flag, boolean active) {
@ -76,9 +77,7 @@ abstract class AbstractEpollChannel extends AbstractChannel {
return (flags & flag) != 0;
}
/**
* Returns the {@link FileDescriptor} that is used by this {@link Channel}.
*/
@Override
public final FileDescriptor fd() {
return fileDescriptor;
}

View File

@ -20,8 +20,8 @@ import io.netty.channel.ChannelOutboundBuffer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.EventLoop;
import io.netty.channel.FileDescriptor;
import io.netty.channel.ServerChannel;
import io.netty.channel.unix.FileDescriptor;
import java.net.InetSocketAddress;
import java.net.SocketAddress;

View File

@ -28,10 +28,9 @@ import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.ConnectTimeoutException;
import io.netty.channel.DefaultFileRegion;
import io.netty.channel.EventLoop;
import io.netty.channel.FileDescriptor;
import io.netty.channel.RecvByteBufAllocator;
import io.netty.channel.socket.ChannelInputShutdownEvent;
import io.netty.channel.unix.FileDescriptor;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.StringUtil;

View File

@ -16,6 +16,7 @@
package io.netty.channel.epoll;
import io.netty.channel.ChannelOption;
import io.netty.channel.unix.DomainSocketReadMode;
public final class EpollChannelOption {
private static final Class<EpollChannelOption> T = EpollChannelOption.class;

View File

@ -25,11 +25,11 @@ import io.netty.channel.ChannelOutboundBuffer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.DefaultAddressedEnvelope;
import io.netty.channel.FileDescriptor;
import io.netty.channel.RecvByteBufAllocator;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.DatagramChannelConfig;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.unix.FileDescriptor;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.StringUtil;

View File

@ -19,11 +19,13 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelOutboundBuffer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.FileDescriptor;
import io.netty.channel.unix.DomainSocketAddress;
import io.netty.channel.unix.DomainSocketChannel;
import io.netty.channel.unix.FileDescriptor;
import java.net.SocketAddress;
public final class EpollDomainSocketChannel extends AbstractEpollStreamChannel {
public final class EpollDomainSocketChannel extends AbstractEpollStreamChannel implements DomainSocketChannel {
private final EpollDomainSocketChannelConfig config = new EpollDomainSocketChannelConfig(this);
private volatile DomainSocketAddress local;
@ -107,7 +109,7 @@ public final class EpollDomainSocketChannel extends AbstractEpollStreamChannel {
@Override
protected Object filterOutboundMessage(Object msg) {
if (msg instanceof NativeFileDescriptor) {
if (msg instanceof FileDescriptor) {
return msg;
}
return super.filterOutboundMessage(msg);
@ -150,7 +152,7 @@ public final class EpollDomainSocketChannel extends AbstractEpollStreamChannel {
readPending = false;
try {
pipeline.fireChannelRead(new NativeFileDescriptor(socketFd));
pipeline.fireChannelRead(new FileDescriptor(socketFd));
} catch (Throwable t) {
// keep on reading as we use epoll ET and need to consume everything from the socket
pipeline.fireChannelReadComplete();

View File

@ -21,10 +21,13 @@ import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.MessageSizeEstimator;
import io.netty.channel.RecvByteBufAllocator;
import io.netty.channel.unix.DomainSocketChannelConfig;
import io.netty.channel.unix.DomainSocketReadMode;
import java.util.Map;
public final class EpollDomainSocketChannelConfig extends EpollChannelConfig {
public final class EpollDomainSocketChannelConfig extends EpollChannelConfig
implements DomainSocketChannelConfig {
private volatile DomainSocketReadMode mode =
DomainSocketReadMode.BYTES;
@ -118,15 +121,7 @@ public final class EpollDomainSocketChannelConfig extends EpollChannelConfig {
return this;
}
/**
* Change the {@link DomainSocketReadMode} for the channel. The default is
* {@link DomainSocketReadMode#BYTES} which means bytes will be read from the
* {@link Channel} and passed through the pipeline. If
* {@link DomainSocketReadMode#FILE_DESCRIPTORS} is used
* {@link NativeFileDescriptor}s will be passed through the {@link ChannelPipeline}.
*
* This setting can be modified on the fly if needed.
*/
@Override
public EpollDomainSocketChannelConfig setReadMode(DomainSocketReadMode mode) {
if (mode == null) {
throw new NullPointerException("mode");
@ -135,9 +130,7 @@ public final class EpollDomainSocketChannelConfig extends EpollChannelConfig {
return this;
}
/**
* Return the {@link DomainSocketReadMode} for the channel.
*/
@Override
public DomainSocketReadMode getReadMode() {
return mode;
}

View File

@ -16,7 +16,9 @@
package io.netty.channel.epoll;
import io.netty.channel.Channel;
import io.netty.channel.FileDescriptor;
import io.netty.channel.unix.DomainSocketAddress;
import io.netty.channel.unix.FileDescriptor;
import io.netty.channel.unix.ServerDomainSocketChannel;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
@ -24,7 +26,8 @@ import java.io.File;
import java.net.SocketAddress;
public final class EpollServerDomainSocketChannel extends AbstractEpollServerChannel {
public final class EpollServerDomainSocketChannel extends AbstractEpollServerChannel
implements ServerDomainSocketChannel {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(
EpollServerDomainSocketChannel.class);

View File

@ -17,8 +17,8 @@ package io.netty.channel.epoll;
import io.netty.channel.Channel;
import io.netty.channel.EventLoop;
import io.netty.channel.FileDescriptor;
import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.unix.FileDescriptor;
import java.net.InetSocketAddress;
import java.net.SocketAddress;

View File

@ -19,9 +19,9 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelPromise;
import io.netty.channel.EventLoop;
import io.netty.channel.FileDescriptor;
import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.unix.FileDescriptor;
import io.netty.util.concurrent.GlobalEventExecutor;
import io.netty.util.internal.OneTimeTask;

View File

@ -18,6 +18,7 @@ package io.netty.channel.epoll;
import io.netty.channel.ChannelException;
import io.netty.channel.DefaultFileRegion;
import io.netty.channel.unix.DomainSocketAddress;
import io.netty.util.internal.EmptyArrays;
import io.netty.util.internal.NativeLibraryLoader;
import io.netty.util.internal.PlatformDependent;

View File

@ -13,11 +13,15 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
package io.netty.channel.unix;
import java.io.File;
import java.net.SocketAddress;
/**
* A address for a
* <a href="http://en.wikipedia.org/wiki/Unix_domain_socket">Unix Domain Socket</a>.
*/
public final class DomainSocketAddress extends SocketAddress {
private final String socketPath;

View 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.
*/
package io.netty.channel.unix;
/**
* A {@link UnixChannel} that supports communication via
* <a href="http://en.wikipedia.org/wiki/Unix_domain_socket">Unix Domain Socket</a>.
*/
public interface DomainSocketChannel extends UnixChannel {
@Override
DomainSocketAddress remoteAddress();
@Override
DomainSocketAddress localAddress();
@Override
DomainSocketChannelConfig config();
}

View File

@ -0,0 +1,70 @@
/*
* 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.buffer.ByteBufAllocator;
import io.netty.channel.ChannelConfig;
import io.netty.channel.MessageSizeEstimator;
import io.netty.channel.RecvByteBufAllocator;
/**
* Special {@link ChannelConfig} for {@link DomainSocketChannel}s.
*/
public interface DomainSocketChannelConfig extends ChannelConfig {
@Override
DomainSocketChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead);
@Override
DomainSocketChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis);
@Override
DomainSocketChannelConfig setWriteSpinCount(int writeSpinCount);
@Override
DomainSocketChannelConfig setAllocator(ByteBufAllocator allocator);
@Override
DomainSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator);
@Override
DomainSocketChannelConfig setAutoRead(boolean autoRead);
@Override
DomainSocketChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark);
@Override
DomainSocketChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark);
@Override
DomainSocketChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator);
/**
* Change the {@link DomainSocketReadMode} for the channel. The default is
* {@link DomainSocketReadMode#BYTES} which means bytes will be read from the
* {@link io.netty.channel.Channel} and passed through the pipeline. If
* {@link DomainSocketReadMode#FILE_DESCRIPTORS} is used
* {@link FileDescriptor}s will be passed through the {@link io.netty.channel.ChannelPipeline}.
*
* This setting can be modified on the fly if needed.
*/
DomainSocketChannelConfig setReadMode(DomainSocketReadMode mode);
/**
* Return the {@link DomainSocketReadMode} for the channel.
*/
DomainSocketReadMode getReadMode();
}

View File

@ -13,17 +13,20 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
package io.netty.channel.unix;
/**
* Different modes of reading from a {@link DomainSocketChannel}.
*/
public enum DomainSocketReadMode {
/**
* Read (@link ByteBuf)s from the {@link EpollSocketChannel}.
* Read (@link ByteBuf)s from the {@link DomainSocketChannel}.
*/
BYTES,
/**
* Read (@link FileDscriptor)s from the {@link EpollSocketChannel}.
* Read (@link FileDscriptor)s from the {@link DomainSocketChannel}.
*/
FILE_DESCRIPTORS
}

View File

@ -13,9 +13,7 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel.epoll;
import io.netty.channel.FileDescriptor;
package io.netty.channel.unix;
import java.io.IOException;
@ -23,25 +21,44 @@ import java.io.IOException;
* Native {@link FileDescriptor} implementation which allows to wrap an {@code int} and provide a
* {@link FileDescriptor} for it.
*/
public final class NativeFileDescriptor implements FileDescriptor {
public class FileDescriptor {
private final int fd;
public NativeFileDescriptor(int fd) {
public FileDescriptor(int fd) {
if (fd < 0) {
throw new IllegalArgumentException("fd must be >= 0");
}
this.fd = fd;
}
@Override
/**
* An invalid file descriptor which was closed before.
*/
public static final FileDescriptor INVALID = new FileDescriptor(0) {
@Override
public int intValue() {
throw new IllegalStateException("invalid file descriptor");
}
@Override
public void close() {
// NOOP
}
};
/**
* Return the int value of the filedescriptor.
*/
public int intValue() {
return fd;
}
@Override
/**
* Close the file descriptor.
*/
public void close() throws IOException {
Native.close(fd);
close(fd);
}
@Override
@ -56,15 +73,17 @@ public final class NativeFileDescriptor implements FileDescriptor {
if (this == o) {
return true;
}
if (!(o instanceof NativeFileDescriptor)) {
if (!(o instanceof FileDescriptor)) {
return false;
}
return fd == ((NativeFileDescriptor) o).fd;
return fd == ((FileDescriptor) o).fd;
}
@Override
public int hashCode() {
return fd;
}
private static native int close(int fd);
}

View File

@ -0,0 +1,30 @@
/*
* 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.ServerChannel;
/**
* {@link ServerChannel} that accepts {@link DomainSocketChannel}'s via
* <a href="http://en.wikipedia.org/wiki/Unix_domain_socket">Unix Domain Socket</a>.
*/
public interface ServerDomainSocketChannel extends ServerChannel, UnixChannel {
@Override
DomainSocketAddress remoteAddress();
@Override
DomainSocketAddress localAddress();
}

View File

@ -13,34 +13,16 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.channel;
package io.netty.channel.unix;
import java.io.IOException;
public interface FileDescriptor {
import io.netty.channel.Channel;
/**
* {@link Channel} that expose operations that are only present on {@code UNIX} like systems.
*/
public interface UnixChannel extends Channel {
/**
* An invalid file descriptor which was closed before.
* Returns the {@link FileDescriptor} that is used by this {@link Channel}.
*/
FileDescriptor INVALID = new FileDescriptor() {
@Override
public int intValue() {
throw new IllegalStateException("invalid file descriptor");
}
@Override
public void close() {
// NOOP
}
};
/**
* Return the int value of the filedescriptor.
*/
int intValue();
/**
* Close the file descriptor.
*/
void close() throws IOException;
FileDescriptor fd();
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2014 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.
*/
/**
* Unix specific transport.
*/
package io.netty.channel.unix;

View File

@ -22,6 +22,8 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.unix.DomainSocketReadMode;
import io.netty.channel.unix.FileDescriptor;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.socket.AbstractSocketTest;
import org.junit.Assert;
@ -71,7 +73,7 @@ public class EpollDomainSocketFdTest extends AbstractSocketTest {
cb.handler(new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
NativeFileDescriptor fd = (NativeFileDescriptor) msg;
FileDescriptor fd = (FileDescriptor) msg;
queue.offer(fd);
}
@ -90,9 +92,9 @@ public class EpollDomainSocketFdTest extends AbstractSocketTest {
cc.close().sync();
sc.close().sync();
if (received instanceof NativeFileDescriptor) {
Assert.assertNotSame(NativeFileDescriptor.INVALID, received);
((NativeFileDescriptor) received).close();
if (received instanceof FileDescriptor) {
Assert.assertNotSame(FileDescriptor.INVALID, received);
((FileDescriptor) received).close();
Assert.assertNull(queue.poll());
} else {
throw (Throwable) received;

View File

@ -24,6 +24,7 @@ import io.netty.channel.socket.InternetProtocolFamily;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.channel.unix.DomainSocketAddress;
import io.netty.testsuite.transport.TestsuitePermutation;
import io.netty.testsuite.transport.TestsuitePermutation.BootstrapFactory;
import io.netty.testsuite.transport.socket.SocketTestPermutation;