handshake.go 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. package torrent
  2. import (
  3. "bytes"
  4. "context"
  5. "fmt"
  6. "io"
  7. "net"
  8. "time"
  9. "github.com/anacrolix/torrent/mse"
  10. pp "github.com/anacrolix/torrent/peer_protocol"
  11. )
  12. // Wraps a raw connection and provides the interface we want for using the
  13. // connection in the message loop.
  14. type deadlineReader struct {
  15. nc net.Conn
  16. r io.Reader
  17. }
  18. func (r deadlineReader) Read(b []byte) (int, error) {
  19. // Keep-alives should be received every 2 mins. Give a bit of gracetime.
  20. err := r.nc.SetReadDeadline(time.Now().Add(150 * time.Second))
  21. if err != nil {
  22. return 0, fmt.Errorf("error setting read deadline: %s", err)
  23. }
  24. return r.r.Read(b)
  25. }
  26. // Handles stream encryption for inbound connections.
  27. func handleEncryption(
  28. rw io.ReadWriter,
  29. skeys mse.SecretKeyIter,
  30. policy HeaderObfuscationPolicy,
  31. selector mse.CryptoSelector,
  32. ) (
  33. ret io.ReadWriter,
  34. headerEncrypted bool,
  35. cryptoMethod mse.CryptoMethod,
  36. err error,
  37. ) {
  38. // Tries to start an unencrypted stream.
  39. if !policy.RequirePreferred || !policy.Preferred {
  40. var protocol [len(pp.Protocol)]byte
  41. _, err = io.ReadFull(rw, protocol[:])
  42. if err != nil {
  43. return
  44. }
  45. // Put the protocol back into the stream.
  46. rw = struct {
  47. io.Reader
  48. io.Writer
  49. }{
  50. io.MultiReader(bytes.NewReader(protocol[:]), rw),
  51. rw,
  52. }
  53. if string(protocol[:]) == pp.Protocol {
  54. ret = rw
  55. return
  56. }
  57. if policy.RequirePreferred {
  58. // We are here because we require unencrypted connections.
  59. err = fmt.Errorf("unexpected protocol string %q and header obfuscation disabled", protocol)
  60. return
  61. }
  62. }
  63. headerEncrypted = true
  64. ret, cryptoMethod, err = mse.ReceiveHandshake(context.TODO(), rw, skeys, selector)
  65. return
  66. }
  67. type PeerExtensionBits = pp.PeerExtensionBits