mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-09-02 15:15:09 +00:00
Initial netty implementation
This commit is contained in:
@@ -11,7 +11,7 @@ apply plugin: 'com.android.application'
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 22
|
compileSdkVersion 22
|
||||||
buildToolsVersion '22.0.1'
|
buildToolsVersion '22.0.0'
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 9
|
minSdkVersion 9
|
||||||
targetSdkVersion 22
|
targetSdkVersion 22
|
||||||
@@ -54,8 +54,7 @@ dependencies {
|
|||||||
compile 'org.apache.mina:mina-core:2.0.9'
|
compile 'org.apache.mina:mina-core:2.0.9'
|
||||||
compile 'org.apache.sshd:sshd-core:0.8.0'
|
compile 'org.apache.sshd:sshd-core:0.8.0'
|
||||||
compile 'org.bouncycastle:bcprov-jdk16:1.46'
|
compile 'org.bouncycastle:bcprov-jdk16:1.46'
|
||||||
|
compile 'io.netty:netty-all:4.0.23.Final'
|
||||||
|
|
||||||
androidTestCompile 'org.mockito:mockito-core:1.10.19'
|
androidTestCompile 'org.mockito:mockito-core:1.10.19'
|
||||||
|
|
||||||
// Because mockito has some problems with dex environment
|
// Because mockito has some problems with dex environment
|
||||||
|
@@ -42,19 +42,23 @@ import java.util.Timer;
|
|||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
|
||||||
public class LanLink extends BaseLink {
|
public class LanLink extends BaseLink {
|
||||||
|
|
||||||
private IoSession session = null;
|
// private IoSession session = null;
|
||||||
|
private Channel session = null;
|
||||||
|
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
Log.e("KDE/LanLink", "Not yet connected");
|
Log.e("KDE/LanLink", "Not yet connected");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.close(true);
|
session.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LanLink(IoSession session, String deviceId, BaseLinkProvider linkProvider) {
|
public LanLink(Channel session, String deviceId, BaseLinkProvider linkProvider) {
|
||||||
super(deviceId, linkProvider);
|
super(deviceId, linkProvider);
|
||||||
this.session = session;
|
this.session = session;
|
||||||
}
|
}
|
||||||
@@ -86,14 +90,14 @@ public class LanLink extends BaseLink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Send body of the network package
|
//Send body of the network package
|
||||||
WriteFuture future = session.write(np.serialize());
|
ChannelFuture future = session.writeAndFlush(np.serialize()).sync();
|
||||||
future.awaitUninterruptibly();
|
if (!future.isSuccess()) {
|
||||||
if (!future.isWritten()) {
|
|
||||||
Log.e("KDE/sendPackage", "!future.isWritten()");
|
Log.e("KDE/sendPackage", "!future.isWritten()");
|
||||||
callback.sendFailure(future.getException());
|
callback.sendFailure(future.cause());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Send payload
|
//Send payload
|
||||||
if (server != null) {
|
if (server != null) {
|
||||||
OutputStream socket = null;
|
OutputStream socket = null;
|
||||||
@@ -173,7 +177,7 @@ public class LanLink extends BaseLink {
|
|||||||
try {
|
try {
|
||||||
socket = new Socket();
|
socket = new Socket();
|
||||||
int tcpPort = np.getPayloadTransferInfo().getInt("port");
|
int tcpPort = np.getPayloadTransferInfo().getInt("port");
|
||||||
InetSocketAddress address = (InetSocketAddress)session.getRemoteAddress();
|
InetSocketAddress address = (InetSocketAddress)session.remoteAddress();
|
||||||
socket.connect(new InetSocketAddress(address.getAddress(), tcpPort));
|
socket.connect(new InetSocketAddress(address.getAddress(), tcpPort));
|
||||||
np.setPayload(socket.getInputStream(), np.getPayloadSize());
|
np.setPayload(socket.getInputStream(), np.getPayloadSize());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@@ -25,32 +25,41 @@ import android.preference.PreferenceManager;
|
|||||||
import android.support.v4.util.LongSparseArray;
|
import android.support.v4.util.LongSparseArray;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.apache.mina.core.future.ConnectFuture;
|
|
||||||
import org.apache.mina.core.future.IoFuture;
|
|
||||||
import org.apache.mina.core.future.IoFutureListener;
|
|
||||||
import org.apache.mina.core.service.IoHandler;
|
|
||||||
import org.apache.mina.core.service.IoHandlerAdapter;
|
|
||||||
import org.apache.mina.core.session.IoSession;
|
|
||||||
import org.apache.mina.filter.codec.ProtocolCodecFilter;
|
|
||||||
import org.apache.mina.filter.codec.textline.LineDelimiter;
|
|
||||||
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
|
|
||||||
import org.apache.mina.transport.socket.nio.NioDatagramAcceptor;
|
|
||||||
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
|
|
||||||
import org.apache.mina.transport.socket.nio.NioSocketConnector;
|
|
||||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
import org.kde.kdeconnect.NetworkPackage;
|
import org.kde.kdeconnect.NetworkPackage;
|
||||||
import org.kde.kdeconnect.UserInterface.CustomDevicesActivity;
|
import org.kde.kdeconnect.UserInterface.CustomDevicesActivity;
|
||||||
|
|
||||||
import java.net.DatagramPacket;
|
|
||||||
import java.net.DatagramSocket;
|
import java.net.DatagramSocket;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Set;
|
|
||||||
|
import io.netty.bootstrap.Bootstrap;
|
||||||
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelFutureListener;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.ChannelOption;
|
||||||
|
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.DatagramPacket;
|
||||||
|
import io.netty.channel.socket.nio.NioDatagramChannel;
|
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
|
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
|
||||||
|
import io.netty.handler.codec.Delimiters;
|
||||||
|
import io.netty.handler.codec.string.StringDecoder;
|
||||||
|
import io.netty.handler.codec.string.StringEncoder;
|
||||||
|
import io.netty.handler.logging.LogLevel;
|
||||||
|
import io.netty.handler.logging.LoggingHandler;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
public class LanLinkProvider extends BaseLinkProvider {
|
public class LanLinkProvider extends BaseLinkProvider {
|
||||||
|
|
||||||
@@ -59,26 +68,29 @@ public class LanLinkProvider extends BaseLinkProvider {
|
|||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final HashMap<String, LanLink> visibleComputers = new HashMap<String, LanLink>();
|
private final HashMap<String, LanLink> visibleComputers = new HashMap<String, LanLink>();
|
||||||
private final LongSparseArray<LanLink> nioSessions = new LongSparseArray<LanLink>();
|
private final LongSparseArray<LanLink> nioLinks = new LongSparseArray<LanLink>();
|
||||||
private final LongSparseArray<NioSocketConnector> nioConnectors = new LongSparseArray<NioSocketConnector>();
|
private final LongSparseArray<Channel> nioChannels = new LongSparseArray<Channel>();
|
||||||
|
|
||||||
private NioSocketAcceptor tcpAcceptor = null;
|
private ServerBootstrap tcpBootstrap = null;
|
||||||
private NioDatagramAcceptor udpAcceptor = null;
|
private Bootstrap udpBootstrap = null;
|
||||||
|
private Channel udpChannel = null;
|
||||||
|
|
||||||
private final IoHandler tcpHandler = new IoHandlerAdapter() {
|
private class TcpHandler extends ChannelInboundHandlerAdapter{
|
||||||
@Override
|
@Override
|
||||||
public void sessionClosed(IoSession session) throws Exception {
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
super.channelInactive(ctx);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
long id = session.getId();
|
long id = ctx.channel().hashCode();
|
||||||
final LanLink brokenLink = nioSessions.get(id);
|
final LanLink brokenLink = nioLinks.get(id);
|
||||||
NioSocketConnector connector = nioConnectors.get(id);
|
Channel channel = nioChannels.get(id);
|
||||||
if (connector != null) {
|
if (channel != null) {
|
||||||
connector.dispose();
|
channel.close();
|
||||||
nioConnectors.remove(id);
|
nioChannels.remove(id);
|
||||||
}
|
}
|
||||||
if (brokenLink != null) {
|
if (brokenLink != null) {
|
||||||
nioSessions.remove(id);
|
nioLinks.remove(id);
|
||||||
//Log.i("KDE/LanLinkProvider", "nioSessions.size(): " + nioSessions.size() + " (-)");
|
//Log.i("KDE/LanLinkProvider", "nioLinks.size(): " + nioLinks.size() + " (-)");
|
||||||
try {
|
try {
|
||||||
brokenLink.disconnect();
|
brokenLink.disconnect();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -110,11 +122,12 @@ public class LanLinkProvider extends BaseLinkProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void messageReceived(IoSession session, Object message) throws Exception {
|
|
||||||
super.messageReceived(session, message);
|
|
||||||
|
|
||||||
//Log.e("LanLinkProvider","Incoming package, address: "+session.getRemoteAddress()).toString());
|
@Override
|
||||||
|
public void channelRead(ChannelHandlerContext ctx, Object message) throws Exception {
|
||||||
|
super.channelRead(ctx, message);
|
||||||
|
|
||||||
|
// Log.e("LanLinkProvider","Incoming package, address: " + ctx.channel().remoteAddress());
|
||||||
// Log.e("LanLinkProvider","Received:"+message);
|
// Log.e("LanLinkProvider","Received:"+message);
|
||||||
|
|
||||||
String theMessage = (String) message;
|
String theMessage = (String) message;
|
||||||
@@ -134,12 +147,12 @@ public class LanLinkProvider extends BaseLinkProvider {
|
|||||||
|
|
||||||
//Log.i("KDE/LanLinkProvider", "Identity package received from " + np.getString("deviceName"));
|
//Log.i("KDE/LanLinkProvider", "Identity package received from " + np.getString("deviceName"));
|
||||||
|
|
||||||
LanLink link = new LanLink(session, np.getString("deviceId"), LanLinkProvider.this);
|
LanLink link = new LanLink(ctx.channel(), np.getString("deviceId"), LanLinkProvider.this);
|
||||||
nioSessions.put(session.getId(),link);
|
nioLinks.put(ctx.channel().hashCode(), link);
|
||||||
//Log.e("KDE/LanLinkProvider","nioSessions.size(): " + nioSessions.size());
|
//Log.i("KDE/LanLinkProvider","nioLinks.size(): " + nioLinks.size());
|
||||||
addLink(np, link);
|
addLink(np, link);
|
||||||
} else {
|
} else {
|
||||||
LanLink prevLink = nioSessions.get(session.getId());
|
LanLink prevLink = nioLinks.get(ctx.channel().hashCode());
|
||||||
if (prevLink == null) {
|
if (prevLink == null) {
|
||||||
Log.e("KDE/LanLinkProvider","Expecting an identity package (A)");
|
Log.e("KDE/LanLinkProvider","Expecting an identity package (A)");
|
||||||
} else {
|
} else {
|
||||||
@@ -148,18 +161,15 @@ public class LanLinkProvider extends BaseLinkProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
private class UdpHandler extends SimpleChannelInboundHandler<DatagramPacket> {
|
||||||
|
|
||||||
private final IoHandler udpHandler = new IoHandlerAdapter() {
|
|
||||||
@Override
|
@Override
|
||||||
public void messageReceived(IoSession udpSession, Object message) throws Exception {
|
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
|
||||||
super.messageReceived(udpSession, message);
|
|
||||||
|
|
||||||
//Log.e("LanLinkProvider", "Udp message received (" + message.getClass() + ") " + message.toString());
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//We should receive a string thanks to the TextLineCodecFactory filter
|
String theMessage = packet.content().toString(CharsetUtil.UTF_8);
|
||||||
String theMessage = (String) message;
|
|
||||||
final NetworkPackage identityPackage = NetworkPackage.unserialize(theMessage);
|
final NetworkPackage identityPackage = NetworkPackage.unserialize(theMessage);
|
||||||
|
|
||||||
if (!identityPackage.getType().equals(NetworkPackage.PACKAGE_TYPE_IDENTITY)) {
|
if (!identityPackage.getType().equals(NetworkPackage.PACKAGE_TYPE_IDENTITY)) {
|
||||||
@@ -172,30 +182,35 @@ public class LanLinkProvider extends BaseLinkProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Log.i("KDE/LanLinkProvider", "Identity package received, creating link");
|
Log.i("KDE/LanLinkProvider", "Identity package received, creating link");
|
||||||
|
|
||||||
final InetSocketAddress address = (InetSocketAddress) udpSession.getRemoteAddress();
|
|
||||||
|
|
||||||
final NioSocketConnector connector = new NioSocketConnector();
|
EventLoopGroup clientGroup = new NioEventLoopGroup();
|
||||||
connector.setHandler(tcpHandler);
|
|
||||||
connector.getSessionConfig().setKeepAlive(true);
|
|
||||||
//TextLineCodecFactory will buffer incoming data and emit a message very time it finds a \n
|
|
||||||
TextLineCodecFactory textLineFactory = new TextLineCodecFactory(Charset.defaultCharset(), LineDelimiter.UNIX, LineDelimiter.UNIX);
|
|
||||||
textLineFactory.setDecoderMaxLineLength(512*1024); //Allow to receive up to 512kb of data
|
|
||||||
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(textLineFactory));
|
|
||||||
|
|
||||||
int tcpPort = identityPackage.getInt("tcpPort", port);
|
|
||||||
final ConnectFuture future = connector.connect(new InetSocketAddress(address.getAddress(), tcpPort));
|
|
||||||
future.addListener(new IoFutureListener<IoFuture>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void operationComplete(IoFuture ioFuture) {
|
|
||||||
try{
|
try{
|
||||||
future.removeListener(this);
|
Bootstrap b = new Bootstrap();
|
||||||
final IoSession session = ioFuture.getSession();
|
b.group(clientGroup);
|
||||||
Log.i("KDE/LanLinkProvider", "Connection successful: " + session.isConnected());
|
b.channel(NioSocketChannel.class);
|
||||||
|
b.handler(new ChannelInitializer<Channel>() {
|
||||||
|
@Override
|
||||||
|
protected void initChannel(Channel ch) throws Exception {
|
||||||
|
ChannelPipeline pipeline = ch.pipeline();
|
||||||
|
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
|
||||||
|
pipeline.addLast(new StringDecoder());
|
||||||
|
pipeline.addLast(new StringEncoder());
|
||||||
|
pipeline.addLast(new TcpHandler());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
int tcpPort = identityPackage.getInt("tcpPort", port);
|
||||||
|
final ChannelFuture channelFuture = b.connect(packet.sender().getAddress(), tcpPort).sync();
|
||||||
|
channelFuture.addListener(new ChannelFutureListener() {
|
||||||
|
@Override
|
||||||
|
public void operationComplete(ChannelFuture future) throws Exception {
|
||||||
|
channelFuture.removeListener(this);
|
||||||
|
final Channel channel = channelFuture.channel();
|
||||||
|
|
||||||
final LanLink link = new LanLink(session, identityPackage.getString("deviceId"), LanLinkProvider.this);
|
Log.i("KDE/LanLinkProvider", "Connection successful: " + channel.isActive());
|
||||||
|
|
||||||
|
final LanLink link = new LanLink(channel, identityPackage.getString("deviceId"), LanLinkProvider.this);
|
||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -203,9 +218,9 @@ public class LanLinkProvider extends BaseLinkProvider {
|
|||||||
link.sendPackage(np2,new Device.SendPackageStatusCallback() {
|
link.sendPackage(np2,new Device.SendPackageStatusCallback() {
|
||||||
@Override
|
@Override
|
||||||
protected void onSuccess() {
|
protected void onSuccess() {
|
||||||
nioSessions.put(session.getId(), link);
|
nioLinks.put(channel.hashCode(), link);
|
||||||
nioConnectors.put(session.getId(), connector);
|
nioChannels.put(channel.hashCode(), channel);
|
||||||
//Log.e("KDE/LanLinkProvider","nioSessions.size(): " + nioSessions.size());
|
Log.i("KDE/LanLinkProvider","nioLinks.size(): " + nioLinks.size());
|
||||||
addLink(identityPackage, link);
|
addLink(identityPackage, link);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,20 +232,19 @@ public class LanLinkProvider extends BaseLinkProvider {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
} catch (Exception e) { //If we don't catch it here, Mina will swallow it :/
|
|
||||||
e.printStackTrace();
|
|
||||||
Log.e("KDE/LanLinkProvider", "sessionClosed exception");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e("KDE/LanLinkProvider","Exception receiving udp package!!");
|
Log.e("KDE/LanLinkProvider","Exception receiving udp package!!");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
private void addLink(NetworkPackage identityPackage, LanLink link) {
|
private void addLink(NetworkPackage identityPackage, LanLink link) {
|
||||||
String deviceId = identityPackage.getString("deviceId");
|
String deviceId = identityPackage.getString("deviceId");
|
||||||
@@ -253,64 +267,59 @@ public class LanLinkProvider extends BaseLinkProvider {
|
|||||||
|
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
|
||||||
//This handles the case when I'm the new device in the network and somebody answers my introduction package
|
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||||
tcpAcceptor = new NioSocketAcceptor();
|
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||||
tcpAcceptor.setHandler(tcpHandler);
|
try{
|
||||||
tcpAcceptor.getSessionConfig().setKeepAlive(true);
|
tcpBootstrap = new ServerBootstrap();
|
||||||
tcpAcceptor.getSessionConfig().setReuseAddress(true);
|
tcpBootstrap.group(bossGroup, workerGroup);
|
||||||
//TextLineCodecFactory will buffer incoming data and emit a message very time it finds a \n
|
tcpBootstrap.channel(NioServerSocketChannel.class);
|
||||||
TextLineCodecFactory textLineFactory = new TextLineCodecFactory(Charset.defaultCharset(), LineDelimiter.UNIX, LineDelimiter.UNIX);
|
tcpBootstrap.option(ChannelOption.SO_BACKLOG, 100);
|
||||||
textLineFactory.setDecoderMaxLineLength(512*1024); //Allow to receive up to 512kb of data
|
tcpBootstrap.handler(new LoggingHandler(LogLevel.INFO));
|
||||||
tcpAcceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(textLineFactory));
|
tcpBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||||
|
tcpBootstrap.childOption(ChannelOption.SO_REUSEADDR, true);
|
||||||
|
tcpBootstrap.childHandler(new ChannelInitializer<Channel>() {
|
||||||
|
@Override
|
||||||
|
protected void initChannel(Channel ch) throws Exception {
|
||||||
|
ChannelPipeline pipeline = ch.pipeline();
|
||||||
|
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
|
||||||
|
pipeline.addLast(new StringDecoder());
|
||||||
|
pipeline.addLast(new StringEncoder());
|
||||||
|
pipeline.addLast(new TcpHandler());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tcpBootstrap.bind(new InetSocketAddress(port)).sync();
|
||||||
|
}catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
udpAcceptor = new NioDatagramAcceptor();
|
EventLoopGroup udpEventLoopGroup = new NioEventLoopGroup();
|
||||||
udpAcceptor.getSessionConfig().setReuseAddress(true); //Share port if existing
|
try {
|
||||||
//TextLineCodecFactory will buffer incoming data and emit a message very time it finds a \n
|
udpBootstrap = new Bootstrap();
|
||||||
//This one will have the default MaxLineLength of 1KB
|
udpBootstrap.group(udpEventLoopGroup);
|
||||||
udpAcceptor.getFilterChain().addLast("codec",
|
udpBootstrap.channel(NioDatagramChannel.class);
|
||||||
new ProtocolCodecFilter(
|
udpBootstrap.option(ChannelOption.SO_BROADCAST, true);
|
||||||
new TextLineCodecFactory(Charset.defaultCharset(), LineDelimiter.UNIX, LineDelimiter.UNIX)
|
udpBootstrap.handler(new ChannelInitializer<Channel>() {
|
||||||
)
|
@Override
|
||||||
);
|
protected void initChannel(Channel ch) throws Exception {
|
||||||
|
ChannelPipeline pipeline = ch.pipeline();
|
||||||
|
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
|
||||||
|
pipeline.addLast(new StringDecoder());
|
||||||
|
pipeline.addLast(new StringEncoder());
|
||||||
|
pipeline.addLast(new UdpHandler());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
udpChannel = udpBootstrap.bind(new InetSocketAddress(port)).sync().channel();
|
||||||
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
|
|
||||||
//This handles the case when I'm the existing device in the network and receive a "hello" UDP package
|
Log.e("KDE/LanLinkProvider", "onStart");
|
||||||
|
|
||||||
Set<SocketAddress> addresses = udpAcceptor.getLocalAddresses();
|
|
||||||
for (SocketAddress address : addresses) {
|
|
||||||
Log.i("KDE/LanLinkProvider", "UDP unbind old address");
|
|
||||||
udpAcceptor.unbind(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Log.i("KDE/LanLinkProvider", "UDP Bind.");
|
|
||||||
udpAcceptor.setHandler(udpHandler);
|
|
||||||
|
|
||||||
try {
|
|
||||||
udpAcceptor.bind(new InetSocketAddress(port));
|
|
||||||
} catch(Exception e) {
|
|
||||||
Log.e("KDE/LanLinkProvider", "Error: Could not bind udp socket");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean success = false;
|
|
||||||
int tcpPort = port;
|
|
||||||
while(!success) {
|
|
||||||
try {
|
|
||||||
tcpAcceptor.bind(new InetSocketAddress(tcpPort));
|
|
||||||
success = true;
|
|
||||||
} catch(Exception e) {
|
|
||||||
tcpPort++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i("KDE/LanLinkProvider","Using tcpPort "+tcpPort);
|
|
||||||
|
|
||||||
//I'm on a new network, let's be polite and introduce myself
|
|
||||||
final int finalTcpPort = tcpPort;
|
|
||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -324,7 +333,7 @@ public class LanLinkProvider extends BaseLinkProvider {
|
|||||||
iplist.add("255.255.255.255"); //Default: broadcast.
|
iplist.add("255.255.255.255"); //Default: broadcast.
|
||||||
|
|
||||||
NetworkPackage identity = NetworkPackage.createIdentityPackage(context);
|
NetworkPackage identity = NetworkPackage.createIdentityPackage(context);
|
||||||
identity.set("tcpPort", finalTcpPort);
|
identity.set("tcpPort", port);
|
||||||
DatagramSocket socket = null;
|
DatagramSocket socket = null;
|
||||||
byte[] bytes = null;
|
byte[] bytes = null;
|
||||||
try {
|
try {
|
||||||
@@ -342,7 +351,7 @@ public class LanLinkProvider extends BaseLinkProvider {
|
|||||||
for (String ipstr : iplist) {
|
for (String ipstr : iplist) {
|
||||||
try {
|
try {
|
||||||
InetAddress client = InetAddress.getByName(ipstr);
|
InetAddress client = InetAddress.getByName(ipstr);
|
||||||
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, client, port);
|
java.net.DatagramPacket packet = new java.net.DatagramPacket(bytes, bytes.length, client, port);
|
||||||
socket.send(packet);
|
socket.send(packet);
|
||||||
//Log.i("KDE/LanLinkProvider","Udp identity package sent to address "+packet.getAddress());
|
//Log.i("KDE/LanLinkProvider","Udp identity package sent to address "+packet.getAddress());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -360,14 +369,14 @@ public class LanLinkProvider extends BaseLinkProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNetworkChange() {
|
public void onNetworkChange() {
|
||||||
//Log.e("KDE/LanLinkProvider","onNetworkChange");
|
Log.e("KDE/LanLinkProvider","onNetworkChange");
|
||||||
|
|
||||||
//FilesHelper.LogOpenFileCount();
|
//FilesHelper.LogOpenFileCount();
|
||||||
|
|
||||||
//Keep existing connections open while unbinding the socket
|
//Keep existing connections open while unbinding the socket
|
||||||
tcpAcceptor.setCloseOnDeactivation(false);
|
// tcpAcceptor.setCloseOnDeactivation(false);
|
||||||
onStop();
|
// onStop();
|
||||||
tcpAcceptor.setCloseOnDeactivation(true);
|
// tcpAcceptor.setCloseOnDeactivation(true);
|
||||||
|
|
||||||
//FilesHelper.LogOpenFileCount();
|
//FilesHelper.LogOpenFileCount();
|
||||||
|
|
||||||
@@ -378,8 +387,14 @@ public class LanLinkProvider extends BaseLinkProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
udpAcceptor.unbind();
|
Log.e("KDE/LanLinkProvider", "onStop");
|
||||||
tcpAcceptor.unbind();
|
try {
|
||||||
|
udpBootstrap.group().shutdownGracefully().sync();
|
||||||
|
tcpBootstrap.group().shutdownGracefully().sync();
|
||||||
|
tcpBootstrap.childGroup().shutdownGracefully().sync();
|
||||||
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Reference in New Issue
Block a user