Example #1
0
// Scrape scrapes using UDP format
func (u UDPTracker) Scrape(files []data.FileRecord) []byte {
	// Iterate all files, grabbing their statistics
	stats := make([]udp.ScrapeStats, 0)
	for _, file := range files {
		stat := udp.ScrapeStats{}

		// Seeders
		stat.Seeders = uint32(file.Seeders())

		// Completed
		stat.Completed = uint32(file.Completed())

		// Leechers
		stat.Leechers = uint32(file.Leechers())

		// Append to slice
		stats = append(stats[:], stat)
	}

	// Create UDP scrape response
	scrape := udp.ScrapeResponse{
		Action:    2,
		TransID:   u.TransID,
		FileStats: stats,
	}

	// Convert to UDP byte buffer
	buf, err := scrape.MarshalBinary()
	if err != nil {
		log.Println(err.Error())
		return u.Error("Could not create UDP scrape response")
	}

	return buf
}
Example #2
0
// TestUDPTrackerScrape verifies that the UDP tracker scrape format is correct
func TestUDPTrackerScrape(t *testing.T) {
	log.Println("TestUDPTrackerScrape()")

	// Generate mock data.FileRecord
	file := data.FileRecord{
		InfoHash: "6465616462656566",
		Verified: true,
	}

	// Save mock file
	if !file.Save() {
		t.Fatalf("Failed to save mock file")
	}

	// Store file in slice
	files := make([]data.FileRecord, 0)
	files = append(files[:], file)

	// Create a UDP tracker, trigger a scrape
	tracker := UDPTracker{TransID: uint32(1234)}
	res := tracker.Scrape(files)

	// Decode response
	scrape := new(udp.ScrapeResponse)
	err := scrape.UnmarshalBinary(res)
	if err != nil {
		t.Fatalf("Failed to decode UDP scrape response")
	}
	log.Println(scrape)

	// Verify correct action
	if scrape.Action != 2 {
		t.Fatalf("Incorrect UDP action, expected 2")
	}

	// Encode response, verify same as before
	scrapeBuf, err := scrape.MarshalBinary()
	if err != nil {
		t.Fatalf("Failed to encode UDP scrape response")
	}

	if !bytes.Equal(res, scrapeBuf) {
		t.Fatalf("Byte slices are not identical")
	}

	// Delete mock file
	if !file.Delete() {
		t.Fatalf("Failed to delete mock file")
	}
}
Example #3
0
// Scrape scrapes using UDP format
func (u UDPTracker) Scrape(files []data.FileRecord) []byte {
	// Buffered channel to receive UDP scrape stats structs
	resChan := make(chan *orderedScrape, len(files))

	// Assign index to each file to preserve order during concurrent operations
	index := 0

	// Iterate all files in parallel
	for _, f := range files {
		// Create orderedScrape, assign index to ensure correct return order during concurrent operations
		o := orderedScrape{
			Index: index,
			File:  udp.ScrapeStats{},
		}
		index++

		go func(f data.FileRecord, o *orderedScrape) {
			// Seeders count
			var err error
			seeders, err := f.Seeders()
			if err != nil {
				log.Println(err.Error())
			}
			o.File.Seeders = uint32(seeders)

			// Completion count
			completed, err := f.Completed()
			if err != nil {
				log.Println(err.Error())
			}
			o.File.Completed = uint32(completed)

			// Leechers count
			leechers, err := f.Leechers()
			if err != nil {
				log.Println(err.Error())
			}
			o.File.Leechers = uint32(leechers)

			// Return results on channel
			resChan <- o
		}(f, &o)
	}

	// Fetch all results from channel
	received := 0
	stats := make([]udp.ScrapeStats, len(files), len(files))
	for o := range resChan {
		stats[o.Index] = o.File
		received++

		// Once all file stats are received, break loop
		if received == len(files) {
			break
		}
	}

	// Close response channel
	close(resChan)

	// Create UDP scrape response
	scrape := udp.ScrapeResponse{
		Action:    2,
		TransID:   u.TransID,
		FileStats: stats,
	}

	// Convert to UDP byte buffer
	buf, err := scrape.MarshalBinary()
	if err != nil {
		log.Println(err.Error())
		return u.Error(ErrScrapeFailure.Error())
	}

	return buf
}
Example #4
0
// TestUDPRouter verifies that the main UDP router is working properly
func TestUDPRouter(t *testing.T) {
	log.Println("TestUDPRouter()")

	// Load config
	config, err := common.LoadConfig()
	if err != nil {
		t.Fatalf("Could not load configuration: %s", err.Error())
	}
	common.Static.Config = config

	// Generate mock data.FileRecord
	file := data.FileRecord{
		InfoHash: "6465616462656566303030303030303030303030",
		Verified: true,
	}

	// Save mock file
	if err := file.Save(); err != nil {
		t.Fatalf("Failed to save mock file: %s", err.Error())
	}

	// Fake UDP address
	addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("Failed to create fake UDP address")
	}

	// Connect packet with handshake
	connect := udp.Packet{udpInitID, 0, 1234}
	connectBuf, err := connect.MarshalBinary()
	if err != nil {
		t.Fatalf("Failed to create UDP connect packet")
	}

	// Perform connection handshake
	res, err := parseUDP(connectBuf, addr)
	if err != nil {
		errRes := new(udp.ErrorResponse)
		err2 := errRes.UnmarshalBinary(res)
		if err2 != nil {
			t.Fatalf(err.Error())
		}

		log.Println("ERROR:", errRes.Error)
		t.Fatalf(err.Error())
	}

	// Retrieve response, get new connection ID, which will be expected by router
	connRes := new(udp.ConnectResponse)
	err = connRes.UnmarshalBinary(res)
	if err != nil {
		t.Fatalf(err.Error())
	}

	// Create announce request
	announce := udp.AnnounceRequest{
		ConnID:     connRes.ConnID,
		Action:     1,
		TransID:    connRes.TransID,
		InfoHash:   []byte("deadbeef000000000000"),
		PeerID:     []byte("00001111222233334444"),
		Downloaded: 0,
		Left:       0,
		Uploaded:   0,
		IP:         0,
		Key:        1234,
		Port:       5000,
	}

	// Get announce bytes
	announceBuf, err := announce.MarshalBinary()
	if err != nil {
		t.Fatalf(err.Error())
	}

	// Send announce to UDP router
	res, err = parseUDP(announceBuf, addr)
	if err != nil {
		errRes := new(udp.ErrorResponse)
		err2 := errRes.UnmarshalBinary(res)
		if err2 != nil {
			t.Fatalf(err.Error())
		}

		log.Println("ERROR:", errRes.Error)
		t.Fatalf(err.Error())
	}

	// Get UDP announce response
	announceRes := new(udp.AnnounceResponse)
	err = announceRes.UnmarshalBinary(res)
	if err != nil {
		errRes := new(udp.ErrorResponse)
		err2 := errRes.UnmarshalBinary(res)
		if err2 != nil {
			t.Fatalf(err.Error())
		}

		log.Println("ERROR:", errRes.Error)
		t.Fatalf(err.Error())
	}
	log.Println(announceRes)

	// Create scrape request
	scrape := udp.ScrapeRequest{
		ConnID:     connRes.ConnID,
		Action:     2,
		TransID:    connRes.TransID,
		InfoHashes: [][]byte{[]byte("deadbeef000000000000")},
	}

	// Get scrape bytes
	scrapeBuf, err := scrape.MarshalBinary()
	if err != nil {
		t.Fatalf(err.Error())
	}

	// Send scrape to UDP router
	res, err = parseUDP(scrapeBuf, addr)
	if err != nil {
		errRes := new(udp.ErrorResponse)
		err2 := errRes.UnmarshalBinary(res)
		if err2 != nil {
			t.Fatalf(err.Error())
		}

		log.Println("ERROR:", errRes.Error)
		t.Fatalf(err.Error())
	}

	// Get UDP scrape response
	scrapeRes := new(udp.ScrapeResponse)
	err = scrapeRes.UnmarshalBinary(res)
	if err != nil {
		errRes := new(udp.ErrorResponse)
		err2 := errRes.UnmarshalBinary(res)
		if err2 != nil {
			t.Fatalf(err.Error())
		}

		log.Println("ERROR:", errRes.Error)
		t.Fatalf(err.Error())
	}
	log.Println(scrapeRes)

	// Delete mock file
	if err := file.Delete(); err != nil {
		t.Fatalf("Failed to delete mock file: %s", err.Error())
	}
}