blob: b432659619592fb0eb7f88b307b6117e7a411721 [file] [log] [blame]
David Benjamin6fd297b2014-08-11 18:43:38 -04001// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Adam Langleydc7e9c42015-09-29 15:21:04 -07005package runner
David Benjamin6fd297b2014-08-11 18:43:38 -04006
7import (
8 "encoding/binary"
David Benjamin83f90402015-01-27 01:09:43 -05009 "fmt"
10 "io"
David Benjamin6fd297b2014-08-11 18:43:38 -040011 "net"
David Benjamin83f90402015-01-27 01:09:43 -050012 "time"
David Benjamin6fd297b2014-08-11 18:43:38 -040013)
14
David Benjamin83f90402015-01-27 01:09:43 -050015// opcodePacket signals a packet, encoded with a 32-bit length prefix, followed
16// by the payload.
17const opcodePacket = byte('P')
18
19// opcodeTimeout signals a read timeout, encoded by a 64-bit number of
20// nanoseconds. On receipt, the peer should reply with
21// opcodeTimeoutAck. opcodeTimeout may only be sent by the Go side.
22const opcodeTimeout = byte('T')
23
24// opcodeTimeoutAck acknowledges a read timeout. This opcode has no payload and
25// may only be sent by the C side. Timeout ACKs act as a synchronization point
26// at the timeout, to bracket one flight of messages from C.
27const opcodeTimeoutAck = byte('t')
28
David Benjamin6fd297b2014-08-11 18:43:38 -040029type packetAdaptor struct {
30 net.Conn
31}
32
David Benjamin83f90402015-01-27 01:09:43 -050033// newPacketAdaptor wraps a reliable streaming net.Conn into a reliable
34// packet-based net.Conn. The stream contains packets and control commands,
35// distinguished by a one byte opcode.
36func newPacketAdaptor(conn net.Conn) *packetAdaptor {
David Benjamin6fd297b2014-08-11 18:43:38 -040037 return &packetAdaptor{conn}
38}
39
David Benjamin83f90402015-01-27 01:09:43 -050040func (p *packetAdaptor) readOpcode() (byte, error) {
41 out := make([]byte, 1)
42 if _, err := io.ReadFull(p.Conn, out); err != nil {
David Benjamin6fd297b2014-08-11 18:43:38 -040043 return 0, err
44 }
David Benjamin83f90402015-01-27 01:09:43 -050045 return out[0], nil
46}
47
48func (p *packetAdaptor) readPacketBody() ([]byte, error) {
49 var length uint32
50 if err := binary.Read(p.Conn, binary.BigEndian, &length); err != nil {
51 return nil, err
52 }
David Benjamin6fd297b2014-08-11 18:43:38 -040053 out := make([]byte, length)
David Benjamin83f90402015-01-27 01:09:43 -050054 if _, err := io.ReadFull(p.Conn, out); err != nil {
55 return nil, err
56 }
57 return out, nil
58}
59
60func (p *packetAdaptor) Read(b []byte) (int, error) {
61 opcode, err := p.readOpcode()
David Benjamin6fd297b2014-08-11 18:43:38 -040062 if err != nil {
63 return 0, err
64 }
David Benjamin83f90402015-01-27 01:09:43 -050065 if opcode != opcodePacket {
Adam Langleycaf6b092015-04-17 12:23:05 -070066 return 0, fmt.Errorf("unexpected opcode '%d'", opcode)
David Benjamin83f90402015-01-27 01:09:43 -050067 }
68 out, err := p.readPacketBody()
69 if err != nil {
70 return 0, err
David Benjamin6fd297b2014-08-11 18:43:38 -040071 }
72 return copy(b, out), nil
73}
74
75func (p *packetAdaptor) Write(b []byte) (int, error) {
David Benjamin83f90402015-01-27 01:09:43 -050076 payload := make([]byte, 1+4+len(b))
77 payload[0] = opcodePacket
78 binary.BigEndian.PutUint32(payload[1:5], uint32(len(b)))
79 copy(payload[5:], b)
80 if _, err := p.Conn.Write(payload); err != nil {
David Benjamin6fd297b2014-08-11 18:43:38 -040081 return 0, err
82 }
David Benjamin6fd297b2014-08-11 18:43:38 -040083 return len(b), nil
84}
David Benjamin5e961c12014-11-07 01:48:35 -050085
David Benjamin83f90402015-01-27 01:09:43 -050086// SendReadTimeout instructs the peer to simulate a read timeout. It then waits
87// for acknowledgement of the timeout, buffering any packets received since
88// then. The packets are then returned.
89func (p *packetAdaptor) SendReadTimeout(d time.Duration) ([][]byte, error) {
90 payload := make([]byte, 1+8)
91 payload[0] = opcodeTimeout
92 binary.BigEndian.PutUint64(payload[1:], uint64(d.Nanoseconds()))
93 if _, err := p.Conn.Write(payload); err != nil {
94 return nil, err
95 }
96
Adam Langleycaf6b092015-04-17 12:23:05 -070097 var packets [][]byte
David Benjamin83f90402015-01-27 01:09:43 -050098 for {
99 opcode, err := p.readOpcode()
100 if err != nil {
101 return nil, err
102 }
103 switch opcode {
104 case opcodeTimeoutAck:
105 // Done! Return the packets buffered and continue.
106 return packets, nil
107 case opcodePacket:
108 // Buffer the packet for the caller to process.
109 packet, err := p.readPacketBody()
110 if err != nil {
111 return nil, err
112 }
113 packets = append(packets, packet)
114 default:
Adam Langleycaf6b092015-04-17 12:23:05 -0700115 return nil, fmt.Errorf("unexpected opcode '%d'", opcode)
David Benjamin83f90402015-01-27 01:09:43 -0500116 }
117 }
118}
119
David Benjamin5e961c12014-11-07 01:48:35 -0500120type replayAdaptor struct {
121 net.Conn
122 prevWrite []byte
123}
124
125// newReplayAdaptor wraps a packeted net.Conn. It transforms it into
126// one which, after writing a packet, always replays the previous
127// write.
128func newReplayAdaptor(conn net.Conn) net.Conn {
129 return &replayAdaptor{Conn: conn}
130}
131
132func (r *replayAdaptor) Write(b []byte) (int, error) {
133 n, err := r.Conn.Write(b)
134
135 // Replay the previous packet and save the current one to
136 // replay next.
137 if r.prevWrite != nil {
138 r.Conn.Write(r.prevWrite)
139 }
140 r.prevWrite = append(r.prevWrite[:0], b...)
141
142 return n, err
143}
David Benjamin5fa3eba2015-01-22 16:35:40 -0500144
145type damageAdaptor struct {
146 net.Conn
147 damage bool
148}
149
150// newDamageAdaptor wraps a packeted net.Conn. It transforms it into one which
151// optionally damages the final byte of every Write() call.
152func newDamageAdaptor(conn net.Conn) *damageAdaptor {
153 return &damageAdaptor{Conn: conn}
154}
155
156func (d *damageAdaptor) setDamage(damage bool) {
157 d.damage = damage
158}
159
160func (d *damageAdaptor) Write(b []byte) (int, error) {
161 if d.damage && len(b) > 0 {
162 b = append([]byte{}, b...)
163 b[len(b)-1]++
164 }
165 return d.Conn.Write(b)
166}