155 lines
3.5 KiB
Go
155 lines
3.5 KiB
Go
// Copyright 2023 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
package peer
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
"github.com/signalapp/svr2/peerid"
|
|
pb "github.com/signalapp/svr2/proto"
|
|
)
|
|
|
|
/*
|
|
* The host protocol supports only PeerConnectionMessages
|
|
*
|
|
* Each message is sent by first writing a varint length,
|
|
* followed be the message contents
|
|
*/
|
|
|
|
func writeFramed(w io.Writer, m *pb.PeerConnectionMessage) error {
|
|
bs, err := proto.Marshal(m)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var frameBuf [binary.MaxVarintLen64]byte
|
|
n := binary.PutUvarint(frameBuf[:], uint64(len(bs)))
|
|
if _, err = w.Write(frameBuf[:n]); err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = w.Write(bs)
|
|
return err
|
|
}
|
|
|
|
func readFramed(r *bufio.Reader) (*pb.PeerConnectionMessage, error) {
|
|
bs, err := readFramedRaw(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var msg pb.PeerConnectionMessage
|
|
if err := proto.Unmarshal(bs, &msg); err != nil {
|
|
return nil, err
|
|
}
|
|
return &msg, nil
|
|
}
|
|
|
|
func readFramedRaw(r *bufio.Reader) ([]byte, error) {
|
|
length, err := binary.ReadUvarint(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if length > maxMessageLength {
|
|
return nil, fmt.Errorf("message of length %v too long (or corrupt)", length)
|
|
}
|
|
|
|
dst := make([]byte, length)
|
|
if _, err = io.ReadFull(r, dst); err != nil {
|
|
return nil, err
|
|
}
|
|
return dst, nil
|
|
}
|
|
|
|
func writeAck(w io.Writer, seqno sequenceNumber) error {
|
|
return writeFramed(w, &pb.PeerConnectionMessage{
|
|
Inner: &pb.PeerConnectionMessage_DataAck{
|
|
DataAck: &pb.PeerConnectionDataAck{Seqno: seqno.proto()},
|
|
},
|
|
})
|
|
}
|
|
|
|
func readAck(r *bufio.Reader) (sequenceNumber, error) {
|
|
msg, err := readFramed(r)
|
|
if err != nil {
|
|
return sequenceNumber{}, fmt.Errorf("readAck: %w", err)
|
|
}
|
|
in, ok := msg.Inner.(*pb.PeerConnectionMessage_DataAck)
|
|
if !ok {
|
|
return sequenceNumber{}, errors.New("readAck: unexpected peer connection message")
|
|
}
|
|
seqno, err := makeSeqno(in.DataAck.Seqno)
|
|
if err != nil {
|
|
return sequenceNumber{}, errors.New("readAck: no sequence number provided")
|
|
}
|
|
return seqno, nil
|
|
}
|
|
|
|
func writeHello(w io.Writer, from, to peerid.PeerID) error {
|
|
return writeFramed(
|
|
w,
|
|
&pb.PeerConnectionMessage{
|
|
Inner: &pb.PeerConnectionMessage_Hello{
|
|
Hello: &pb.PeerConnectionHello{FromPeerId: from[:], ToPeerId: to[:]},
|
|
},
|
|
},
|
|
)
|
|
}
|
|
|
|
func readHello(r *bufio.Reader) (from, to peerid.PeerID, returnedErr error) {
|
|
msg, err := readFramed(r)
|
|
if err != nil {
|
|
returnedErr = fmt.Errorf("readHello: %w", err)
|
|
return
|
|
}
|
|
in, ok := msg.Inner.(*pb.PeerConnectionMessage_Hello)
|
|
if !ok {
|
|
returnedErr = errors.New("hello: unexpected peer connection message")
|
|
return
|
|
}
|
|
from, returnedErr = peerid.Make(in.Hello.FromPeerId)
|
|
if returnedErr != nil {
|
|
return
|
|
}
|
|
to, returnedErr = peerid.Make(in.Hello.ToPeerId)
|
|
if returnedErr != nil {
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
func writeHelloAck(w io.Writer, lastAck sequenceNumber) error {
|
|
return writeFramed(
|
|
w,
|
|
&pb.PeerConnectionMessage{
|
|
Inner: &pb.PeerConnectionMessage_HelloAck{
|
|
HelloAck: &pb.PeerConnectionHelloAck{
|
|
LastAck: lastAck.proto(),
|
|
},
|
|
},
|
|
},
|
|
)
|
|
}
|
|
|
|
func readHelloAck(r *bufio.Reader) (sequenceNumber, error) {
|
|
var seqno sequenceNumber
|
|
|
|
msg, err := readFramed(r)
|
|
if err != nil {
|
|
return seqno, fmt.Errorf("readHelloAck: %w", err)
|
|
}
|
|
in, ok := msg.Inner.(*pb.PeerConnectionMessage_HelloAck)
|
|
if !ok {
|
|
return seqno, errors.New("hello ack: unexpected peer connection message")
|
|
}
|
|
if seqno, err = makeSeqno(in.HelloAck.LastAck); err != nil {
|
|
return seqno, err
|
|
}
|
|
return seqno, nil
|
|
}
|