live video streaming server in golang
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

497 lines
12 KiB

package amf
import (
"encoding/binary"
"fmt"
"io"
"time"
)
// amf3 polymorphic router
func (d *Decoder) DecodeAmf3(r io.Reader) (interface{}, error) {
marker, err := ReadMarker(r)
if err != nil {
return nil, err
}
switch marker {
case AMF3_UNDEFINED_MARKER:
return d.DecodeAmf3Undefined(r, false)
case AMF3_NULL_MARKER:
return d.DecodeAmf3Null(r, false)
case AMF3_FALSE_MARKER:
return d.DecodeAmf3False(r, false)
case AMF3_TRUE_MARKER:
return d.DecodeAmf3True(r, false)
case AMF3_INTEGER_MARKER:
return d.DecodeAmf3Integer(r, false)
case AMF3_DOUBLE_MARKER:
return d.DecodeAmf3Double(r, false)
case AMF3_STRING_MARKER:
return d.DecodeAmf3String(r, false)
case AMF3_XMLDOC_MARKER:
return d.DecodeAmf3Xml(r, false)
case AMF3_DATE_MARKER:
return d.DecodeAmf3Date(r, false)
case AMF3_ARRAY_MARKER:
return d.DecodeAmf3Array(r, false)
case AMF3_OBJECT_MARKER:
return d.DecodeAmf3Object(r, false)
case AMF3_XMLSTRING_MARKER:
return d.DecodeAmf3Xml(r, false)
case AMF3_BYTEARRAY_MARKER:
return d.DecodeAmf3ByteArray(r, false)
}
return nil, fmt.Errorf("decode amf3: unsupported type %d", marker)
}
// marker: 1 byte 0x00
// no additional data
func (d *Decoder) DecodeAmf3Undefined(r io.Reader, decodeMarker bool) (result interface{}, err error) {
err = AssertMarker(r, decodeMarker, AMF3_UNDEFINED_MARKER)
return
}
// marker: 1 byte 0x01
// no additional data
func (d *Decoder) DecodeAmf3Null(r io.Reader, decodeMarker bool) (result interface{}, err error) {
err = AssertMarker(r, decodeMarker, AMF3_NULL_MARKER)
return
}
// marker: 1 byte 0x02
// no additional data
func (d *Decoder) DecodeAmf3False(r io.Reader, decodeMarker bool) (result bool, err error) {
err = AssertMarker(r, decodeMarker, AMF3_FALSE_MARKER)
result = false
return
}
// marker: 1 byte 0x03
// no additional data
func (d *Decoder) DecodeAmf3True(r io.Reader, decodeMarker bool) (result bool, err error) {
err = AssertMarker(r, decodeMarker, AMF3_TRUE_MARKER)
result = true
return
}
// marker: 1 byte 0x04
func (d *Decoder) DecodeAmf3Integer(r io.Reader, decodeMarker bool) (result int32, err error) {
if err = AssertMarker(r, decodeMarker, AMF3_INTEGER_MARKER); err != nil {
return
}
var u29 uint32
u29, err = d.decodeU29(r)
if err != nil {
return
}
result = int32(u29)
if result > 0xfffffff {
result = int32(u29 - 0x20000000)
}
return
}
// marker: 1 byte 0x05
func (d *Decoder) DecodeAmf3Double(r io.Reader, decodeMarker bool) (result float64, err error) {
if err = AssertMarker(r, decodeMarker, AMF3_DOUBLE_MARKER); err != nil {
return
}
err = binary.Read(r, binary.BigEndian, &result)
if err != nil {
return float64(0), fmt.Errorf("amf3 decode: unable to read double: %s", err)
}
return
}
// marker: 1 byte 0x06
// format:
// - u29 reference int. if reference, no more data. if not reference,
// length value of bytes to read to complete string.
func (d *Decoder) DecodeAmf3String(r io.Reader, decodeMarker bool) (result string, err error) {
if err = AssertMarker(r, decodeMarker, AMF3_STRING_MARKER); err != nil {
return
}
var isRef bool
var refVal uint32
isRef, refVal, err = d.decodeReferenceInt(r)
if err != nil {
return "", fmt.Errorf("amf3 decode: unable to decode string reference and length: %s", err)
}
if isRef {
result = d.stringRefs[refVal]
return
}
buf := make([]byte, refVal)
_, err = r.Read(buf)
if err != nil {
return "", fmt.Errorf("amf3 decode: unable to read string: %s", err)
}
result = string(buf)
if result != "" {
d.stringRefs = append(d.stringRefs, result)
}
return
}
// marker: 1 byte 0x08
// format:
// - u29 reference int, if reference, no more data
// - timestamp double
func (d *Decoder) DecodeAmf3Date(r io.Reader, decodeMarker bool) (result time.Time, err error) {
if err = AssertMarker(r, decodeMarker, AMF3_DATE_MARKER); err != nil {
return
}
var isRef bool
var refVal uint32
isRef, refVal, err = d.decodeReferenceInt(r)
if err != nil {
return result, fmt.Errorf("amf3 decode: unable to decode date reference and length: %s", err)
}
if isRef {
res, ok := d.objectRefs[refVal].(time.Time)
if ok != true {
return result, fmt.Errorf("amf3 decode: unable to extract time from date object references")
}
return res, err
}
var u64 float64
err = binary.Read(r, binary.BigEndian, &u64)
if err != nil {
return result, fmt.Errorf("amf3 decode: unable to read double: %s", err)
}
result = time.Unix(int64(u64/1000), 0).UTC()
d.objectRefs = append(d.objectRefs, result)
return
}
// marker: 1 byte 0x09
// format:
// - u29 reference int. if reference, no more data.
// - string representing associative array if present
// - n values (length of u29)
func (d *Decoder) DecodeAmf3Array(r io.Reader, decodeMarker bool) (result Array, err error) {
if err = AssertMarker(r, decodeMarker, AMF3_ARRAY_MARKER); err != nil {
return
}
var isRef bool
var refVal uint32
isRef, refVal, err = d.decodeReferenceInt(r)
if err != nil {
return result, fmt.Errorf("amf3 decode: unable to decode array reference and length: %s", err)
}
if isRef {
objRefId := refVal >> 1
res, ok := d.objectRefs[objRefId].(Array)
if ok != true {
return result, fmt.Errorf("amf3 decode: unable to extract array from object references")
}
return res, err
}
var key string
key, err = d.DecodeAmf3String(r, false)
if err != nil {
return result, fmt.Errorf("amf3 decode: unable to read key for array: %s", err)
}
if key != "" {
return result, fmt.Errorf("amf3 decode: array key is not empty, can't handle associative array")
}
for i := uint32(0); i < refVal; i++ {
tmp, err := d.DecodeAmf3(r)
if err != nil {
return result, fmt.Errorf("amf3 decode: array element could not be decoded: %s", err)
}
result = append(result, tmp)
}
d.objectRefs = append(d.objectRefs, result)
return
}
// marker: 1 byte 0x09
// format: oh dear god
func (d *Decoder) DecodeAmf3Object(r io.Reader, decodeMarker bool) (result interface{}, err error) {
if err = AssertMarker(r, decodeMarker, AMF3_OBJECT_MARKER); err != nil {
return nil, err
}
// decode the initial u29
isRef, refVal, err := d.decodeReferenceInt(r)
if err != nil {
return nil, fmt.Errorf("amf3 decode: unable to decode object reference and length: %s", err)
}
// if this is a object reference only, grab it and return it
if isRef {
objRefId := refVal >> 1
return d.objectRefs[objRefId], nil
}
// each type has traits that are cached, if the peer sent a reference
// then we'll need to look it up and use it.
var trait Trait
traitIsRef := (refVal & 0x01) == 0
if traitIsRef {
traitRef := refVal >> 1
trait = d.traitRefs[traitRef]
} else {
// build a new trait from what's left of the given u29
trait = *NewTrait()
trait.Externalizable = (refVal & 0x02) != 0
trait.Dynamic = (refVal & 0x04) != 0
var cls string
cls, err = d.DecodeAmf3String(r, false)
if err != nil {
return result, fmt.Errorf("amf3 decode: unable to read trait type for object: %s", err)
}
trait.Type = cls
// traits have property keys, encoded as amf3 strings
propLength := refVal >> 3
for i := uint32(0); i < propLength; i++ {
tmp, err := d.DecodeAmf3String(r, false)
if err != nil {
return result, fmt.Errorf("amf3 decode: unable to read trait property for object: %s", err)
}
trait.Properties = append(trait.Properties, tmp)
}
d.traitRefs = append(d.traitRefs, trait)
}
d.objectRefs = append(d.objectRefs, result)
// objects can be externalizable, meaning that the system has no concrete understanding of
// their properties or how they are encoded. in that case, we need to find and delegate behavior
// to the right object.
if trait.Externalizable {
switch trait.Type {
case "DSA": // AsyncMessageExt
result, err = d.decodeAsyncMessageExt(r)
if err != nil {
return result, fmt.Errorf("amf3 decode: unable to decode dsa: %s", err)
}
case "DSK": // AcknowledgeMessageExt
result, err = d.decodeAcknowledgeMessageExt(r)
if err != nil {
return result, fmt.Errorf("amf3 decode: unable to decode dsk: %s", err)
}
case "flex.messaging.io.ArrayCollection":
result, err = d.decodeArrayCollection(r)
if err != nil {
return result, fmt.Errorf("amf3 decode: unable to decode ac: %s", err)
}
// store an extra reference to array collection container
d.objectRefs = append(d.objectRefs, result)
default:
fn, ok := d.externalHandlers[trait.Type]
if ok {
result, err = fn(d, r)
if err != nil {
return result, fmt.Errorf("amf3 decode: unable to call external decoder for type %s: %s", trait.Type, err)
}
} else {
return result, fmt.Errorf("amf3 decode: unable to decode external type %s, no handler", trait.Type)
}
}
return result, err
}
var key string
var val interface{}
var obj Object
obj = make(Object)
// non-externalizable objects have property keys in traits, iterate through them
// and add the read values to the object
for _, key = range trait.Properties {
val, err = d.DecodeAmf3(r)
if err != nil {
return result, fmt.Errorf("amf3 decode: unable to decode object property: %s", err)
}
obj[key] = val
}
// if an object is dynamic, it can have extra key/value data at the end. in this case,
// read keys until we get an empty one.
if trait.Dynamic {
for {
key, err = d.DecodeAmf3String(r, false)
if err != nil {
return result, fmt.Errorf("amf3 decode: unable to decode dynamic key: %s", err)
}
if key == "" {
break
}
val, err = d.DecodeAmf3(r)
if err != nil {
return result, fmt.Errorf("amf3 decode: unable to decode dynamic value: %s", err)
}
obj[key] = val
}
}
result = obj
return
}
// marker: 1 byte 0x07 or 0x0b
// format:
// - u29 reference int. if reference, no more data. if not reference,
// length value of bytes to read to complete string.
func (d *Decoder) DecodeAmf3Xml(r io.Reader, decodeMarker bool) (result string, err error) {
if decodeMarker {
var marker byte
marker, err = ReadMarker(r)
if err != nil {
return "", err
}
if (marker != AMF3_XMLDOC_MARKER) && (marker != AMF3_XMLSTRING_MARKER) {
return "", fmt.Errorf("decode assert marker failed: expected %v or %v, got %v", AMF3_XMLDOC_MARKER, AMF3_XMLSTRING_MARKER, marker)
}
}
var isRef bool
var refVal uint32
isRef, refVal, err = d.decodeReferenceInt(r)
if err != nil {
return "", fmt.Errorf("amf3 decode: unable to decode xml reference and length: %s", err)
}
if isRef {
var ok bool
buf := d.objectRefs[refVal]
result, ok = buf.(string)
if ok != true {
return "", fmt.Errorf("amf3 decode: cannot coerce object reference into xml string")
}
return
}
buf := make([]byte, refVal)
_, err = r.Read(buf)
if err != nil {
return "", fmt.Errorf("amf3 decode: unable to read xml string: %s", err)
}
result = string(buf)
if result != "" {
d.objectRefs = append(d.objectRefs, result)
}
return
}
// marker: 1 byte 0x0c
// format:
// - u29 reference int. if reference, no more data. if not reference,
// length value of bytes to read.
func (d *Decoder) DecodeAmf3ByteArray(r io.Reader, decodeMarker bool) (result []byte, err error) {
if err = AssertMarker(r, decodeMarker, AMF3_BYTEARRAY_MARKER); err != nil {
return
}
var isRef bool
var refVal uint32
isRef, refVal, err = d.decodeReferenceInt(r)
if err != nil {
return result, fmt.Errorf("amf3 decode: unable to decode byte array reference and length: %s", err)
}
if isRef {
var ok bool
result, ok = d.objectRefs[refVal].([]byte)
if ok != true {
return result, fmt.Errorf("amf3 decode: unable to convert object ref to bytes")
}
return
}
result = make([]byte, refVal)
_, err = r.Read(result)
if err != nil {
return result, fmt.Errorf("amf3 decode: unable to read bytearray: %s", err)
}
d.objectRefs = append(d.objectRefs, result)
return
}
func (d *Decoder) decodeU29(r io.Reader) (result uint32, err error) {
var b byte
for i := 0; i < 3; i++ {
b, err = ReadByte(r)
if err != nil {
return
}
result = (result << 7) + uint32(b&0x7F)
if (b & 0x80) == 0 {
return
}
}
b, err = ReadByte(r)
if err != nil {
return
}
result = ((result << 8) + uint32(b))
return
}
func (d *Decoder) decodeReferenceInt(r io.Reader) (isRef bool, refVal uint32, err error) {
u29, err := d.decodeU29(r)
if err != nil {
return false, 0, fmt.Errorf("amf3 decode: unable to decode reference int: %s", err)
}
isRef = u29&0x01 == 0
refVal = u29 >> 1
return
}