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.