/* * Copyright (c) 2015 Huawei, Inc and others. 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.usc.agent; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.DatagramPacket; import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import io.netty.util.AttributeKey; import java.net.ConnectException; import java.net.InetAddress; import java.net.PortUnreachableException; import java.util.HashMap; import org.opendaylight.usc.protocol.UscControl; import org.opendaylight.usc.protocol.UscData; import org.opendaylight.usc.protocol.UscError; import org.opendaylight.usc.protocol.UscFrame; import org.opendaylight.usc.protocol.UscHeader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.util.concurrent.SettableFuture; /** * @author gwu * */ public class UscAgentUdpHandler extends SimpleChannelInboundHandler<UscFrame> { private static final Logger LOG = LoggerFactory.getLogger(UscAgentUdpHandler.class); public static final AttributeKey<Integer> SESSION_ID = AttributeKey.valueOf("agentUdpSessionId"); public static final AttributeKey<Integer> PORT = AttributeKey.valueOf("agentUdpPort"); final EventLoopGroup clientGroup = new NioEventLoopGroup(); final Bootstrap cb = new Bootstrap(); final HashMap<Integer, Channel> clients = new HashMap<>(); final DatagramChannel plugin; private final UscAgentUdp agent; class ClientHandler extends SimpleChannelInboundHandler<DatagramPacket> { @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Exception { Channel ch = ctx.channel(); int sessionId = ch.attr(SESSION_ID).get(); int port = ch.attr(PORT).get(); if (e instanceof ConnectException) { UscError reply = new UscError(port, sessionId, UscError.ErrorCode.ECONNREFUSED.getCode()); plugin.writeAndFlush(reply); } else if (e instanceof PortUnreachableException) { UscError reply = new UscError(port, sessionId, UscError.ErrorCode.ENETUNREACH.getCode()); plugin.writeAndFlush(reply); } else { UscError reply = new UscError(port, sessionId, UscError.ErrorCode.E_OTHER.getCode()); plugin.writeAndFlush(reply); super.exceptionCaught(ctx, e); } } @Override protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { LOG.trace("Got reply " + packet); ByteBuf payload = packet.content(); Channel ch = ctx.channel(); int sessionId = ch.attr(SESSION_ID).get(); int port = ch.attr(PORT).get(); UscData reply = new UscData(port, sessionId, payload.copy()); LOG.trace("Send to plugin " + reply); plugin.writeAndFlush(reply); } }; public UscAgentUdpHandler(UscAgentUdp agent, NioDatagramChannel ch) { this.agent = agent; this.plugin = ch; cb.group(clientGroup); cb.channel(NioDatagramChannel.class); cb.handler(new ChannelInitializer<NioDatagramChannel>() { @Override protected void initChannel(NioDatagramChannel ch) throws Exception { LOG.trace("initChannel: clientHandler connects to EchoServer."); ChannelPipeline p = ch.pipeline(); p.addLast(new LoggingHandler("UscAgentUdpHandler 2", LogLevel.TRACE)); p.addLast(new ClientHandler()); p.addLast(new LoggingHandler("UscAgentUdpHandler 2", LogLevel.TRACE)); } }); } @Override protected void channelRead0(ChannelHandlerContext ctx, UscFrame frame) throws Exception { final UscHeader header = frame.getHeader(); final int sessionId = header.getSessionId(); final int port = header.getApplicationPort(); Channel client = clients.get(sessionId); if (frame instanceof UscData) { if (client == null) { try { client = cb.connect(InetAddress.getLoopbackAddress(), port).sync().channel(); client.attr(SESSION_ID).set(sessionId); client.attr(PORT).set(port); clients.put(sessionId, client); } catch (Exception e) { if (e instanceof ConnectException) { UscError reply = new UscError(port, sessionId, UscError.ErrorCode.ECONNREFUSED.getCode()); plugin.writeAndFlush(reply); } else if (e instanceof PortUnreachableException) { UscError reply = new UscError(port, sessionId, UscError.ErrorCode.ENETUNREACH.getCode()); plugin.writeAndFlush(reply); } else { UscError reply = new UscError(port, sessionId, UscError.ErrorCode.E_OTHER.getCode()); plugin.writeAndFlush(reply); throw e; } } } if (client != null) { client.writeAndFlush(frame.getPayload()); } } else if(frame instanceof UscControl) { UscControl control = (UscControl)frame; // close it if(control.getControlCode() == UscControl.ControlCode.TERMINATION_REQUEST) { if(client != null) { client.close(); clients.remove(sessionId); } // send back the response UscControl data = new UscControl(port, sessionId, UscControl.ControlCode.TERMINATION_RESPONSE.getCode()); plugin.writeAndFlush(data); LOG.trace("UscAgentUdpHandler send TERMINATION_RESPONSE"); } else if(control.getControlCode() == UscControl.ControlCode.TERMINATION_RESPONSE) { LOG.trace("UscAgentUdpHandler received control message TERMINATION_RESPONSE, port#: " + port + " ,session#: " + sessionId); SettableFuture<Boolean> status = agent.getCloseFuture().get(sessionId); status.set(true); try { LOG.trace("UscAgentUdp termination status: " + status.get()); }catch(Exception e) { ; } } else if(control.getControlCode() == UscControl.ControlCode.ECHO) { // send back the response UscControl data = new UscControl(port, sessionId, UscControl.ControlCode.ECHO.getCode()); plugin.writeAndFlush(data); LOG.trace("UscAgentUdpHandler send ECHO back."); } } } }