All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.hekate.network.netty.NettyClientHandshakeHandler Maven / Gradle / Ivy

/*
 * Copyright 2022 The Hekate Project
 *
 * The Hekate 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.hekate.network.netty;

import io.hekate.network.netty.NetworkProtocol.HandshakeAccept;
import io.hekate.network.netty.NetworkProtocol.HandshakeReject;
import io.hekate.network.netty.NetworkProtocol.HandshakeRequest;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.ssl.SslHandshakeCompletionEvent;
import java.net.ConnectException;
import org.slf4j.Logger;

class NettyClientHandshakeHandler extends SimpleChannelInboundHandler {
    private final Logger log;

    private final boolean debug;

    private final boolean trace;

    private final String id;

    private final String protocol;

    private final int affinity;

    private final T login;

    private final boolean ssl;

    // TODO: Workaround for https://github.com/netty/netty/pull/10860 (remove after upgrading to Netty 4.1.56.Final or above).
    private boolean handshakeSent;

    public NettyClientHandshakeHandler(
        String id,
        String protocol,
        int affinity,
        T login,
        Logger log,
        boolean ssl
    ) {
        this.id = id;
        this.protocol = protocol;
        this.affinity = affinity;
        this.login = login;
        this.ssl = ssl;
        this.log = log;
        this.debug = log.isDebugEnabled();
        this.trace = log.isTraceEnabled();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);

        if (ssl) {
            if (trace) {
                log.trace("Deferred handshake until SSL connection is established [to={}]", id);
            }
        } else {
            handshake(ctx);
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof SslHandshakeCompletionEvent) {
            if (((SslHandshakeCompletionEvent)evt).isSuccess()) {
                if (trace) {
                    log.trace("SSL connection established [to={}]", id);
                }

                handshake(ctx);
            }
        }

        super.userEventTriggered(ctx, evt);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        ctx.fireExceptionCaught(new ConnectException("Got disconnected on handshake [channel=" + id + ']'));
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (trace) {
            log.trace("Received handshake response [from={}, message={}]", id, msg);
        }

        NetworkProtocol handshakeMsg = (NetworkProtocol)msg;

        if (handshakeMsg.type() == NetworkProtocol.Type.HANDSHAKE_REJECT) {
            HandshakeReject reject = (HandshakeReject)handshakeMsg;

            String reason = reject.reason();

            if (debug) {
                log.debug("Server rejected connection [to={}, reason={}]", id, reason);
            }

            ctx.fireExceptionCaught(new ConnectException(reason));
        } else {
            HandshakeAccept accept = (HandshakeAccept)handshakeMsg;

            // Unregister self from the pipeline (handshake is a one time event).
            ctx.pipeline().remove(this);

            // Fire handshake event.
            ctx.fireUserEventTriggered(new NettyClientHandshakeEvent(accept));
        }
    }

    private void handshake(ChannelHandlerContext ctx) {
        if (!handshakeSent) {
            handshakeSent = true;

            HandshakeRequest request = new HandshakeRequest(protocol, login, affinity);

            if (trace) {
                log.trace("Connected ...sending handshake request [qqq={}, to={}, from={}, request={}]", System.identityHashCode(this), id,
                    ctx.channel().localAddress(), request);
            }

            ctx.writeAndFlush(request);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy