msg.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package krpc
  2. import (
  3. "github.com/anacrolix/torrent/bencode"
  4. )
  5. // Msg represents messages that nodes in the network send to each other as specified by the protocol.
  6. // They are also referred to as the KRPC messages.
  7. // There are three types of messages: QUERY, RESPONSE, ERROR
  8. // The message is a dictionary that is then
  9. // "bencoded" (serialization & compression format adopted by the BitTorrent)
  10. // and sent via the UDP connection to peers.
  11. //
  12. // A KRPC message is a single dictionary with two keys common to every message and additional keys depending on the type of message.
  13. // Every message has a key "t" with a string value representing a transaction ID.
  14. // This transaction ID is generated by the querying node and is echoed in the response, so responses
  15. // 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.
  16. // 3 message types: QUERY, RESPONSE, ERROR
  17. type Msg struct {
  18. Q string `bencode:"q,omitempty"` // Query method (one of 4: "ping", "find_node", "get_peers", "announce_peer")
  19. A *MsgArgs `bencode:"a,omitempty"` // named arguments sent with a query
  20. T string `bencode:"t"` // required: transaction ID
  21. Y string `bencode:"y"` // required: type of the message: q for QUERY, r for RESPONSE, e for ERROR
  22. R *Return `bencode:"r,omitempty"` // RESPONSE type only
  23. E *Error `bencode:"e,omitempty"` // ERROR type only
  24. IP NodeAddr `bencode:"ip,omitempty"`
  25. ReadOnly bool `bencode:"ro,omitempty"` // BEP 43. Sender does not respond to queries.
  26. }
  27. type MsgArgs struct {
  28. ID ID `bencode:"id"` // ID of the querying Node
  29. InfoHash ID `bencode:"info_hash,omitempty"` // InfoHash of the torrent
  30. Target ID `bencode:"target,omitempty"` // ID of the node sought
  31. // Token received from an earlier get_peers query. Also used in a BEP 44 put.
  32. Token string `bencode:"token,omitempty"`
  33. Port *int `bencode:"port,omitempty"` // Sender's torrent port
  34. ImpliedPort bool `bencode:"implied_port,omitempty"` // Use senders apparent DHT port
  35. Want []Want `bencode:"want,omitempty"` // Contains strings like "n4" and "n6" from BEP 32.
  36. NoSeed int `bencode:"noseed,omitempty"` // BEP 33
  37. Scrape int `bencode:"scrape,omitempty"` // BEP 33
  38. // BEP 44
  39. // I don't know if we should use bencode.Bytes for this. If we unmarshalled bytes that didn't
  40. // marshal back the same, our hashes will not match. But this might also serve to prevent abuse.
  41. V interface{} `bencode:"v,omitempty"`
  42. Seq *int64 `bencode:"seq,omitempty"`
  43. Cas int64 `bencode:"cas,omitempty"`
  44. K [32]byte `bencode:"k,omitempty"`
  45. Salt []byte `bencode:"salt,omitempty"`
  46. Sig [64]byte `bencode:"sig,omitempty"`
  47. }
  48. type Want string
  49. const (
  50. WantNodes Want = "n4"
  51. WantNodes6 Want = "n6"
  52. )
  53. // BEP 51 (DHT Infohash Indexing)
  54. type Bep51Return struct {
  55. Interval *int64 `bencode:"interval,omitempty"`
  56. Num *int64 `bencode:"num,omitempty"`
  57. // Nodes supporting this extension should always include the samples field in the response, even
  58. // when it is zero-length. This lets indexing nodes to distinguish nodes supporting this
  59. // extension from those that respond to unknown query types which contain a target field [2].
  60. Samples *CompactInfohashes `bencode:"samples,omitempty"`
  61. }
  62. type Bep44Return struct {
  63. V bencode.Bytes `bencode:"v,omitempty"`
  64. K [32]byte `bencode:"k,omitempty"`
  65. Sig [64]byte `bencode:"sig,omitempty"`
  66. Seq *int64 `bencode:"seq,omitempty"`
  67. }
  68. type Return struct {
  69. // All returns are supposed to contain an ID, but what if they don't?
  70. ID ID `bencode:"id"` // ID of the queried (and responding) node
  71. // K closest nodes to the requested target. Included in responses to queries that imply
  72. // traversal, for example get_peers, find_nodes, get, sample_infohashes.
  73. Nodes CompactIPv4NodeInfo `bencode:"nodes,omitempty"`
  74. Nodes6 CompactIPv6NodeInfo `bencode:"nodes6,omitempty"`
  75. Token *string `bencode:"token,omitempty"` // Token for future announce_peer or put (BEP 44)
  76. Values []NodeAddr `bencode:"values,omitempty"` // Torrent peers
  77. // BEP 33 (scrapes)
  78. BFsd *ScrapeBloomFilter `bencode:"BFsd,omitempty"`
  79. BFpe *ScrapeBloomFilter `bencode:"BFpe,omitempty"`
  80. Bep51Return
  81. // BEP 44
  82. Bep44Return
  83. }
  84. func (r Return) ForAllNodes(f func(NodeInfo)) {
  85. for _, n := range r.Nodes {
  86. f(n)
  87. }
  88. for _, n := range r.Nodes6 {
  89. f(n)
  90. }
  91. }
  92. // The node ID of the source of this Msg. Returns nil if it isn't present.
  93. // TODO: Can we verify Msgs more aggressively so this is guaranteed to return
  94. // a valid ID for a checked Msg?
  95. func (m Msg) SenderID() *ID {
  96. switch m.Y {
  97. case "q":
  98. if m.A == nil {
  99. return nil
  100. }
  101. return &m.A.ID
  102. case "r":
  103. if m.R == nil {
  104. return nil
  105. }
  106. return &m.R.ID
  107. }
  108. return nil
  109. }
  110. // This does not return an error, but (*Error)(nil) is still a non-nil error. You have been warned!
  111. // This language is evil.
  112. func (m Msg) Error() *Error {
  113. if m.Y != "e" {
  114. return nil
  115. }
  116. return m.E
  117. }