-
-
Notifications
You must be signed in to change notification settings - Fork 83
/
msg.go
152 lines (124 loc) · 5.81 KB
/
msg.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package dht
import (
"github.com/anacrolix/torrent/bencode"
)
// Msg represents messages that nodes in the network send to each other as specified by the protocol.
// They are also referred to as the KRPC messages.
// There are three types of messages: QUERY, RESPONSE, ERROR
// The message is a dictionary that is then
// "bencoded" (serialization & compression format adopted by the BitTorrent)
// and sent via the UDP connection to peers.
//
// A KRPC message is a single dictionary with two keys common to every message and additional keys depending on the type of message.
// Every message has a key "t" with a string value representing a transaction ID.
// This transaction ID is generated by the querying node and is echoed in the response, so responses
// may be correlated with multiple queries to the same node. The transaction ID should be encoded as a short string of binary numbers, typically 2 characters are enough as they cover 2^16 outstanding queries. The other key contained in every KRPC message is "y" with a single character value describing the type of message. The value of the "y" key is one of "q" for query, "r" for response, or "e" for error.
// 3 message types: QUERY, RESPONSE, ERROR
type Msg struct {
Q string `bencode:"q,omitempty"` // Query method (one of 4: "ping", "find_node", "get_peers", "announce_peer")
A *MsgArgs `bencode:"a,omitempty"` // named arguments sent with a query
T string `bencode:"t"` // required: transaction ID
Y string `bencode:"y"` // required: type of the message: q for QUERY, r for RESPONSE, e for ERROR
R *Return `bencode:"r,omitempty"` // RESPONSE type only
E *Error `bencode:"e,omitempty"` // ERROR type only
IP NodeAddr `bencode:"ip,omitempty"`
ReadOnly bool `bencode:"ro,omitempty"` // BEP 43. Sender does not respond to queries.
// https://www.libtorrent.org/dht_extensions.html
ClientId string `bencode:"v,omitempty"`
}
const (
YQuery = "q"
YResponse = "r"
YError = "e"
)
type MsgArgs struct {
ID ID `bencode:"id"` // ID of the querying Node
InfoHash ID `bencode:"info_hash,omitempty"` // InfoHash of the torrent
Target ID `bencode:"target,omitempty"` // ID of the node sought
// Token received from an earlier get_peers query. Also used in a BEP 44 put.
Token string `bencode:"token,omitempty"`
Port *int `bencode:"port,omitempty"` // Sender's torrent port
ImpliedPort bool `bencode:"implied_port,omitempty"` // Use senders apparent DHT port
Want []Want `bencode:"want,omitempty"` // Contains strings like "n4" and "n6" from BEP 32.
NoSeed int `bencode:"noseed,omitempty"` // BEP 33
Scrape int `bencode:"scrape,omitempty"` // BEP 33
// BEP 44
// I don't know if we should use bencode.Bytes for this. If we unmarshalled bytes that didn't
// marshal back the same, our hashes will not match. But this might also serve to prevent abuse.
V interface{} `bencode:"v,omitempty"`
// Why is this optional? Because I think we need to know if it wasn't set rather than use a
// default value.
Seq *int64 `bencode:"seq,omitempty"`
Cas int64 `bencode:"cas,omitempty"`
K [32]byte `bencode:"k,omitempty"`
Salt []byte `bencode:"salt,omitempty"`
Sig [64]byte `bencode:"sig,omitempty"`
}
type Want string
const (
WantNodes Want = "n4"
WantNodes6 Want = "n6"
)
// BEP 51 (DHT Infohash Indexing)
type Bep51Return struct {
Interval *int64 `bencode:"interval,omitempty"`
Num *int64 `bencode:"num,omitempty"`
// Nodes supporting this extension should always include the samples field in the response, even
// when it is zero-length. This lets indexing nodes to distinguish nodes supporting this
// extension from those that respond to unknown query types which contain a target field [2].
Samples *CompactInfohashes `bencode:"samples,omitempty"`
}
type Bep44Return struct {
V bencode.Bytes `bencode:"v,omitempty"`
K [32]byte `bencode:"k,omitempty"`
Sig [64]byte `bencode:"sig,omitempty"`
Seq *int64 `bencode:"seq,omitempty"`
}
type Return struct {
// All returns are supposed to contain an ID, but what if they don't?
ID ID `bencode:"id"` // ID of the queried (and responding) node
// k closest nodes to the requested target. Included in responses to queries that imply
// traversal, for example get_peers, find_nodes, get, sample_infohashes.
Nodes CompactIPv4NodeInfo `bencode:"nodes,omitempty"`
Nodes6 CompactIPv6NodeInfo `bencode:"nodes6,omitempty"`
Token *string `bencode:"token,omitempty"` // Token for future announce_peer or put (BEP 44)
Values []NodeAddr `bencode:"values,omitempty"` // Torrent peers
// BEP 33 (scrapes)
BFsd *ScrapeBloomFilter `bencode:"BFsd,omitempty"`
BFpe *ScrapeBloomFilter `bencode:"BFpe,omitempty"`
Bep51Return
// BEP 44
Bep44Return
}
type CompactInfohashes []ID
func (CompactInfohashes) ElemSize() int { return 20 }
func (me CompactInfohashes) MarshalBinary() ([]byte, error) {
return marshalBinarySlice(me)
}
func (me CompactInfohashes) MarshalBencode() ([]byte, error) {
return bencodeBytesResult(me.MarshalBinary())
}
func (me *CompactInfohashes) UnmarshalBinary(b []byte) error {
return unmarshalBinarySlice(me, b)
}
func (me *CompactInfohashes) UnmarshalBencode(b []byte) error {
return unmarshalBencodedBinary(me, b)
}
type (
CompactIPv6NodeInfo []NodeInfo
)
func (CompactIPv6NodeInfo) ElemSize() int {
return 38
}
func (me CompactIPv6NodeInfo) MarshalBinary() ([]byte, error) {
return marshalBinarySlice(me)
}
func (me CompactIPv6NodeInfo) MarshalBencode() ([]byte, error) {
return bencodeBytesResult(me.MarshalBinary())
}
func (me *CompactIPv6NodeInfo) UnmarshalBinary(b []byte) error {
return unmarshalBinarySlice(me, b)
}
func (me *CompactIPv6NodeInfo) UnmarshalBencode(b []byte) error {
return unmarshalBencodedBinary(me, b)
}