handshake.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. package peer_protocol
  2. import (
  3. "context"
  4. "encoding/hex"
  5. "errors"
  6. "fmt"
  7. "github.com/anacrolix/torrent/internal/ctxrw"
  8. "io"
  9. "math/bits"
  10. "strconv"
  11. "strings"
  12. "unsafe"
  13. "github.com/anacrolix/torrent/metainfo"
  14. )
  15. type ExtensionBit uint
  16. // https://www.bittorrent.org/beps/bep_0004.html
  17. // https://wiki.theory.org/BitTorrentSpecification.html#Reserved_Bytes
  18. const (
  19. ExtensionBitDht = 0 // http://www.bittorrent.org/beps/bep_0005.html
  20. ExtensionBitFast = 2 // http://www.bittorrent.org/beps/bep_0006.html
  21. // A peer connection initiator can set this when sending a v1 infohash during handshake if they
  22. // allow the receiving end to upgrade to v2 by responding with the corresponding v2 infohash.
  23. // BEP 52, and BEP 4. TODO: Set by default and then clear it when it's not appropriate to send.
  24. ExtensionBitV2Upgrade = 4
  25. ExtensionBitAzureusExtensionNegotiation1 = 16
  26. ExtensionBitAzureusExtensionNegotiation2 = 17
  27. // LibTorrent Extension Protocol, http://www.bittorrent.org/beps/bep_0010.html
  28. ExtensionBitLtep = 20
  29. // https://wiki.theory.org/BitTorrent_Location-aware_Protocol_1
  30. ExtensionBitLocationAwareProtocol = 43
  31. ExtensionBitAzureusMessagingProtocol = 63 // https://www.bittorrent.org/beps/bep_0004.html
  32. )
  33. func handshakeWriter(w io.Writer, bb <-chan []byte, done chan<- error) {
  34. var err error
  35. for b := range bb {
  36. _, err = w.Write(b)
  37. if err != nil {
  38. break
  39. }
  40. }
  41. done <- err
  42. }
  43. type (
  44. PeerExtensionBits [8]byte
  45. )
  46. var bitTags = []struct {
  47. bit ExtensionBit
  48. tag string
  49. }{
  50. // Ordered by their bit position left to right.
  51. {ExtensionBitAzureusMessagingProtocol, "amp"},
  52. {ExtensionBitLocationAwareProtocol, "loc"},
  53. {ExtensionBitLtep, "ltep"},
  54. {ExtensionBitAzureusExtensionNegotiation2, "azen2"},
  55. {ExtensionBitAzureusExtensionNegotiation1, "azen1"},
  56. {ExtensionBitV2Upgrade, "v2"},
  57. {ExtensionBitFast, "fast"},
  58. {ExtensionBitDht, "dht"},
  59. }
  60. func (pex PeerExtensionBits) String() string {
  61. pexHex := hex.EncodeToString(pex[:])
  62. tags := make([]string, 0, len(bitTags)+1)
  63. for _, bitTag := range bitTags {
  64. if pex.GetBit(bitTag.bit) {
  65. tags = append(tags, bitTag.tag)
  66. pex.SetBit(bitTag.bit, false)
  67. }
  68. }
  69. unknownCount := bits.OnesCount64(*(*uint64)((unsafe.Pointer(&pex[0]))))
  70. if unknownCount != 0 {
  71. tags = append(tags, fmt.Sprintf("%v unknown", unknownCount))
  72. }
  73. return fmt.Sprintf("%v (%s)", pexHex, strings.Join(tags, ", "))
  74. }
  75. func NewPeerExtensionBytes(bits ...ExtensionBit) (ret PeerExtensionBits) {
  76. for _, b := range bits {
  77. ret.SetBit(b, true)
  78. }
  79. return
  80. }
  81. func (pex PeerExtensionBits) SupportsExtended() bool {
  82. return pex.GetBit(ExtensionBitLtep)
  83. }
  84. func (pex PeerExtensionBits) SupportsDHT() bool {
  85. return pex.GetBit(ExtensionBitDht)
  86. }
  87. func (pex PeerExtensionBits) SupportsFast() bool {
  88. return pex.GetBit(ExtensionBitFast)
  89. }
  90. func (pex *PeerExtensionBits) SetBit(bit ExtensionBit, on bool) {
  91. if on {
  92. pex[7-bit/8] |= 1 << (bit % 8)
  93. } else {
  94. pex[7-bit/8] &^= 1 << (bit % 8)
  95. }
  96. }
  97. func (pex PeerExtensionBits) GetBit(bit ExtensionBit) bool {
  98. return pex[7-bit/8]&(1<<(bit%8)) != 0
  99. }
  100. type HandshakeResult struct {
  101. PeerExtensionBits
  102. PeerID [20]byte
  103. metainfo.Hash
  104. }
  105. // ih is nil if we expect the peer to declare the InfoHash, such as when the peer initiated the
  106. // connection. Returns ok if the Handshake was successful, and err if there was an unexpected
  107. // condition other than the peer simply abandoning the Handshake.
  108. func Handshake(
  109. ctx context.Context,
  110. sock io.ReadWriter,
  111. ih *metainfo.Hash,
  112. peerID [20]byte,
  113. extensions PeerExtensionBits,
  114. ) (
  115. res HandshakeResult, err error,
  116. ) {
  117. sock = ctxrw.WrapReadWriter(ctx, sock)
  118. // Bytes to be sent to the peer. Should never block the sender.
  119. postCh := make(chan []byte, 4)
  120. // A single error value sent when the writer completes.
  121. writeDone := make(chan error, 1)
  122. // Performs writes to the socket and ensures posts don't block.
  123. go handshakeWriter(sock, postCh, writeDone)
  124. defer func() {
  125. close(postCh) // Done writing.
  126. if err != nil {
  127. return
  128. }
  129. // Wait until writes complete before returning from handshake.
  130. err = <-writeDone
  131. if err != nil {
  132. err = fmt.Errorf("error writing: %w", err)
  133. }
  134. }()
  135. post := func(bb []byte) {
  136. select {
  137. case postCh <- bb:
  138. default:
  139. panic("mustn't block while posting")
  140. }
  141. }
  142. post([]byte(Protocol))
  143. post(extensions[:])
  144. if ih != nil { // We already know what we want.
  145. post(ih[:])
  146. post(peerID[:])
  147. }
  148. var b [68]byte
  149. _, err = io.ReadFull(sock, b[:68])
  150. if err != nil {
  151. return res, fmt.Errorf("while reading: %w", err)
  152. }
  153. if string(b[:20]) != Protocol {
  154. return res, errors.New("unexpected protocol string")
  155. }
  156. copyExact := func(dst, src []byte) {
  157. if dstLen, srcLen := uint64(len(dst)), uint64(len(src)); dstLen != srcLen {
  158. panic("dst len " + strconv.FormatUint(dstLen, 10) + " != src len " + strconv.FormatUint(srcLen, 10))
  159. }
  160. copy(dst, src)
  161. }
  162. copyExact(res.PeerExtensionBits[:], b[20:28])
  163. copyExact(res.Hash[:], b[28:48])
  164. copyExact(res.PeerID[:], b[48:68])
  165. // peerExtensions.Add(res.PeerExtensionBits.String(), 1)
  166. // TODO: Maybe we can just drop peers here if we're not interested. This
  167. // could prevent them trying to reconnect, falsely believing there was
  168. // just a problem.
  169. if ih == nil { // We were waiting for the peer to tell us what they wanted.
  170. post(res.Hash[:])
  171. post(peerID[:])
  172. }
  173. return
  174. }