1 /**
2  * @file sdp/msg.c  SDP Message processing
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 #include <re_types.h>
7 #include <re_fmt.h>
8 #include <re_mem.h>
9 #include <re_mbuf.h>
10 #include <re_list.h>
11 #include <re_sa.h>
12 #include <re_sdp.h>
13 #include "sdp.h"
14 
15 
16 static int attr_decode_fmtp(struct sdp_media *m, const struct pl *pl)
17 {
destructor(void * arg)18 	struct sdp_format *fmt;
19 	struct pl id, params;
20 
21 	if (!m)
22 		return 0;
23 
24 	if (re_regex(pl->p, pl->l, "[^ ]+ [^]*", &id, &params))
25 		return EBADMSG;
26 
27 	fmt = sdp_format_find(&m->rfmtl, &id);
28 	if (!fmt)
29 		return 0;
30 
31 	fmt->params = mem_deref(fmt->params);
32 
33 	return pl_strdup(&fmt->params, &params);
34 }
35 
36 
37 static int attr_decode_rtcp(struct sdp_media *m, const struct pl *pl)
38 {
39 	struct pl port, addr;
40 	int err = 0;
41 
42 	if (!m)
43 		return 0;
44 
media_alloc(struct sdp_media ** mp,struct list * list)45 	if (!re_regex(pl->p, pl->l, "[0-9]+ IN IP[46]1 [^ ]+",
46 		      &port, NULL, &addr)) {
47 		(void)sa_set(&m->raddr_rtcp, &addr, pl_u32(&port));
48 	}
49 	else if (!re_regex(pl->p, pl->l, "[0-9]+", &port)) {
50 		sa_set_port(&m->raddr_rtcp, pl_u32(&port));
51 	}
52 	else
53 		err = EBADMSG;
54 
55 	return err;
56 }
57 
58 
59 static int attr_decode_rtpmap(struct sdp_media *m, const struct pl *pl)
60 {
61 	struct pl id, name, srate, ch;
62 	struct sdp_format *fmt;
63 	int err;
64 
65 	if (!m)
66 		return 0;
67 
68 	if (re_regex(pl->p, pl->l, "[^ ]+ [^/]+/[0-9]+[/]*[^]*",
69 		     &id, &name, &srate, NULL, &ch))
70 		return EBADMSG;
71 
72 	fmt = sdp_format_find(&m->rfmtl, &id);
73 	if (!fmt)
74 		return 0;
75 
76 	fmt->name = mem_deref(fmt->name);
77 
78 	err = pl_strdup(&fmt->name, &name);
79 	if (err)
80 		return err;
81 
82 	fmt->srate = pl_u32(&srate);
83 	fmt->ch = ch.l ? pl_u32(&ch) : 1;
84 
85 	return 0;
86 }
sdp_media_add(struct sdp_media ** mp,struct sdp_session * sess,const char * name,uint16_t port,const char * proto)87 
88 
89 static int attr_decode(struct sdp_session *sess, struct sdp_media *m,
90 		       enum sdp_dir *dir, const struct pl *pl)
91 {
92 	struct pl name, val;
93 	int err = 0;
94 
95 	if (re_regex(pl->p, pl->l, "[^:]+:[^]+", &name, &val)) {
96 		name = *pl;
97 		val  = pl_null;
98 	}
99 
100 	if (!pl_strcmp(&name, "fmtp"))
101 		err = attr_decode_fmtp(m, &val);
102 
103 	else if (!pl_strcmp(&name, "inactive"))
104 		*dir = SDP_INACTIVE;
105 
106 	else if (!pl_strcmp(&name, "recvonly"))
107 		*dir = SDP_SENDONLY;
108 
109 	else if (!pl_strcmp(&name, "rtcp"))
110 		err = attr_decode_rtcp(m, &val);
111 
112 	else if (!pl_strcmp(&name, "rtpmap"))
113 		err = attr_decode_rtpmap(m, &val);
114 
115 	else if (!pl_strcmp(&name, "sendonly"))
116 		*dir = SDP_RECVONLY;
117 
118 	else if (!pl_strcmp(&name, "sendrecv"))
119 		*dir = SDP_SENDRECV;
120 
121 	else
122 		err = sdp_attr_add(m ? &m->rattrl : &sess->rattrl,
123 				   &name, &val);
124 
125 	return err;
126 }
sdp_media_radd(struct sdp_media ** mp,struct sdp_session * sess,const struct pl * name,const struct pl * proto)127 
128 
129 static int bandwidth_decode(int32_t *bwv, const struct pl *pl)
130 {
131 	struct pl type, bw;
132 
133 	if (re_regex(pl->p, pl->l, "[^:]+:[0-9]+", &type, &bw))
134 		return EBADMSG;
135 
136 	if (!pl_strcmp(&type, "CT"))
137 		bwv[SDP_BANDWIDTH_CT] = pl_u32(&bw);
138 
139 	else if (!pl_strcmp(&type, "AS"))
140 		bwv[SDP_BANDWIDTH_AS] = pl_u32(&bw);
141 
142 	else if (!pl_strcmp(&type, "RS"))
143 		bwv[SDP_BANDWIDTH_RS] = pl_u32(&bw);
144 
145 	else if (!pl_strcmp(&type, "RR"))
146 		bwv[SDP_BANDWIDTH_RR] = pl_u32(&bw);
147 
148 	else if (!pl_strcmp(&type, "TIAS"))
149 		bwv[SDP_BANDWIDTH_TIAS] = pl_u32(&bw);
150 
151 	return 0;
152 }
153 
154 
155 static int conn_decode(struct sa *sa, const struct pl *pl)
156 {
157 	struct pl v;
158 
sdp_media_rreset(struct sdp_media * m)159 	if (re_regex(pl->p, pl->l, "IN IP[46]1 [^ ]+", NULL, &v))
160 		return EBADMSG;
161 
162 	(void)sa_set(sa, &v, sa_port(sa));
163 
164 	return 0;
165 }
166 
167 
168 static int media_decode(struct sdp_media **mp, struct sdp_session *sess,
169 			bool offer, const struct pl *pl)
170 {
171 	struct pl name, port, proto, fmtv, fmt;
172 	struct sdp_media *m;
173 	int err;
174 
175 	if (re_regex(pl->p, pl->l, "[a-z]+ [^ ]+ [^ ]+[^]*",
176 		     &name, &port, &proto, &fmtv))
177 		return EBADMSG;
178 
179 	m = list_ledata(*mp ? (*mp)->le.next : sess->medial.head);
180 	if (!m) {
181 		if (!offer)
182 			return EPROTO;
183 
184 		m = sdp_media_find(sess, &name, &proto, true);
185 		if (!m) {
186 			err = sdp_media_radd(&m, sess, &name, &proto);
187 			if (err)
sdp_media_proto_cmp(struct sdp_media * m,const struct pl * proto,bool update)188 				return err;
189 		}
190 		else {
191 			list_unlink(&m->le);
192 			list_append(&sess->medial, &m->le, m);
193 		}
194 
195 		m->uproto = mem_deref(m->uproto);
196 	}
197 	else {
198 		if (pl_strcmp(&name, m->name))
199 			return offer ? ENOTSUP : EPROTO;
200 
201 		m->uproto = mem_deref(m->uproto);
202 
203 		if (!sdp_media_proto_cmp(m, &proto, offer)) {
204 
205 			err = pl_strdup(&m->uproto, &proto);
206 			if (err)
207 				return err;
208 		}
209 	}
210 
211 	while (!re_regex(fmtv.p, fmtv.l, " [^ ]+", &fmt)) {
212 
213 		pl_advance(&fmtv, fmt.p + fmt.l - fmtv.p);
214 
215 		err = sdp_format_radd(m, &fmt);
216 		if (err)
217 			return err;
218 	}
219 
220 	m->raddr = sess->raddr;
221 	sa_set_port(&m->raddr, m->uproto ? 0 : pl_u32(&port));
222 
223 	m->rdir = sess->rdir;
224 
225 	*mp = m;
sdp_media_find(const struct sdp_session * sess,const struct pl * name,const struct pl * proto,bool update_proto)226 
227 	return 0;
228 }
229 
230 
231 static int version_decode(const struct pl *pl)
232 {
233 	return pl_strcmp(pl, "0") ? ENOSYS : 0;
234 }
235 
236 
237 /**
238  * Decode an SDP message into an SDP Session
239  *
240  * @param sess  SDP Session
241  * @param mb    Memory buffer containing SDP message
242  * @param offer True if SDP offer, False if SDP answer
243  *
244  * @return 0 if success, otherwise errorcode
245  */
246 int sdp_decode(struct sdp_session *sess, struct mbuf *mb, bool offer)
247 {
248 	struct sdp_media *m;
249 	struct pl pl, val;
250 	struct le *le;
251 	char type = 0;
252 	int err = 0;
253 
254 	if (!sess || !mb)
255 		return EINVAL;
256 
257 	sdp_session_rreset(sess);
258 
sdp_media_align_formats(struct sdp_media * m,bool offer)259 	for (le=sess->medial.head; le; le=le->next) {
260 
261 		m = le->data;
262 
263 		sdp_media_rreset(m);
264 	}
265 
266 	pl.p = (const char *)mbuf_buf(mb);
267 	pl.l = mbuf_get_left(mb);
268 
269 	m = NULL;
270 
271 	for (;pl.l && !err; pl.p++, pl.l--) {
272 
273 		switch (*pl.p) {
274 
275 		case '\r':
276 		case '\n':
277 			if (!type)
278 				break;
279 
280 			switch (type) {
281 
282 			case 'a':
283 				err = attr_decode(sess, m,
284 						  m ? &m->rdir : &sess->rdir,
285 						  &val);
286 				break;
287 
288 			case 'b':
289 				err = bandwidth_decode(m? m->rbwv : sess->rbwv,
290 						       &val);
291 				break;
292 
293 			case 'c':
294 				err = conn_decode(m ? &m->raddr : &sess->raddr,
295 						  &val);
296 				break;
297 
298 			case 'm':
299 				err = media_decode(&m, sess, offer, &val);
300 				break;
301 
302 			case 'v':
303 				err = version_decode(&val);
304 				break;
305 			}
306 
307 #if 0
308 			if (err)
309 				re_printf("** %c='%r': %m\n", type, &val, err);
310 #endif
311 
312 			type = 0;
313 			break;
314 
315 		default:
316 			if (type) {
317 				val.l++;
318 				break;
319 			}
320 
321 			if (pl.l < 2 || *(pl.p + 1) != '=') {
322 				err = EBADMSG;
323 				break;
324 			}
325 
326 			type  = *pl.p;
327 			val.p = pl.p + 2;
328 			val.l = 0;
329 
330 			pl.p += 1;
331 			pl.l -= 1;
332 			break;
333 		}
334 	}
335 
336 	if (err)
337 		return err;
338 
339 	if (type)
340 		return EBADMSG;
341 
342 	for (le=sess->medial.head; le; le=le->next)
343 		sdp_media_align_formats(le->data, offer);
344 
sdp_media_set_alt_protos(struct sdp_media * m,unsigned protoc,...)345 	return 0;
346 }
347 
348 
349 static int media_encode(const struct sdp_media *m, struct mbuf *mb, bool offer)
350 {
351 	enum sdp_bandwidth i;
352 	const char *proto;
353 	int err, supc = 0;
354 	bool disabled;
355 	struct le *le;
356 	uint16_t port;
357 
358 	for (le=m->lfmtl.head; le; le=le->next) {
359 
360 		const struct sdp_format *fmt = le->data;
361 
362 		if (fmt->sup)
363 			++supc;
364 	}
365 
366 	if (m->uproto && !offer) {
367 		disabled = true;
368 		port = 0;
369 		proto = m->uproto;
370 	}
371 	else if (m->disabled || supc == 0 || (!offer && !sa_port(&m->raddr))) {
372 		disabled = true;
373 		port = 0;
374 		proto = m->proto;
375 	}
376 	else {
377 		disabled = false;
378 		port = sa_port(&m->laddr);
379 		proto = m->proto;
380 	}
381 
sdp_media_set_encode_handler(struct sdp_media * m,sdp_media_enc_h * ench,void * arg)382 	err = mbuf_printf(mb, "m=%s %u %s", m->name, port, proto);
383 
384 	if (disabled) {
385 		err |= mbuf_write_str(mb, " 0\r\n");
386 		return err;
387 	}
388 
389 	for (le=m->lfmtl.head; le; le=le->next) {
390 
391 		const struct sdp_format *fmt = le->data;
392 
393 		if (!fmt->sup)
394 			continue;
395 
396 		err |= mbuf_printf(mb, " %s", fmt->id);
397 	}
398 
sdp_media_set_fmt_ignore(struct sdp_media * m,bool fmt_ignore)399 	err |= mbuf_write_str(mb, "\r\n");
400 
401 	if (sa_isset(&m->laddr, SA_ADDR)) {
402 		const int ipver = sa_af(&m->laddr) == AF_INET ? 4 : 6;
403 		err |= mbuf_printf(mb, "c=IN IP%d %j\r\n", ipver, &m->laddr);
404 	}
405 
406 	for (i=SDP_BANDWIDTH_MIN; i<SDP_BANDWIDTH_MAX; i++) {
407 
408 		if (m->lbwv[i] < 0)
409 			continue;
410 
411 		err |= mbuf_printf(mb, "b=%s:%i\r\n",
412 				   sdp_bandwidth_name(i), m->lbwv[i]);
413 	}
sdp_media_set_disabled(struct sdp_media * m,bool disabled)414 
415 	for (le=m->lfmtl.head; le; le=le->next) {
416 
417 		const struct sdp_format *fmt = le->data;
418 
419 		if (!fmt->sup || !str_isset(fmt->name))
420 			continue;
421 
422 		err |= mbuf_printf(mb, "a=rtpmap:%s %s/%u",
423 				   fmt->id, fmt->name, fmt->srate);
424 
425 		if (fmt->ch > 1)
426 			err |= mbuf_printf(mb, "/%u", fmt->ch);
427 
428 		err |= mbuf_printf(mb, "\r\n");
sdp_media_set_lport(struct sdp_media * m,uint16_t port)429 
430 		if (str_isset(fmt->params))
431 			err |= mbuf_printf(mb, "a=fmtp:%s %s\r\n",
432 					   fmt->id, fmt->params);
433 		if (fmt->ench)
434 			err |= fmt->ench(mb, fmt, offer, fmt->data);
435 	}
436 
437 	if (sa_isset(&m->laddr_rtcp, SA_ALL))
438 		err |= mbuf_printf(mb, "a=rtcp:%u IN IP%d %j\r\n",
439 				   sa_port(&m->laddr_rtcp),
440 				   (AF_INET == sa_af(&m->laddr_rtcp)) ? 4 : 6,
441 				   &m->laddr_rtcp);
442 	else if (sa_isset(&m->laddr_rtcp, SA_PORT))
443 		err |= mbuf_printf(mb, "a=rtcp:%u\r\n",
sdp_media_set_laddr(struct sdp_media * m,const struct sa * laddr)444 				   sa_port(&m->laddr_rtcp));
445 
446 	err |= mbuf_printf(mb, "a=%s\r\n",
447 			   sdp_dir_name(offer ? m->ldir : m->ldir & m->rdir));
448 
449 	for (le = m->lattrl.head; le; le = le->next)
450 		err |= mbuf_printf(mb, "%H", sdp_attr_print, le->data);
451 
452 	if (m->ench)
453 		err |= m->ench(mb, offer, m->arg);
454 
455 	return err;
456 }
457 
458 
459 /**
sdp_media_set_lbandwidth(struct sdp_media * m,enum sdp_bandwidth type,int32_t bw)460  * Encode an SDP Session into a memory buffer
461  *
462  * @param mbp   Pointer to allocated memory buffer
463  * @param sess  SDP Session
464  * @param offer True if SDP Offer, False if SDP Answer
465  *
466  * @return 0 if success, otherwise errorcode
467  */
468 int sdp_encode(struct mbuf **mbp, struct sdp_session *sess, bool offer)
469 {
470 	const int ipver = sa_af(&sess->laddr) == AF_INET ? 4 : 6;
471 	enum sdp_bandwidth i;
472 	struct mbuf *mb;
473 	struct le *le;
474 	int err;
475 
476 	if (!mbp || !sess)
477 		return EINVAL;
478 
479 	mb = mbuf_alloc(512);
480 	if (!mb)
481 		return ENOMEM;
482 
483 	err  = mbuf_printf(mb, "v=%u\r\n", SDP_VERSION);
484 	err |= mbuf_printf(mb, "o=- %u %u IN IP%d %j\r\n",
485 			   sess->id, sess->ver++, ipver, &sess->laddr);
486 	err |= mbuf_write_str(mb, "s=-\r\n");
487 	err |= mbuf_printf(mb, "c=IN IP%d %j\r\n", ipver, &sess->laddr);
488 
489 	for (i=SDP_BANDWIDTH_MIN; i<SDP_BANDWIDTH_MAX; i++) {
490 
491 		if (sess->lbwv[i] < 0)
492 			continue;
493 
494 		err |= mbuf_printf(mb, "b=%s:%i\r\n",
495 				   sdp_bandwidth_name(i), sess->lbwv[i]);
496 	}
497 
498 	err |= mbuf_write_str(mb, "t=0 0\r\n");
499 
500 	for (le = sess->lattrl.head; le; le = le->next)
501 		err |= mbuf_printf(mb, "%H", sdp_attr_print, le->data);
502 
503 	for (le=sess->lmedial.head; offer && le;) {
504 
505 		struct sdp_media *m = le->data;
506 
507 		le = le->next;
508 
509 		if (m->disabled)
510 			continue;
511 
512 		list_unlink(&m->le);
513 		list_append(&sess->medial, &m->le, m);
514 	}
515 
516 	for (le=sess->medial.head; le; le=le->next) {
517 
518 		struct sdp_media *m = le->data;
519 
520 		err |= media_encode(m, mb, offer);
521 	}
522 
523 	mb->pos = 0;
524 
525 	if (err)
526 		mem_deref(mb);
527 	else
528 		*mbp = mb;
529 
530 	return err;
531 }
532