Пример #1
0
/**
 * Accept an incoming SIP Session connection
 *
 * @param sessp     Pointer to allocated SIP Session
 * @param sock      SIP Session socket
 * @param msg       Incoming SIP message
 * @param scode     Response status code
 * @param reason    Response reason phrase
 * @param cuser     Contact username
 * @param ctype     Session content-type
 * @param desc      Content description (e.g. SDP)
 * @param authh     SIP Authentication handler
 * @param aarg      Authentication handler argument
 * @param aref      True to mem_ref() aarg
 * @param offerh    Session offer handler
 * @param answerh   Session answer handler
 * @param estabh    Session established handler
 * @param infoh     Session info handler
 * @param referh    Session refer handler
 * @param closeh    Session close handler
 * @param arg       Handler argument
 * @param fmt       Formatted strings with extra SIP Headers
 *
 * @return 0 if success, otherwise errorcode
 */
int sipsess_accept(struct sipsess **sessp, struct sipsess_sock *sock,
		   const struct sip_msg *msg, uint16_t scode,
		   const char *reason, const char *cuser, const char *ctype,
		   struct mbuf *desc,
		   sip_auth_h *authh, void *aarg, bool aref,
		   sipsess_offer_h *offerh, sipsess_answer_h *answerh,
		   sipsess_estab_h *estabh, sipsess_info_h *infoh,
		   sipsess_refer_h *referh, sipsess_close_h *closeh,
		   void *arg, const char *fmt, ...)
{
	struct sipsess *sess;
	va_list ap;
	int err;

	if (!sessp || !sock || !msg || scode < 101 || scode > 299 ||
	    !cuser || !ctype)
		return EINVAL;

	err = sipsess_alloc(&sess, sock, cuser, ctype, NULL, authh, aarg, aref,
			    offerh, answerh, NULL, estabh, infoh, referh,
			    closeh, arg);
	if (err)
		return err;

	err = sip_dialog_accept(&sess->dlg, msg);
	if (err)
		goto out;

	hash_append(sock->ht_sess,
		    hash_joaat_str(sip_dialog_callid(sess->dlg)),
		    &sess->he, sess);

	sess->msg = mem_ref((void *)msg);

	err = sip_strans_alloc(&sess->st, sess->sip, msg, cancel_handler,
			       sess);
	if (err)
		goto out;

	va_start(ap, fmt);

	if (scode >= 200)
		err = sipsess_reply_2xx(sess, msg, scode, reason, desc,
					fmt, &ap);
	else
		err = sip_treplyf(&sess->st, NULL, sess->sip,
				  msg, true, scode, reason,
				  "Contact: <sip:%s@%J%s>\r\n"
				  "%v"
				  "%s%s%s"
				  "Content-Length: %zu\r\n"
				  "\r\n"
				  "%b",
				  sess->cuser, &msg->dst,
				  sip_transp_param(msg->tp),
				  fmt, &ap,
				  desc ? "Content-Type: " : "",
				  desc ? sess->ctype : "",
				  desc ? "\r\n" : "",
				  desc ? mbuf_get_left(desc) : (size_t)0,
				  desc ? mbuf_buf(desc) : NULL,
				  desc ? mbuf_get_left(desc) : (size_t)0);

	va_end(ap);

	if (err)
		goto out;

 out:
	if (err)
		mem_deref(sess);
	else
		*sessp = sess;

	return err;
}
Пример #2
0
static int media_alloc(struct menc_media **stp, struct menc_sess *sess,
		 struct rtp_sock *rtp,
		 struct udp_sock *rtpsock, struct udp_sock *rtcpsock,
	         const struct sa *raddr_rtp,
	         const struct sa *raddr_rtcp,
		 struct sdp_media *sdpm)
{
	struct menc_st *st;
	const char *rattr = NULL;
	int layer = 10; /* above zero */
	int err = 0;
	bool mux = (rtpsock == rtcpsock);
	(void)sess;
	(void)rtp;
	(void)raddr_rtp;
	(void)raddr_rtcp;

	if (!stp || !sdpm || !sess)
		return EINVAL;

	st = (struct menc_st *)*stp;
	if (!st) {

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

		st->sess = sess;
		st->sdpm = mem_ref(sdpm);

		if (0 == str_cmp(sdp_media_proto(sdpm), "RTP/AVP")) {
			err = sdp_media_set_alt_protos(st->sdpm, 4,
						       "RTP/AVP",
						       "RTP/AVPF",
						       "RTP/SAVP",
						       "RTP/SAVPF");
			if (err)
				goto out;
		}

		if (rtpsock) {
			st->rtpsock = mem_ref(rtpsock);
			err |= udp_register_helper(&st->uh_rtp, rtpsock,
						   layer, send_handler,
						   recv_handler, st);
		}
		if (rtcpsock && !mux) {
			st->rtcpsock = mem_ref(rtcpsock);
			err |= udp_register_helper(&st->uh_rtcp, rtcpsock,
						   layer, send_handler,
						   recv_handler, st);
		}
		if (err)
			goto out;

		/* set our preferred crypto-suite */
		err |= str_dup(&st->crypto_suite, preferred_suite);
		if (err)
			goto out;

		rand_bytes(st->key_tx, sizeof(st->key_tx));
	}

	/* SDP handling */

	if (sdp_media_rport(sdpm))
		st->got_sdp = true;

	if (sdp_media_rattr(st->sdpm, "crypto")) {

		rattr = sdp_media_rattr_apply(st->sdpm, "crypto",
					      sdp_attr_handler, st);
		if (!rattr) {
			warning("srtp: no valid a=crypto attribute from"
				" remote peer\n");
		}
	}

	if (!rattr)
		err = sdp_enc(st, sdpm, 1, st->crypto_suite);

 out:
	if (err)
		mem_deref(st);
	else
		*stp = (struct menc_media *)st;

	return err;
}
Пример #3
0
/*
 * you can call this at any time
 *
 * @param addr HOST:     SA_ADDR portion is used
 *             non-HOST: SA_ADDR + SA_PORT portion is used
 *
 * @param base_addr  Optional
 * @param rel_addr   Optional
 *
 * @param layer  mandatory for HOST and RELAY candidates
 */
int trice_lcand_add(struct ice_lcand **lcandp, struct trice *icem,
		    unsigned compid, int proto,
		    uint32_t prio, const struct sa *addr,
		    const struct sa *base_addr,
		    enum ice_cand_type type, const struct sa *rel_addr,
		    enum ice_tcptype tcptype,
		    void *sock, int layer)
{
	struct ice_lcand *lcand;
	int err = 0;

	if (!icem || !compid || !proto || !addr)
		return EINVAL;

	if (!sa_isset(addr, SA_ADDR)) {
		DEBUG_WARNING("lcand_add: SA_ADDR is not set\n");
		return EINVAL;
	}
	if (type != ICE_CAND_TYPE_HOST) {
		if (!sa_isset(addr, SA_PORT)) {
			DEBUG_WARNING("lcand_add: %s: SA_PORT"
				      " must be set (%J)\n",
				      ice_cand_type2name(type), addr);
			return EINVAL;
		}
	}

	/* lookup candidate, replace if PRIO is higher */

	/* TODO: dont look up TCP-ACTIVE types for now (port is zero) */
	if (proto == IPPROTO_UDP) {

		lcand = trice_lcand_find(icem, -1, compid, proto, addr);
		if (lcand) {
			trice_printf(icem,
				    "add_local[%s.%J] --"
				    " candidate already exists"
				    " (%H)\n",
				    ice_cand_type2name(type), addr,
				    trice_cand_print, lcand);

			if (prio > lcand->attr.prio)
				lcand = mem_deref(lcand);
			else {
				goto out;
			}
		}
	}

	err = trice_add_lcandidate(&lcand, icem, &icem->lcandl, compid, NULL,
				   proto, prio, addr, base_addr,
				   type, rel_addr, tcptype);
	if (err)
		return err;

	if (type == ICE_CAND_TYPE_HOST) {

		switch (proto) {

		case IPPROTO_UDP:
			if (sock) {
				struct sa laddr;

				lcand->us = mem_ref(sock);

				err = udp_local_get(lcand->us,
						    &laddr);
				if (err)
					goto out;

				lcand->attr.addr = *addr;
				sa_set_port(&lcand->attr.addr,
					    sa_port(&laddr));
			}
			else {
				err = udp_listen(&lcand->us, addr,
						 dummy_udp_recv, lcand);
				if (err)
					goto out;

				err = udp_local_get(lcand->us,
						    &lcand->attr.addr);
				if (err)
					goto out;
			}

			err = udp_register_helper(&lcand->uh, lcand->us,
						  layer,
						  udp_helper_send_handler,
						  udp_helper_recv_handler,
						  lcand);
			if (err)
				goto out;
			break;

		case IPPROTO_TCP:

			/* TCP-transport has 3 variants:
			   active, passive, so */

			if (lcand->attr.tcptype == ICE_TCP_ACTIVE) {

				/* the port MUST be set to 9 (i.e., Discard) */
				/*sa_set_port(&lcand->attr.addr, 9); */
			}
			else if (lcand->attr.tcptype == ICE_TCP_PASSIVE ||
				 lcand->attr.tcptype == ICE_TCP_SO) {

				err = tcp_listen(&lcand->ts, addr,
						 tcp_conn_handler, lcand);
				if (err)
					goto out;
				err = tcp_local_get(lcand->ts,
						    &lcand->attr.addr);
				if (err)
					goto out;
			}
			else {
				err = EPROTONOSUPPORT;
				goto out;
			}
			break;

		default:
			err = EPROTONOSUPPORT;
			goto out;
		}
	}
	else if (type == ICE_CAND_TYPE_RELAY) {

		switch (proto) {

		case IPPROTO_UDP:

			if (sock) {
				lcand->us = mem_ref(sock);
			}
			else {
				err = udp_listen(&lcand->us, NULL,
						 dummy_udp_recv, lcand);
				if (err)
					goto out;
			}

			err = udp_register_helper(&lcand->uh, lcand->us,
						  layer,
						  udp_helper_send_handler,
						  udp_helper_recv_handler,
						  lcand);
			if (err)
				goto out;

			break;

		default:
			err = EPROTONOSUPPORT;
			goto out;
		}
	}
	else if (type == ICE_CAND_TYPE_SRFLX ||
		 type == ICE_CAND_TYPE_PRFLX) {

		/* Special case for SRFLX UDP candidates, if he has
		 * its own UDP-socket that can be used.
		 */
		if (proto == IPPROTO_UDP && sock) {

			lcand->us = mem_ref(sock);

			err = udp_register_helper(&lcand->uh, lcand->us,
						  layer,
						  udp_helper_send_handler,
						  udp_helper_recv_handler,
						  lcand);
			if (err)
				goto out;
		}
	}

	lcand->layer = layer;

	/* pair this local-candidate with all existing remote-candidates */
	err = trice_candpair_with_local(icem, lcand);
	if (err)
		goto out;

	/* new pair -- refresh the checklist timer */
	trice_checklist_refresh(icem);

 out:
	if (err)
		mem_deref(lcand);
	else if (lcandp)
		*lcandp = lcand;

	return err;
}
Пример #4
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
		}
	}
}
Пример #5
0
static void tcp_recv_handler(struct mbuf *mbx, void *arg)
{
	struct candidate *tl = arg;
	int err = 0;

	if (tl->mb) {
		size_t pos;

		pos = tl->mb->pos;

		tl->mb->pos = tl->mb->end;

		err = mbuf_write_mem(tl->mb, mbuf_buf(mbx),
				     mbuf_get_left(mbx));
		if (err)
			goto out;

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

	for (;;) {

		size_t len, pos, end;
		uint16_t typ;

		if (mbuf_get_left(tl->mb) < 4)
			break;

		/* STUN Header */
		typ = ntohs(mbuf_read_u16(tl->mb));
		len = ntohs(mbuf_read_u16(tl->mb));

		if (typ < 0x4000)
			len += STUN_HEADER_SIZE;
		else if (typ < 0x8000)
			len += 4;
		else {
			err = EBADMSG;
			goto out;
		}

		tl->mb->pos -= 4;

		if (mbuf_get_left(tl->mb) < len)
			break;

		pos = tl->mb->pos;
		end = tl->mb->end;

		tl->mb->end = pos + len;

		handle_packet(tl, tl->mb);

		/* 4 byte alignment */
		while (len & 0x03)
			++len;

		tl->mb->pos = pos + len;
		tl->mb->end = end;

		if (tl->mb->pos >= tl->mb->end) {
			tl->mb = mem_deref(tl->mb);
			break;
		}
	}

 out:
	if (err) {
		re_printf("tcp recv error (%m)\n", err);
	}
}
Пример #6
0
/**
 * Put one frame into the jitter buffer
 *
 * @param jb   Jitter buffer
 * @param hdr  RTP Header
 * @param mem  Memory pointer - will be referenced
 *
 * @return 0 if success, otherwise errorcode
 */
int jbuf_put(struct jbuf *jb, const struct rtp_header *hdr, void *mem)
{
	struct frame *f;
	struct le *le, *tail;
	uint16_t seq;
	int err = 0;

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

	seq = hdr->seq;

	STAT_INC(n_put);

	if (jb->running) {

		/* Packet arrived too late to be put into buffer */
		if (seq_less((seq + jb->n), jb->seq_put)) {
			STAT_INC(n_late);
			DEBUG_INFO("packet too late: seq=%u (seq_put=%u)\n",
				   seq, jb->seq_put);
			return ETIMEDOUT;
		}
	}

	frame_alloc(jb, &f);

	tail = jb->framel.tail;

	/* If buffer is empty -> append to tail
	   Frame is later than tail -> append to tail
	*/
	if (!tail || seq_less(((struct frame *)tail->data)->hdr.seq, seq)) {
		list_append(&jb->framel, &f->le, f);
		goto out;
	}

	/* Out-of-sequence, find right position */
	for (le = tail; le; le = le->prev) {
		const uint16_t seq_le = ((struct frame *)le->data)->hdr.seq;

		if (seq_less(seq_le, seq)) { /* most likely */
			DEBUG_INFO("put: out-of-sequence"
				   " - inserting after seq=%u (seq=%u)\n",
				   seq_le, seq);
			list_insert_after(&jb->framel, le, &f->le, f);
			break;
		}
		else if (seq == seq_le) { /* less likely */
			/* Detect duplicates */
			DEBUG_INFO("duplicate: seq=%u\n", seq);
			STAT_INC(n_dups);
			list_insert_after(&jb->framel, le, &f->le, f);
			frame_deref(jb, f);
			return EALREADY;
		}

		/* sequence number less than current seq, continue */
	}

	/* no earlier timestamps found, put in head */
	if (!le) {
		DEBUG_INFO("put: out-of-sequence"
			   " - put in head (seq=%u)\n", seq);
		list_prepend(&jb->framel, &f->le, f);
	}

	STAT_INC(n_oos);

 out:
	/* Update last timestamp */
	jb->running = true;
	jb->seq_put = seq;

	/* Success */
	f->hdr = *hdr;
	f->mem = mem_ref(mem);

	return err;
}
Пример #7
0
/**
 * Initialize a SIP Dialog from an incoming SIP Message
 *
 * @param dlg SIP Dialog to initialize
 * @param msg SIP Message
 *
 * @return 0 if success, otherwise errorcode
 */
int sip_dialog_create(struct sip_dialog *dlg, const struct sip_msg *msg)
{
	char *uri = NULL, *rtag = NULL;
	const struct sip_hdr *contact;
	struct route_enc renc;
	struct sip_addr addr;
	struct pl pl;
	int err;

	if (!dlg || dlg->rtag || !dlg->cpos || !msg)
		return EINVAL;

	contact = sip_msg_hdr(msg, SIP_HDR_CONTACT);

	if (!contact)
		return EBADMSG;

	if (sip_addr_decode(&addr, &contact->val))
		return EBADMSG;

	renc.mb = mbuf_alloc(512);
	if (!renc.mb)
		return ENOMEM;

	err = pl_strdup(&uri, &addr.auri);
	if (err)
		goto out;

	err = pl_strdup(&rtag, msg->req ? &msg->from.tag : &msg->to.tag);
	if (err)
		goto out;

	renc.end = 0;

	err |= sip_msg_hdr_apply(msg, msg->req, SIP_HDR_RECORD_ROUTE,
				 record_route_handler, &renc) ? ENOMEM : 0;
	err |= mbuf_printf(renc.mb, "To: %r\r\n",
			   msg->req ? &msg->from.val : &msg->to.val);

	dlg->mb->pos = dlg->cpos;
	err |= mbuf_write_mem(renc.mb, mbuf_buf(dlg->mb),
			      mbuf_get_left(dlg->mb));
	dlg->mb->pos = 0;

	if (err)
		goto out;

	renc.mb->pos = 0;

	if (renc.end) {
		pl.p = (const char *)mbuf_buf(renc.mb) + ROUTE_OFFSET;
		pl.l = renc.end - ROUTE_OFFSET;
		err = sip_addr_decode(&addr, &pl);
		if (err)
			goto out;

		dlg->route = addr.uri;
	}
	else {
		struct uri tmp;

		pl_set_str(&pl, uri);
		err = uri_decode(&tmp, &pl);
		if (err)
			goto out;

		dlg->route = tmp;
	}

	mem_deref(dlg->mb);
	mem_deref(dlg->uri);

	dlg->mb   = mem_ref(renc.mb);
	dlg->rtag = mem_ref(rtag);
	dlg->uri  = mem_ref(uri);
	dlg->rseq = msg->req ? msg->cseq.num : 0;
	dlg->cpos = 0;

 out:
	mem_deref(renc.mb);
	mem_deref(rtag);
	mem_deref(uri);

	return err;
}
Пример #8
0
int sdp_format_add(struct sdp_format **fmtp, struct sdp_media *m,
		   bool prepend, const char *id, const char *name,
		   uint32_t srate, uint8_t ch,
		   sdp_fmtp_cmp_h *cmph, void *data, bool ref,
		   const char *params, ...)
{
	struct sdp_format *fmt;
	int err;

	if (!m)
		return EINVAL;

	if (!id && (m->dynpt > RTP_DYNPT_END))
		return ERANGE;

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

	if (prepend)
		list_prepend(&m->lfmtl, &fmt->le, fmt);
	else
		list_append(&m->lfmtl, &fmt->le, fmt);

	if (id)
		err = str_dup(&fmt->id, id);
	else
		err = re_sdprintf(&fmt->id, "%i", m->dynpt++);
	if (err)
		goto out;

	if (name) {
		err = str_dup(&fmt->name, name);
		if (err)
			goto out;
	}

	if (params) {
		va_list ap;

		va_start(ap, params);
		err = re_vsdprintf(&fmt->params, params, ap);
		va_end(ap);

		if (err)
			goto out;
	}

	fmt->pt    = atoi(fmt->id);
	fmt->srate = srate;
	fmt->ch    = ch;
	fmt->cmph  = cmph;
	fmt->data  = ref ? mem_ref(data) : data;
	fmt->ref   = ref;
	fmt->sup   = true;

 out:
	if (err)
		mem_deref(fmt);
	else if (fmtp)
		*fmtp = fmt;

	return err;
}
Пример #9
0
int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock,
		    const struct sip_msg *msg, struct sip_dialog *dlg,
		    const struct sipevent_event *event,
		    uint16_t scode, const char *reason, uint32_t expires_min,
		    uint32_t expires_dfl, uint32_t expires_max,
		    const char *cuser, const char *ctype,
		    sip_auth_h *authh, void *aarg, bool aref,
		    sipnot_close_h *closeh, void *arg, const char *fmt, ...)
{
	struct sipnot *not;
	uint32_t expires;
	int err;

	if (!notp || !sock || !msg || !scode || !reason || !expires_dfl ||
	    !expires_max || !cuser || !ctype || expires_dfl < expires_min)
		return EINVAL;

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

	if (!pl_strcmp(&msg->met, "REFER")) {

		err = str_dup(&not->event, "refer");
		if (err)
			goto out;

		err = re_sdprintf(&not->id, "%u", msg->cseq.num);
		if (err)
			goto out;
	}
	else {
		if (!event) {
			err = EINVAL;
			goto out;
		}

		err = pl_strdup(&not->event, &event->event);
		if (err)
			goto out;

		if (pl_isset(&event->id)) {

			err = pl_strdup(&not->id, &event->id);
			if (err)
				goto out;
		}
	}

	if (dlg) {
		not->dlg = mem_ref(dlg);
	}
	else {
		err = sip_dialog_accept(&not->dlg, msg);
		if (err)
			goto out;
	}

	hash_append(sock->ht_not,
		    hash_joaat_str(sip_dialog_callid(not->dlg)),
		    &not->he, not);

	err = sip_auth_alloc(&not->auth, authh, aarg, aref);
	if (err)
		goto out;

	err = str_dup(&not->cuser, cuser);
	if (err)
		goto out;

	err = str_dup(&not->ctype, ctype);
	if (err)
		goto out;

	if (fmt) {
		va_list ap;

		va_start(ap, fmt);
		err = re_vsdprintf(&not->hdrs, fmt, ap);
		va_end(ap);
		if (err)
			goto out;
	}

	not->expires_min = expires_min;
	not->expires_dfl = expires_dfl;
	not->expires_max = expires_max;
	not->substate = SIPEVENT_PENDING;
	not->sock   = mem_ref(sock);
	not->sip    = mem_ref(sock->sip);
	not->closeh = closeh ? closeh : internal_close_handler;
	not->arg    = arg;

	if (pl_isset(&msg->expires))
		expires = pl_u32(&msg->expires);
	else
		expires = not->expires_dfl;

	sipnot_refresh(not, expires);

	err = sipnot_reply(not, msg, scode, reason);
	if (err)
		goto out;

	not->subscribed = true;

 out:
	if (err)
		mem_deref(not);
	else
		*notp = not;

	return err;
}
Пример #10
0
/**
 * Decode a HTTP message
 *
 * @param msgp Pointer to allocated HTTP Message
 * @param mb   Buffer containing HTTP Message
 * @param req  True for request, false for response
 *
 * @return 0 if success, otherwise errorcode
 */
int http_msg_decode(struct http_msg **msgp, struct mbuf *mb, bool req)
{
	struct pl b, s, e, name, scode;
	const char *p, *cv;
	struct http_msg *msg;
	bool comsep, quote;
	enum http_hdrid id = HTTP_HDR_NONE;
	uint32_t ws, lf;
	size_t l;
	int err;

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

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

	if (re_regex(p, l, "[\r\n]*[^\r\n]+[\r]*[\n]1", &b, &s, NULL, &e))
		return (l > STARTLINE_MAX) ? EBADMSG : ENODATA;

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

	msg->mb = mem_ref(mb);

	if (req) {
		if (re_regex(s.p, s.l, "[a-z]+ [^? ]+[^ ]* HTTP/[0-9.]+",
			     &msg->met, &msg->path, &msg->prm, &msg->ver) ||
		    msg->met.p != s.p) {
			err = EBADMSG;
			goto out;
		}
	}
	else {
		if (re_regex(s.p, s.l, "HTTP/[0-9.]+ [0-9]+ [^]*",
			     &msg->ver, &scode, &msg->reason) ||
		    msg->ver.p != s.p + 5) {
			err = EBADMSG;
			goto out;
		}

		msg->scode = pl_u32(&scode);
	}

	l -= e.p + e.l - p;
	p = e.p + e.l;

	name.p = cv = NULL;
	name.l = ws = lf = 0;
	comsep = false;
	quote = false;

	for (; l > 0; p++, l--) {

		switch (*p) {

		case ' ':
		case '\t':
			lf = 0; /* folding */
			++ws;
			break;

		case '\r':
			++ws;
			break;

		case '\n':
			++ws;

			if (!name.p) {
				++p; --l; /* no headers */
				err = 0;
				goto out;
			}

			if (!lf++)
				break;

			++p; --l; /* eoh */

			/*@fallthrough@*/

		default:
			if (lf || (*p == ',' && comsep && !quote)) {

				if (!name.l) {
					err = EBADMSG;
					goto out;
				}

				err = hdr_add(msg, &name, id, cv ? cv : p,
					      cv ? p - cv - ws : 0);
				if (err)
					goto out;

				if (!lf) { /* comma separated */
					cv = NULL;
					break;
				}

				if (lf > 1) { /* eoh */
					err = 0;
					goto out;
				}

				comsep = false;
				name.p = NULL;
				cv = NULL;
				lf = 0;
			}

			if (!name.p) {
				name.p = p;
				name.l = 0;
				ws = 0;
			}

			if (!name.l) {
				if (*p != ':') {
					ws = 0;
					break;
				}

				name.l = MAX((int)(p - name.p - ws), 0);
				if (!name.l) {
					err = EBADMSG;
					goto out;
				}

				id = hdr_hash(&name);
				comsep = hdr_comma_separated(id);
				break;
			}

			if (!cv) {
				quote = false;
				cv = p;
			}

			if (*p == '"')
				quote = !quote;

			ws = 0;
			break;
		}
	}

	err = ENODATA;

 out:
	if (err)
		mem_deref(msg);
	else {
		*msgp = msg;
		mb->pos = mb->end - l;
	}

	return err;
}
Пример #11
0
/**
 * Add a SIP transport
 *
 * @param sip   SIP stack instance
 * @param tp    SIP Transport
 * @param laddr Local network address
 * @param ...   Optional transport parameters such as TLS context
 *
 * @return 0 if success, otherwise errorcode
 */
int sip_transp_add(struct sip *sip, enum sip_transp tp,
		   const struct sa *laddr, ...)
{
	struct sip_transport *transp;
	struct tls *tls;
	va_list ap;
	int err;

	if (!sip || !laddr || !sa_isset(laddr, SA_ADDR))
		return EINVAL;

	transp = mem_zalloc(sizeof(*transp), transp_destructor);
	if (!transp)
		return ENOMEM;

	list_append(&sip->transpl, &transp->le, transp);
	transp->sip = sip;
	transp->tp  = tp;

	va_start(ap, laddr);

	switch (tp) {

	case SIP_TRANSP_UDP:
		err = udp_listen((struct udp_sock **)&transp->sock, laddr,
				 udp_recv_handler, transp);
		if (err)
			break;

		err = udp_local_get(transp->sock, &transp->laddr);
		break;

	case SIP_TRANSP_TLS:
		tls = va_arg(ap, struct tls *);
		if (!tls) {
			err = EINVAL;
			break;
		}

		transp->tls = mem_ref(tls);

		/*@fallthrough@*/

	case SIP_TRANSP_TCP:
		err = tcp_listen((struct tcp_sock **)&transp->sock, laddr,
				 tcp_connect_handler, transp);
		if (err)
			break;

		err = tcp_sock_local_get(transp->sock, &transp->laddr);
		break;

	default:
		err = EPROTONOSUPPORT;
		break;
	}

	va_end(ap);

	if (err)
		mem_deref(transp);

	return err;
}
Пример #12
0
static int conn_send(struct sip_connqent **qentp, struct sip *sip, bool secure,
		     const struct sa *dst, struct mbuf *mb,
		     sip_transp_h *transph, void *arg)
{
	struct sip_conn *conn, *new_conn = NULL;
	struct sip_connqent *qent;
	int err = 0;

	conn = conn_find(sip, dst, secure);
	if (conn) {
		if (!conn->established)
			goto enqueue;

		return tcp_send(conn->tc, mb);
	}

	new_conn = conn = mem_zalloc(sizeof(*conn), conn_destructor);
	if (!conn)
		return ENOMEM;

	hash_append(sip->ht_conn, sa_hash(dst, SA_ALL), &conn->he, conn);
	conn->paddr = *dst;
	conn->sip   = sip;

	err = tcp_connect(&conn->tc, dst, tcp_estab_handler, tcp_recv_handler,
			  tcp_close_handler, conn);
	if (err)
		goto out;

	err = tcp_conn_local_get(conn->tc, &conn->laddr);
	if (err)
		goto out;

#ifdef USE_TLS
	if (secure) {
		const struct sip_transport *transp;

		transp = transp_find(sip, SIP_TRANSP_TLS, sa_af(dst), dst);
		if (!transp || !transp->tls) {
			err = EPROTONOSUPPORT;
			goto out;
		}

		err = tls_start_tcp(&conn->sc, transp->tls, conn->tc, 0);
		if (err)
			goto out;
	}
#endif

	tmr_start(&conn->tmr, TCP_IDLE_TIMEOUT * 1000, conn_tmr_handler, conn);

 enqueue:
	qent = mem_zalloc(sizeof(*qent), qent_destructor);
	if (!qent) {
		err = ENOMEM;
		goto out;

	}

	list_append(&conn->ql, &qent->le, qent);
	qent->mb = mem_ref(mb);
	qent->transph = transph ? transph : internal_transport_handler;
	qent->arg = arg;

	if (qentp) {
		qent->qentp = qentp;
		*qentp = qent;
	}

 out:
	if (err)
		mem_deref(new_conn);

	return err;
}
Пример #13
0
static void tcp_recv_handler(struct mbuf *mb, void *arg)
{
	struct sip_conn *conn = arg;
	size_t pos;
	int err = 0;

	if (conn->mb) {
		pos = conn->mb->pos;

		conn->mb->pos = conn->mb->end;

		err = mbuf_write_mem(conn->mb, mbuf_buf(mb),mbuf_get_left(mb));
		if (err)
			goto out;

		conn->mb->pos = pos;

		if (mbuf_get_left(conn->mb) > TCP_BUFSIZE_MAX) {
			err = EOVERFLOW;
			goto out;
		}
	}
	else {
		conn->mb = mem_ref(mb);
	}

	for (;;) {
		struct sip_msg *msg;
		uint32_t clen;
		size_t end;

		if (mbuf_get_left(conn->mb) < 2)
			break;

		if (!memcmp(mbuf_buf(conn->mb), "\r\n", 2)) {

			tmr_start(&conn->tmr, TCP_IDLE_TIMEOUT * 1000,
				  conn_tmr_handler, conn);

			conn->mb->pos += 2;

			if (mbuf_get_left(conn->mb) >= 2 &&
			    !memcmp(mbuf_buf(conn->mb), "\r\n", 2)) {

				struct mbuf mbr;

				conn->mb->pos += 2;

				mbr.buf  = crlfcrlf;
				mbr.size = sizeof(crlfcrlf);
				mbr.pos  = 0;
				mbr.end  = 2;

				err = tcp_send(conn->tc, &mbr);
				if (err)
					break;
			}

			if (mbuf_get_left(conn->mb))
				continue;

			conn->mb = mem_deref(conn->mb);
			break;
		}

		pos = conn->mb->pos;

		err = sip_msg_decode(&msg, conn->mb);
		if (err) {
			if (err == ENODATA)
				err = 0;
			break;
		}

		if (!msg->clen.p) {
			mem_deref(msg);
			err = EBADMSG;
			break;
		}

		clen = pl_u32(&msg->clen);

		if (mbuf_get_left(conn->mb) < clen) {
			conn->mb->pos = pos;
			mem_deref(msg);
			break;
		}

		tmr_start(&conn->tmr, TCP_IDLE_TIMEOUT * 1000,
			  conn_tmr_handler, conn);

		end = conn->mb->end;

		msg->mb->end = msg->mb->pos + clen;
		msg->sock = mem_ref(conn);
		msg->src = conn->paddr;
		msg->dst = conn->laddr;
		msg->tp = conn->sc ? SIP_TRANSP_TLS : SIP_TRANSP_TCP;

		sip_recv(conn->sip, msg);
		mem_deref(msg);

		if (end <= conn->mb->end) {
			conn->mb = mem_deref(conn->mb);
			break;
		}

		mb = mbuf_alloc(end - conn->mb->end);
		if (!mb) {
			err = ENOMEM;
			goto out;
		}

		(void)mbuf_write_mem(mb, &conn->mb->buf[conn->mb->end],
				     end - conn->mb->end);

		mb->pos = 0;

		mem_deref(conn->mb);
		conn->mb = mb;
	}

 out:
	if (err) {
		conn_close(conn, err);
		mem_deref(conn);
	}
}
Пример #14
0
int audiosess_alloc(struct audiosess_st **stp,
		    audiosess_int_h *inth, void *arg)
{
	struct audiosess_st *st = NULL;
	struct audiosess *as = NULL;
	int err = 0;
	bool created = false;
#if TARGET_OS_IPHONE
	AudioSessionPropertyID id = kAudioSessionProperty_AudioRouteChange;
	UInt32 category;
	OSStatus ret;
#endif

	if (!stp)
		return EINVAL;

#if TARGET_OS_IPHONE
	/* Must be done for all modules */
	category = kAudioSessionCategory_PlayAndRecord;
	ret = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
				      sizeof(category), &category);
	if (ret) {
		re_fprintf(stderr, "Audio Category: %d\n", ret);
		return EINVAL;
	}
#endif

	if (gas)
		goto makesess;

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

#if TARGET_OS_IPHONE
	ret = AudioSessionSetActive(true);
	if (ret) {
		re_fprintf(stderr, "AudioSessionSetActive: %d\n", ret);
		err = ENOSYS;
		goto out;
	}

	ret = AudioSessionAddPropertyListener(id, propListener, as);
	if (ret) {
		re_fprintf(stderr, "AudioSessionAddPropertyListener: %d\n",
			   ret);
		err = EINVAL;
		goto out;
	}
#endif

	gas = as;
	created = true;

 makesess:
	st = mem_zalloc(sizeof(*st), sess_destructor);
	if (!st) {
		err = ENOMEM;
		goto out;
	}
	st->inth = inth;
	st->arg = arg;
	st->as = created ? gas : mem_ref(gas);

	list_append(&gas->sessl, &st->le, st);

 out:
	if (err) {
		mem_deref(as);
		mem_deref(st);
	}
	else {
		*stp = st;
	}

	return err;
}
Пример #15
0
/**
 * Fork a SIP Dialog from an incoming SIP Message
 *
 * @param dlgp Pointer to allocated SIP Dialog
 * @param odlg Original SIP Dialog
 * @param msg  SIP Message
 *
 * @return 0 if success, otherwise errorcode
 */
int sip_dialog_fork(struct sip_dialog **dlgp, struct sip_dialog *odlg,
		    const struct sip_msg *msg)
{
	const struct sip_hdr *contact;
	struct sip_dialog *dlg;
	struct route_enc renc;
	struct sip_addr addr;
	struct pl pl;
	int err;

	if (!dlgp || !odlg || !odlg->cpos || !msg)
		return EINVAL;

	contact = sip_msg_hdr(msg, SIP_HDR_CONTACT);

	if (!contact || !msg->callid.p)
		return EBADMSG;

	if (sip_addr_decode(&addr, &contact->val))
		return EBADMSG;

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

	dlg->callid = mem_ref(odlg->callid);
	dlg->ltag   = mem_ref(odlg->ltag);
	dlg->lseq   = odlg->lseq;
	dlg->rseq   = msg->req ? msg->cseq.num : 0;

	err = pl_strdup(&dlg->uri, &addr.auri);
	if (err)
		goto out;

	err = pl_strdup(&dlg->rtag, msg->req ? &msg->from.tag : &msg->to.tag);
	if (err)
		goto out;

	dlg->mb = mbuf_alloc(512);
	if (!dlg->mb) {
		err = ENOMEM;
		goto out;
	}

	renc.mb  = dlg->mb;
	renc.end = 0;

	err |= sip_msg_hdr_apply(msg, msg->req, SIP_HDR_RECORD_ROUTE,
				 record_route_handler, &renc) ? ENOMEM : 0;
	err |= mbuf_printf(dlg->mb, "To: %r\r\n",
			   msg->req ? &msg->from.val : &msg->to.val);

	odlg->mb->pos = odlg->cpos;
	err |= mbuf_write_mem(dlg->mb, mbuf_buf(odlg->mb),
			      mbuf_get_left(odlg->mb));
	odlg->mb->pos = 0;

	if (err)
		goto out;

	dlg->mb->pos = 0;

	if (renc.end) {
		pl.p = (const char *)mbuf_buf(dlg->mb) + ROUTE_OFFSET;
		pl.l = renc.end - ROUTE_OFFSET;
		err = sip_addr_decode(&addr, &pl);
		dlg->route = addr.uri;
	}
	else {
		pl_set_str(&pl, dlg->uri);
		err = uri_decode(&dlg->route, &pl);
	}

 out:
	if (err)
		mem_deref(dlg);
	else
		*dlgp = dlg;

	return err;
}
Пример #16
0
/**
 * Allocate a SIP Registration client
 *
 * @param regp     Pointer to allocated SIP Registration client
 * @param sip      SIP Stack instance
 * @param reg_uri  SIP Request URI
 * @param to_uri   SIP To-header URI
 * @param from_uri SIP From-header URI
 * @param expires  Registration interval in [seconds]
 * @param cuser    Contact username
 * @param routev   Optional route vector
 * @param routec   Number of routes
 * @param regid    Register identification
 * @param authh    Authentication handler
 * @param aarg     Authentication handler argument
 * @param aref     True to ref argument
 * @param resph    Response handler
 * @param arg      Response handler argument
 * @param params   Optional Contact-header parameters
 * @param fmt      Formatted strings with extra SIP Headers
 *
 * @return 0 if success, otherwise errorcode
 */
int sipreg_register(struct sipreg **regp, struct sip *sip, const char *reg_uri,
		    const char *to_uri, const char *from_uri, uint32_t expires,
		    const char *cuser, const char *routev[], uint32_t routec,
		    int regid, sip_auth_h *authh, void *aarg, bool aref,
		    sip_resp_h *resph, void *arg,
		    const char *params, const char *fmt, ...)
{
	struct sipreg *reg;
	int err;

	if (!regp || !sip || !reg_uri || !to_uri || !from_uri ||
	    !expires || !cuser)
		return EINVAL;

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

	err = sip_dialog_alloc(&reg->dlg, reg_uri, to_uri, NULL, from_uri,
			       routev, routec);
	if (err)
		goto out;

	err = sip_auth_alloc(&reg->auth, authh, aarg, aref);
	if (err)
		goto out;

	err = str_dup(&reg->cuser, cuser);
	if (params)
		err |= str_dup(&reg->params, params);
	if (err)
		goto out;

	/* Custom SIP headers */
	if (fmt) {
		va_list ap;

		reg->hdrs = mbuf_alloc(256);
		if (!reg->hdrs) {
			err = ENOMEM;
			goto out;
		}

		va_start(ap, fmt);
		err = mbuf_vprintf(reg->hdrs, fmt, ap);
		reg->hdrs->pos = 0;
		va_end(ap);

		if (err)
			goto out;
	}

	reg->sip     = mem_ref(sip);
	reg->expires = expires;
	reg->resph   = resph ? resph : dummy_handler;
	reg->arg     = arg;
	reg->regid   = regid;

	err = request(reg, true);
	if (err)
		goto out;

 out:
	if (err)
		mem_deref(reg);
	else
		*regp = reg;

	return err;
}
Пример #17
0
static int alloc(struct menc_media **stp, struct menc_sess *sess,
		 struct rtp_sock *rtp,
		 int proto, void *rtpsock, void *rtcpsock,
		 struct sdp_media *sdpm)
{
	struct menc_st *st;
	const char *rattr = NULL;
	int layer = 10; /* above zero */
	int err = 0;
	bool mux = (rtpsock == rtcpsock);
	(void)sess;
	(void)rtp;

	if (!stp || !sdpm)
		return EINVAL;
	if (proto != IPPROTO_UDP)
		return EPROTONOSUPPORT;

	st = (struct menc_st *)*stp;
	if (!st) {

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

		st->sdpm = mem_ref(sdpm);

		err = sdp_media_set_alt_protos(st->sdpm, 4,
					       "RTP/AVP",
					       "RTP/AVPF",
					       "RTP/SAVP",
					       "RTP/SAVPF");
		if (err)
			goto out;

		if (rtpsock) {
			st->rtpsock = mem_ref(rtpsock);
			err |= udp_register_helper(&st->uh_rtp, rtpsock,
						   layer, send_handler,
						   recv_handler, st);
		}
		if (rtcpsock && !mux) {
			st->rtcpsock = mem_ref(rtcpsock);
			err |= udp_register_helper(&st->uh_rtcp, rtcpsock,
						   layer, send_handler,
						   recv_handler, st);
		}
		if (err)
			goto out;

		/* set our preferred crypto-suite */
		err |= str_dup(&st->crypto_suite, aes_cm_128_hmac_sha1_80);
		if (err)
			goto out;

		err = setup_srtp(st);
		if (err)
			goto out;
	}

	/* SDP handling */

	if (sdp_media_rattr(st->sdpm, "crypto")) {

		rattr = sdp_media_rattr_apply(st->sdpm, "crypto",
					      sdp_attr_handler, st);
		if (!rattr) {
			DEBUG_WARNING("no valid a=crypto attribute from"
				      " remote peer\n");
		}
	}

	if (!rattr)
		err = sdp_enc(st, sdpm, 0, st->crypto_suite);

 out:
	if (err)
		mem_deref(st);
	else
		*stp = (struct menc_media *)st;

	return err;
}
Пример #18
0
int coreaudio_player_alloc(struct auplay_st **stp, struct auplay *ap,
			   struct auplay_prm *prm, const char *device,
			   auplay_write_h *wh, void *arg)
{
	AudioStreamBasicDescription fmt;
	struct auplay_st *st;
	uint32_t bytc, i;
	OSStatus status;
	int err;

	(void)device;

	st = mem_zalloc(sizeof(*st), auplay_destructor);
	if (!st)
		return ENOMEM;

	st->ap  = mem_ref(ap);
	st->wh  = wh;
	st->arg = arg;

	err = pthread_mutex_init(&st->mutex, NULL);
	if (err)
		goto out;

	err = audio_session_enable();
	if (err)
		goto out;

	fmt.mSampleRate       = (Float64)prm->srate;
	fmt.mFormatID         = audio_fmt(prm->fmt);
	fmt.mFormatFlags      = kLinearPCMFormatFlagIsSignedInteger |
		                kAudioFormatFlagIsPacked;
#ifdef __BIG_ENDIAN__
	fmt.mFormatFlags     |= kAudioFormatFlagIsBigEndian;
#endif
	fmt.mFramesPerPacket  = 1;
	fmt.mBytesPerFrame    = prm->ch * bytesps(prm->fmt);
	fmt.mBytesPerPacket   = prm->ch * bytesps(prm->fmt);
	fmt.mChannelsPerFrame = prm->ch;
	fmt.mBitsPerChannel   = 8*bytesps(prm->fmt);

	status = AudioQueueNewOutput(&fmt, play_handler, st, NULL,
				     kCFRunLoopCommonModes, 0, &st->queue);
	if (status) {
		re_fprintf(stderr, "AudioQueueNewOutput error: %i\n", status);
		err = ENODEV;
		goto out;
	}

	bytc = prm->frame_size * bytesps(prm->fmt);

	for (i=0; i<ARRAY_SIZE(st->buf); i++)  {

		status = AudioQueueAllocateBuffer(st->queue, bytc,
						  &st->buf[i]);
		if (status)  {
			err = ENOMEM;
			goto out;
		}

		st->buf[i]->mAudioDataByteSize = bytc;

		memset(st->buf[i]->mAudioData, 0,
		       st->buf[i]->mAudioDataByteSize);

		(void)AudioQueueEnqueueBuffer(st->queue, st->buf[i], 0, NULL);
	}

	status = AudioQueueStart(st->queue, NULL);
	if (status)  {
		re_fprintf(stderr, "AudioQueueStart error %i\n", status);
		err = ENODEV;
		goto out;
	}

 out:
	if (err)
		mem_deref(st);
	else
		*stp = st;

	return err;
}
Пример #19
0
static void recv_handler(struct mbuf *mb, void *arg)
{
	struct http_msg *msg = NULL;
	struct http_req *req = arg;
	size_t pos;
	int err;

	if (req->data) {
		if (req->datah)
			req->datah(mb, req->arg);
		return;
	}

	if (req->mb) {

		const size_t len = mbuf_get_left(mb);

		if ((mbuf_get_left(req->mb) + len) > BUFSIZE_MAX) {
			err = EOVERFLOW;
			goto out;
		}

		pos = req->mb->pos;
		req->mb->pos = req->mb->end;

		err = mbuf_write_mem(req->mb, mbuf_buf(mb), len);
		if (err)
			goto out;

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

	pos = req->mb->pos;

	err = http_msg_decode(&msg, req->mb, false);
	if (err) {
		if (err == ENODATA) {
			req->mb->pos = pos;
			return;
		}
		goto out;
	}

	if (req->datah) {
		tmr_cancel(&req->tmr);
		req->data = true;
		if (req->resph)
			req->resph(0, msg, req->arg);
		mem_deref(msg);
		return;
	}

	if (mbuf_get_left(req->mb) < msg->clen) {
		req->mb->pos = pos;
		mem_deref(msg);
		return;
	}

	req->mb->end = req->mb->pos + msg->clen;

 out:
	req_close(req, err, msg);
	mem_deref(req);
	mem_deref(msg);
}
Пример #20
0
static int alloc(struct vidsrc_st **stp, struct vidsrc *vs,
		 struct media_ctx **mctx, struct vidsrc_prm *prm,
		 const struct vidsz *size, const char *fmt,
		 const char *dev, vidsrc_frame_h *frameh,
		 vidsrc_error_h *errorh, void *arg)
{
#if LIBAVFORMAT_VERSION_INT < ((52<<16) + (110<<8) + 0)
	AVFormatParameters prms;
#endif
	struct vidsrc_st *st;
	bool found_stream = false;
	uint32_t i;
	int ret, err = 0;

	(void)mctx;
	(void)errorh;

	if (!stp || !size || !frameh)
		return EINVAL;

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

	st->vs     = mem_ref(vs);
	st->app_sz = *size;
	st->frameh = frameh;
	st->arg    = arg;

	if (prm) {
		st->fps = prm->fps;
	}
	else {
		st->fps = 25;
	}

	/*
	 * avformat_open_input() was added in lavf 53.2.0 according to
	 * ffmpeg/doc/APIchanges
	 */

#if LIBAVFORMAT_VERSION_INT >= ((52<<16) + (110<<8) + 0)
	(void)fmt;
	ret = avformat_open_input(&st->ic, dev, NULL, NULL);
#else

	/* Params */
	memset(&prms, 0, sizeof(prms));

	prms.time_base          = (AVRational){1, st->fps};
	prms.channels           = 1;
	prms.width              = size->w;
	prms.height             = size->h;
	prms.pix_fmt            = PIX_FMT_YUV420P;
	prms.channel            = 0;

	ret = av_open_input_file(&st->ic, dev, av_find_input_format(fmt),
				 0, &prms);
#endif

	if (ret < 0) {
		err = ENOENT;
		goto out;
	}

#if LIBAVFORMAT_VERSION_INT >= ((53<<16) + (4<<8) + 0)
	ret = avformat_find_stream_info(st->ic, NULL);
#else
	ret = av_find_stream_info(st->ic);
#endif

	if (ret < 0) {
		warning("avformat: %s: no stream info\n", dev);
		err = ENOENT;
		goto out;
	}

#if 0
	dump_format(st->ic, 0, dev, 0);
#endif

	for (i=0; i<st->ic->nb_streams; i++) {
		const struct AVStream *strm = st->ic->streams[i];
		AVCodecContext *ctx = strm->codec;

		if (ctx->codec_type != AVMEDIA_TYPE_VIDEO)
			continue;

		debug("avformat: stream %u:  %u x %u "
		      "  time_base=%d/%d\n",
		      i, ctx->width, ctx->height,
		      ctx->time_base.num, ctx->time_base.den);

		st->sz.w   = ctx->width;
		st->sz.h   = ctx->height;
		st->ctx    = ctx;
		st->sindex = strm->index;

		if (ctx->codec_id != AV_CODEC_ID_NONE) {

			st->codec = avcodec_find_decoder(ctx->codec_id);
			if (!st->codec) {
				err = ENOENT;
				goto out;
			}

#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0)
			ret = avcodec_open2(ctx, st->codec, NULL);
#else
			ret = avcodec_open(ctx, st->codec);
#endif
			if (ret < 0) {
				err = ENOENT;
				goto out;
			}
		}

		found_stream = true;
		break;
	}

	if (!found_stream) {
		err = ENOENT;
		goto out;
	}

	st->run = true;
	err = pthread_create(&st->thread, NULL, read_thread, st);
	if (err) {
		st->run = false;
		goto out;
	}

 out:
	if (err)
		mem_deref(st);
	else
		*stp = st;

	return err;
}
Пример #21
0
/**
 * Send an HTTP request
 *
 * @param reqp      Pointer to allocated HTTP request object
 * @param cli       HTTP Client
 * @param met       Request method
 * @param uri       Request URI
 * @param resph     Response handler
 * @param datah     Content handler (optional)
 * @param arg       Handler argument
 * @param fmt       Formatted HTTP headers and body (optional)
 *
 * @return 0 if success, otherwise errorcode
 */
int http_request(struct http_req **reqp, struct http_cli *cli, const char *met,
		 const char *uri, http_resp_h *resph, http_data_h *datah,
		 void *arg, const char *fmt, ...)
{
	struct pl scheme, host, port, path;
	struct http_req *req;
	uint16_t defport;
	bool secure;
	va_list ap;
	int err;

	if (!reqp || !cli || !met || !uri)
		return EINVAL;

	if (re_regex(uri, strlen(uri), "[a-z]+://[^:/]+[:]*[0-9]*[^]+",
		     &scheme, &host, NULL, &port, &path) || scheme.p != uri)
		return EINVAL;

	if (!pl_strcasecmp(&scheme, "http") ||
	    !pl_strcasecmp(&scheme, "ws")) {
		secure  = false;
		defport = 80;
	}
#ifdef USE_TLS
	else if (!pl_strcasecmp(&scheme, "https") ||
		 !pl_strcasecmp(&scheme, "wss")) {
		secure  = true;
		defport = 443;
	}
#endif
	else
		return ENOTSUP;

	req = mem_zalloc(sizeof(*req), req_destructor);
	if (!req)
		return ENOMEM;

	req->tls    = mem_ref(cli->tls);
	req->secure = secure;
	req->port   = pl_isset(&port) ? pl_u32(&port) : defport;
	req->resph  = resph;
	req->datah  = datah;
	req->arg    = arg;

	err = pl_strdup(&req->host, &host);
	if (err)
		goto out;

	req->mbreq = mbuf_alloc(1024);
	if (!req->mbreq) {
		err = ENOMEM;
		goto out;
	}

	err = mbuf_printf(req->mbreq,
			  "%s %r HTTP/1.1\r\n"
			  "Host: %r\r\n",
			  met, &path, &host);
	if (fmt) {
		va_start(ap, fmt);
		err |= mbuf_vprintf(req->mbreq, fmt, ap);
		va_end(ap);
	}
	else {
		err |= mbuf_write_str(req->mbreq, "\r\n");
	}
	if (err)
		goto out;

	req->mbreq->pos = 0;

	if (!sa_set_str(&req->srvv[0], req->host, req->port)) {

		req->srvc = 1;

		err = req_connect(req);
		if (err)
			goto out;
	}
	else {
		err = dnsc_query(&req->dq, cli->dnsc, req->host,
				 DNS_TYPE_A, DNS_CLASS_IN, true,
				 query_handler, req);
		if (err)
			goto out;
	}

 out:
	if (err)
		mem_deref(req);
	else {
		req->reqp = reqp;
		*reqp = req;
	}

	return err;
}
Пример #22
0
/**
 * Align the locate/remote formats of an SDP Media line
 *
 * @param m     SDP Media line
 * @param offer True if SDP Offer, False if SDP Answer
 */
void sdp_media_align_formats(struct sdp_media *m, bool offer)
{
	struct sdp_format *rfmt, *lfmt;
	struct le *rle, *lle;

	if (!m || m->disabled || !sa_port(&m->raddr) || m->fmt_ignore)
		return;

	for (lle=m->lfmtl.head; lle; lle=lle->next) {

		lfmt = lle->data;

		lfmt->rparams = mem_deref(lfmt->rparams);
		lfmt->sup = false;
	}

	for (rle=m->rfmtl.head; rle; rle=rle->next) {

		rfmt = rle->data;

		for (lle=m->lfmtl.head; lle; lle=lle->next) {

			lfmt = lle->data;

			if (sdp_format_cmp(lfmt, rfmt))
				break;
		}

		if (!lle) {
			rfmt->sup = false;
			continue;
		}

		mem_deref(lfmt->rparams);
		lfmt->rparams = mem_ref(rfmt->params);

		lfmt->sup = true;
		rfmt->sup = true;

		if (rfmt->ref)
			rfmt->data = mem_deref(rfmt->data);
		else
			rfmt->data = NULL;

		if (lfmt->ref)
			rfmt->data = mem_ref(lfmt->data);
		else
			rfmt->data = lfmt->data;

		rfmt->ref = lfmt->ref;

		if (offer) {
			mem_deref(lfmt->id);
			lfmt->id = mem_ref(rfmt->id);
			lfmt->pt = atoi(lfmt->id ? lfmt->id : "");

			list_unlink(&lfmt->le);
			list_append(&m->lfmtl, &lfmt->le, lfmt);
		}
	}

	if (offer) {

		for (lle=m->lfmtl.tail; lle; ) {

			lfmt = lle->data;

			lle = lle->prev;

			if (!lfmt->sup) {
				list_unlink(&lfmt->le);
				list_append(&m->lfmtl, &lfmt->le, lfmt);
			}
		}
	}
}
Пример #23
0
static int alloc_handler(struct ausrc_st **stp, const struct ausrc *as,
			 struct media_ctx **ctx,
			 struct ausrc_prm *prm, const char *dev,
			 ausrc_read_h *rh, ausrc_error_h *errh, void *arg)
{
	struct ausrc_st *st;
	int err;

	if (!stp || !as || !prm || !rh)
		return EINVAL;

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

	st->as   = as;
	st->rh   = rh;
	st->errh = errh;
	st->arg  = arg;

	st->mp3 = mpg123_new(NULL, &err);
	if (!st->mp3) {
		err = ENODEV;
		goto out;
	}

	err = mpg123_open_feed(st->mp3);
	if (err != MPG123_OK) {
		warning("rst: mpg123_open_feed: %s\n",
			mpg123_strerror(st->mp3));
		err = ENODEV;
		goto out;
	}

	/* Set wanted output format */
	mpg123_format_none(st->mp3);
	mpg123_format(st->mp3, prm->srate, prm->ch,
		      aufmt_to_encoding(prm->fmt));
	mpg123_volume(st->mp3, 0.3);

	st->sampc = prm->srate * prm->ch * prm->ptime / 1000;
	st->sampsz = aufmt_sample_size(prm->fmt);

	st->ptime = prm->ptime;

	info("rst: audio ptime=%u sampc=%zu aubuf=[%u:%u]\n",
	     st->ptime, st->sampc,
	     prm->srate * prm->ch * 2,
	     prm->srate * prm->ch * 40);

	/* 1 - 20 seconds of audio */
	err = aubuf_alloc(&st->aubuf,
			  prm->srate * prm->ch * st->sampsz,
			  prm->srate * prm->ch * st->sampsz * 20);
	if (err)
		goto out;

	if (ctx && *ctx && (*ctx)->id && !strcmp((*ctx)->id, "rst")) {
		st->rst = mem_ref(*ctx);
	}
	else {
		err = rst_alloc(&st->rst, dev);
		if (err)
			goto out;

		if (ctx)
			*ctx = (struct media_ctx *)st->rst;
	}

	rst_set_audio(st->rst, st);

	st->run = true;

	err = pthread_create(&st->thread, NULL, play_thread, st);
	if (err) {
		st->run = false;
		goto out;
	}

 out:
	if (err)
		mem_deref(st);
	else
		*stp = st;

	return err;
}
Пример #24
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;
}
Пример #25
0
static inline int hdr_add(struct sip_msg *msg, const struct pl *name,
			  enum sip_hdrid id, const char *p, ssize_t l,
			  bool atomic, bool line)
{
	struct sip_hdr *hdr;
	int err = 0;

	hdr = mem_zalloc(sizeof(*hdr), hdr_destructor);
	if (!hdr)
		return ENOMEM;

	hdr->name  = *name;
	hdr->val.p = p;
	hdr->val.l = MAX(l, 0);
	hdr->id    = id;

	switch (id) {

	case SIP_HDR_VIA:
	case SIP_HDR_ROUTE:
		if (!atomic)
			break;

		hash_append(msg->hdrht, id, &hdr->he, mem_ref(hdr));
		list_append(&msg->hdrl, &hdr->le, mem_ref(hdr));
		break;

	default:
		if (atomic)
			hash_append(msg->hdrht, id, &hdr->he, mem_ref(hdr));
		if (line)
			list_append(&msg->hdrl, &hdr->le, mem_ref(hdr));
		break;
	}

	/* parse common headers */
	switch (id) {

	case SIP_HDR_VIA:
		if (!atomic || pl_isset(&msg->via.sentby))
			break;

		err = sip_via_decode(&msg->via, &hdr->val);
		break;

	case SIP_HDR_TO:
		err = sip_addr_decode((struct sip_addr *)&msg->to, &hdr->val);
		if (err)
			break;

		(void)msg_param_decode(&msg->to.params, "tag", &msg->to.tag);
		msg->to.val = hdr->val;
		break;

	case SIP_HDR_FROM:
		err = sip_addr_decode((struct sip_addr *)&msg->from,
				      &hdr->val);
		if (err)
			break;

		(void)msg_param_decode(&msg->from.params, "tag",
				       &msg->from.tag);
		msg->from.val = hdr->val;
		break;

	case SIP_HDR_CALL_ID:
		msg->callid = hdr->val;
		break;

	case SIP_HDR_CSEQ:
		err = sip_cseq_decode(&msg->cseq, &hdr->val);
		break;

	case SIP_HDR_MAX_FORWARDS:
		msg->maxfwd = hdr->val;
		break;

	case SIP_HDR_CONTENT_TYPE:
		err = msg_ctype_decode(&msg->ctyp, &hdr->val);
		break;

	case SIP_HDR_CONTENT_LENGTH:
		msg->clen = hdr->val;
		break;

	case SIP_HDR_EXPIRES:
		msg->expires = hdr->val;
		break;

	default:
		/* re_printf("%r = %u\n", &hdr->name, id); */
		break;
	}

	mem_deref(hdr);

	return err;
}
Пример #26
0
static void tcp_recv_handler(struct mbuf *mb_pkt, void *arg)
{
	struct allocation *alloc = arg;
	int err = 0;

	/* re-assembly of fragments */
	if (alloc->mb) {
		size_t pos;

		pos = alloc->mb->pos;

		alloc->mb->pos = alloc->mb->end;

		err = mbuf_write_mem(alloc->mb,
				     mbuf_buf(mb_pkt), mbuf_get_left(mb_pkt));
		if (err)
			goto out;

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

	for (;;) {

		size_t len, pos, end;
		struct sa src;
		uint16_t typ;

		if (mbuf_get_left(alloc->mb) < 4)
			break;

		typ = ntohs(mbuf_read_u16(alloc->mb));
		len = ntohs(mbuf_read_u16(alloc->mb));

		if (typ < 0x4000)
			len += STUN_HEADER_SIZE;
		else if (typ < 0x8000)
			len += 4;
		else {
			err = EBADMSG;
			goto out;
		}

		alloc->mb->pos -= 4;

		if (mbuf_get_left(alloc->mb) < len)
			break;

		pos = alloc->mb->pos;
		end = alloc->mb->end;

		alloc->mb->end = pos + len;

		/* forward packet to TURN client */
		err = turnc_recv(alloc->turnc, &src, alloc->mb);
		if (err)
			goto out;

		if (mbuf_get_left(alloc->mb)) {
			data_handler(alloc, &src, alloc->mb);
		}

		/* 4 byte alignment */
		while (len & 0x03)
			++len;

		alloc->mb->pos = pos + len;
		alloc->mb->end = end;

		if (alloc->mb->pos >= alloc->mb->end) {
			alloc->mb = mem_deref(alloc->mb);
			break;
		}
	}

 out:
	if (err) {
		alloc->alloch(err, 0, NULL, NULL, NULL, alloc->arg);
	}
}
Пример #27
0
/**
 * Decode a SIP message
 *
 * @param msgp Pointer to allocated SIP Message
 * @param mb   Buffer containing SIP Message
 *
 * @return 0 if success, otherwise errorcode
 */
int sip_msg_decode(struct sip_msg **msgp, struct mbuf *mb)
{
	struct pl x, y, z, e, name;
	const char *p, *v, *cv;
	struct sip_msg *msg;
	bool comsep, quote;
	enum sip_hdrid id = SIP_HDR_NONE;
	uint32_t ws, lf;
	size_t l;
	int err;

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

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

	if (re_regex(p, l, "[^ \t\r\n]+ [^ \t\r\n]+ [^\r\n]*[\r]*[\n]1",
		     &x, &y, &z, NULL, &e) || x.p != (char *)mbuf_buf(mb))
		return (l > STARTLINE_MAX) ? EBADMSG : ENODATA;

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

	err = hash_alloc(&msg->hdrht, HDR_HASH_SIZE);
	if (err)
		goto out;

	msg->tag = rand_u64();
	msg->mb  = mem_ref(mb);
	msg->req = (0 == pl_strcmp(&z, "SIP/2.0"));

	if (msg->req) {

		msg->met = x;
		msg->ruri = y;
		msg->ver = z;

		if (uri_decode(&msg->uri, &y)) {
			err = EBADMSG;
			goto out;
		}
	}
	else {
		msg->ver    = x;
		msg->scode  = pl_u32(&y);
		msg->reason = z;

		if (!msg->scode) {
			err = EBADMSG;
			goto out;
		}
	}

	l -= e.p + e.l - p;
	p = e.p + e.l;

	name.p = v = cv = NULL;
	name.l = ws = lf = 0;
	comsep = false;
	quote = false;

	for (; l > 0; p++, l--) {

		switch (*p) {

		case ' ':
		case '\t':
			lf = 0; /* folding */
			++ws;
			break;

		case '\r':
			++ws;
			break;

		case '\n':
			++ws;

			if (!lf++)
				break;

			++p; --l; /* eoh */

			/*@fallthrough@*/

		default:
			if (lf || (*p == ',' && comsep && !quote)) {

				if (!name.l) {
					err = EBADMSG;
					goto out;
				}

				err = hdr_add(msg, &name, id, cv ? cv : p,
					      cv ? p - cv - ws : 0,
					      true, cv == v && lf);
				if (err)
					goto out;

				if (!lf) { /* comma separated */
					cv = NULL;
					break;
				}

				if (cv != v) {
					err = hdr_add(msg, &name, id,
						      v ? v : p,
						      v ? p - v - ws : 0,
						      false, true);
					if (err)
						goto out;
				}

				if (lf > 1) { /* eoh */
					err = 0;
					goto out;
				}

				comsep = false;
				name.p = NULL;
				cv = v = NULL;
				lf = 0;
			}

			if (!name.p) {
				name.p = p;
				name.l = 0;
				ws = 0;
			}

			if (!name.l) {
				if (*p != ':') {
					ws = 0;
					break;
				}

				name.l = MAX((int)(p - name.p - ws), 0);
				if (!name.l) {
					err = EBADMSG;
					goto out;
				}

				id = hdr_hash(&name);
				comsep = hdr_comma_separated(id);
				break;
			}

			if (!cv) {
				quote = false;
				cv = p;
			}

			if (!v) {
				v = p;
			}

			if (*p == '"')
				quote = !quote;

			ws = 0;
			break;
		}
	}

	err = ENODATA;

 out:
	if (err)
		mem_deref(msg);
	else {
		*msgp = msg;
		mb->pos = mb->end - l;
	}

	return err;
}
Пример #28
0
static int alloc(struct vidsrc_st **stp, struct vidsrc *vs,
		 struct media_ctx **ctx, struct vidsrc_prm *prm,
		 const struct vidsz *size, const char *fmt,
		 const char *dev, vidsrc_frame_h *frameh,
		 vidsrc_error_h *errorh, void *arg)
{
	struct vidsrc_st *st;
	int err;

	(void)ctx;
	(void)prm;
	(void)fmt;
	(void)errorh;

	if (!stp || !size || !frameh)
		return EINVAL;

	if (!str_isset(dev))
		dev = "/dev/video0";

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

	st->vs     = mem_ref(vs);
	st->fd     = -1;
	st->size   = *size;
	st->frameh = frameh;
	st->arg    = arg;

	DEBUG_NOTICE("open: %s %ix%i\n", dev, size->w, size->h);

	err = vd_open(st, dev);
	if (err)
		goto out;

	v4l_get_caps(st);

	err = v4l_check_palette(st);
	if (err)
		goto out;

	err = v4l_get_win(st->fd, st->size.w, st->size.h);
	if (err)
		goto out;

	/* note: assumes RGB24 */
	st->mb = mbuf_alloc(rgb24_size(&st->size));
	if (!st->mb) {
		err = ENOMEM;
		goto out;
	}

	st->run = true;
	err = pthread_create(&st->thread, NULL, read_thread, st);
	if (err) {
		st->run = false;
		goto out;
	}

 out:
	if (err)
		mem_deref(st);
	else
		*stp = st;

	return err;
}
Пример #29
0
static void tcp_recv_handler(struct mbuf *mb, void *arg)
{
	struct turnserver *conn = arg;
	int err = 0;

	if (conn->mb) {
		size_t pos;

		pos = conn->mb->pos;

		conn->mb->pos = conn->mb->end;

		err = mbuf_write_mem(conn->mb, mbuf_buf(mb),mbuf_get_left(mb));
		if (err) {
			DEBUG_WARNING("tcp: buffer write error: %m\n", err);
			goto out;
		}

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

	for (;;) {

		size_t len, pos, end;
		uint16_t typ;

		if (mbuf_get_left(conn->mb) < 4)
			break;

		typ = ntohs(mbuf_read_u16(conn->mb));
		len = ntohs(mbuf_read_u16(conn->mb));

		if (len > TCP_MAX_LENGTH) {
			re_printf("tcp: bad length: %zu\n", len);
			err = EBADMSG;
			goto out;
		}

		if (typ < 0x4000)
			len += STUN_HEADER_SIZE;
		else if (typ < 0x8000)
			len += 4;
		else {
			re_printf("tcp: bad type: 0x%04x\n", typ);
			err = EBADMSG;
			goto out;
		}

		conn->mb->pos -= 4;

		if (mbuf_get_left(conn->mb) < len)
			break;

		pos = conn->mb->pos;
		end = conn->mb->end;

		conn->mb->end = pos + len;

		process_msg(conn, IPPROTO_TCP, conn->tc, &conn->paddr,
			    conn->mb);

		/* 4 byte alignment */
		while (len & 0x03)
			++len;

		conn->mb->pos = pos + len;
		conn->mb->end = end;

		if (conn->mb->pos >= conn->mb->end) {
			conn->mb = mem_deref(conn->mb);
			break;
		}
	}

 out:
	if (err) {
		conn->mb = mem_deref(conn->mb);
	}
}