github.com/mutagen-io/mutagen@v0.18.0-rc1/pkg/synchronization/compression/handshake.go (about)

     1  package compression
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  )
     8  
     9  // errAlgorithmUnsupported indicates that the algorithm requested by the client
    10  // is unsupported by the server.
    11  var errAlgorithmUnsupported = errors.New("algorithm unsupported")
    12  
    13  // ClientHandshake performs a client-side compression handshake on the stream.
    14  // It transmits the desired compression algorithm and verifies that this
    15  // algorithm is supported by the server.
    16  func ClientHandshake(stream io.ReadWriter, algorithm Algorithm) error {
    17  	// Verify that the algorithm can be encoded into a single byte.
    18  	if algorithm < 0 || algorithm > 255 {
    19  		return errors.New("invalid algorithm value")
    20  	}
    21  
    22  	// Convert the algorithm specification.
    23  	data := [1]byte{byte(algorithm)}
    24  
    25  	// Transmit the data.
    26  	if _, err := stream.Write(data[:]); err != nil {
    27  		return fmt.Errorf("unable to transmit algorithm specification: %w", err)
    28  	}
    29  
    30  	// Receive the response.
    31  	if _, err := io.ReadFull(stream, data[:]); err != nil {
    32  		return fmt.Errorf("unable to receive response: %w", err)
    33  	}
    34  
    35  	// Handle the response.
    36  	switch data[0] {
    37  	case 0:
    38  		return errAlgorithmUnsupported
    39  	case 1:
    40  		return nil
    41  	default:
    42  		return errors.New("invalid response from server")
    43  	}
    44  }
    45  
    46  // ServerHandshake performs a server-side compression handshake on the stream.
    47  // It receives the desired compression algorithm from the client, verifies that
    48  // this algorithm is supported, and transmits a response to the client.
    49  func ServerHandshake(stream io.ReadWriter) (Algorithm, error) {
    50  	// Receive the algorithm specification.
    51  	var data [1]byte
    52  	if _, err := io.ReadFull(stream, data[:]); err != nil {
    53  		return Algorithm_AlgorithmDefault, fmt.Errorf("unable to receive algorithm specification: %w", err)
    54  	}
    55  
    56  	// Convert the algorithm specification and ensure that it's supported.
    57  	algorithm := Algorithm(data[0])
    58  	supported := algorithm.SupportStatus() == AlgorithmSupportStatusSupported
    59  
    60  	// Format and transmit the response.
    61  	if supported {
    62  		data[0] = 1
    63  	} else {
    64  		data[0] = 0
    65  	}
    66  	if _, err := stream.Write(data[:]); err != nil {
    67  		return Algorithm_AlgorithmDefault, fmt.Errorf("unable to transmit response: %w", err)
    68  	}
    69  
    70  	// Handle unsupported algorithms.
    71  	if !supported {
    72  		return Algorithm_AlgorithmDefault, errAlgorithmUnsupported
    73  	}
    74  
    75  	// Success.
    76  	return algorithm, nil
    77  }