shithub: rtmp

ref: 0ec0e4fde657c442431548180c91018078c2bf3c
dir: /rtmp.c/

View raw version
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <bio.h>
#include <libsec.h>
#include "amf.h"
#include "ivf.h"
#include "rtmp.h"

enum {
	Port = 1935,

	Sigsz = 1536,

	ChanCtl = 3,

	SzLarge,
	SzMedium,
	SzSmall,
	SzTiny,

	PktInvoke = 20,
};

typedef struct RTMPacket RTMPacket;

struct RTMP {
	int f;
	int invokes;
};

struct RTMPacket {
	int chan;
	int sztype;
	int pktype;
	u32int ts;
	u8int *data;
	int sz;
};

static int
handshake(int f)
{
	u8int cl[1+Sigsz], sv[1+Sigsz];

	cl[0] = 3; /* no encryption */
	memset(cl+1, 0, 8);
	prng(cl+1+8, Sigsz-8);
	if(write(f, cl, sizeof(cl)) != sizeof(cl))
		goto err;
	if(readn(f, sv, sizeof(sv)) != sizeof(sv))
		goto err;
	if(cl[0] != sv[0]){
		werrstr("expected %d (no encryption), got %d", cl[0], sv[0]);
		goto err;
	}
	if(write(f, sv+1, Sigsz) != Sigsz)
		goto err;
	if(readn(f, sv+1, Sigsz) != Sigsz)
		goto err;
	if(memcmp(cl, sv, sizeof(cl)) != 0){
		werrstr("signature mismatch");
		goto err;
	}

	return 0;

err:
	werrstr("handshake: %r");
	return -1;
}

static int
connect(int f, char *path)
{
	RTMPacket p;

	memset(&p, 0, sizeof(p));
	p.chan = ChanCtl;
	p.sztype = SzLarge;
	p.pktype = PktInvoke;

	return -1;
}

static int
rtmpsend(RTMP *r, RTMPacket *p)
{
	return -1;
}

RTMP *
rtmpdial(char *url)
{
	char *s, *e, *path;
	int f, port, ctl;
	RTMP *r;

	f = -1;
	if(memcmp(url, "rtmp://", 7) != 0){
		werrstr("invalid url");
		goto err;
	}
	s = url + 7;
	if((e = strpbrk(s, ":/")) == nil){
		werrstr("no path");
		goto err;
	}
	port = 1935;
	if(*e == ':'){
		if((port = strtol(e+1, &path, 10)) < 1 || path == e+1 || *path != '/'){
			werrstr("invalid port");
			goto err;
		}
	}else{
		path = e;
	}

	s = smprint("tcp!%.*s!%d", (int)(e-s), s, port);
	f = dial(s, nil, nil, &ctl);
	free(s);
	if(f < 0)
		goto err;

	if(handshake(f) != 0 || connect(f, path) == 0)
		goto err;

	if((r = calloc(1, sizeof(*r))) == nil)
		sysfatal("memory");
	r->f = f;

	return r;

err:
	werrstr("rtmpdial: %r");
	if(f >= 0)
		close(f);
	return nil;
}