sdp_decode.c
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:48k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is MPEG4IP.
  13.  * 
  14.  * The Initial Developer of the Original Code is Cisco Systems Inc.
  15.  * Portions created by Cisco Systems Inc. are
  16.  * Copyright (C) Cisco Systems Inc. 2000, 2001.  All Rights Reserved.
  17.  * 
  18.  * Contributor(s): 
  19.  *              Bill May        wmay@cisco.com
  20.  */
  21. /*
  22.  * sdp_decode.c
  23.  *
  24.  * decode SDP format from file into session description structures
  25.  * defined in sdp.h
  26.  *
  27.  * October, 2000
  28.  * Bill May (wmay@cisco.com)
  29.  * Cisco Systems, Inc.
  30.  */
  31. #include "sdp.h"
  32. #include "sdp_decode_private.h"
  33. #define ADV_SPACE(a) {while (isspace(*(a)) && (*(a) != ''))(a)++;}
  34. static const char *SPACES=" t";
  35. #define FREE_CHECK(a,b) if (a->b != NULL) { free(a->b); a->b = NULL;}
  36. /*****************************************************************************
  37.  * Memory free routines - frees memory associated with various structures
  38.  *****************************************************************************/
  39. static void free_bandwidth_desc (bandwidth_t *bptr)
  40. {
  41.   bandwidth_t *q;
  42.   while (bptr != NULL) {
  43.     q = bptr;
  44.     bptr = q->next;
  45.     FREE_CHECK(q, user_band);
  46.     free(q);
  47.   }
  48. }
  49. static void free_category_list (category_list_t **cptr)
  50. {
  51.   category_list_t *p;
  52.   if (*cptr == NULL) return;
  53.   
  54.   while (*cptr != NULL) {
  55.     p = *cptr;
  56.     *cptr = p->next;
  57.     free(p);
  58.   }
  59. }
  60. static void free_connect_desc (connect_desc_t *cptr)
  61. {
  62.   FREE_CHECK(cptr, conn_type);
  63.   FREE_CHECK(cptr, conn_addr);
  64. }
  65. /*
  66.  * free_media_desc()
  67.  * Frees all memory associated with a media descriptor(mptr)
  68.  */
  69. static void free_media_desc (media_desc_t *mptr)
  70. {
  71.   free_bandwidth_desc(mptr->media_bandwidth);
  72.   mptr->media_bandwidth = NULL;
  73.   free_connect_desc(&mptr->media_connect);
  74.   sdp_free_format_list(&mptr->fmt);
  75.   sdp_free_string_list(&mptr->unparsed_a_lines);
  76.   FREE_CHECK(mptr, media);
  77.   FREE_CHECK(mptr, media_desc);
  78.   FREE_CHECK(mptr, proto);
  79.   FREE_CHECK(mptr, sdplang);
  80.   FREE_CHECK(mptr, lang);
  81.   FREE_CHECK(mptr, orient_user_type);
  82.   FREE_CHECK(mptr, control_string);
  83.   FREE_CHECK(mptr, key.key);
  84.   mptr->parent = NULL;
  85.   free(mptr);
  86. }
  87. static void free_time_desc (session_time_desc_t *time)
  88. {
  89.   time_repeat_desc_t *rptr;
  90.   
  91.   if (time->next != NULL) {
  92.     free_time_desc(time->next);
  93.     time->next = NULL;
  94.   }
  95.   while (time->repeat != NULL) {
  96.     rptr = time->repeat;
  97.     time->repeat = rptr->next;
  98.     free (rptr);
  99.   }
  100.   free(time);
  101. }
  102. /*
  103.  * sdp_free_session_desc()
  104.  * Inputs - sptr - pointer to session_description list to free
  105.  */
  106. void sdp_free_session_desc (session_desc_t *sptr)
  107. {
  108.   session_desc_t *p;
  109.   media_desc_t *mptr, *q;
  110.   p = sptr;
  111.   while (p != NULL) {
  112.     sptr = p;
  113.     p = p->next;
  114.     
  115.     sptr->next = NULL;
  116.     mptr = sptr->media;
  117.     sptr->media = NULL;
  118.     while (mptr != NULL) {
  119.       q = mptr;
  120.       mptr = q->next;
  121.       free_media_desc(q);
  122.     }
  123.     FREE_CHECK(sptr, etag);
  124.     FREE_CHECK(sptr, orig_username);
  125.     FREE_CHECK(sptr, control_string);
  126.     FREE_CHECK(sptr, create_addr_type);
  127.     FREE_CHECK(sptr, create_addr);
  128.     FREE_CHECK(sptr, session_name);
  129.     FREE_CHECK(sptr, session_desc);
  130.     FREE_CHECK(sptr, uri);
  131.     FREE_CHECK(sptr, key.key);
  132.     FREE_CHECK(sptr, keywds);
  133.     FREE_CHECK(sptr, lang);
  134.     FREE_CHECK(sptr, tool);
  135.     FREE_CHECK(sptr, charset);
  136.     FREE_CHECK(sptr, sdplang);
  137.     FREE_CHECK(sptr, conf_type_user);
  138.     if (sptr->time_desc != NULL) {
  139.       free_time_desc(sptr->time_desc);
  140.       sptr->time_desc = NULL;
  141.     }
  142.     free_bandwidth_desc(sptr->session_bandwidth);
  143.     sptr->session_bandwidth = NULL;
  144.     free_category_list(&sptr->category_list);
  145.     free_connect_desc(&sptr->session_connect);
  146.     sdp_free_string_list(&sptr->admin_phone);
  147.     sdp_free_string_list(&sptr->admin_email);
  148.     sdp_free_string_list(&sptr->unparsed_a_lines);
  149.     
  150.     while (sptr->time_adj_desc != NULL) {
  151.       time_adj_desc_t *aptr;
  152.       aptr = sptr->time_adj_desc;
  153.       sptr->time_adj_desc = aptr->next;
  154.       free(aptr);
  155.     }
  156.   
  157.     free(sptr);
  158.   }
  159. }
  160. /*****************************************************************************
  161.  * Utility routines - string manipulation, etc
  162.  *****************************************************************************/
  163. /*
  164.  * get_next_line will get the next line to process, and stick it in
  165.  * lptr.
  166.  *
  167.  * Inputs:
  168.  *    lptr - buffer to store into
  169.  *    decode - pointer to where to get next line
  170.  *    buflen - max length of buffer
  171.  *
  172.  * Outputs:
  173.  *    TRUE - have a new line.
  174.  *    FALSE - all done.
  175.  */
  176. static int get_next_line (char **polptr,
  177.   sdp_decode_info_t *decode,
  178.   uint32_t *buflen)
  179. {
  180.   char *fret;
  181.   uint32_t len;
  182.   uint32_t buflen_left;
  183.   const char *cptr;
  184.   if (decode->isMem) {
  185.     cptr = decode->memptr;
  186.     if (*cptr == '') return FALSE;
  187.     while (*cptr != '' && *cptr != 'n' && *cptr != 'r') cptr++;
  188.     len = cptr - decode->memptr;
  189.     if (*buflen <= len + 1) {
  190.       if (len > 65535) {
  191. sdp_debug(LOG_CRIT, "Max line length of 65535 exceeded %u", 
  192.   len);
  193. return (FALSE);
  194.       }
  195.       *polptr = realloc(*polptr, len + 1);
  196.       *buflen = len + 1;
  197.     }
  198.     memcpy(*polptr, decode->memptr, len);
  199.     (*polptr)[len] = '';
  200.     decode->memptr += len;
  201.     while (*decode->memptr == 'n' || *decode->memptr == 'r')
  202.       decode->memptr++;
  203.   } else {
  204.     char *ptr;
  205.     // File reads...
  206.     if (decode->ifile == NULL)
  207.       return FALSE;
  208.     if (*buflen == 0) {
  209.       *polptr = (char *)malloc(1024);
  210.       *buflen = 1024;
  211.     }
  212.     // Read file until we hit the end, or a non-blank line read
  213.     ptr = *polptr;
  214.     buflen_left = *buflen;
  215.     len = 0;
  216.     while (1) {
  217.       fret = fgets(ptr, buflen_left, decode->ifile);
  218.       if (fret == NULL) {
  219. if (len > 0) {
  220.   sdp_debug(LOG_WARNING, "Unterminated last line");
  221.   (*polptr)[len] = ''; // make sure
  222.   return (TRUE);
  223. }
  224. return (FALSE);
  225.       }
  226.       len = strlen(ptr);
  227.       if (ptr[len - 1] == 'n' || ptr[len - 1] == 'r') {
  228. // we have an end of line
  229. len--;
  230. while (len >= 0 &&
  231.        (ptr[len] == 'n' || ptr[len] == 'r')) {
  232.   ptr[len] = '';
  233.   len--;
  234. }
  235. return (TRUE);
  236.       }
  237.       
  238.       // too long...
  239.       buflen_left -= len;
  240.       if (*buflen + 1024 > 65535) {
  241. sdp_debug(LOG_CRIT, "Max line length of 65535 exceeded %u", 
  242.   *buflen);
  243. return (FALSE);
  244.       }
  245.       *buflen += 1024;
  246.       buflen_left += 1024;
  247.       *polptr = realloc(*polptr, *buflen);
  248.       ptr = *polptr + *buflen - buflen_left;
  249.     }
  250.   }
  251.   return TRUE;
  252. }
  253. /*
  254.  * strtou64()
  255.  * Converts string to uint64_t number up to next space, with error checking.
  256.  * Inputs:
  257.  *    lptr - pointer to pointer to string.  *lptr will be modified
  258.  *    num - return value
  259.  * Outputs - TRUE - sucess, FALSE, failure
  260.  */
  261. static int strtou64 (char **lptr, uint64_t *num)
  262. {
  263.   char *sep;
  264.   
  265.   *num = 0;
  266.   ADV_SPACE((*lptr));
  267.   sep = strsep(lptr, SPACES);
  268.   if (sep == NULL || *lptr == NULL) {
  269.     return (FALSE);
  270.   }
  271.   *num = 0;
  272.   while (*sep != '') {
  273.     if (isdigit(*sep)) {
  274.       *num *= 10;
  275.       *num += *sep - '0';
  276.       sep++;
  277.     } else {
  278.       return (FALSE);
  279.     }
  280.   }
  281.   return (TRUE);
  282. }
  283. /*
  284.  * str_to_time_offset()
  285.  * converts typed-time field (number or [#d][#h][#m][#s])
  286.  *
  287.  * Inputs -
  288.  *   str -  terminated string to translate
  289.  *   retval - pointer to return value
  290.  * Returns -
  291.  *   TRUE - valid string processed;
  292.  *   FALSE - invalid string
  293.  */
  294. static int str_to_time_offset (const char *str, uint32_t *retval)
  295. {
  296.   uint32_t value;
  297.   uint32_t accum;
  298.   char temp;
  299.   
  300.   value = 0;
  301.   accum = 0;
  302.   if (!isdigit(*str)) return (FALSE);
  303.   
  304.   while (*str != '') {
  305.     if (isdigit(*str)) {
  306.       accum *= 10;
  307.       accum += (*str - '0');
  308.     } else {
  309.       temp = tolower(*str);
  310.       if (temp == 'd') {
  311. value += accum * SEC_PER_DAY;
  312. accum = 0;
  313.       } else if (temp == 'h') {
  314. value += accum * SEC_PER_HOUR;
  315. accum = 0;
  316.       } else if (temp == 'm') {
  317. value += accum * SEC_PER_MINUTE;
  318. accum = 0;
  319.       } else if (temp == 's') {
  320. value += accum;
  321. accum = 0;
  322.       } else {
  323. sdp_debug(LOG_ERR, "Illegal character %c in time offset", temp);
  324. return (FALSE);
  325.       }
  326.     }
  327.     str++;
  328.   }
  329.   value += accum;
  330.   *retval = value;
  331.   return (TRUE);
  332. }
  333. /*
  334.  * time_adj_order_in_list()
  335.  * order linked list by adj_time values.  We don't allow 2 items in the
  336.  * list - "new" value might be free'd at end
  337.  * Inputs:
  338.  *   start - pointer to start of list
  339.  *   new - pointer to new value
  340.  * Returns:
  341.  *   pointer to head of list - new value might be free'd.
  342.  */
  343. static time_adj_desc_t *time_adj_order_in_list (time_adj_desc_t *start,
  344. time_adj_desc_t *new)
  345. {
  346.   time_adj_desc_t *p, *q;
  347.   if (start == NULL)
  348.     return (new);
  349.   p = start;
  350.   q = NULL;
  351.   while (p != NULL) {
  352.     if (new->adj_time == p->adj_time) {
  353.       sdp_debug(LOG_NOTICE, "Duplicate time %ld in adj description", p->adj_time);
  354.       free(new);
  355.       return (start);
  356.     }
  357.     if (new->adj_time < p->adj_time) {
  358.       new->next = p;
  359.       if (q == NULL) {
  360. return (new);
  361.       } else {
  362. q->next = new;
  363. return (start);
  364.       }
  365.     }
  366.     q = p;
  367.     p = p->next;
  368.   }
  369.   q->next = new;
  370.   return (start);
  371. }
  372. /*****************************************************************************
  373.  * Line parsing routines
  374.  *****************************************************************************/
  375. /*
  376.  * sdp_decode_parse_a_bool()
  377.  * parses a boolean field.
  378.  */
  379. static int sdp_decode_parse_a_bool (int arg,
  380.     char *lptr,
  381.     session_desc_t *sptr,
  382.     media_desc_t *mptr)
  383. {
  384.   switch (arg) {
  385.   case 0:
  386.     if (mptr != NULL) mptr->recvonly = TRUE;
  387.     else sptr->recvonly = TRUE;
  388.     break;
  389.   case 1:
  390.     if (mptr != NULL) mptr->sendrecv = TRUE;
  391.     else sptr->sendrecv = TRUE;
  392.     break;
  393.   case 2:
  394.     if (mptr != NULL) mptr->sendonly = TRUE;
  395.     else sptr->sendonly = TRUE;
  396.     break;
  397.   }
  398.   return (0);
  399. }
  400. /*
  401.  * sdp_decode_parse_a_rtpmap()
  402.  * parses a=rtpmap:<fmt> <name>/<clockrate>[/<enc_param>]
  403.  */
  404. static int sdp_decode_parse_a_fmtp (int arg,
  405.     char *lptr,
  406.     session_desc_t *sptr,
  407.     media_desc_t *mptr)
  408. {
  409.   format_list_t *fptr;
  410.   int len;
  411.   
  412.   if (mptr == NULL)
  413.     return (-1);
  414.   /*
  415.    * See our format matches a value in the media's format list.
  416.    */
  417.   fptr = sdp_find_format_in_line(mptr->fmt,lptr) ;
  418.   if (fptr == NULL) {
  419.     sdp_debug(LOG_ALERT, "Can't find fmtp format %s in media format list", lptr);
  420.     return (-1);
  421.   }
  422.   len = strlen(fptr->fmt);
  423.   lptr += len;
  424.   lptr++;
  425.   ADV_SPACE(lptr);
  426.   fptr->fmt_param = strdup(lptr);
  427.   if (fptr->fmt_param == NULL) {
  428.     return (-1);
  429.   }
  430.   return (0);
  431. }
  432. /*
  433.  * sdp_decode_parse_a_rtpmap()
  434.  * parses a=rtpmap:<fmt> <name>/<clockrate>[/<enc_param>]
  435.  */
  436. static int sdp_decode_parse_a_rtpmap (int arg,
  437.       char *lptr,
  438.       session_desc_t *sptr,
  439.       media_desc_t *mptr)
  440. {
  441.   char *enc, *slash, *temp;
  442.   format_list_t *fptr;
  443.   int len;
  444.   uint32_t a, b;
  445.   
  446.   if (mptr == NULL)
  447.     return (-1);
  448.   /*
  449.    * See our format matches a value in the media's format list.
  450.    */
  451.   fptr = sdp_find_format_in_line(mptr->fmt,lptr) ;
  452.   if (fptr == NULL) {
  453.     sdp_debug(LOG_ALERT, "Can't find rtpmap format %s in media list", lptr);
  454.     return (-1);
  455.   }
  456.   len = strlen(fptr->fmt);
  457.   /*
  458.    * Matches entry left in fptr.  Decode rest of line
  459.    */
  460.   enc = lptr + len;
  461.   ADV_SPACE(enc);
  462.   slash = strchr(enc, '/');  
  463.   if (slash == NULL) {
  464.     sdp_debug(LOG_ERR, "Couldn't find / in rtpmap");
  465.     return (-1);
  466.   }
  467.   *slash++ = '';
  468.   temp = enc;
  469.   while ((!(isspace(*temp))) && *temp != '') temp++;
  470.   *temp = '';
  471.   
  472.   // enc points to encode name
  473.   ADV_SPACE(slash);
  474.   temp = strsep(&slash, " t/");
  475.   if (temp == NULL) {
  476.     sdp_debug(LOG_ERR, "Can't find seperator after encode name in rtpmap");
  477.     return (-1);
  478.   }
  479.   if (sscanf(temp, "%u", &a) == 0) {
  480.     sdp_debug(LOG_ERR, "Couldn't decode rtp clockrate %s", temp);
  481.     return (-1);
  482.   }
  483.   b = 0;
  484.   if (slash != NULL) {
  485.     ADV_SPACE(slash);
  486.     if (*slash == '/') {
  487.       slash++;
  488.       ADV_SPACE(slash);
  489.     }
  490.     if (isdigit(*slash)) {
  491.       sscanf(slash, "%u", &b);
  492.     }
  493.   }
  494.   
  495.   fptr->rtpmap = malloc(sizeof(rtpmap_desc_t));
  496.   if (fptr->rtpmap == NULL)
  497.     return (-1);
  498.   fptr->rtpmap->encode_name = strdup(enc);
  499.   fptr->rtpmap->clock_rate = a;
  500.   fptr->rtpmap->encode_param = b;
  501.   
  502.   return (0);
  503. }
  504. /*
  505.  * sdp_decode_parse_a_cat()
  506.  * parses a=category:foo.bar...
  507.  */
  508. static int sdp_decode_parse_a_cat (int arg,
  509.    char *orig_line,
  510.    session_desc_t *sptr,
  511.    media_desc_t *mptr)
  512. {
  513.   char *sep, *line, *lptr;
  514.   int errret;
  515.   uint64_t cat;
  516.   category_list_t *cptr, *new;
  517.   
  518.   if (sptr->category_list != NULL) {
  519.     return (-1);
  520.   }
  521.   errret = 0;
  522.   cptr = NULL; // shut up compiler
  523.   line = strdup(orig_line);
  524.   lptr = line;
  525.   while ((sep = strsep(&lptr, " t."))) {
  526.     if (*sep != '') {
  527.       cat = 0;
  528.       while (isdigit(*sep)) {
  529. cat *= 10;
  530. cat += *sep - '0';
  531. sep++;
  532.       }
  533.       if (cat == 0) {
  534. break;
  535.       }
  536.       new = malloc(sizeof(category_list_t));
  537.       if (new == NULL) {
  538. break;
  539.       }
  540.       new->category = cat;
  541.       new->next = NULL;
  542.       if (sptr->category_list == NULL) {
  543. cptr = sptr->category_list = new;
  544.       } else {
  545. cptr->next = new;
  546. cptr = new;
  547.       }
  548.     }
  549.   }
  550.   if (errret != 0) {
  551.     free_category_list(&sptr->category_list);
  552.   }
  553.   free(line);
  554.   return (errret);
  555. }
  556. /*
  557.  * sdp_decode_parse_a_frame()
  558.  * parses a=framerate:<float number>
  559.  */
  560. static int sdp_decode_parse_a_frame (int arg,
  561.      char *lptr,
  562.      session_desc_t *sptr,
  563.      media_desc_t *mptr)
  564. {
  565.   char *endptr;
  566.   
  567.   if (mptr == NULL) {
  568.     return (-1);
  569.   }
  570.   mptr->framerate = strtod(lptr, &endptr);
  571.   if (endptr == lptr || endptr == NULL) return (-1);
  572.   ADV_SPACE(endptr);
  573.   if (*endptr != '') {
  574.     sdp_debug(LOG_ERR, "Garbage at end of frame rate `%s'", endptr);
  575.     return (-1);
  576.   }
  577.   mptr->framerate_present = TRUE;
  578.   return (0);
  579. }
  580. static int convert_npt (char *from, char *to, double *ret)
  581. {
  582.   int decimal = FALSE;
  583.   double accum;
  584.   double mult;
  585.   *ret = 0.0;
  586.   mult = 0.0;
  587.   accum = 0.0;
  588.   
  589.   while ((to == NULL && *from != '') || from < to) {
  590.     if (isdigit(*from)) {
  591.       if (decimal == FALSE) {
  592. accum *= 10.0;
  593. accum += *from - '0';
  594.       } else {
  595. accum += ((*from - '0') * mult);
  596. mult /= 10.0;
  597.       }
  598.     } else if (*from == ':') {
  599.       accum *= 60.0;
  600.       *ret += accum;
  601.       accum = 0;
  602.     } else if (*from == '.') {
  603.       decimal = TRUE;
  604.       mult = .1;
  605.     } else {
  606.       sdp_debug(LOG_ERR, "Illegal character in NPT string %c", *from);
  607.       return (FALSE);
  608.     }
  609.     from++;
  610.   }
  611.   *ret += accum;
  612.   return (TRUE);
  613. }
  614. static int convert_smpte (char *from, char *to, uint16_t fps, double *ret)
  615. {
  616.   int decimal = FALSE;
  617.   double accum;
  618.   double mult;
  619.   unsigned int colon;
  620.   *ret = 0.0;
  621.   mult = 0.0;
  622.   accum = 0.0;
  623.   colon = 0;
  624.   if (fps == 0) fps = 30;
  625.   
  626.   while ((to == NULL && *from != '') || from < to) {
  627.     if (isdigit(*from)) {
  628.       if (decimal == FALSE) {
  629. accum *= 10.0;
  630. accum += (*from - '0');
  631.       } else {
  632. accum += ((*from - '0') * mult);
  633. mult /= 10.0;
  634.       }
  635.     } else if (*from == ':') {
  636.       *ret += accum;
  637.       if (colon > 1)
  638.         *ret *= fps;
  639.       else 
  640. *ret *= 60.0;
  641.       accum = 0.0;
  642.       colon++;
  643.     } else if (*from == '.') {
  644.       decimal = TRUE;
  645.       mult = .1;
  646.     } else {
  647.       sdp_debug(LOG_ERR, "Illegal character in SMPTE decode %c", *from);
  648.       return (FALSE);
  649.     }
  650.     from++;
  651.   }
  652.   *ret += accum;
  653.   if (colon <= 2) *ret *= fps;
  654.   return (TRUE);
  655. }
  656. static int sdp_decode_parse_a_range (int arg,
  657.      char *lptr,
  658.      session_desc_t *sptr,
  659.      media_desc_t *mptr)
  660. {
  661.   char *dash;
  662.   char *second;
  663.   range_desc_t *rptr;
  664.   if (mptr == NULL) rptr = &sptr->session_range;
  665.   else rptr = &mptr->media_range;
  666.   if (rptr->have_range) return (-1);
  667.   if (strncasecmp(lptr, "npt", strlen("npt")) == 0) {
  668.     lptr += strlen("npt");
  669.     rptr->range_is_npt = TRUE;
  670.   } else if (strncasecmp(lptr, "smpte", strlen("smpte")) == 0) {
  671.     lptr += strlen("smpte");
  672.     rptr->range_is_npt = FALSE;
  673.     if (*lptr == '-') {
  674.       lptr++;
  675.       if (strncasecmp(lptr, "30-drop", strlen("30-drop")) == 0) {
  676. rptr->range_smpte_fps = 0;
  677. lptr += strlen("30-drop");
  678.       } else {
  679. while (isdigit(*lptr)) {
  680.   rptr->range_smpte_fps *= 10;
  681.   rptr->range_smpte_fps += *lptr - '0';
  682.   lptr++;
  683. }
  684.       }
  685.     } else {
  686.       rptr->range_smpte_fps = 0;
  687.     }
  688.   } else {
  689.     sdp_debug(LOG_ERR, "range decode - unknown keyword %s", lptr);
  690.     return (-1);
  691.   }
  692.   ADV_SPACE(lptr);
  693.   if (*lptr != '=') {
  694.     sdp_debug(LOG_ERR, "range decode - no =");
  695.     return (-1);
  696.   }
  697.   lptr++;
  698.   ADV_SPACE(lptr);
  699.   dash = strchr(lptr, '-');
  700.   if (dash == NULL) return (-1);
  701.   if (rptr->range_is_npt) {
  702.     if (convert_npt(lptr, dash, &rptr->range_start) == FALSE) {
  703.       sdp_debug(LOG_ERR, "Couldn't decode range from npt %s", lptr);
  704.       return (-1);
  705.     }
  706.   } else {
  707.     if (convert_smpte(lptr,
  708.       dash,
  709.       rptr->range_smpte_fps,
  710.       &rptr->range_start) == FALSE) {
  711.       sdp_debug(LOG_ERR, "Couldn't decode range from smpte %s", lptr);
  712.       return (-1);
  713.     }
  714.   }
  715.       
  716.   second = dash + 1;
  717.   ADV_SPACE(second);
  718.   if (*second != '') {
  719.     if (rptr->range_is_npt) {
  720.       if (convert_npt(second, NULL, &rptr->range_end) == FALSE) {
  721. sdp_debug(LOG_ERR, "Couldn't decode range to npt %s", lptr);
  722. return (-1);
  723.       }
  724.     } else {
  725.       if (convert_smpte(second,
  726. NULL,
  727. rptr->range_smpte_fps,
  728. &rptr->range_end) == FALSE) {
  729. sdp_debug(LOG_ERR, "Couldn't decode range to smpte %s", lptr);
  730. return (-1);
  731.       }
  732.     }
  733.   } else {
  734.     rptr->range_end_infinite = TRUE;
  735.   }
  736.   rptr->have_range = TRUE;
  737.   return (0);
  738. }
  739. /*
  740.  * sdp_decode_parse_a_int()
  741.  * parses a=<name>:<uint>
  742.  */
  743. static int sdp_decode_parse_a_int (int arg,
  744.    char *orig_line,
  745.    session_desc_t *sptr,
  746.    media_desc_t *mptr)
  747. {
  748.   uint32_t num;
  749.   num = 0;
  750.   if (!isdigit(*orig_line)) {
  751.     return (-1);
  752.   }
  753.   while (isdigit(*orig_line)) {
  754.     num *= 10;
  755.     num += *orig_line - '0';
  756.     orig_line++;
  757.   }
  758.   ADV_SPACE(orig_line);
  759.   if (*orig_line != '') {
  760.     sdp_debug(LOG_ERR, "Garbage at end of integer %s", orig_line);
  761.     return(-1);
  762.   }
  763.   switch (arg) {
  764.   case 0:
  765.     if (mptr == NULL) return (-1);
  766.     mptr->ptime = num;
  767.     mptr->ptime_present = TRUE;
  768.     break;
  769.   case 1:
  770.     if (mptr == NULL) return (-1);
  771.     mptr->quality = num;
  772.     mptr->quality_present = TRUE;
  773.     break;
  774.   }
  775.   return (0);
  776. }
  777. /*
  778.  * check_value_list_or_user()
  779.  * This will compare string in lptr with items in list.  If strncasecmp()
  780.  * matches, and the next value after the match in lptr is a space or ,
  781.  * we return the index in list + 1.
  782.  * If no entrys are on the list, we'll strdup the value, and store in
  783.  * *uservalue
  784.  */
  785. static int check_value_list_or_user (char *lptr,
  786.      const char **list,
  787.      char **user_value)
  788. {
  789.   uint32_t len;
  790.   int cnt;
  791.   cnt = 1;
  792.   while (*list != NULL) {
  793.     len = strlen(*list);
  794.     if (strncasecmp(lptr, *list, len) == 0) {
  795.       return (cnt);
  796.     }
  797.     cnt++;
  798.     list++;
  799.   }
  800.   *user_value = strdup(lptr);
  801.   return(cnt);
  802. }
  803. const char *type_values[] = {
  804.   "broadcast", // CONFERENCE_TYPE_BROADCAST
  805.   "meeting",   // CONFERENCE_TYPE_MEETING
  806.   "moderated", // CONFERENCE_TYPE_MODERATED
  807.   "test",      // CONFERENCE_TYPE_TEST
  808.   "H332",      // CONFERENCE_TYPE_H332
  809.   NULL         // CONFERENCE_TYPE_USER
  810. };
  811. static const char *orient_values[] = {
  812.   "portrait", // ORIENT_TYPE_PORTRAIT
  813.   "landscape",// ORIENT_TYPE_LANDSCAPE
  814.   "seascape", // ORIENT_TYPE_SEASCAPE
  815.   NULL        // ORIENT_TYPE_USER
  816. };
  817. /*
  818.  * sdp_decode_parse_a_str()
  819.  * parses a=<identifier>:<name>
  820.  * Will usually save the value of <name> in a field in the media_desc_t or
  821.  * session_desc_t.
  822.  */
  823. static int sdp_decode_parse_a_str (int arg,
  824.    char *lptr,
  825.    session_desc_t *sptr,
  826.    media_desc_t *mptr)
  827. {
  828.   switch (arg) {
  829.   case 0: // keywds
  830.     if (sptr->keywds != NULL) {
  831.       sdp_debug(LOG_ERR, "2nd keywds statement");
  832.       return (-1);
  833.     }
  834.     sptr->keywds = strdup(lptr);
  835.     break;
  836.   case 1: // tool
  837.     if (sptr->tool != NULL) {
  838.       sdp_debug(LOG_ERR, "2nd tool statement");
  839.       return (-1);
  840.     }
  841.     sptr->tool = strdup(lptr);
  842.     break;
  843.   case 2: // charset
  844.     if (sptr->charset != NULL) {
  845.       sdp_debug(LOG_ERR, "2nd charset statement");
  846.       return (-1);
  847.     }
  848.     sptr->charset = strdup(lptr);
  849.     break;
  850.   case 3: // sdplang
  851.     if (mptr != NULL) {
  852.       if (mptr->sdplang != NULL) {
  853. sdp_debug(LOG_ERR, "2nd sdplang statement in media");
  854. return (-1);
  855.       }
  856.       mptr->sdplang = strdup(lptr);
  857.     } else {
  858.       if (sptr->sdplang != NULL) {
  859. sdp_debug(LOG_ERR, "2nd sdplang statement in session");
  860. return (-1);
  861.       }
  862.       sptr->sdplang = strdup(lptr);
  863.     }
  864.     break;
  865.   case 4: // lang
  866.     if (mptr != NULL) {
  867.       if (mptr->lang != NULL) {
  868. sdp_debug(LOG_ERR, "2nd lang statement in media");
  869. return (-1);
  870.       }
  871.       mptr->lang = strdup(lptr);
  872.     } else {
  873.       if (sptr->lang != NULL) {
  874. sdp_debug(LOG_ERR, "2nd lang statement in media");
  875. return (-1);
  876.       }
  877.       sptr->lang = strdup(lptr);
  878.     }
  879.     break;
  880.   case 5: // type
  881.     if (sptr->conf_type != 0) {
  882.       sdp_debug(LOG_ERR, "2nd conftype statement");
  883.       return (-1);
  884.     }
  885.     sptr->conf_type = check_value_list_or_user(lptr,
  886.        type_values,
  887.        &sptr->conf_type_user);
  888.     break;
  889.   case 6: // orient
  890.     if (mptr == NULL || mptr->orient_type != 0) {
  891.       sdp_debug(LOG_ERR, "2nd orient type statement");
  892.       return (-1);
  893.     }
  894.     mptr->orient_type = check_value_list_or_user(lptr,
  895.  orient_values,
  896.  &mptr->orient_user_type);
  897.     break;
  898.   case 7: // control
  899.     if (mptr == NULL) {
  900.       if (sptr->control_string != NULL) {
  901. sdp_debug(LOG_ERR, "2nd control statement in media");
  902. return (-1);
  903.       }
  904.       sptr->control_string = strdup(lptr);
  905.     } else {
  906.       if (mptr->control_string != NULL) {
  907. sdp_debug(LOG_ERR, "2nd control statement in session");
  908. return (-1);
  909.       }
  910.       mptr->control_string = strdup(lptr);
  911.     }
  912.     break;
  913.   case 8:
  914.     if (sptr->etag != NULL) {
  915.       sdp_debug(LOG_ERR, "2nd etag statement");
  916.       return (-1);
  917.     }
  918.     sptr->etag = strdup(lptr);
  919.     break;
  920.   }
  921.   return (0);
  922. }
  923. /*
  924.  * This structure provides the information needed by the parsing
  925.  * engine in sdp_decode_parse_a.  This function processes lines of
  926.  * the format a=<identifier>[:<options>].
  927.  * name - <identifier>
  928.  * len - sizeof(identifier) (saves on CPU time)
  929.  * have_colon - if a colon is necessary
  930.  * remove_spaces_after_colon - if colon is necessary, and we want
  931.  *   to remove spaces before <option>.  Do not use this if other character
  932.  *   sets may come into play.
  933.  * parse_routine - routine to call if keyword matched.  Return 0 if successful-
  934.  *   -1 will save the whole "a=..." string.
  935.  * arg - value to pass to parse_routine
  936.  */
  937. static struct {
  938.   char *name;
  939.   uint32_t len;
  940.   int have_colon;
  941.   int remove_spaces_after_colon;
  942.   int (*parse_routine)(int arg, char *lptr,
  943.        session_desc_t *sptr, media_desc_t *mptr);
  944.   int arg;
  945. } a_types[] =
  946. {
  947.   { "rtpmap", sizeof("rtpmap"), TRUE, TRUE, sdp_decode_parse_a_rtpmap, 0 },
  948.   { "cat", sizeof("cat"), TRUE, TRUE, sdp_decode_parse_a_cat, 0 },
  949.   { "fmtp", sizeof("fmtp"), TRUE, TRUE, sdp_decode_parse_a_fmtp, 0 },
  950.   { "keywds", sizeof("keywds"), TRUE, FALSE, sdp_decode_parse_a_str, 0},
  951.   { "tool", sizeof("tool"), TRUE, TRUE, sdp_decode_parse_a_str, 1},
  952.   { "charset", sizeof("charset"), TRUE, TRUE, sdp_decode_parse_a_str, 2},
  953.   { "sdplang", sizeof("sdplang"), TRUE, TRUE, sdp_decode_parse_a_str, 3},
  954.   { "lang", sizeof("lang"), TRUE, TRUE, sdp_decode_parse_a_str, 4},
  955.   { "type", sizeof("type"), TRUE, TRUE, sdp_decode_parse_a_str, 5},
  956.   { "orient", sizeof("orient"), TRUE, TRUE, sdp_decode_parse_a_str, 6},
  957.   { "control", sizeof("control"), TRUE, TRUE, sdp_decode_parse_a_str, 7},
  958.   { "etag", sizeof("etag"), TRUE, TRUE, sdp_decode_parse_a_str, 8},
  959.   { "recvonly", sizeof("recvonly"), FALSE, FALSE, sdp_decode_parse_a_bool, 0},
  960.   { "sendrecv", sizeof("sendrecv"), FALSE, FALSE, sdp_decode_parse_a_bool, 1},
  961.   { "sendonly", sizeof("sendonly"), FALSE, FALSE, sdp_decode_parse_a_bool, 2},
  962.   { "ptime", sizeof("ptime"), TRUE, TRUE, sdp_decode_parse_a_int, 0 },
  963.   { "quality", sizeof("quality"), TRUE, TRUE, sdp_decode_parse_a_int, 1},
  964.   { "framerate", sizeof("framerate"), TRUE, TRUE, sdp_decode_parse_a_frame, 0},
  965.   { "range", sizeof("range"), TRUE, TRUE, sdp_decode_parse_a_range, 0 },
  966.   { NULL, 0, FALSE, FALSE, NULL },
  967. };
  968. /*
  969.  * sdp_decode_parse_a()
  970.  * decodes a= lines, or stores the complete string in media or session
  971.  * unparsed_a_lines list.
  972.  */
  973. static int sdp_decode_parse_a (char *lptr,
  974.        char *line,
  975.        session_desc_t *sptr,
  976.        media_desc_t *mptr)
  977. {
  978.   int ix;
  979.   int errret;
  980.   int parsed;
  981.   char *after;
  982.   
  983.   ix = 0;
  984.   errret = 0;
  985.   parsed = FALSE;
  986.   /*
  987.    * go through above array, looking for a complete match
  988.    */
  989.   while (a_types[ix].name != NULL) {
  990.     if (strncasecmp(lptr,
  991.     a_types[ix].name,
  992.     a_types[ix].len - 1) == 0) {
  993.       after = lptr + a_types[ix].len - 1;
  994.       if (!(isspace(*after) ||
  995.     *after == ':' ||
  996.     *after == '')) {
  997. // partial match - not good enough
  998. continue;
  999.       }
  1000.    
  1001.       parsed = TRUE;
  1002.       /*
  1003.        * Have a match.  If specified, look for colon, and remove space
  1004.        * after colon
  1005.        */
  1006.       if (a_types[ix].have_colon) {
  1007. ADV_SPACE(after);
  1008. if (*after != ':') {
  1009.   errret = ESDP_ATTRIBUTES_NO_COLON;
  1010.   break;
  1011. }
  1012. after++;
  1013. if (a_types[ix].remove_spaces_after_colon) {
  1014.   ADV_SPACE(after);
  1015. }
  1016.       }
  1017.       /*
  1018.        * Call the correct parsing routine
  1019.        */
  1020.       errret = (a_types[ix].parse_routine)(a_types[ix].arg, after, sptr, mptr);
  1021.       break;
  1022.     }
  1023.     ix++;
  1024.   }
  1025.   /*
  1026.    * Worse comes to worst, store the whole line
  1027.    */
  1028.   if (parsed == FALSE || errret != 0) {
  1029.     if (sdp_add_string_to_list(mptr == NULL ?
  1030.    &sptr->unparsed_a_lines :
  1031.    &mptr->unparsed_a_lines,
  1032.    line) == FALSE) {
  1033.       return (ENOMEM);
  1034.     }
  1035.   }
  1036.   return (0);
  1037. }
  1038. /*
  1039.  * sdp_decode_parse_bandwidth()
  1040.  * parses b=<modifier>:<value>
  1041.  * Inputs: lptr - pointer to line, bptr - pointer to store in
  1042.  * Outputs: TRUE - valid, FALSE, invalid
  1043.  */
  1044. static int sdp_decode_parse_bandwidth (char *lptr,
  1045.        bandwidth_t **bptr)
  1046. {
  1047.   char *cptr, *endptr;
  1048.   bandwidth_t *new, *p;
  1049.   bandwidth_modifier_t modifier;
  1050.   uint32_t temp;
  1051.   cptr = strchr(lptr, ':');
  1052.   if (cptr == NULL) {
  1053.     sdp_debug(LOG_ERR, "No colon in bandwidth");
  1054.     return (ESDP_BANDWIDTH);
  1055.   }
  1056.   *cptr++ = '';
  1057.   
  1058.   if (strncasecmp(lptr, "as", strlen("as")) == 0) {
  1059.     modifier = BANDWIDTH_MODIFIER_AS;
  1060.   } else if (strncasecmp(lptr, "ct", strlen("ct")) == 0) {
  1061.     modifier = BANDWIDTH_MODIFIER_CT;
  1062.   } else {
  1063.     modifier = BANDWIDTH_MODIFIER_USER;
  1064.     endptr = cptr - 2;
  1065.     while (isspace(*endptr) && endptr >lptr) *endptr-- = '';
  1066.   }
  1067.   if (*cptr == '') {
  1068.     sdp_debug(LOG_ERR, "No bandwidth in bandwidth");
  1069.     return (ESDP_BANDWIDTH);
  1070.   }
  1071.   temp = strtoul(cptr, &endptr, 10);
  1072.   if (*endptr != '') {
  1073.     sdp_debug(LOG_ERR, "Error in decoding bandwidth value %s", cptr);
  1074.     return (ESDP_BANDWIDTH);
  1075.   }
  1076.   
  1077.   new = malloc(sizeof(bandwidth_t));
  1078.   if (new == NULL) {
  1079.     return (ENOMEM);
  1080.   }
  1081.   new->modifier = modifier;
  1082.   if (modifier == BANDWIDTH_MODIFIER_USER) {
  1083.     new->user_band = strdup(lptr);
  1084.     if (new->user_band == NULL) {
  1085.       free(new);
  1086.       return (ENOMEM);
  1087.     }
  1088.   } else {
  1089. new->user_band = NULL;
  1090.   }
  1091.   new->bandwidth = temp;
  1092.   new->next = NULL;
  1093.   if (*bptr == NULL) {
  1094.     *bptr = new;
  1095.   } else {
  1096.     p = *bptr;
  1097.     while (p->next != NULL) p = p->next;
  1098.     p->next = new;
  1099.   }
  1100.   return (0);
  1101. }
  1102. /*
  1103.  * sdp_decode_parse_connect()
  1104.  * parse c=<network type> <address type> <connect address>
  1105.  * Inputs: lptr, connect pointer
  1106.  * Outputs - error code or 0 if parsed correctly
  1107.  */
  1108. static int sdp_decode_parse_connect (char *lptr, connect_desc_t *cptr)
  1109. {
  1110.   char *sep, *beg;
  1111.   cptr->ttl = 0;
  1112.   cptr->num_addr = 0;
  1113.   // <network type> should be IN
  1114.   sep = strsep(&lptr, SPACES);
  1115.   if (sep == NULL ||
  1116.       lptr == NULL ||
  1117.       strcasecmp(sep, "IN") != 0) {
  1118.     sdp_debug(LOG_ERR, "IN statement missing from c");
  1119.     return (ESDP_CONNECT);
  1120.   }
  1121.   // <address type> - should be IPV4
  1122.   ADV_SPACE(lptr);
  1123.   sep = strsep(&lptr, SPACES);
  1124.   if (sep == NULL || lptr == NULL) {
  1125.     sdp_debug(LOG_ERR, "No connection type in c=");
  1126.     return (ESDP_CONNECT);
  1127.   }
  1128.   cptr->conn_type = strdup(sep);
  1129.   // Address - first look if we have a / - that indicates multicast, and a
  1130.   // ttl.
  1131.   ADV_SPACE(lptr);
  1132.   sep = strchr(lptr, '/');
  1133.   if (sep == NULL) {
  1134.     // unicast address
  1135.     cptr->conn_addr = strdup(lptr);
  1136.     cptr->used = TRUE;
  1137.     return (0);
  1138.   }
  1139.   // Okay - multicast address.  Take address up to / (get rid of trailing
  1140.   // spaces)
  1141.   beg = lptr;
  1142.   lptr = sep + 1;
  1143.   sep--;
  1144.   while (isspace(*sep) && sep > beg) sep--;
  1145.   sep++;
  1146.   *sep = '';
  1147.   cptr->conn_addr = strdup(beg);
  1148.   // Now grab the ttl
  1149.   ADV_SPACE(lptr);
  1150.   sep = strsep(&lptr, " t/");
  1151.   if (!isdigit(*sep)) {
  1152.     free_connect_desc(cptr);
  1153.     sdp_debug(LOG_ERR, "No multicast TTL in c=");
  1154.     return (ESDP_CONNECT);
  1155.   }
  1156.   sscanf(sep, "%u", &cptr->ttl);
  1157.   // And see if we have a number of ports
  1158.   if (lptr != NULL) {
  1159.     // we have a number of ports, as well
  1160.     ADV_SPACE(lptr);
  1161.     if (!isdigit(*lptr)) {
  1162.       sdp_debug(LOG_ERR, "c=: garbage after multicast ttl %s", lptr);
  1163.       free_connect_desc(cptr);
  1164.       return (ESDP_CONNECT);
  1165.     }
  1166.     sscanf(lptr, "%u", &cptr->num_addr);
  1167.   }
  1168.   cptr->used = TRUE;
  1169.   return (0);
  1170. }
  1171. /*
  1172.  * sdp_decode_parse_key()
  1173.  */
  1174. static int sdp_decode_parse_key (char *lptr, key_desc_t *kptr)
  1175. {
  1176.   if (strncmp(lptr, "prompt", strlen("prompt")) == 0) {
  1177.     // handle prompt command
  1178.     kptr->key_type = KEY_TYPE_PROMPT;
  1179.     return (0);
  1180.   }
  1181.   if (strncasecmp(lptr, "clear", strlen("clear")) == 0) {
  1182.     kptr->key_type = KEY_TYPE_CLEAR;
  1183.     lptr += strlen("clear");
  1184.   } else if (strncasecmp(lptr, "base64", strlen("base64")) == 0) {
  1185.     kptr->key_type = KEY_TYPE_BASE64;
  1186.     lptr += strlen("base64");
  1187.   } else if (strncasecmp(lptr, "uri", strlen("uri")) == 0) {
  1188.     kptr->key_type = KEY_TYPE_URI;
  1189.     lptr += strlen("uri");
  1190.   } else {
  1191.     sdp_debug(LOG_ERR, "key statement keyword error %s", lptr);
  1192.     return (ESDP_KEY);
  1193.   }
  1194.   ADV_SPACE(lptr);
  1195.   if (*lptr != ':') {
  1196.     return (ESDP_KEY);
  1197.   }
  1198.   lptr++;
  1199.   // Because most of the types can have spaces, we take everything after
  1200.   // the colon here.  To eliminate the whitespace, use ADV_SPACE(lptr);
  1201.   kptr->key = strdup(lptr);
  1202.   return (0);
  1203. }
  1204. /*
  1205.  * sdp_decode_parse_media()
  1206.  * decodes m= lines.
  1207.  * m=<media> <port>[/<numport>] <proto> <fmt list>
  1208.  * Inputs:
  1209.  *   lptr - pointer to line
  1210.  *   sptr - pointer to session description to modify
  1211.  * Outputs:
  1212.  *   pointer to new media description
  1213.  */
  1214. static media_desc_t *sdp_decode_parse_media (char *lptr,
  1215.      session_desc_t *sptr,
  1216.      int *err)
  1217. {
  1218.   char *mdesc, *proto, *sep;
  1219.   media_desc_t *new, *mp;
  1220.   uint32_t read, port_no;
  1221.   string_list_t *q;
  1222.   *err = 0;
  1223.   // m=<media> <port> <transport> <fmt list>
  1224.   mdesc = strsep(&lptr, SPACES);
  1225.   if (mdesc == NULL || lptr == NULL) {
  1226.     sdp_debug(LOG_CRIT, "No media type");
  1227.     *err = ESDP_MEDIA;
  1228.     return (NULL);
  1229.   }
  1230.   // <port>
  1231.   ADV_SPACE(lptr);
  1232.   read = 0;
  1233.   if (!isdigit(*lptr)) {
  1234.     sdp_debug(LOG_ERR, "Illegal port number in media %s", lptr);
  1235.     *err = ESDP_MEDIA;
  1236.     return (NULL);
  1237.   }
  1238.   while (isdigit(*lptr)) {
  1239.     read *= 10;
  1240.     read += *lptr - '0';
  1241.     lptr++;
  1242.   }
  1243.   ADV_SPACE(lptr);
  1244.   // number of ports (optional)
  1245.   if (*lptr == '/') {
  1246.     lptr++;
  1247.     ADV_SPACE(lptr);
  1248.     if (!isdigit(*lptr)) {
  1249.       sdp_debug(LOG_ERR, "Illegal port number in media %s", lptr);
  1250.       *err = ESDP_MEDIA;
  1251.       return (NULL);
  1252.     }
  1253.     sep = strsep(&lptr, SPACES);
  1254.     if (lptr == NULL) {
  1255.       sdp_debug(LOG_ERR, "Missing keywords in media");
  1256.       *err = ESDP_MEDIA;
  1257.       return (NULL);
  1258.     }
  1259.     sscanf(sep, "%u", &port_no);
  1260.     ADV_SPACE(lptr);
  1261.   } else {
  1262.     port_no = 0;
  1263.   }
  1264.   // <transport> (protocol)
  1265.   proto = strsep(&lptr, SPACES);
  1266.   if (proto == NULL || lptr == NULL) {
  1267.     sdp_debug(LOG_ERR, "No transport in media");
  1268.     *err = ESDP_MEDIA;
  1269.     return (NULL);
  1270.   }
  1271.   ADV_SPACE(lptr);
  1272.   if (!isalnum(*lptr)) {
  1273.     *err = ESDP_MEDIA;
  1274.     return (NULL);
  1275.   }  
  1276.   // malloc memory and set.
  1277.   new = malloc(sizeof(media_desc_t));
  1278.   if (new == NULL) {
  1279.     *err = ENOMEM;
  1280.     return (NULL);
  1281.   }
  1282.   memset(new, 0, sizeof(media_desc_t));
  1283.   new->media = strdup(mdesc);
  1284.   new->port = (uint16_t)read;
  1285.   new->proto = strdup(proto);
  1286.   new->num_ports = (unsigned short)port_no;
  1287.   // parse format list - these are not necessarilly lists of numbers
  1288.   // so we store as strings.
  1289.   q = NULL;
  1290.   do {
  1291.     sep = strsep(&lptr, SPACES);
  1292.     if (sep != NULL) {
  1293.       if (sdp_add_format_to_list(new, sep) == NULL) {
  1294. free_media_desc(new);
  1295. *err = ENOMEM;
  1296. return (NULL);
  1297.       }
  1298.       if (lptr != NULL) {
  1299. ADV_SPACE(lptr);
  1300.       }
  1301.     }
  1302.   } while (sep != NULL);
  1303.   new->parent = sptr;
  1304.   // Add to list of media
  1305.   if (sptr->media == NULL) {
  1306.     sptr->media = new;
  1307.   } else {
  1308.     mp = sptr->media;
  1309.     while (mp->next != NULL) mp = mp->next;
  1310.     mp->next = new;
  1311.   }
  1312.   
  1313.   return (new);
  1314. }
  1315. /*
  1316.  * sdp_decode_parse_origin()
  1317.  * parses o= line
  1318.  * o=<username> <session id> <version> <network type> <addr type> <addr>
  1319.  *
  1320.  * Inputs:
  1321.  *   lptr - pointer to line to parse
  1322.  *   sptr - session desc
  1323.  * Output - TRUE, valid, FALSE, invalid
  1324.  */
  1325. static int sdp_decode_parse_origin (char *lptr, session_desc_t *sptr)
  1326. {
  1327.   char *username, *sep;
  1328.   // Username - leave null if "-"
  1329.   username = strsep(&lptr, SPACES);
  1330.   if (username == NULL || lptr == NULL) {
  1331.     sdp_debug(LOG_ERR, "o=: no username");
  1332.     return (ESDP_ORIGIN);
  1333.   }
  1334.   ADV_SPACE(lptr);
  1335.   if (strcmp(username, "-") != 0) {
  1336.     sptr->orig_username = strdup(username);
  1337.   }
  1338.     
  1339.   if (strtou64(&lptr, &sptr->session_id) == FALSE) {
  1340.     sdp_debug(LOG_ERR, "Non-numeric session id");
  1341.     return (ESDP_ORIGIN);
  1342.   }
  1343.   if (strtou64(&lptr, &sptr->session_version) == FALSE) {
  1344.     sdp_debug(LOG_ERR, "Non-numeric session version");
  1345.     return (ESDP_ORIGIN);
  1346.   }
  1347.   
  1348.   ADV_SPACE(lptr);
  1349.   sep = strsep(&lptr, SPACES);
  1350.   if ((sep == NULL) ||
  1351.       (lptr == NULL) ||
  1352.       (strcasecmp(sep, "IN") != 0)) {
  1353.     sdp_debug(LOG_ERR, "o=: no IN statement");
  1354.     return (ESDP_ORIGIN);
  1355.   }
  1356.   ADV_SPACE(lptr);
  1357.   sep = strsep(&lptr, SPACES);
  1358.   if (sep == NULL || lptr == NULL) {
  1359.     sdp_debug(LOG_ERR, "o=: No creation address type");
  1360.     return (ESDP_ORIGIN);
  1361.   }
  1362.   sptr->create_addr_type = strdup(sep);
  1363.   ADV_SPACE(lptr);
  1364.   sep = strsep(&lptr, SPACES);
  1365.   if (sep == NULL) {
  1366.     sdp_debug(LOG_ERR, "o=: No creation address");
  1367.     return (ESDP_ORIGIN);
  1368.   }
  1369.   sptr->create_addr = strdup(sep);
  1370.   
  1371.   return (0);
  1372. }
  1373. /*
  1374.  * sdp_decode_parse_time()
  1375.  * decode t= statements
  1376.  *
  1377.  * Inputs:
  1378.  *   sptr - pointer to session_desc_t to write into.
  1379.  *   lptr - pointer to line.  Should point at first number (spaces removed)
  1380.  *
  1381.  * Outputs:
  1382.  *   pointer to session_time_desc_t to use as current one.
  1383.  *   NULL if string invalid
  1384.  */
  1385. static session_time_desc_t *sdp_decode_parse_time (char *lptr,
  1386.    session_desc_t *sptr,
  1387.    int *err)
  1388. {
  1389.   session_time_desc_t *tptr;
  1390.   uint32_t start, end;
  1391.   *err = 0;
  1392.   if (!isdigit(*lptr)) {
  1393.     *err = ESDP_TIME;
  1394.     sdp_debug(LOG_ERR, "t= statement has illegal first character %c", *lptr);
  1395.     return (NULL);
  1396.   }
  1397.   start = end = 0;
  1398.   
  1399.   while (isdigit(*lptr)) {
  1400.     start *= 10;
  1401.     start += *lptr - '0';
  1402.     lptr++;
  1403.   }
  1404.   ADV_SPACE(lptr);
  1405.   if (!isdigit(*lptr)) {
  1406.     sdp_debug(LOG_ERR,
  1407.       "t= statement has illegal character after 1st number %c",
  1408.       *lptr);
  1409.     *err = ESDP_TIME;
  1410.     return (NULL);
  1411.   }
  1412.   
  1413.   while (isdigit(*lptr)) {
  1414.     end *= 10;
  1415.     end += *lptr - '0';
  1416.     lptr++;
  1417.   }
  1418.   
  1419.   tptr = malloc(sizeof(session_time_desc_t));
  1420.   if (tptr == NULL) {
  1421.     *err = ENOMEM;
  1422.     return (NULL);
  1423.   }
  1424.   tptr->next = NULL;
  1425.   tptr->repeat = NULL;
  1426.   // Convert from NTP time to Unix time (unless time is 0)
  1427.   tptr->start_time = (start == 0) ? 0 : (start - NTP_TO_UNIX_TIME);
  1428.   tptr->end_time = (end == 0) ? 0 : (end - NTP_TO_UNIX_TIME);
  1429.   // Add to end of linked list of time descriptions
  1430.   if (sptr->time_desc == NULL) {
  1431.     sptr->time_desc = tptr;
  1432.   } else {
  1433.     session_time_desc_t *q;
  1434.     q = sptr->time_desc;
  1435.     while (q->next != NULL) q = q->next;
  1436.     q->next = tptr;
  1437.   }
  1438.   
  1439.   return (tptr);
  1440.   
  1441. }
  1442. /*
  1443.  * sdp_decode_parse_time_adj()
  1444.  * decode z= fields.
  1445.  * Inputs: lptr - pointer to line to decode
  1446.  *   session - pointer to session_descriptor to add
  1447.  * Returns:
  1448.  *   TRUE - valid line
  1449.  *   FALSE - invalid line
  1450.  */
  1451. static int sdp_decode_parse_time_adj (char *lptr,
  1452.       session_desc_t *session)
  1453. {
  1454.   char *sep;
  1455.   int valid;
  1456.   time_adj_desc_t *start_aptr, *aptr;
  1457.   time_t adj_time;
  1458.   int32_t offset;
  1459.   int possign;
  1460.   int err;
  1461.   
  1462.   if (!isdigit(*lptr)) {
  1463.     sdp_debug(LOG_ERR, "Illegal character for z= field %s", lptr);
  1464.     return (ESDP_TIME_ADJ);
  1465.   }
  1466.   start_aptr = NULL;
  1467.   valid = TRUE;
  1468.   /*
  1469.    * parse pairs of <adjustment time> <offset>
  1470.    */
  1471.   err = ESDP_TIME_ADJ;
  1472.   
  1473.   while ((sep = strsep(&lptr, SPACES)) && valid == TRUE) {
  1474.     if (lptr == NULL) {
  1475.       valid = FALSE;
  1476.       continue;
  1477.     }
  1478.     // process <adjustment time> - adjust it from NTP to unix time
  1479.     sscanf(sep, "%ld", &adj_time);
  1480.     // Check for negative sign for offset.
  1481.     ADV_SPACE(lptr);
  1482.     if (*lptr == '-') {
  1483.       possign = FALSE;
  1484.       lptr++;
  1485.     } else possign = TRUE;
  1486.     ADV_SPACE(lptr);
  1487.     
  1488.     sep = strsep(&lptr, SPACES);
  1489.     if (adj_time == 0 || sep == NULL) {
  1490.       valid = FALSE;
  1491.       continue;
  1492.     }
  1493.     adj_time -= NTP_TO_UNIX_TIME;
  1494.     // Process offset - could be positive or negative.
  1495.     if (str_to_time_offset(sep, &offset) == FALSE) {
  1496.       valid = FALSE;
  1497.       continue;
  1498.     }
  1499.     if (possign == FALSE) offset = 0 - offset;
  1500.     /*
  1501.      * create a time structure - order the link list by value
  1502.      * of adj_times
  1503.      */
  1504.     aptr = malloc(sizeof(time_adj_desc_t));
  1505.     if (aptr == NULL) {
  1506.       valid = FALSE;
  1507.       err = ENOMEM;
  1508.       continue;
  1509.     }
  1510.     
  1511.     aptr->next = NULL;
  1512.     aptr->adj_time = adj_time;
  1513.     aptr->offset = offset;
  1514.     if (lptr != NULL) {
  1515.       ADV_SPACE(lptr);
  1516.     }
  1517.     start_aptr = time_adj_order_in_list(start_aptr, aptr);
  1518.     
  1519.   }
  1520.   if (valid == FALSE) {
  1521.     while (start_aptr != NULL) {
  1522.       aptr = start_aptr;
  1523.       start_aptr = aptr->next;
  1524.       free(aptr);
  1525.     }
  1526.     return (err);
  1527.   }
  1528.   if (start_aptr == NULL) return (err);
  1529.   while (start_aptr != NULL) {
  1530.     aptr = start_aptr->next;
  1531.     start_aptr = aptr->next;
  1532.     aptr->next = NULL;
  1533.     session->time_adj_desc = time_adj_order_in_list(session->time_adj_desc,
  1534.     aptr);
  1535.   }
  1536.   return (0);
  1537. }
  1538. /*
  1539.  * sdp_decode_parse_time_repeat
  1540.  * parse "r=" field in SDP description, store info off of current time
  1541.  * pointer
  1542.  *
  1543.  * Inputs : lptr - pointer to decode buffer
  1544.  *    current_time - current time pointer returned by sdp_decode_parse_time()
  1545.  *
  1546.  * Outputs - TRUE - decoded successfully - FALSE - error
  1547.  */
  1548. static int sdp_decode_parse_time_repeat (char *lptr,
  1549.  session_time_desc_t *current_time)
  1550. {
  1551.   time_repeat_desc_t *rptr;
  1552.   char *sep;
  1553.   uint32_t interval, duration;
  1554.   
  1555.   if (current_time == NULL) {
  1556.     sdp_debug(LOG_ERR, "r= before or without time");
  1557.     return (ESDP_REPEAT_NOTIME);
  1558.   }
  1559.   sep = strsep(&lptr, SPACES);
  1560.   if (sep == NULL || lptr == NULL) {
  1561.     sdp_debug(LOG_ERR, "Interval not found in repeat statment");
  1562.     return (ESDP_REPEAT);
  1563.   }
  1564.   if (str_to_time_offset(sep, &interval) == FALSE) {
  1565.     sdp_debug(LOG_ERR, "Illegal string conversion in repeat");
  1566.     return (ESDP_REPEAT);
  1567.   }
  1568.   
  1569.   ADV_SPACE(lptr);
  1570.   sep = strsep(&lptr, SPACES);
  1571.   if (sep == NULL || lptr == NULL) {
  1572.     sdp_debug(LOG_ERR, "No duration in repeat statement");
  1573.     return (ESDP_REPEAT);
  1574.   }
  1575.   if (str_to_time_offset(sep, &duration) == FALSE) {
  1576.     return (ESDP_REPEAT);
  1577.   }
  1578.   
  1579.   if (duration == 0 || interval == 0) {
  1580.     sdp_debug(LOG_ERR, "duration or interval are 0 in repeat");
  1581.     return (ESDP_REPEAT);
  1582.   }
  1583.   ADV_SPACE(lptr);
  1584.   
  1585.   rptr = malloc(sizeof(time_repeat_desc_t));
  1586.   if (rptr == NULL)
  1587.     return (ENOMEM);
  1588.   rptr->next = NULL;
  1589.   rptr->offset_cnt = 0;
  1590.   rptr->repeat_interval = interval;
  1591.   rptr->active_duration = duration;
  1592.   // Read offset fields - we set a maximum of 16 here.
  1593.   while ((sep = strsep(&lptr, SPACES)) &&
  1594.  rptr->offset_cnt < MAX_REPEAT_OFFSETS) {
  1595.     if (str_to_time_offset(sep, &rptr->offsets[rptr->offset_cnt]) == FALSE) {
  1596.       sdp_debug(LOG_ERR, "Illegal repeat offset - number %d", rptr->offset_cnt);
  1597.       free(rptr);
  1598.       return (ESDP_REPEAT);
  1599.     }
  1600.     rptr->offset_cnt++;
  1601.     if (lptr != NULL) {
  1602.       ADV_SPACE(lptr);
  1603.     }
  1604.   }
  1605.   if (rptr->offset_cnt == 0 || sep != NULL) {
  1606.     sdp_debug(LOG_ERR, "No listed offset in repeat");
  1607.     free(rptr);
  1608.     return (ESDP_REPEAT);
  1609.   }
  1610.   
  1611.   if (current_time->repeat == NULL) {
  1612.     current_time->repeat = rptr;
  1613.   } else {
  1614.     time_repeat_desc_t *q;
  1615.     q = current_time->repeat;
  1616.     while (q->next != NULL) q = q->next;
  1617.     q->next = rptr;
  1618.   }
  1619.   return (0);
  1620. }
  1621. /*****************************************************************************
  1622.  * Main library routines
  1623.  *****************************************************************************/
  1624. /*
  1625.  * sdp_decode()
  1626.  * main routine
  1627.  * Inputs:
  1628.  *   decode - pointer to sdp_decode_info_t set before calling.
  1629.  *   retlist - pointer to pointer of list head
  1630.  *   translated - pointer to return number translated
  1631.  * Outputs:
  1632.  *   error code or 0.  Negative error codes are local, positive are errorno.
  1633.  *   retlist - pointer to list of session_desc_t.
  1634.  *   translated - number translated.
  1635.  */
  1636. int sdp_decode (sdp_decode_info_t *decode,
  1637. session_desc_t **retlist,
  1638. int *translated)
  1639. {
  1640.   char *line, *lptr;
  1641.   char code;
  1642.   int errret;
  1643.   uint32_t linelen;
  1644.   session_desc_t *first_session,*sptr;
  1645.   media_desc_t *current_media;
  1646.   session_time_desc_t *current_time;
  1647.   if ((decode == NULL) || (decode->isSet != TRUE)) {
  1648.     return -EINVAL;
  1649.   }
  1650.   *retlist = first_session = NULL;
  1651.   sptr = NULL;
  1652.   current_media = NULL;
  1653.   current_time = NULL;
  1654.   *translated = 0;
  1655.   errret = 0;
  1656.   line = NULL;
  1657.   linelen = 0;
  1658.   while (errret == 0 && get_next_line(&line, decode, &linelen) != FALSE) {
  1659.     lptr = line;
  1660.     ADV_SPACE(lptr);
  1661.     /*
  1662.      * All spaces ?  Just go to next line.
  1663.      */
  1664.     if (*lptr == '')
  1665.       continue;
  1666.     sdp_debug(LOG_DEBUG, "'%s'",  lptr);
  1667.     /*
  1668.      * Let's be strict about 1 character code
  1669.      */
  1670.     code = *lptr++;
  1671.     ADV_SPACE(lptr);
  1672.     if (*lptr == '=') {
  1673.       lptr++;
  1674.       ADV_SPACE(lptr);
  1675.       if ((sptr == NULL) && (tolower(code) != 'v')) {
  1676. sdp_debug(LOG_ERR, "Version not 1st statement");
  1677. errret = ESDP_INVVER;
  1678. break;
  1679.       }
  1680.       switch (tolower(code)) {
  1681.       case 'v': {
  1682. int ver;
  1683. if ((sscanf(lptr, "%u", &ver) != 1) ||
  1684.     (ver != 0)) {
  1685.   errret = ESDP_INVVER;
  1686.   sdp_debug(LOG_ERR, "SDP Version not correct, %s", line);
  1687.   break;
  1688. }
  1689. /*
  1690.  * Next session...
  1691.  */
  1692. sptr = malloc(sizeof(session_desc_t));
  1693. if (sptr == NULL) {
  1694.   errret = ENOMEM;
  1695.   break;
  1696. }
  1697. memset(sptr, 0, sizeof(session_desc_t));
  1698. if (first_session == NULL) {
  1699.   *retlist = first_session = sptr;
  1700. } else {
  1701.   session_desc_t *p;
  1702.   p = first_session;
  1703.   while (p->next != NULL) p = p->next;
  1704.   p->next = sptr;
  1705. }
  1706. *translated = *translated + 1;
  1707. current_media = NULL;
  1708. current_time = NULL;
  1709. break;
  1710.       }
  1711.       case 'o':
  1712. errret = sdp_decode_parse_origin(lptr, sptr);
  1713. break;
  1714.       case 's':
  1715. sptr->session_name = strdup(lptr);
  1716. if (sptr->session_name == NULL) {
  1717.   errret = ENOMEM;
  1718. }
  1719. break;
  1720.       case 'i':
  1721. if (current_media != NULL) {
  1722.   current_media->media_desc = strdup(lptr);
  1723.   if (current_media->media_desc == NULL) {
  1724.     errret = ENOMEM;
  1725.   }
  1726. } else {
  1727.   sptr->session_desc = strdup(lptr);
  1728.   if (sptr->session_desc == NULL) {
  1729.     errret = ENOMEM;
  1730.   }
  1731. }
  1732. break;
  1733.       case 'u':
  1734. sptr->uri = strdup(lptr);
  1735. if (sptr->uri == NULL) {
  1736.   errret = ENOMEM;
  1737. }
  1738. break;
  1739.       case 'e':
  1740. if (sdp_add_string_to_list(&sptr->admin_email, lptr) == FALSE) {
  1741.   errret = ENOMEM;
  1742. }
  1743. break;
  1744.       case 'p':
  1745. if (sdp_add_string_to_list(&sptr->admin_phone, lptr) == FALSE) {
  1746.   errret = ENOMEM;
  1747. }
  1748. break;
  1749.       case 'c':
  1750. errret = sdp_decode_parse_connect(lptr,
  1751.   current_media ?
  1752.   &current_media->media_connect :
  1753.   &sptr->session_connect);
  1754. break;
  1755.       case 'b':
  1756. errret= sdp_decode_parse_bandwidth(lptr,
  1757.    current_media != NULL ?
  1758.    &current_media->media_bandwidth :
  1759.    &sptr->session_bandwidth);
  1760. break;
  1761.       case 't':
  1762. current_time = sdp_decode_parse_time(lptr, sptr, &errret);
  1763. if (current_time == NULL) {
  1764.   errret = ESDP_TIME;
  1765. }
  1766. break;
  1767.       case 'r':
  1768. if (current_time != NULL) {
  1769.   errret = sdp_decode_parse_time_repeat(lptr, current_time);
  1770. }
  1771. break;
  1772.       case 'z':
  1773. errret = sdp_decode_parse_time_adj(lptr, sptr);
  1774. break;
  1775.       case 'k':
  1776. errret = sdp_decode_parse_key(lptr,
  1777.       current_media == NULL ? &sptr->key :
  1778.       &current_media->key);
  1779. break;
  1780.       case 'a':
  1781. errret = sdp_decode_parse_a(lptr, line, sptr, current_media);
  1782. break;
  1783.       case 'm':
  1784. current_media = sdp_decode_parse_media(lptr, sptr, &errret);
  1785. break;
  1786.       default:
  1787. sdp_debug(LOG_ERR, "unknown code - %s", line);
  1788. errret = ESDP_UNKNOWN_LINE;
  1789.       }
  1790.     } else {
  1791.       // bigger than 1 character code
  1792.       sdp_debug(LOG_ERR, "More than 1 character code - %s", line);
  1793.       errret = ESDP_UNKNOWN_LINE;
  1794.     }
  1795.   }
  1796.   if (line != NULL) {
  1797.     free(line);
  1798.   }
  1799.   if (errret != 0) {
  1800.     if (sptr != NULL) {
  1801.       if (first_session == sptr) {
  1802. *retlist = NULL;
  1803.       } else {
  1804. session_desc_t *p;
  1805. p = first_session;
  1806. while (p->next != sptr) {
  1807.   p = p->next;
  1808. }
  1809. p->next = NULL;
  1810.       }
  1811.       sdp_free_session_desc(sptr);
  1812.     }
  1813.     sdp_debug(LOG_ALERT, "SDP decode failure %d", errret);
  1814.     return (errret);
  1815.   }
  1816.   return (0);
  1817. }
  1818. /*
  1819.  * set_sdp_decode_from_memory()
  1820.  * Allows sdp decode to be run from a memory block.
  1821.  *
  1822.  * Inputs: memptr - pointer to memory.  Won't be touched.
  1823.  * Outputs: pointer to sdp_decode_info_t to be used.
  1824.  */
  1825. sdp_decode_info_t *set_sdp_decode_from_memory (const char *memptr)
  1826. {
  1827.   sdp_decode_info_t *decode_ptr;
  1828.   decode_ptr = malloc(sizeof(sdp_decode_info_t));
  1829.   if (decode_ptr == NULL)
  1830.     return (NULL);
  1831.   
  1832.   memset(decode_ptr, 0, sizeof(sdp_decode_info_t));
  1833.   decode_ptr->isSet = TRUE;
  1834.   decode_ptr->isMem = TRUE;
  1835.   decode_ptr->memptr = memptr;
  1836.   decode_ptr->filename = NULL;
  1837.   decode_ptr->ifile = NULL;
  1838.   return (decode_ptr);
  1839. }
  1840. /*
  1841.  * set_sdp_decode_from_filename()
  1842.  * Allows sdp decode to be run on a file
  1843.  *
  1844.  * Inputs: filename - name of file to open
  1845.  * Outputs: pointer to sdp_decode_info_t to be used.
  1846.  */
  1847. sdp_decode_info_t *set_sdp_decode_from_filename (const char *filename)
  1848. {
  1849.   sdp_decode_info_t *decode_ptr;
  1850.   decode_ptr = malloc(sizeof(sdp_decode_info_t));
  1851.   if (decode_ptr == NULL)
  1852.     return (NULL);
  1853.   
  1854.   memset(decode_ptr, 0, sizeof(sdp_decode_info_t));
  1855.   decode_ptr->isSet = TRUE;
  1856.   decode_ptr->isMem = FALSE;
  1857.   decode_ptr->memptr = NULL;
  1858.   decode_ptr->filename = filename;
  1859.   decode_ptr->ifile = fopen(filename, "r");
  1860.   if (decode_ptr->ifile == NULL) {
  1861.     free(decode_ptr);
  1862.     return (NULL);
  1863.   }
  1864.   return (decode_ptr);
  1865. }
  1866. void sdp_decode_info_free (sdp_decode_info_t *decode)
  1867. {
  1868.   if (decode->isMem == FALSE) {
  1869.     fclose(decode->ifile);
  1870.   }
  1871.   free(decode);
  1872. }