github.com/anacrolix/torrent@v1.61.0/handshake.go (about)

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