Torrent: UDP Response Tracking (Update # 3 - Work)

Update # 4: java demo added to work with UDP and send msg message (remember that the connection is the first!) Check your own answer below.

==================================================== ==

Update # 3: I managed to get it working, the doConnect () method is presented below, more information in my own answer below.

==================================================== ==

I am mainly interested in how to download tracker response when url announcement protocol is UDP.

Details: Thus, these are some announcements of announcements from a valid torrent file (the first of them is the main one)

http://tracker.torrentbox.com:2710/announce udp://elbitz.net:80/announce.php?passkey=362fc69de3402e8ef5794c7ecf7c58d4 udp://tracker.podtropolis.com:2711/announce 

If the protocol is HTTP, everything is going well, and this is how I work:

 String fullUrl = announceURL + "?info_hash=" + this.m_TorrentInfoHashAsURL + .. // i add the params URL url = new URL(fullUrl); URLConnection connection = url.openConnection(); InputStream is = connection.getInputStream(); .. //reading the stream 

If the protocol is UDP, the URL constructor throws "java.net.MalformedURLException: unknown protocol: udp"

So, I think that the problem can be resumed until the following: how to download a response from a URL via UDP? (hope this is simple, and I don't see any datagram thing)

UPDATE # 1:

I did some more research on the Internet and came to the following structure inserted below (should work .. but that doesn’t mean, I mean locally, but not with a real tracker)

reference to technical specifications: http://www.bittorrent.org/beps/bep_0015.html

Ex: This is how I create the socket, but on the actual tracker I never get anything back as an answer, so something does not work:

 if full url: udp://elbitz.net:80/announce.php?passkey=362fc69de3402e8ef5794c7ecf7c58d4 this.m_TrackerHost: elbitz.net this.m_TrackerPort: 80 private DatagramSocket m_WorkingSocket; private DatagramSocket getWorkingSocket() { Logger.d(TAG, "getWorkingSocket()"); if(this.m_WorkingSocket==null){ Random rnd = new Random(); for (int i = 0; i < 100; i++) { try { int port = 15000 + rnd.nextInt(15000); // [15000-30000) DatagramSocket result = new DatagramSocket(port); InetAddress trackerAddress = InetAddress.getByName(this.m_TrackerHost); result.connect(trackerAddress, this.m_TrackerPort); this.m_WorkingSocket = result; } catch (SocketException se) { Logger.w(TAG, "getWorkingSocket() - port is taken"); } catch (SecurityException se) { Logger.w(TAG, "getWorkingSocket() - port is blocked?"); } catch (UnknownHostException e) { Logger.w(TAG, "getWorkingSocket() - unkwnown host?"); } } } return this.m_WorkingSocket; } 

& now the full code from doConnect, which should be the first phase of communication (the next is the announcement .. similar code there)

 private boolean doConnect() throws IOException{ Logger.d(TAG, "doConnect()"); DatagramSocket workingSocket = this.getWorkingSocket(); DatagramPacket sendPacket = null, receivePacket = null; byte[] sendData = null; byte[] receiveData = null; int round = 0; Logger.d(TAG, "doConnect(): first round, timeout: " + this.getTimeoutInMillis(ACTION_ID_CONNECT, round)); while(true) { if(round==8){ Logger.w(TAG, "doConnect() - failed to connect with tracker, consumed in vain all 8 rounds.."); return false; } workingSocket.setSoTimeout(this.getTimeoutInMillis(ACTION_ID_CONNECT, round)); if(receivePacket==null){ /* Offset Size Name Value 0 32-bit integer action 0 // connect 4 32-bit integer transaction_id 8 64-bit integer connection_id 16 */ receiveData = new byte[16]; //CONNECT: at least 16 bytes receivePacket = new DatagramPacket(receiveData, receiveData.length); sendData = this.getConnectRequest();//return byte[] with everything..just like in specs sendPacket = new DatagramPacket(sendData, sendData.length); } try { Logger.d(TAG, "doConnect() - sending connect data: " + (Arrays.toString(sendData))); workingSocket.send(sendPacket); workingSocket.receive(receivePacket); break; } catch (SocketTimeoutException ste) { round ++; Logger.w(TAG, "doConnect() connect - new round: " + (round+1) + "|timeout: " + this.getTimeoutInMillis(ACTION_ID_CONNECT, round)); continue; } } byte[] connectResponse = receivePacket.getData(); int actionIdFromResponse = Utils.byteArrayToInt(Utils.subArray(connectResponse, 0, 4)); int transactionIdFromResponse = Utils.byteArrayToInt(Utils.subArray(connectResponse, 4, 4)); long connectionIdFromResponse = Utils.byteArrayToLong(Utils.subArray(connectResponse, 8, 8)); if(transactionIdFromResponse!=this.m_TransactionId){ Logger.w(TAG, "doConnect() - received different transactionId"); return false; } if(actionIdFromResponse!=ACTION_ID_CONNECT){ Logger.w(TAG, "doConnect() - didnt received ACTION_ID_CONNECT"); return false; } //store connectionId this.m_ConnectionId = connectionIdFromResponse; return true; } 

The problem remains. I never get a response from the tracker (I also tried with a different URL) A new question: is it normal to create a socket on elbitz.net, port: 80, when the full url contains more information (for example: / announcement)?

Update # 2

The code above seems to work fine .. I found on google a list of trackers that implemented this specification, and voila answered (for example: "udp: //tracker.openbittorrent.com: 80")

A new question over and over here: http://www.bittorrent.org/beps/bep_0015.html - It seems I don’t see how to get a list of peers? .. in the usual request to the torrent tracker (via http) there were 2 cases: a normal response (a card with bencoded) and a compressed response (in binary form). So, was there a peer list now?

  • from the specification this is the announcement response:
 /* Offset Size Name Value 0 32-bit integer action 1 // announce 4 32-bit integer transaction_id 8 32-bit integer interval 12 32-bit integer leechers 16 32-bit integer seeders 20 + 6 * n 32-bit integer IP address 24 + 6 * n 16-bit integer TCP port 20 + 6 * N */ 

from my tests, I always get the same values ​​for the fields: IP address and TCP port .. plus that I get one response per request .. so CANT BE IT! .. I need a peer list!

Please, help! the only types of response messages that I implemented are still scratches and errors ... but no one contains the information that interests me (peer information: ip and port) ex: scrape

 Offset Size Name Value 0 32-bit integer action 2 // scrape 4 32-bit integer transaction_id 8 + 12 * n 32-bit integer seeders 12 + 12 * n 32-bit integer completed 16 + 12 * n 32-bit integer leechers 8 + 12 * N 
+4
source share
2 answers

My answers to my question .. well, thanks, me!

  • if it starts with udp: // it is valid
  • if url: udp: //elbitz.net: 80 / announce.php? passkey = 362fc69de3402e8ef5794c7ecf7c58d4 you create a socket on udp: //elbitz.net using port 80 (/ part of the declaration is not used when creating a UDP socket)
  • since this is UDP, the answer is not garaged (you did not select exeption, just wait), the specs mention the 8 round rule, but that means wait a while for the aint alive tracker to be implemented
  • in the case of commenting on UDP, you send 2 types of requests (Connect and Announce, each as 1 UDP packet) and get 1 response (obviously, just if you're lucky, as well as a UDP packet). To extract useful information, you need to analyze the answer byteBuffer again the real information is here: http://www.bittorrent.org/beps/bep_0015.html ;
  • you cannot declare until you get a Connect response (you need transactional identifiers, read specifications) my doConnect () - Ok, I changed very few lines from it (for example: im using the maximum size in bytes for the used byteBuffer by DataGramPacket, which means the new byte [65508] instead of [16] - the minimum size. Upon receipt of the answer, the rest will fill in bytes, which means 0)
  • as you see in doConnect, there is a while loop (it shows the max 8 round rule);
  • socketTimeOut is constantly increasing (using the formula from the specifications, 30 seconds, 90, etc.)
  • After receiving a response to the connection, you should make an announcement (), the contents of the method seem to be different (again, see the specifications), and again I use the maximum size for the buffer (new byte [65508]), but this time it makes more sense. because the size of the list of peers received is not hard-coded (it may be 1/8/10 peers .. I always request 10).
    (the minimum size is 20 bytes, this happens when peer information is not added to msg). Again, this answer is just one packet (there is a number in these max 65508 bytes. I think I get 70% of the indentation).
  • everything is slow due to blocking methods (receive ()), and I have it on my own branch (usually those trackers that respond should not consume more than two rounds .. it's nice)
  • Not visible in the rule code above, 1 minute rule (for reconnecting after 1 minute)
  • My opinion: this ugly code! working with UDP .. and flows, because everything is slow and blocking.

UPDATE ***

Code disabled for working with udp

 DatagramSocket workingSocket = ?;// DatagramPacket sendPacket = null, receivePacket = null; byte[] sendData = null; byte[] receiveData = null; receiveData = new byte[65508]; //NOTE: at least 16 bytes | 65508 is max size, unused bytes are 0 receivePacket = new DatagramPacket(receiveData, receiveData.length); sendData = this.getRequestTypeAnnounce(announceUDPWrapper.a_TransactionId); sendPacket = new DatagramPacket(sendData, sendData.length); workingSocket.send(sendPacket); workingSocket.receive(receivePacket); byte[] fullResponse = receivePacket.getData(); 

Code compressed to create msg message

 private byte[] getRequestTypeAnnounce(AnnounceUDPWrapper announceUDPWrapper) { //long connectionId, int transactionId, int tcpPort ByteBuffer bBuffer = ByteBuffer.allocate(98); bBuffer.putLong(announceUDPWrapper.a_ConnectionId); bBuffer.putInt(ACTION_ID_ANNOUNCE); bBuffer.putInt(announceUDPWrapper.a_TransactionId); bBuffer.put(announceUDPWrapper.a_InfoHash);//<<<< what you asked.. adding the infoHash which is byte[] bBuffer.put(this.m_MyId); bBuffer.putLong(announceUDPWrapper.a_Downloaded); bBuffer.putLong(announceUDPWrapper.a_Uploaded); bBuffer.putLong(announceUDPWrapper.a_Left); bBuffer.putInt(announceUDPWrapper.a_EventType.ordinal()); bBuffer.put(Utils.intToByteArray(0));// ip, 0 = default bBuffer.putInt(0);//key bBuffer.putInt(10);//num_want byte[] portAsBytes = Utils.intToByteArray(announceUDPWrapper.a_ListeningTCPPort); bBuffer.put(Utils.subArray(portAsBytes, 2, 2)); //port return bBuffer.array(); } 
+3
source

It seems to me that you are mixing network layers here.

udp is at the bottom level - http: // goes through tcp, while some other protocols can go through udp. IP is lower than this, so the protocol you are trying to use is similar to "torrent over udp, over IP".

See here for documentation on the torrent / udp protocol.

0
source

All Articles