blob: c2306351e9226d94466cdfaa77dc1905520bb0ea [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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 org.apache.kerby.kerberos.kdc.impl;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import org.apache.kerby.kerberos.kerb.KrbException;
import org.apache.kerby.kerberos.kerb.server.KdcContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.InetSocketAddress;
/**
* A combined and mixed network server handling UDP and TCP.
*/
public class NettyKdcNetwork {
private KdcContext kdcContext;
private InetSocketAddress tcpAddress;
private InetSocketAddress udpAddress;
private EventLoopGroup bossGroup;
private EventLoopGroup workerGroup;
private EventLoopGroup group;
private DefaultEventExecutorGroup executorGroup;
private static final Logger LOG = LoggerFactory.getLogger(NettyKdcNetwork.class);
public void init(KdcContext kdcContext) {
this.kdcContext = kdcContext;
// Configure the server.
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
executorGroup = new DefaultEventExecutorGroup(10); //TODO: to configure.
}
public void listen(InetSocketAddress tcpAddress,
InetSocketAddress udpAddress) throws IOException {
this.tcpAddress = tcpAddress;
this.udpAddress = udpAddress;
}
public void start() throws Exception {
try {
doStart();
} catch (Exception e) {
LOG.error("Error occurred while starting the netty kdc network. " + e.toString());
throw new KrbException("Error occurred while starting the netty kdc network. ", e);
}
}
private void doStart() throws Exception {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(createChannelInitializer());
// Start the server.
b.bind(tcpAddress.getPort()).sync();
if (udpAddress != null) {
startUDPServer();
}
}
private void startUDPServer() throws InterruptedException {
this.group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group).channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler((ChannelHandler) new NettyKdcUdpServerHandler(kdcContext));
b.bind(udpAddress.getPort()).sync();
}
static class KrbMessageDecoder extends LengthFieldBasedFrameDecoder {
KrbMessageDecoder() {
super(1 * 1024 * 1024, 0, 4, 0, 4, true);
}
}
private ChannelInitializer<SocketChannel> createChannelInitializer() {
return new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new KrbMessageDecoder());
p.addLast(executorGroup,
"KDC_HANDLER",
new NettyKdcHandler(kdcContext));
}
};
}
public synchronized void stop() {
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
if (udpAddress != null) {
group.shutdownGracefully();
}
try {
bossGroup.terminationFuture().sync();
workerGroup.terminationFuture().sync();
if (udpAddress != null) {
group.terminationFuture().sync();
}
} catch (InterruptedException e) {
LOG.error("Interrupted when sync. " + e);
}
}
}