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

流媒体/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.  * rtsp_util.c - mixture of various utilities needed for rtsp client
  23.  */
  24. #include "rtsp_private.h"
  25. static int rtsp_debug_level = LOG_ALERT;
  26. static error_msg_func_t rtsp_error_msg = NULL;
  27. /*
  28.  * Ugh - a global variable for the loglevel.
  29.  * We probably want to enhance this to pass a function vector as well.
  30.  */
  31. void rtsp_set_loglevel (int loglevel)
  32. {
  33.   rtsp_debug_level = loglevel;
  34. }
  35. void rtsp_set_error_func (error_msg_func_t func)
  36. {
  37.   rtsp_error_msg = func;
  38. }
  39. /*
  40.  * rtsp_debug()
  41.  * Display rtsp debug information.  Probably want to hook this into
  42.  * a rtsp_client, and enhance it to do file, console, and user routine
  43.  * output.
  44.  */
  45. void rtsp_debug (int loglevel, const char *fmt, ...)
  46. {
  47.   //struct timeval thistime;
  48.   va_list ap;
  49.   //char buffer[80];
  50.   if (loglevel <= rtsp_debug_level) {
  51.     if (rtsp_error_msg != NULL) {
  52.       va_start(ap, fmt);
  53.       (rtsp_error_msg)(loglevel, "librtsp", fmt, ap);
  54.       va_end(ap);
  55.     }
  56.   }
  57. }
  58. void free_session_info (rtsp_session_t *session)
  59. {
  60.   CHECK_AND_FREE(session, session);
  61.   CHECK_AND_FREE(session, url);
  62.   free(session);
  63. }
  64. /*
  65.  * clear_decode_response()
  66.  * Frees memory associated with that structure and clears it.
  67.  */
  68. void clear_decode_response (rtsp_decode_t *resp)
  69. {
  70.   CHECK_AND_FREE(resp, retresp);
  71.   CHECK_AND_FREE(resp, body);
  72.   CHECK_AND_FREE(resp, accept);
  73.   CHECK_AND_FREE(resp, accept_encoding);
  74.   CHECK_AND_FREE(resp, accept_language);
  75.   CHECK_AND_FREE(resp, allow_public);
  76.   CHECK_AND_FREE(resp, authorization);
  77.   CHECK_AND_FREE(resp, bandwidth);
  78.   CHECK_AND_FREE(resp, blocksize);
  79.   CHECK_AND_FREE(resp, cache_control);
  80.   CHECK_AND_FREE(resp, content_base);
  81.   CHECK_AND_FREE(resp, content_encoding);
  82.   CHECK_AND_FREE(resp, content_language);
  83.   CHECK_AND_FREE(resp, content_location);
  84.   CHECK_AND_FREE(resp, content_type);
  85.   CHECK_AND_FREE(resp, cookie);
  86.   CHECK_AND_FREE(resp, date);
  87.   CHECK_AND_FREE(resp, expires);
  88.   CHECK_AND_FREE(resp, from);
  89.   CHECK_AND_FREE(resp, if_modified_since);
  90.   CHECK_AND_FREE(resp, last_modified);
  91.   CHECK_AND_FREE(resp, location);
  92.   CHECK_AND_FREE(resp, proxy_authenticate);
  93.   CHECK_AND_FREE(resp, proxy_require);
  94.   CHECK_AND_FREE(resp, range);
  95.   CHECK_AND_FREE(resp, referer);
  96.   CHECK_AND_FREE(resp, require);
  97.   CHECK_AND_FREE(resp, retry_after);
  98.   CHECK_AND_FREE(resp, rtp_info);
  99.   CHECK_AND_FREE(resp, scale);
  100.   CHECK_AND_FREE(resp, server);
  101.   CHECK_AND_FREE(resp, session);
  102.   CHECK_AND_FREE(resp, speed);
  103.   CHECK_AND_FREE(resp, transport);
  104.   CHECK_AND_FREE(resp, unsupported);
  105.   CHECK_AND_FREE(resp, user_agent);
  106.   CHECK_AND_FREE(resp, via);
  107.   CHECK_AND_FREE(resp, www_authenticate);
  108.   resp->content_length = 0;
  109.   resp->cseq = 0;
  110.   resp->close_connection = FALSE;
  111. }
  112. /*
  113.  * free_decode_response()
  114.  * frees memory associated with response, along with response.
  115.  */
  116. void free_decode_response (rtsp_decode_t *decode)
  117. {
  118.   if (decode != NULL) {
  119.     clear_decode_response(decode);
  120.     free(decode);
  121.   }
  122. }
  123. /*
  124.  * rtsp_set_and_decode_url()
  125.  * will decode the url, make sure it matches RTSP url information,
  126.  * pulls out the server name and port, then gets the server address
  127.  */
  128. int rtsp_dissect_url (rtsp_client_t *rptr, const char *url)
  129. {
  130.   const char *uptr;
  131.   const char *nextslash, *nextcolon, *rightbracket;
  132.   int hostlen;
  133.   
  134.   if (rptr->url != NULL || rptr->server_name != NULL) {
  135.     return (EEXIST);
  136.   }
  137.   uptr = url;
  138.   rptr->url = strdup(url);
  139.   if (strncmp("rtsp://", url, strlen("rtsp://")) == 0) {
  140.     rptr->useTCP = TRUE;
  141.     uptr += strlen("rtsp://");
  142. #if 0
  143.   } else if (strncmp("rtspu://", url, strlen("rtspu:")) == 0) {
  144.     uptr += strlen("rtspu://");
  145. #endif
  146.   } else {
  147.     return(-1);
  148.   }
  149.   rptr->port = 554;
  150.   rightbracket = NULL;
  151.   if (*uptr == '[') {
  152.     uptr++; // don't include the '['
  153.     rightbracket = strchr(uptr, ']');
  154.     if (rightbracket != NULL) {
  155.       // literal IPv6 address
  156.       if (rightbracket[1] == ':') {
  157. nextcolon = rightbracket + 1;
  158.       } else
  159. nextcolon = NULL;
  160.       nextslash = strchr(rightbracket, '/');
  161.     } else {
  162.       return (EINVAL);
  163.     }
  164.   } else {
  165.   nextslash = strchr(uptr, '/');
  166.   nextcolon = strchr(uptr, ':');
  167.   }
  168.   if (nextslash != NULL || nextcolon != NULL) {
  169.     if (nextcolon != NULL &&
  170. (nextcolon < nextslash || nextslash == NULL)) {
  171.       hostlen = nextcolon - uptr;
  172.       // have a port number
  173.       nextcolon++;
  174.       rptr->port = 0;
  175.       while (isdigit(*nextcolon)) {
  176. rptr->port *= 10;
  177. rptr->port += *nextcolon - '0';
  178. nextcolon++;
  179.       }
  180.       if (rptr->port == 0 || (*nextcolon != '/' && *nextcolon != '')) {
  181. return (EINVAL);
  182.       }
  183.     } else {
  184.       // no port number
  185.       hostlen = nextslash - uptr;
  186.     }
  187.     if (rightbracket != NULL) {
  188.        hostlen--;
  189.     }
  190.     if (hostlen == 0) {
  191.       return (EINVAL);
  192.     }
  193.     rptr->server_name = malloc(hostlen + 1);
  194.     if (rptr->server_name == NULL) {
  195.       return (ENOMEM);
  196.     }
  197.     memcpy(rptr->server_name, uptr, hostlen);
  198.     rptr->server_name[hostlen] = '';
  199.   } else {
  200.     if (*uptr == '') {
  201.       return (EINVAL);
  202.     }
  203.     rptr->server_name = strdup(uptr);
  204.     if (rptr->server_name == NULL) {
  205.       return (ENOMEM);
  206.     }
  207.     if (rightbracket != NULL) {
  208.       rptr->server_name[strlen(rptr->server_name) - 1] = '';
  209.     }
  210.   }
  211.   return (0);
  212. }
  213. /*
  214.  * rtsp_setup_redirect()
  215.  * Sets up URLs, does the connect for redirects.  Need to handle
  216.  * 300 case (multiple choices).  Imagine that if we had that, we'd just
  217.  * loop through the body until we found a server that we could connect
  218.  * with.
  219.  */
  220. int rtsp_setup_redirect (rtsp_client_t *info)
  221. {
  222.   rtsp_decode_t *decode;
  223.   int ret;
  224.   if (info->decode_response == NULL)
  225.     return (-1);
  226.   info->redirect_count++;
  227.   if (info->redirect_count > 5) 
  228.     return (-1);
  229.   decode = info->decode_response;
  230.   if (decode->location == NULL)
  231.     return (-1);
  232.   
  233.   if (info->orig_url == NULL) {
  234.     info->orig_url = info->url;
  235.     info->url = NULL;
  236.   } else {
  237.     CHECK_AND_FREE(info, url);
  238.   }
  239.   CHECK_AND_FREE(info, server_name);
  240.   rtsp_close_socket(info);
  241.   ret = rtsp_dissect_url(info, decode->location);
  242.   if (ret != 0) return (ret);
  243.   
  244.   return (rtsp_create_socket(info));
  245. }
  246. /* return last occurrence of needle in haystack */
  247. static const char *my_strrstr (const char *haystack, const char *needle)
  248. {
  249.    int needle_len = strlen(needle);
  250.    int haystack_len = strlen(haystack);
  251.    haystack_len -= needle_len;
  252.    while (haystack_len >= 0) {
  253.      if (strncmp(haystack + haystack_len, needle, needle_len) == 0) {
  254.         return (haystack + haystack_len);
  255.      }
  256.      haystack_len--;
  257.    }
  258.    return (NULL);
  259. }
  260. /* 
  261.  * removes the overlap between the base_url and the control_string
  262.  * the base_url will never contain /trackID= x, so remove it
  263.  * Example: rm_rtsp_overlap("rtsp://www.blah.com/foo", "foo/trackId=2")
  264.  *          will return "rtsp://www.blah.com/foo/trackId=2"
  265.  */
  266. static char *rm_rtsp_overlap (const char *control_string, const char *base_url)
  267. {
  268.   char *str = NULL;
  269.   uint32_t cblen = 0; 
  270.   char *file_ptr = strrchr(control_string, '/'); 
  271.   if (file_ptr != NULL && file_ptr != control_string) {
  272.     char *path = NULL;
  273.     char *last_path_in_base = NULL;
  274. uint32_t control_len = strlen(control_string);
  275. uint32_t file_len = strlen(file_ptr);
  276. uint32_t last_path_len = 0;
  277.     /* path will contain control str without /trackID = x at the end */
  278.     path = (char *)malloc(control_len - file_len + 1);
  279.     if (path == NULL) 
  280.       exit(EXIT_FAILURE);
  281.     strncpy (path, control_string, control_len - file_len);
  282.     path[control_len - file_len] = '';
  283.     last_path_in_base = strdup(my_strrstr(base_url, path));
  284. if (last_path_in_base != NULL) 
  285.   last_path_len = strlen(last_path_in_base);
  286.     if (last_path_in_base == NULL 
  287. || last_path_len != strlen(path)) {
  288.   /* couldn't find path in base url or isn't at end of base url */
  289.       free(path);
  290.   free(last_path_in_base);
  291.       return ((char *)NULL);
  292.     } 
  293. else {
  294.   /* make sure there is one and only one '/' between the base url
  295.        * and the control string */
  296.       cblen = strlen(base_url) - last_path_len;
  297.       if (*control_string != '/') {
  298.         cblen +=1;
  299.       }
  300.       str = (char *)malloc(cblen + control_len +1);
  301.       if (str == NULL) 
  302.         exit(EXIT_FAILURE);
  303.       /* copy base_url up to last occurrence of path */
  304.       strncpy(str, base_url, cblen);
  305.       str[cblen] = '';
  306.       strcat(str, control_string);
  307.       free(path);
  308.     }
  309. free(last_path_in_base);
  310.   }
  311.   return ((char *)str);
  312. }
  313. /* 
  314.  * attempts to match the session url with  
  315.  * content_base/url or session_name/url
  316.  * if content base and url overlap, or if session_name and 
  317.  * url overlap, remove the overlap and attempt to match again
  318.  * return 1 if matched, 0 otherwise
  319.  */
  320. int rtsp_is_url_my_stream (rtsp_session_t *session,
  321.    const char *url,
  322.    const char *content_base,
  323.    const char *session_name)
  324.   char *session_url = session->url;
  325.   const char *end;
  326.   int is_match = 0;
  327.   end = my_strrstr(session_url, url); 
  328.   if (end != NULL  || strcmp(url,"*") == 0) {
  329.     if (strncmp(session_url, content_base,
  330. strlen(session_url) - strlen(end)) == 0
  331. || strncmp(session_url, session_name, 
  332.    strlen(session_url) - strlen(end)) == 0) {
  333.       is_match = 1;
  334.     }
  335.     else {
  336.       /* url isn't contained in the session_url */
  337.       /* check if there is an overlap */
  338.       char *str1 = rm_rtsp_overlap(url, content_base);
  339.       char *str2 = rm_rtsp_overlap(url, session_name);
  340.       if (strcmp(session_url, str1) == 0 
  341.   || strcmp(session_url, str2) == 0)  
  342. is_match = 1;
  343.       free(str1);
  344.       free(str2);
  345.     }
  346.   }
  347.   return (is_match);
  348. }
  349. struct in_addr get_server_ip_address (rtsp_session_t *session)
  350. {
  351.   return session->parent->server_addr;
  352. }