Java tutorial
/* * Copyright 2014 Napolov Dmitry * * 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. */ package org.aotorrent.common.connection; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.channel.*; 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 org.aotorrent.common.TorrentEngine; import org.aotorrent.common.protocol.tracker.UDPAnnounceReply; import org.aotorrent.common.protocol.tracker.UDPAnnounceRequest; import org.aotorrent.common.protocol.tracker.UDPConnectReply; import org.aotorrent.common.protocol.tracker.UDPConnectRequest; import java.net.InetAddress; import java.net.URISyntaxException; import java.util.Date; public class UDPTrackerConnection extends AbstractTrackerConnection { private int transactionId; public UDPTrackerConnection(TorrentEngine torrentEngine, String url, byte[] infoHash, byte[] peerId, InetAddress ip, int port) throws URISyntaxException { super(torrentEngine, url, infoHash, peerId, ip, port, null); } @Override protected void obtainPeers() { try { EventLoopGroup group = new NioEventLoopGroup(); Bootstrap b = new Bootstrap(); b.group(group).channel(NioDatagramChannel.class).handler(new ChannelInitializer<DatagramChannel>() { @Override protected void initChannel(DatagramChannel ch) throws Exception { final ChannelPipeline p = ch.pipeline(); p.addLast(new TrackerConnectionHandler()); } }); Channel ch = b.bind(0).sync().channel(); transactionId = RANDOM.nextInt(); LOGGER.debug("Sending connect request to " + address); ch.writeAndFlush(new DatagramPacket(new UDPConnectRequest(transactionId).toTransmit(), address)); ch.closeFuture().sync(); } catch (InterruptedException e) { LOGGER.error("Tracker connection interrupted"); } } private class TrackerConnectionHandler extends SimpleChannelInboundHandler<DatagramPacket> { private long connectionId; @Override protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket datagram) throws Exception { final ByteBuf data = datagram.content(); final int action = data.getInt(0); switch (action) { case 0: final UDPConnectReply connectReply = new UDPConnectReply(data); if (connectReply.getTransactionId() != transactionId) { return; } connectionId = connectReply.getConnectionId(); LOGGER.debug("Got connect reply with connectionId = " + connectionId + "Sending announce request to " + address); sendAnnounceRequest(ctx); break; case 1: final UDPAnnounceReply announceReply = new UDPAnnounceReply(data); if (announceReply.getTransactionId() != transactionId) { return; } nextRequest = new Date(System.currentTimeMillis() + (announceReply.getInterval() * 1000)); LOGGER.debug("Got peers from tracker" + announceReply.getPeers()); torrentEngine.appendPeers(announceReply.getPeers()); ctx.close(); } } private void sendAnnounceRequest(ChannelHandlerContext ctx) { transactionId = RANDOM.nextInt(); UDPAnnounceRequest request = new UDPAnnounceRequest(connectionId, transactionId, infoHash, peerId, downloaded, left, uploaded, 2, localAddress.getPort()); ctx.writeAndFlush(new DatagramPacket(request.toTransmit(), address)); } } }