UDP Tracker not sending any response

85 views Asked by At

I am trying to implement a torrent client in golang using the UDP Tracker Protocol. I first open a UDP connection and send a connect message to the tracker but receive no response in return.

Here's the complete source code and below are the important functions:

main.go/main() function

    // Path to .torrent file must be provided in the os args
    if len(os.Args) != 2 {
        log.Fatal("missing required argument \"path\"")
    }
    path := os.Args[1]

    // Read and parse the torrent file
    torrent, err := torrent.Open(path)
    if err != nil {
        log.Fatal(err)
    }

    announceURL, err := url.Parse(torrent.Announce)
    if err != nil {
        log.Fatal(err)
    }
    port, err := strconv.Atoi(announceURL.Port())
    if err != nil {
        log.Fatal(err)
    }

    // Create a new Node instance for this client
    node, err := node.New(announceURL.Hostname(), uint16(port))
    if err != nil {
        log.Fatal(err)
    }
    defer node.Close()  // close the under lying UDP connection

    // Send connection message to the tracker
    if err := node.SendConnect(); err != nil {
        log.Fatal(err)
    }

    for runtime.NumGoroutine() > 1 {
    }

node.go/node.New() function Creates a new Node for the current client

// Dial a connection to the given host
    addr := host + ":" + strconv.Itoa(int(port))
    raddr, err := net.ResolveUDPAddr("udp4", addr)
    if err != nil {
        return nil, err
    }
    c, err := net.DialUDP("udp4", nil, raddr)
    if err != nil {
        return nil, err
    }

    // Calculate Node's ID
    buf := [2]byte{}
    binary.BigEndian.PutUint16(buf[:], port)
    sha1Sum := sha1.Sum(append([]byte(host), buf[:]...))
    id := hex.EncodeToString(sha1Sum[:])

    // Create a new Node
    n := &Node{
        ID:      id,
        UDPConn: c,
    }

    // Listen for incoming messages
    readCh := make(chan []byte)
    go n.listen(readCh)

    return n, nil

node.go/node.listen() function listens for incoming messages

buf := make([]byte, 1024)
    for {
        _, err := n.Read(buf)
        if err != nil {
            log.Printf("error while reading from %v ~ %v\n", n.RemoteAddr(), err)
        } else {
            ch <- buf
        }
    }

node.go/process() function Do something with the incoming messages

for {
        msg := <-ch
        log.Println(string(msg))
    }

node.go/SendConnect() function Sends a connect message to the tracker

var protocolID int64 = 0x41727101980
    var action int32 = 0
    var transactionID int32 = utils.NewTransactionID()  // auto increment integer

    // Create the message as a buffer
    buf := make([]byte, 16) // `Connect` messages are of fixed length
    binary.BigEndian.PutUint64(buf[:8], uint64(protocolID))
    binary.BigEndian.PutUint32(buf[8:12], uint32(action))
    binary.BigEndian.PutUint32(buf[12:16], uint32(transactionID))

    // Send message
    _, err := n.Write(buf)

    return err

go.mod

module github.com/Ehab-24/torrent-udp

go 1.20

require github.com/jackpal/bencode-go v1.0.0

I tried different UDP trackers and torrent files. I am also certain I haven't made a mistake in setting up the connection.

I am sure I'm missing something important here. Any help is greatly appreciated.

0

There are 0 answers