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, ¶ms)) 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, ¶ms); 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