Пример #1
0
static int general_packetize(struct mbuf *mb, size_t pktsize,
			     videnc_packet_h *pkth, void *arg)
{
	int err = 0;

	/* Assemble frame into smaller packets */
	while (!err) {
		size_t sz, left = mbuf_get_left(mb);
		bool last = (left < pktsize);
		if (!left)
			break;

		sz = last ? left : pktsize;

		err = pkth(last, NULL, 0, mbuf_buf(mb), sz, arg);

		mbuf_advance(mb, sz);
	}

	return err;
}
Пример #2
0
/* Receive packet on the "relayed" address -- relay to the client */
static void relay_udp_recv(const struct sa *src, struct mbuf *mb, void *arg)
{
	struct turnserver *turn = arg;
	struct channel *chan;
	int err = 0;

	++turn->n_recv;

	chan = find_channel_peer(turn, src);
	if (chan) {
		uint16_t len = mbuf_get_left(mb);
		size_t start;

		if (mb->pos < 4) {
			DEBUG_WARNING("relay_udp_recv: mb pos < 4\n");
			return;
		}

		mb->pos -= 4;
		start = mb->pos;

		(void)mbuf_write_u16(mb, htons(chan->nr));
		(void)mbuf_write_u16(mb, htons(len));

		mb->pos = start;

		err = udp_send(turn->us, &turn->cli, mb);
	}
	else {
		err = stun_indication(IPPROTO_UDP, turn->us,
				      &turn->cli, 0, STUN_METHOD_DATA,
				      NULL, 0, false, 2,
				      STUN_ATTR_XOR_PEER_ADDR, src,
				      STUN_ATTR_DATA, mb);
	}

	if (err) {
		DEBUG_WARNING("relay_udp_recv: error %m\n", err);
	}
}
Пример #3
0
/**
 * Encoder audio and send via stream
 *
 * @note This function has REAL-TIME properties
 *
 * @param a     Audio object
 * @param tx    Audio transmit object
 * @param sampv Audio samples
 * @param sampc Number of audio samples
 */
static void encode_rtp_send(struct audio *a, struct autx *tx,
			    int16_t *sampv, size_t sampc)
{
	size_t frame_size;  /* number of samples per channel */
	size_t len;
	int err;

	if (!tx->ac)
		return;

	tx->mb->pos = tx->mb->end = STREAM_PRESZ;
	len = mbuf_get_space(tx->mb);

	err = tx->ac->ench(tx->enc, mbuf_buf(tx->mb), &len, sampv, sampc);
	if (err) {
		warning("audio: %s encode error: %d samples (%m)\n",
			tx->ac->name, sampc, err);
		goto out;
	}

	tx->mb->pos = STREAM_PRESZ;
	tx->mb->end = STREAM_PRESZ + len;

	if (mbuf_get_left(tx->mb)) {

		err = stream_send(a->strm, tx->marker, -1, tx->ts, tx->mb);
		if (err)
			goto out;
	}

	/* The RTP clock rate used for generating the RTP timestamp is
	 * independent of the number of channels and the encoding
	 */
	frame_size = (tx->is_g722 ? sampc/2 : sampc) / tx->ac->ch;

	tx->ts += (uint32_t)frame_size;

 out:
	tx->marker = false;
}
Пример #4
0
void http_request_h(struct http_conn *conn, const struct http_msg *msg, void *arg)
{
    int err;
    enum app_cmd cmd;
    const struct http_hdr * expect_hdr;
    struct mbuf *mb = msg->mb;
    uint8_t *ret_buf;
    size_t ret_len;

    if(pl_strcmp(&msg->met, "POST")) {
        http_creply(conn, 405, "Method not allowed", "text/plain", "EMET");
        return;
    }

    expect_hdr = http_msg_hdr(msg, HTTP_HDR_EXPECT);
    if(expect_hdr != NULL && version_cmp(version, &expect_hdr->val) < 0) {
        http_creply(conn, 417, "Expectation Failed", "text/plain", "%s", version);
        return;
    }

    cmd = (enum app_cmd)(hash_joaat_ci(msg->path.p, msg->path.l) & 0xfff);
    err = app_handle(cmd, mbuf_buf(mb), mbuf_get_left(mb), &ret_buf, &ret_len);
    if(err < 0) {
        http_creply(conn, 500, "Internal Server Error", "text/plain", "EINT");
        return;
    }

    if(err > 200) {
        http_creply(conn, err, "Error", "text/plain", "NO", 2);
        return;
    }

    if(err == 0) {
        http_creply(conn, 200, "OK", "text/plain; charset=utf-8", "%b", ret_buf, ret_len);
    } else {
        http_creply(conn, 403, "Forbidden", "text/plain", "%b", ret_buf, ret_len);
    }

    free(ret_buf);
}
Пример #5
0
static void message_handler(const struct pl *peer, const struct pl *ctype,
			    struct mbuf *body, void *arg)
{
	struct gtk_mod *mod = arg;
	char title[128];
	char msg[512];

#if GLIB_CHECK_VERSION(2,40,0)
	GNotification *notification;
#elif defined(USE_LIBNOTIFY)
	NotifyNotification *notification;
#endif

	(void)ctype;


	/* Display notification of chat */

	re_snprintf(title, sizeof title, "Chat from %r", peer);
	title[sizeof title - 1] = '\0';

	re_snprintf(msg, sizeof msg, "%b",
			mbuf_buf(body), mbuf_get_left(body));

#if GLIB_CHECK_VERSION(2,40,0)
	notification = g_notification_new(title);
	g_notification_set_body(notification, msg);
	g_application_send_notification(mod->app, NULL, notification);
	g_object_unref(notification);

#elif defined(USE_LIBNOTIFY)
	(void)mod;

	if (!notify_is_initted())
		return;
	notification = notify_notification_new(title, msg, "baresip");
	notify_notification_show(notification, NULL);
	g_object_unref(notification);
#endif
}
Пример #6
0
static bool send_handler(int *err, struct sa *dst, struct mbuf *mb, void *arg)
{
	struct tls_sock *ts = arg;
	struct tls_conn *tc;
	int r;

	tc = tls_udp_conn(ts, dst);
	if (!tc) {

		/* No connection found, assuming Client role */

		tc = conn_alloc(ts, dst);
		if (!tc) {
			*err = ENOMEM;
			return true;
		}

		SSL_set_connect_state(tc->ssl);

		check_timer(tc);
	}

	r = SSL_write(tc->ssl, mbuf_buf(mb), (int)mbuf_get_left(mb));
	if (r < 0) {

		switch (SSL_get_error(tc->ssl, r)) {

		case SSL_ERROR_WANT_READ:
			break;

		default:
			DEBUG_WARNING("SSL_write: %d\n",
				      SSL_get_error(tc->ssl, r));
			*err = EPROTO;
			return true;
		}
	}

	return true;
}
Пример #7
0
/* responsible for adding the SHIM header
   - assumes that the sent MBUF contains a complete packet
 */
static bool shim_send_handler(int *err, struct mbuf *mb, void *arg)
{
	struct shim *shim = arg;
	size_t len;
	(void)shim;

	if (mb->pos < SHIM_HDR_SIZE) {
		DEBUG_WARNING("send: not enough space for SHIM header\n");
		*err = ENOMEM;
		return true;
	}

	len = mbuf_get_left(mb);

	mb->pos -= SHIM_HDR_SIZE;
	*err = mbuf_write_u16(mb, htons(len));
	mb->pos -= SHIM_HDR_SIZE;

	++shim->n_tx;

	return false;
}
Пример #8
0
/**
 * Decode a multipart/mixed message and find the part with application/sdp
 *
 * @param ctype_prm  Content type parameter
 * @param mb         Mbuffer containing the SDP
 *
 * @return 0 if success, otherwise errorcode
 */
int sdp_decode_multipart(const struct pl *ctype_prm, struct mbuf *mb)
{
	struct pl bnd, s, e, p;
	char expr[64];
	int err;

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

	/* fetch the boundary tag, excluding quotes */
	err = re_regex(ctype_prm->p, ctype_prm->l,
		       "boundary=[~]+", &bnd);
	if (err)
		return err;

	if (re_snprintf(expr, sizeof(expr), "--%r[^]+", &bnd) < 0)
		return ENOMEM;

	/* find 1st boundary */
	err = re_regex((char *)mbuf_buf(mb), mbuf_get_left(mb), expr, &s);
	if (err)
		return err;

	/* iterate over each part */
	while (s.l > 2) {
		if (re_regex(s.p, s.l, expr, &e))
			return 0;

		p.p = s.p + 2;
		p.l = e.p - p.p - bnd.l - 2;

		/* valid part in "p" */
		decode_part(&p, mb);

		s = e;
	}

	return 0;
}
Пример #9
0
static bool udp_helper_recv(struct sa *src, struct mbuf *mb, void *arg)
{
	struct menc_media *st = arg;
	unsigned int length;
	zrtp_status_t s;
	const char *proto_name = "srtp";
	enum pkt_type ptype = get_packet_type(mb);

	if (drop_packets(st))
		return true;

	length = (unsigned int)mbuf_get_left(mb);

	if (ptype == PKT_TYPE_RTCP) {
		proto_name = "srtcp";
		s = zrtp_process_srtcp(st->zrtp_stream,
			    (char *)mbuf_buf(mb), &length);
	}
	else if (ptype == PKT_TYPE_RTP || ptype == PKT_TYPE_ZRTP) {
		s = zrtp_process_srtp(st->zrtp_stream,
			    (char *)mbuf_buf(mb), &length);
	}
	else
		return false;

	if (s != zrtp_status_ok) {

		if (s == zrtp_status_drop)
			return true;

		warning("zrtp: recv(port=%d): zrtp_process_%s: %d '%s'\n",
			sa_port(src), proto_name, s, zrtp_log_status2str(s));
		return false;
	}

	mb->end = mb->pos + length;

	return false;
}
Пример #10
0
static void udp_recv(const struct sa *src, struct mbuf *mb, void *arg)
{
	struct sip_server *srv = arg;
	struct sip_msg *msg;
	int err;

#if 0
	re_printf("sip: %zu bytes from %J\n", mbuf_get_left(mb), src);
	re_printf("%b\n", mb->buf, mb->end);
#endif

	err = sip_msg_decode(&msg, mb);
	if (err) {
		warning("selftest: sip_msg_decode: %m\n", err);
		return;
	}

	if (0 == pl_strcmp(&msg->met, "REGISTER"))
		srv->got_register_req = true;

	msg->sock = mem_ref(srv->us);
	msg->src  = *src;
	msg->dst  = srv->laddr;
	msg->tp   = SIP_TRANSP_UDP;

	if (srv->terminate)
		err = sip_reply(srv->sip, msg, 503, "Server Error");
	else
		err = sip_reply(srv->sip, msg, 200, "OK");
	if (err) {
		warning("selftest: could not reply: %m\n", err);
	}

	mem_deref(msg);

	if (srv->terminate)
		re_cancel();
}
Пример #11
0
static void udp_recv(const struct sa *src, struct mbuf *mb, void *arg)
{
	struct ui_st *st = arg;
	struct mbuf *mbr = mbuf_alloc(64);
	struct re_printf pf;

	pf.vph = print_handler;
	pf.arg = mbr;

	while (mbuf_get_left(mb)) {
		char ch = mbuf_read_u8(mb);

		if (ch == '\r')
			ch = '\n';

		ui_input_key(ch, &pf);
	}

	mbr->pos = 0;
	(void)udp_send(st->us, src, mbr);

	mem_deref(mbr);
}
Пример #12
0
static bool udp_helper_recv(struct sa *src, struct mbuf *mb, void *arg)
{
	struct menc_media *st = arg;
	unsigned int length;
	zrtp_status_t s;
	(void)src;

	length = (unsigned int)mbuf_get_left(mb);

	s = zrtp_process_srtp(st->zrtp_stream, (char *)mbuf_buf(mb), &length);
	if (s != zrtp_status_ok) {

		if (s == zrtp_status_drop)
			return true;

		warning("zrtp: zrtp_process_srtp: %d\n", s);
		return false;
	}

	mb->end = mb->pos + length;

	return false;
}
Пример #13
0
/**
 * Decode an RTCP Payload-Specific Feedback Message
 *
 * @param mb  Buffer to decode
 * @param msg RTCP Message to decode into
 *
 * @return 0 for success, otherwise errorcode
 */
int rtcp_psfb_decode(struct mbuf *mb, struct rtcp_msg *msg)
{
	size_t i, sz;

	if (!msg)
		return EINVAL;

	switch (msg->hdr.count) {

	case RTCP_PSFB_PLI:
		/* no params */
		break;

	case RTCP_PSFB_SLI:
		sz = msg->r.fb.n * sizeof(*msg->r.fb.fci.sliv);
		msg->r.fb.fci.sliv = mem_alloc(sz, NULL);
		if (!msg->r.fb.fci.sliv)
			return ENOMEM;

		if (mbuf_get_left(mb) < msg->r.fb.n * SLI_SIZE)
			return EBADMSG;
		for (i=0; i<msg->r.fb.n; i++) {
			const uint32_t v = ntohl(mbuf_read_u32(mb));

			msg->r.fb.fci.sliv[i].first  = v>>19 & 0x1fff;
			msg->r.fb.fci.sliv[i].number = v>> 6 & 0x1fff;
			msg->r.fb.fci.sliv[i].picid  = v>> 0 & 0x003f;
		}
		break;

	default:
		DEBUG_NOTICE("unknown PSFB fmt %d\n", msg->hdr.count);
		break;
	}

	return 0;
}
Пример #14
0
static void sipsub_notify_handler(struct sip *sip, const struct sip_msg *msg,
				  void *arg)
{
	struct call *call = arg;
	struct pl scode, reason;
	uint32_t sc;

	if (re_regex((char *)mbuf_buf(msg->mb), mbuf_get_left(msg->mb),
		     "SIP/2.0 [0-9]+ [^\r\n]+", &scode, &reason)) {
		(void)sip_reply(sip, msg, 400, "Bad sipfrag");
		return;
	}

	(void)sip_reply(sip, msg, 200, "OK");

	sc = pl_u32(&scode);

	if (sc >= 300) {
		warning("call: transfer failed: %u %r\n", sc, &reason);
	}
	else if (sc >= 200) {
		call_event_handler(call, CALL_EVENT_CLOSED, "Call transfered");
	}
}
Пример #15
0
static bool send_handler(int *err, struct sa *dst, struct mbuf *mb, void *arg)
{
	struct menc_st *st = arg;
	err_status_t e;
	int len;
	(void)dst;

	if (!st->use_srtp || !is_rtp_or_rtcp(mb))
		return false;

	len = (int)mbuf_get_left(mb);

	if (mbuf_get_space(mb) < ((size_t)len + SRTP_MAX_TRAILER_LEN)) {
		mbuf_resize(mb, mb->pos + len + SRTP_MAX_TRAILER_LEN);
	}

	if (is_rtcp_packet(mb)) {
		e = srtp_protect_rtcp(st->srtp_tx, mbuf_buf(mb), &len);
	}
	else {
		e = srtp_protect(st->srtp_tx, mbuf_buf(mb), &len);
	}

	if (err_status_ok != e) {
		DEBUG_WARNING("send: failed to protect %s-packet"
			      " with %d bytes (%H)\n",
			      is_rtcp_packet(mb) ? "RTCP" : "RTP",
			      len, errstatus_print, e);
		*err = EPROTO;
		return false;
	}

	mbuf_set_end(mb, mb->pos + len);

	return false;  /* continue processing */
}
Пример #16
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;
}
Пример #17
0
void stun_attr_dump(const struct stun_attr *a)
{
	uint32_t i;
	size_t len;

	if (!a)
		return;

	(void)re_printf(" %-25s", stun_attr_name(a->type));

	switch (a->type) {

	case STUN_ATTR_MAPPED_ADDR:
	case STUN_ATTR_XOR_PEER_ADDR:
	case STUN_ATTR_XOR_RELAY_ADDR:
	case STUN_ATTR_XOR_MAPPED_ADDR:
	case STUN_ATTR_ALT_SERVER:
	case STUN_ATTR_RESP_ORIGIN:
	case STUN_ATTR_OTHER_ADDR:
		(void)re_printf("%J", &a->v.sa);
		break;

	case STUN_ATTR_CHANGE_REQ:
		(void)re_printf("ip=%u port=%u", a->v.change_req.ip,
				a->v.change_req.port);
		break;

	case STUN_ATTR_USERNAME:
	case STUN_ATTR_REALM:
	case STUN_ATTR_NONCE:
	case STUN_ATTR_SOFTWARE:
		(void)re_printf("%s", a->v.str);
		break;

	case STUN_ATTR_MSG_INTEGRITY:
		(void)re_printf("%w", &a->v.msg_integrity, 20);
		break;

	case STUN_ATTR_ERR_CODE:
		(void)re_printf("%u %s", a->v.err_code.code,
				a->v.err_code.reason);
		break;

	case STUN_ATTR_UNKNOWN_ATTR:
		for (i=0; i<a->v.unknown_attr.typec; i++)
			(void)re_printf("0x%04x ", a->v.unknown_attr.typev[i]);
		break;

	case STUN_ATTR_CHANNEL_NUMBER:
		(void)re_printf("0x%04x", a->v.uint16);
		break;

	case STUN_ATTR_LIFETIME:
	case STUN_ATTR_PRIORITY:
		(void)re_printf("%u", a->v.uint32);
		break;

	case STUN_ATTR_DATA:
	case STUN_ATTR_PADDING:
		len = mbuf_get_left(&a->v.mb);
		(void)re_printf("%w%s (%u bytes)", mbuf_buf(&a->v.mb),
				MIN(len, 16), len > 16 ? "..." : "", len);
		break;

	case STUN_ATTR_REQ_ADDR_FAMILY:
	case STUN_ATTR_REQ_TRANSPORT:
		(void)re_printf("%u", a->v.uint8);
		break;

	case STUN_ATTR_EVEN_PORT:
		(void)re_printf("r=%u", a->v.even_port.r);
		break;

	case STUN_ATTR_DONT_FRAGMENT:
	case STUN_ATTR_USE_CAND:
		/* no value */
		break;

	case STUN_ATTR_RSV_TOKEN:
		(void)re_printf("0x%016llx", a->v.rsv_token);
		break;

	case STUN_ATTR_RESP_PORT:
		(void)re_printf("%u", a->v.uint16);
		break;

	case STUN_ATTR_FINGERPRINT:
		(void)re_printf("0x%08x", a->v.fingerprint);
		break;

	case STUN_ATTR_CONTROLLING:
	case STUN_ATTR_CONTROLLED:
		(void)re_printf("%llu", a->v.uint64);
		break;

	default:
		(void)re_printf("???");
		break;
	}

	(void)re_printf("\n");
}
Пример #18
0
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;
}
Пример #19
0
static void rtp_recv(const struct sa *src, const struct rtp_header *hdr,
		     struct mbuf *mb, void *arg)
{
	struct stream *s = arg;
	bool flush = false;
	int err;

	s->ts_last = tmr_jiffies();

	if (!mbuf_get_left(mb))
		return;

	if (!(sdp_media_ldir(s->sdp) & SDP_RECVONLY))
		return;

	metric_add_packet(&s->metric_rx, mbuf_get_left(mb));

	if (hdr->ssrc != s->ssrc_rx) {
		if (s->ssrc_rx) {
			flush = true;
			info("stream: %s: SSRC changed %x -> %x"
			     " (%u bytes from %J)\n",
			     sdp_media_name(s->sdp), s->ssrc_rx, hdr->ssrc,
			     mbuf_get_left(mb), src);
		}
		s->ssrc_rx = hdr->ssrc;
	}

	if (s->jbuf) {

		struct rtp_header hdr2;
		void *mb2 = NULL;

		/* Put frame in Jitter Buffer */
		if (flush)
			jbuf_flush(s->jbuf);

		err = jbuf_put(s->jbuf, hdr, mb);
		if (err) {
			info("%s: dropping %u bytes from %J (%m)\n",
			     sdp_media_name(s->sdp), mb->end,
			     src, err);
			s->metric_rx.n_err++;
		}

		if (jbuf_get(s->jbuf, &hdr2, &mb2)) {

			if (!s->jbuf_started)
				return;

			memset(&hdr2, 0, sizeof(hdr2));
		}

		s->jbuf_started = true;

		if (lostcalc(s, hdr2.seq) > 0)
			s->rtph(hdr, NULL, s->arg);

		s->rtph(&hdr2, mb2, s->arg);

		mem_deref(mb2);
	}
	else {
		if (lostcalc(s, hdr->seq) > 0)
			s->rtph(hdr, NULL, s->arg);

		s->rtph(hdr, mb, s->arg);
	}
}
Пример #20
0
int turnc_recv(struct turnc *turnc, struct sa *src, struct mbuf *mb)
{
	struct stun_attr *peer, *data;
	struct stun_unknown_attr ua;
	struct stun_msg *msg;
	int err = 0;

	if (!turnc || !src || !mb)
		return EINVAL;

	if (stun_msg_decode(&msg, mb, &ua)) {

		struct chan_hdr hdr;
		struct chan *chan;

		if (turnc_chan_hdr_decode(&hdr, mb))
			return EBADMSG;

		if (mbuf_get_left(mb) < hdr.len)
			return EBADMSG;

		chan = turnc_chan_find_numb(turnc, hdr.nr);
		if (!chan)
			return EBADMSG;

		*src = *turnc_chan_peer(chan);

		return 0;
	}

	switch (stun_msg_class(msg)) {

	case STUN_CLASS_INDICATION:
		if (ua.typec > 0) {
			err = ENOSYS;
			break;
		}

		if (stun_msg_method(msg) != STUN_METHOD_DATA) {
			err = ENOSYS;
			break;
		}

		peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR);
		data = stun_msg_attr(msg, STUN_ATTR_DATA);
		if (!peer || !data) {
			err = EPROTO;
			break;
		}

		*src = peer->v.xor_peer_addr;

		mb->pos = data->v.data.pos;
		mb->end = data->v.data.end;
		break;

	case STUN_CLASS_ERROR_RESP:
	case STUN_CLASS_SUCCESS_RESP:
		(void)stun_ctrans_recv(turnc->stun, msg, &ua);
		mb->pos = mb->end;
		break;

	default:
		err = ENOSYS;
		break;
	}

	mem_deref(msg);

	return err;
}
Пример #21
0
static int publish(struct publisher *pub)
{
	int err;
	const char *aor = ua_aor(pub->ua);
	struct mbuf *mb;

	mb = mbuf_alloc(1024);
	if (!mb)
		return ENOMEM;

	if (pub->expires && !pub->refresh)
		err = mbuf_printf(mb,
	"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n"
	"<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\r\n"
	"    xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\"\r\n"
	"    xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\"\r\n"
	"    entity=\"%s\">\r\n"
	"  <dm:person id=\"p4159\"><rpid:activities/></dm:person>\r\n"
	"  <tuple id=\"t4109\">\r\n"
	"    <status>\r\n"
	"      <basic>%s</basic>\r\n"
	"    </status>\r\n"
	"    <contact>%s</contact>\r\n"
	"  </tuple>\r\n"
	"</presence>\r\n"
		  ,aor,
		  presence_status_str(ua_presence_status(pub->ua)), aor);
	else
		err = mbuf_printf(mb, "");
	if (err)
		goto out;

	mb->pos = 0;

	/* XXX: can be simplified with 1 function call, by adding a
	   print-handler that prints "SIP-If-Match: ETAG" */
	if (pub->etag)
		err = sip_req_send(pub->ua, "PUBLISH", aor,
				   pub->expires ? response_handler : NULL,
				   pub,
			   "%s"
			   "Event: presence\r\n"
			   "Expires: %u\r\n"
			   "SIP-If-Match: %s\r\n"
			   "Content-Length: %zu\r\n"
			   "\r\n"
			   "%b",
			   pub->expires
				   ? "Content-Type: application/pidf+xml\r\n"
				   : "",

			   pub->expires,
			   pub->etag,
			   mbuf_get_left(mb),
			   mbuf_buf(mb),
			   mbuf_get_left(mb));
	else
		err = sip_req_send(pub->ua, "PUBLISH", aor,
				   pub->expires ? response_handler : NULL,
				   pub,
			   "%s"
			   "Event: presence\r\n"
			   "Expires: %u\r\n"
			   "Content-Length: %zu\r\n"
			   "\r\n"
			   "%b",
			   pub->expires
				   ? "Content-Type: application/pidf+xml\r\n"
				   : "",
			   pub->expires,
			   mbuf_get_left(mb),
			   mbuf_buf(mb),
			   mbuf_get_left(mb));
	if (err) {
		warning("publisher: send PUBLISH: (%m)\n", err);
	}

out:
	mem_deref(mb);

	return err;
}
Пример #22
0
static bool udp_recv_handler(struct sa *src, struct mbuf *mb, void *arg)
{
	struct stun_attr *peer, *data;
	struct stun_unknown_attr ua;
	struct turnc *turnc = arg;
	struct stun_msg *msg;
	bool hdld = true;

	if (!sa_cmp(&turnc->srv, src, SA_ALL) &&
	    !sa_cmp(&turnc->psrv, src, SA_ALL))
		return false;

	if (stun_msg_decode(&msg, mb, &ua)) {

		struct chan_hdr hdr;
		struct chan *chan;

		if (turnc_chan_hdr_decode(&hdr, mb))
			return true;

		if (mbuf_get_left(mb) < hdr.len)
			return true;

		chan = turnc_chan_find_numb(turnc, hdr.nr);
		if (!chan)
			return true;

		*src = *turnc_chan_peer(chan);

		return false;
	}

	switch (stun_msg_class(msg)) {

	case STUN_CLASS_INDICATION:
		if (ua.typec > 0)
			break;

		if (stun_msg_method(msg) != STUN_METHOD_DATA)
			break;

		peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR);
		data = stun_msg_attr(msg, STUN_ATTR_DATA);
		if (!peer || !data)
			break;

		*src = peer->v.xor_peer_addr;

		mb->pos = data->v.data.pos;
		mb->end = data->v.data.end;

		hdld = false;
		break;

	case STUN_CLASS_ERROR_RESP:
	case STUN_CLASS_SUCCESS_RESP:
		(void)stun_ctrans_recv(turnc->stun, msg, &ua);
		break;

	default:
		break;
	}

	mem_deref(msg);

	return hdld;
}
Пример #23
0
int turnc_send(struct turnc *turnc, const struct sa *dst, struct mbuf *mb)
{
	size_t pos, indlen;
	struct chan *chan;
	int err;

	if (!turnc || !dst || !mb)
		return EINVAL;

	chan = turnc_chan_find_peer(turnc, dst);
	if (chan) {
		struct chan_hdr hdr;

		if (mb->pos < CHAN_HDR_SIZE)
			return EINVAL;

		hdr.nr  = turnc_chan_numb(chan);
		hdr.len = mbuf_get_left(mb);

		mb->pos -= CHAN_HDR_SIZE;
		pos = mb->pos;

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

		if (turnc->proto == IPPROTO_TCP) {

			mb->pos = mb->end;

			/* padding */
			while (hdr.len++ & 0x03) {
				err = mbuf_write_u8(mb, 0x00);
				if (err)
					return err;
			}
		}

		mb->pos = pos;
	}
	else {
		indlen = stun_indlen(dst);

		if (mb->pos < indlen)
			return EINVAL;

		mb->pos -= indlen;
		pos = mb->pos;

		err = stun_msg_encode(mb, STUN_METHOD_SEND,
				      STUN_CLASS_INDICATION, sendind_tid,
				      NULL, NULL, 0, false, 0x00, 2,
				      STUN_ATTR_XOR_PEER_ADDR, dst,
				      STUN_ATTR_DATA, mb);
		if (err)
			return err;

		mb->pos = pos;
	}

	switch (turnc->proto) {

	case IPPROTO_UDP:
		err = udp_send(turnc->sock, &turnc->srv, mb);
		break;

	case IPPROTO_TCP:
		err = tcp_send(turnc->sock, mb);
		break;

#ifdef USE_DTLS
	case STUN_TRANSP_DTLS:
		err = dtls_send(turnc->sock, mb);
		break;
#endif

	default:
		err = EPROTONOSUPPORT;
		break;
	}

	return err;
}
Пример #24
0
int udp_sock::send(const struct sa *dst, struct mbuf *mb)
{
	struct sa hdst;
	TRequestStatus stat;
	int err = 0;

	DEBUG_INFO("udp_sock::send %u bytes to %J\n", mbuf_get_left(mb), dst);

	/* Check for error in e.g. connected state */
	if (cerr) {
		err = cerr;
		cerr = 0; /* clear error */
		return err;
	}

	/* call helpers in reverse order */
	struct le *le = list_tail(&helpers);
	while (le) {
		struct udp_helper *uh;

		uh = (struct udp_helper *)le->data;
		le = le->prev;

		if (dst != &hdst) {
			sa_cpy(&hdst, dst);
			dst = &hdst;
		}

		if (uh->sendh(&err, &hdst, mb, uh->arg) || err)
			return err;
	}

	TInetAddr ia(sa_in(dst), sa_port(dst));

	const TPtrC8 buf_tx(mb->buf + mb->pos, mb->end - mb->pos);

	if (conn) {
		cus->iSocket.Connect(ia, stat);
		User::WaitForRequest(stat);

		if (KErrNone != stat.Int()) {
			DEBUG_WARNING("udp_sock::send Connect: kerr=%d\n",
				      stat.Int());
			if (KErrGeneral == stat.Int())
				return ECONNREFUSED;
		}

#if 0
		/* TODO: Cause Access-Violation in WINS emulator! */
		cus->iSocket.Send(buf_tx, 0, stat);
#else
		cus->iSocket.SendTo(buf_tx, ia, 0, stat);
#endif
	}
	else {
		cus->iSocket.SendTo(buf_tx, ia, 0, stat);
	}

	User::WaitForRequest(stat);

	return kerr2errno(stat.Int());
}
Пример #25
0
int stun_attr_encode(struct mbuf *mb, uint16_t type, const void *v,
		     const uint8_t *tid, uint8_t padding)
{
	const struct stun_change_req *ch_req = v;
	const struct stun_errcode *err_code = v;
	const struct stun_unknown_attr *ua = v;
	const unsigned int *num = v;
	const struct mbuf *mbd = v;
	size_t start, len;
	uint32_t i, n;
	int err = 0;

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

	mb->pos += 4;
	start = mb->pos;

	switch (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_encode(mb, v, tid);
		break;

	case STUN_ATTR_CHANGE_REQ:
		n = (uint32_t)ch_req->ip << 2 | (uint32_t)ch_req->port << 1;
		err |= mbuf_write_u32(mb, htonl(n));
		break;

	case STUN_ATTR_USERNAME:
	case STUN_ATTR_REALM:
	case STUN_ATTR_NONCE:
	case STUN_ATTR_SOFTWARE:
		err |= mbuf_write_str(mb, v);
		break;

	case STUN_ATTR_MSG_INTEGRITY:
		err |= mbuf_write_mem(mb, v, 20);
		break;

	case STUN_ATTR_ERR_CODE:
		err |= mbuf_write_u16(mb, 0x00);
		err |= mbuf_write_u8(mb,  err_code->code/100);
		err |= mbuf_write_u8(mb,  err_code->code%100);
		err |= mbuf_write_str(mb, err_code->reason);
		break;

	case STUN_ATTR_UNKNOWN_ATTR:
		for (i=0; i<ua->typec; i++)
			err |= mbuf_write_u16(mb, htons(ua->typev[i]));
		break;

	case STUN_ATTR_CHANNEL_NUMBER:
	case STUN_ATTR_RESP_PORT:
		err |= mbuf_write_u16(mb, htons(*num));
		err |= mbuf_write_u16(mb, 0x0000);
		break;

	case STUN_ATTR_LIFETIME:
	case STUN_ATTR_PRIORITY:
	case STUN_ATTR_FINGERPRINT:
		err |= mbuf_write_u32(mb, htonl(*num));
		break;

	case STUN_ATTR_DATA:
	case STUN_ATTR_PADDING:
		if (mb == mbd) {
			mb->pos = mb->end;
			break;
		}
		err |= mbuf_write_mem(mb, mbuf_buf(mbd), mbuf_get_left(mbd));
		break;

	case STUN_ATTR_REQ_ADDR_FAMILY:
	case STUN_ATTR_REQ_TRANSPORT:
		err |= mbuf_write_u8(mb, *num);
		err |= mbuf_write_u8(mb, 0x00);
		err |= mbuf_write_u16(mb, 0x0000);
		break;

	case STUN_ATTR_EVEN_PORT:
		err |= mbuf_write_u8(mb, ((struct stun_even_port *)v)->r << 7);
		break;

	case STUN_ATTR_DONT_FRAGMENT:
	case STUN_ATTR_USE_CAND:
		 /* no value */
		break;

	case STUN_ATTR_RSV_TOKEN:
	case STUN_ATTR_CONTROLLED:
	case STUN_ATTR_CONTROLLING:
		err |= mbuf_write_u64(mb, sys_htonll(*(uint64_t *)v));
		break;

	default:
		err = EINVAL;
		break;
	}

	/* header */
	len = mb->pos - start;

	mb->pos = start - 4;
	err |= mbuf_write_u16(mb, htons(type));
	err |= mbuf_write_u16(mb, htons(len));
	mb->pos += len;

	/* padding */
	while ((mb->pos - start) & 0x03)
		err |= mbuf_write_u8(mb, padding);

	return err;
}
Пример #26
0
int sdp_decode(struct sdp_session *sess, struct mbuf *mb, bool offer)
{
	struct sdp_media *m;
	struct pl pl, val;
	struct le *le;
	char type = 0;
	int err = 0;

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

	sdp_session_rreset(sess);

	for (le=sess->medial.head; le; le=le->next) {

		m = le->data;

		sdp_media_rreset(m);
	}

	pl.p = (const char *)mbuf_buf(mb);
	pl.l = mbuf_get_left(mb);

	m = NULL;

	for (;pl.l && !err; pl.p++, pl.l--) {

		switch (*pl.p) {

		case '\r':
		case '\n':
			if (!type)
				break;

			switch (type) {

			case 'a':
				err = attr_decode(sess, m,
						  m ? &m->rdir : &sess->rdir,
						  &val);
				break;

			case 'b':
				err = bandwidth_decode(m? m->rbwv : sess->rbwv,
						       &val);
				break;

			case 'c':
				err = conn_decode(m ? &m->raddr : &sess->raddr,
						  &val);
				break;

			case 'm':
				err = media_decode(&m, sess, offer, &val);
				break;

			case 'v':
				err = version_decode(&val);
				break;
			}

#if 0
			if (err)
				re_printf("*** %c='%r': %s\n", type, &val,
					  strerror(err));
#endif

			type = 0;
			break;

		default:
			if (type) {
				val.l++;
				break;
			}

			if (pl.l < 2 || *(pl.p + 1) != '=') {
				err = EBADMSG;
				break;
			}

			type  = *pl.p;
			val.p = pl.p + 2;
			val.l = 0;

			pl.p += 1;
			pl.l -= 1;
			break;
		}
	}

	if (err)
		return err;

	if (type)
		return EBADMSG;

	for (le=sess->medial.head; le; le=le->next)
		sdp_media_align_formats(le->data, offer);

	return 0;
}
Пример #27
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;
}
Пример #28
0
int call_accept(struct call *call, struct sipsess_sock *sess_sock,
		const struct sip_msg *msg)
{
	bool got_offer;
	int err;

	if (!call || !msg)
		return EINVAL;

	call->outgoing = false;

	got_offer = (mbuf_get_left(msg->mb) > 0);

	err = pl_strdup(&call->peer_uri, &msg->from.auri);
	if (err)
		return err;

	if (pl_isset(&msg->from.dname)) {
		err = pl_strdup(&call->peer_name, &msg->from.dname);
		if (err)
			return err;
	}

	if (got_offer) {
		struct sdp_media *m;
		const struct sa *raddr;

		err = sdp_decode(call->sdp, msg->mb, true);
		if (err)
			return err;

		call->got_offer = true;

		/*
		 * Each media description in the SDP answer MUST
		 * use the same network type as the corresponding
		 * media description in the offer.
		 *
		 * See RFC 6157
		 */
		m = stream_sdpmedia(audio_strm(call->audio));
		raddr = sdp_media_raddr(m);

		if (sa_af(raddr) != call->af) {
			info("call: incompatible address-family"
			     " (local=%s, remote=%s)\n",
			     net_af2name(call->af),
			     net_af2name(sa_af(raddr)));

			sip_treply(NULL, uag_sip(), msg,
				   488, "Not Acceptable Here");

			call_event_handler(call, CALL_EVENT_CLOSED,
					   "Wrong address family");
			return 0;
		}

		/* Check if we have any common audio codecs, after
		 * the SDP offer has been parsed
		 */
		if (!have_common_audio_codecs(call)) {
			info("call: no common audio codecs - rejected\n");

			sip_treply(NULL, uag_sip(), msg,
				   488, "Not Acceptable Here");

			call_event_handler(call, CALL_EVENT_CLOSED,
					   "No audio codecs");

			return 0;
		}
	}

	err = sipsess_accept(&call->sess, sess_sock, msg, 180, "Ringing",
			     ua_cuser(call->ua), "application/sdp", NULL,
			     auth_handler, call->acc, true,
			     sipsess_offer_handler, sipsess_answer_handler,
			     sipsess_estab_handler, sipsess_info_handler,
			     sipsess_refer_handler, sipsess_close_handler,
			     call, "Allow: %s\r\n", uag_allowed_methods());
	if (err) {
		warning("call: sipsess_accept: %m\n", err);
		return err;
	}

	set_state(call, STATE_INCOMING);

	/* New call */
	tmr_start(&call->tmr_inv, LOCAL_TIMEOUT*1000, invite_timeout, call);

	if (!call->acc->mnat)
		call_event_handler(call, CALL_EVENT_INCOMING, call->peer_uri);

	return err;
}
Пример #29
0
/**
 * Allocate a new Call state object
 *
 * @param callp       Pointer to allocated Call state object
 * @param cfg         Global configuration
 * @param lst         List of call objects
 * @param local_name  Local display name (optional)
 * @param local_uri   Local SIP uri
 * @param acc         Account parameters
 * @param ua          User-Agent
 * @param prm         Call parameters
 * @param msg         SIP message for incoming calls
 * @param xcall       Optional call to inherit properties from
 * @param eh          Call event handler
 * @param arg         Handler argument
 *
 * @return 0 if success, otherwise errorcode
 */
int call_alloc(struct call **callp, const struct config *cfg, struct list *lst,
	       const char *local_name, const char *local_uri,
	       struct account *acc, struct ua *ua, const struct call_prm *prm,
	       const struct sip_msg *msg, struct call *xcall,
	       call_event_h *eh, void *arg)
{
	struct call *call;
	enum vidmode vidmode = prm ? prm->vidmode : VIDMODE_OFF;
	bool use_video = true, got_offer = false;
	int label = 0;
	int err = 0;

	if (!cfg || !local_uri || !acc || !ua)
		return EINVAL;

	call = mem_zalloc(sizeof(*call), call_destructor);
	if (!call)
		return ENOMEM;

	MAGIC_INIT(call);

	call->config_avt = cfg->avt;

	tmr_init(&call->tmr_inv);

	call->acc    = mem_ref(acc);
	call->ua     = ua;
	call->state  = STATE_IDLE;
	call->eh     = eh;
	call->arg    = arg;
	call->af     = prm ? prm->af : AF_INET;

	err = str_dup(&call->local_uri, local_uri);
	if (local_name)
		err |= str_dup(&call->local_name, local_name);
	if (err)
		goto out;

	/* Init SDP info */
	err = sdp_session_alloc(&call->sdp, net_laddr_af(call->af));
	if (err)
		goto out;

	err = sdp_session_set_lattr(call->sdp, true,
				    "tool", "baresip " BARESIP_VERSION);
	if (err)
		goto out;

	/* Check for incoming SDP Offer */
	if (msg && mbuf_get_left(msg->mb))
		got_offer = true;

	/* Initialise media NAT handling */
	if (acc->mnat) {
		err = acc->mnat->sessh(&call->mnats, net_dnsc(), call->af,
				       acc->stun_host, acc->stun_port,
				       acc->stun_user, acc->stun_pass,
				       call->sdp, !got_offer,
				       mnat_handler, call);
		if (err) {
			warning("call: medianat session: %m\n", err);
			goto out;
		}
	}
	call->mnat_wait = true;

	/* Media encryption */
	if (acc->menc) {
		if (acc->menc->sessh) {
			err = acc->menc->sessh(&call->mencs, call->sdp,
						!got_offer,
						menc_error_handler, call);
			if (err) {
				warning("call: mediaenc session: %m\n", err);
				goto out;
			}
		}
	}

	/* Audio stream */
	err = audio_alloc(&call->audio, cfg, call,
			  call->sdp, ++label,
			  acc->mnat, call->mnats, acc->menc, call->mencs,
			  acc->ptime, account_aucodecl(call->acc),
			  audio_event_handler, audio_error_handler, call);
	if (err)
		goto out;

#ifdef USE_VIDEO
	/* We require at least one video codec, and at least one
	   video source or video display */
	use_video = (vidmode != VIDMODE_OFF)
		&& (list_head(account_vidcodecl(call->acc)) != NULL)
		&& (NULL != vidsrc_find(NULL) || NULL != vidisp_find(NULL));

	/* Video stream */
	if (use_video) {
 		err = video_alloc(&call->video, cfg,
				  call, call->sdp, ++label,
				  acc->mnat, call->mnats,
				  acc->menc, call->mencs,
				  "main",
				  account_vidcodecl(call->acc),
				  video_error_handler, call);
		if (err)
			goto out;
 	}

	if (str_isset(cfg->bfcp.proto)) {

		err = bfcp_alloc(&call->bfcp, call->sdp,
				 cfg->bfcp.proto, !got_offer,
				 acc->mnat, call->mnats);
		if (err)
			goto out;
	}
#else
	(void)use_video;
	(void)vidmode;
#endif

	/* inherit certain properties from original call */
	if (xcall) {
		call->not = mem_ref(xcall->not);
	}

	list_append(lst, &call->le, call);

 out:
	if (err)
		mem_deref(call);
	else if (callp)
		*callp = call;

	return err;
}
Пример #30
0
int decode_h263(struct viddec_state *st, struct vidframe *frame,
		bool marker, uint16_t seq, struct mbuf *src)
{
	struct h263_hdr hdr;
	int err;

	if (!st || !frame)
		return EINVAL;

	if (!src)
		return 0;

	(void)seq;

	err = h263_hdr_decode(&hdr, src);
	if (err)
		return err;

#if 0
	debug(".....[%s seq=%5u ] MODE %s -"
	      " SBIT=%u EBIT=%u I=%s"
	      " (%5u/%5u bytes)\n",
	      marker ? "M" : " ", seq,
	      h263_hdr_mode(&hdr) == H263_MODE_A ? "A" : "B",
	      hdr.sbit, hdr.ebit, hdr.i ? "Inter" : "Intra",
	      mbuf_get_left(src), st->mb->end);
#endif

	if (!hdr.i)
		st->got_keyframe = true;

#if 0
	if (st->mb->pos == 0) {
		uint8_t *p = mbuf_buf(src);

		if (p[0] != 0x00 || p[1] != 0x00) {
			warning("invalid PSC detected (%02x %02x)\n",
				p[0], p[1]);
			return EPROTO;
		}
	}
#endif

	/*
	 * The H.263 Bit-stream can be fragmented on bit-level,
	 * indicated by SBIT and EBIT. Example:
	 *
	 *               8 bit  2 bit
	 *            .--------.--.
	 * Packet 1   |        |  |
	 * SBIT=0     '--------'--'
	 * EBIT=6
	 *                        .------.--------.--------.
	 * Packet 2               |      |        |        |
	 * SBIT=2                 '------'--------'--------'
	 * EBIT=0                   6bit    8bit     8bit
	 *
	 */

	if (hdr.sbit > 0) {
		const uint8_t mask  = (1 << (8 - hdr.sbit)) - 1;
		const uint8_t sbyte = mbuf_read_u8(src) & mask;

		st->mb->buf[st->mb->end - 1] |= sbyte;
	}

	return ffdecode(st, frame, marker, src);
}