// TestUDPAnnounce verifies that the UDP tracker announce output format is correct func TestUDPAnnounce(t *testing.T) { log.Println("TestUDPAnnounce()") // Load config config := common.LoadConfig() common.Static.Config = config // Generate mock data.FileRecord file := data.FileRecord{ InfoHash: "6465616462656566", Verified: true, } // Save mock file if !file.Save() { t.Fatalf("Failed to save mock file") } // Generate fake announce query query := url.Values{} query.Set("info_hash", "deadbeef") query.Set("ip", "127.0.0.1") query.Set("port", "5000") query.Set("uploaded", "0") query.Set("downloaded", "0") query.Set("left", "0") query.Set("numwant", "50") // Create a UDP tracker, trigger an announce tracker := UDPTracker{TransID: uint32(1234)} res := tracker.Announce(query, file) // Decode response announce := new(udp.AnnounceResponse) err := announce.UnmarshalBinary(res) if err != nil { t.Fatalf("Failed to decode UDP announce response") } log.Println(announce) // Verify correct action if announce.Action != 1 { t.Fatalf("Incorrect UDP action, expected 1") } // Encode response, verify same as before announceBuf, err := announce.MarshalBinary() if err != nil { t.Fatalf("Failed to encode UDP announce response") } if !bytes.Equal(res, announceBuf) { t.Fatalf("Byte slices are not identical") } // Delete mock file if !file.Delete() { t.Fatalf("Failed to delete mock file") } }
// Announce announces using UDP format func (u UDPTracker) Announce(query url.Values, file data.FileRecord) []byte { // Create UDP announce response announce := udp.AnnounceResponse{ Action: 1, TransID: u.TransID, Interval: uint32(common.Static.Config.Interval), Leechers: uint32(file.Leechers()), Seeders: uint32(file.Seeders()), } // Convert to UDP byte buffer announceBuf, err := announce.MarshalBinary() if err != nil { log.Println(err.Error()) return u.Error("Could not create UDP announce response") } // Numwant numwant, err := strconv.Atoi(query.Get("numwant")) if err != nil { numwant = 50 } // Add compact peer list res := bytes.NewBuffer(announceBuf) err = binary.Write(res, binary.BigEndian, file.PeerList(query.Get("ip"), numwant)) if err != nil { log.Println(err.Error()) return u.Error("Could not create UDP announce response") } return res.Bytes() }
// Announce announces using UDP format func (u UDPTracker) Announce(query url.Values, file data.FileRecord) []byte { // Create UDP announce response announce := udp.AnnounceResponse{ Action: 1, TransID: u.TransID, Interval: uint32(common.Static.Config.Interval), } // Calculate file seeders and leechers seeders, err := file.Seeders() if err != nil { log.Println(err.Error()) } announce.Seeders = uint32(seeders) leechers, err := file.Leechers() if err != nil { log.Println(err.Error()) } announce.Leechers = uint32(leechers) // Convert to UDP byte buffer announceBuf, err := announce.MarshalBinary() if err != nil { log.Println(err.Error()) return u.Error(ErrAnnounceFailure.Error()) } // Numwant numwant, err := strconv.Atoi(query.Get("numwant")) if err != nil { numwant = 50 } // Retrieve compact peer list // Note: because we are UDP, we send the second parameter 'false' to get // a "best guess" peer list, due to anonymous announces peers, err := file.CompactPeerList(numwant, false) if err != nil { log.Println(err.Error()) return u.Error(ErrPeerListFailure.Error()) } // Add compact peer list res := bytes.NewBuffer(announceBuf) err = binary.Write(res, binary.BigEndian, peers) if err != nil { log.Println(err.Error()) return u.Error(ErrPeerListFailure.Error()) } return res.Bytes() }