2014-08-11 23:43:38 +01:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2014-11-07 06:48:35 +00:00
|
|
|
// 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.
|
2014-08-11 23:43:38 +01:00
|
|
|
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
|
|
|
|
}
|
2014-11-07 06:48:35 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2015-01-22 21:35:40 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|