Changeset 129 for pjproject/trunk/pjmedia/src/pjmedia/sdp.c
- Timestamp:
- Feb 2, 2006 7:16:07 PM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia/sdp.c
r121 r129 18 18 */ 19 19 #include <pjmedia/sdp.h> 20 #include <pjmedia/errno.h> 20 21 #include <pjlib-util/scanner.h> 22 #include <pj/array.h> 21 23 #include <pj/except.h> 22 24 #include <pj/log.h> … … 25 27 #include <pj/pool.h> 26 28 #include <pj/assert.h> 29 #include <pj/ctype.h> 30 27 31 28 32 enum { … … 32 36 #define TOKEN "-.!%*_=`'~" 33 37 #define NTP_OFFSET ((pj_uint32_t)2208988800) 34 #define LOG_THIS "sdp" 38 #define THIS_FILE "sdp.c" 39 40 typedef struct parse_context 41 { 42 pj_status_t last_error; 43 } parse_context; 44 35 45 36 46 /* 37 47 * Prototypes for line parser. 38 48 */ 39 static void parse_version(pj_scanner *scanner); 40 static void parse_origin(pj_scanner *scanner, pjsdp_session_desc *ses); 41 static void parse_time(pj_scanner *scanner, pjsdp_session_desc *ses); 42 static void parse_generic_line(pj_scanner *scanner, pj_str_t *str); 43 static void parse_connection_info(pj_scanner *scanner, pjsdp_conn_info *conn); 44 static pjsdp_attr *parse_attr(pj_pool_t *pool, pj_scanner *scanner); 45 static void parse_media(pj_scanner *scanner, pjsdp_media_desc *med); 46 47 /* 48 * Prototypes for attribute parsers. 49 */ 50 static pjsdp_rtpmap_attr * parse_rtpmap_attr( pj_pool_t *pool, pj_scanner *scanner ); 51 static pjsdp_attr_string * parse_generic_string_attr( pj_pool_t *pool, pj_scanner *scanner ); 52 static pjsdp_attr_num * parse_generic_num_attr( pj_pool_t *pool, pj_scanner *scanner ); 53 static pjsdp_attr * parse_name_only_attr( pj_pool_t *pool, pj_scanner *scanner ); 54 static pjsdp_fmtp_attr * parse_fmtp_attr( pj_pool_t *pool, pj_scanner *scanner ); 55 56 57 /* 58 * Prototypes for functions to print attribute. 59 * All of them returns integer for the length printed, or -1 on error. 60 */ 61 static int print_rtpmap_attr(const pjsdp_rtpmap_attr *attr, 62 char *buf, int length); 63 static int print_generic_string_attr(const pjsdp_attr_string *attr, 64 char *buf, int length); 65 static int print_generic_num_attr(const pjsdp_attr_num *attr, 66 char *buf, int length); 67 static int print_name_only_attr(const pjsdp_attr *attr, 68 char *buf, int length); 69 static int print_fmtp_attr(const pjsdp_fmtp_attr *attr, 70 char *buf, int length); 71 72 /* 73 * Prototypes for cloning attributes. 74 */ 75 static pjsdp_attr* clone_rtpmap_attr (pj_pool_t *pool, const pjsdp_attr *rhs); 76 static pjsdp_attr* clone_generic_string_attr (pj_pool_t *pool, const pjsdp_attr *rhs); 77 static pjsdp_attr* clone_generic_num_attr (pj_pool_t *pool, const pjsdp_attr *rhs); 78 static pjsdp_attr* clone_name_only_attr (pj_pool_t *pool, const pjsdp_attr *rhs); 79 static pjsdp_attr* clone_fmtp_attr (pj_pool_t *pool, const pjsdp_attr *rhs); 80 81 82 /* 83 * Prototypes 84 */ 85 static void init_sdp_parser(void); 86 87 88 typedef void * (*FPARSE)(pj_pool_t *pool, pj_scanner *scanner); 89 typedef int (*FPRINT)(const void *attr, char *buf, int length); 90 typedef pjsdp_attr* (*FCLONE)(pj_pool_t *pool, const pjsdp_attr *rhs); 91 92 /* 93 * Array of functions to print attribute. 94 */ 95 static struct attr_map_rec 96 { 97 pj_str_t name; 98 FPARSE parse_attr; 99 FPRINT print_attr; 100 FCLONE clone; 101 } attr_map[] = 102 { 103 {{"rtpmap", 6}, (FPARSE)&parse_rtpmap_attr, (FPRINT)&print_rtpmap_attr, (FCLONE)&clone_rtpmap_attr}, 104 {{"cat", 3}, (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr, (FCLONE)&clone_generic_string_attr}, 105 {{"keywds", 6}, (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr, (FCLONE)&clone_generic_string_attr}, 106 {{"tool", 4}, (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr, (FCLONE)&clone_generic_string_attr}, 107 {{"ptime", 5}, (FPARSE)&parse_generic_num_attr, (FPRINT)&print_generic_num_attr, (FCLONE)&clone_generic_num_attr}, 108 {{"recvonly", 8}, (FPARSE)&parse_name_only_attr, (FPRINT)&print_name_only_attr, (FCLONE)&clone_name_only_attr}, 109 {{"sendonly", 8}, (FPARSE)&parse_name_only_attr, (FPRINT)&print_name_only_attr, (FCLONE)&clone_name_only_attr}, 110 {{"sendrecv", 8}, (FPARSE)&parse_name_only_attr, (FPRINT)&print_name_only_attr, (FCLONE)&clone_name_only_attr}, 111 {{"orient", 6}, (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr, (FCLONE)&clone_generic_string_attr}, 112 {{"type", 4}, (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr, (FCLONE)&clone_generic_string_attr}, 113 {{"charset", 7}, (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr, (FCLONE)&clone_generic_string_attr}, 114 {{"sdplang", 7}, (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr, (FCLONE)&clone_generic_string_attr}, 115 {{"lang", 4}, (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr, (FCLONE)&clone_generic_string_attr}, 116 {{"framerate", 9}, (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr, (FCLONE)&clone_generic_string_attr}, 117 {{"quality", 7}, (FPARSE)&parse_generic_num_attr, (FPRINT)&print_generic_num_attr, (FCLONE)&clone_generic_num_attr}, 118 {{"fmtp", 4}, (FPARSE)&parse_fmtp_attr, (FPRINT)&print_fmtp_attr, (FCLONE)&clone_fmtp_attr}, 119 {{"inactive", 8}, (FPARSE)&parse_name_only_attr, (FPRINT)&print_name_only_attr, (FCLONE)&clone_name_only_attr}, 120 {{"", 0}, NULL, (FPRINT)&print_generic_string_attr, (FCLONE)&clone_generic_string_attr} 121 }; 49 static void parse_version(pj_scanner *scanner, parse_context *ctx); 50 static void parse_origin(pj_scanner *scanner, pjmedia_sdp_session *ses, 51 parse_context *ctx); 52 static void parse_time(pj_scanner *scanner, pjmedia_sdp_session *ses, 53 parse_context *ctx); 54 static void parse_generic_line(pj_scanner *scanner, pj_str_t *str, 55 parse_context *ctx); 56 static void parse_connection_info(pj_scanner *scanner, pjmedia_sdp_conn *conn, 57 parse_context *ctx); 58 static pjmedia_sdp_attr *parse_attr(pj_pool_t *pool, pj_scanner *scanner, 59 parse_context *ctx); 60 static void parse_media(pj_scanner *scanner, pjmedia_sdp_media *med, 61 parse_context *ctx); 62 122 63 123 64 /* … … 144 85 } 145 86 146 static int print_rtpmap_attr(const pjsdp_rtpmap_attr *rtpmap, 147 char *buf, int len) 148 { 149 char *p = buf; 150 151 if (len < 16+rtpmap->encoding_name.slen+rtpmap->parameter.slen) { 152 return -1; 153 } 87 PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_create( pj_pool_t *pool, 88 const char *name, 89 const pj_str_t *value) 90 { 91 pjmedia_sdp_attr *attr; 92 93 PJ_ASSERT_RETURN(pool && name, NULL); 94 95 attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr)); 96 pj_strdup2(pool, &attr->name, name); 97 98 if (value) 99 pj_strdup(pool, &attr->value, value); 100 else { 101 attr->value.ptr = NULL; 102 attr->value.slen = 0; 103 } 104 105 return attr; 106 } 107 108 PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_clone(pj_pool_t *pool, 109 const pjmedia_sdp_attr *rhs) 110 { 111 pjmedia_sdp_attr *attr; 154 112 155 /* colon and payload type. */ 156 *p++ = ':'; 157 len = pj_utoa(rtpmap->payload_type, p); 158 p += len; 159 160 /* space, encoding name */ 113 PJ_ASSERT_RETURN(pool && rhs, NULL); 114 115 attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr)); 116 117 pj_strdup(pool, &attr->name, &rhs->name); 118 pj_strdup(pool, &attr->value, &rhs->value); 119 120 return attr; 121 } 122 123 PJ_DEF(pjmedia_sdp_attr*) 124 pjmedia_sdp_attr_find (unsigned count, 125 const pjmedia_sdp_attr *const attr_array[], 126 const pj_str_t *name, 127 const pj_str_t *c_fmt) 128 { 129 char fmtbuf[16]; 130 pj_str_t fmt = { NULL, 0}; 131 unsigned i; 132 133 if (c_fmt) { 134 /* To search the format, we prepend the string with a colon and 135 * append space 136 */ 137 PJ_ASSERT_RETURN(c_fmt->slen<sizeof(fmtbuf)-2, NULL); 138 fmt.ptr = fmtbuf; 139 fmt.slen = c_fmt->slen + 2; 140 fmtbuf[0] = ':'; 141 pj_memcpy(fmt.ptr+1, c_fmt->ptr, c_fmt->slen); 142 fmtbuf[c_fmt->slen+1] = ' '; 143 144 } 145 146 for (i=0; i<count; ++i) { 147 if (pj_strcmp(&attr_array[i]->name, name) == 0) { 148 const pjmedia_sdp_attr *a = attr_array[i]; 149 if (c_fmt) { 150 if (a->value.slen > fmt.slen && 151 pj_strncmp(&a->value, &fmt, fmt.slen)==0) 152 { 153 return (pjmedia_sdp_attr*)a; 154 } 155 } else 156 return (pjmedia_sdp_attr*)a; 157 } 158 } 159 return NULL; 160 } 161 162 PJ_DEF(pjmedia_sdp_attr*) 163 pjmedia_sdp_attr_find2(unsigned count, 164 const pjmedia_sdp_attr *const attr_array[], 165 const char *c_name, 166 const pj_str_t *c_fmt) 167 { 168 pj_str_t name; 169 170 name.ptr = (char*)c_name; 171 name.slen = pj_native_strlen(c_name); 172 173 return pjmedia_sdp_attr_find(count, attr_array, &name, c_fmt); 174 } 175 176 177 PJ_DEF(pj_status_t) pjmedia_sdp_attr_add(unsigned *count, 178 pjmedia_sdp_attr *attr_array[], 179 pjmedia_sdp_attr *attr) 180 { 181 PJ_ASSERT_RETURN(count && attr_array && attr, PJ_EINVAL); 182 PJ_ASSERT_RETURN(*count < PJSDP_MAX_ATTR, PJ_ETOOMANY); 183 184 attr_array[*count] = attr; 185 (*count)++; 186 187 return PJ_SUCCESS; 188 } 189 190 191 PJ_DEF(unsigned) pjmedia_sdp_attr_remove_all(unsigned *count, 192 pjmedia_sdp_attr *attr_array[], 193 const char *name) 194 { 195 unsigned i, removed = 0; 196 pj_str_t attr_name; 197 198 PJ_ASSERT_RETURN(count && attr_array && name, PJ_EINVAL); 199 200 attr_name.ptr = (char*)name; 201 attr_name.slen = pj_native_strlen(name); 202 203 for (i=0; i<*count; ) { 204 if (pj_strcmp(&attr_array[i]->name, &attr_name)==0) { 205 pj_array_erase(attr_array, sizeof(pjmedia_sdp_attr*), 206 *count, i); 207 --(*count); 208 ++removed; 209 } else { 210 ++i; 211 } 212 } 213 214 return removed; 215 } 216 217 218 PJ_DEF(pj_status_t) pjmedia_sdp_attr_remove( unsigned *count, 219 pjmedia_sdp_attr *attr_array[], 220 pjmedia_sdp_attr *attr ) 221 { 222 unsigned i, removed=0; 223 224 PJ_ASSERT_RETURN(count && attr_array && attr, PJ_EINVAL); 225 226 for (i=0; i<*count; ) { 227 if (attr_array[i] == attr) { 228 pj_array_erase(attr_array, sizeof(pjmedia_sdp_attr*), 229 *count, i); 230 --(*count); 231 ++removed; 232 } else { 233 ++i; 234 } 235 } 236 237 return removed ? PJ_SUCCESS : PJ_ENOTFOUND; 238 } 239 240 241 PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_rtpmap( const pjmedia_sdp_attr *attr, 242 pjmedia_sdp_rtpmap *rtpmap) 243 { 244 const char *p = attr->value.ptr; 245 const char *end = attr->value.ptr + attr->value.slen; 246 pj_str_t token; 247 248 PJ_ASSERT_RETURN(pj_strcmp2(&attr->name, "rtpmap")==0, PJ_EINVALIDOP); 249 250 /* rtpmap sample: 251 * a=rtpmap:98 L16/16000/2. 252 */ 253 254 /* Eat the first ':' */ 255 if (*p != ':') return PJMEDIA_SDP_EINRTPMAP; 256 257 /* Get ':' */ 258 ++p; 259 260 /* Get payload type. */ 261 token.ptr = (char*)p; 262 while (pj_isdigit(*p) && p!=end) 263 ++p; 264 token.slen = p - token.ptr; 265 if (token.slen == 0) 266 return PJMEDIA_SDP_EINRTPMAP; 267 268 rtpmap->pt = token; 269 270 /* Expecting space after payload type. */ 271 if (*p != ' ') return PJMEDIA_SDP_EINRTPMAP; 272 273 /* Get space. */ 274 ++p; 275 276 /* Get encoding name. */ 277 token.ptr = (char*)p; 278 while (*p != '/' && p != end) 279 ++p; 280 token.slen = p - token.ptr; 281 if (token.slen == 0) 282 return PJMEDIA_SDP_EINRTPMAP; 283 rtpmap->enc_name = token; 284 285 /* Expecting '/' after encoding name. */ 286 if (*p != '/') return PJMEDIA_SDP_EINRTPMAP; 287 288 /* Get '/' */ 289 ++p; 290 291 /* Get the clock rate. */ 292 token.ptr = (char*)p; 293 while (pj_isdigit(*p) && p != end) 294 ++p; 295 token.slen = p - token.ptr; 296 if (token.slen == 0) 297 return PJMEDIA_SDP_EINRTPMAP; 298 299 rtpmap->clock_rate = pj_strtoul(&token); 300 301 /* Expecting either '/' or EOF */ 302 if (*p != '/' && p != end) 303 return PJMEDIA_SDP_EINRTPMAP; 304 305 if (*p == '/') { 306 ++p; 307 token.ptr = (char*)p; 308 token.slen = end-p; 309 rtpmap->param = token; 310 } else { 311 rtpmap->param.ptr = NULL; 312 rtpmap->param.slen = 0; 313 } 314 315 return PJ_SUCCESS; 316 317 } 318 319 PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_fmtp( const pjmedia_sdp_attr *attr, 320 pjmedia_sdp_fmtp *fmtp) 321 { 322 const char *p = attr->value.ptr; 323 const char *end = attr->value.ptr + attr->value.slen; 324 pj_str_t token; 325 326 PJ_ASSERT_RETURN(pj_strcmp2(&attr->name, "fmtp")==0, PJ_EINVALIDOP); 327 328 /* fmtp BNF: 329 * a=fmtp:<format> <format specific parameter> 330 */ 331 332 /* Eat the first ':' */ 333 if (*p != ':') return PJMEDIA_SDP_EINFMTP; 334 335 /* Get ':' */ 336 ++p; 337 338 /* Get format. */ 339 token.ptr = (char*)p; 340 while (pj_isdigit(*p) && p!=end) 341 ++p; 342 token.slen = p - token.ptr; 343 if (token.slen == 0) 344 return PJMEDIA_SDP_EINFMTP; 345 346 fmtp->fmt = token; 347 348 /* Expecting space after format. */ 349 if (*p != ' ') return PJMEDIA_SDP_EINFMTP; 350 351 /* Get space. */ 352 ++p; 353 354 /* Set the remaining string as fmtp format parameter. */ 355 fmtp->fmt_param.ptr = (char*)p; 356 fmtp->fmt_param.slen = end - p; 357 358 return PJ_SUCCESS; 359 } 360 361 PJ_DEF(pj_status_t) pjmedia_sdp_attr_to_rtpmap(pj_pool_t *pool, 362 const pjmedia_sdp_attr *attr, 363 pjmedia_sdp_rtpmap **p_rtpmap) 364 { 365 PJ_ASSERT_RETURN(pool && attr && p_rtpmap, PJ_EINVAL); 366 367 *p_rtpmap = pj_pool_alloc(pool, sizeof(pjmedia_sdp_rtpmap)); 368 PJ_ASSERT_RETURN(*p_rtpmap, PJ_ENOMEM); 369 370 return pjmedia_sdp_attr_get_rtpmap(attr, *p_rtpmap); 371 } 372 373 374 PJ_DEF(pj_status_t) pjmedia_sdp_rtpmap_to_attr(pj_pool_t *pool, 375 const pjmedia_sdp_rtpmap *rtpmap, 376 pjmedia_sdp_attr **p_attr) 377 { 378 pjmedia_sdp_attr *attr; 379 char tempbuf[64], *p, *endbuf; 380 int i; 381 382 /* Check arguments. */ 383 PJ_ASSERT_RETURN(pool && rtpmap && p_attr, PJ_EINVAL); 384 385 /* Check that mandatory attributes are specified. */ 386 PJ_ASSERT_RETURN(rtpmap->enc_name.slen && rtpmap->clock_rate, 387 PJMEDIA_SDP_EINRTPMAP); 388 389 /* Check size. */ 390 i = rtpmap->enc_name.slen + rtpmap->param.slen + 32; 391 if (i >= sizeof(tempbuf)-1) { 392 pj_assert(!"rtpmap attribute is too long"); 393 return PJMEDIA_SDP_ERTPMAPTOOLONG; 394 } 395 396 attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr)); 397 PJ_ASSERT_RETURN(attr != NULL, PJ_ENOMEM); 398 399 attr->name.ptr = "rtpmap"; 400 attr->name.slen = 6; 401 402 p = tempbuf; 403 endbuf = tempbuf+sizeof(tempbuf); 404 405 /* Add payload type. */ 406 pj_memcpy(p, rtpmap->pt.ptr, rtpmap->pt.slen); 407 p += rtpmap->pt.slen; 161 408 *p++ = ' '; 162 pj_memcpy(p, rtpmap->encoding_name.ptr, rtpmap->encoding_name.slen); 163 p += rtpmap->encoding_name.slen; 164 165 /* slash, clock-rate. */ 409 410 /* Add encoding name. */ 411 for (i=0; i<rtpmap->enc_name.slen; ++i) 412 p[i] = rtpmap->enc_name.ptr[i]; 413 p += rtpmap->enc_name.slen; 166 414 *p++ = '/'; 167 len = pj_utoa(rtpmap->clock_rate, p); 168 p += len; 169 170 /* optionally add encoding parameter. */ 171 if (rtpmap->parameter.slen) { 415 416 /* Add clock rate. */ 417 p += pj_utoa(rtpmap->clock_rate, p); 418 419 /* Add parameter if necessary. */ 420 if (rtpmap->param.slen > 0) { 172 421 *p++ = '/'; 173 pj_memcpy(p, rtpmap->parameter.ptr, rtpmap->parameter.slen); 174 p += rtpmap->parameter.slen; 175 } 176 177 return p-buf; 178 } 179 180 static int print_generic_string_attr(const pjsdp_attr_string *attr, 181 char *buf, int len) 182 { 183 char *p = buf; 184 185 if (len < attr->value.slen + 4) { 186 return -1; 187 } 188 189 /* colon and attribute value. */ 190 *p++ = ':'; 191 pj_memcpy(p, attr->value.ptr, attr->value.slen); 192 p += attr->value.slen; 193 194 return p-buf; 195 } 196 197 static int print_generic_num_attr(const pjsdp_attr_num *attr, char *buf, int len) 198 { 199 char *p = buf; 200 201 if (len < 10) { 202 return -1; 203 } 204 *p++ = ':'; 205 return pj_utoa(attr->value, p); 206 } 207 208 static int print_name_only_attr(const pjsdp_attr *attr, char *buf, int len) 209 { 210 PJ_UNUSED_ARG(attr); 211 PJ_UNUSED_ARG(buf); 212 PJ_UNUSED_ARG(len); 213 return 0; 214 } 215 216 static int print_fmtp_attr(const pjsdp_fmtp_attr *fmtp, char *buf, int len) 217 { 218 char *p = buf; 219 220 if (len < 4+fmtp->format.slen+fmtp->param.slen) { 221 return -1; 222 } 223 224 /* colon and format. */ 225 *p++ = ':'; 226 pj_memcpy(p, fmtp->format.ptr, fmtp->format.slen); 227 p += fmtp->format.slen; 228 229 /* space and parameter. */ 230 *p++ = ' '; 231 pj_memcpy(p, fmtp->param.ptr, fmtp->param.slen); 232 p += fmtp->param.slen; 233 234 return p-buf; 235 } 236 237 238 static int print_attr(const pjsdp_attr *attr, char *buf, int len) 239 { 240 char *p = buf; 241 struct attr_map_rec *desc = &attr_map[attr->type]; 242 243 if (len < 16) { 244 return -1; 245 } 246 247 *p++ = 'a'; 248 *p++ = '='; 249 pj_memcpy(p, desc->name.ptr, desc->name.slen); 250 p += desc->name.slen; 251 252 len = (*desc->print_attr)(attr, p, (buf+len)-p); 253 if (len < 0) { 254 return -1; 255 } 256 p += len; 257 *p++ = '\r'; 258 *p++ = '\n'; 259 return p-buf; 260 } 261 262 static pjsdp_attr* clone_rtpmap_attr (pj_pool_t *pool, const pjsdp_attr *p) 263 { 264 const pjsdp_rtpmap_attr *rhs = (const pjsdp_rtpmap_attr*)p; 265 pjsdp_rtpmap_attr *attr = pj_pool_alloc (pool, sizeof(pjsdp_rtpmap_attr)); 266 if (!attr) 267 return NULL; 268 269 attr->type = rhs->type; 270 attr->payload_type = rhs->payload_type; 271 if (!pj_strdup (pool, &attr->encoding_name, &rhs->encoding_name)) return NULL; 272 attr->clock_rate = rhs->clock_rate; 273 if (!pj_strdup (pool, &attr->parameter, &rhs->parameter)) return NULL; 274 275 return (pjsdp_attr*)attr; 276 } 277 278 static pjsdp_attr* clone_generic_string_attr (pj_pool_t *pool, const pjsdp_attr *p) 279 { 280 const pjsdp_attr_string* rhs = (const pjsdp_attr_string*) p; 281 pjsdp_attr_string *attr = pj_pool_alloc (pool, sizeof(pjsdp_attr_string)); 282 if (!attr) 283 return NULL; 284 285 attr->type = rhs->type; 286 if (!pj_strdup (pool, &attr->value, &rhs->value)) return NULL; 287 288 return (pjsdp_attr*)attr; 289 } 290 291 static pjsdp_attr* clone_generic_num_attr (pj_pool_t *pool, const pjsdp_attr *p) 292 { 293 const pjsdp_attr_num* rhs = (const pjsdp_attr_num*) p; 294 pjsdp_attr_num *attr = pj_pool_alloc (pool, sizeof(pjsdp_attr_num)); 295 if (!attr) 296 return NULL; 297 298 attr->type = rhs->type; 299 attr->value = rhs->value; 300 301 return (pjsdp_attr*)attr; 302 } 303 304 static pjsdp_attr* clone_name_only_attr (pj_pool_t *pool, const pjsdp_attr *rhs) 305 { 306 pjsdp_attr *attr = pj_pool_alloc (pool, sizeof(pjsdp_attr)); 307 if (!attr) 308 return NULL; 309 310 attr->type = rhs->type; 311 return attr; 312 } 313 314 static pjsdp_attr* clone_fmtp_attr (pj_pool_t *pool, const pjsdp_attr *p) 315 { 316 const pjsdp_fmtp_attr* rhs = (const pjsdp_fmtp_attr*) p; 317 pjsdp_fmtp_attr *attr = pj_pool_alloc (pool, sizeof(pjsdp_fmtp_attr)); 318 if (!attr) 319 return NULL; 320 321 attr->type = rhs->type; 322 if (!pj_strdup (pool, &attr->format, &rhs->format)) return NULL; 323 if (!pj_strdup (pool, &attr->param, &rhs->param)) return NULL; 324 325 return (pjsdp_attr*)attr; 326 } 327 328 PJ_DEF(pjsdp_attr*) pjsdp_attr_clone (pj_pool_t *pool, const pjsdp_attr *rhs) 329 { 330 struct attr_map_rec *desc; 331 332 if (rhs->type >= PJSDP_END_OF_ATTR) { 333 pj_assert(0); 334 return NULL; 335 } 336 337 desc = &attr_map[rhs->type]; 338 return (*desc->clone) (pool, rhs); 339 } 340 341 PJ_DEF(const pjsdp_attr*) pjsdp_attr_find (int count, const pjsdp_attr *attr_array[], int type) 342 { 343 int i; 344 345 for (i=0; i<count; ++i) { 346 if (attr_array[i]->type == type) 347 return attr_array[i]; 348 } 349 return NULL; 350 } 351 352 static int print_connection_info( pjsdp_conn_info *c, char *buf, int len) 422 for (i=0; i<rtpmap->param.slen; ++i) 423 p[i] = rtpmap->param.ptr[i]; 424 p += rtpmap->param.slen; 425 } 426 427 *p = '\0'; 428 429 attr->value.slen = p-tempbuf; 430 attr->value.ptr = pj_pool_alloc(pool, attr->value.slen); 431 pj_memcpy(attr->value.ptr, tempbuf, attr->value.slen); 432 433 *p_attr = attr; 434 return PJ_SUCCESS; 435 } 436 437 438 static int print_connection_info( pjmedia_sdp_conn *c, char *buf, int len) 353 439 { 354 440 char *p = buf; … … 373 459 } 374 460 375 PJ_DEF(pjsdp_conn_info*) pjsdp_conn_info_clone (pj_pool_t *pool, const pjsdp_conn_info *rhs) 376 { 377 pjsdp_conn_info *c = pj_pool_alloc (pool, sizeof(pjsdp_conn_info)); 461 PJ_DEF(pjmedia_sdp_conn*) pjmedia_sdp_conn_clone (pj_pool_t *pool, 462 const pjmedia_sdp_conn *rhs) 463 { 464 pjmedia_sdp_conn *c = pj_pool_alloc (pool, sizeof(pjmedia_sdp_conn)); 378 465 if (!c) return NULL; 379 466 … … 385 472 } 386 473 387 static int print_media_desc( pjsdp_media_desc *m, char *buf, int len) 474 static pj_ssize_t print_attr(const pjmedia_sdp_attr *attr, 475 char *buf, pj_size_t len) 476 { 477 char *p = buf; 478 479 if ((int)len < attr->name.slen + attr->value.slen + 10) 480 return -1; 481 482 *p++ = 'a'; 483 *p++ = '='; 484 pj_memcpy(p, attr->name.ptr, attr->name.slen); 485 p += attr->name.slen; 486 487 488 if (attr->value.slen) { 489 pj_memcpy(p, attr->value.ptr, attr->value.slen); 490 p += attr->value.slen; 491 } 492 493 *p++ = '\r'; 494 *p++ = '\n'; 495 return p-buf; 496 } 497 498 static int print_media_desc( pjmedia_sdp_media *m, char *buf, int len) 388 499 { 389 500 char *p = buf; … … 440 551 } 441 552 442 PJ_DEF(pjsdp_media_desc*) pjsdp_media_desc_clone (pj_pool_t *pool, 443 const pjsdp_media_desc *rhs) 553 PJ_DEF(pjmedia_sdp_media*) pjmedia_sdp_media_clone( 554 pj_pool_t *pool, 555 const pjmedia_sdp_media *rhs) 444 556 { 445 557 unsigned int i; 446 pjsdp_media_desc *m = pj_pool_alloc (pool, sizeof(pjsdp_media_desc)); 447 if (!m) 448 return NULL; 558 pjmedia_sdp_media *m = pj_pool_alloc (pool, sizeof(pjmedia_sdp_media)); 559 PJ_ASSERT_RETURN(m != NULL, NULL); 449 560 450 561 pj_strdup (pool, &m->desc.media, &rhs->desc.media); … … 457 568 458 569 if (rhs->conn) { 459 m->conn = pjsdp_conn_info_clone (pool, rhs->conn); 460 if (!m->conn) 461 return NULL; 570 m->conn = pjmedia_sdp_conn_clone (pool, rhs->conn); 571 PJ_ASSERT_RETURN(m->conn != NULL, NULL); 462 572 } else { 463 573 m->conn = NULL; … … 466 576 m->attr_count = rhs->attr_count; 467 577 for (i=0; i < rhs->attr_count; ++i) { 468 m->attr[i] = pjsdp_attr_clone (pool, rhs->attr[i]); 469 if (!m->attr[i]) 470 return NULL; 578 m->attr[i] = pjmedia_sdp_attr_clone (pool, rhs->attr[i]); 579 PJ_ASSERT_RETURN(m->attr[i] != NULL, NULL); 471 580 } 472 581 … … 474 583 } 475 584 476 /** Check if the media description has the specified attribute. */ 477 PJ_DEF(pj_bool_t) pjsdp_media_desc_has_attr (const pjsdp_media_desc *m, 478 pjsdp_attr_type_e attr_type) 479 { 480 unsigned i; 481 for (i=0; i<m->attr_count; ++i) { 482 pjsdp_attr *attr = m->attr[i]; 483 if (attr->type == attr_type) 484 return 1; 485 } 486 return 0; 487 } 488 489 /** Find rtpmap attribute for the specified payload type. */ 490 PJ_DEF(const pjsdp_rtpmap_attr*) 491 pjsdp_media_desc_find_rtpmap (const pjsdp_media_desc *m, unsigned pt) 492 { 493 unsigned i; 494 for (i=0; i<m->attr_count; ++i) { 495 pjsdp_attr *attr = m->attr[i]; 496 if (attr->type == PJSDP_ATTR_RTPMAP) { 497 const pjsdp_rtpmap_attr* rtpmap = (const pjsdp_rtpmap_attr*)attr; 498 if (rtpmap->payload_type == pt) 499 return rtpmap; 500 } 501 } 502 return NULL; 503 } 504 505 506 static int print_session(const pjsdp_session_desc *ses, char *buf, pj_ssize_t len) 585 PJ_DEF(pjmedia_sdp_attr*) 586 pjmedia_sdp_media_find_attr(const pjmedia_sdp_media *m, 587 const pj_str_t *name, const pj_str_t *fmt) 588 { 589 PJ_ASSERT_RETURN(m && name, NULL); 590 return pjmedia_sdp_attr_find(m->attr_count, m->attr, name, fmt); 591 } 592 593 594 595 PJ_DEF(pjmedia_sdp_attr*) 596 pjmedia_sdp_media_find_attr2(const pjmedia_sdp_media *m, 597 const char *name, const pj_str_t *fmt) 598 { 599 PJ_ASSERT_RETURN(m && name, NULL); 600 return pjmedia_sdp_attr_find2(m->attr_count, m->attr, name, fmt); 601 } 602 603 604 PJ_DEF(pj_status_t) pjmedia_sdp_media_add_attr( pjmedia_sdp_media *m, 605 pjmedia_sdp_attr *attr) 606 { 607 return pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 608 } 609 610 PJ_DEF(unsigned) 611 pjmedia_sdp_media_remove_all_attr(pjmedia_sdp_media *m, 612 const char *name) 613 { 614 return pjmedia_sdp_attr_remove_all(&m->attr_count, m->attr, name); 615 } 616 617 PJ_DEF(pj_status_t) 618 pjmedia_sdp_media_remove_attr(pjmedia_sdp_media *m, 619 pjmedia_sdp_attr *attr) 620 { 621 return pjmedia_sdp_attr_remove(&m->attr_count, m->attr, attr); 622 } 623 624 static int print_session(const pjmedia_sdp_session *ses, 625 char *buf, pj_ssize_t len) 507 626 { 508 627 char *p = buf; … … 605 724 */ 606 725 607 static void parse_version(pj_scanner *scanner) 608 { 726 static void parse_version(pj_scanner *scanner, parse_context *ctx) 727 { 728 ctx->last_error = PJMEDIA_SDP_EINVER; 729 609 730 pj_scan_advance_n(scanner, 3, SKIP_WS); 610 731 pj_scan_get_newline(scanner); 611 732 } 612 733 613 static void parse_origin(pj_scanner *scanner, pjsdp_session_desc *ses) 734 static void parse_origin(pj_scanner *scanner, pjmedia_sdp_session *ses, 735 parse_context *ctx) 614 736 { 615 737 pj_str_t str; 738 739 ctx->last_error = PJMEDIA_SDP_EINORIGIN; 616 740 617 741 /* o= */ … … 647 771 } 648 772 649 static void parse_time(pj_scanner *scanner, pjsdp_session_desc *ses) 773 static void parse_time(pj_scanner *scanner, pjmedia_sdp_session *ses, 774 parse_context *ctx) 650 775 { 651 776 pj_str_t str; 777 778 ctx->last_error = PJMEDIA_SDP_EINTIME; 652 779 653 780 /* t= */ … … 668 795 } 669 796 670 static void parse_generic_line(pj_scanner *scanner, pj_str_t *str) 671 { 797 static void parse_generic_line(pj_scanner *scanner, pj_str_t *str, 798 parse_context *ctx) 799 { 800 ctx->last_error = PJMEDIA_SDP_EINSDP; 801 672 802 /* x= */ 673 803 pj_scan_advance_n(scanner, 2, SKIP_WS); … … 680 810 } 681 811 682 static void parse_connection_info(pj_scanner *scanner, pjsdp_conn_info *conn) 683 { 812 static void parse_connection_info(pj_scanner *scanner, pjmedia_sdp_conn *conn, 813 parse_context *ctx) 814 { 815 ctx->last_error = PJMEDIA_SDP_EINCONN; 816 684 817 /* c= */ 685 818 pj_scan_advance_n(scanner, 2, SKIP_WS); … … 700 833 } 701 834 702 static void parse_media(pj_scanner *scanner, pjsdp_media_desc *med) 835 static void parse_media(pj_scanner *scanner, pjmedia_sdp_media *med, 836 parse_context *ctx) 703 837 { 704 838 pj_str_t str; 839 840 ctx->last_error = PJMEDIA_SDP_EINMEDIA; 705 841 706 842 /* m= */ … … 742 878 } 743 879 744 static pjsdp_rtpmap_attr * parse_rtpmap_attr( pj_pool_t *pool, pj_scanner *scanner ) 745 { 746 pjsdp_rtpmap_attr *rtpmap; 747 pj_str_t str; 748 749 rtpmap = pj_pool_calloc(pool, 1, sizeof(*rtpmap)); 750 if (pj_scan_get_char(scanner) != ':') { 751 PJ_THROW(SYNTAX_ERROR); 752 } 753 pj_scan_get_until_ch(scanner, ' ', &str); 754 rtpmap->payload_type = pj_strtoul(&str); 755 pj_scan_get_char(scanner); 756 757 pj_scan_get_until_ch(scanner, '/', &rtpmap->encoding_name); 758 pj_scan_get_char(scanner); 759 pj_scan_get(scanner, &cs_token, &str); 760 rtpmap->clock_rate = pj_strtoul(&str); 761 762 if (*scanner->curptr == '/') { 763 pj_scan_get_char(scanner); 764 pj_scan_get_until_ch(scanner, '\r', &rtpmap->parameter); 765 } 766 767 return rtpmap; 768 } 769 770 static pjsdp_attr_string * parse_generic_string_attr( pj_pool_t *pool, pj_scanner *scanner ) 771 { 772 pjsdp_attr_string *attr; 773 attr = pj_pool_calloc(pool, 1, sizeof(*attr)); 774 775 if (pj_scan_get_char(scanner) != ':') { 776 PJ_THROW(SYNTAX_ERROR); 777 } 778 pj_scan_get_until_ch(scanner, '\r', &attr->value); 779 return attr; 780 } 781 782 static pjsdp_attr_num * parse_generic_num_attr( pj_pool_t *pool, pj_scanner *scanner ) 783 { 784 pjsdp_attr_num *attr; 785 pj_str_t str; 786 787 attr = pj_pool_calloc(pool, 1, sizeof(*attr)); 788 789 if (pj_scan_get_char(scanner) != ':') { 790 PJ_THROW(SYNTAX_ERROR); 791 } 792 pj_scan_get_until_ch(scanner, '\r', &str); 793 attr->value = pj_strtoul(&str); 794 return attr; 795 } 796 797 static pjsdp_attr * parse_name_only_attr( pj_pool_t *pool, pj_scanner *scanner ) 798 { 799 pjsdp_attr *attr; 800 880 static void on_scanner_error(pj_scanner *scanner) 881 { 801 882 PJ_UNUSED_ARG(scanner); 802 attr = pj_pool_calloc(pool, 1, sizeof(*attr)); 803 return attr; 804 } 805 806 static pjsdp_fmtp_attr * parse_fmtp_attr( pj_pool_t *pool, pj_scanner *scanner ) 807 { 808 pjsdp_fmtp_attr *fmtp; 809 810 fmtp = pj_pool_calloc(pool, 1, sizeof(*fmtp)); 811 812 if (pj_scan_get_char(scanner) != ':') { 813 PJ_THROW(SYNTAX_ERROR); 814 } 815 pj_scan_get_until_ch(scanner, ' ', &fmtp->format); 816 pj_scan_get_char(scanner); 817 pj_scan_get_until_ch(scanner, '\r', &fmtp->param); 818 return fmtp; 819 } 820 821 static pjsdp_attr *parse_attr( pj_pool_t *pool, pj_scanner *scanner) 822 { 823 void * (*parse_func)(pj_pool_t *pool, pj_scanner *scanner) = NULL; 824 pj_str_t attrname; 825 unsigned i; 826 pjsdp_attr *attr; 883 884 PJ_THROW(SYNTAX_ERROR); 885 } 886 887 static pjmedia_sdp_attr *parse_attr( pj_pool_t *pool, pj_scanner *scanner, 888 parse_context *ctx) 889 { 890 pjmedia_sdp_attr *attr; 891 892 ctx->last_error = PJMEDIA_SDP_EINATTR; 893 894 attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr)); 827 895 828 896 /* skip a= */ … … 830 898 831 899 /* get attr name. */ 832 pj_scan_get(scanner, &cs_token, &attrname); 833 834 /* find entry to handle attrname */ 835 for (i=0; i<PJ_ARRAY_SIZE(attr_map); ++i) { 836 struct attr_map_rec *p = &attr_map[i]; 837 if (pj_strcmp(&attrname, &p->name) == 0) { 838 parse_func = p->parse_attr; 839 break; 840 } 841 } 842 843 /* fallback to generic string parser. */ 844 if (parse_func == NULL) { 845 parse_func = &parse_generic_string_attr; 846 } 847 848 attr = (*parse_func)(pool, scanner); 849 attr->type = i; 850 900 pj_scan_get(scanner, &cs_token, &attr->name); 901 902 if (*scanner->curptr != '\r' && *scanner->curptr != '\n') { 903 /* get value */ 904 pj_scan_get_until_ch(scanner, '\r', &attr->value); 905 } else { 906 attr->value.ptr = NULL; 907 attr->value.slen = 0; 908 } 909 851 910 /* newline */ 852 911 pj_scan_get_newline(scanner); 853 912 854 913 return attr; 855 }856 857 static void on_scanner_error(pj_scanner *scanner)858 {859 PJ_UNUSED_ARG(scanner);860 861 PJ_THROW(SYNTAX_ERROR);862 914 } 863 915 … … 865 917 * Parse SDP message. 866 918 */ 867 PJ_DEF(pjsdp_session_desc*) pjsdp_parse( char *buf, pj_size_t len, 868 pj_pool_t *pool) 919 PJ_DEF(pj_status_t) pjmedia_sdp_parse( pj_pool_t *pool, 920 char *buf, pj_size_t len, 921 pjmedia_sdp_session **p_sdp) 869 922 { 870 923 pj_scanner scanner; 871 pj sdp_session_desc*session;872 pj sdp_media_desc*media = NULL;924 pjmedia_sdp_session *session; 925 pjmedia_sdp_media *media = NULL; 873 926 void *attr; 874 pj sdp_conn_info*conn;927 pjmedia_sdp_conn *conn; 875 928 pj_str_t dummy; 876 929 int cur_name = 254; 930 parse_context ctx; 877 931 PJ_USE_EXCEPTION; 878 932 933 ctx.last_error = PJ_SUCCESS; 934 879 935 init_sdp_parser(); 880 936 881 937 pj_scan_init(&scanner, buf, len, 0, &on_scanner_error); 882 session = pj_pool_calloc(pool, 1, sizeof(*session)); 938 session = pj_pool_calloc(pool, 1, sizeof(pjmedia_sdp_session)); 939 PJ_ASSERT_RETURN(session != NULL, PJ_ENOMEM); 883 940 884 941 PJ_TRY { … … 887 944 switch (cur_name) { 888 945 case 'a': 889 attr = parse_attr(pool, &scanner );946 attr = parse_attr(pool, &scanner, &ctx); 890 947 if (attr) { 891 948 if (media) { … … 897 954 break; 898 955 case 'o': 899 parse_origin(&scanner, session );956 parse_origin(&scanner, session, &ctx); 900 957 break; 901 958 case 's': 902 parse_generic_line(&scanner, &session->name );959 parse_generic_line(&scanner, &session->name, &ctx); 903 960 break; 904 961 case 'c': 905 962 conn = pj_pool_calloc(pool, 1, sizeof(*conn)); 906 parse_connection_info(&scanner, conn );963 parse_connection_info(&scanner, conn, &ctx); 907 964 if (media) { 908 965 media->conn = conn; … … 912 969 break; 913 970 case 't': 914 parse_time(&scanner, session );971 parse_time(&scanner, session, &ctx); 915 972 break; 916 973 case 'm': 917 974 media = pj_pool_calloc(pool, 1, sizeof(*media)); 918 parse_media(&scanner, media );975 parse_media(&scanner, media, &ctx); 919 976 session->media[ session->media_count++ ] = media; 920 977 break; 921 978 case 'v': 922 parse_version(&scanner );979 parse_version(&scanner, &ctx); 923 980 break; 924 981 default: 925 parse_generic_line(&scanner, &dummy );982 parse_generic_line(&scanner, &dummy, &ctx); 926 983 break; 927 984 } 928 985 } 986 987 ctx.last_error = PJ_SUCCESS; 988 929 989 } 930 990 PJ_CATCH(SYNTAX_ERROR) { 931 PJ_LOG(2, (LOG_THIS, "Syntax error in SDP parser '%c' line %d col %d", 932 cur_name, scanner.line, pj_scan_get_col(&scanner))); 933 if (!pj_scan_is_eof(&scanner)) { 934 if (*scanner.curptr != '\r') { 935 pj_scan_get_until_ch(&scanner, '\r', &dummy); 936 } 937 pj_scan_get_newline(&scanner); 938 } 991 992 char errmsg[PJMEDIA_ERR_MSG_SIZE]; 993 pjmedia_strerror(ctx.last_error, errmsg, sizeof(errmsg)); 994 995 PJ_LOG(4, (THIS_FILE, "Error parsing SDP in line %d col %d: %s", 996 scanner.line, pj_scan_get_col(&scanner), 997 errmsg)); 998 999 session = NULL; 1000 939 1001 } 940 1002 PJ_END; 941 1003 942 1004 pj_scan_fini(&scanner); 943 return session; 1005 1006 *p_sdp = session; 1007 return ctx.last_error; 944 1008 } 945 1009 … … 947 1011 * Print SDP description. 948 1012 */ 949 PJ_DEF(int) pjsdp_print( const pjsdp_session_desc *desc, char *buf, pj_size_t size) 1013 PJ_DEF(int) pjmedia_sdp_print( const pjmedia_sdp_session *desc, 1014 char *buf, pj_size_t size) 950 1015 { 951 1016 return print_session(desc, buf, size); … … 953 1018 954 1019 1020 /* 1021 * Clone session 1022 */ 1023 PJ_DEF(pjmedia_sdp_session*) 1024 pjmedia_sdp_session_clone( pj_pool_t *pool, 1025 const pjmedia_sdp_session *rhs) 1026 { 1027 pjmedia_sdp_session *sess; 1028 unsigned i; 1029 1030 PJ_ASSERT_RETURN(pool && rhs, NULL); 1031 1032 sess = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_session)); 1033 PJ_ASSERT_RETURN(sess != NULL, NULL); 1034 1035 /* Clone origin line. */ 1036 pj_strdup(pool, &sess->origin.user, &rhs->origin.user); 1037 sess->origin.id = rhs->origin.id; 1038 sess->origin.version = rhs->origin.version; 1039 pj_strdup(pool, &sess->origin.net_type, &rhs->origin.net_type); 1040 pj_strdup(pool, &sess->origin.addr_type, &rhs->origin.addr_type); 1041 pj_strdup(pool, &sess->origin.addr, &rhs->origin.addr); 1042 1043 /* Clone subject line. */ 1044 pj_strdup(pool, &sess->name, &rhs->name); 1045 1046 /* Clone connection line */ 1047 if (rhs->conn) { 1048 sess->conn = pjmedia_sdp_conn_clone(pool, rhs->conn); 1049 PJ_ASSERT_RETURN(sess->conn != NULL, NULL); 1050 } 1051 1052 /* Clone time line. */ 1053 sess->time.start = rhs->time.start; 1054 sess->time.stop = rhs->time.stop; 1055 1056 /* Duplicate session attributes. */ 1057 sess->attr_count = rhs->attr_count; 1058 for (i=0; i<rhs->attr_count; ++i) { 1059 sess->attr[i] = pjmedia_sdp_attr_clone(pool, rhs->attr[i]); 1060 } 1061 1062 /* Duplicate media descriptors. */ 1063 sess->media_count = rhs->media_count; 1064 for (i=0; i<rhs->media_count; ++i) { 1065 sess->media[i] = pjmedia_sdp_media_clone(pool, rhs->media[i]); 1066 } 1067 1068 return sess; 1069 } 1070 1071 1072 #define CHECK(exp,ret) do { \ 1073 pj_assert(exp); \ 1074 if (!(exp)) \ 1075 return ret; \ 1076 } while (0) 1077 1078 /* Validate SDP connetion info. */ 1079 static pj_status_t validate_sdp_conn(const pjmedia_sdp_conn *c) 1080 { 1081 CHECK( c, PJ_EINVAL); 1082 CHECK( pj_strcmp2(&c->net_type, "IN")==0, PJMEDIA_SDP_EINCONN); 1083 CHECK( pj_strcmp2(&c->addr_type, "IP4")==0 || 1084 pj_strcmp2(&c->addr_type, "IP6")==0, 1085 PJMEDIA_SDP_EINCONN); 1086 CHECK( c->addr.slen != 0, PJMEDIA_SDP_EINCONN); 1087 1088 return PJ_SUCCESS; 1089 } 1090 1091 1092 /* Validate SDP session descriptor. */ 1093 PJ_DEF(pj_status_t) pjmedia_sdp_validate(const pjmedia_sdp_session *sdp) 1094 { 1095 unsigned i; 1096 1097 CHECK( sdp != NULL, PJ_EINVAL); 1098 1099 /* Validate origin line. */ 1100 CHECK( sdp->origin.user.slen != 0, PJMEDIA_SDP_EINORIGIN); 1101 CHECK( pj_strcmp2(&sdp->origin.net_type, "IN")==0, 1102 PJMEDIA_SDP_EINORIGIN); 1103 CHECK( pj_strcmp2(&sdp->origin.addr_type, "IP4")==0 || 1104 pj_strcmp2(&sdp->origin.addr_type, "IP6")==0, 1105 PJMEDIA_SDP_EINORIGIN); 1106 CHECK( sdp->origin.addr.slen != 0, PJMEDIA_SDP_EINORIGIN); 1107 1108 /* Validate subject line. */ 1109 CHECK( sdp->name.slen != 0, PJMEDIA_SDP_EINNAME); 1110 1111 /* Ignore start and stop time. */ 1112 1113 /* If session level connection info is present, validate it. */ 1114 if (sdp->conn) { 1115 pj_status_t status = validate_sdp_conn(sdp->conn); 1116 if (status != PJ_SUCCESS) 1117 return status; 1118 } 1119 1120 /* Validate each media. */ 1121 for (i=0; i<sdp->media_count; ++i) { 1122 const pjmedia_sdp_media *m = sdp->media[i]; 1123 unsigned j; 1124 1125 /* Validate the m= line. */ 1126 CHECK( m->desc.media.slen != 0, PJMEDIA_SDP_EINMEDIA); 1127 CHECK( m->desc.transport.slen != 0, PJMEDIA_SDP_EINMEDIA); 1128 CHECK( m->desc.fmt_count != 0, PJMEDIA_SDP_ENOFMT); 1129 1130 /* If media level connection info is present, validate it. */ 1131 if (m->conn) { 1132 pj_status_t status = validate_sdp_conn(m->conn); 1133 if (status != PJ_SUCCESS) 1134 return status; 1135 } 1136 1137 /* If media doesn't have connection info, then connection info 1138 * must be present in the session. 1139 */ 1140 if (m->conn == NULL) { 1141 if (sdp->conn == NULL) 1142 return PJMEDIA_SDP_EMISSINGCONN; 1143 } 1144 1145 /* Verify payload type. */ 1146 for (j=0; j<m->desc.fmt_count; ++j) { 1147 unsigned pt = pj_strtoul(&m->desc.fmt[j]); 1148 1149 /* Payload type is between 0 and 127. */ 1150 CHECK( pt <= 127, PJMEDIA_SDP_EINPT); 1151 1152 /* If port is not zero, then for each dynamic payload type, an 1153 * rtpmap attribute must be specified. 1154 */ 1155 if (m->desc.port != 0 && pt >= 96) { 1156 const pjmedia_sdp_attr *a; 1157 1158 a = pjmedia_sdp_media_find_attr2(m, "rtpmap", &m->desc.fmt[j]); 1159 CHECK( a != NULL, PJMEDIA_SDP_EMISSINGRTPMAP); 1160 } 1161 } 1162 } 1163 1164 /* Looks good. */ 1165 return PJ_SUCCESS; 1166 } 1167 1168
Note: See TracChangeset
for help on using the changeset viewer.