tracker_protocol.zig (2276B)
1 const std = @import("std"); 2 const bencode = @import("bencode.zig"); 3 4 // https://wiki.theory.org/BitTorrentSpecification#Tracker_Response 5 pub const TrackerResp = struct { 6 // interval: u64, 7 peers: []std.net.Address, 8 9 pub fn parse(a: std.mem.Allocator, b: bencode.BValue) !TrackerResp { 10 var ipl = std.ArrayList(std.net.Address).init(a); 11 defer ipl.deinit(); 12 var d = b.asDict() catch return error.Malformatted; 13 var pb = d.get("peers") orelse return error.Malformatted; 14 var ps = pb.asString() catch return error.Malformatted; 15 if ((ps.len % 6) != 0) return error.Malformatted; 16 for (0..ps.len / 6) |ix| { 17 const start = ix * 6; 18 const port = std.mem.readInt(u16, ps[start + 4 .. start + 6][0..2], .big); 19 var ip = [_]u8{0} ** 4; 20 @memcpy(&ip, ps[start .. start + 4]); 21 try ipl.append(std.net.Address.initIp4(ip, port)); 22 } 23 return .{ 24 .peers = try ipl.toOwnedSlice(), 25 }; 26 } 27 28 pub fn deinit(self: *TrackerResp, a: std.mem.Allocator) void { 29 a.free(self.peers); 30 } 31 }; 32 33 pub fn trackerRequestUrl(a: std.mem.Allocator, info_hash: [20]u8, peer_id: [20]u8, left: usize, announce: []const u8) ![]const u8 { 34 var q = std.StringHashMap([]const u8).init(a); 35 defer q.deinit(); 36 try q.put("info_hash", &info_hash); 37 try q.put("peer_id", &peer_id); 38 try q.put("port", "6881"); 39 try q.put("uploaded", "0"); 40 try q.put("downloaded", "0"); 41 var buf_left = [_]u8{0} ** 1024; 42 try q.put("left", try std.fmt.bufPrint(&buf_left, "{}", .{left})); 43 try q.put("compact", "1"); 44 var qs = try toqs(a, q); 45 defer a.free(qs); 46 return try std.fmt.allocPrint(a, "{s}?{s}", .{ announce, qs }); 47 } 48 49 fn toqs(a: std.mem.Allocator, hm: std.StringHashMap([]const u8)) ![]const u8 { 50 var al = std.ArrayList(u8).init(a); 51 defer al.deinit(); 52 var w = al.writer(); 53 var it = hm.iterator(); 54 var first = true; 55 while (it.next()) |entry| { 56 if (!first) try w.writeByte('&'); 57 try std.Uri.writeEscapedQuery(w, entry.key_ptr.*); 58 try w.writeByte('='); 59 try std.Uri.writeEscapedQuery(w, entry.value_ptr.*); 60 first = false; 61 } 62 return try al.toOwnedSlice(); 63 }