/*
* (C) Copyright 2015-2016 the original author or authors.
*
* Licensed 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.
*
* Contributors:
* ohun@live.cn (夜色)
*/
package com.mpush.netty.udp;
import com.mpush.api.PacketReceiver;
import com.mpush.api.connection.Connection;
import com.mpush.api.protocol.Packet;
import com.mpush.netty.codec.PacketDecoder;
import com.mpush.netty.connection.NettyConnection;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.DatagramPacket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
/**
* Created by ohun on 16/10/21.
*
* @author ohun@live.cn (夜色)
*/
@ChannelHandler.Sharable
public final class UDPChannelHandler extends ChannelInboundHandlerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(UDPChannelHandler.class);
private final NettyConnection connection = new NettyConnection();
private final PacketReceiver receiver;
private InetAddress multicastAddress;
private NetworkInterface networkInterface;
public UDPChannelHandler(PacketReceiver receiver) {
this.receiver = receiver;
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
connection.init(ctx.channel(), false);
if (multicastAddress != null) {
((DatagramChannel) ctx.channel()).joinGroup(multicastAddress, networkInterface, null).addListener(future -> {
if (future.isSuccess()) {
LOGGER.info("join multicast group success, channel={}, group={}", ctx.channel(), multicastAddress);
} else {
LOGGER.error("join multicast group error, channel={}, group={}", ctx.channel(), multicastAddress, future.cause());
}
});
}
LOGGER.info("init udp channel={}", ctx.channel());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
connection.close();
if (multicastAddress != null) {
((DatagramChannel) ctx.channel()).leaveGroup(multicastAddress, networkInterface, null).addListener(future -> {
if (future.isSuccess()) {
LOGGER.info("leave multicast group success, channel={}, group={}", ctx.channel(), multicastAddress);
} else {
LOGGER.error("leave multicast group error, channel={}, group={}", ctx.channel(), multicastAddress, future.cause());
}
});
}
LOGGER.info("disconnect udp channel={}, connection={}", ctx.channel(), connection);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
DatagramPacket datagramPacket = (DatagramPacket) msg;
Packet packet = PacketDecoder.decodeFrame(datagramPacket);
receiver.onReceive(packet, connection);
datagramPacket.release();//最后一个使用方要释放引用
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
connection.close();
LOGGER.error("udp handler caught an exception, channel={}, conn={}", ctx.channel(), connection, cause);
}
public UDPChannelHandler setMulticastAddress(InetAddress multicastAddress) {
if (!multicastAddress.isMulticastAddress()) {
throw new IllegalArgumentException(multicastAddress + "not a multicastAddress");
}
this.multicastAddress = multicastAddress;
return this;
}
public UDPChannelHandler setNetworkInterface(NetworkInterface networkInterface) {
this.networkInterface = networkInterface;
return this;
}
public Connection getConnection() {
return connection;
}
}