Python устанавливает соединение с UDP BitTorrent-трекером - PullRequest
0 голосов
/ 10 июня 2018

Я учусь устанавливать соединение с трекером udp для отправки соединений и получения ответа.Однако я не уверен, почему я не получаю ответ о соединении.

Торрент, с которого я пытаюсь получить файлы, расположен здесь

# It produces this magnet link. 
mag_link = 'magnet:?xt=urn:btih:5daa22057577521a378b71e0f0de6a934bd5c2ea&tr=http%3A%2F%2Facademictorrents.com%2Fannounce.php&tr=udp%3A%2F%2Ftracker.publicbt.com%3A80%2Fannounce&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80%2Fannounce'

После этого я использую urllib.parse для анализа ссылки для получения элементов.такие как xt, tr, dn и т. д.

from urllib import parse
processed_mag_link = parse.parse_qs(parse.urlparse(mag_link).query)

Я просмотрел некоторые документы по bit torrent protocols и udp connections и получил приведенный ниже код.Буду очень признателен, если вы можете поделиться со мной, почему я не могу получить ответ соединения с трекером.

import random
import socket
import struct
from urllib import parse
from urllib.parse import urlparse

def magnet_link_decode(mag_link):
    # Parsing of mag_link
    processed_mag_link = parse.parse_qs(parse.urlparse(mag_link).query)
    # Renaming of mag_link
    processed_mag_link = {
        'exact_topic': processed_mag_link.get('xt'),
        'display_name': processed_mag_link.get('dn'),
        'tracker_name': processed_mag_link.get('tr')
    }
    print(processed_mag_link['tracker_name'])
    return processed_mag_link


def announce_udp(processed_nag_link):
    trackers = magnet_link_decode(processed_nag_link)['tracker_name']

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.settimeout(5)

    for tracker in trackers:
        tracker = urlparse(tracker)
        try:
            if tracker.scheme == 'udp':
                print('connecting to: ', tracker.hostname)
                connection = (socket.gethostbyname(tracker.hostname), tracker.port)
                request, transaction_id = udp_create_connection_request()
                sock.sendto(request, connection)
                buffer = sock.recvfrom(1048)[0]
                connection_id = udp_parse_connection_response(buffer, transaction_id)
                print(connection_id)
            elif tracker.scheme == 'http':
                pass  # do nothing for now

        except socket.gaierror:
            print('Connection to: {err} failed..'.format(err=tracker.hostname))
        except socket.timeout:
            pass  


def udp_parse_connection_response(buf, sent_transaction_id):

    print('connecting')
    if len(buf) < 16:
        raise RuntimeError("Wrong response length getting connection id: %s" % len(buf))
    action = struct.unpack_from("!i", buf)[0]  # first 4 bytes is action

    res_transaction_id = struct.unpack_from("!i", buf, 4)[0]  # next 4 bytes is transaction id
    if res_transaction_id != sent_transaction_id:
        raise RuntimeError("Transaction ID doesnt match in connection response! Expected %s, got %s"
                       % (sent_transaction_id, res_transaction_id))

    if action == 0x0:
        connection_id = struct.unpack_from("!q", buf, 8)[0]  # unpack 8 bytes from byte 8, should be the connection_id
        return connection_id
    elif action == 0x3:
        error = struct.unpack_from("!s", buf, 8)
        raise RuntimeError("Error while trying to get a connection response: %s" % error)


def udp_create_connection_request():
    connection_id = 0x41727101980  # default connection id
    action = 0x0  # action (0 = give me a new connection id)
    transaction_id = int(random.randrange(0, 255))
    print("Transaction ID :", transaction_id)
    buffer = struct.pack("!q", connection_id)  # first 8 bytes is connection id
    buffer += struct.pack("!i", action)  # next 4 bytes is action
    buffer += struct.pack("!i", transaction_id)  # next 4 bytes is transaction id

    return buffer, transaction_id

Для первой части magnet_link_decode - это, по существу, разбор магнитной связи для получения info_hash, а также трекеров.

Следующая часть announce_udp - посмотреть, смогу ли я подключиться и получить ответ от трекера.Я не совсем уверен, что это правильно, но похоже, что он ничего не может получить из кода buffer = sock.recvfrom(1048)[0]

...