Java tutorial
/* * Copyright (c) 2013 Robert Varga. All rights reserved. * * This program and the accompanying materials are made available under the * 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.tcpmd5.netty; import com.google.common.base.Preconditions; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelException; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelPromise; import io.netty.channel.EventLoop; import io.netty.channel.FileRegion; import io.netty.channel.nio.AbstractNioByteChannel; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import org.opendaylight.tcpmd5.api.KeyAccessFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * {@link io.netty.channel.socket.nio.NioSocketChannel} enabled with support for TCP MD5 Signature option. */ public class MD5NioSocketChannel extends AbstractNioByteChannel implements io.netty.channel.socket.SocketChannel { private static final Logger LOG = LoggerFactory.getLogger(MD5NioSocketChannel.class); private static final ChannelMetadata METADATA = new ChannelMetadata(false); private final MD5SocketChannelConfig config; private static SocketChannel newChannel() { try { return SocketChannel.open(); } catch (IOException e) { throw new ChannelException("Failed to instantiate channel", e); } } MD5NioSocketChannel(final MD5NioServerSocketChannel parent, final SocketChannel channel, final KeyAccessFactory factory) { super(parent, channel); this.config = new DefaultMD5SocketChannelConfig(this, factory); } public MD5NioSocketChannel(final KeyAccessFactory keyAccessFactory) { this(null, newChannel(), keyAccessFactory); } @Override public MD5SocketChannelConfig config() { return this.config; } @Override protected SocketChannel javaChannel() { return (SocketChannel) super.javaChannel(); } @Override public boolean isActive() { final SocketChannel ch = javaChannel(); return ch.isOpen() && ch.isConnected(); } @Override public ChannelMetadata metadata() { return METADATA; } @Override public MD5NioServerSocketChannel parent() { return (MD5NioServerSocketChannel) super.parent(); } @Override public InetSocketAddress localAddress() { return (InetSocketAddress) super.localAddress(); } @Override public InetSocketAddress remoteAddress() { return (InetSocketAddress) super.remoteAddress(); } @Override public boolean isInputShutdown() { // Needed to un-hide the super implementation, which is protected // The logging here just side-steps sonar final boolean ret = super.isInputShutdown(); LOG.trace("Channel {} input shutdown {}", this, ret); return ret; } @Override public boolean isOutputShutdown() { return javaChannel().socket().isOutputShutdown() || !isActive(); } @Override public ChannelFuture shutdownOutput() { return shutdownOutput(newPromise()); } @Override public ChannelFuture shutdownOutput(final ChannelPromise future) { EventLoop loop = eventLoop(); if (loop.inEventLoop()) { try { javaChannel().socket().shutdownOutput(); future.setSuccess(); } catch (Exception e) { future.setFailure(e); } } else { loop.execute(new Runnable() { @Override public void run() { shutdownOutput(future); } }); } return future; } @Override protected long doWriteFileRegion(final FileRegion region) throws IOException { return region.transferTo(javaChannel(), region.transfered()); } @Override protected int doReadBytes(final ByteBuf buf) throws IOException { return buf.writeBytes(javaChannel(), buf.writableBytes()); } @Override protected int doWriteBytes(final ByteBuf buf) throws IOException { return buf.readBytes(javaChannel(), buf.readableBytes()); } @Override protected boolean doConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) throws IOException { if (localAddress != null) { javaChannel().socket().bind(localAddress); } boolean success = false; try { boolean connected = javaChannel().connect(remoteAddress); if (!connected) { selectionKey().interestOps(SelectionKey.OP_CONNECT); } success = true; return connected; } finally { if (!success) { doClose(); } } } @Override protected void doFinishConnect() throws IOException { Preconditions.checkState(javaChannel().finishConnect(), "finishConnect() failed"); } @Override protected SocketAddress localAddress0() { return javaChannel().socket().getLocalSocketAddress(); } @Override protected SocketAddress remoteAddress0() { return javaChannel().socket().getRemoteSocketAddress(); } @Override protected void doBind(final SocketAddress localAddress) throws IOException { javaChannel().socket().bind(localAddress); } @Override protected void doDisconnect() throws IOException { doClose(); } @Override protected void doClose() throws IOException { javaChannel().close(); } }