| // 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) |
| } |