mirror of
https://github.com/hanzozt/zt.git
synced 2026-11-03 05:01:58 +00:00
284 lines
5.5 KiB
Go
284 lines
5.5 KiB
Go
package loop3
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha512"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"github.com/michaelquigley/pfxlog"
|
|
"github.com/openziti/foundation/v2/info"
|
|
"github.com/pkg/errors"
|
|
"time"
|
|
)
|
|
|
|
type Message interface {
|
|
Tx(p *protocol) error
|
|
Rx(p *protocol) error
|
|
}
|
|
|
|
var success = []byte{1}
|
|
var failure = []byte{0}
|
|
|
|
type Result struct {
|
|
Success bool
|
|
Message string
|
|
}
|
|
|
|
func (r *Result) getSuccessBytes() []byte {
|
|
if r.Success {
|
|
return success
|
|
}
|
|
return failure
|
|
}
|
|
|
|
func (r *Result) Tx(p *protocol) error {
|
|
dataLen := 1 + len(r.Message)
|
|
if err := p.txHeader(p.peer, dataLen); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := p.peer.Write(r.getSuccessBytes()); err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(r.Message) > 0 {
|
|
if _, err := p.peer.Write([]byte(r.Message)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
MsgTxRate.Mark(1)
|
|
BytesTxRate.Mark(int64(4 + 4 + dataLen))
|
|
|
|
if r.Success {
|
|
pfxlog.ContextLogger(p.test.Name).Infof("<- [result+]")
|
|
} else {
|
|
pfxlog.ContextLogger(p.test.Name).Infof("<- [result-]")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *Result) Rx(p *protocol) error {
|
|
msgLen, err := p.rxHeader()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if msgLen < 1 {
|
|
return errors.Errorf("not enough data to deserialize Result need at least one byte")
|
|
}
|
|
body, err := p.rxMsgBody(msgLen)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r.Success = body[0] == 1
|
|
r.Message = string(body[1:])
|
|
|
|
MsgRxRate.Mark(1)
|
|
BytesRxRate.Mark(int64(4 + 4 + msgLen))
|
|
|
|
if r.Success {
|
|
pfxlog.ContextLogger(p.test.Name).Infof("<- [result+]")
|
|
} else {
|
|
pfxlog.ContextLogger(p.test.Name).Infof("<- [result-]")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
const (
|
|
BlockTypePlain byte = 1
|
|
BlockTypeLatencyRequest byte = 2
|
|
BlockTypeLatencyResponse byte = 3
|
|
)
|
|
|
|
type Block interface {
|
|
PrepForSend(p *protocol)
|
|
Tx(p *protocol) error
|
|
Verify(p *protocol) error
|
|
}
|
|
|
|
type RandHashedBlock struct {
|
|
Type byte
|
|
Sequence uint32
|
|
Hash []byte
|
|
Data []byte
|
|
Timestamp time.Time
|
|
}
|
|
|
|
func (block *RandHashedBlock) getTimestampBytes() ([]byte, error) {
|
|
if block.Type == BlockTypeLatencyRequest {
|
|
block.Timestamp = time.Now()
|
|
}
|
|
|
|
tsBuf := bytes.Buffer{}
|
|
|
|
if block.Type != BlockTypePlain {
|
|
ts, err := block.Timestamp.MarshalBinary()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(ts) > 32 {
|
|
panic(errors.Errorf("unexpected timestamp length: %v", len(ts)))
|
|
}
|
|
|
|
tsBuf.WriteByte(byte(len(ts)))
|
|
tsBuf.Write(ts)
|
|
}
|
|
return tsBuf.Bytes(), nil
|
|
}
|
|
|
|
func (block *RandHashedBlock) PrepForSend(p *protocol) {
|
|
var latency *time.Time
|
|
if block.Type == BlockTypePlain {
|
|
select {
|
|
case latency = <-p.latencies:
|
|
default:
|
|
latency = nil
|
|
}
|
|
|
|
if latency != nil {
|
|
block.Type = BlockTypeLatencyResponse
|
|
block.Timestamp = *latency
|
|
}
|
|
}
|
|
}
|
|
|
|
func (block *RandHashedBlock) Tx(p *protocol) error {
|
|
tsBytes, err := block.getTimestampBytes()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
dataLen := 1 /* block type */ + len(tsBytes) + 4 /* sequence bytes */ + len(block.Hash) + len(block.Data)
|
|
|
|
buf := &bytes.Buffer{}
|
|
if err := p.txHeader(buf, dataLen); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := buf.Write([]byte{block.Type}); err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(tsBytes) > 0 {
|
|
if _, err := buf.Write(tsBytes); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
seqBytes := make([]byte, 4)
|
|
binary.LittleEndian.PutUint32(seqBytes, block.Sequence)
|
|
|
|
if _, err := buf.Write(seqBytes); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := buf.Write(block.Hash); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := buf.Write(block.Data); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := p.peer.Write(buf.Bytes()); err != nil {
|
|
return err
|
|
}
|
|
|
|
MsgTxRate.Mark(1)
|
|
BytesTxRate.Mark(int64(8 + dataLen))
|
|
|
|
pfxlog.ContextLogger(p.test.Name).Infof("-> #%d (%s)", block.Sequence, info.ByteCount(int64(len(block.Data))))
|
|
|
|
return nil
|
|
}
|
|
|
|
func (block *RandHashedBlock) Rx(p *protocol) error {
|
|
length, err := p.rxHeader()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
body, err := p.rxMsgBody(length)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
buf := bytes.NewBuffer(body)
|
|
block.Type, err = buf.ReadByte()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if block.Type != BlockTypePlain {
|
|
tsLen, err := buf.ReadByte()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := block.Timestamp.UnmarshalBinary(buf.Next(int(tsLen))); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
seqBytes := buf.Next(4)
|
|
block.Sequence = binary.LittleEndian.Uint32(seqBytes)
|
|
|
|
block.Hash = buf.Next(64)
|
|
block.Data = buf.Bytes()
|
|
|
|
MsgRxRate.Mark(1)
|
|
BytesRxRate.Mark(int64(8 + length))
|
|
|
|
if block.Type == BlockTypeLatencyResponse {
|
|
elapsed := time.Since(block.Timestamp)
|
|
MsgLatency.Update(elapsed)
|
|
}
|
|
|
|
pfxlog.ContextLogger(p.test.Name).Infof("<- #%d (%s)", block.Sequence, info.ByteCount(int64(len(block.Data))))
|
|
|
|
return nil
|
|
}
|
|
|
|
func (block *RandHashedBlock) Verify(p *protocol) error {
|
|
if block.Sequence != uint32(p.rxSequence) {
|
|
return fmt.Errorf("expected sequence [%d] got sequence [%d]", p.rxSequence, block.Sequence)
|
|
}
|
|
|
|
hash := sha512.Sum512(block.Data)
|
|
if hex.EncodeToString(hash[:]) != hex.EncodeToString(block.Hash) {
|
|
return errors.New("mismatched hashes")
|
|
}
|
|
p.rxSequence++
|
|
|
|
return nil
|
|
}
|
|
|
|
type SeqBlock []byte
|
|
|
|
func (s SeqBlock) PrepForSend(*protocol) {
|
|
// does nothing
|
|
}
|
|
|
|
func (s SeqBlock) Tx(p *protocol) error {
|
|
_, err := p.peer.Write(s)
|
|
if err == nil {
|
|
pfxlog.ContextLogger(p.test.Name).Infof("-> #%d (%s)", p.txCount, info.ByteCount(int64(len(s))))
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (block SeqBlock) Verify(p *protocol) error {
|
|
for idx, b := range block {
|
|
cmp := byte(p.rxSequence)
|
|
if cmp != b {
|
|
err := fmt.Errorf("expected sequence [%d] got sequence [%d] at index %v", cmp, b, idx)
|
|
panic(err)
|
|
}
|
|
p.rxSequence++
|
|
}
|
|
return nil
|
|
}
|