Glimesh/rtmp-ingest

Handshake fails for certain RTMP clients

clone1018 opened this issue · 5 comments

Seems for some reason the handshake does not shake successfully with restream, so connecting does not work.

Server closed by error: Err = Random echo is not matched
github.com/yutopp/go-rtmp/handshake.HandshakeWithClient
	/root/go/pkg/mod/github.com/yutopp/go-rtmp@v0.0.1/handshake/handshake.go:102
github.com/yutopp/go-rtmp.(*serverConn).Serve
	/root/go/pkg/mod/github.com/yutopp/go-rtmp@v0.0.1/server_conn.go:28
github.com/yutopp/go-rtmp.(*Server).handleConn
	/root/go/pkg/mod/github.com/yutopp/go-rtmp@v0.0.1/server.go:115
runtime.goexit
	/usr/local/go/src/runtime/asm_amd64.s:1581

Failed to handshake
github.com/yutopp/go-rtmp.(*serverConn).Serve
	/root/go/pkg/mod/github.com/yutopp/go-rtmp@v0.0.1/server_conn.go:31
github.com/yutopp/go-rtmp.(*Server).handleConn
	/root/go/pkg/mod/github.com/yutopp/go-rtmp@v0.0.1/server.go:115
runtime.goexit
	/usr/local/go/src/runtime/asm_amd64.s:1581

The primary example of this is restream.io

Seems owncast had the same issue: owncast/owncast#34

Need to look into if they maintain a fork of the RTMP library we should be using instead!

Here's some quick code to do a basic RTMP handshake (and send an invalid one for testing):

package main

import (
	"bufio"
	"crypto/rand"
	"fmt"
	"io"
	"net"
)

func main() {
	token := make([]byte, 1536)
	rand.Read(token)

	wrongResponse := make([]byte, 1536)
	rand.Read(wrongResponse)

	conn, err := net.Dial("tcp", "localhost:1935")
	if err != nil {
		panic(err)
	}
	reader := bufio.NewReader(conn)

	// Write 0x03 and token
	conn.Write([]byte{0x03})
	conn.Write(token)

	// Check status response
	status := make([]byte, 1)
	_, err = reader.Read(status)
	if err != nil {
		panic(err)
	}
	fmt.Printf("First Res: %#v\n", status)

	// Generate handshake
	handshake := make([]byte, 1536)
	_, err = io.ReadFull(conn, handshake)
	if err != nil {
		panic(err)
	}
	conn.Write(handshake)
	// Uncomment this if you want the handshake to fail
	// conn.Write(wrongResponse)
	_, err = reader.Read(status)
	if err != nil {
		panic(err)
	}
	fmt.Printf("Second Res: %#v\n", status)
}

Forked go-rtmp so I could add in lal's handshake code. Seems to be working but will need to actually test.

That fixed it it seems, there were two issues:

  1. Digest handshake was not implemented. Glimesh/go-rtmp@a33e29d
  2. Publishing Type is sometimes missing from certain services, I made a patch to go-rtmp to default to live (it is a live streaming server after all). Glimesh/go-rtmp@4f0095b#diff-985ac45622f50b5032960af0abd0cca4e5b9bd93ee9b1d76c72093de0d0cd8b5R205-R207