diff options
Diffstat (limited to 'src/tracker_protocol.zig')
-rw-r--r-- | src/tracker_protocol.zig | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/src/tracker_protocol.zig b/src/tracker_protocol.zig new file mode 100644 index 0000000..0a6a9c2 --- /dev/null +++ b/src/tracker_protocol.zig @@ -0,0 +1,63 @@ +const std = @import("std"); +const bencode = @import("bencode.zig"); + +// https://wiki.theory.org/BitTorrentSpecification#Tracker_Response +pub const TrackerResp = struct { + // interval: u64, + peers: []std.net.Address, + + pub fn parse(a: std.mem.Allocator, b: bencode.BValue) !TrackerResp { + var ipl = std.ArrayList(std.net.Address).init(a); + defer ipl.deinit(); + var d = b.asDict() catch return error.Malformatted; + var pb = d.get("peers") orelse return error.Malformatted; + var ps = pb.asString() catch return error.Malformatted; + if ((ps.len % 6) != 0) return error.Malformatted; + for (0..ps.len / 6) |ix| { + const start = ix * 6; + const port = std.mem.readInt(u16, ps[start + 4 .. start + 6][0..2], .big); + var ip = [_]u8{0} ** 4; + @memcpy(&ip, ps[start .. start + 4]); + try ipl.append(std.net.Address.initIp4(ip, port)); + } + return .{ + .peers = try ipl.toOwnedSlice(), + }; + } + + pub fn deinit(self: *TrackerResp, a: std.mem.Allocator) void { + a.free(self.peers); + } +}; + +pub fn trackerRequestUrl(a: std.mem.Allocator, info_hash: [20]u8, peer_id: [20]u8, left: usize, announce: []const u8) ![]const u8 { + var q = std.StringHashMap([]const u8).init(a); + defer q.deinit(); + try q.put("info_hash", &info_hash); + try q.put("peer_id", &peer_id); + try q.put("port", "6881"); + try q.put("uploaded", "0"); + try q.put("downloaded", "0"); + var buf_left = [_]u8{0} ** 1024; + try q.put("left", try std.fmt.bufPrint(&buf_left, "{}", .{left})); + try q.put("compact", "1"); + var qs = try toqs(a, q); + defer a.free(qs); + return try std.fmt.allocPrint(a, "{s}?{s}", .{ announce, qs }); +} + +fn toqs(a: std.mem.Allocator, hm: std.StringHashMap([]const u8)) ![]const u8 { + var al = std.ArrayList(u8).init(a); + defer al.deinit(); + var w = al.writer(); + var it = hm.iterator(); + var first = true; + while (it.next()) |entry| { + if (!first) try w.writeByte('&'); + try std.Uri.writeEscapedQuery(w, entry.key_ptr.*); + try w.writeByte('='); + try std.Uri.writeEscapedQuery(w, entry.value_ptr.*); + first = false; + } + return try al.toOwnedSlice(); +} |