Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2002-2017 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.neo4j.bolt.transport;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.neo4j.logging.Log;
import org.neo4j.logging.LogProvider;
import static io.netty.buffer.Unpooled.wrappedBuffer;
/**
* Handles incoming chunks of data for a given client channel. This initially will negotiate a protocol version to use,
* and then delegate future messages to the chosen protocol.
*
* This class is stateful, one instance is expected per channel.
*/
public class SocketTransportHandler extends ChannelInboundHandlerAdapter
{
private final ProtocolChooser protocolChooser;
private final Log log;
private BoltProtocol protocol;
public SocketTransportHandler( ProtocolChooser protocolChooser, LogProvider logging )
{
this.protocolChooser = protocolChooser;
this.log = logging.getLog( getClass() );
}
@Override
public void channelRead( ChannelHandlerContext ctx, Object msg ) throws Exception
{
if ( msg instanceof ByteBuf )
{
ByteBuf buffer = (ByteBuf) msg;
if ( protocol == null )
{
chooseProtocolVersion( ctx, buffer );
}
else
{
protocol.handle( ctx, buffer );
}
}
else
{
ctx.fireChannelRead( msg );
}
}
@Override
public void channelInactive( ChannelHandlerContext ctx ) throws Exception
{
close( ctx );
}
@Override
public void handlerRemoved( ChannelHandlerContext ctx ) throws Exception
{
close( ctx );
}
@Override
public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause ) throws Exception
{
log.error( "Fatal error occurred when handling a client connection: " + cause.getMessage(), cause );
close( ctx );
}
private void close( ChannelHandlerContext ctx )
{
if ( protocol != null )
{
// handshake was successful and protocol was initialized, so it needs to be closed now
// channel will be closed as part of the protocol's close procedure
protocol.close();
protocol = null;
}
else
{
// handshake did not happen or failed, protocol was not initialized, so we need to close the channel
// channel will be closed as part of the context's close procedure
ctx.close();
}
}
private void chooseProtocolVersion( ChannelHandlerContext ctx, ByteBuf buffer ) throws Exception
{
HandshakeOutcome outcome = protocolChooser.handleVersionHandshakeChunk( buffer, ctx.channel() );
switch ( outcome )
{
case PROTOCOL_CHOSEN:
// A protocol version has been successfully agreed upon, therefore we can
// reply positively with four bytes reflecting this selection and leave
// the connection open for INIT etc...
protocol = protocolChooser.chosenProtocol();
ctx.writeAndFlush( ctx.alloc().buffer( 4 ).writeInt( protocol.version() ) );
// If there is more data pending, the client optimistically sent this in its initial payload. It really
// shouldn't be doing that since it can't know which versions we support, but here we are anyway.
// Emulate a second call to channelRead, the remaining data in the buffer will be forwarded to the newly
// selected protocol.
if ( buffer.readableBytes() > 0 )
{
channelRead( ctx, buffer );
}
else
{
buffer.release();
}
return;
case NO_APPLICABLE_PROTOCOL:
// No protocol match could be found between the versions suggested by the
// client and the versions supported by the server. In this case, we have
// no option but to report a 'zero' version match and close the connection.
buffer.release();
ctx.writeAndFlush( wrappedBuffer( new byte[]{0, 0, 0, 0} ) )
.sync()
.channel()
.close();
return;
case INSECURE_HANDSHAKE:
// There has been an attempt to carry out an unencrypted handshake over a
// connection that requires encryption. No response will be sent and the
// connection will be closed immediately. Note this is the same action as
// for INVALID_HANDSHAKE below, so we can just fall through.
case INVALID_HANDSHAKE:
// The handshake went horribly wrong for some reason. As above, we'll
// simply close the connection and say no more about it.
buffer.release();
ctx.close();
return;
case PARTIAL_HANDSHAKE:
// Handshake ongoing. More bytes are required before the exchange is
// complete so we'll simply return and take no specific action.
return;
default:
throw new IllegalStateException( "Unknown handshake outcome: " + outcome );
}
}
}