/**
 * @file srtp/stream.c  Secure Real-time Transport Protocol (SRTP) -- stream
 *
 * Copyright (C) 2010 Creytiv.com
 */
#include <re_types.h>
#include <re_mem.h>
#include <re_mbuf.h>
#include <re_list.h>
#include <re_aes.h>
#include <re_srtp.h>
#include "srtp.h"


/** SRTP protocol values */
#ifndef SRTP_MAX_STREAMS
#define SRTP_MAX_STREAMS  (8)  /**< Maximum number of SRTP streams */
#endif


static void stream_destructor(void *arg)
{
	struct srtp_stream *strm = arg;

	list_unlink(&strm->le);
}


static struct srtp_stream *stream_find(struct srtp *srtp, uint32_t ssrc)
{
	struct le *le;

	for (le = srtp->streaml.head; le; le = le->next) {

		struct srtp_stream *strm = le->data;

		if (strm->ssrc == ssrc)
			return strm;
	}

	return NULL;
}


static int stream_new(struct srtp_stream **strmp, struct srtp *srtp,
		      uint32_t ssrc)
{
	struct srtp_stream *strm;

	if (list_count(&srtp->streaml) >= SRTP_MAX_STREAMS)
		return ENOSR;

	strm = mem_zalloc(sizeof(*strm), stream_destructor);
	if (!strm)
		return ENOMEM;

	strm->ssrc = ssrc;
	srtp_replay_init(&strm->replay_rtp);
	srtp_replay_init(&strm->replay_rtcp);

	list_append(&srtp->streaml, &strm->le, strm);

	if (strmp)
		*strmp = strm;

	return 0;
}


int stream_get(struct srtp_stream **strmp, struct srtp *srtp, uint32_t ssrc)
{
	struct srtp_stream *strm;

	if (!strmp || !srtp)
		return EINVAL;

	strm = stream_find(srtp, ssrc);
	if (strm) {
		*strmp = strm;
		return 0;
	}

	return stream_new(strmp, srtp, ssrc);
}


int stream_get_seq(struct srtp_stream **strmp, struct srtp *srtp,
		   uint32_t ssrc, uint16_t seq)
{
	struct srtp_stream *strm;
	int err;

	if (!strmp || !srtp)
		return EINVAL;

	err = stream_get(&strm, srtp, ssrc);
	if (err)
		return err;

	/* Set the initial sequence number once only */
	if (!strm->s_l_set) {
		strm->s_l = seq;
		strm->s_l_set = true;
	}

	*strmp = strm;

	return 0;
}
