blob: 671b413306d0491a28d57bc4c2b3bba014f7cd6e [file] [log] [blame]
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"encoding/binary"
"errors"
"net"
)
type packetAdaptor struct {
net.Conn
}
// newPacketAdaptor wraps a reliable streaming net.Conn into a
// reliable packet-based net.Conn. Every packet is encoded with a
// 32-bit length prefix as a framing layer.
func newPacketAdaptor(conn net.Conn) net.Conn {
return &packetAdaptor{conn}
}
func (p *packetAdaptor) Read(b []byte) (int, error) {
var length uint32
if err := binary.Read(p.Conn, binary.BigEndian, &length); err != nil {
return 0, err
}
out := make([]byte, length)
n, err := p.Conn.Read(out)
if err != nil {
return 0, err
}
if n != int(length) {
return 0, errors.New("internal error: length mismatch!")
}
return copy(b, out), nil
}
func (p *packetAdaptor) Write(b []byte) (int, error) {
length := uint32(len(b))
if err := binary.Write(p.Conn, binary.BigEndian, length); err != nil {
return 0, err
}
n, err := p.Conn.Write(b)
if err != nil {
return 0, err
}
if n != len(b) {
return 0, errors.New("internal error: length mismatch!")
}
return len(b), nil
}
type replayAdaptor struct {
net.Conn
prevWrite []byte
}
// newReplayAdaptor wraps a packeted net.Conn. It transforms it into
// one which, after writing a packet, always replays the previous
// write.
func newReplayAdaptor(conn net.Conn) net.Conn {
return &replayAdaptor{Conn: conn}
}
func (r *replayAdaptor) Write(b []byte) (int, error) {
n, err := r.Conn.Write(b)
// Replay the previous packet and save the current one to
// replay next.
if r.prevWrite != nil {
r.Conn.Write(r.prevWrite)
}
r.prevWrite = append(r.prevWrite[:0], b...)
return n, err
}
type damageAdaptor struct {
net.Conn
damage bool
}
// newDamageAdaptor wraps a packeted net.Conn. It transforms it into one which
// optionally damages the final byte of every Write() call.
func newDamageAdaptor(conn net.Conn) *damageAdaptor {
return &damageAdaptor{Conn: conn}
}
func (d *damageAdaptor) setDamage(damage bool) {
d.damage = damage
}
func (d *damageAdaptor) Write(b []byte) (int, error) {
if d.damage && len(b) > 0 {
b = append([]byte{}, b...)
b[len(b)-1]++
}
return d.Conn.Write(b)
}