a geicko-2 based round robin ranking system designed to test c++ battleship submissions
battleship.dunkirk.sh
1package sshfx
2
3import (
4 "errors"
5 "io"
6)
7
8// smallBufferSize is an initial allocation minimal capacity.
9const smallBufferSize = 64
10
11// RawPacket implements the general packet format from draft-ietf-secsh-filexfer-02
12//
13// RawPacket is intended for use in clients receiving responses,
14// where a response will be expected to be of a limited number of types,
15// and unmarshaling unknown/unexpected response packets is unnecessary.
16//
17// For servers expecting to receive arbitrary request packet types,
18// use RequestPacket.
19//
20// Defined in https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-3
21type RawPacket struct {
22 PacketType PacketType
23 RequestID uint32
24
25 Data Buffer
26}
27
28// Type returns the Type field defining the SSH_FXP_xy type for this packet.
29func (p *RawPacket) Type() PacketType {
30 return p.PacketType
31}
32
33// Reset clears the pointers and reference-semantic variables of RawPacket,
34// releasing underlying resources, and making them and the RawPacket suitable to be reused,
35// so long as no other references have been kept.
36func (p *RawPacket) Reset() {
37 p.Data = Buffer{}
38}
39
40// MarshalPacket returns p as a two-part binary encoding of p.
41//
42// The internal p.RequestID is overridden by the reqid argument.
43func (p *RawPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
44 buf := NewBuffer(b)
45 if buf.Cap() < 9 {
46 buf = NewMarshalBuffer(0)
47 }
48
49 buf.StartPacket(p.PacketType, reqid)
50
51 return buf.Packet(p.Data.Bytes())
52}
53
54// MarshalBinary returns p as the binary encoding of p.
55//
56// This is a convenience implementation primarily intended for tests,
57// because it is inefficient with allocations.
58func (p *RawPacket) MarshalBinary() ([]byte, error) {
59 return ComposePacket(p.MarshalPacket(p.RequestID, nil))
60}
61
62// UnmarshalFrom decodes a RawPacket from the given Buffer into p.
63//
64// The Data field will alias the passed in Buffer,
65// so the buffer passed in should not be reused before RawPacket.Reset().
66func (p *RawPacket) UnmarshalFrom(buf *Buffer) error {
67 *p = RawPacket{
68 PacketType: PacketType(buf.ConsumeUint8()),
69 RequestID: buf.ConsumeUint32(),
70 }
71
72 p.Data = *buf
73
74 return buf.Err
75}
76
77// UnmarshalBinary decodes a full raw packet out of the given data.
78// It is assumed that the uint32(length) has already been consumed to receive the data.
79//
80// This is a convenience implementation primarily intended for tests,
81// because this must clone the given data byte slice,
82// as Data is not allowed to alias any part of the data byte slice.
83func (p *RawPacket) UnmarshalBinary(data []byte) error {
84 clone := make([]byte, len(data))
85 n := copy(clone, data)
86 return p.UnmarshalFrom(NewBuffer(clone[:n]))
87}
88
89// readPacket reads a uint32 length-prefixed binary data packet from r.
90// using the given byte slice as a backing array.
91//
92// If the packet length read from r is bigger than maxPacketLength,
93// or greater than math.MaxInt32 on a 32-bit implementation,
94// then a `ErrLongPacket` error will be returned.
95//
96// If the given byte slice is insufficient to hold the packet,
97// then it will be extended to fill the packet size.
98func readPacket(r io.Reader, b []byte, maxPacketLength uint32) ([]byte, error) {
99 if cap(b) < 4 {
100 // We will need allocate our own buffer just for reading the packet length.
101
102 // However, we don’t really want to allocate an extremely narrow buffer (4-bytes),
103 // and cause unnecessary allocation churn from both length reads and small packet reads,
104 // so we use smallBufferSize from the bytes package as a reasonable guess.
105
106 // But if callers really do want to force narrow throw-away allocation of every packet body,
107 // they can do so with a buffer of capacity 4.
108 b = make([]byte, smallBufferSize)
109 }
110
111 if _, err := io.ReadFull(r, b[:4]); err != nil {
112 return nil, err
113 }
114
115 length := unmarshalUint32(b)
116 if int(length) < 5 {
117 // Must have at least uint8(type) and uint32(request-id)
118
119 if int(length) < 0 {
120 // Only possible when strconv.IntSize == 32,
121 // the packet length is longer than math.MaxInt32,
122 // and thus longer than any possible slice.
123 return nil, ErrLongPacket
124 }
125
126 return nil, ErrShortPacket
127 }
128 if length > maxPacketLength {
129 return nil, ErrLongPacket
130 }
131
132 if int(length) > cap(b) {
133 // We know int(length) must be positive, because of tests above.
134 b = make([]byte, length)
135 }
136
137 n, err := io.ReadFull(r, b[:length])
138 return b[:n], err
139}
140
141// ReadFrom provides a simple functional packet reader,
142// using the given byte slice as a backing array.
143//
144// To protect against potential denial of service attacks,
145// if the read packet length is longer than maxPacketLength,
146// then no packet data will be read, and ErrLongPacket will be returned.
147// (On 32-bit int architectures, all packets >= 2^31 in length
148// will return ErrLongPacket regardless of maxPacketLength.)
149//
150// If the read packet length is longer than cap(b),
151// then a throw-away slice will allocated to meet the exact packet length.
152// This can be used to limit the length of reused buffers,
153// while still allowing reception of occasional large packets.
154//
155// The Data field may alias the passed in byte slice,
156// so the byte slice passed in should not be reused before RawPacket.Reset().
157func (p *RawPacket) ReadFrom(r io.Reader, b []byte, maxPacketLength uint32) error {
158 b, err := readPacket(r, b, maxPacketLength)
159 if err != nil {
160 return err
161 }
162
163 return p.UnmarshalFrom(NewBuffer(b))
164}
165
166// RequestPacket implements the general packet format from draft-ietf-secsh-filexfer-02
167// but also automatically decode/encodes valid request packets (2 < type < 100 || type == 200).
168//
169// RequestPacket is intended for use in servers receiving requests,
170// where any arbitrary request may be received, and so decoding them automatically
171// is useful.
172//
173// For clients expecting to receive specific response packet types,
174// where automatic unmarshaling of the packet body does not make sense,
175// use RawPacket.
176//
177// Defined in https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-3
178type RequestPacket struct {
179 RequestID uint32
180
181 Request Packet
182}
183
184// Type returns the SSH_FXP_xy value associated with the underlying packet.
185func (p *RequestPacket) Type() PacketType {
186 return p.Request.Type()
187}
188
189// Reset clears the pointers and reference-semantic variables in RequestPacket,
190// releasing underlying resources, and making them and the RequestPacket suitable to be reused,
191// so long as no other references have been kept.
192func (p *RequestPacket) Reset() {
193 p.Request = nil
194}
195
196// MarshalPacket returns p as a two-part binary encoding of p.
197//
198// The internal p.RequestID is overridden by the reqid argument.
199func (p *RequestPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
200 if p.Request == nil {
201 return nil, nil, errors.New("empty request packet")
202 }
203
204 return p.Request.MarshalPacket(reqid, b)
205}
206
207// MarshalBinary returns p as the binary encoding of p.
208//
209// This is a convenience implementation primarily intended for tests,
210// because it is inefficient with allocations.
211func (p *RequestPacket) MarshalBinary() ([]byte, error) {
212 return ComposePacket(p.MarshalPacket(p.RequestID, nil))
213}
214
215// UnmarshalFrom decodes a RequestPacket from the given Buffer into p.
216//
217// The Request field may alias the passed in Buffer, (e.g. SSH_FXP_WRITE),
218// so the buffer passed in should not be reused before RequestPacket.Reset().
219func (p *RequestPacket) UnmarshalFrom(buf *Buffer) error {
220 typ := PacketType(buf.ConsumeUint8())
221 if buf.Err != nil {
222 return buf.Err
223 }
224
225 req, err := newPacketFromType(typ)
226 if err != nil {
227 return err
228 }
229
230 *p = RequestPacket{
231 RequestID: buf.ConsumeUint32(),
232 Request: req,
233 }
234
235 return p.Request.UnmarshalPacketBody(buf)
236}
237
238// UnmarshalBinary decodes a full request packet out of the given data.
239// It is assumed that the uint32(length) has already been consumed to receive the data.
240//
241// This is a convenience implementation primarily intended for tests,
242// because this must clone the given data byte slice,
243// as Request is not allowed to alias any part of the data byte slice.
244func (p *RequestPacket) UnmarshalBinary(data []byte) error {
245 clone := make([]byte, len(data))
246 n := copy(clone, data)
247 return p.UnmarshalFrom(NewBuffer(clone[:n]))
248}
249
250// ReadFrom provides a simple functional packet reader,
251// using the given byte slice as a backing array.
252//
253// To protect against potential denial of service attacks,
254// if the read packet length is longer than maxPacketLength,
255// then no packet data will be read, and ErrLongPacket will be returned.
256// (On 32-bit int architectures, all packets >= 2^31 in length
257// will return ErrLongPacket regardless of maxPacketLength.)
258//
259// If the read packet length is longer than cap(b),
260// then a throw-away slice will allocated to meet the exact packet length.
261// This can be used to limit the length of reused buffers,
262// while still allowing reception of occasional large packets.
263//
264// The Request field may alias the passed in byte slice,
265// so the byte slice passed in should not be reused before RawPacket.Reset().
266func (p *RequestPacket) ReadFrom(r io.Reader, b []byte, maxPacketLength uint32) error {
267 b, err := readPacket(r, b, maxPacketLength)
268 if err != nil {
269 return err
270 }
271
272 return p.UnmarshalFrom(NewBuffer(b))
273}