mirror of
https://github.com/ossrs/srs.git
synced 2025-02-15 04:42:04 +00:00
For the DJI M30, there is a bug where empty NALU packets with a size of zero are causing issues with HLS streaming. This bug leads to random unpublish events due to the SRS disconnecting the connection for the HLS module when it fails to handle empty NALU packets. To address this bug, we have patched the system to ignore any empty NALU packets with a size of zero. Additionally, we have created a tool in the srs-bench to replay pcapng files captured by tcpdump or Wireshark. We have also added utest using mprotect and asan to detect any memory corruption. It is important to note that this bug has been fixed in versions 4.0.2716477f31004
and 5.0.170939f6b484b
. This patch specifically addresses the issue in SRS 6.0. Please be aware that there is another commit related to this bug that partially fixes the issue but still leaves a small problem for asan to detect memory corruption. This commit,577cd299e1
, only ignores empty NALU packets but still reads beyond the memory. --------- Co-authored-by: chundonglinlin <chundonglinlin@163.com>
232 lines
8.8 KiB
Go
232 lines
8.8 KiB
Go
// Copyright 2012 Google, Inc. All rights reserved.
|
|
//
|
|
// Use of this source code is governed by a BSD-style license
|
|
// that can be found in the LICENSE file in the root of the source
|
|
// tree.
|
|
|
|
package gopacket
|
|
|
|
import (
|
|
"fmt"
|
|
)
|
|
|
|
// SerializableLayer allows its implementations to be written out as a set of bytes,
|
|
// so those bytes may be sent on the wire or otherwise used by the caller.
|
|
// SerializableLayer is implemented by certain Layer types, and can be encoded to
|
|
// bytes using the LayerWriter object.
|
|
type SerializableLayer interface {
|
|
// SerializeTo writes this layer to a slice, growing that slice if necessary
|
|
// to make it fit the layer's data.
|
|
// Args:
|
|
// b: SerializeBuffer to write this layer on to. When called, b.Bytes()
|
|
// is the payload this layer should wrap, if any. Note that this
|
|
// layer can either prepend itself (common), append itself
|
|
// (uncommon), or both (sometimes padding or footers are required at
|
|
// the end of packet data). It's also possible (though probably very
|
|
// rarely needed) to overwrite any bytes in the current payload.
|
|
// After this call, b.Bytes() should return the byte encoding of
|
|
// this layer wrapping the original b.Bytes() payload.
|
|
// opts: options to use while writing out data.
|
|
// Returns:
|
|
// error if a problem was encountered during encoding. If an error is
|
|
// returned, the bytes in data should be considered invalidated, and
|
|
// not used.
|
|
//
|
|
// SerializeTo calls SHOULD entirely ignore LayerContents and
|
|
// LayerPayload. It just serializes based on struct fields, neither
|
|
// modifying nor using contents/payload.
|
|
SerializeTo(b SerializeBuffer, opts SerializeOptions) error
|
|
// LayerType returns the type of the layer that is being serialized to the buffer
|
|
LayerType() LayerType
|
|
}
|
|
|
|
// SerializeOptions provides options for behaviors that SerializableLayers may want to
|
|
// implement.
|
|
type SerializeOptions struct {
|
|
// FixLengths determines whether, during serialization, layers should fix
|
|
// the values for any length field that depends on the payload.
|
|
FixLengths bool
|
|
// ComputeChecksums determines whether, during serialization, layers
|
|
// should recompute checksums based on their payloads.
|
|
ComputeChecksums bool
|
|
}
|
|
|
|
// SerializeBuffer is a helper used by gopacket for writing out packet layers.
|
|
// SerializeBuffer starts off as an empty []byte. Subsequent calls to PrependBytes
|
|
// return byte slices before the current Bytes(), AppendBytes returns byte
|
|
// slices after.
|
|
//
|
|
// Byte slices returned by PrependBytes/AppendBytes are NOT zero'd out, so if
|
|
// you want to make sure they're all zeros, set them as such.
|
|
//
|
|
// SerializeBuffer is specifically designed to handle packet writing, where unlike
|
|
// with normal writes it's easier to start writing at the inner-most layer and
|
|
// work out, meaning that we often need to prepend bytes. This runs counter to
|
|
// typical writes to byte slices using append(), where we only write at the end
|
|
// of the buffer.
|
|
//
|
|
// It can be reused via Clear. Note, however, that a Clear call will invalidate the
|
|
// byte slices returned by any previous Bytes() call (the same buffer is
|
|
// reused).
|
|
//
|
|
// 1) Reusing a write buffer is generally much faster than creating a new one,
|
|
// and with the default implementation it avoids additional memory allocations.
|
|
// 2) If a byte slice from a previous Bytes() call will continue to be used,
|
|
// it's better to create a new SerializeBuffer.
|
|
//
|
|
// The Clear method is specifically designed to minimize memory allocations for
|
|
// similar later workloads on the SerializeBuffer. IE: if you make a set of
|
|
// Prepend/Append calls, then clear, then make the same calls with the same
|
|
// sizes, the second round (and all future similar rounds) shouldn't allocate
|
|
// any new memory.
|
|
type SerializeBuffer interface {
|
|
// Bytes returns the contiguous set of bytes collected so far by Prepend/Append
|
|
// calls. The slice returned by Bytes will be modified by future Clear calls,
|
|
// so if you're planning on clearing this SerializeBuffer, you may want to copy
|
|
// Bytes somewhere safe first.
|
|
Bytes() []byte
|
|
// PrependBytes returns a set of bytes which prepends the current bytes in this
|
|
// buffer. These bytes start in an indeterminate state, so they should be
|
|
// overwritten by the caller. The caller must only call PrependBytes if they
|
|
// know they're going to immediately overwrite all bytes returned.
|
|
PrependBytes(num int) ([]byte, error)
|
|
// AppendBytes returns a set of bytes which appends the current bytes in this
|
|
// buffer. These bytes start in an indeterminate state, so they should be
|
|
// overwritten by the caller. The caller must only call AppendBytes if they
|
|
// know they're going to immediately overwrite all bytes returned.
|
|
AppendBytes(num int) ([]byte, error)
|
|
// Clear resets the SerializeBuffer to a new, empty buffer. After a call to clear,
|
|
// the byte slice returned by any previous call to Bytes() for this buffer
|
|
// should be considered invalidated.
|
|
Clear() error
|
|
// Layers returns all the Layers that have been successfully serialized into this buffer
|
|
// already.
|
|
Layers() []LayerType
|
|
// PushLayer adds the current Layer to the list of Layers that have been serialized
|
|
// into this buffer.
|
|
PushLayer(LayerType)
|
|
}
|
|
|
|
type serializeBuffer struct {
|
|
data []byte
|
|
start int
|
|
prepended, appended int
|
|
layers []LayerType
|
|
}
|
|
|
|
// NewSerializeBuffer creates a new instance of the default implementation of
|
|
// the SerializeBuffer interface.
|
|
func NewSerializeBuffer() SerializeBuffer {
|
|
return &serializeBuffer{}
|
|
}
|
|
|
|
// NewSerializeBufferExpectedSize creates a new buffer for serialization, optimized for an
|
|
// expected number of bytes prepended/appended. This tends to decrease the
|
|
// number of memory allocations made by the buffer during writes.
|
|
func NewSerializeBufferExpectedSize(expectedPrependLength, expectedAppendLength int) SerializeBuffer {
|
|
return &serializeBuffer{
|
|
data: make([]byte, expectedPrependLength, expectedPrependLength+expectedAppendLength),
|
|
start: expectedPrependLength,
|
|
prepended: expectedPrependLength,
|
|
appended: expectedAppendLength,
|
|
}
|
|
}
|
|
|
|
func (w *serializeBuffer) Bytes() []byte {
|
|
return w.data[w.start:]
|
|
}
|
|
|
|
func (w *serializeBuffer) PrependBytes(num int) ([]byte, error) {
|
|
if num < 0 {
|
|
panic("num < 0")
|
|
}
|
|
if w.start < num {
|
|
toPrepend := w.prepended
|
|
if toPrepend < num {
|
|
toPrepend = num
|
|
}
|
|
w.prepended += toPrepend
|
|
length := cap(w.data) + toPrepend
|
|
newData := make([]byte, length)
|
|
newStart := w.start + toPrepend
|
|
copy(newData[newStart:], w.data[w.start:])
|
|
w.start = newStart
|
|
w.data = newData[:toPrepend+len(w.data)]
|
|
}
|
|
w.start -= num
|
|
return w.data[w.start : w.start+num], nil
|
|
}
|
|
|
|
func (w *serializeBuffer) AppendBytes(num int) ([]byte, error) {
|
|
if num < 0 {
|
|
panic("num < 0")
|
|
}
|
|
initialLength := len(w.data)
|
|
if cap(w.data)-initialLength < num {
|
|
toAppend := w.appended
|
|
if toAppend < num {
|
|
toAppend = num
|
|
}
|
|
w.appended += toAppend
|
|
newData := make([]byte, cap(w.data)+toAppend)
|
|
copy(newData[w.start:], w.data[w.start:])
|
|
w.data = newData[:initialLength]
|
|
}
|
|
// Grow the buffer. We know it'll be under capacity given above.
|
|
w.data = w.data[:initialLength+num]
|
|
return w.data[initialLength:], nil
|
|
}
|
|
|
|
func (w *serializeBuffer) Clear() error {
|
|
w.start = w.prepended
|
|
w.data = w.data[:w.start]
|
|
w.layers = w.layers[:0]
|
|
return nil
|
|
}
|
|
|
|
func (w *serializeBuffer) Layers() []LayerType {
|
|
return w.layers
|
|
}
|
|
|
|
func (w *serializeBuffer) PushLayer(l LayerType) {
|
|
w.layers = append(w.layers, l)
|
|
}
|
|
|
|
// SerializeLayers clears the given write buffer, then writes all layers into it so
|
|
// they correctly wrap each other. Note that by clearing the buffer, it
|
|
// invalidates all slices previously returned by w.Bytes()
|
|
//
|
|
// Example:
|
|
// buf := gopacket.NewSerializeBuffer()
|
|
// opts := gopacket.SerializeOptions{}
|
|
// gopacket.SerializeLayers(buf, opts, a, b, c)
|
|
// firstPayload := buf.Bytes() // contains byte representation of a(b(c))
|
|
// gopacket.SerializeLayers(buf, opts, d, e, f)
|
|
// secondPayload := buf.Bytes() // contains byte representation of d(e(f)). firstPayload is now invalidated, since the SerializeLayers call Clears buf.
|
|
func SerializeLayers(w SerializeBuffer, opts SerializeOptions, layers ...SerializableLayer) error {
|
|
w.Clear()
|
|
for i := len(layers) - 1; i >= 0; i-- {
|
|
layer := layers[i]
|
|
err := layer.SerializeTo(w, opts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
w.PushLayer(layer.LayerType())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SerializePacket is a convenience function that calls SerializeLayers
|
|
// on packet's Layers().
|
|
// It returns an error if one of the packet layers is not a SerializableLayer.
|
|
func SerializePacket(buf SerializeBuffer, opts SerializeOptions, packet Packet) error {
|
|
sls := []SerializableLayer{}
|
|
for _, layer := range packet.Layers() {
|
|
sl, ok := layer.(SerializableLayer)
|
|
if !ok {
|
|
return fmt.Errorf("layer %s is not serializable", layer.LayerType().String())
|
|
}
|
|
sls = append(sls, sl)
|
|
}
|
|
return SerializeLayers(buf, opts, sls...)
|
|
}
|