📄 sdp_decode.c
字号:
break; case 7: // control if (mptr == NULL) { if (sptr->control_string != NULL) { sdp_debug(LOG_ERR, "2nd control statement in media"); return (-1); } sptr->control_string = strdup(lptr); } else { if (mptr->control_string != NULL) { sdp_debug(LOG_ERR, "2nd control statement in session"); return (-1); } mptr->control_string = strdup(lptr); } break; case 8: if (sptr->etag != NULL) { sdp_debug(LOG_ERR, "2nd etag statement"); return (-1); } sptr->etag = strdup(lptr); break; } return (0);} /* * This structure provides the information needed by the parsing * engine in sdp_decode_parse_a. This function processes lines of * the format a=<identifier>[:<options>]. * name - <identifier> * len - sizeof(identifier) (saves on CPU time) * have_colon - if a colon is necessary * remove_spaces_after_colon - if colon is necessary, and we want * to remove spaces before <option>. Do not use this if other character * sets may come into play. * parse_routine - routine to call if keyword matched. Return 0 if successful- * -1 will save the whole "a=..." string. * arg - value to pass to parse_routine */static struct { char *name; uint32_t len; int have_colon; int remove_spaces_after_colon; int (*parse_routine)(int arg, char *lptr, session_desc_t *sptr, media_desc_t *mptr); int arg;} a_types[] ={ { "rtpmap", sizeof("rtpmap"), TRUE, TRUE, sdp_decode_parse_a_rtpmap, 0 }, { "cat", sizeof("cat"), TRUE, TRUE, sdp_decode_parse_a_cat, 0 }, { "fmtp", sizeof("fmtp"), TRUE, TRUE, sdp_decode_parse_a_fmtp, 0 }, { "keywds", sizeof("keywds"), TRUE, FALSE, sdp_decode_parse_a_str, 0}, { "tool", sizeof("tool"), TRUE, TRUE, sdp_decode_parse_a_str, 1}, { "charset", sizeof("charset"), TRUE, TRUE, sdp_decode_parse_a_str, 2}, { "sdplang", sizeof("sdplang"), TRUE, TRUE, sdp_decode_parse_a_str, 3}, { "lang", sizeof("lang"), TRUE, TRUE, sdp_decode_parse_a_str, 4}, { "type", sizeof("type"), TRUE, TRUE, sdp_decode_parse_a_str, 5}, { "orient", sizeof("orient"), TRUE, TRUE, sdp_decode_parse_a_str, 6}, { "control", sizeof("control"), TRUE, TRUE, sdp_decode_parse_a_str, 7}, { "etag", sizeof("etag"), TRUE, TRUE, sdp_decode_parse_a_str, 8}, { "recvonly", sizeof("recvonly"), FALSE, FALSE, sdp_decode_parse_a_bool, 0}, { "sendrecv", sizeof("sendrecv"), FALSE, FALSE, sdp_decode_parse_a_bool, 1}, { "sendonly", sizeof("sendonly"), FALSE, FALSE, sdp_decode_parse_a_bool, 2}, { "ptime", sizeof("ptime"), TRUE, TRUE, sdp_decode_parse_a_int, 0 }, { "quality", sizeof("quality"), TRUE, TRUE, sdp_decode_parse_a_int, 1}, { "framerate", sizeof("framerate"), TRUE, TRUE, sdp_decode_parse_a_frame, 0}, { "range", sizeof("range"), TRUE, TRUE, sdp_decode_parse_a_range, 0 }, { "rtcp", sizeof("rtcp"), TRUE, TRUE, sdp_decode_parse_a_rtcp, 0 }, { NULL, 0, FALSE, FALSE, NULL, 0 },};/* * sdp_decode_parse_a() * decodes a= lines, or stores the complete string in media or session * unparsed_a_lines list. */static int sdp_decode_parse_a (char *lptr, char *line, session_desc_t *sptr, media_desc_t *mptr){ int ix; int errret; int parsed; char *after; ix = 0; errret = 0; parsed = FALSE; /* * go through above array, looking for a complete match */ while (a_types[ix].name != NULL) { if (strncasecmp(lptr, a_types[ix].name, a_types[ix].len - 1) == 0) { after = lptr + a_types[ix].len - 1; if (!(isspace(*after) || *after == ':' || *after == '\0')) { // partial match - not good enough continue; } parsed = TRUE; /* * Have a match. If specified, look for colon, and remove space * after colon */ if (a_types[ix].have_colon) { ADV_SPACE(after); if (*after != ':') { errret = ESDP_ATTRIBUTES_NO_COLON; break; } after++; if (a_types[ix].remove_spaces_after_colon) { ADV_SPACE(after); } } /* * Call the correct parsing routine */ errret = (a_types[ix].parse_routine)(a_types[ix].arg, after, sptr, mptr); break; } ix++; } /* * Worse comes to worst, store the whole line */ if (parsed == FALSE || errret != 0) { if (sdp_add_string_to_list(mptr == NULL ? &sptr->unparsed_a_lines : &mptr->unparsed_a_lines, line) == FALSE) { return (ENOMEM); } } return (0);}/* * sdp_decode_parse_bandwidth() * parses b=<modifier>:<value> * Inputs: lptr - pointer to line, bptr - pointer to store in * Outputs: TRUE - valid, FALSE, invalid */static int sdp_decode_parse_bandwidth (char *lptr, bandwidth_t **bptr){ char *cptr, *endptr; bandwidth_t *new, *p; bandwidth_modifier_t modifier; uint32_t temp; cptr = strchr(lptr, ':'); if (cptr == NULL) { sdp_debug(LOG_ERR, "No colon in bandwidth"); return (ESDP_BANDWIDTH); } *cptr++ = '\0'; if (strncasecmp(lptr, "as", strlen("as")) == 0) { modifier = BANDWIDTH_MODIFIER_AS; } else if (strncasecmp(lptr, "ct", strlen("ct")) == 0) { modifier = BANDWIDTH_MODIFIER_CT; } else { modifier = BANDWIDTH_MODIFIER_USER; endptr = cptr - 2; while (isspace(*endptr) && endptr >lptr) *endptr-- = '\0'; } if (*cptr == '\0') { sdp_debug(LOG_ERR, "No bandwidth in bandwidth"); return (ESDP_BANDWIDTH); } temp = strtoul(cptr, &endptr, 10); if (*endptr != '\0') { sdp_debug(LOG_ERR, "Error in decoding bandwidth value %s", cptr); return (ESDP_BANDWIDTH); } new = malloc(sizeof(bandwidth_t)); if (new == NULL) { return (ENOMEM); } new->modifier = modifier; if (modifier == BANDWIDTH_MODIFIER_USER) { new->user_band = strdup(lptr); if (new->user_band == NULL) { free(new); return (ENOMEM); } } else { new->user_band = NULL; } new->bandwidth = temp; new->next = NULL; if (*bptr == NULL) { *bptr = new; } else { p = *bptr; while (p->next != NULL) p = p->next; p->next = new; } return (0);}/* * sdp_decode_parse_connect() * parse c=<network type> <address type> <connect address> * Inputs: lptr, connect pointer * Outputs - error code or 0 if parsed correctly */static int sdp_decode_parse_connect (char *lptr, connect_desc_t *cptr){ char *sep, *beg; if (cptr->used != FALSE) return ESDP_CONNECT; cptr->ttl = 0; cptr->num_addr = 0; // <network type> should be IN sep = strsep(&lptr, SPACES); if (sep == NULL || lptr == NULL || strcasecmp(sep, "IN") != 0) { sdp_debug(LOG_ERR, "IN statement missing from c"); return (ESDP_CONNECT); } // <address type> - should be IPV4 ADV_SPACE(lptr); sep = strsep(&lptr, SPACES); if (sep == NULL || lptr == NULL) { sdp_debug(LOG_ERR, "No connection type in c="); return (ESDP_CONNECT); } cptr->conn_type = strdup(sep); // Address - first look if we have a / - that indicates multicast, and a // ttl. ADV_SPACE(lptr); sep = strchr(lptr, '/'); if (sep == NULL) { // unicast address cptr->conn_addr = strdup(lptr); cptr->used = TRUE; return (0); } // Okay - multicast address. Take address up to / (get rid of trailing // spaces) beg = lptr; lptr = sep + 1; sep--; while (isspace(*sep) && sep > beg) sep--; sep++; *sep = '\0'; cptr->conn_addr = strdup(beg); // Now grab the ttl ADV_SPACE(lptr); sep = strsep(&lptr, " \t/"); if (!isdigit(*sep)) { free_connect_desc(cptr); sdp_debug(LOG_ERR, "No multicast TTL in c="); return (ESDP_CONNECT); } if (sscanf(sep, "%u", &cptr->ttl) != 1) return -1; // And see if we have a number of ports if (lptr != NULL) { // we have a number of ports, as well ADV_SPACE(lptr); if (!isdigit(*lptr)) { sdp_debug(LOG_ERR, "c=: garbage after multicast ttl %s", lptr); free_connect_desc(cptr); return (ESDP_CONNECT); } if (sscanf(lptr, "%u", &cptr->num_addr) != 1) return -1; } cptr->used = TRUE; return (0);}/* * sdp_decode_parse_key() */static int sdp_decode_parse_key (char *lptr, key_desc_t *kptr){ if (strncmp(lptr, "prompt", strlen("prompt")) == 0) { // handle prompt command kptr->key_type = KEY_TYPE_PROMPT; return (0); } if (strncasecmp(lptr, "clear", strlen("clear")) == 0) { kptr->key_type = KEY_TYPE_CLEAR; lptr += strlen("clear"); } else if (strncasecmp(lptr, "base64", strlen("base64")) == 0) { kptr->key_type = KEY_TYPE_BASE64; lptr += strlen("base64"); } else if (strncasecmp(lptr, "uri", strlen("uri")) == 0) { kptr->key_type = KEY_TYPE_URI; lptr += strlen("uri"); } else { sdp_debug(LOG_ERR, "key statement keyword error %s", lptr); return (ESDP_KEY); } ADV_SPACE(lptr); if (*lptr != ':') { return (ESDP_KEY); } lptr++; // Because most of the types can have spaces, we take everything after // the colon here. To eliminate the whitespace, use ADV_SPACE(lptr); if (kptr->key == NULL) kptr->key = strdup(lptr); return (0);}/* * sdp_decode_parse_media() * decodes m= lines. * m=<media> <port>[/<numport>] <proto> <fmt list> * Inputs: * lptr - pointer to line * sptr - pointer to session description to modify * Outputs: * pointer to new media description */static media_desc_t *sdp_decode_parse_media (char *lptr, session_desc_t *sptr, int *err){ char *mdesc, *proto, *sep; media_desc_t *new, *mp; uint32_t read_in, port_no; string_list_t *q; *err = 0; // m=<media> <port> <transport> <fmt list> mdesc = strsep(&lptr, SPACES); if (mdesc == NULL || lptr == NULL) { sdp_debug(LOG_CRIT, "No media type"); *err = ESDP_MEDIA; return (NULL); } // <port> ADV_SPACE(lptr); read_in = 0; if (!isdigit(*lptr)) { sdp_debug(LOG_ERR, "Illegal port number in media %s", lptr); *err = ESDP_MEDIA; return (NULL); } while (isdigit(*lptr)) { read_in *= 10; read_in += *lptr - '0'; lptr++; } ADV_SPACE(lptr); // number of ports (optional) if (*lptr == '/') { lptr++; ADV_SPACE(lptr); if (!isdigit(*lptr)) { sdp_debug(LOG_ERR, "Illegal port number in media %s", lptr); *err = ESDP_MEDIA; return (NULL); } sep = strsep(&lptr, SPACES); if (lptr == NULL) { sdp_debug(LOG_ERR, "Missing keywords in media"); *err = ESDP_MEDIA; return (NULL); } if (sscanf(sep, "%u", &port_no) != 1) { *err = ESDP_MEDIA; return NULL; } ADV_SPACE(lptr); } else { port_no = 0; } // <transport> (protocol) proto = strsep(&lptr, SPACES); if (proto == NULL || lptr == NULL) { sdp_debug(LOG_ERR, "No transport in media"); *err = ESDP_MEDIA; return (NULL); } ADV_SPACE(lptr); if (!isalnum(*lptr)) { *err = ESDP_MEDIA; return (NULL); } // malloc memory and set. new = malloc(sizeof(media_desc_t)); if (new == NULL) { *err = ENOMEM; return (NULL); } memset(new, 0, sizeof(media_desc_t)); new->media = strdup(mdesc); new->port = (uint16_t)read_in; new->proto = strdup(proto); new->num_ports = (unsigned short)port_no; // parse format list - these are not necessarilly lists of numbers // so we store as strings. q = NULL; do { sep = strsep(&lptr, SPACES); if (sep != NULL) { if (sdp_add_format_to_list(new, sep) == NULL) { sdp_free_media_desc(new); *err = ENOMEM; return (NULL); } if (lptr != NULL) { ADV_SPACE(lptr); } } } while (sep != NULL); new->parent = sptr; // Add to list of media if (sptr->media == NULL) { sptr->media = new; } else { mp = sptr->media; while (mp->next != NULL) mp = mp->next; mp->next = new; } return (new);}/* * sdp_decode_parse_origin() * parses o= line * o=<username> <session id> <version> <network type> <addr type> <addr> * * Inputs: * lptr - pointer to line to parse * sptr - session desc * Output - TRUE, valid, FALSE, invalid */static int sdp_decode_parse_origin (char *lptr, session_desc_t *sptr){ char *username, *sep; if (sptr->create_addr_type != NULL) return ESDP_ORIGIN; // Username - leave null if "-" username = strsep(&lptr, SPACES); if (username == NULL || lptr == NULL) { sdp_debug(LOG_ERR, "o=: no username"); return (ESDP_ORIGIN); } ADV_SPACE(lptr); if (strcmp(username, "-") != 0) { sptr->orig_username = strdup(username); } if (strtou64(&lptr, &sptr->session_id) == FALSE) { sdp_debug(LOG_ERR, "Non-numeric session id"); return (ESDP_ORIGIN); } if (strtou64(&lptr, &sptr->session_version) == FALSE) { sdp_debug(LOG_ERR, "Non-numeric session version"); return (ESDP_ORIGIN); } ADV_SPACE(lptr); sep = strsep(&lptr, SPACES); if ((sep == NULL) || (lptr == NULL) || (strcasecmp(sep, "IN") != 0)) { sdp_debug(LOG_ERR, "o=: no IN statement"); return (ESDP_ORIGIN); } ADV_SPACE(lptr); sep = strsep(&lptr, SPACES); if (sep == NULL || lptr == NULL) { sdp_debug(LOG_ERR, "o=: No creation address type"); return (ESDP_ORIGIN); } sptr->create_addr_type = strdup(sep); ADV_SPACE(lptr); sep = strsep(&lptr, SPACES); if (sep == NULL) { sdp_debug(LOG_ERR, "o=: No creation address"); return (ESDP_ORIGIN); } sptr->create_addr = strdup(sep); return (0);}/* * sdp_decode_parse_time() * decode t= statements * * Inputs: * sptr - pointer to session_desc_t to write into. * lptr - pointer to line. Should point at first number (spaces removed) * * Outputs: * pointer to session_time_desc_t to use as current one. * NULL if string invalid */static session_time_desc_t *sdp_decode_parse_time (char *lptr, session_desc_t *sptr, int *err){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -