yggdrasil-go/src/yggdrasil/stream.go

77 lines
2.2 KiB
Go
Raw Normal View History

package yggdrasil
import (
"errors"
"fmt"
"github.com/yggdrasil-network/yggdrasil-go/src/util"
)
type stream struct {
buffer []byte
}
const streamMsgSize = 2048 + 65535
var streamMsg = [...]byte{0xde, 0xad, 0xb1, 0x75} // "dead bits"
func (s *stream) init() {
s.buffer = make([]byte, 2*streamMsgSize)
}
// This reads from the channel into a []byte buffer for incoming messages. It
// copies completed messages out of the cache into a new slice, and passes them
// to the peer struct via the provided `in func([]byte)` argument. Then it
// shifts the incomplete fragments of data forward so future reads won't
// overwrite it.
func (s *stream) write(bs []byte, in func([]byte)) error {
frag := s.buffer[:0]
if n := len(bs); n > 0 {
frag = append(frag, bs[:n]...)
msg, ok, err2 := stream_chopMsg(&frag)
if err2 != nil {
return fmt.Errorf("message error: %v", err2)
}
if !ok {
// We didn't get the whole message yet
return nil
}
newMsg := append(util.GetBytes(), msg...)
in(newMsg)
util.Yield()
}
return nil
}
// This takes a pointer to a slice as an argument. It checks if there's a
// complete message and, if so, slices out those parts and returns the message,
// true, and nil. If there's no error, but also no complete message, it returns
// nil, false, and nil. If there's an error, it returns nil, false, and the
// error, which the reader then handles (currently, by returning from the
// reader, which causes the connection to close).
func stream_chopMsg(bs *[]byte) ([]byte, bool, error) {
// Returns msg, ok, err
if len(*bs) < len(streamMsg) {
return nil, false, nil
}
for idx := range streamMsg {
if (*bs)[idx] != streamMsg[idx] {
return nil, false, errors.New("bad message")
}
}
msgLen, msgLenLen := wire_decode_uint64((*bs)[len(streamMsg):])
if msgLen > streamMsgSize {
return nil, false, errors.New("oversized message")
}
msgBegin := len(streamMsg) + msgLenLen
msgEnd := msgBegin + int(msgLen)
if msgLenLen == 0 || len(*bs) < msgEnd {
// We don't have the full message
// Need to buffer this and wait for the rest to come in
return nil, false, nil
}
msg := (*bs)[msgBegin:msgEnd]
(*bs) = (*bs)[msgEnd:]
return msg, true, nil
}