2008-08-08 02:37:18 +02:00
|
|
|
/*
|
2011-12-09 06:18:34 +01:00
|
|
|
* Copyright 2011 The Netty Project
|
2008-08-08 02:37:18 +02:00
|
|
|
*
|
2011-12-09 06:18:34 +01:00
|
|
|
* 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:
|
2008-08-08 02:37:18 +02:00
|
|
|
*
|
2011-12-09 06:18:34 +01:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2008-08-08 03:27:24 +02:00
|
|
|
*
|
2009-08-28 09:15:49 +02:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
2011-12-09 06:18:34 +01:00
|
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
2009-08-28 09:15:49 +02:00
|
|
|
* License for the specific language governing permissions and limitations
|
|
|
|
* under the License.
|
2008-08-08 02:37:18 +02:00
|
|
|
*/
|
2011-12-09 04:38:59 +01:00
|
|
|
package io.netty.channel;
|
2008-08-08 02:37:18 +02:00
|
|
|
|
2012-05-20 07:19:11 +02:00
|
|
|
import io.netty.buffer.ChannelBuffer;
|
2012-05-01 10:19:41 +02:00
|
|
|
import io.netty.logging.InternalLogger;
|
|
|
|
import io.netty.logging.InternalLoggerFactory;
|
|
|
|
import io.netty.util.DefaultAttributeMap;
|
|
|
|
|
2012-05-09 16:42:01 +02:00
|
|
|
import java.io.IOException;
|
2012-05-11 13:44:00 +02:00
|
|
|
import java.net.ConnectException;
|
2008-08-08 02:37:18 +02:00
|
|
|
import java.net.SocketAddress;
|
2012-05-09 15:09:06 +02:00
|
|
|
import java.nio.channels.ClosedChannelException;
|
2012-05-25 15:16:25 +02:00
|
|
|
import java.util.ArrayDeque;
|
|
|
|
import java.util.Deque;
|
2012-05-24 17:57:10 +02:00
|
|
|
import java.util.Queue;
|
2012-05-15 10:10:54 +02:00
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
2009-02-16 12:59:33 +01:00
|
|
|
import java.util.concurrent.ConcurrentMap;
|
2012-05-11 13:44:00 +02:00
|
|
|
import java.util.concurrent.ScheduledFuture;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
2008-08-08 02:37:18 +02:00
|
|
|
|
|
|
|
/**
|
2008-09-02 09:13:20 +02:00
|
|
|
* A skeletal {@link Channel} implementation.
|
2008-08-08 02:37:18 +02:00
|
|
|
*/
|
2012-05-01 10:19:41 +02:00
|
|
|
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
|
|
|
|
|
|
|
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractChannel.class);
|
2008-08-08 02:37:18 +02:00
|
|
|
|
2009-02-16 12:59:33 +01:00
|
|
|
static final ConcurrentMap<Integer, Channel> allChannels = new ConcurrentHashMap<Integer, Channel>();
|
|
|
|
|
2012-05-09 15:09:06 +02:00
|
|
|
/**
|
|
|
|
* Generates a negative unique integer ID. This method generates only
|
|
|
|
* negative integers to avoid conflicts with user-specified IDs where only
|
|
|
|
* non-negative integers are allowed.
|
|
|
|
*/
|
2009-02-16 12:59:33 +01:00
|
|
|
private static Integer allocateId(Channel channel) {
|
2012-05-10 14:56:10 +02:00
|
|
|
int idVal = System.identityHashCode(channel);
|
|
|
|
if (idVal > 0) {
|
|
|
|
idVal = -idVal;
|
|
|
|
} else if (idVal == 0) {
|
2012-05-09 15:09:06 +02:00
|
|
|
idVal = -1;
|
|
|
|
}
|
2012-05-10 14:56:10 +02:00
|
|
|
|
2012-05-09 15:09:06 +02:00
|
|
|
Integer id;
|
2009-02-16 12:59:33 +01:00
|
|
|
for (;;) {
|
2012-05-09 15:09:06 +02:00
|
|
|
id = Integer.valueOf(idVal);
|
2009-02-16 12:59:33 +01:00
|
|
|
// Loop until a unique ID is acquired.
|
|
|
|
// It should be found in one loop practically.
|
|
|
|
if (allChannels.putIfAbsent(id, channel) == null) {
|
|
|
|
// Successfully acquired.
|
|
|
|
return id;
|
|
|
|
} else {
|
|
|
|
// Taken by other channel at almost the same moment.
|
2012-05-09 15:09:06 +02:00
|
|
|
idVal --;
|
|
|
|
if (idVal >= 0) {
|
|
|
|
idVal = -1;
|
|
|
|
}
|
2009-02-16 12:59:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-08 02:37:18 +02:00
|
|
|
private final Channel parent;
|
2012-05-09 15:09:06 +02:00
|
|
|
private final Integer id;
|
2012-05-01 10:19:41 +02:00
|
|
|
private final Unsafe unsafe;
|
2012-05-01 10:48:06 +02:00
|
|
|
private final ChannelPipeline pipeline = new DefaultChannelPipeline(this);
|
|
|
|
private final ChannelFuture succeededFuture = new SucceededChannelFuture(this);
|
2012-05-12 18:37:16 +02:00
|
|
|
private final ChannelFuture voidFuture = new VoidChannelFuture(this);
|
|
|
|
private final CloseFuture closeFuture = new CloseFuture(this);
|
2012-05-01 10:19:41 +02:00
|
|
|
|
2012-05-16 16:02:06 +02:00
|
|
|
private volatile SocketAddress localAddress;
|
|
|
|
private volatile SocketAddress remoteAddress;
|
2012-05-01 10:19:41 +02:00
|
|
|
private volatile EventLoop eventLoop;
|
2012-05-02 14:05:53 +02:00
|
|
|
private volatile boolean registered;
|
2012-05-09 15:09:06 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The future of the current connection attempt. If not null, subsequent
|
|
|
|
* connection attempts will fail.
|
|
|
|
*/
|
2012-05-02 14:05:53 +02:00
|
|
|
private ChannelFuture connectFuture;
|
2012-05-11 13:44:00 +02:00
|
|
|
private ScheduledFuture<?> connectTimeoutFuture;
|
|
|
|
private ConnectException connectTimeoutException;
|
|
|
|
|
2012-05-12 17:40:28 +02:00
|
|
|
private long flushedAmount;
|
2012-05-25 15:16:25 +02:00
|
|
|
private final Deque<FlushCheckpoint> flushCheckpoints = new ArrayDeque<FlushCheckpoint>();
|
2012-05-12 17:40:28 +02:00
|
|
|
private ClosedChannelException closedChannelException;
|
2008-08-08 02:37:18 +02:00
|
|
|
|
|
|
|
/** Cache for the string representation of this channel */
|
2012-05-01 10:19:41 +02:00
|
|
|
private boolean strValActive;
|
2008-08-08 02:37:18 +02:00
|
|
|
private String strVal;
|
2012-05-01 10:19:41 +02:00
|
|
|
|
2008-09-02 09:13:20 +02:00
|
|
|
/**
|
|
|
|
* Creates a new instance.
|
|
|
|
*
|
2012-05-09 15:09:06 +02:00
|
|
|
* @param id
|
|
|
|
* the unique non-negative integer ID of this channel.
|
|
|
|
* Specify {@code null} to auto-generate a unique negative integer
|
|
|
|
* ID.
|
2008-09-02 09:13:20 +02:00
|
|
|
* @param parent
|
|
|
|
* the parent of this channel. {@code null} if there's no parent.
|
|
|
|
*/
|
2012-05-09 15:09:06 +02:00
|
|
|
protected AbstractChannel(Channel parent, Integer id) {
|
|
|
|
if (id == null) {
|
|
|
|
id = allocateId(this);
|
|
|
|
} else {
|
|
|
|
if (id.intValue() < 0) {
|
|
|
|
throw new IllegalArgumentException("id: " + id + " (expected: >= 0)");
|
|
|
|
}
|
|
|
|
if (allChannels.putIfAbsent(id, this) != null) {
|
|
|
|
throw new IllegalArgumentException("duplicate ID: " + id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-01 10:19:41 +02:00
|
|
|
this.parent = parent;
|
2012-05-09 15:09:06 +02:00
|
|
|
this.id = id;
|
2012-05-01 10:19:41 +02:00
|
|
|
unsafe = new DefaultUnsafe();
|
2010-05-19 08:29:43 +02:00
|
|
|
|
2012-05-12 18:37:16 +02:00
|
|
|
closeFuture().addListener(new ChannelFutureListener() {
|
2012-05-01 10:19:41 +02:00
|
|
|
@Override
|
|
|
|
public void operationComplete(ChannelFuture future) {
|
|
|
|
allChannels.remove(id());
|
|
|
|
}
|
|
|
|
});
|
2010-05-19 08:29:43 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2012-05-01 10:19:41 +02:00
|
|
|
public final Integer id() {
|
2008-08-08 02:37:18 +02:00
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2012-05-01 10:19:41 +02:00
|
|
|
public Channel parent() {
|
2008-08-08 02:37:18 +02:00
|
|
|
return parent;
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2012-05-01 10:19:41 +02:00
|
|
|
public ChannelPipeline pipeline() {
|
2008-08-08 02:37:18 +02:00
|
|
|
return pipeline;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2012-05-01 10:19:41 +02:00
|
|
|
public EventLoop eventLoop() {
|
2012-05-09 15:09:06 +02:00
|
|
|
if (eventLoop == null) {
|
|
|
|
throw new IllegalStateException("channel not registered to an event loop");
|
|
|
|
}
|
2012-05-01 10:19:41 +02:00
|
|
|
return eventLoop;
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2012-05-16 16:02:06 +02:00
|
|
|
@Override
|
|
|
|
public SocketAddress localAddress() {
|
|
|
|
SocketAddress localAddress = this.localAddress;
|
|
|
|
if (localAddress == null) {
|
|
|
|
try {
|
|
|
|
this.localAddress = localAddress = unsafe().localAddress();
|
|
|
|
} catch (Throwable t) {
|
|
|
|
// Sometimes fails on a closed socket in Windows.
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return localAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void invalidateLocalAddress() {
|
|
|
|
localAddress = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public SocketAddress remoteAddress() {
|
|
|
|
SocketAddress remoteAddress = this.remoteAddress;
|
|
|
|
if (remoteAddress == null) {
|
|
|
|
try {
|
|
|
|
this.remoteAddress = remoteAddress = unsafe().remoteAddress();
|
|
|
|
} catch (Throwable t) {
|
|
|
|
// Sometimes fails on a closed socket in Windows.
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return remoteAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void invalidateRemoteAddress() {
|
|
|
|
remoteAddress = null;
|
|
|
|
}
|
|
|
|
|
2012-05-09 15:09:06 +02:00
|
|
|
@Override
|
|
|
|
public boolean isOpen() {
|
|
|
|
return unsafe().ch().isOpen();
|
|
|
|
}
|
|
|
|
|
2012-05-02 14:05:53 +02:00
|
|
|
@Override
|
|
|
|
public boolean isRegistered() {
|
|
|
|
return registered;
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2012-05-09 15:09:06 +02:00
|
|
|
public ChannelFuture bind(SocketAddress localAddress) {
|
2012-05-11 02:00:35 +02:00
|
|
|
return pipeline().bind(localAddress);
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2012-05-09 15:09:06 +02:00
|
|
|
public ChannelFuture connect(SocketAddress remoteAddress) {
|
2012-05-11 02:00:35 +02:00
|
|
|
return pipeline().connect(remoteAddress);
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2012-05-09 15:09:06 +02:00
|
|
|
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
|
2012-05-11 02:00:35 +02:00
|
|
|
return pipeline().connect(remoteAddress, localAddress);
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2012-05-09 15:09:06 +02:00
|
|
|
public ChannelFuture disconnect() {
|
2012-05-11 02:00:35 +02:00
|
|
|
return pipeline().disconnect();
|
2008-10-02 06:40:46 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2012-05-09 15:09:06 +02:00
|
|
|
public ChannelFuture close() {
|
2012-05-11 02:00:35 +02:00
|
|
|
return pipeline().close();
|
2008-11-26 10:21:00 +01:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2012-05-09 15:09:06 +02:00
|
|
|
public ChannelFuture deregister() {
|
2012-05-11 02:00:35 +02:00
|
|
|
return pipeline().deregister();
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2012-05-09 15:09:06 +02:00
|
|
|
public ChannelFuture flush() {
|
2012-05-11 02:00:35 +02:00
|
|
|
return pipeline().flush();
|
2012-05-09 15:09:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ChannelFuture write(Object message) {
|
2012-05-11 02:00:35 +02:00
|
|
|
return pipeline().write(message);
|
2012-05-09 15:09:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ChannelFuture bind(SocketAddress localAddress, ChannelFuture future) {
|
|
|
|
return pipeline().bind(localAddress, future);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ChannelFuture connect(SocketAddress remoteAddress, ChannelFuture future) {
|
|
|
|
return pipeline().connect(remoteAddress, future);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelFuture future) {
|
|
|
|
return pipeline().connect(remoteAddress, localAddress, future);
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2012-05-09 15:09:06 +02:00
|
|
|
public ChannelFuture disconnect(ChannelFuture future) {
|
|
|
|
return pipeline().disconnect(future);
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2012-05-09 15:09:06 +02:00
|
|
|
public ChannelFuture close(ChannelFuture future) {
|
|
|
|
return pipeline().close(future);
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2012-05-09 15:09:06 +02:00
|
|
|
@Override
|
|
|
|
public ChannelFuture deregister(ChannelFuture future) {
|
|
|
|
return pipeline().deregister(future);
|
|
|
|
}
|
2012-05-01 10:48:06 +02:00
|
|
|
|
2012-05-09 15:09:06 +02:00
|
|
|
@Override
|
|
|
|
public ChannelBufferHolder<Object> out() {
|
|
|
|
return pipeline().out();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ChannelFuture flush(ChannelFuture future) {
|
|
|
|
return pipeline().flush(future);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ChannelFuture write(Object message, ChannelFuture future) {
|
|
|
|
return pipeline.write(message, future);
|
|
|
|
}
|
2012-05-01 10:48:06 +02:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public ChannelFuture newFuture() {
|
|
|
|
return new DefaultChannelFuture(this, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ChannelFuture newSucceededFuture() {
|
|
|
|
return succeededFuture;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ChannelFuture newFailedFuture(Throwable cause) {
|
|
|
|
return new FailedChannelFuture(this, cause);
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2012-05-12 18:37:16 +02:00
|
|
|
public ChannelFuture closeFuture() {
|
|
|
|
return closeFuture;
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2012-05-01 10:19:41 +02:00
|
|
|
public Unsafe unsafe() {
|
|
|
|
return unsafe;
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2012-05-01 10:19:41 +02:00
|
|
|
/**
|
|
|
|
* Returns the {@linkplain System#identityHashCode(Object) identity hash code}
|
|
|
|
* of this channel.
|
|
|
|
*/
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2012-05-01 10:19:41 +02:00
|
|
|
public final int hashCode() {
|
|
|
|
return System.identityHashCode(this);
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2012-05-01 10:19:41 +02:00
|
|
|
/**
|
|
|
|
* Returns {@code true} if and only if the specified object is identical
|
|
|
|
* with this channel (i.e: {@code this == o}).
|
|
|
|
*/
|
2011-12-07 07:54:15 +01:00
|
|
|
@Override
|
2012-05-01 10:19:41 +02:00
|
|
|
public final boolean equals(Object o) {
|
|
|
|
return this == o;
|
2011-12-07 07:54:15 +01:00
|
|
|
}
|
|
|
|
|
2012-05-01 10:19:41 +02:00
|
|
|
/**
|
|
|
|
* Compares the {@linkplain #id() ID} of the two channels.
|
|
|
|
*/
|
2011-12-07 07:54:15 +01:00
|
|
|
@Override
|
2012-05-01 10:19:41 +02:00
|
|
|
public final int compareTo(Channel o) {
|
|
|
|
return id().compareTo(o.id());
|
2011-12-07 07:54:15 +01:00
|
|
|
}
|
2012-05-01 10:19:41 +02:00
|
|
|
|
2008-09-02 09:13:20 +02:00
|
|
|
/**
|
|
|
|
* Returns the {@link String} representation of this channel. The returned
|
2012-05-01 10:19:41 +02:00
|
|
|
* string contains the {@linkplain #id() ID}, {@linkplain #localAddress() local address},
|
|
|
|
* and {@linkplain #remoteAddress() remote address} of this channel for
|
2008-09-02 09:13:20 +02:00
|
|
|
* easier identification.
|
|
|
|
*/
|
2008-08-08 02:37:18 +02:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
2012-05-01 10:19:41 +02:00
|
|
|
boolean active = isActive();
|
|
|
|
if (strValActive == active && strVal != null) {
|
2008-08-08 02:37:18 +02:00
|
|
|
return strVal;
|
|
|
|
}
|
|
|
|
|
2012-05-11 03:47:45 +02:00
|
|
|
SocketAddress remoteAddr = remoteAddress();
|
|
|
|
SocketAddress localAddr = localAddress();
|
|
|
|
if (remoteAddr != null) {
|
|
|
|
SocketAddress srcAddr;
|
|
|
|
SocketAddress dstAddr;
|
|
|
|
if (parent == null) {
|
|
|
|
srcAddr = localAddr;
|
|
|
|
dstAddr = remoteAddr;
|
2008-08-08 02:37:18 +02:00
|
|
|
} else {
|
2012-05-11 03:47:45 +02:00
|
|
|
srcAddr = remoteAddr;
|
|
|
|
dstAddr = localAddr;
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
2012-05-11 03:47:45 +02:00
|
|
|
strVal = String.format("[id: 0x%08x, %s %s %s]", id, srcAddr, active? "=>" : ":>", dstAddr);
|
|
|
|
} else if (localAddr != null) {
|
|
|
|
strVal = String.format("[id: 0x%08x, %s]", id, localAddr);
|
|
|
|
} else {
|
|
|
|
strVal = String.format("[id: 0x%08x]", id);
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2012-05-01 10:19:41 +02:00
|
|
|
strValActive = active;
|
2009-02-09 09:00:26 +01:00
|
|
|
return strVal;
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
2009-02-16 15:32:40 +01:00
|
|
|
|
2012-05-01 10:19:41 +02:00
|
|
|
private class DefaultUnsafe implements Unsafe {
|
2010-01-09 06:40:40 +01:00
|
|
|
|
|
|
|
@Override
|
2012-05-01 10:19:41 +02:00
|
|
|
public java.nio.channels.Channel ch() {
|
|
|
|
return javaChannel();
|
2010-01-09 06:40:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2012-05-01 10:19:41 +02:00
|
|
|
public ChannelBufferHolder<Object> out() {
|
|
|
|
return firstOut();
|
2010-01-09 06:40:40 +01:00
|
|
|
}
|
|
|
|
|
2012-05-10 17:57:42 +02:00
|
|
|
@Override
|
|
|
|
public ChannelFuture voidFuture() {
|
|
|
|
return voidFuture;
|
|
|
|
}
|
|
|
|
|
2012-05-02 08:01:58 +02:00
|
|
|
@Override
|
|
|
|
public SocketAddress localAddress() {
|
|
|
|
return localAddress0();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public SocketAddress remoteAddress() {
|
|
|
|
return remoteAddress0();
|
|
|
|
}
|
|
|
|
|
2012-05-01 16:18:29 +02:00
|
|
|
@Override
|
|
|
|
public void register(EventLoop eventLoop, ChannelFuture future) {
|
|
|
|
if (eventLoop == null) {
|
|
|
|
throw new NullPointerException("eventLoop");
|
|
|
|
}
|
2012-05-14 16:57:23 +02:00
|
|
|
if (isRegistered()) {
|
2012-05-01 16:18:29 +02:00
|
|
|
throw new IllegalStateException("registered to an event loop already");
|
|
|
|
}
|
2012-05-12 17:40:28 +02:00
|
|
|
if (!isCompatible(eventLoop)) {
|
|
|
|
throw new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName());
|
|
|
|
}
|
|
|
|
|
2012-05-01 16:18:29 +02:00
|
|
|
AbstractChannel.this.eventLoop = eventLoop;
|
|
|
|
|
|
|
|
assert eventLoop().inEventLoop();
|
2012-05-09 15:09:06 +02:00
|
|
|
|
|
|
|
if (!ensureOpen(future)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
doRegister();
|
|
|
|
registered = true;
|
|
|
|
future.setSuccess();
|
2012-05-02 14:05:53 +02:00
|
|
|
pipeline().fireChannelRegistered();
|
2012-05-10 16:19:59 +02:00
|
|
|
if (isActive()) {
|
|
|
|
pipeline().fireChannelActive();
|
|
|
|
}
|
2012-05-09 15:09:06 +02:00
|
|
|
} catch (Throwable t) {
|
|
|
|
// Close the channel directly to avoid FD leak.
|
|
|
|
try {
|
|
|
|
doClose();
|
|
|
|
} catch (Throwable t2) {
|
|
|
|
logger.warn("Failed to close a channel", t2);
|
|
|
|
}
|
|
|
|
|
|
|
|
future.setFailure(t);
|
|
|
|
pipeline().fireExceptionCaught(t);
|
2012-05-14 07:17:40 +02:00
|
|
|
closeFuture().setSuccess();
|
2012-05-02 14:05:53 +02:00
|
|
|
}
|
2012-05-01 16:18:29 +02:00
|
|
|
}
|
|
|
|
|
2012-05-01 10:19:41 +02:00
|
|
|
@Override
|
|
|
|
public void bind(final SocketAddress localAddress, final ChannelFuture future) {
|
|
|
|
if (eventLoop().inEventLoop()) {
|
2012-05-09 15:09:06 +02:00
|
|
|
if (!ensureOpen(future)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
boolean wasActive = isActive();
|
|
|
|
doBind(localAddress);
|
|
|
|
future.setSuccess();
|
|
|
|
if (!wasActive && isActive()) {
|
|
|
|
pipeline().fireChannelActive();
|
|
|
|
}
|
|
|
|
} catch (Throwable t) {
|
|
|
|
future.setFailure(t);
|
|
|
|
pipeline().fireExceptionCaught(t);
|
|
|
|
closeIfClosed();
|
|
|
|
}
|
2012-05-01 10:19:41 +02:00
|
|
|
} else {
|
|
|
|
eventLoop().execute(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2012-05-09 15:09:06 +02:00
|
|
|
bind(localAddress, future);
|
2012-05-01 10:19:41 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void connect(final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelFuture future) {
|
|
|
|
if (eventLoop().inEventLoop()) {
|
2012-05-09 15:09:06 +02:00
|
|
|
if (!ensureOpen(future)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
if (connectFuture != null) {
|
|
|
|
throw new IllegalStateException("connection attempt already made");
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean wasActive = isActive();
|
|
|
|
if (doConnect(remoteAddress, localAddress)) {
|
|
|
|
future.setSuccess();
|
|
|
|
if (!wasActive && isActive()) {
|
|
|
|
pipeline().fireChannelActive();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
connectFuture = future;
|
2012-05-11 13:44:00 +02:00
|
|
|
|
|
|
|
// Schedule connect timeout.
|
|
|
|
int connectTimeoutMillis = config().getConnectTimeoutMillis();
|
|
|
|
if (connectTimeoutMillis > 0) {
|
|
|
|
connectTimeoutFuture = eventLoop().schedule(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
if (connectTimeoutException == null) {
|
|
|
|
connectTimeoutException = new ConnectException("connection timed out");
|
|
|
|
}
|
|
|
|
ChannelFuture connectFuture = AbstractChannel.this.connectFuture;
|
|
|
|
if (connectFuture == null) {
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
if (connectFuture.setFailure(connectTimeoutException)) {
|
|
|
|
pipeline().fireExceptionCaught(connectTimeoutException);
|
|
|
|
close(voidFuture());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, connectTimeoutMillis, TimeUnit.MILLISECONDS);
|
|
|
|
}
|
2012-05-09 15:09:06 +02:00
|
|
|
}
|
|
|
|
} catch (Throwable t) {
|
|
|
|
future.setFailure(t);
|
|
|
|
pipeline().fireExceptionCaught(t);
|
|
|
|
closeIfClosed();
|
2012-05-02 14:05:53 +02:00
|
|
|
}
|
2012-05-01 10:19:41 +02:00
|
|
|
} else {
|
|
|
|
eventLoop().execute(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2012-05-09 15:09:06 +02:00
|
|
|
connect(remoteAddress, localAddress, future);
|
2012-05-01 10:19:41 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-02 14:05:53 +02:00
|
|
|
@Override
|
|
|
|
public void finishConnect() {
|
|
|
|
assert eventLoop().inEventLoop();
|
|
|
|
assert connectFuture != null;
|
2012-05-09 15:09:06 +02:00
|
|
|
try {
|
2012-05-11 14:19:19 +02:00
|
|
|
boolean wasActive = isActive();
|
2012-05-09 15:09:06 +02:00
|
|
|
doFinishConnect();
|
|
|
|
connectFuture.setSuccess();
|
2012-05-11 14:19:19 +02:00
|
|
|
if (!wasActive && isActive()) {
|
|
|
|
pipeline().fireChannelActive();
|
|
|
|
}
|
2012-05-09 15:09:06 +02:00
|
|
|
} catch (Throwable t) {
|
|
|
|
connectFuture.setFailure(t);
|
|
|
|
pipeline().fireExceptionCaught(t);
|
|
|
|
closeIfClosed();
|
|
|
|
} finally {
|
2012-05-11 13:44:00 +02:00
|
|
|
connectTimeoutFuture.cancel(false);
|
2012-05-09 15:09:06 +02:00
|
|
|
connectFuture = null;
|
|
|
|
}
|
2012-05-02 14:05:53 +02:00
|
|
|
}
|
|
|
|
|
2012-05-01 10:19:41 +02:00
|
|
|
@Override
|
|
|
|
public void disconnect(final ChannelFuture future) {
|
|
|
|
if (eventLoop().inEventLoop()) {
|
2012-05-09 15:09:06 +02:00
|
|
|
try {
|
|
|
|
boolean wasActive = isActive();
|
|
|
|
doDisconnect();
|
|
|
|
future.setSuccess();
|
|
|
|
if (wasActive && !isActive()) {
|
|
|
|
pipeline().fireChannelInactive();
|
|
|
|
}
|
|
|
|
} catch (Throwable t) {
|
|
|
|
future.setFailure(t);
|
|
|
|
closeIfClosed();
|
|
|
|
}
|
2012-05-01 10:19:41 +02:00
|
|
|
} else {
|
|
|
|
eventLoop().execute(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2012-05-09 15:09:06 +02:00
|
|
|
disconnect(future);
|
2012-05-01 10:19:41 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void close(final ChannelFuture future) {
|
|
|
|
if (eventLoop().inEventLoop()) {
|
2012-05-14 07:17:40 +02:00
|
|
|
if (closeFuture.setClosed()) {
|
2012-05-09 15:09:06 +02:00
|
|
|
boolean wasActive = isActive();
|
|
|
|
try {
|
|
|
|
doClose();
|
|
|
|
future.setSuccess();
|
|
|
|
} catch (Throwable t) {
|
|
|
|
future.setFailure(t);
|
|
|
|
}
|
2012-05-10 16:19:59 +02:00
|
|
|
|
2012-05-12 17:40:28 +02:00
|
|
|
if (closedChannelException != null) {
|
|
|
|
closedChannelException = new ClosedChannelException();
|
|
|
|
}
|
|
|
|
|
|
|
|
notifyFlushFutures(closedChannelException);
|
|
|
|
|
2012-05-09 15:09:06 +02:00
|
|
|
if (wasActive && !isActive()) {
|
|
|
|
pipeline().fireChannelInactive();
|
|
|
|
}
|
2012-05-10 16:19:59 +02:00
|
|
|
|
2012-05-10 17:57:42 +02:00
|
|
|
deregister(voidFuture());
|
2012-05-09 15:09:06 +02:00
|
|
|
} else {
|
|
|
|
// Closed already.
|
|
|
|
future.setSuccess();
|
|
|
|
}
|
2012-05-01 10:19:41 +02:00
|
|
|
} else {
|
|
|
|
eventLoop().execute(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2012-05-09 15:09:06 +02:00
|
|
|
close(future);
|
2012-05-01 10:19:41 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void deregister(final ChannelFuture future) {
|
|
|
|
if (eventLoop().inEventLoop()) {
|
2012-05-01 16:19:31 +02:00
|
|
|
try {
|
2012-05-09 15:09:06 +02:00
|
|
|
doDeregister();
|
|
|
|
} catch (Throwable t) {
|
|
|
|
logger.warn("Unexpected exception occurred while deregistering a channel.", t);
|
2012-05-01 16:19:31 +02:00
|
|
|
} finally {
|
2012-05-02 14:05:53 +02:00
|
|
|
registered = false;
|
2012-05-14 16:57:23 +02:00
|
|
|
future.setSuccess();
|
2012-05-02 14:05:53 +02:00
|
|
|
pipeline().fireChannelUnregistered();
|
2012-05-01 16:19:31 +02:00
|
|
|
}
|
2012-05-01 10:19:41 +02:00
|
|
|
} else {
|
|
|
|
eventLoop().execute(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2012-05-09 15:09:06 +02:00
|
|
|
deregister(future);
|
2012-05-01 10:19:41 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2012-05-09 15:09:06 +02:00
|
|
|
public void read() {
|
2012-05-01 10:19:41 +02:00
|
|
|
assert eventLoop().inEventLoop();
|
2012-05-20 07:19:11 +02:00
|
|
|
|
|
|
|
final ChannelBufferHolder<Object> buf = pipeline().nextIn();
|
2012-05-12 17:40:28 +02:00
|
|
|
boolean closed = false;
|
2012-05-20 08:03:28 +02:00
|
|
|
boolean read = false;
|
2012-05-09 15:09:06 +02:00
|
|
|
try {
|
2012-05-25 15:16:25 +02:00
|
|
|
if (buf.hasMessageBuffer()) {
|
|
|
|
Queue<Object> msgBuf = buf.messageBuffer();
|
|
|
|
for (;;) {
|
2012-05-26 00:32:28 +02:00
|
|
|
int localReadAmount = doReadMessages(msgBuf);
|
2012-05-25 15:16:25 +02:00
|
|
|
if (localReadAmount > 0) {
|
|
|
|
read = true;
|
|
|
|
} else if (localReadAmount == 0) {
|
|
|
|
break;
|
|
|
|
} else if (localReadAmount < 0) {
|
|
|
|
closed = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ChannelBuffer byteBuf = buf.byteBuffer();
|
|
|
|
for (;;) {
|
2012-05-26 00:32:28 +02:00
|
|
|
int localReadAmount = doReadBytes(byteBuf);
|
2012-05-25 15:16:25 +02:00
|
|
|
if (localReadAmount > 0) {
|
|
|
|
read = true;
|
|
|
|
} else if (localReadAmount < 0) {
|
|
|
|
closed = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!expandReadBuffer(byteBuf)) {
|
2012-05-20 07:19:11 +02:00
|
|
|
break;
|
|
|
|
}
|
2012-05-09 15:09:06 +02:00
|
|
|
}
|
|
|
|
}
|
2012-05-20 08:03:28 +02:00
|
|
|
} catch (Throwable t) {
|
|
|
|
if (read) {
|
|
|
|
read = false;
|
2012-05-09 15:09:06 +02:00
|
|
|
pipeline.fireInboundBufferUpdated();
|
|
|
|
}
|
|
|
|
pipeline().fireExceptionCaught(t);
|
2012-05-09 16:42:01 +02:00
|
|
|
if (t instanceof IOException) {
|
2012-05-10 17:57:42 +02:00
|
|
|
close(voidFuture());
|
2012-05-09 16:42:01 +02:00
|
|
|
}
|
2012-05-12 17:40:28 +02:00
|
|
|
} finally {
|
2012-05-20 08:03:28 +02:00
|
|
|
if (read) {
|
|
|
|
pipeline.fireInboundBufferUpdated();
|
|
|
|
}
|
2012-05-12 17:40:28 +02:00
|
|
|
if (closed && isOpen()) {
|
|
|
|
close(voidFuture());
|
|
|
|
}
|
2012-05-09 15:09:06 +02:00
|
|
|
}
|
2012-05-01 10:19:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2012-05-09 15:09:06 +02:00
|
|
|
public void flush(final ChannelFuture future) {
|
2012-05-01 10:19:41 +02:00
|
|
|
if (eventLoop().inEventLoop()) {
|
2012-05-12 17:40:28 +02:00
|
|
|
// Append flush future to the notification list.
|
2012-05-12 22:09:05 +02:00
|
|
|
if (future != voidFuture) {
|
2012-05-25 15:16:25 +02:00
|
|
|
long checkpoint = flushedAmount + out().size();
|
|
|
|
if (future instanceof FlushCheckpoint) {
|
|
|
|
FlushCheckpoint cp = (FlushCheckpoint) future;
|
|
|
|
cp.flushCheckpoint(checkpoint);
|
|
|
|
flushCheckpoints.add(cp);
|
2012-05-12 17:40:28 +02:00
|
|
|
} else {
|
2012-05-25 15:16:25 +02:00
|
|
|
flushCheckpoints.add(new DefaultFlushCheckpoint(checkpoint, future));
|
2012-05-12 17:40:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-12 22:09:05 +02:00
|
|
|
// Attempt/perform outbound I/O if:
|
|
|
|
// - the channel is inactive - flush0() will fail the futures.
|
|
|
|
// - the event loop has no plan to call flushForcibly().
|
|
|
|
if (!isActive() || !inEventLoopDrivenFlush()) {
|
|
|
|
// Note that we don't call flushForcibly() because otherwise its stack trace
|
|
|
|
// will be confusing.
|
|
|
|
flush0();
|
2012-05-09 15:09:06 +02:00
|
|
|
}
|
2012-05-01 10:19:41 +02:00
|
|
|
} else {
|
|
|
|
eventLoop().execute(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2012-05-12 17:40:28 +02:00
|
|
|
flush(future);
|
2012-05-01 10:19:41 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2010-01-09 06:40:40 +01:00
|
|
|
}
|
2012-05-09 15:09:06 +02:00
|
|
|
|
2012-05-12 22:09:05 +02:00
|
|
|
@Override
|
|
|
|
public void flushForcibly() {
|
|
|
|
flush0();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void flush0() {
|
|
|
|
// Perform outbound I/O.
|
|
|
|
try {
|
2012-05-24 17:57:10 +02:00
|
|
|
ChannelBufferHolder<Object> out = out();
|
|
|
|
if (out.hasByteBuffer()) {
|
|
|
|
flushByteBuf(out.byteBuffer());
|
|
|
|
} else {
|
|
|
|
flushMessageBuf(out.messageBuffer());
|
2012-05-12 22:09:05 +02:00
|
|
|
}
|
|
|
|
} catch (Throwable t) {
|
|
|
|
notifyFlushFutures(t);
|
|
|
|
pipeline().fireExceptionCaught(t);
|
|
|
|
close(voidFuture());
|
|
|
|
} finally {
|
|
|
|
if (!isActive()) {
|
|
|
|
close(voidFuture());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-24 17:57:10 +02:00
|
|
|
private void flushByteBuf(ChannelBuffer buf) throws Exception {
|
2012-05-26 00:32:28 +02:00
|
|
|
if (!buf.readable()) {
|
|
|
|
// Reset reader/writerIndex to 0 if the buffer is empty.
|
|
|
|
buf.clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-05-24 17:57:10 +02:00
|
|
|
for (int i = config().getWriteSpinCount() - 1; i >= 0; i --) {
|
2012-05-26 00:32:28 +02:00
|
|
|
int localFlushedAmount = doWriteBytes(buf, i == 0);
|
2012-05-24 17:57:10 +02:00
|
|
|
if (localFlushedAmount > 0) {
|
|
|
|
flushedAmount += localFlushedAmount;
|
|
|
|
notifyFlushFutures();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!buf.readable()) {
|
|
|
|
// Reset reader/writerIndex to 0 if the buffer is empty.
|
|
|
|
buf.clear();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void flushMessageBuf(Queue<Object> buf) throws Exception {
|
|
|
|
final int writeSpinCount = config().getWriteSpinCount() - 1;
|
|
|
|
while (!buf.isEmpty()) {
|
|
|
|
boolean wrote = false;
|
|
|
|
for (int i = writeSpinCount; i >= 0; i --) {
|
2012-05-26 00:32:28 +02:00
|
|
|
int localFlushedAmount = doWriteMessages(buf, i == 0);
|
2012-05-24 17:57:10 +02:00
|
|
|
if (localFlushedAmount > 0) {
|
|
|
|
flushedAmount += localFlushedAmount;
|
|
|
|
wrote = true;
|
|
|
|
notifyFlushFutures();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!wrote) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-12 17:40:28 +02:00
|
|
|
private void notifyFlushFutures() {
|
2012-05-25 15:16:25 +02:00
|
|
|
if (flushCheckpoints.isEmpty()) {
|
2012-05-12 17:40:28 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
final long flushedAmount = AbstractChannel.this.flushedAmount;
|
2012-05-25 15:16:25 +02:00
|
|
|
for (;;) {
|
|
|
|
FlushCheckpoint cp = flushCheckpoints.poll();
|
|
|
|
if (cp == null) {
|
2012-05-12 17:40:28 +02:00
|
|
|
break;
|
|
|
|
}
|
2012-05-25 15:16:25 +02:00
|
|
|
if (cp.flushCheckpoint() > flushedAmount) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cp.future().setSuccess();
|
|
|
|
}
|
2012-05-12 17:40:28 +02:00
|
|
|
|
|
|
|
// Avoid overflow
|
2012-05-25 15:16:25 +02:00
|
|
|
if (flushCheckpoints.isEmpty()) {
|
2012-05-12 17:40:28 +02:00
|
|
|
// Reset the counter if there's nothing in the notification list.
|
|
|
|
AbstractChannel.this.flushedAmount = 0;
|
|
|
|
} else if (flushedAmount >= 0x1000000000000000L) {
|
|
|
|
// Otherwise, reset the counter only when the counter grew pretty large
|
|
|
|
// so that we can reduce the cost of updating all entries in the notification list.
|
|
|
|
AbstractChannel.this.flushedAmount = 0;
|
2012-05-25 15:16:25 +02:00
|
|
|
for (FlushCheckpoint cp: flushCheckpoints) {
|
|
|
|
cp.flushCheckpoint(cp.flushCheckpoint() - flushedAmount);
|
|
|
|
}
|
2012-05-12 17:40:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void notifyFlushFutures(Throwable cause) {
|
2012-05-25 15:16:25 +02:00
|
|
|
for (;;) {
|
|
|
|
FlushCheckpoint cp = flushCheckpoints.poll();
|
|
|
|
if (cp == null) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cp.future().setFailure(cause);
|
2012-05-12 17:40:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-09 15:09:06 +02:00
|
|
|
private boolean ensureOpen(ChannelFuture future) {
|
|
|
|
if (isOpen()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Exception e = new ClosedChannelException();
|
|
|
|
future.setFailure(e);
|
|
|
|
pipeline().fireExceptionCaught(e);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void closeIfClosed() {
|
|
|
|
if (isOpen()) {
|
|
|
|
return;
|
|
|
|
}
|
2012-05-10 17:57:42 +02:00
|
|
|
close(voidFuture());
|
2012-05-09 15:09:06 +02:00
|
|
|
}
|
2010-01-09 06:40:40 +01:00
|
|
|
}
|
2012-05-01 10:19:41 +02:00
|
|
|
|
2012-05-25 15:16:25 +02:00
|
|
|
static abstract class FlushCheckpoint {
|
|
|
|
abstract long flushCheckpoint();
|
|
|
|
abstract void flushCheckpoint(long checkpoint);
|
|
|
|
abstract ChannelFuture future();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static class DefaultFlushCheckpoint extends FlushCheckpoint {
|
|
|
|
private long checkpoint;
|
2012-05-12 17:40:28 +02:00
|
|
|
private final ChannelFuture future;
|
|
|
|
|
2012-05-25 15:16:25 +02:00
|
|
|
DefaultFlushCheckpoint(long checkpoint, ChannelFuture future) {
|
|
|
|
this.checkpoint = checkpoint;
|
2012-05-12 17:40:28 +02:00
|
|
|
this.future = future;
|
2012-05-25 15:16:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
long flushCheckpoint() {
|
|
|
|
return checkpoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
void flushCheckpoint(long checkpoint) {
|
|
|
|
this.checkpoint = checkpoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
ChannelFuture future() {
|
|
|
|
return future;
|
2012-05-12 17:40:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-12 18:37:16 +02:00
|
|
|
private static final class CloseFuture extends DefaultChannelFuture implements ChannelFuture.Unsafe {
|
|
|
|
|
|
|
|
CloseFuture(AbstractChannel ch) {
|
|
|
|
super(ch, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean setSuccess() {
|
|
|
|
throw new IllegalStateException();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean setFailure(Throwable cause) {
|
|
|
|
throw new IllegalStateException();
|
|
|
|
}
|
|
|
|
|
2012-05-14 07:17:40 +02:00
|
|
|
boolean setClosed() {
|
2012-05-12 18:37:16 +02:00
|
|
|
boolean set = super.setSuccess();
|
|
|
|
assert set;
|
2012-05-14 07:17:40 +02:00
|
|
|
return set;
|
2012-05-12 18:37:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-12 17:40:28 +02:00
|
|
|
protected abstract boolean isCompatible(EventLoop loop);
|
|
|
|
|
2012-05-01 10:19:41 +02:00
|
|
|
protected abstract java.nio.channels.Channel javaChannel();
|
|
|
|
protected abstract ChannelBufferHolder<Object> firstOut();
|
|
|
|
|
2012-05-02 08:01:58 +02:00
|
|
|
protected abstract SocketAddress localAddress0();
|
|
|
|
protected abstract SocketAddress remoteAddress0();
|
|
|
|
|
2012-05-09 15:09:06 +02:00
|
|
|
protected abstract void doRegister() throws Exception;
|
|
|
|
protected abstract void doBind(SocketAddress localAddress) throws Exception;
|
|
|
|
protected abstract boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception;
|
|
|
|
protected abstract void doFinishConnect() throws Exception;
|
|
|
|
protected abstract void doDisconnect() throws Exception;
|
|
|
|
protected abstract void doClose() throws Exception;
|
|
|
|
protected abstract void doDeregister() throws Exception;
|
2012-05-01 10:19:41 +02:00
|
|
|
|
2012-05-26 00:32:28 +02:00
|
|
|
protected int doReadMessages(Queue<Object> buf) throws Exception {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected int doReadBytes(ChannelBuffer buf) throws Exception {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected int doWriteMessages(Queue<Object> buf, boolean lastSpin) throws Exception {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected int doWriteBytes(ChannelBuffer buf, boolean lastSpin) throws Exception {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
|
2012-05-12 22:09:05 +02:00
|
|
|
protected abstract boolean inEventLoopDrivenFlush();
|
2012-05-20 07:19:11 +02:00
|
|
|
|
2012-05-25 15:16:25 +02:00
|
|
|
private static boolean expandReadBuffer(ChannelBuffer byteBuf) {
|
2012-05-20 07:19:11 +02:00
|
|
|
if (!byteBuf.writable()) {
|
|
|
|
// FIXME: Use a sensible value.
|
2012-05-20 07:30:26 +02:00
|
|
|
byteBuf.ensureWritableBytes(4096);
|
2012-05-20 07:19:11 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|