mirror of https://bitbucket.org/ausocean/av.git
Merged in gardening/rtmp-safe-packets (pull request #59)
rtmp: make packet handling safer Approved-by: Alan Noble <anoble@gmail.com>
This commit is contained in:
commit
85b29ff9db
639
rtmp/amf.go
639
rtmp/amf.go
|
@ -33,15 +33,10 @@ LICENSE
|
||||||
*/
|
*/
|
||||||
package rtmp
|
package rtmp
|
||||||
|
|
||||||
/*
|
|
||||||
#include <stdlib.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"log"
|
"log"
|
||||||
"unsafe"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -56,242 +51,182 @@ const (
|
||||||
|
|
||||||
// unsigned short AMF_DecodeInt16(const char* data);
|
// unsigned short AMF_DecodeInt16(const char* data);
|
||||||
// amf.c +41
|
// amf.c +41
|
||||||
func C_AMF_DecodeInt16(data *byte) uint16 {
|
func C_AMF_DecodeInt16(data []byte) uint16 {
|
||||||
c := unsafe.Pointer(data)
|
return uint16(data[0])<<8 | uint16(data[1])
|
||||||
return uint16(*(*uint8)(c)<<8 | *(*byte)(incBytePtr(c, 1)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// unsigned int AMF_DecodeInt24(const char* data);
|
// unsigned int AMF_DecodeInt24(const char* data);
|
||||||
// amf.c +50
|
// amf.c +50
|
||||||
func C_AMF_DecodeInt24(data *byte) uint32 {
|
func C_AMF_DecodeInt24(data []byte) uint32 {
|
||||||
c := (*[3]byte)(unsafe.Pointer(data))
|
return uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2])
|
||||||
return (uint32(c[0]) << 16) | (uint32(c[1]) << 8) | uint32(c[2])
|
|
||||||
/*
|
|
||||||
// TODO Understand logic and simplify
|
|
||||||
c := (*uint8)(unsafe.Pointer(data))
|
|
||||||
dst := uint32(int32(*c) << 16)
|
|
||||||
dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) +
|
|
||||||
(uintptr)(int32(1))*unsafe.Sizeof(*c))))) << 8)
|
|
||||||
dst |= uint32(int32(*((*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) +
|
|
||||||
(uintptr)(int32(2))*unsafe.Sizeof(*c))))))
|
|
||||||
return dst
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// unsigned int AMF_DeocdeInt32(const char* data);
|
// unsigned int AMF_DeocdeInt32(const char* data);
|
||||||
// amf.c +59
|
// amf.c +59
|
||||||
func C_AMF_DecodeInt32(data *byte) uint32 {
|
func C_AMF_DecodeInt32(data []byte) uint32 {
|
||||||
c := (*uint8)(data)
|
return uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
|
||||||
val := uint32(
|
|
||||||
int32(*c)<<24 |
|
|
||||||
int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 1)))<<16 |
|
|
||||||
int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 2)))<<8 |
|
|
||||||
int32(*(*uint8)(incBytePtr(unsafe.Pointer(c), 3))))
|
|
||||||
return uint32(val)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// void AMF_DecodeString(const char* data, C_AVal* bv);
|
// void AMF_DecodeString(const char* data, C_AVal* bv);
|
||||||
// amf.c +68
|
// amf.c +68
|
||||||
func C_AMF_DecodeString(data *byte) string {
|
func C_AMF_DecodeString(data []byte) string {
|
||||||
n := C_AMF_DecodeInt16(data)
|
n := C_AMF_DecodeInt16(data)
|
||||||
if n == 0 {
|
return string(data[2 : 2+n])
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return string((*[_Gi]byte)(incBytePtr(unsafe.Pointer(data), 2))[:n])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// void AMF_DecodeLongString(const char *data, AVal *bv);
|
// void AMF_DecodeLongString(const char *data, AVal *bv);
|
||||||
// amf.c +75
|
// amf.c +75
|
||||||
func C_AMF_DecodeLongString(data *byte) string {
|
func C_AMF_DecodeLongString(data []byte) string {
|
||||||
n := C_AMF_DecodeInt32(data)
|
n := C_AMF_DecodeInt32(data)
|
||||||
if n == 0 {
|
return string(data[2 : 2+n])
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return string((*[_Gi]byte)(incBytePtr(unsafe.Pointer(data), 4))[:n])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// double AMF_DecodeNumber(const char* data);
|
// double AMF_DecodeNumber(const char* data);
|
||||||
// amf.c +82
|
// amf.c +82
|
||||||
func C_AMF_DecodeNumber(data *byte) float64 {
|
func C_AMF_DecodeNumber(data []byte) float64 {
|
||||||
var dVal float64
|
return math.Float64frombits(binary.BigEndian.Uint64(data))
|
||||||
var ci, co *uint8
|
|
||||||
ci = (*uint8)(unsafe.Pointer(data))
|
|
||||||
co = (*uint8)(unsafe.Pointer(&dVal))
|
|
||||||
for i := 0; i < 8; i++ {
|
|
||||||
(*[_Gi]byte)(unsafe.Pointer(co))[i] = (*[_Gi]byte)(unsafe.Pointer(ci))[7-i]
|
|
||||||
}
|
|
||||||
return dVal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// int AMF_DecodeBoolean(const char *data);
|
// int AMF_DecodeBoolean(const char *data);
|
||||||
// amf.c +132
|
// amf.c +132
|
||||||
func C_AMF_DecodeBoolean(data *byte) bool {
|
func C_AMF_DecodeBoolean(data []byte) bool {
|
||||||
return *data != 0
|
return data[0] != 0
|
||||||
}
|
|
||||||
|
|
||||||
// char* AMF_EncodeInt16(char* output, char* outend, short nVal);
|
|
||||||
// amf.c +138
|
|
||||||
func C_AMF_EncodeInt16(output *byte, outend *byte, nVal int16) *byte {
|
|
||||||
outputPtr := unsafe.Pointer(output)
|
|
||||||
outendPtr := unsafe.Pointer(outend)
|
|
||||||
if uintptr(outputPtr)+2 > uintptr(outendPtr) {
|
|
||||||
// length < 2
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// Assign output[1]
|
|
||||||
second := (*byte)(incBytePtr(outputPtr, 1))
|
|
||||||
*second = (byte)(nVal & 0xff)
|
|
||||||
// Assign output[0]
|
|
||||||
*output = (byte)(nVal >> 8)
|
|
||||||
return (*byte)(incBytePtr(outputPtr, 2))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// char* AMF_EncodeInt24(char* output, char* outend, int nVal);
|
// char* AMF_EncodeInt24(char* output, char* outend, int nVal);
|
||||||
// amf.c +149
|
// amf.c +149
|
||||||
func C_AMF_EncodeInt24(output *byte, outend *byte, nVal int32) *byte {
|
func C_AMF_EncodeInt24(dst []byte, val int32) []byte {
|
||||||
outputPtr := unsafe.Pointer(output)
|
if len(dst) < 3 {
|
||||||
outendPtr := unsafe.Pointer(outend)
|
|
||||||
if uintptr(outputPtr)+3 > uintptr(outendPtr) {
|
|
||||||
// length < 3
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Assign output[2]
|
_ = dst[2]
|
||||||
third := (*byte)(incBytePtr(outputPtr, 2))
|
dst[0] = byte(val >> 16)
|
||||||
*third = (byte)(nVal & 0xff)
|
dst[1] = byte(val >> 8)
|
||||||
// Assign output[1]
|
dst[2] = byte(val)
|
||||||
second := (*byte)(incBytePtr(outputPtr, 1))
|
if len(dst) == 3 {
|
||||||
*second = (byte)(nVal >> 8)
|
return nil
|
||||||
// Assign output[0]
|
}
|
||||||
*output = (byte)(nVal >> 16)
|
return dst[3:]
|
||||||
return (*byte)(incBytePtr(outputPtr, 3))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// char* AMF_EncodeInt32(char* output, char* outend, int nVal);
|
// char* AMF_EncodeInt32(char* output, char* outend, int nVal);
|
||||||
// amf.c +161
|
// amf.c +160
|
||||||
func C_AMF_EncodeInt32(output *byte, outend *byte, nVal int32) *byte {
|
func C_AMF_EncodeInt32(dst []byte, val int32) []byte {
|
||||||
outputPtr := unsafe.Pointer(output)
|
if len(dst) < 4 {
|
||||||
outendPtr := unsafe.Pointer(outend)
|
|
||||||
if uintptr(outputPtr)+4 > uintptr(outendPtr) {
|
|
||||||
// length < 4
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Assign output[3]
|
binary.BigEndian.PutUint32(dst, uint32(val))
|
||||||
forth := (*byte)(incBytePtr(outputPtr, 3))
|
if len(dst) == 4 {
|
||||||
*forth = (byte)(nVal & 0xff)
|
return nil
|
||||||
// Assign output[2]
|
}
|
||||||
third := (*byte)(incBytePtr(outputPtr, 2))
|
return dst[4:]
|
||||||
*third = (byte)(nVal >> 8)
|
|
||||||
// Assign output[1]
|
|
||||||
second := (*byte)(incBytePtr(outputPtr, 1))
|
|
||||||
*second = (byte)(nVal >> 16)
|
|
||||||
// Assign output[0]
|
|
||||||
*output = (byte)(nVal >> 24)
|
|
||||||
return (*byte)(incBytePtr(outputPtr, 4))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// char* AMF_EncodeString(char* output, char* outend, const C_AVal* bv);
|
// char* AMF_EncodeString(char* output, char* outend, const C_AVal* bv);
|
||||||
// amf.c +174
|
// amf.c +173
|
||||||
func C_AMF_EncodeString(output *byte, outend *byte, s string) *byte {
|
func C_AMF_EncodeString(dst []byte, val string) []byte {
|
||||||
buflen := int(uintptr(unsafe.Pointer(outend)) - uintptr(unsafe.Pointer(output)))
|
const typeSize = 1
|
||||||
if len(s) < 65536 && 1+2+len(s) > buflen {
|
if len(val) < 65536 && len(val)+typeSize+binary.Size(int16(0)) > len(dst) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if 1+4+len(s) > buflen {
|
if len(val)+typeSize+binary.Size(int32(0)) > len(dst) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
outputPtr := unsafe.Pointer(output)
|
|
||||||
dst := (*[_Gi]byte)(unsafe.Pointer(output))[:buflen]
|
if len(val) < 65536 {
|
||||||
if len(s) < 65536 {
|
|
||||||
dst[0] = AMF_STRING
|
dst[0] = AMF_STRING
|
||||||
binary.BigEndian.PutUint16(dst[1:3], uint16(len(s)))
|
dst = dst[1:]
|
||||||
copy(dst[3:], s)
|
binary.BigEndian.PutUint16(dst[:2], uint16(len(val)))
|
||||||
outputPtr = incBytePtr(outputPtr, 3+len(s))
|
dst = dst[2:]
|
||||||
} else {
|
copy(dst, val)
|
||||||
dst[0] = AMF_LONG_STRING
|
if len(dst) == len(val) {
|
||||||
binary.BigEndian.PutUint32(dst[1:5], uint32(len(s)))
|
return nil
|
||||||
copy(dst[5:], s)
|
}
|
||||||
outputPtr = incBytePtr(outputPtr, 5+len(s))
|
return dst[len(val):]
|
||||||
}
|
}
|
||||||
return (*byte)(outputPtr)
|
dst[0] = AMF_LONG_STRING
|
||||||
|
dst = dst[1:]
|
||||||
|
binary.BigEndian.PutUint32(dst[:4], uint32(len(val)))
|
||||||
|
dst = dst[4:]
|
||||||
|
copy(dst, val)
|
||||||
|
if len(dst) == len(val) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return dst[len(val):]
|
||||||
}
|
}
|
||||||
|
|
||||||
// char* AMF_EncodeNumber(char* output, char* outend, double dVal);
|
// char* AMF_EncodeNumber(char* output, char* outend, double dVal);
|
||||||
// amf.c +199
|
// amf.c +199
|
||||||
func C_AMF_EncodeNumber(output *byte, outend *byte, dVal float64) *byte {
|
func C_AMF_EncodeNumber(dst []byte, val float64) []byte {
|
||||||
if int(uintptr(unsafe.Pointer(output)))+1+8 > int(uintptr(unsafe.Pointer(outend))) {
|
if len(dst) < 9 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// TODO: port this
|
dst[0] = AMF_NUMBER
|
||||||
*(*byte)(unsafe.Pointer(output)) = AMF_NUMBER
|
dst = dst[1:]
|
||||||
output = (*byte)(incBytePtr(unsafe.Pointer(output), 1))
|
binary.BigEndian.PutUint64(dst, math.Float64bits(val))
|
||||||
// NOTE: here we are assuming little endian for both byte order and float
|
return dst[8:]
|
||||||
// word order
|
|
||||||
var ci, co *uint8
|
|
||||||
ci = (*uint8)(unsafe.Pointer(&dVal))
|
|
||||||
co = (*uint8)(unsafe.Pointer(output))
|
|
||||||
for i := 0; i < 8; i++ {
|
|
||||||
(*[_Gi]byte)(unsafe.Pointer(co))[i] = (*[_Gi]byte)(unsafe.Pointer(ci))[7-i]
|
|
||||||
}
|
|
||||||
return (*byte)(incBytePtr(unsafe.Pointer(output), 8))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// char* AMF_EncodeBoolean(char* output, char* outend, int bVal);
|
// char* AMF_EncodeBoolean(char* output, char* outend, int bVal);
|
||||||
// amf.c +260
|
// amf.c +260
|
||||||
func C_AMF_EncodeBoolean(output *byte, outend *byte, bVal bool) *byte {
|
func C_AMF_EncodeBoolean(dst []byte, val bool) []byte {
|
||||||
if int(uintptr(unsafe.Pointer(output)))+2 > int(uintptr(unsafe.Pointer(outend))) {
|
if len(dst) < 2 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
*(*byte)(unsafe.Pointer(output)) = AMF_BOOLEAN
|
dst[0] = AMF_BOOLEAN
|
||||||
output = (*byte)(incBytePtr(unsafe.Pointer(output), 1))
|
if val {
|
||||||
var val byte
|
dst[1] = 1
|
||||||
if bVal {
|
|
||||||
val = 1
|
|
||||||
}
|
}
|
||||||
*(*byte)(unsafe.Pointer(output)) = val
|
if len(dst) == 2 {
|
||||||
output = (*byte)(incBytePtr(unsafe.Pointer(output), 1))
|
return nil
|
||||||
return output
|
}
|
||||||
|
return dst[2:]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// char* AMF_EncodeNamedString(char* output, char* outend, const C_AVal* strName, const C_AVal* strValue);
|
// char* AMF_EncodeNamedString(char* output, char* outend, const C_AVal* strName, const C_AVal* strValue);
|
||||||
// amf.c +273
|
// amf.c +273
|
||||||
func C_AMF_EncodeNamedString(output *byte, outend *byte, key, val string) *byte {
|
func C_AMF_EncodeNamedString(dst []byte, key, val string) []byte {
|
||||||
buflen := int(uintptr(unsafe.Pointer(outend)) - uintptr(unsafe.Pointer(output)))
|
if 2+len(key) > len(dst) {
|
||||||
if 2+len(key) > buflen {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
dst := (*[_Gi]byte)(unsafe.Pointer(output))[:buflen]
|
|
||||||
binary.BigEndian.PutUint16(dst[:2], uint16(len(key)))
|
binary.BigEndian.PutUint16(dst[:2], uint16(len(key)))
|
||||||
copy(dst[2:], key)
|
dst = dst[2:]
|
||||||
output = (*byte)(incBytePtr(unsafe.Pointer(output), 2+len(key)))
|
copy(dst, key)
|
||||||
return C_AMF_EncodeString(output, outend, val)
|
if len(key) == len(dst) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return C_AMF_EncodeString(dst[len(key):], val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// char* AMF_EncodeNamedNumber(char* output, char* outend, const C_AVal* strName, double dVal);
|
// char* AMF_EncodeNamedNumber(char* output, char* outend, const C_AVal* strName, double dVal);
|
||||||
// amf.c +286
|
// amf.c +286
|
||||||
func C_AMF_EncodeNamedNumber(output *byte, outend *byte, key string, val float64) *byte {
|
func C_AMF_EncodeNamedNumber(dst []byte, key string, val float64) []byte {
|
||||||
buflen := int(uintptr(unsafe.Pointer(outend)) - uintptr(unsafe.Pointer(output)))
|
if 2+len(key) > len(dst) {
|
||||||
if 2+len(key) > buflen {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
dst := (*[_Gi]byte)(unsafe.Pointer(output))[:buflen]
|
|
||||||
binary.BigEndian.PutUint16(dst[:2], uint16(len(key)))
|
binary.BigEndian.PutUint16(dst[:2], uint16(len(key)))
|
||||||
copy(dst[2:], key)
|
dst = dst[2:]
|
||||||
output = (*byte)(incBytePtr(unsafe.Pointer(output), 2+len(key)))
|
copy(dst, key)
|
||||||
return C_AMF_EncodeNumber(output, outend, val)
|
if len(key) == len(dst) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return C_AMF_EncodeNumber(dst[len(key):], val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// char* AMF_EncodeNamedBoolean(char* output, char* outend, const C_AVal* strname, int bVal);
|
// char* AMF_EncodeNamedBoolean(char* output, char* outend, const C_AVal* strname, int bVal);
|
||||||
// amf.c +299
|
// amf.c +299
|
||||||
func C_AMF_EncodeNamedBoolean(output *byte, outend *byte, key string, val bool) *byte {
|
func C_AMF_EncodeNamedBoolean(dst []byte, key string, val bool) []byte {
|
||||||
buflen := int(uintptr(unsafe.Pointer(outend)) - uintptr(unsafe.Pointer(output)))
|
if 2+len(key) > len(dst) {
|
||||||
if 2+len(key) > buflen {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
dst := (*[_Gi]byte)(unsafe.Pointer(output))[:buflen]
|
|
||||||
binary.BigEndian.PutUint16(dst[:2], uint16(len(key)))
|
binary.BigEndian.PutUint16(dst[:2], uint16(len(key)))
|
||||||
copy(dst[2:], key)
|
dst = dst[2:]
|
||||||
output = (*byte)(incBytePtr(unsafe.Pointer(output), 2+len(key)))
|
copy(dst, key)
|
||||||
return C_AMF_EncodeBoolean(output, outend, val)
|
if len(key) == len(dst) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return C_AMF_EncodeBoolean(dst[len(key):], val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// void AMFProp_SetName(AMFObjectProperty *prop, AVal *name);
|
// void AMFProp_SetName(AMFObjectProperty *prop, AVal *name);
|
||||||
|
@ -303,7 +238,7 @@ func C_AMFProp_SetName(prop *C_AMFObjectProperty, name string) {
|
||||||
// double AMFProp_GetNumber(AMFObjectProperty* prop);
|
// double AMFProp_GetNumber(AMFObjectProperty* prop);
|
||||||
// amf.c +330
|
// amf.c +330
|
||||||
func C_AMFProp_GetNumber(prop *C_AMFObjectProperty) float64 {
|
func C_AMFProp_GetNumber(prop *C_AMFObjectProperty) float64 {
|
||||||
return float64(prop.p_vu.p_number)
|
return prop.p_vu.p_number
|
||||||
}
|
}
|
||||||
|
|
||||||
// void AMFProp_GetString(AMFObjectProperty* prop, AVal* str);
|
// void AMFProp_GetString(AMFObjectProperty* prop, AVal* str);
|
||||||
|
@ -327,140 +262,61 @@ func C_AMFProp_GetObject(prop *C_AMFObjectProperty, obj *C_AMFObject) {
|
||||||
|
|
||||||
// char* AMFPropEncode(AMFOBjectProperty* prop, char* pBufer, char* pBufEnd);
|
// char* AMFPropEncode(AMFOBjectProperty* prop, char* pBufer, char* pBufEnd);
|
||||||
// amf.c +366
|
// amf.c +366
|
||||||
func C_AMF_PropEncode(p *C_AMFObjectProperty, pBuffer *byte, pBufEnd *byte) *byte {
|
func C_AMF_PropEncode(p *C_AMFObjectProperty, dst []byte) []byte {
|
||||||
if p.p_type == AMF_INVALID {
|
if p.p_type == AMF_INVALID {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
buflen := int(uintptr(unsafe.Pointer(pBufEnd)) - uintptr(unsafe.Pointer(pBuffer)))
|
if p.p_type != AMF_NULL && len(p.p_name)+2+1 >= len(dst) {
|
||||||
if p.p_type != AMF_NULL && len(p.p_name)+2+1 >= buflen {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.p_type != AMF_NULL && len(p.p_name) != 0 {
|
if p.p_type != AMF_NULL && len(p.p_name) != 0 {
|
||||||
(*[_Gi]byte)(unsafe.Pointer(pBuffer))[0] = byte(len(p.p_name) >> 8)
|
binary.BigEndian.PutUint16(dst[:2], uint16(len(p.p_name)))
|
||||||
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
dst = dst[2:]
|
||||||
(*[_Gi]byte)(unsafe.Pointer(pBuffer))[0] = byte(len(p.p_name) & 0xff)
|
copy(dst, p.p_name)
|
||||||
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
dst = dst[len(p.p_name):]
|
||||||
copy((*[_Gi]byte)(unsafe.Pointer(pBuffer))[:], p.p_name)
|
|
||||||
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), len(p.p_name)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch p.p_type {
|
switch p.p_type {
|
||||||
case AMF_NUMBER:
|
case AMF_NUMBER:
|
||||||
pBuffer = C_AMF_EncodeNumber(pBuffer, pBufEnd, float64(p.p_vu.p_number))
|
dst = C_AMF_EncodeNumber(dst, p.p_vu.p_number)
|
||||||
case AMF_BOOLEAN:
|
case AMF_BOOLEAN:
|
||||||
pBuffer = C_AMF_EncodeBoolean(pBuffer, pBufEnd, p.p_vu.p_number != 0)
|
dst = C_AMF_EncodeBoolean(dst, p.p_vu.p_number != 0)
|
||||||
case AMF_STRING:
|
case AMF_STRING:
|
||||||
pBuffer = C_AMF_EncodeString(pBuffer, pBufEnd, p.p_vu.p_aval)
|
dst = C_AMF_EncodeString(dst, p.p_vu.p_aval)
|
||||||
case AMF_NULL:
|
case AMF_NULL:
|
||||||
buflen = int(uintptr(unsafe.Pointer(pBufEnd)) - uintptr(unsafe.Pointer(pBuffer)))
|
if len(dst) < 2 {
|
||||||
if 1 >= buflen {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
*(*byte)(unsafe.Pointer(pBuffer)) = AMF_NULL
|
dst[0] = AMF_NULL
|
||||||
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
dst = dst[1:]
|
||||||
case AMF_OBJECT:
|
case AMF_OBJECT:
|
||||||
pBuffer = C_AMF_Encode(&p.p_vu.p_object, pBuffer, pBufEnd)
|
dst = C_AMF_Encode(&p.p_vu.p_object, dst)
|
||||||
//pBuffer = (*byte)(unsafe.Pointer(C.AMF_Encode(&p.p_vu.p_object, (*byte)(
|
|
||||||
//unsafe.Pointer(pBuffer)), (*byte)(unsafe.Pointer(pBufEnd)))))
|
|
||||||
case AMF_ECMA_ARRAY:
|
case AMF_ECMA_ARRAY:
|
||||||
pBuffer = C_AMF_EncodeEcmaArray(&p.p_vu.p_object, pBuffer, pBufEnd)
|
dst = C_AMF_EncodeEcmaArray(&p.p_vu.p_object, dst)
|
||||||
//pBuffer = (*byte)(unsafe.Pointer(C.AMF_EncodeEcmaArray(&p.p_vu.p_object, (*byte)(unsafe.Pointer(pBuffer)), (*byte)(unsafe.Pointer(pBufEnd)))))
|
|
||||||
case AMF_STRICT_ARRAY:
|
case AMF_STRICT_ARRAY:
|
||||||
//pBuffer = (*byte)(unsafe.Pointer(C.AMF_EncodeArray(&p.p_vu.p_object, (*byte)(unsafe.Pointer(pBuffer)), (*byte)(unsafe.Pointer(pBufEnd)))))
|
dst = C_AMF_EncodeArray(&p.p_vu.p_object, dst)
|
||||||
pBuffer = C_AMF_EncodeArray(&p.p_vu.p_object, pBuffer, pBufEnd)
|
|
||||||
default:
|
default:
|
||||||
log.Println("C_AMF_PropEncode: invalid type!")
|
log.Println("C_AMF_PropEncode: invalid type!")
|
||||||
pBuffer = nil
|
dst = nil
|
||||||
}
|
}
|
||||||
return pBuffer
|
return dst
|
||||||
}
|
|
||||||
|
|
||||||
// int AMF3ReadInteger(const char *data, int32_t *valp);
|
|
||||||
// amf.c +426
|
|
||||||
// TODO test
|
|
||||||
func C_AMF3ReadInteger(data *byte, valp *int32) int32 {
|
|
||||||
var i int
|
|
||||||
var val int32
|
|
||||||
|
|
||||||
for i <= 2 {
|
|
||||||
/* handle first 3 bytes */
|
|
||||||
if (*[_Gi]byte)(unsafe.Pointer(data))[i]&0x80 != 0 {
|
|
||||||
/* byte used */
|
|
||||||
val <<= 7 /* shift up */
|
|
||||||
val |= int32((*[_Gi]byte)(unsafe.Pointer(data))[i] & 0x7f) /* add bits */
|
|
||||||
i++
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if i > 2 {
|
|
||||||
/* use 4th byte, all 8bits */
|
|
||||||
val <<= 8
|
|
||||||
val |= int32((*[_Gi]byte)(unsafe.Pointer(data))[3])
|
|
||||||
|
|
||||||
/* range check */
|
|
||||||
if val > AMF3_INTEGER_MAX {
|
|
||||||
val -= (1 << 29)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* use 7bits of last unparsed byte (0xxxxxxx) */
|
|
||||||
val <<= 7
|
|
||||||
val |= int32((*[_Gi]byte)(unsafe.Pointer(data))[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
*valp = val
|
|
||||||
|
|
||||||
if i > 2 {
|
|
||||||
return 4
|
|
||||||
}
|
|
||||||
return int32(i + 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// int AMF3ReadString(const char *data, AVal *str);
|
|
||||||
// amf.c +466
|
|
||||||
func C_AMF3ReadString(data *byte, str *string) int32 {
|
|
||||||
var ref int32
|
|
||||||
// assert elided - we will get a panic if it's nil.
|
|
||||||
|
|
||||||
len := C_AMF3ReadInteger(data, &ref)
|
|
||||||
data = (*byte)(sliceToPtr((*[_Gi]byte)(unsafe.Pointer(data))[len:]))
|
|
||||||
|
|
||||||
if ref&0x1 == 0 {
|
|
||||||
/* reference: 0xxx */
|
|
||||||
// TODO(kortschak) Logging.
|
|
||||||
// refIndex := (ref >> 1)
|
|
||||||
// RTMP_Log(RTMP_LOGDEBUG,
|
|
||||||
// "%s, string reference, index: %d, not supported, ignoring!",
|
|
||||||
// __FUNCTION__, refIndex);
|
|
||||||
*str = ""
|
|
||||||
return len
|
|
||||||
} else {
|
|
||||||
nSize := (ref >> 1)
|
|
||||||
*str = string((*[_Gi]byte)(unsafe.Pointer(data))[:nSize])
|
|
||||||
return len + nSize
|
|
||||||
}
|
|
||||||
return len
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// int AMFProp_Decode(C_AMFObjectProperty* prop, const char* pBuffer, int nSize, int bDecodeName);
|
// int AMFProp_Decode(C_AMFObjectProperty* prop, const char* pBuffer, int nSize, int bDecodeName);
|
||||||
// amf.c +619
|
// amf.c +619
|
||||||
func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeName int32) int32 {
|
func C_AMFProp_Decode(prop *C_AMFObjectProperty, data []byte, bDecodeName int32) int32 {
|
||||||
|
|
||||||
var nOriginalSize int32 = nSize
|
|
||||||
var nRes int32
|
|
||||||
|
|
||||||
prop.p_name = ""
|
prop.p_name = ""
|
||||||
|
|
||||||
if nSize == 0 || pBuffer == nil {
|
nOriginalSize := len(data)
|
||||||
|
if len(data) == 0 {
|
||||||
// TODO use new logger here
|
// TODO use new logger here
|
||||||
// RTMP_Log(RTMP_LOGDEBUG, "%s: Empty buffer/no buffer pointer!", __FUNCTION__);
|
// RTMP_Log(RTMP_LOGDEBUG, "%s: Empty buffer/no buffer pointer!", __FUNCTION__);
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
if bDecodeName != 0 && nSize < 4 {
|
if bDecodeName != 0 && len(data) < 4 {
|
||||||
// at least name (length + at least 1 byte) and 1 byte of data
|
// at least name (length + at least 1 byte) and 1 byte of data
|
||||||
// TODO use new logger here
|
// TODO use new logger here
|
||||||
// RTMP_Log(RTMP_LOGDEBUG, "%s: Not enough data for decoding with name, less than 4 bytes!",__FUNCTION__);
|
// RTMP_Log(RTMP_LOGDEBUG, "%s: Not enough data for decoding with name, less than 4 bytes!",__FUNCTION__);
|
||||||
|
@ -468,53 +324,50 @@ func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeNa
|
||||||
}
|
}
|
||||||
|
|
||||||
if bDecodeName != 0 {
|
if bDecodeName != 0 {
|
||||||
nNameSize := C_AMF_DecodeInt16(pBuffer)
|
nNameSize := C_AMF_DecodeInt16(data[:2])
|
||||||
if int32(nNameSize) > nSize-2 {
|
if int(nNameSize) > len(data)-2 {
|
||||||
// TODO use new logger here
|
// TODO use new logger here
|
||||||
//RTMP_Log(RTMP_LOGDEBUG, "%s: Name size out of range: namesize (%d) > len (%d) - 2",__FUNCTION__, nNameSize, nSize);
|
//RTMP_Log(RTMP_LOGDEBUG, "%s: Name size out of range: namesize (%d) > len (%d) - 2",__FUNCTION__, nNameSize, nSize);
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
prop.p_name = C_AMF_DecodeString(pBuffer)
|
prop.p_name = C_AMF_DecodeString(data)
|
||||||
nSize -= int32(2 + nNameSize)
|
data = data[2+nNameSize:]
|
||||||
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(2+nNameSize)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if nSize == 0 {
|
if len(data) == 0 {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
nSize--
|
prop.p_type = C_AMFDataType(data[0])
|
||||||
|
data = data[1:]
|
||||||
prop.p_type = (C_AMFDataType)(int32(*pBuffer))
|
|
||||||
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
|
||||||
|
|
||||||
|
var nRes int32
|
||||||
switch prop.p_type {
|
switch prop.p_type {
|
||||||
case AMF_NUMBER:
|
case AMF_NUMBER:
|
||||||
if nSize < 8 {
|
if len(data) < 8 {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
prop.p_vu.p_number = float64(C_AMF_DecodeNumber(pBuffer))
|
prop.p_vu.p_number = C_AMF_DecodeNumber(data[:8])
|
||||||
nSize -= 8
|
data = data[8:]
|
||||||
|
|
||||||
case AMF_BOOLEAN:
|
case AMF_BOOLEAN:
|
||||||
panic("AMF_BOOLEAN not supported")
|
panic("AMF_BOOLEAN not supported")
|
||||||
|
|
||||||
case AMF_STRING:
|
case AMF_STRING:
|
||||||
var nStringSize = C_AMF_DecodeInt16(pBuffer)
|
nStringSize := C_AMF_DecodeInt16(data[:2])
|
||||||
|
if len(data) < int(nStringSize+2) {
|
||||||
if int64(nSize) < int64(nStringSize)+2 {
|
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
prop.p_vu.p_aval = C_AMF_DecodeString(pBuffer)
|
prop.p_vu.p_aval = C_AMF_DecodeString(data)
|
||||||
nSize -= int32(2 + nStringSize)
|
data = data[2+nStringSize:]
|
||||||
|
|
||||||
case AMF_OBJECT:
|
case AMF_OBJECT:
|
||||||
var nRes int32 = int32(C_AMF_Decode(&prop.p_vu.p_object, pBuffer, nSize, 1))
|
nRes := C_AMF_Decode(&prop.p_vu.p_object, data, 1)
|
||||||
if nRes == -1 {
|
if nRes == -1 {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
nSize -= nRes
|
data = data[nRes:]
|
||||||
|
|
||||||
case AMF_MOVIECLIP:
|
case AMF_MOVIECLIP:
|
||||||
// TODO use new logger here
|
// TODO use new logger here
|
||||||
|
@ -526,26 +379,21 @@ func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeNa
|
||||||
prop.p_type = AMF_NULL
|
prop.p_type = AMF_NULL
|
||||||
|
|
||||||
case AMF_REFERENCE:
|
case AMF_REFERENCE:
|
||||||
|
|
||||||
// TODO use new logger here
|
// TODO use new logger here
|
||||||
log.Println("AMFProp_Decode: AMF_REFERENCE not supported!")
|
log.Println("AMFProp_Decode: AMF_REFERENCE not supported!")
|
||||||
//RTMP_Log(RTMP_LOGERROR, "AMF_REFERENCE not supported!");
|
//RTMP_Log(RTMP_LOGERROR, "AMF_REFERENCE not supported!");
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
case AMF_ECMA_ARRAY:
|
case AMF_ECMA_ARRAY:
|
||||||
|
|
||||||
nSize -= 4
|
|
||||||
|
|
||||||
// next comes the rest, mixed array has a final 0x000009 mark and names, so its an object
|
// next comes the rest, mixed array has a final 0x000009 mark and names, so its an object
|
||||||
nRes = C_AMF_Decode(&prop.p_vu.p_object, (*byte)(incBytePtr(
|
data = data[4:]
|
||||||
unsafe.Pointer(pBuffer), 4)), nSize, 1)
|
nRes = C_AMF_Decode(&prop.p_vu.p_object, data, 1)
|
||||||
if nRes == -1 {
|
if nRes == -1 {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
nSize -= nRes
|
data = data[nRes:]
|
||||||
|
|
||||||
case AMF_OBJECT_END:
|
case AMF_OBJECT_END:
|
||||||
|
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
case AMF_STRICT_ARRAY:
|
case AMF_STRICT_ARRAY:
|
||||||
|
@ -564,7 +412,6 @@ func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeNa
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
case AMF_TYPED_OBJECT:
|
case AMF_TYPED_OBJECT:
|
||||||
|
|
||||||
// TODO use new logger here
|
// TODO use new logger here
|
||||||
// RTMP_Log(RTMP_LOGERROR, "AMF_TYPED_OBJECT not supported!")
|
// RTMP_Log(RTMP_LOGERROR, "AMF_TYPED_OBJECT not supported!")
|
||||||
return -1
|
return -1
|
||||||
|
@ -579,7 +426,7 @@ func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeNa
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
return nOriginalSize - nSize
|
return int32(nOriginalSize - len(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
// void AMFProp_Reset(AMFObjectProperty* prop);
|
// void AMFProp_Reset(AMFObjectProperty* prop);
|
||||||
|
@ -596,225 +443,127 @@ func C_AMFProp_Reset(prop *C_AMFObjectProperty) {
|
||||||
|
|
||||||
// char* AMF_Encode(AMFObject* obj, char* pBuffer, char* pBufEnd);
|
// char* AMF_Encode(AMFObject* obj, char* pBuffer, char* pBufEnd);
|
||||||
// amf.c +891
|
// amf.c +891
|
||||||
func C_AMF_Encode(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte {
|
func C_AMF_Encode(obj *C_AMFObject, dst []byte) []byte {
|
||||||
if uintptr(unsafe.Pointer(pBuffer))+uintptr(4) >= uintptr(unsafe.Pointer(pBufEnd)) {
|
if len(dst) < 5 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
*pBuffer = AMF_OBJECT
|
dst[0] = AMF_OBJECT
|
||||||
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
dst = dst[1:]
|
||||||
|
|
||||||
for i := 0; i < int(obj.o_num); i++ {
|
for i := 0; i < len(obj.o_props); i++ {
|
||||||
res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer(
|
dst = C_AMF_PropEncode(&obj.o_props[i], dst)
|
||||||
obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd)
|
if dst == nil {
|
||||||
if res == nil {
|
|
||||||
log.Println("C_AMF_Encode: failed to encode property in index")
|
log.Println("C_AMF_Encode: failed to encode property in index")
|
||||||
break
|
break
|
||||||
} else {
|
|
||||||
pBuffer = res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if uintptr(incBytePtr(unsafe.Pointer(pBuffer), 3)) >= uintptr(unsafe.Pointer(pBufEnd)) {
|
if len(dst) < 4 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
return C_AMF_EncodeInt24(dst, AMF_OBJECT_END)
|
||||||
pBuffer = C_AMF_EncodeInt24(pBuffer, pBufEnd, int32(AMF_OBJECT_END))
|
|
||||||
|
|
||||||
return pBuffer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// char* AMF_EncodeEcmaArray(AMFObject* obj, char* pBuffer, char* pBufEnd);
|
// char* AMF_EncodeEcmaArray(AMFObject* obj, char* pBuffer, char* pBufEnd);
|
||||||
// amf.c +924
|
// amf.c +924
|
||||||
func C_AMF_EncodeEcmaArray(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte {
|
func C_AMF_EncodeEcmaArray(obj *C_AMFObject, dst []byte) []byte {
|
||||||
if int(uintptr(unsafe.Pointer(pBuffer)))+4 >= int(uintptr(unsafe.Pointer(pBufEnd))) {
|
if len(dst) < 5 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
*pBuffer = AMF_ECMA_ARRAY
|
dst[0] = AMF_ECMA_ARRAY
|
||||||
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
dst = dst[1:]
|
||||||
|
binary.BigEndian.PutUint32(dst[:4], uint32(len(obj.o_props)))
|
||||||
|
dst = dst[4:]
|
||||||
|
|
||||||
pBuffer = C_AMF_EncodeInt32(pBuffer, pBufEnd, int32(obj.o_num))
|
for i := 0; i < len(obj.o_props); i++ {
|
||||||
|
dst = C_AMF_PropEncode(&obj.o_props[i], dst)
|
||||||
for i := 0; i < int(obj.o_num); i++ {
|
if dst == nil {
|
||||||
res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer(
|
|
||||||
obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd)
|
|
||||||
if res == nil {
|
|
||||||
log.Println("C_AMF_EncodeEcmaArray: failed to encode property!")
|
log.Println("C_AMF_EncodeEcmaArray: failed to encode property!")
|
||||||
break
|
break
|
||||||
} else {
|
|
||||||
pBuffer = res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if int(uintptr(unsafe.Pointer(pBuffer)))+3 >= int(uintptr(unsafe.Pointer(pBufEnd))) {
|
if len(dst) < 4 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
return C_AMF_EncodeInt24(dst, AMF_OBJECT_END)
|
||||||
pBuffer = C_AMF_EncodeInt24(pBuffer, pBufEnd, AMF_OBJECT_END)
|
|
||||||
|
|
||||||
return pBuffer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// char* AMF_EncodeArray(AMFObject* obj, char* pBuffer, char* pBufEnd);
|
// char* AMF_EncodeArray(AMFObject* obj, char* pBuffer, char* pBufEnd);
|
||||||
// amf.c +959
|
// amf.c +959
|
||||||
func C_AMF_EncodeArray(obj *C_AMFObject, pBuffer *byte, pBufEnd *byte) *byte {
|
func C_AMF_EncodeArray(obj *C_AMFObject, dst []byte) []byte {
|
||||||
if int(uintptr(unsafe.Pointer(pBuffer)))+4 >= int(uintptr(unsafe.Pointer(pBufEnd))) {
|
if len(dst) < 5 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
*pBuffer = AMF_STRICT_ARRAY
|
dst[0] = AMF_STRICT_ARRAY
|
||||||
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
dst = dst[1:]
|
||||||
|
binary.BigEndian.PutUint32(dst[:4], uint32(len(obj.o_props)))
|
||||||
|
dst = dst[4:]
|
||||||
|
|
||||||
pBuffer = C_AMF_EncodeInt32(pBuffer, pBufEnd, int32(obj.o_num))
|
for i := 0; i < len(obj.o_props); i++ {
|
||||||
|
dst = C_AMF_PropEncode(&obj.o_props[i], dst)
|
||||||
for i := 0; i < int(obj.o_num); i++ {
|
if dst == nil {
|
||||||
res := C_AMF_PropEncode((*C_AMFObjectProperty)(incPtr(unsafe.Pointer(
|
log.Println("C_AMF_EncodeArray: failed to encode property!")
|
||||||
obj.o_props), i, int(unsafe.Sizeof(*obj.o_props)))), pBuffer, pBufEnd)
|
|
||||||
if res == nil {
|
|
||||||
log.Println("C_AMF_EncodeEcmaArray: failed to encode property!")
|
|
||||||
break
|
break
|
||||||
} else {
|
|
||||||
pBuffer = res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pBuffer
|
return dst
|
||||||
}
|
|
||||||
|
|
||||||
// int AMF_DecodeArray(AMFObject *obj, const char *pBuffer, int nSize, int nArrayLen, int bDecodeName);
|
|
||||||
// amf.c +993
|
|
||||||
func C_AMF_DecodeArray(obj *C_AMFObject, pBuffer *byte, nSize, nArrayLen, bDecodeName int32) int32 {
|
|
||||||
nOriginalSize := nSize
|
|
||||||
var bError int32 = 0
|
|
||||||
|
|
||||||
obj.o_num = 0
|
|
||||||
obj.o_props = nil
|
|
||||||
for nArrayLen > 0 {
|
|
||||||
var prop C_AMFObjectProperty
|
|
||||||
var nRes int32
|
|
||||||
nArrayLen--
|
|
||||||
|
|
||||||
if nSize <= 0 {
|
|
||||||
bError = 1
|
|
||||||
break
|
|
||||||
}
|
|
||||||
nRes = C_AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName)
|
|
||||||
if nRes == -1 {
|
|
||||||
bError = 1
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
nSize -= nRes
|
|
||||||
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(nRes)))
|
|
||||||
C_AMF_AddProp(obj, &prop)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if bError != 0 {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
return nOriginalSize - nSize
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// int AMF_Decode(AMFObject *obj, const char* pBuffer, int nSize, int bDecodeName);
|
// int AMF_Decode(AMFObject *obj, const char* pBuffer, int nSize, int bDecodeName);
|
||||||
// amf.c +1180
|
// amf.c +1180
|
||||||
func C_AMF_Decode(obj *C_AMFObject, pBuffer *byte, nSize int32, bDecodeName int32) int32 {
|
func C_AMF_Decode(obj *C_AMFObject, data []byte, bDecodeName int32) int32 {
|
||||||
var nOriginalSize int32 = nSize
|
nOriginalSize := len(data)
|
||||||
var bError int32 = 0
|
|
||||||
|
|
||||||
obj.o_num = 0
|
obj.o_props = obj.o_props[:0]
|
||||||
obj.o_props = nil
|
for len(data) != 0 {
|
||||||
|
if len(data) >= 3 && C_AMF_DecodeInt24(data[:3]) == AMF_OBJECT_END {
|
||||||
for nSize > 0 {
|
data = data[3:]
|
||||||
var prop C_AMFObjectProperty
|
|
||||||
var nRes int32
|
|
||||||
|
|
||||||
if nSize >= 3 && C_AMF_DecodeInt24(pBuffer) == AMF_OBJECT_END {
|
|
||||||
nSize -= 3
|
|
||||||
bError = 0
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if bError != 0 {
|
var prop C_AMFObjectProperty
|
||||||
// TODO use new logger here
|
nRes := C_AMFProp_Decode(&prop, data, bDecodeName)
|
||||||
log.Println("AMF_Decode: decoding error, ignoring bytes until next known pattern!")
|
|
||||||
nSize--
|
|
||||||
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// TODO port AMFProp_Decode
|
|
||||||
nRes = int32(C_AMFProp_Decode(&prop, (*byte)(unsafe.Pointer(pBuffer)),
|
|
||||||
int32(nSize), int32(bDecodeName)))
|
|
||||||
// nRes = int32(C.AMFProp_Decode(&prop, (*byte)(unsafe.Pointer(pBuffer)),
|
// nRes = int32(C.AMFProp_Decode(&prop, (*byte)(unsafe.Pointer(pBuffer)),
|
||||||
// int32(nSize), int32(bDecodeName)))
|
// int32(nSize), int32(bDecodeName)))
|
||||||
if nRes == -1 {
|
if nRes == -1 {
|
||||||
bError = 1
|
return -1
|
||||||
break
|
|
||||||
} else {
|
|
||||||
nSize -= nRes
|
|
||||||
if nSize < 0 {
|
|
||||||
bError = 1
|
|
||||||
break
|
|
||||||
}
|
|
||||||
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(nRes)))
|
|
||||||
C_AMF_AddProp(obj, &prop)
|
|
||||||
}
|
}
|
||||||
|
data = data[nRes:]
|
||||||
|
obj.o_props = append(obj.o_props, prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
if bError != 0 {
|
return int32(nOriginalSize - len(data))
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
return nOriginalSize - nSize
|
|
||||||
}
|
|
||||||
|
|
||||||
// void AMF_AddProp(AMFObject* obj, const AMFObjectProperty* prop);
|
|
||||||
// amf.c + 1234
|
|
||||||
func C_AMF_AddProp(obj *C_AMFObject, prop *C_AMFObjectProperty) {
|
|
||||||
if (obj.o_num & 0x0f) == 0 {
|
|
||||||
//obj.o_props = (*C_AMFObjectProperty)(realloc(unsafe.Pointer(obj.o_props),
|
|
||||||
//uint32(int(obj.o_num+16)*int(unsafe.Sizeof(*obj.o_props)))))
|
|
||||||
obj.o_props = (*C_AMFObjectProperty)(C.realloc(unsafe.Pointer(obj.o_props),
|
|
||||||
C.size_t(int(obj.o_num+16)*int(unsafe.Sizeof(*obj.o_props)))))
|
|
||||||
}
|
|
||||||
memmove(unsafe.Pointer(&(*(*C_AMFObjectProperty)(incPtr(
|
|
||||||
unsafe.Pointer(obj.o_props), int(obj.o_num), int(unsafe.Sizeof(*obj.o_props)))))),
|
|
||||||
unsafe.Pointer(prop), unsafe.Sizeof(*obj.o_props))
|
|
||||||
obj.o_num++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFObjectProperty* AMF_GetProp(AMFObject *obj, const AVal* name, int nIndex);
|
// AMFObjectProperty* AMF_GetProp(AMFObject *obj, const AVal* name, int nIndex);
|
||||||
// amf.c + 1249
|
// amf.c + 1249
|
||||||
func C_AMF_GetProp(obj *C_AMFObject, name string, nIndex int32) *C_AMFObjectProperty {
|
func C_AMF_GetProp(obj *C_AMFObject, name string, idx int32) *C_AMFObjectProperty {
|
||||||
if nIndex >= 0 {
|
if idx >= 0 {
|
||||||
if nIndex < int32(obj.o_num) {
|
if idx < int32(len(obj.o_props)) {
|
||||||
return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props),
|
return &obj.o_props[idx]
|
||||||
int(nIndex), int(unsafe.Sizeof(*obj.o_props)))))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for n := int32(0); n < obj.o_num; n++ {
|
for i, p := range obj.o_props {
|
||||||
p_name := (*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props),
|
if p.p_name == name {
|
||||||
int(n), int(unsafe.Sizeof(*obj.o_props))))).p_name
|
return &obj.o_props[i]
|
||||||
if p_name == name {
|
|
||||||
return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props),
|
|
||||||
int(n), int(unsafe.Sizeof(*obj.o_props)))))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (*C_AMFObjectProperty)(&AMFProp_Invalid)
|
return &AMFProp_Invalid
|
||||||
}
|
}
|
||||||
|
|
||||||
// void AMF_Reset(AMFObject* obj);
|
// void AMF_Reset(AMFObject* obj);
|
||||||
// amf.c +1282
|
// amf.c +1282
|
||||||
func C_AMF_Reset(obj *C_AMFObject) {
|
func C_AMF_Reset(obj *C_AMFObject) {
|
||||||
var n int32
|
for i := range obj.o_props {
|
||||||
for n = 0; n < int32(obj.o_num); n++ {
|
C_AMFProp_Reset(&obj.o_props[i])
|
||||||
C_AMFProp_Reset(&(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props),
|
|
||||||
int(n), int(unsafe.Sizeof(*obj.o_props))))))
|
|
||||||
}
|
}
|
||||||
//C.free(unsafe.Pointer(obj.o_props))
|
obj.o_props = obj.o_props[:0]
|
||||||
obj.o_props = nil
|
|
||||||
obj.o_num = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -60,8 +60,7 @@ type C_AMFDataType int32
|
||||||
// typedef struct AMF_Object
|
// typedef struct AMF_Object
|
||||||
// amf.h +67
|
// amf.h +67
|
||||||
type C_AMFObject struct {
|
type C_AMFObject struct {
|
||||||
o_num int32
|
o_props []C_AMFObjectProperty
|
||||||
o_props *C_AMFObjectProperty
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// typedef struct P_vu
|
// typedef struct P_vu
|
||||||
|
|
1389
rtmp/rtmp.go
1389
rtmp/rtmp.go
File diff suppressed because it is too large
Load Diff
|
@ -31,6 +31,8 @@ LICENSE
|
||||||
*/
|
*/
|
||||||
package rtmp
|
package rtmp
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
RTMPT_OPEN = iota
|
RTMPT_OPEN = iota
|
||||||
RTMPT_SEND
|
RTMPT_SEND
|
||||||
|
@ -114,8 +116,7 @@ const (
|
||||||
// rtmp.h +105
|
// rtmp.h +105
|
||||||
type C_RTMPChunk struct {
|
type C_RTMPChunk struct {
|
||||||
c_headerSize int32
|
c_headerSize int32
|
||||||
c_chunkSize int32
|
c_chunk []byte
|
||||||
c_chunk *byte
|
|
||||||
c_header [RTMP_MAX_HEADER_SIZE]byte
|
c_header [RTMP_MAX_HEADER_SIZE]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,24 +125,25 @@ type C_RTMPChunk struct {
|
||||||
type C_RTMPPacket struct {
|
type C_RTMPPacket struct {
|
||||||
m_headerType uint8
|
m_headerType uint8
|
||||||
m_packetType uint8
|
m_packetType uint8
|
||||||
m_hasAbsTimestamp uint8
|
m_hasAbsTimestamp bool
|
||||||
m_nChannel int32
|
m_nChannel int32
|
||||||
m_nTimeStamp uint32
|
m_nTimeStamp uint32
|
||||||
m_nInfoField2 int32
|
m_nInfoField2 int32
|
||||||
m_nBodySize uint32
|
m_nBodySize uint32
|
||||||
m_nBytesRead uint32
|
m_nBytesRead uint32
|
||||||
m_chunk *C_RTMPChunk
|
m_chunk *C_RTMPChunk
|
||||||
m_body *byte
|
m_header []byte
|
||||||
|
m_body []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// typedef struct RTMPSockBuf
|
// typedef struct RTMPSockBuf
|
||||||
// rtmp.h +127
|
// rtmp.h +127
|
||||||
type C_RTMPSockBuf struct {
|
type C_RTMPSockBuf struct {
|
||||||
sb_socket int32
|
conn *net.TCPConn
|
||||||
sb_size int32
|
sb_size int
|
||||||
sb_start *byte
|
sb_start int
|
||||||
sb_buf [RTMP_BUFFER_CACHE_SIZE]byte // port const
|
sb_buf [RTMP_BUFFER_CACHE_SIZE]byte // port const
|
||||||
sb_timedout int32
|
sb_timedout bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// RTMPPacket_IsReady(a)
|
// RTMPPacket_IsReady(a)
|
||||||
|
@ -174,18 +176,6 @@ type C_RTMP_LNK struct {
|
||||||
port uint16
|
port uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
// typedef struct RTMP_READ
|
|
||||||
// rtmp.h +200
|
|
||||||
type C_RTMP_READ struct {
|
|
||||||
buf *byte
|
|
||||||
dataType uint8
|
|
||||||
flags uint8
|
|
||||||
status int8
|
|
||||||
nResumeTS uint32
|
|
||||||
nIgnoredFrameCounter uint32
|
|
||||||
nIgnoredFlvFrameCounter uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// typedef struct RTMPMethod
|
// typedef struct RTMPMethod
|
||||||
// rtmp.h +231
|
// rtmp.h +231
|
||||||
type C_RTMP_METHOD struct {
|
type C_RTMP_METHOD struct {
|
||||||
|
@ -209,16 +199,15 @@ type C_RTMP struct {
|
||||||
m_nClientBW int32
|
m_nClientBW int32
|
||||||
m_nClientBW2 uint8
|
m_nClientBW2 uint8
|
||||||
m_bPlaying bool
|
m_bPlaying bool
|
||||||
m_bSendEncoding uint8
|
m_bSendEncoding bool
|
||||||
m_bSendCounter uint8
|
m_bSendCounter bool
|
||||||
m_numInvokes int32
|
m_numInvokes int32
|
||||||
m_numCalls int32
|
m_methodCalls []C_RTMP_METHOD
|
||||||
m_methodCalls *C_RTMP_METHOD
|
|
||||||
m_channelsAllocatedIn int32
|
m_channelsAllocatedIn int32
|
||||||
m_channelsAllocatedOut int32
|
m_channelsAllocatedOut int32
|
||||||
m_vecChannelsIn **C_RTMPPacket
|
m_vecChannelsIn []*C_RTMPPacket
|
||||||
m_vecChannelsOut **C_RTMPPacket
|
m_vecChannelsOut []*C_RTMPPacket
|
||||||
m_channelTimestamp *int32
|
m_channelTimestamp []int32
|
||||||
m_fAudioCodecs float64
|
m_fAudioCodecs float64
|
||||||
m_fVideoCodecs float64
|
m_fVideoCodecs float64
|
||||||
m_fEncoding float64
|
m_fEncoding float64
|
||||||
|
@ -226,7 +215,6 @@ type C_RTMP struct {
|
||||||
m_msgCounter int32
|
m_msgCounter int32
|
||||||
m_resplen int32
|
m_resplen int32
|
||||||
m_unackd int32
|
m_unackd int32
|
||||||
m_read C_RTMP_READ
|
|
||||||
m_write C_RTMPPacket
|
m_write C_RTMPPacket
|
||||||
m_sb C_RTMPSockBuf
|
m_sb C_RTMPSockBuf
|
||||||
Link C_RTMP_LNK
|
Link C_RTMP_LNK
|
||||||
|
|
|
@ -1,193 +0,0 @@
|
||||||
/*
|
|
||||||
NAME
|
|
||||||
rtmp_test.go
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
See Readme.md
|
|
||||||
|
|
||||||
AUTHOR
|
|
||||||
Saxon Nelson-Milton <saxon@ausocean.org>
|
|
||||||
|
|
||||||
LICENSE
|
|
||||||
rtmp_test.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean)
|
|
||||||
|
|
||||||
It is free software: you can redistribute it and/or modify them
|
|
||||||
under the terms of the GNU General Public License as published by the
|
|
||||||
Free Software Foundation, either version 3 of the License, or (at your
|
|
||||||
option) any later version.
|
|
||||||
|
|
||||||
It is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with revid in gpl.txt. If not, see http://www.gnu.org/licenses.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package rtmp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
arrStart = 0
|
|
||||||
arrEnd = 5
|
|
||||||
arrSize = 6
|
|
||||||
inc = 3
|
|
||||||
dec = 3
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
byteSize = 1
|
|
||||||
int32Size = 4
|
|
||||||
int64Size = 8
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
byteArr = [arrSize]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}
|
|
||||||
int32Arr = [arrSize]int32{1, 2, 3, 4, 5, 6}
|
|
||||||
int64Arr = [arrSize]int64{1, 2, 3, 4, 5, 6}
|
|
||||||
errMsg = "Obtained: %v, but wanted: %v"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO: write test for realloc
|
|
||||||
// TODO: write test for memmove
|
|
||||||
// TODO: write test for allocate
|
|
||||||
|
|
||||||
func TestMemcmp(t *testing.T) {
|
|
||||||
slice1 := []byte("ABCDEFG")
|
|
||||||
slice2 := []byte("ABCDEFG")
|
|
||||||
slice3 := []byte("ABCDJFG")
|
|
||||||
|
|
||||||
if memcmp(unsafe.Pointer(&slice1[0]), unsafe.Pointer(&slice2[0]), 7) != 0 {
|
|
||||||
t.Errorf("Should have got 0!")
|
|
||||||
}
|
|
||||||
|
|
||||||
if memcmp(unsafe.Pointer(&slice1[0]), unsafe.Pointer(&slice3[0]), 7) == 0 {
|
|
||||||
t.Errorf("Should not have got 0!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMemset(t *testing.T) {
|
|
||||||
size := 10
|
|
||||||
setNum := 5
|
|
||||||
testVal := byte('A')
|
|
||||||
mem := malloc(uintptr(size))
|
|
||||||
memset((*byte)(mem), testVal, setNum)
|
|
||||||
for i := 0; i < size; i++ {
|
|
||||||
if i > setNum-1 {
|
|
||||||
testVal = byte(0)
|
|
||||||
}
|
|
||||||
if (*[_Gi]byte)(mem)[i] != testVal {
|
|
||||||
t.Errorf("mem doesn't match expected values at: %v", i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGoStrToCStr(t *testing.T) {
|
|
||||||
goStr := "string\000"
|
|
||||||
bStr := goStrToCStr(goStr)
|
|
||||||
|
|
||||||
testData := []byte{'s', 't', 'r', 'i', 'n', 'g', '\000'}
|
|
||||||
|
|
||||||
for i := 0; i < len(goStr); i++ {
|
|
||||||
val := (*[_Gi]byte)(unsafe.Pointer(bStr))[i]
|
|
||||||
testVal := testData[i]
|
|
||||||
if val != testVal {
|
|
||||||
t.Errorf("Wanted: %v, but got: %v", testVal, val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStrdup(t *testing.T) {
|
|
||||||
goStr := "string\000"
|
|
||||||
bStr := goStrToCStr(goStr)
|
|
||||||
|
|
||||||
testData := []byte{'s', 't', 'r', 'i', 'n', 'g', '\000'}
|
|
||||||
|
|
||||||
newStr := strdup(bStr)
|
|
||||||
|
|
||||||
for i := 0; i < len(goStr); i++ {
|
|
||||||
val := (*[_Gi]byte)(unsafe.Pointer(newStr))[i]
|
|
||||||
testVal := testData[i]
|
|
||||||
if val != testVal {
|
|
||||||
t.Errorf("Wanted: %v, but got: %v", testVal, val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStrlen(t *testing.T) {
|
|
||||||
goStr := "string\000"
|
|
||||||
bStr := goStrToCStr(goStr)
|
|
||||||
eLength := 6
|
|
||||||
oLength := strlen(bStr)
|
|
||||||
if oLength != int32(eLength) {
|
|
||||||
t.Errorf("Wanted: %v, but got: %v", eLength, oLength)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStrchr(t *testing.T) {
|
|
||||||
goStr := "string\000"
|
|
||||||
bStr := goStrToCStr(goStr)
|
|
||||||
// First try to find something that is in the string
|
|
||||||
ePtr := uintptr(incBytePtr(unsafe.Pointer(bStr), 2))
|
|
||||||
obtainedPtr := uintptr(unsafe.Pointer(strchr(bStr, 'r')))
|
|
||||||
if ePtr != obtainedPtr {
|
|
||||||
t.Errorf("wanted: %v, but got: %v", ePtr, obtainedPtr)
|
|
||||||
}
|
|
||||||
// Now try something that isn't actually in the string
|
|
||||||
obtainedPtr2 := strchr(bStr, 'k')
|
|
||||||
ePtr2 := (*byte)(nil)
|
|
||||||
if ePtr2 != obtainedPtr2 {
|
|
||||||
t.Errorf("wanted: %v, but got: %v", ePtr, obtainedPtr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIncPtr(t *testing.T) {
|
|
||||||
// Test how it deals with bytes
|
|
||||||
bytePtr := unsafe.Pointer(&byteArr[arrStart])
|
|
||||||
valueByte := *(*byte)(incPtr(bytePtr, inc, byteSize))
|
|
||||||
if valueByte != byteArr[inc] {
|
|
||||||
t.Errorf(errMsg, valueByte, byteArr[inc])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test how it deals with int32s
|
|
||||||
int32Ptr := unsafe.Pointer(&int32Arr[arrStart])
|
|
||||||
valueInt32 := *(*int32)(incPtr(int32Ptr, inc, int32Size))
|
|
||||||
if valueInt32 != int32Arr[inc] {
|
|
||||||
t.Errorf(errMsg, valueInt32, int32Arr[inc])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test how it deals with int64
|
|
||||||
int64Ptr := unsafe.Pointer(&int64Arr[arrStart])
|
|
||||||
valueInt64 := *(*int64)(incPtr(int64Ptr, inc, int64Size))
|
|
||||||
if valueInt64 != int64Arr[inc] {
|
|
||||||
t.Errorf(errMsg, valueInt64, int64Arr[inc])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecPtr(t *testing.T) {
|
|
||||||
// Test how it deals with bytes
|
|
||||||
bytePtr := unsafe.Pointer(&byteArr[arrEnd])
|
|
||||||
valueByte := *(*byte)(decPtr(bytePtr, dec, byteSize))
|
|
||||||
if valueByte != byteArr[arrEnd-dec] {
|
|
||||||
t.Errorf(errMsg, valueByte, byteArr[inc])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test how it deals with ints
|
|
||||||
int32Ptr := unsafe.Pointer(&int32Arr[arrEnd])
|
|
||||||
valueInt32 := *(*int32)(decPtr(int32Ptr, dec, int32Size))
|
|
||||||
if valueInt32 != int32Arr[arrEnd-inc] {
|
|
||||||
t.Errorf(errMsg, valueInt32, int32Arr[inc])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test how it deals with int64
|
|
||||||
int64Ptr := unsafe.Pointer(&int64Arr[arrEnd])
|
|
||||||
valueInt64 := *(*int64)(decPtr(int64Ptr, dec, int64Size))
|
|
||||||
if valueInt64 != int64Arr[arrEnd-dec] {
|
|
||||||
t.Errorf(errMsg, valueInt64, int64Arr[inc])
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
NAME
|
||||||
|
rtmp.go
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
See Readme.md
|
||||||
|
|
||||||
|
AUTHORS
|
||||||
|
Saxon Nelson-Milton <saxon@ausocean.org>
|
||||||
|
Dan Kortschak <dan@ausocean.org>
|
||||||
|
|
||||||
|
LICENSE
|
||||||
|
rtmp.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean)
|
||||||
|
|
||||||
|
It is free software: you can redistribute it and/or modify them
|
||||||
|
under the terms of the GNU General Public License as published by the
|
||||||
|
Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with revid in gpl.txt. If not, see http://www.gnu.org/licenses.
|
||||||
|
|
||||||
|
Derived from librtmp under the GNU Lesser General Public License 2.1
|
||||||
|
Copyright (C) 2005-2008 Team XBMC http://www.xbmc.org
|
||||||
|
Copyright (C) 2008-2009 Andrej Stepanchuk
|
||||||
|
Copyright (C) 2009-2010 Howard Chu
|
||||||
|
*/
|
||||||
|
|
||||||
|
package rtmp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// int RTMP_Connect(RTMP *r, RTMPPacket* cp);
|
||||||
|
// rtmp.c +1032
|
||||||
|
func C_RTMP_Connect(r *C_RTMP, cp *C_RTMPPacket) (ok bool) {
|
||||||
|
if r.Link.hostname == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var hostname string
|
||||||
|
if r.Link.socksport != 0 {
|
||||||
|
hostname = fmt.Sprintf("%s:%d", r.Link.sockshost, r.Link.socksport)
|
||||||
|
} else {
|
||||||
|
hostname = fmt.Sprintf("%s:%d", r.Link.hostname, r.Link.port)
|
||||||
|
}
|
||||||
|
addr, err := net.ResolveTCPAddr("tcp4", hostname)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
r.m_sb.conn, err = net.DialTCP("tcp4", nil, addr)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if r.Link.socksport != 0 {
|
||||||
|
if !C_SocksNegotiate(r, addr) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := r.m_sb.conn.File()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed to get fd to set timeout: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
tv := setTimeval(int(r.Link.timeout))
|
||||||
|
err = unix.SetsockoptTimeval(int(f.Fd()), unix.SOL_SOCKET, unix.SO_RCVTIMEO, &tv)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed to set timeout: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.m_bSendCounter = true
|
||||||
|
|
||||||
|
return C_RTMP_Connect1(r, cp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// int SocksNegotiate(RTMP* r);
|
||||||
|
// rtmp.c +1062
|
||||||
|
func C_SocksNegotiate(r *C_RTMP, addr *net.TCPAddr) (ok bool) {
|
||||||
|
ip := addr.IP.To4()
|
||||||
|
packet := []byte{
|
||||||
|
0x4, // SOCKS version
|
||||||
|
0x1, // Establish a TCP/IP stream connection
|
||||||
|
byte(r.Link.port >> 8), byte(r.Link.port),
|
||||||
|
ip[0], ip[1], ip[2], ip[3],
|
||||||
|
0x0, // Empty user ID string
|
||||||
|
}
|
||||||
|
|
||||||
|
C_WriteN(r, packet)
|
||||||
|
|
||||||
|
if C_ReadN(r, packet[:8]) != 8 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if packet[0] == 0x0 && packet[1] == 0x5a {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// TODO: use new logger here
|
||||||
|
log.Println("C_SocksNegotitate: SOCKS returned error code!")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// int RTMPSockBuf_Fill(RTMPSockBuf* sb);
|
||||||
|
// rtmp.c +4253
|
||||||
|
func C_RTMPSockBuf_Fill(sb *C_RTMPSockBuf) int {
|
||||||
|
if sb.sb_size == 0 {
|
||||||
|
sb.sb_start = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := sb.conn.Read(sb.sb_buf[sb.sb_start+sb.sb_size:])
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
sb.sb_size += n
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// int RTMPSockBuf_Send(RTMPSockBuf* sb, const char* buf, int len);
|
||||||
|
// rtmp.c +4297
|
||||||
|
// TODO replace send with golang net connection send
|
||||||
|
func C_RTMPSockBuf_Send(sb *C_RTMPSockBuf, buf []byte) int32 {
|
||||||
|
n, err := sb.conn.Write(buf)
|
||||||
|
if err != nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return int32(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// int
|
||||||
|
// RTMPSockBuf_Close(RTMPSockBuf *sb)
|
||||||
|
// rtmp.c +4369
|
||||||
|
func C_RTMPSockBuf_Close(sb *C_RTMPSockBuf) int32 {
|
||||||
|
if sb.conn != nil {
|
||||||
|
err := sb.conn.Close()
|
||||||
|
sb.conn = nil
|
||||||
|
if err == nil {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package rtmp
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
func setTimeval(sec int) unix.Timeval {
|
||||||
|
return unix.Timeval{Sec: int64(sec)}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package rtmp
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
func setTimeval(sec int) unix.Timeval {
|
||||||
|
return unix.Timeval{Sec: int32(sec)}
|
||||||
|
}
|
Loading…
Reference in New Issue