github.com/gopacket/gopacket@v1.1.0/writer.go (about)

     1  // Copyright 2012 Google, Inc. All rights reserved.
     2  //
     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
     5  // tree.
     6  
     7  package gopacket
     8  
     9  import (
    10  	"fmt"
    11  )
    12  
    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.
    20  	//  Args:
    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.
    30  	//  Returns:
    31  	//   error if a problem was encountered during encoding.  If an error is
    32  	//   returned, the bytes in data should be considered invalidated, and
    33  	//   not used.
    34  	//
    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
    39  	// LayerType returns the type of the layer that is being serialized to the buffer
    40  	LayerType() LayerType
    41  }
    42  
    43  // SerializeOptions provides options for behaviors that SerializableLayers may want to
    44  // implement.
    45  type SerializeOptions struct {
    46  	// FixLengths determines whether, during serialization, layers should fix
    47  	// the values for any length field that depends on the payload.
    48  	FixLengths bool
    49  	// ComputeChecksums determines whether, during serialization, layers
    50  	// should recompute checksums based on their payloads.
    51  	ComputeChecksums bool
    52  }
    53  
    54  // SerializeBuffer is a helper used by gopacket for writing out packet layers.
    55  // SerializeBuffer starts off as an empty []byte.  Subsequent calls to PrependBytes
    56  // return byte slices before the current Bytes(), AppendBytes returns byte
    57  // slices after.
    58  //
    59  // Byte slices returned by PrependBytes/AppendBytes are NOT zero'd out, so if
    60  // you want to make sure they're all zeros, set them as such.
    61  //
    62  // SerializeBuffer is specifically designed to handle packet writing, where unlike
    63  // with normal writes it's easier to start writing at the inner-most layer and
    64  // work out, meaning that we often need to prepend bytes.  This runs counter to
    65  // typical writes to byte slices using append(), where we only write at the end
    66  // of the buffer.
    67  //
    68  // It can be reused via Clear.  Note, however, that a Clear call will invalidate the
    69  // byte slices returned by any previous Bytes() call (the same buffer is
    70  // reused).
    71  //
    72  //  1. Reusing a write buffer is generally much faster than creating a new one,
    73  //     and with the default implementation it avoids additional memory allocations.
    74  //  2. If a byte slice from a previous Bytes() call will continue to be used,
    75  //     it's better to create a new SerializeBuffer.
    76  //
    77  // The Clear method is specifically designed to minimize memory allocations for
    78  // similar later workloads on the SerializeBuffer.  IE: if you make a set of
    79  // Prepend/Append calls, then clear, then make the same calls with the same
    80  // sizes, the second round (and all future similar rounds) shouldn't allocate
    81  // any new memory.
    82  type SerializeBuffer interface {
    83  	// Bytes returns the contiguous set of bytes collected so far by Prepend/Append
    84  	// calls.  The slice returned by Bytes will be modified by future Clear calls,
    85  	// so if you're planning on clearing this SerializeBuffer, you may want to copy
    86  	// Bytes somewhere safe first.
    87  	Bytes() []byte
    88  	// PrependBytes returns a set of bytes which prepends the current bytes in this
    89  	// buffer.  These bytes start in an indeterminate state, so they should be
    90  	// overwritten by the caller.  The caller must only call PrependBytes if they
    91  	// know they're going to immediately overwrite all bytes returned.
    92  	PrependBytes(num int) ([]byte, error)
    93  	// AppendBytes returns a set of bytes which appends the current bytes in this
    94  	// buffer.  These bytes start in an indeterminate state, so they should be
    95  	// overwritten by the caller.  The caller must only call AppendBytes if they
    96  	// know they're going to immediately overwrite all bytes returned.
    97  	AppendBytes(num int) ([]byte, error)
    98  	// Clear resets the SerializeBuffer to a new, empty buffer.  After a call to clear,
    99  	// the byte slice returned by any previous call to Bytes() for this buffer
   100  	// should be considered invalidated.
   101  	Clear() error
   102  	// Layers returns all the Layers that have been successfully serialized into this buffer
   103  	// already.
   104  	Layers() []LayerType
   105  	// PushLayer adds the current Layer to the list of Layers that have been serialized
   106  	// into this buffer.
   107  	PushLayer(LayerType)
   108  }
   109  
   110  type serializeBuffer struct {
   111  	data                []byte
   112  	start               int
   113  	prepended, appended int
   114  	layers              []LayerType
   115  }
   116  
   117  // NewSerializeBuffer creates a new instance of the default implementation of
   118  // the SerializeBuffer interface.
   119  func NewSerializeBuffer() SerializeBuffer {
   120  	return &serializeBuffer{}
   121  }
   122  
   123  // NewSerializeBufferExpectedSize creates a new buffer for serialization, optimized for an
   124  // expected number of bytes prepended/appended.  This tends to decrease the
   125  // number of memory allocations made by the buffer during writes.
   126  func NewSerializeBufferExpectedSize(expectedPrependLength, expectedAppendLength int) SerializeBuffer {
   127  	return &serializeBuffer{
   128  		data:      make([]byte, expectedPrependLength, expectedPrependLength+expectedAppendLength),
   129  		start:     expectedPrependLength,
   130  		prepended: expectedPrependLength,
   131  		appended:  expectedAppendLength,
   132  	}
   133  }
   134  
   135  func (w *serializeBuffer) Bytes() []byte {
   136  	return w.data[w.start:]
   137  }
   138  
   139  func (w *serializeBuffer) PrependBytes(num int) ([]byte, error) {
   140  	if num < 0 {
   141  		panic("num < 0")
   142  	}
   143  	if w.start < num {
   144  		toPrepend := w.prepended
   145  		if toPrepend < num {
   146  			toPrepend = num
   147  		}
   148  		w.prepended += toPrepend
   149  		length := cap(w.data) + toPrepend
   150  		newData := make([]byte, length)
   151  		newStart := w.start + toPrepend
   152  		copy(newData[newStart:], w.data[w.start:])
   153  		w.start = newStart
   154  		w.data = newData[:toPrepend+len(w.data)]
   155  	}
   156  	w.start -= num
   157  	return w.data[w.start : w.start+num], nil
   158  }
   159  
   160  func (w *serializeBuffer) AppendBytes(num int) ([]byte, error) {
   161  	if num < 0 {
   162  		panic("num < 0")
   163  	}
   164  	initialLength := len(w.data)
   165  	if cap(w.data)-initialLength < num {
   166  		toAppend := w.appended
   167  		if toAppend < num {
   168  			toAppend = num
   169  		}
   170  		w.appended += toAppend
   171  		newData := make([]byte, cap(w.data)+toAppend)
   172  		copy(newData[w.start:], w.data[w.start:])
   173  		w.data = newData[:initialLength]
   174  	}
   175  	// Grow the buffer.  We know it'll be under capacity given above.
   176  	w.data = w.data[:initialLength+num]
   177  	return w.data[initialLength:], nil
   178  }
   179  
   180  func (w *serializeBuffer) Clear() error {
   181  	w.start = w.prepended
   182  	w.data = w.data[:w.start]
   183  	w.layers = w.layers[:0]
   184  	return nil
   185  }
   186  
   187  func (w *serializeBuffer) Layers() []LayerType {
   188  	return w.layers
   189  }
   190  
   191  func (w *serializeBuffer) PushLayer(l LayerType) {
   192  	w.layers = append(w.layers, l)
   193  }
   194  
   195  // SerializeLayers clears the given write buffer, then writes all layers into it so
   196  // they correctly wrap each other.  Note that by clearing the buffer, it
   197  // invalidates all slices previously returned by w.Bytes()
   198  //
   199  // Example:
   200  //
   201  //	buf := gopacket.NewSerializeBuffer()
   202  //	opts := gopacket.SerializeOptions{}
   203  //	gopacket.SerializeLayers(buf, opts, a, b, c)
   204  //	firstPayload := buf.Bytes()  // contains byte representation of a(b(c))
   205  //	gopacket.SerializeLayers(buf, opts, d, e, f)
   206  //	secondPayload := buf.Bytes()  // contains byte representation of d(e(f)). firstPayload is now invalidated, since the SerializeLayers call Clears buf.
   207  func SerializeLayers(w SerializeBuffer, opts SerializeOptions, layers ...SerializableLayer) error {
   208  	w.Clear()
   209  	for i := len(layers) - 1; i >= 0; i-- {
   210  		layer := layers[i]
   211  		err := layer.SerializeTo(w, opts)
   212  		if err != nil {
   213  			return err
   214  		}
   215  		w.PushLayer(layer.LayerType())
   216  	}
   217  	return nil
   218  }
   219  
   220  // SerializePacket is a convenience function that calls SerializeLayers
   221  // on packet's Layers().
   222  // It returns an error if one of the packet layers is not a SerializableLayer.
   223  func SerializePacket(buf SerializeBuffer, opts SerializeOptions, packet Packet) error {
   224  	sls := []SerializableLayer{}
   225  	for _, layer := range packet.Layers() {
   226  		sl, ok := layer.(SerializableLayer)
   227  		if !ok {
   228  			return fmt.Errorf("layer %s is not serializable", layer.LayerType().String())
   229  		}
   230  		sls = append(sls, sl)
   231  	}
   232  	return SerializeLayers(buf, opts, sls...)
   233  }