X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=netconf%2Fnetconf-netty-util%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetconf%2Fnettyutil%2FAbstractNetconfSessionNegotiator.java;h=15db27a4c4ab9b0f4cb645af3bee090871045769;hb=f66e0af27ba2ac1099924685f298033751f72854;hp=b3d35dc3c0d05bd8811505b4c450948052c9f0ff;hpb=4198af3bf54526fa0b2ca4e4e1e1f8b0c81eb281;p=netconf.git diff --git a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/AbstractNetconfSessionNegotiator.java b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/AbstractNetconfSessionNegotiator.java index b3d35dc3c0..15db27a4c4 100644 --- a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/AbstractNetconfSessionNegotiator.java +++ b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/AbstractNetconfSessionNegotiator.java @@ -5,24 +5,22 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ - package org.opendaylight.netconf.nettyutil; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; +import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; + import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.ssl.SslHandler; import io.netty.util.Timeout; import io.netty.util.Timer; -import io.netty.util.TimerTask; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; import io.netty.util.concurrent.Promise; +import java.util.Optional; import java.util.concurrent.TimeUnit; +import org.checkerframework.checker.lock.qual.GuardedBy; import org.opendaylight.netconf.api.NetconfDocumentedException; import org.opendaylight.netconf.api.NetconfMessage; import org.opendaylight.netconf.api.NetconfSessionListener; @@ -35,70 +33,76 @@ import org.opendaylight.netconf.nettyutil.handler.NetconfMessageToXMLEncoder; import org.opendaylight.netconf.nettyutil.handler.NetconfXMLToHelloMessageDecoder; import org.opendaylight.netconf.nettyutil.handler.NetconfXMLToMessageDecoder; import org.opendaylight.netconf.util.messages.FramingMechanism; -import org.opendaylight.protocol.framework.AbstractSessionNegotiator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; -public abstract class AbstractNetconfSessionNegotiator
, L extends NetconfSessionListener , L extends NetconfSessionListener () {
- @Override
- public void operationComplete(final ChannelFuture future) throws Exception {
- if(future.isSuccess()) {
- LOG.debug("Channel {} closed: success", future.channel());
- } else {
- LOG.warn("Channel {} closed: fail", future.channel());
- }
- }
- });
- }
- } else if(channel.isOpen()) {
- channel.pipeline().remove(NAME_OF_EXCEPTION_HANDLER);
- }
- }
- }
+ timeoutTask = this.timer.newTimeout(this::timeoutExpired, connectionTimeoutMillis, TimeUnit.MILLISECONDS);
+ }
- private boolean isPromiseFinished() {
- return promise.isDone() || promise.isCancelled();
+ private synchronized void timeoutExpired(final Timeout timeout) {
+ if (state != State.ESTABLISHED) {
+ LOG.debug("Connection timeout after {}, session backed by channel {} is in state {}", timeout, channel,
+ state);
+
+ // Do not fail negotiation if promise is done or canceled
+ // It would result in setting result of the promise second time and that throws exception
+ if (!promise.isDone() && !promise.isCancelled()) {
+ LOG.warn("Netconf session backed by channel {} was not established after {}", channel,
+ connectionTimeoutMillis);
+ changeState(State.FAILED);
+
+ channel.close().addListener(future -> {
+ if (future.isSuccess()) {
+ LOG.debug("Channel {} closed: success", channel);
+ } else {
+ LOG.warn("Channel {} closed: fail", channel);
+ }
+ });
}
-
- }, connectionTimeoutMillis, TimeUnit.MILLISECONDS);
+ } else if (channel.isOpen()) {
+ channel.pipeline().remove(NAME_OF_EXCEPTION_HANDLER);
+ }
}
private void cancelTimeout() {
- if(timeout!=null) {
- timeout.cancel();
+ if (timeoutTask != null) {
+ timeoutTask.cancel();
}
}
- protected final S getSessionForHelloMessage(final NetconfHelloMessage netconfMessage) throws NetconfDocumentedException {
- Preconditions.checkNotNull(netconfMessage, "netconfMessage");
-
+ protected final S getSessionForHelloMessage(final NetconfHelloMessage netconfMessage)
+ throws NetconfDocumentedException {
final Document doc = netconfMessage.getDocument();
if (shouldUseChunkFraming(doc)) {
@@ -170,8 +163,11 @@ public abstract class AbstractNetconfSessionNegotiator
* Inbound hello message handler should be kept until negotiation is successful
* It caches any non-hello messages while negotiation is still in progress
*/
protected final void replaceHelloMessageInboundHandler(final S session) {
- ChannelHandler helloMessageHandler = replaceChannelHandler(channel, AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, new NetconfXMLToMessageDecoder());
+ ChannelHandler helloMessageHandler = replaceChannelHandler(channel,
+ AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, new NetconfXMLToMessageDecoder());
- Preconditions.checkState(helloMessageHandler instanceof NetconfXMLToHelloMessageDecoder,
+ checkState(helloMessageHandler instanceof NetconfXMLToHelloMessageDecoder,
"Pipeline handlers misplaced on session: %s, pipeline: %s", session, channel.pipeline());
Iterable {
+ if (!f.isSuccess()) {
+ LOG.info("Failed to send message {} on channel {}", msg, channel, f.cause());
+ negotiationFailed(f.cause());
+ } else {
+ LOG.trace("Message {} sent to socket on channel {}", msg, channel);
+ }
+ });
+ }
+
+ @Override
+ @SuppressWarnings("checkstyle:illegalCatch")
+ public final void channelActive(final ChannelHandlerContext ctx) {
+ LOG.debug("Starting session negotiation on channel {}", channel);
+ try {
+ startNegotiation();
+ } catch (final Exception e) {
+ LOG.warn("Unexpected negotiation failure on channel {}", channel, e);
+ negotiationFailed(e);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("checkstyle:illegalCatch")
+ public final void channelRead(final ChannelHandlerContext ctx, final Object msg) {
+ LOG.debug("Negotiation read invoked on channel {}", channel);
+ try {
+ handleMessage((NetconfHelloMessage) msg);
+ } catch (final Exception e) {
+ LOG.debug("Unexpected error while handling negotiation message {} on channel {}", msg, channel, e);
+ negotiationFailed(e);
+ }
+ }
+
+ @Override
+ public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
+ LOG.info("Unexpected error during negotiation on channel {}", channel, cause);
+ negotiationFailed(cause);
+ }
+
+ protected abstract void handleMessage(NetconfHelloMessage msg) throws Exception;
}
>
- extends AbstractSessionNegotiator>
+ extends ChannelInboundHandlerAdapter implements NetconfSessionNegotiator {
+ /**
+ * Possible states for Finite State Machine.
+ */
+ protected enum State {
+ IDLE, OPEN_WAIT, FAILED, ESTABLISHED
+ }
private static final Logger LOG = LoggerFactory.getLogger(AbstractNetconfSessionNegotiator.class);
public static final String NAME_OF_EXCEPTION_HANDLER = "lastExceptionHandler";
protected final P sessionPreferences;
+ protected final Channel channel;
+ private final long connectionTimeoutMillis;
+ private final Promise promise;
private final L sessionListener;
- private Timeout timeout;
+ private final Timer timer;
- /**
- * Possible states for Finite State Machine
- */
- protected enum State {
- IDLE, OPEN_WAIT, FAILED, ESTABLISHED
- }
+ private Timeout timeoutTask;
+ @GuardedBy("this")
private State state = State.IDLE;
- private final Promise promise;
- private final Timer timer;
- private final long connectionTimeoutMillis;
- protected AbstractNetconfSessionNegotiator(final P sessionPreferences, final Promise promise, final Channel channel, final Timer timer,
- final L sessionListener, final long connectionTimeoutMillis) {
- super(promise, channel);
+ protected AbstractNetconfSessionNegotiator(final P sessionPreferences, final Promise promise,
+ final Channel channel, final Timer timer,
+ final L sessionListener, final long connectionTimeoutMillis) {
+ this.channel = requireNonNull(channel);
+ this.promise = requireNonNull(promise);
this.sessionPreferences = sessionPreferences;
- this.promise = promise;
this.timer = timer;
this.sessionListener = sessionListener;
this.connectionTimeoutMillis = connectionTimeoutMillis;
}
- @Override
protected final void startNegotiation() {
- final Optional