1 // Copyright 2012 Google, Inc. All rights reserved.
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the LICENSE file in the root of the source
13 // SerializableLayer allows its implementations to be written out as a set of bytes,
14 // so those bytes may be sent on the wire or otherwise used by the caller.
15 // SerializableLayer is implemented by certain Layer types, and can be encoded to
16 // bytes using the LayerWriter object.
17 type SerializableLayer interface {
18 // SerializeTo writes this layer to a slice, growing that slice if necessary
19 // to make it fit the layer's data.
21 // b: SerializeBuffer to write this layer on to. When called, b.Bytes()
22 // is the payload this layer should wrap, if any. Note that this
23 // layer can either prepend itself (common), append itself
24 // (uncommon), or both (sometimes padding or footers are required at
25 // the end of packet data). It's also possible (though probably very
26 // rarely needed) to overwrite any bytes in the current payload.
27 // After this call, b.Bytes() should return the byte encoding of
28 // this layer wrapping the original b.Bytes() payload.
29 // opts: options to use while writing out data.
31 // error if a problem was encountered during encoding. If an error is
32 // returned, the bytes in data should be considered invalidated, and
35 // SerializeTo calls SHOULD entirely ignore LayerContents and
36 // LayerPayload. It just serializes based on struct fields, neither
37 // modifying nor using contents/payload.
38 SerializeTo(b SerializeBuffer, opts SerializeOptions) error
41 // SerializeOptions provides options for behaviors that SerializableLayers may want to
43 type SerializeOptions struct {
44 // FixLengths determines whether, during serialization, layers should fix
45 // the values for any length field that depends on the payload.
47 // ComputeChecksums determines whether, during serialization, layers
48 // should recompute checksums based on their payloads.
52 // SerializeBuffer is a helper used by gopacket for writing out packet layers.
53 // SerializeBuffer starts off as an empty []byte. Subsequent calls to PrependBytes
54 // return byte slices before the current Bytes(), AppendBytes returns byte
57 // Byte slices returned by PrependBytes/AppendBytes are NOT zero'd out, so if
58 // you want to make sure they're all zeros, set them as such.
60 // SerializeBuffer is specifically designed to handle packet writing, where unlike
61 // with normal writes it's easier to start writing at the inner-most layer and
62 // work out, meaning that we often need to prepend bytes. This runs counter to
63 // typical writes to byte slices using append(), where we only write at the end
66 // It can be reused via Clear. Note, however, that a Clear call will invalidate the
67 // byte slices returned by any previous Bytes() call (the same buffer is
70 // 1) Reusing a write buffer is generally much faster than creating a new one,
71 // and with the default implementation it avoids additional memory allocations.
72 // 2) If a byte slice from a previous Bytes() call will continue to be used,
73 // it's better to create a new SerializeBuffer.
75 // The Clear method is specifically designed to minimize memory allocations for
76 // similar later workloads on the SerializeBuffer. IE: if you make a set of
77 // Prepend/Append calls, then clear, then make the same calls with the same
78 // sizes, the second round (and all future similar rounds) shouldn't allocate
80 type SerializeBuffer interface {
81 // Bytes returns the contiguous set of bytes collected so far by Prepend/Append
82 // calls. The slice returned by Bytes will be modified by future Clear calls,
83 // so if you're planning on clearing this SerializeBuffer, you may want to copy
84 // Bytes somewhere safe first.
86 // PrependBytes returns a set of bytes which prepends the current bytes in this
87 // buffer. These bytes start in an indeterminate state, so they should be
88 // overwritten by the caller. The caller must only call PrependBytes if they
89 // know they're going to immediately overwrite all bytes returned.
90 PrependBytes(num int) ([]byte, error)
91 // AppendBytes returns a set of bytes which appends the current bytes in this
92 // buffer. These bytes start in an indeterminate state, so they should be
93 // overwritten by the caller. The caller must only call AppendBytes if they
94 // know they're going to immediately overwrite all bytes returned.
95 AppendBytes(num int) ([]byte, error)
96 // Clear resets the SerializeBuffer to a new, empty buffer. After a call to clear,
97 // the byte slice returned by any previous call to Bytes() for this buffer
98 // should be considered invalidated.
102 type serializeBuffer struct {
105 prepended, appended int
108 // NewSerializeBuffer creates a new instance of the default implementation of
109 // the SerializeBuffer interface.
110 func NewSerializeBuffer() SerializeBuffer {
111 return &serializeBuffer{}
114 // NewSerializeBufferExpectedSize creates a new buffer for serialization, optimized for an
115 // expected number of bytes prepended/appended. This tends to decrease the
116 // number of memory allocations made by the buffer during writes.
117 func NewSerializeBufferExpectedSize(expectedPrependLength, expectedAppendLength int) SerializeBuffer {
118 return &serializeBuffer{
119 data: make([]byte, expectedPrependLength, expectedPrependLength+expectedAppendLength),
120 start: expectedPrependLength,
121 prepended: expectedPrependLength,
122 appended: expectedAppendLength,
126 func (w *serializeBuffer) Bytes() []byte {
127 return w.data[w.start:]
130 func (w *serializeBuffer) PrependBytes(num int) ([]byte, error) {
135 toPrepend := w.prepended
139 w.prepended += toPrepend
140 length := cap(w.data) + toPrepend
141 newData := make([]byte, length)
142 newStart := w.start + toPrepend
143 copy(newData[newStart:], w.data[w.start:])
145 w.data = newData[:toPrepend+len(w.data)]
148 return w.data[w.start : w.start+num], nil
151 func (w *serializeBuffer) AppendBytes(num int) ([]byte, error) {
155 initialLength := len(w.data)
156 if cap(w.data)-initialLength < num {
157 toAppend := w.appended
161 w.appended += toAppend
162 newData := make([]byte, cap(w.data)+toAppend)
163 copy(newData[w.start:], w.data[w.start:])
164 w.data = newData[:initialLength]
166 // Grow the buffer. We know it'll be under capacity given above.
167 w.data = w.data[:initialLength+num]
168 return w.data[initialLength:], nil
171 func (w *serializeBuffer) Clear() error {
172 w.start = w.prepended
173 w.data = w.data[:w.start]
177 // SerializeLayers clears the given write buffer, then writes all layers into it so
178 // they correctly wrap each other. Note that by clearing the buffer, it
179 // invalidates all slices previously returned by w.Bytes()
182 // buf := gopacket.NewSerializeBuffer()
183 // opts := gopacket.SerializeOptions{}
184 // gopacket.SerializeLayers(buf, opts, a, b, c)
185 // firstPayload := buf.Bytes() // contains byte representation of a(b(c))
186 // gopacket.SerializeLayers(buf, opts, d, e, f)
187 // secondPayload := buf.Bytes() // contains byte representation of d(e(f)). firstPayload is now invalidated, since the SerializeLayers call Clears buf.
188 func SerializeLayers(w SerializeBuffer, opts SerializeOptions, layers ...SerializableLayer) error {
190 for i := len(layers) - 1; i >= 0; i-- {
192 err := layer.SerializeTo(w, opts)
200 // SerializePacket is a convenience function that calls SerializeLayers
201 // on packet's Layers().
202 // It returns an error if one of the packet layers is not a SerializebleLayer.
203 func SerializePacket(buf SerializeBuffer, opts SerializeOptions, packet Packet) error {
204 sls := []SerializableLayer{}
205 for _, layer := range packet.Layers() {
206 sl, ok := layer.(SerializableLayer)
208 return fmt.Errorf("layer %s is not serializable", layer.LayerType().String())
210 sls = append(sls, sl)
212 return SerializeLayers(buf, opts, sls...)