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

流媒体/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_command.c - process API calls to send/receive rtsp commands
  23.  */
  24. #include "rtsp_private.h"
  25. static const char *UserAgent = "Cisco RTSP 1.0";
  26. /*
  27.  * rtsp_build_common()
  28.  * Builds a common header based on rtsp_command_t information.
  29.  */
  30. static int rtsp_build_common (char *buffer,
  31.       uint32_t maxlen,
  32.       uint32_t *at,
  33.       rtsp_client_t *info,
  34.       rtsp_command_t *cmd,
  35.       const char *session)
  36. {
  37.   int ret;
  38.   /*
  39.    * The below is ugly, but it will allow us to remove a lot of lines
  40.    * of code.  SNPRINTF_CHECK makes sure (for this routine), that we
  41.    * don't have more data in the buffer than allowed - it will return
  42.    * an error code if that happens.
  43.    */
  44. #define SNPRINTF_CHECK(fmt, value) 
  45.   ret = snprintf(buffer + *at, maxlen - *at, (fmt), (value)); 
  46.   if (ret == -1) { 
  47.     return (-1); 
  48.   }
  49.   *at += ret;
  50.   SNPRINTF_CHECK("CSeq: %urn", info->next_cseq);
  51.   if (info->cookie) {
  52.     SNPRINTF_CHECK("Cookie: %srn", info->cookie);
  53.   }
  54.   if (cmd && cmd->accept) {
  55.     SNPRINTF_CHECK("Accept: %srn", cmd->accept);
  56.   }
  57.   if (cmd && cmd->accept_encoding) {
  58.     SNPRINTF_CHECK("Accept-Encoding: %srn", cmd->accept_encoding);
  59.   }
  60.   if (cmd && cmd->accept_language) {
  61.     SNPRINTF_CHECK("Accept-Language: %srn", cmd->accept_language);
  62.   }
  63.   if (cmd && cmd->authorization) {
  64.     SNPRINTF_CHECK("Authorization: %srn", cmd->authorization);
  65.   }
  66.   if (cmd && cmd->bandwidth != 0) {
  67.     SNPRINTF_CHECK("Bandwidth: %urn", cmd->bandwidth);
  68.   }
  69.   if (cmd && cmd->blocksize != 0) {
  70.     SNPRINTF_CHECK("Blocksize: %urn", cmd->blocksize);
  71.   }
  72.   if (cmd && cmd->cachecontrol) {
  73.     SNPRINTF_CHECK("Cache-Control: %srn", cmd->cachecontrol);
  74.   }
  75.   if (cmd && cmd->conference) {
  76.     SNPRINTF_CHECK("Conference: %srn", cmd->conference);
  77.   }
  78.   if (cmd && cmd->from) {
  79.     SNPRINTF_CHECK("From: %srn", cmd->from);
  80.   }
  81.   if (cmd && cmd->proxyauth) {
  82.     SNPRINTF_CHECK("Proxy-Authorization: %srn", cmd->proxyauth);
  83.   }
  84.   if (cmd && cmd->proxyrequire) {
  85.     SNPRINTF_CHECK("Proxy-Require: %srn", cmd->proxyrequire);
  86.   }
  87.   if (cmd && cmd->range) {
  88.     SNPRINTF_CHECK("Range: %srn", cmd->range);
  89.   }
  90.   if (cmd && cmd->referer) {
  91.     SNPRINTF_CHECK("Referer: %srn", cmd->referer);
  92.   }
  93.   if (cmd && cmd->scale != 0.0) {
  94.     SNPRINTF_CHECK("Scale: %grn", cmd->scale);
  95.   }
  96.   if (session) {
  97.     SNPRINTF_CHECK("Session: %srn", session);
  98.   } else if (cmd && cmd->session) {
  99.     SNPRINTF_CHECK("Session: %srn", cmd->session);
  100.   }
  101.   if (cmd && cmd->speed != 0.0) {
  102.     SNPRINTF_CHECK("Speed: %grn", cmd->speed);
  103.   }
  104.   if (cmd && cmd->transport) {
  105.     SNPRINTF_CHECK("Transport: %srn", cmd->transport);
  106.   }
  107.     
  108.   SNPRINTF_CHECK("User-Agent: %srn",
  109.       (cmd && cmd->useragent != NULL ?  cmd->useragent : UserAgent));
  110.   if (cmd && cmd->User) {
  111.     SNPRINTF_CHECK("%s", cmd->User);
  112.   }
  113. #undef SNPRINTF_CHECK
  114.   return (0);
  115. }
  116. /*
  117.  * rtsp_send_describe - send the describe info to a server
  118.  */
  119. int rtsp_send_describe (rtsp_client_t *info,
  120. rtsp_command_t *cmd,
  121. rtsp_decode_t **decode_result)
  122. {
  123.   char buffer[2048];
  124.   uint32_t maxlen, buflen;
  125.   int ret;
  126.   rtsp_decode_t *decode;
  127.   *decode_result = NULL;
  128.   info->redirect_count = 0;
  129.   do {
  130.     maxlen = sizeof(buffer);
  131.     buflen = snprintf(buffer, maxlen, "DESCRIBE %s RTSP/1.0rn", info->url);
  132.     if (rtsp_build_common(buffer, maxlen, &buflen, info, cmd, NULL) == -1) {
  133.       return (RTSP_RESPONSE_RECV_ERROR);
  134.     }
  135.     
  136.     ret = snprintf(buffer + buflen, maxlen - buflen, "rn");
  137.     if (ret == -1) {
  138.       return (RTSP_RESPONSE_RECV_ERROR);
  139.     }
  140.     buflen += ret;
  141.     rtsp_debug(LOG_INFO, "Sending DESCRIBE %s", info->url);
  142.     rtsp_debug(LOG_DEBUG, buffer);
  143.     ret = rtsp_send_and_get(info, buffer, buflen);
  144.     decode = info->decode_response;
  145.     
  146.     if (ret == RTSP_RESPONSE_GOOD) {
  147.       rtsp_debug(LOG_INFO, "DESCRIBE returned correctly");
  148.       *decode_result = info->decode_response;
  149.       info->decode_response = NULL;
  150.       return (RTSP_RESPONSE_GOOD);
  151.     } else if (ret != RTSP_RESPONSE_REDIRECT) {
  152.       
  153.       rtsp_debug(LOG_ERR, "DESCRIBE return code %d", ret);
  154.       if (ret != RTSP_RESPONSE_RECV_ERROR &&
  155.   decode != NULL) {
  156. *decode_result = info->decode_response;
  157. info->decode_response = NULL;
  158. rtsp_debug(LOG_ERR, "Error code %s %s",
  159.    decode->retcode,
  160.    decode->retresp);
  161.       }
  162.       return (ret);
  163.     }
  164.     /*
  165.      * Handle this through the redirects
  166.      */
  167.   }  while (ret == RTSP_RESPONSE_REDIRECT);
  168.   
  169.   return (RTSP_RESPONSE_RECV_ERROR);
  170. }
  171. /*
  172.  * rtsp_send_setup - When we get the describe, this will set up a
  173.  * particular stream.  Use the session handle for all further commands for
  174.  * the stream (play, pause, teardown).
  175.  */
  176. int rtsp_send_setup (rtsp_client_t *info,
  177.      const char *url,
  178.      rtsp_command_t *cmd,
  179.      rtsp_session_t **session_result,
  180.      rtsp_decode_t **decode_result,
  181.      int is_aggregate)
  182. {
  183.   char buffer[2048], *temp;
  184.   uint32_t maxlen, buflen;
  185.   int ret;
  186.   rtsp_decode_t *decode;
  187.   rtsp_session_t *sptr;
  188.   
  189.   *decode_result = NULL;
  190.   *session_result = NULL;
  191.   info->redirect_count = 0;
  192.   if (cmd == NULL || cmd->transport == NULL) {
  193.     return (RTSP_RESPONSE_MISSING_OR_BAD_PARAM);
  194.   }
  195.   if (strncmp(url, "rtsp://", strlen("rtsp://")) != 0) {
  196.     return (RTSP_RESPONSE_BAD_URL);
  197.   }
  198.   temp = strchr(url + strlen("rtsp://"), '/');
  199.   if (temp == NULL) {
  200.     return (RTSP_RESPONSE_BAD_URL);
  201.   }
  202.   if (strncmp(url, info->url, temp - url) != 0) {
  203.     rtsp_debug(LOG_ALERT, "Bad url %s", url);
  204.     rtsp_debug(LOG_ALERT, "Should be %s", info->url);
  205.     return (RTSP_RESPONSE_BAD_URL);
  206.   }
  207.   maxlen = sizeof(buffer);
  208.   buflen = snprintf(buffer, maxlen, "SETUP %s RTSP/1.0rn", url);
  209.   if (rtsp_build_common(buffer,
  210. maxlen,
  211. &buflen,
  212. info,
  213. cmd,
  214. is_aggregate ? info->session : NULL) == -1) {
  215.     return (RTSP_RESPONSE_RECV_ERROR);
  216.   }
  217.     
  218.   ret = snprintf(buffer + buflen, maxlen - buflen, "rn");
  219.   if (ret == -1) {
  220.     return (RTSP_RESPONSE_RECV_ERROR);
  221.   }
  222.   buflen += ret;
  223.   rtsp_debug(LOG_INFO, "Sending SETUP %s", url);
  224.   rtsp_debug(LOG_DEBUG, buffer);
  225.   ret = rtsp_send_and_get(info, buffer, buflen);
  226.   decode = info->decode_response;
  227.     
  228.   if (ret == RTSP_RESPONSE_GOOD) {
  229.     rtsp_debug(LOG_INFO, "SETUP returned correctly");
  230.     *decode_result = info->decode_response;
  231.     info->decode_response = NULL;
  232. #ifndef IPTV_COMPATIBLE
  233.     if ((*decode_result)->session == NULL) {
  234.       return (RTSP_RESPONSE_BAD);
  235.     }
  236. #endif
  237.     if (is_aggregate && info->session != NULL) {
  238.       if (strcmp(info->session, (*decode_result)->session) != 0) {
  239. rtsp_debug(LOG_ALERT, "Session for %s returned different %s %s",
  240.    url, info->session, (*decode_result)->session);
  241. return (RTSP_RESPONSE_BAD);
  242.       }
  243.     }
  244.     sptr = info->session_list;
  245.     while (sptr != NULL) {
  246.       if (strcmp(sptr->url, url) == 0)
  247. break;
  248.       sptr = sptr->next;
  249.     }
  250.     if (sptr == NULL) {
  251.       sptr = malloc(sizeof(rtsp_session_t));
  252.       if (sptr == NULL) {
  253. return (RTSP_RESPONSE_RECV_ERROR);
  254.       }
  255.       sptr->url = strdup(url);
  256.       if ((*decode_result)->session != NULL)
  257. sptr->session = strdup((*decode_result)->session);
  258.       else
  259. sptr->session = NULL;
  260.       sptr->parent = info;
  261.       sptr->next = info->session_list;
  262.       info->session_list = sptr;
  263.       if (is_aggregate && info->session == NULL)
  264. info->session = sptr->session;
  265.     }
  266.     *session_result = sptr;
  267.     return (RTSP_RESPONSE_GOOD);
  268.   } else {
  269.     rtsp_debug(LOG_ERR, "SETUP return code %d", ret);
  270.     if (ret != RTSP_RESPONSE_RECV_ERROR &&
  271. decode != NULL) {
  272.       *decode_result = info->decode_response;
  273.       info->decode_response = NULL;
  274.       rtsp_debug(LOG_ERR, "Error code %s %s",
  275.  decode->retcode,
  276.  decode->retresp);
  277.     }
  278.     return (ret);
  279.   }
  280.   
  281.   return (RTSP_RESPONSE_RECV_ERROR);
  282. }
  283. /*
  284.  * check_session - make sure that the session is correct for that command
  285.  */
  286. static int check_session (rtsp_session_t *session,
  287.    rtsp_command_t *cmd)
  288. {
  289.   rtsp_session_t *sptr;
  290.   rtsp_client_t *info;
  291.   info = session->parent;
  292.   if (info == NULL) {
  293.     rtsp_debug(LOG_ALERT, "Session doesn't point to parent");
  294.     return (FALSE);
  295.   }
  296.   
  297.   sptr = info->session_list;
  298.   while (sptr != session && sptr != NULL) sptr = sptr->next;
  299.   if (sptr == NULL) {
  300.     rtsp_debug(LOG_ALERT, "session not found in info list");
  301.     return (FALSE);
  302.   }
  303.   
  304.   if ((cmd != NULL) &&
  305.       (cmd->session != NULL) &&
  306.       (strcmp(cmd->session, session->session) != 0)) {
  307.     rtsp_debug(LOG_ALERT, "Have cmd->session set wrong");
  308.     return (FALSE);
  309.   }
  310.   return (TRUE);
  311. }
  312. static int rtsp_send_play_or_pause (const char *command,
  313.     const char *url,
  314.     const char *session,
  315.     rtsp_client_t *info,
  316.     rtsp_command_t *cmd,
  317.     rtsp_decode_t **decode_result)
  318. {
  319.   char buffer[2048];
  320.   uint32_t maxlen, buflen;
  321.   int ret;
  322.   rtsp_decode_t *decode;
  323.   *decode_result = NULL;
  324.   if (info->server_socket < 0) {
  325.     return (RTSP_RESPONSE_CLOSED_SOCKET);
  326.   }
  327.   maxlen = sizeof(buffer);
  328.   buflen = snprintf(buffer, maxlen, "%s %s RTSP/1.0rn", command, url);
  329.   if (rtsp_build_common(buffer, maxlen, &buflen,
  330. info, cmd, session) == -1) {
  331.     return (RTSP_RESPONSE_RECV_ERROR);
  332.   }
  333.     
  334.   ret = snprintf(buffer + buflen, maxlen - buflen, "rn");
  335.   if (ret == -1) {
  336.     return (RTSP_RESPONSE_RECV_ERROR);
  337.   }
  338.   buflen += ret;
  339.   rtsp_debug(LOG_INFO, "Sending %s %s", command, url);
  340.   rtsp_debug(LOG_DEBUG, buffer);
  341.   ret = rtsp_send_and_get(info, buffer, buflen);
  342.   decode = info->decode_response;
  343.     
  344.   if (ret == RTSP_RESPONSE_GOOD) {
  345.     rtsp_debug(LOG_ERR, "%s returned correctly", command);
  346.     *decode_result = info->decode_response;
  347.     info->decode_response = NULL;
  348.     return (RTSP_RESPONSE_GOOD);
  349.   } else {
  350.     rtsp_debug(LOG_ERR, "%s return code %d", command, ret);
  351.     if (ret != RTSP_RESPONSE_RECV_ERROR &&
  352. decode != NULL) {
  353.       *decode_result = info->decode_response;
  354.       info->decode_response = NULL;
  355.       rtsp_debug(LOG_ERR, "Error code %s %s",
  356.  decode->retcode,
  357.  decode->retresp);
  358.     }
  359.     return (ret);
  360.   }
  361.   
  362.   return (RTSP_RESPONSE_RECV_ERROR);
  363. }
  364. /*
  365.  * rtsp_send_play - send play command.  It helps if Range is set
  366.  */
  367. int rtsp_send_play (rtsp_session_t *session,
  368.     rtsp_command_t *cmd,
  369.     rtsp_decode_t **decode_result)
  370. {
  371.   if (check_session(session, cmd) == FALSE) {
  372.     return (RTSP_RESPONSE_MISSING_OR_BAD_PARAM);
  373.   }
  374.   return (rtsp_send_play_or_pause("PLAY",
  375.   session->url,
  376.   session->session,
  377.   session->parent,
  378.   cmd,
  379.   decode_result));
  380. }
  381. /*
  382.  * rtsp_send_pause - send a pause on a particular session
  383.  */
  384. int rtsp_send_pause (rtsp_session_t *session,
  385.      rtsp_command_t *cmd,
  386.      rtsp_decode_t **decode_result)
  387. {
  388.   if (check_session(session, cmd) == FALSE) {
  389.     return (RTSP_RESPONSE_MISSING_OR_BAD_PARAM);
  390.   }
  391.   return (rtsp_send_play_or_pause("PAUSE",
  392.   session->url,
  393.   session->session,
  394.   session->parent,
  395.   cmd,
  396.   decode_result));
  397. }
  398. int rtsp_send_aggregate_play (rtsp_client_t *info,
  399.       const char *aggregate_url,
  400.       rtsp_command_t *cmd,
  401.       rtsp_decode_t **decode_result)
  402. {
  403.   return (rtsp_send_play_or_pause("PLAY",
  404.   aggregate_url,
  405.   info->session,
  406.   info,
  407.   cmd,
  408.   decode_result));
  409. }
  410. int rtsp_send_aggregate_pause (rtsp_client_t *info,
  411.        const char *aggregate_url,
  412.        rtsp_command_t *cmd,
  413.        rtsp_decode_t **decode_result)
  414. {
  415.   return (rtsp_send_play_or_pause("PAUSE",
  416.   aggregate_url,
  417.   info->session,
  418.   info,
  419.   cmd,
  420.   decode_result));
  421. }
  422. static int rtsp_send_teardown_common (rtsp_client_t *info,
  423.       const char *url,
  424.       const char *session,
  425.       rtsp_command_t *cmd,
  426.       rtsp_decode_t **decode_result)
  427. {
  428.   char buffer[2048];
  429.   uint32_t maxlen, buflen;
  430.   int ret;
  431.   rtsp_decode_t *decode;
  432.   
  433.   *decode_result = NULL;
  434.   if (info->server_socket < 0) {
  435.     return (RTSP_RESPONSE_CLOSED_SOCKET);
  436.   }
  437.   maxlen = sizeof(buffer);
  438.   buflen = snprintf(buffer, maxlen, "TEARDOWN %s RTSP/1.0rn", url);
  439.   if (rtsp_build_common(buffer, maxlen, &buflen,
  440. info, cmd, session) == -1) {
  441.     return (RTSP_RESPONSE_RECV_ERROR);
  442.   }
  443.     
  444.   ret = snprintf(buffer + buflen, maxlen - buflen, "rn");
  445.   if (ret == -1) {
  446.     return (RTSP_RESPONSE_RECV_ERROR);
  447.   }
  448.   buflen += ret;
  449.   rtsp_debug(LOG_INFO, "Sending TEARDOWN %s", url);
  450.   rtsp_debug(LOG_DEBUG, buffer);
  451.   ret = rtsp_send_and_get(info, buffer, buflen);
  452.   decode = info->decode_response;
  453.     
  454.   if (ret == RTSP_RESPONSE_GOOD) {
  455.     rtsp_debug(LOG_INFO, "TEARDOWN returned correctly");
  456.     *decode_result = info->decode_response;
  457.     info->decode_response = NULL;
  458.     return (RTSP_RESPONSE_GOOD);
  459.   } else {
  460.     rtsp_debug(LOG_ERR, "TEARDOWN return code %d", ret);
  461.     if (ret != RTSP_RESPONSE_RECV_ERROR &&
  462. decode != NULL) {
  463.       *decode_result = info->decode_response;
  464.       info->decode_response = NULL;
  465.       rtsp_debug(LOG_ERR, "Error code %s %s",
  466.  decode->retcode,
  467.  decode->retresp);
  468.     }
  469.     return (ret);
  470.   }
  471.   
  472.   return (RTSP_RESPONSE_RECV_ERROR);
  473. }
  474. /*
  475.  * rtsp_send_teardown.  Sends a teardown for a session.  We might eventually
  476.  * want to provide a teardown for the base url, rather than one for each
  477.  * session
  478.  */
  479. int rtsp_send_teardown (rtsp_session_t *session,
  480. rtsp_command_t *cmd,
  481. rtsp_decode_t **decode_result)
  482. {
  483.   int ret;
  484.   rtsp_client_t *info;
  485.   rtsp_session_t *sptr;
  486.   if (check_session(session, cmd) == FALSE) {
  487.     return (RTSP_RESPONSE_MISSING_OR_BAD_PARAM);
  488.   }
  489.   info = session->parent;
  490.   ret = rtsp_send_teardown_common(info,
  491.   session->url,
  492.   session->session,
  493.   cmd,
  494.   decode_result);
  495.   if (ret == RTSP_RESPONSE_GOOD) {
  496.     if (info->session_list == session) {
  497.       info->session_list = session->next;
  498.     } else {
  499.       sptr = info->session_list;
  500.       while (sptr->next != session) sptr = sptr->next;
  501.       sptr->next = session->next;
  502.     }
  503.     free_session_info(session);
  504.   }
  505.   return (ret);
  506. }
  507. int rtsp_send_aggregate_teardown (rtsp_client_t *info,
  508.   const char *url,
  509.   rtsp_command_t *cmd,
  510.   rtsp_decode_t **decode_result)
  511. {
  512.   int ret;
  513.   rtsp_session_t *p;
  514.   ret = rtsp_send_teardown_common(info,
  515.   url,
  516.   info->session,
  517.   cmd,
  518.   decode_result);
  519.   if (ret == RTSP_RESPONSE_GOOD) {
  520.     while (info->session_list != NULL) {
  521.       p = info->session_list;
  522.       info->session_list = info->session_list->next;
  523.       free_session_info(p);
  524.     }
  525.   }
  526.   return (ret);
  527. }
  528.   
  529.