Esempio n. 1
0
File: sdes.c Progetto: soramimi/qSIP
/**
 * Decode SDES items from a buffer
 *
 * @param mb   Buffer to decode from
 * @param sdes RTCP SDES to decode into
 *
 * @return 0 if success, otherwise errorcode
 */
int rtcp_sdes_decode(struct mbuf *mb, struct rtcp_sdes *sdes)
{
	size_t start;

	if (!sdes)
		return EINVAL;
	if (mbuf_get_left(mb) < RTCP_SRC_SIZE)
		return EBADMSG;

	start = mb->pos;
	sdes->src = ntohl(mbuf_read_u32(mb));

	/* Decode all SDES items */
	while (mbuf_get_left(mb) >= RTCP_SDES_MIN_SIZE) {
		uint8_t type;
		struct rtcp_sdes_item *item;

		type = mbuf_read_u8(mb);
		if (type == RTCP_SDES_END)
			break;

		if (mbuf_get_left(mb) < 1)
			return EBADMSG;

		if (!sdes->itemv) {
			sdes->itemv = mem_alloc(sizeof(*sdes->itemv), NULL);
			if (!sdes->itemv)
				return ENOMEM;
		}
		else {
			const size_t sz = (sdes->n + 1) * sizeof(*sdes->itemv);
			struct rtcp_sdes_item *itemv;

			itemv = mem_realloc(sdes->itemv, sz);
			if (!itemv)
				return ENOMEM;

			sdes->itemv = itemv;
		}

		item = &sdes->itemv[sdes->n];

		item->type = (enum rtcp_sdes_type)type;
		item->length = mbuf_read_u8(mb);
		if (mbuf_get_left(mb) < item->length)
			return EBADMSG;
		item->data = mem_alloc(item->length, NULL);
		if (!item->data)
			return ENOMEM;
		(void)mbuf_read_mem(mb, (uint8_t *)item->data, item->length);

		sdes->n++;
	}

	/* slurp padding */
	while ((mb->pos - start) & 0x3 && mbuf_get_left(mb))
		++mb->pos;

	return 0;
}
Esempio n. 2
0
/**
 * Duplicate a null-terminated string from a memory buffer
 *
 * @param mb   Memory buffer
 * @param strp Pointer to destination string; allocated and set
 * @param len  Length of string
 *
 * @return 0 if success, otherwise errorcode
 */
int mbuf_strdup(struct mbuf *mb, char **strp, size_t len)
{
	char *str;
	int err;

	if (!mb || !strp)
		return EINVAL;

	str = mem_alloc(len + 1, NULL);
	if (!str)
		return ENOMEM;

	err = mbuf_read_mem(mb, (uint8_t *)str, len);
	if (err)
		goto out;

	str[len] = '\0';

 out:
	if (err)
		mem_deref(str);
	else
		*strp = str;

	return err;
}
Esempio n. 3
0
File: rtp.c Progetto: hbowden/re
/**
 * Decode an RTP header from a buffer
 *
 * @param hdr RTP Header to decode into
 * @param mb  Buffer to decode from
 *
 * @return 0 if success, otherwise errorcode
 */
int rtp_hdr_decode(struct rtp_header *hdr, struct mbuf *mb)
{
	uint8_t buf[2];
	int err, i;
	size_t header_len;

	if (!hdr || !mb)
		return EINVAL;

	if (mbuf_get_left(mb) < RTP_HEADER_SIZE)
		return EBADMSG;

	err = mbuf_read_mem(mb, buf, sizeof(buf));
	if (err)
		return err;

	hdr->ver  = (buf[0] >> 6) & 0x03;
	hdr->pad  = (buf[0] >> 5) & 0x01;
	hdr->ext  = (buf[0] >> 4) & 0x01;
	hdr->cc   = (buf[0] >> 0) & 0x0f;
	hdr->m    = (buf[1] >> 7) & 0x01;
	hdr->pt   = (buf[1] >> 0) & 0x7f;

	hdr->seq  = ntohs(mbuf_read_u16(mb));
	hdr->ts   = ntohl(mbuf_read_u32(mb));
	hdr->ssrc = ntohl(mbuf_read_u32(mb));

	header_len = hdr->cc*sizeof(uint32_t);
	if (mbuf_get_left(mb) < header_len)
		return EBADMSG;

	for (i=0; i<hdr->cc; i++) {
		hdr->csrc[i] = ntohl(mbuf_read_u32(mb));
	}

	if (hdr->ext) {
		if (mbuf_get_left(mb) < 4)
			return EBADMSG;

		hdr->x.type = ntohs(mbuf_read_u16(mb));
		hdr->x.len  = ntohs(mbuf_read_u16(mb));

		if (mbuf_get_left(mb) < hdr->x.len*sizeof(uint32_t))
			return EBADMSG;

		mb->pos += hdr->x.len*sizeof(uint32_t);
	}

	return 0;
}
Esempio n. 4
0
/**
 * NOTE: DSP cannot be destroyed inside handler
 */
static bool write_handler(uint8_t *buf, size_t sz, void *arg)
{
	struct play *play = arg;

	lock_write_get(play->lock);

	if (play->eof)
		goto silence;

	if (mbuf_get_left(play->mb) < sz) {
		play->eof = true;
	}
	else {
		(void)mbuf_read_mem(play->mb, buf, sz);
	}

 silence:
	if (play->eof)
		memset(buf, 0, sz);

	lock_rel(play->lock);

	return true;
}
Esempio n. 5
0
int stun_hdr_decode(struct mbuf *mb, struct stun_hdr *hdr)
{
	if (!mb || !hdr)
		return EINVAL;

	if (mbuf_get_left(mb) < STUN_HEADER_SIZE)
		return EBADMSG;

	hdr->type = ntohs(mbuf_read_u16(mb));
	if (hdr->type & 0xc000)
		return EBADMSG;

	hdr->len = ntohs(mbuf_read_u16(mb));
	if (hdr->len & 0x3)
		return EBADMSG;

	hdr->cookie = ntohl(mbuf_read_u32(mb));
	(void)mbuf_read_mem(mb, hdr->tid, sizeof(hdr->tid));

	if (mbuf_get_left(mb) < hdr->len)
		return EBADMSG;

	return 0;
}
Esempio n. 6
0
/**
 * Read a 64-bit value from a memory buffer
 *
 * @param mb Memory buffer
 *
 * @return 64-bit value
 */
uint64_t mbuf_read_u64(struct mbuf *mb)
{
	uint64_t v;

	return (0 == mbuf_read_mem(mb, (uint8_t *)&v, sizeof(v))) ? v : 0;
}
Esempio n. 7
0
/**
 * Read an 8-bit value from a memory buffer
 *
 * @param mb Memory buffer
 *
 * @return 8-bit value
 */
uint8_t mbuf_read_u8(struct mbuf *mb)
{
	uint8_t v;

	return (0 == mbuf_read_mem(mb, &v, sizeof(v))) ? v : 0;
}
Esempio n. 8
0
int stun_attr_decode(struct stun_attr **attrp, struct mbuf *mb,
		     const uint8_t *tid, struct stun_unknown_attr *ua)
{
	struct stun_attr *attr;
	size_t start, len;
	uint32_t i, n;
	int err = 0;

	if (!mb || !attrp)
		return EINVAL;

	if (mbuf_get_left(mb) < 4)
		return EBADMSG;

	attr = mem_zalloc(sizeof(*attr), destructor);
	if (!attr)
		return ENOMEM;

	attr->type = htons(mbuf_read_u16(mb));
	len = htons(mbuf_read_u16(mb));

	if (mbuf_get_left(mb) < len)
		goto badmsg;

	start = mb->pos;

	switch (attr->type) {

	case STUN_ATTR_MAPPED_ADDR:
	case STUN_ATTR_ALT_SERVER:
	case STUN_ATTR_RESP_ORIGIN:
	case STUN_ATTR_OTHER_ADDR:
		tid = NULL;
		/*@fallthrough@*/
	case STUN_ATTR_XOR_PEER_ADDR:
	case STUN_ATTR_XOR_RELAY_ADDR:
	case STUN_ATTR_XOR_MAPPED_ADDR:
		err = stun_addr_decode(mb, &attr->v.sa, tid);
		break;

	case STUN_ATTR_CHANGE_REQ:
		if (len != 4)
			goto badmsg;

		n = ntohl(mbuf_read_u32(mb));
		attr->v.change_req.ip   = (n >> 2) & 0x1;
		attr->v.change_req.port = (n >> 1) & 0x1;
		break;

	case STUN_ATTR_USERNAME:
	case STUN_ATTR_REALM:
	case STUN_ATTR_NONCE:
	case STUN_ATTR_SOFTWARE:
		err = str_decode(mb, &attr->v.str, len);
		break;

	case STUN_ATTR_MSG_INTEGRITY:
		if (len != 20)
			goto badmsg;

		err = mbuf_read_mem(mb, attr->v.msg_integrity, 20);
		break;

	case STUN_ATTR_ERR_CODE:
		if (len < 4)
			goto badmsg;

		mb->pos += 2;
		attr->v.err_code.code  = (mbuf_read_u8(mb) & 0x7) * 100;
		attr->v.err_code.code += mbuf_read_u8(mb);
		err = str_decode(mb, &attr->v.err_code.reason, len - 4);
		break;

	case STUN_ATTR_UNKNOWN_ATTR:
		for (i=0; i<len/2; i++) {
			uint16_t type = ntohs(mbuf_read_u16(mb));

			if (i >= ARRAY_SIZE(attr->v.unknown_attr.typev))
				continue;

			attr->v.unknown_attr.typev[i] = type;
			attr->v.unknown_attr.typec++;
		}
		break;

	case STUN_ATTR_CHANNEL_NUMBER:
	case STUN_ATTR_RESP_PORT:
		if (len < 2)
			goto badmsg;

	        attr->v.uint16 = ntohs(mbuf_read_u16(mb));
		break;

	case STUN_ATTR_LIFETIME:
	case STUN_ATTR_PRIORITY:
	case STUN_ATTR_FINGERPRINT:
		if (len != 4)
			goto badmsg;

	        attr->v.uint32 = ntohl(mbuf_read_u32(mb));
		break;

	case STUN_ATTR_DATA:
	case STUN_ATTR_PADDING:
		attr->v.mb.buf  = mem_ref(mb->buf);
		attr->v.mb.size = mb->size;
		attr->v.mb.pos  = mb->pos;
		attr->v.mb.end  = mb->pos + len;
		mb->pos += len;
		break;

	case STUN_ATTR_REQ_ADDR_FAMILY:
	case STUN_ATTR_REQ_TRANSPORT:
		if (len < 1)
			goto badmsg;

	        attr->v.uint8 = mbuf_read_u8(mb);
		break;

	case STUN_ATTR_EVEN_PORT:
		if (len < 1)
			goto badmsg;

		attr->v.even_port.r = (mbuf_read_u8(mb) >> 7) & 0x1;
		break;

	case STUN_ATTR_DONT_FRAGMENT:
	case STUN_ATTR_USE_CAND:
		if (len > 0)
			goto badmsg;

		/* no value */
		break;

	case STUN_ATTR_RSV_TOKEN:
	case STUN_ATTR_CONTROLLING:
	case STUN_ATTR_CONTROLLED:
		if (len != 8)
			goto badmsg;

	        attr->v.uint64 = sys_ntohll(mbuf_read_u64(mb));
		break;

	default:
		mb->pos += len;

		if (attr->type >= 0x8000)
			break;

		if (ua && ua->typec < ARRAY_SIZE(ua->typev))
			ua->typev[ua->typec++] = attr->type;
		break;
	}

	if (err)
		goto error;

	/* padding */
	while (((mb->pos - start) & 0x03) && mbuf_get_left(mb))
		++mb->pos;

	*attrp = attr;

	return 0;

 badmsg:
	err = EBADMSG;
 error:
	mem_deref(attr);

	return err;
}
int srtp_decrypt(struct srtp *srtp, struct mbuf *mb)
{
	struct srtp_stream *strm;
	struct rtp_header hdr;
	struct comp *comp;
	uint64_t ix;
	size_t start;
	int diff;
	int err;

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

	comp = &srtp->rtp;

	start = mb->pos;

	err = rtp_hdr_decode(&hdr, mb);
	if (err)
		return err;

	err = stream_get_seq(&strm, srtp, hdr.ssrc, hdr.seq);
	if (err)
		return err;

	diff = seq_diff(strm->s_l, hdr.seq);
	if (diff > 32768)
		return ETIMEDOUT;

	/* Roll-Over Counter (ROC) */
	if (diff <= -32768) {
		strm->roc++;
		strm->s_l = 0;
	}

	ix = srtp_get_index(strm->roc, strm->s_l, hdr.seq);

	if (comp->hmac) {
		uint8_t tag_calc[SHA_DIGEST_LENGTH];
		uint8_t tag_pkt[SHA_DIGEST_LENGTH];
		size_t pld_start, tag_start;

		if (mbuf_get_left(mb) < comp->tag_len)
			return EBADMSG;

		pld_start = mb->pos;
		tag_start = mb->end - comp->tag_len;

		mb->pos = tag_start;

		err = mbuf_read_mem(mb, tag_pkt, comp->tag_len);
		if (err)
			return err;

		mb->pos = mb->end = tag_start;

		err = mbuf_write_u32(mb, htonl(strm->roc));
		if (err)
			return err;

		mb->pos = start;

		err = hmac_digest(comp->hmac, tag_calc, sizeof(tag_calc),
				  mbuf_buf(mb), mbuf_get_left(mb));
		if (err)
			return err;

		mb->pos = pld_start;
		mb->end = tag_start;

		if (0 != memcmp(tag_calc, tag_pkt, comp->tag_len))
			return EAUTH;

		/*
		 * 3.3.2.  Replay Protection
		 *
		 * Secure replay protection is only possible when
		 * integrity protection is present.
		 */
		if (!srtp_replay_check(&strm->replay_rtp, ix))
			return EALREADY;
	}

	if (comp->aes) {

		union vect128 iv;
		uint8_t *p = mbuf_buf(mb);

		srtp_iv_calc(&iv, &comp->k_s, strm->ssrc, ix);

		aes_set_iv(comp->aes, iv.u8);
		err = aes_decr(comp->aes, p, p, mbuf_get_left(mb));
		if (err)
			return err;
	}

	if (hdr.seq > strm->s_l)
		strm->s_l = hdr.seq;

	mb->pos = start;

	return 0;
}
Esempio n. 10
0
static void recv_handler(struct mbuf *mb, void *arg)
{
	struct rst *rst = arg;
	size_t n;

	if (!rst->head_recv) {

		struct pl hdr, name, metaint, eoh;

		if (rst->mb) {
			size_t pos;
			int err;

			pos = rst->mb->pos;

			rst->mb->pos = rst->mb->end;

			err = mbuf_write_mem(rst->mb, mbuf_buf(mb),
					     mbuf_get_left(mb));
			if (err) {
				re_printf("rst: buffer write error: %m\n",
					  err);
				rst->tc = mem_deref(rst->tc);
				tmr_start(&rst->tmr, RETRY_WAIT,
					  reconnect, rst);
				return;
			}

			rst->mb->pos = pos;
		}
		else {
			rst->mb = mem_ref(mb);
		}

		if (re_regex((const char *)mbuf_buf(rst->mb),
			     mbuf_get_left(rst->mb),
			     "[^\r\n]1\r\n\r\n", &eoh))
			return;

		rst->head_recv = true;

		hdr.p = (const char *)mbuf_buf(rst->mb);
		hdr.l = eoh.p + 5 - hdr.p;

		if (!re_regex(hdr.p, hdr.l, "icy-name:[ \t]*[^\r\n]+\r\n",
			      NULL, &name))
			(void)pl_strdup(&rst->name, &name);

		if (!re_regex(hdr.p, hdr.l, "icy-metaint:[ \t]*[0-9]+\r\n",
			      NULL, &metaint))
			rst->metaint = pl_u32(&metaint);

		if (rst->metaint == 0) {
			re_printf("rst: icy meta interval not available\n");
			rst->tc = mem_deref(rst->tc);
			tmr_start(&rst->tmr, RETRY_WAIT, reconnect, rst);
			return;
		}

		rst_video_update(rst->vidsrc_st, rst->name, NULL);

		rst->mb->pos += hdr.l;

		re_printf("rst: name='%s' metaint=%zu\n",
			  rst->name, rst->metaint);

		if (rst->mb->pos >= rst->mb->end)
			return;

		mb = rst->mb;
	}

	while (mb->pos < mb->end) {

		if (rst->metasz > 0) {

			n = min(mbuf_get_left(mb), rst->metasz - rst->bytec);

			if (rst->meta)
				mbuf_read_mem(mb,
					     (uint8_t *)&rst->meta[rst->bytec],
					      n);
			else
				mb->pos += n;

			rst->bytec += n;
#if 0
			re_printf("rst: metadata %zu bytes\n", n);
#endif
			if (rst->bytec >= rst->metasz) {
#if 0
				re_printf("rst: metadata: [%s]\n", rst->meta);
#endif
				rst->metasz = 0;
				rst->bytec  = 0;

				rst_video_update(rst->vidsrc_st, rst->name,
						 rst->meta);
			}
		}
		else if (rst->bytec < rst->metaint) {

			n = min(mbuf_get_left(mb), rst->metaint - rst->bytec);

			rst_audio_feed(rst->ausrc_st, mbuf_buf(mb), n);

			rst->bytec += n;
			mb->pos    += n;
#if 0
			re_printf("rst: mp3data %zu bytes\n", n);
#endif
		}
		else {
			rst->metasz = mbuf_read_u8(mb) * 16;
			rst->bytec  = 0;

			rst->meta = mem_deref(rst->meta);
			rst->meta = mem_zalloc(rst->metasz + 1, NULL);
#if 0
			re_printf("rst: metalength %zu bytes\n", rst->metasz);
#endif
		}
	}
}
Esempio n. 11
0
File: pkt.c Progetto: kaija/libre
/**
 * Decode one RTCP message from a buffer
 *
 * @param msgp Pointer to allocated RTCP Message
 * @param mb   Buffer to decode from
 *
 * @return 0 for success, otherwise errorcode
 */
int rtcp_decode(struct rtcp_msg **msgp, struct mbuf *mb)
{
	struct rtcp_msg *msg = NULL;
	size_t start, i, sz, count, rem;
	int err;

	if (!msgp)
		return EINVAL;
	if (mbuf_get_left(mb) < RTCP_HDR_SIZE)
		return EBADMSG;

	msg = mem_zalloc(sizeof(*msg), rtcp_destructor);
	if (!msg)
		return ENOMEM;

	start = mb->pos;

	/* decode and check header */
	err = rtcp_hdr_decode(mb, &msg->hdr);
	if (err)
		goto out;

	if (msg->hdr.version != RTCP_VERSION)
		goto badmsg;

	/* check length and remaining */
	rem = msg->hdr.length * sizeof(uint32_t);
	if (mbuf_get_left(mb) < rem)
		goto badmsg;

	count = msg->hdr.count;

	switch (msg->hdr.pt) {

	case RTCP_SR:
		if (mbuf_get_left(mb) < (RTCP_SRC_SIZE + RTCP_SR_SIZE))
			goto badmsg;
		msg->r.sr.ssrc     = ntohl(mbuf_read_u32(mb));
		msg->r.sr.ntp_sec  = ntohl(mbuf_read_u32(mb));
		msg->r.sr.ntp_frac = ntohl(mbuf_read_u32(mb));
		msg->r.sr.rtp_ts   = ntohl(mbuf_read_u32(mb));
		msg->r.sr.psent    = ntohl(mbuf_read_u32(mb));
		msg->r.sr.osent    = ntohl(mbuf_read_u32(mb));

		err = rtcp_rr_alloc(&msg->r.sr.rrv, count);
		if (err)
			goto out;
		for (i=0; i<count && !err; i++)
			err = rtcp_rr_decode(mb, &msg->r.sr.rrv[i]);
		break;

	case RTCP_RR:
		if (mbuf_get_left(mb) < RTCP_SRC_SIZE)
			goto badmsg;
		msg->r.rr.ssrc = ntohl(mbuf_read_u32(mb));

		err = rtcp_rr_alloc(&msg->r.rr.rrv, count);
		if (err)
			goto out;
		for (i=0; i<count && !err; i++)
			err = rtcp_rr_decode(mb, &msg->r.rr.rrv[i]);
		break;

	case RTCP_SDES:
		if (count == 0)
			break;

		sz = count * sizeof(*msg->r.sdesv);
		msg->r.sdesv = mem_zalloc(sz, NULL);
		if (!msg->r.sdesv) {
			err = ENOMEM;
			goto out;
		}

		for (i=0; i<msg->hdr.count && !err; i++)
			err = rtcp_sdes_decode(mb, &msg->r.sdesv[i]);
		break;

	case RTCP_BYE:
		sz = count * sizeof(*msg->r.bye.srcv);
		msg->r.bye.srcv = mem_alloc(sz, NULL);
		if (!msg->r.bye.srcv) {
			err = ENOMEM;
			goto out;
		}
		if (mbuf_get_left(mb) < sz)
			goto badmsg;
		for (i=0; i<count; i++)
			msg->r.bye.srcv[i] = ntohl(mbuf_read_u32(mb));

		/* decode reason (optional) */
		if (rem > count*sizeof(uint32_t)) {
			const size_t len = mbuf_read_u8(mb);
			if (mbuf_get_left(mb) < len)
				goto badmsg;

			err = mbuf_strdup(mb, &msg->r.bye.reason, len);
		}
		break;

	case RTCP_APP:
		if (mbuf_get_left(mb) < RTCP_APP_SIZE)
			goto badmsg;
		msg->r.app.src = ntohl(mbuf_read_u32(mb));
		(void)mbuf_read_mem(mb, (uint8_t *)msg->r.app.name,
				    sizeof(msg->r.app.name));
		if (rem > RTCP_APP_SIZE) {
			msg->r.app.data_len = rem - RTCP_APP_SIZE;
			msg->r.app.data = mem_alloc(msg->r.app.data_len, NULL);
			if (!msg->r.app.data) {
				err = ENOMEM;
				goto out;
			}
			if (mbuf_get_left(mb) < msg->r.app.data_len)
				goto badmsg;
			(void)mbuf_read_mem(mb, msg->r.app.data,
					    msg->r.app.data_len);
		}
		break;

	case RTCP_FIR:
		if (mbuf_get_left(mb) < RTCP_FIR_SIZE)
			goto badmsg;
		msg->r.fir.ssrc = ntohl(mbuf_read_u32(mb));
		break;

	case RTCP_NACK:
		if (mbuf_get_left(mb) < RTCP_NACK_SIZE)
			goto badmsg;
		msg->r.nack.ssrc = ntohl(mbuf_read_u32(mb));
		msg->r.nack.fsn  = ntohs(mbuf_read_u16(mb));
		msg->r.nack.blp  = ntohs(mbuf_read_u16(mb));
		break;

	case RTCP_RTPFB:
		if (mbuf_get_left(mb) < RTCP_FB_SIZE)
			goto badmsg;
		msg->r.fb.ssrc_packet = ntohl(mbuf_read_u32(mb));
		msg->r.fb.ssrc_media = ntohl(mbuf_read_u32(mb));
		msg->r.fb.n = msg->hdr.length - 2;

		err = rtcp_rtpfb_decode(mb, msg);
		break;

	case RTCP_PSFB:
		if (mbuf_get_left(mb) < RTCP_FB_SIZE)
			goto badmsg;
		msg->r.fb.ssrc_packet = ntohl(mbuf_read_u32(mb));
		msg->r.fb.ssrc_media = ntohl(mbuf_read_u32(mb));
		msg->r.fb.n = msg->hdr.length - 2;

		err = rtcp_psfb_decode(mb, msg);
		break;

	default:
		/* unknown message type */
		mbuf_advance(mb, rem);
		break;
	}
	if (err)
		goto out;

	/* slurp padding */
	while ((mb->pos - start) & 0x3 && mbuf_get_left(mb))
		++mb->pos;

 out:
	if (err)
		mem_deref(msg);
	else
		*msgp = msg;

	return err;

 badmsg:
	mem_deref(msg);
	return EBADMSG;
}