rtsp.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:17k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * rtsp.c: minimalistic implementation of rtsp protocol.
  3.  *         Not RFC 2326 compilant yet and only handle REAL RTSP.
  4.  *****************************************************************************
  5.  * Copyright (C) 2002-2004 the xine project
  6.  * Copyright (C) 2005 VideoLAN
  7.  * $Id: 9587cea4c5e035e363fdf858f6a191c109105076 $
  8.  *
  9.  * Authors: Gildas Bazin <gbazin@videolan.org>
  10.  *          Adapted from xine which itself adapted it from joschkas real tools.
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or
  15.  * (at your option) any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include "rtsp.h"
  31. #define BUF_SIZE 4096
  32. #define HEADER_SIZE 1024
  33. #define MAX_FIELDS 256
  34. struct rtsp_s {
  35.   int           s;
  36.   char         *host;
  37.   int           port;
  38.   char         *path;
  39.   char         *mrl;
  40.   char         *user_agent;
  41.   char         *server;
  42.   unsigned int  server_state;
  43.   uint32_t      server_caps;
  44.   unsigned int  cseq;
  45.   char         *session;
  46.   char        *answers[MAX_FIELDS];   /* data of last message */
  47.   char        *scheduled[MAX_FIELDS]; /* will be sent with next message */
  48. };
  49. /*
  50.  * constants
  51.  */
  52. const char rtsp_protocol_version[]="RTSP/1.0";
  53. /* server states */
  54. #define RTSP_CONNECTED 1
  55. #define RTSP_INIT      2
  56. #define RTSP_READY     4
  57. #define RTSP_PLAYING   8
  58. #define RTSP_RECORDING 16
  59. /* server capabilities */
  60. #define RTSP_OPTIONS       0x001
  61. #define RTSP_DESCRIBE      0x002
  62. #define RTSP_ANNOUNCE      0x004
  63. #define RTSP_SETUP         0x008
  64. #define RTSP_GET_PARAMETER 0x010
  65. #define RTSP_SET_PARAMETER 0x020
  66. #define RTSP_TEARDOWN      0x040
  67. #define RTSP_PLAY          0x080
  68. #define RTSP_RECORD        0x100
  69. /*
  70.  * rtsp_get gets a line from stream
  71.  * and returns a null terminated string (must be freed).
  72.  */
  73.  
  74. static char *rtsp_get( rtsp_client_t *rtsp )
  75. {
  76.   char *psz_buffer = malloc( BUF_SIZE );
  77.   char *psz_string = NULL;
  78.   if( rtsp->pf_read_line( rtsp->p_userdata, (uint8_t*)psz_buffer, (unsigned int)BUF_SIZE ) >= 0 )
  79.   {
  80.     //printf( "<< '%s'n", psz_buffer );
  81.       psz_string = strdup( psz_buffer );
  82.   }
  83.   free( psz_buffer );
  84.   return psz_string;
  85. }
  86. /*
  87.  * rtsp_put puts a line on stream
  88.  */
  89. static int rtsp_put( rtsp_client_t *rtsp, const char *psz_string )
  90. {
  91.     unsigned int i_buffer = strlen( psz_string );
  92.     char *psz_buffer = malloc( i_buffer + 3 );
  93.     int i_ret;
  94.     strcpy( psz_buffer, psz_string );
  95.     psz_buffer[i_buffer] = 'r'; psz_buffer[i_buffer+1] = 'n';
  96.     psz_buffer[i_buffer+2] = 0;
  97.     i_ret = rtsp->pf_write( rtsp->p_userdata, (uint8_t*)psz_buffer, i_buffer + 2 );
  98.     free( psz_buffer );
  99.     return i_ret;
  100. }
  101. /*
  102.  * extract server status code
  103.  */
  104. static int rtsp_get_status_code( rtsp_client_t *rtsp, const char *psz_string )
  105. {
  106.     char psz_buffer[4];
  107.     int i_code = 0;
  108.     if( !strncmp( psz_string, "RTSP/1.0", sizeof("RTSP/1.0") - 1 ) )
  109.     {
  110.         memcpy( psz_buffer, psz_string + sizeof("RTSP/1.0"), 3 );
  111.         psz_buffer[3] = 0;
  112.         i_code = atoi( psz_buffer );
  113.     }
  114.     else if( !strncmp( psz_string, "SET_PARAMETER", 8 ) )
  115.     {
  116.         return RTSP_STATUS_SET_PARAMETER;
  117.     }
  118.     if( i_code != 200 )
  119.     {
  120.         //fprintf( stderr, "librtsp: server responds: '%s'n", psz_string );
  121.     }
  122.     return i_code;
  123. }
  124. /*
  125.  * send a request
  126.  */
  127. static int rtsp_send_request( rtsp_client_t *rtsp, const char *psz_type,
  128.                               const char *psz_what )
  129. {
  130.     char **ppsz_payload = rtsp->p_private->scheduled;
  131.     char *psz_buffer;
  132.     int i_ret;
  133.     psz_buffer = malloc( strlen(psz_type) + strlen(psz_what) +
  134.                          sizeof("RTSP/1.0") + 2 );
  135.     sprintf( psz_buffer, "%s %s %s", psz_type, psz_what, "RTSP/1.0" );
  136.     i_ret = rtsp_put( rtsp, psz_buffer );
  137.     free( psz_buffer );
  138.     if( ppsz_payload )
  139.         while( *ppsz_payload )
  140.         {
  141.             rtsp_put( rtsp, *ppsz_payload );
  142.             ppsz_payload++;
  143.         }
  144.     rtsp_put( rtsp, "" );
  145.     rtsp_unschedule_all( rtsp );
  146.     return i_ret;
  147. }
  148. /*
  149.  * schedule standard fields
  150.  */
  151. static void rtsp_schedule_standard( rtsp_client_t *rtsp )
  152. {
  153.     char tmp[17];
  154.     sprintf( tmp, "Cseq: %u", rtsp->p_private->cseq);
  155.     rtsp_schedule_field( rtsp, tmp );
  156.     if( rtsp->p_private->session )
  157.     {
  158.         char *buf;
  159.         buf = malloc( strlen(rtsp->p_private->session) + 15 );
  160.         sprintf( buf, "Session: %s", rtsp->p_private->session );
  161.         rtsp_schedule_field( rtsp, buf );
  162.         free( buf );
  163.     }
  164. }
  165. /*
  166.  * get the answers, if server responses with something != 200, return NULL
  167.  */
  168. static int rtsp_get_answers( rtsp_client_t *rtsp )
  169. {
  170.     char *answer = NULL;
  171.     unsigned int answer_seq;
  172.     char **answer_ptr = rtsp->p_private->answers;
  173.     int code;
  174.     int ans_count = 0;
  175.     answer = rtsp_get( rtsp );
  176.     if( !answer ) return 0;
  177.     code = rtsp_get_status_code( rtsp, answer );
  178.     free( answer );
  179.     rtsp_free_answers( rtsp );
  180.     do { /* while we get answer lines */
  181.       answer = rtsp_get( rtsp );
  182.       if( !answer ) return 0;
  183.       if( !strncasecmp( answer, "Cseq:", 5 ) )
  184.       {
  185.           sscanf( answer, "%*s %u", &answer_seq );
  186.           if( rtsp->p_private->cseq != answer_seq )
  187.           {
  188.             //fprintf( stderr, "warning: Cseq mismatch. got %u, assumed %u",
  189.             //       answer_seq, rtsp->p_private->cseq );
  190.               rtsp->p_private->cseq = answer_seq;
  191.           }
  192.       }
  193.       if( !strncasecmp( answer, "Server:", 7 ) )
  194.       {
  195.           char *buf = malloc( strlen(answer) );
  196.           sscanf( answer, "%*s %s", buf );
  197.           free( rtsp->p_private->server );
  198.           rtsp->p_private->server = buf;
  199.       }
  200.       if( !strncasecmp( answer, "Session:", 8 ) )
  201.       {
  202.           char *buf = malloc( strlen(answer) );
  203.           sscanf( answer, "%*s %s", buf );
  204.           if( rtsp->p_private->session )
  205.           {
  206.               if( strcmp( buf, rtsp->p_private->session ) )
  207.               {
  208.                   //fprintf( stderr,
  209.                   //         "rtsp: warning: setting NEW session: %sn", buf );
  210.                   free( rtsp->p_private->session );
  211.                   rtsp->p_private->session = strdup( buf );
  212.               }
  213.           }
  214.           else
  215.           {
  216.               //fprintf( stderr, "setting session id to: %sn", buf );
  217.               rtsp->p_private->session = strdup( buf );
  218.           }
  219.           free( buf );
  220.       }
  221.       *answer_ptr = answer;
  222.       answer_ptr++;
  223.     } while( (strlen(answer) != 0) && (++ans_count < MAX_FIELDS) );
  224.     rtsp->p_private->cseq++;
  225.     *answer_ptr = NULL;
  226.     rtsp_schedule_standard( rtsp );
  227.     return code;
  228. }
  229. /*
  230.  * send an ok message
  231.  */
  232. int rtsp_send_ok( rtsp_client_t *rtsp )
  233. {
  234.     char cseq[16];
  235.     rtsp_put( rtsp, "RTSP/1.0 200 OK" );
  236.     sprintf( cseq, "CSeq: %u", rtsp->p_private->cseq );
  237.     rtsp_put( rtsp, cseq );
  238.     rtsp_put( rtsp, "" );
  239.     return 0;
  240. }
  241. /*
  242.  * implementation of must-have rtsp requests; functions return
  243.  * server status code.
  244.  */
  245. int rtsp_request_options( rtsp_client_t *rtsp, const char *what )
  246. {
  247.     char *buf;
  248.     if( what ) buf = strdup(what);
  249.     else
  250.     {
  251.         buf = malloc( strlen(rtsp->p_private->host) + 16 );
  252.         sprintf( buf, "rtsp://%s:%i", rtsp->p_private->host,
  253.                  rtsp->p_private->port );
  254.     }
  255.     rtsp_send_request( rtsp, "OPTIONS", buf );
  256.     free( buf );
  257.     return rtsp_get_answers( rtsp );
  258. }
  259. int rtsp_request_describe( rtsp_client_t *rtsp, const char *what )
  260. {
  261.     char *buf;
  262.     if( what )
  263.     {
  264.         buf = strdup(what);
  265.     }
  266.     else
  267.     {
  268.         buf = malloc( strlen(rtsp->p_private->host) +
  269.                       strlen(rtsp->p_private->path) + 16 );
  270.         sprintf( buf, "rtsp://%s:%i/%s", rtsp->p_private->host,
  271.                  rtsp->p_private->port, rtsp->p_private->path );
  272.     }
  273.     rtsp_send_request( rtsp, "DESCRIBE", buf );
  274.     free( buf );
  275.     return rtsp_get_answers( rtsp );
  276. }
  277. int rtsp_request_setup( rtsp_client_t *rtsp, const char *what )
  278. {
  279.     rtsp_send_request( rtsp, "SETUP", what );
  280.     return rtsp_get_answers( rtsp );
  281. }
  282. int rtsp_request_setparameter( rtsp_client_t *rtsp, const char *what )
  283. {
  284.     char *buf;
  285.     if( what )
  286.     {
  287.         buf = strdup(what);
  288.     }
  289.     else
  290.     {
  291.         buf = malloc( strlen(rtsp->p_private->host) +
  292.                       strlen(rtsp->p_private->path) + 16 );
  293.         sprintf( buf, "rtsp://%s:%i/%s", rtsp->p_private->host,
  294.                  rtsp->p_private->port, rtsp->p_private->path );
  295.     }
  296.     rtsp_send_request( rtsp, "SET_PARAMETER", buf );
  297.     free( buf );
  298.     return rtsp_get_answers( rtsp );
  299. }
  300. int rtsp_request_play( rtsp_client_t *rtsp, const char *what )
  301. {
  302.     char *buf;
  303.     if( what )
  304.     {
  305.         buf = strdup( what );
  306.     }
  307.     else
  308.     {
  309.         buf = malloc( strlen(rtsp->p_private->host) +
  310.                       strlen(rtsp->p_private->path) + 16 );
  311.         sprintf( buf, "rtsp://%s:%i/%s", rtsp->p_private->host,
  312.                  rtsp->p_private->port, rtsp->p_private->path );
  313.     }
  314.     rtsp_send_request( rtsp, "PLAY", buf );
  315.     free( buf );
  316.     return rtsp_get_answers( rtsp );
  317. }
  318. int rtsp_request_tearoff( rtsp_client_t *rtsp, const char *what )
  319. {
  320.     rtsp_send_request( rtsp, "TEAROFF", what );
  321.     return rtsp_get_answers( rtsp );
  322. }
  323. /*
  324.  * read opaque data from stream
  325.  */
  326. int rtsp_read_data( rtsp_client_t *rtsp, uint8_t *buffer, unsigned int size )
  327. {
  328.     int i, seq;
  329.     if( size >= 4 )
  330.     {
  331.         i = rtsp->pf_read( rtsp->p_userdata, (uint8_t*)buffer, (unsigned int) 4 );
  332.         if( i < 4 ) return i;
  333.         if( buffer[0]=='S' && buffer[1]=='E' && buffer[2]=='T' &&
  334.             buffer[3]=='_' )
  335.         {
  336.             char *rest = rtsp_get( rtsp );
  337.             if( !rest ) return -1;
  338.             seq = -1;
  339.             do
  340.             {
  341.                 free( rest );
  342.                 rest = rtsp_get( rtsp );
  343.                 if( !rest ) return -1;
  344.                 if( !strncasecmp( rest, "Cseq:", 5 ) )
  345.                     sscanf( rest, "%*s %u", &seq );
  346.             } while( *rest );
  347.             free( rest );
  348.             if( seq < 0 )
  349.             {
  350.                 //fprintf(stderr, "warning: cseq not recognized!n");
  351.                 seq = 1;
  352.             }
  353.             /* lets make the server happy */
  354.             rtsp_put( rtsp, "RTSP/1.0 451 Parameter Not Understood" );
  355.             rest = malloc(17);
  356.             sprintf( rest,"CSeq: %u", seq );
  357.             rtsp_put( rtsp, rest );
  358.             rtsp_put( rtsp, "" );
  359.             free( rest );
  360.             i = rtsp->pf_read( rtsp->p_userdata, (unsigned char*)buffer, size );
  361.         }
  362.         else
  363.         {
  364.             i = rtsp->pf_read( rtsp->p_userdata, (unsigned char*)buffer + 4, size - 4 );
  365.             i += 4;
  366.         }
  367.     }
  368.     else i = rtsp->pf_read( rtsp->p_userdata, (unsigned char*)buffer, size );
  369.     //fprintf( stderr, "<< %d of %d bytesn", i, size );
  370.     return i;
  371. }
  372. /*
  373.  * connect to a rtsp server
  374.  */
  375. int rtsp_connect( rtsp_client_t *rtsp, const char *psz_mrl,
  376.                   const char *psz_user_agent )
  377. {
  378.     rtsp_t *s;
  379.     char *mrl_ptr;
  380.     char *slash, *colon;
  381.     unsigned int hostend, pathbegin, i;
  382.     if( !psz_mrl ) return -1;
  383.     s = malloc( sizeof(rtsp_t) );
  384.     rtsp->p_private = s;
  385.     if( !strncmp( psz_mrl, "rtsp://", 7 ) ) psz_mrl += 7;
  386.     mrl_ptr = strdup( psz_mrl );
  387.     for( i=0; i<MAX_FIELDS; i++ )
  388.     {
  389.         s->answers[i]=NULL;
  390.         s->scheduled[i]=NULL;
  391.     }
  392.     s->host = NULL;
  393.     s->port = 554; /* rtsp standard port */
  394.     s->path = NULL;
  395.     s->mrl  = strdup(psz_mrl);
  396.     s->server = NULL;
  397.     s->server_state = 0;
  398.     s->server_caps = 0;
  399.     s->cseq = 0;
  400.     s->session = NULL;
  401.     if( psz_user_agent ) s->user_agent = strdup( psz_user_agent );
  402.     else s->user_agent = strdup( "User-Agent: RealMedia Player Version "
  403.                                  "6.0.9.1235 (linux-2.0-libc6-i386-gcc2.95)" );
  404.     slash = strchr( mrl_ptr, '/' );
  405.     colon = strchr( mrl_ptr, ':' );
  406.     if( !slash ) slash = mrl_ptr + strlen(mrl_ptr) + 1;
  407.     if( !colon ) colon = slash;
  408.     if( colon > slash ) colon = slash;
  409.     pathbegin = slash - mrl_ptr;
  410.     hostend = colon - mrl_ptr;
  411.     s->host = malloc(hostend+1);
  412.     strncpy( s->host, mrl_ptr, hostend );
  413.     s->host[hostend] = 0;
  414.     if( pathbegin < strlen(mrl_ptr) ) s->path = strdup(mrl_ptr+pathbegin+1);
  415.     if( colon != slash )
  416.     {
  417.         char buffer[pathbegin-hostend];
  418.         strncpy( buffer, mrl_ptr+hostend+1, pathbegin-hostend-1 );
  419.         buffer[pathbegin-hostend-1] = 0;
  420.         s->port = atoi(buffer);
  421.         if( s->port < 0 || s->port > 65535 ) s->port = 554;
  422.     }
  423.     free( mrl_ptr );
  424.     //fprintf( stderr, "got mrl: %s %i %sn", s->host, s->port, s->path );
  425.     s->s = rtsp->pf_connect( rtsp->p_userdata, s->host, s->port );
  426.     if( s->s < 0 )
  427.     {
  428.         //fprintf(stderr, "rtsp: failed to connect to '%s'n", s->host);
  429.         rtsp_close( rtsp );
  430.         return -1;
  431.     }
  432.     s->server_state = RTSP_CONNECTED;
  433.     /* now lets send an options request. */
  434.     rtsp_schedule_field( rtsp, "CSeq: 1");
  435.     rtsp_schedule_field( rtsp, s->user_agent);
  436.     rtsp_schedule_field( rtsp, "ClientChallenge: "
  437.                                "9e26d33f2984236010ef6253fb1887f7");
  438.     rtsp_schedule_field( rtsp, "PlayerStarttime: [28/03/2003:22:50:23 00:00]");
  439.     rtsp_schedule_field( rtsp, "CompanyID: KnKV4M4I/B2FjJ1TToLycw==" );
  440.     rtsp_schedule_field( rtsp, "GUID: 00000000-0000-0000-0000-000000000000" );
  441.     rtsp_schedule_field( rtsp, "RegionData: 0" );
  442.     rtsp_schedule_field( rtsp, "ClientID: "
  443.                                "Linux_2.4_6.0.9.1235_play32_RN01_EN_586" );
  444.     /*rtsp_schedule_field( rtsp, "Pragma: initiate-session" );*/
  445.     rtsp_request_options( rtsp, NULL );
  446.     return 0;
  447. }
  448. /*
  449.  * closes an rtsp connection
  450.  */
  451. void rtsp_close( rtsp_client_t *rtsp )
  452. {
  453.     if( rtsp->p_private->server_state )
  454.     {
  455.         /* TODO: send a TEAROFF */
  456.         rtsp->pf_disconnect( rtsp->p_userdata );
  457.     }
  458.     free( rtsp->p_private->path );
  459.     free( rtsp->p_private->host );
  460.     free( rtsp->p_private->mrl );
  461.     free( rtsp->p_private->session );
  462.     free( rtsp->p_private->user_agent );
  463.     free( rtsp->p_private->server );
  464.     rtsp_free_answers( rtsp );
  465.     rtsp_unschedule_all( rtsp );
  466.     free( rtsp->p_private );
  467. }
  468. /*
  469.  * search in answers for tags. returns a pointer to the content
  470.  * after the first matched tag. returns NULL if no match found.
  471.  */
  472. char *rtsp_search_answers( rtsp_client_t *rtsp, const char *tag )
  473. {
  474.     char **answer;
  475.     char *ptr;
  476.     if( !rtsp->p_private->answers ) return NULL;
  477.     answer = rtsp->p_private->answers;
  478.     while(*answer)
  479.     {
  480.         if( !strncasecmp( *answer, tag, strlen(tag) ) )
  481.         {
  482.             ptr = strchr(*answer, ':');
  483.             ptr++;
  484.             while( *ptr == ' ' ) ptr++;
  485.             return ptr;
  486.         }
  487.         answer++;
  488.     }
  489.     return NULL;
  490. }
  491. /*
  492.  * session id management
  493.  */
  494. void rtsp_set_session( rtsp_client_t *rtsp, const char *id )
  495. {
  496.     free( rtsp->p_private->session );
  497.     rtsp->p_private->session = strdup(id);
  498. }
  499. char *rtsp_get_session( rtsp_client_t *rtsp )
  500. {
  501.     return rtsp->p_private->session;
  502. }
  503. char *rtsp_get_mrl( rtsp_client_t *rtsp )
  504. {
  505.     return rtsp->p_private->mrl;
  506. }
  507. /*
  508.  * schedules a field for transmission
  509.  */
  510. void rtsp_schedule_field( rtsp_client_t *rtsp, const char *string )
  511. {
  512.     int i = 0;
  513.     if( !string ) return;
  514.     while( rtsp->p_private->scheduled[i] ) i++;
  515.     rtsp->p_private->scheduled[i] = strdup(string);
  516. }
  517. /*
  518.  * removes the first scheduled field which prefix matches string.
  519.  */
  520. void rtsp_unschedule_field( rtsp_client_t *rtsp, const char *string )
  521. {
  522.     char **ptr = rtsp->p_private->scheduled;
  523.     if( !string ) return;
  524.     while( *ptr )
  525.     {
  526.       if( !strncmp(*ptr, string, strlen(string)) ) break;
  527.     }
  528.     free( *ptr );
  529.     ptr++;
  530.     do
  531.     {
  532.         *(ptr-1) = *ptr;
  533.     } while( *ptr );
  534. }
  535. /*
  536.  * unschedule all fields
  537.  */
  538. void rtsp_unschedule_all( rtsp_client_t *rtsp )
  539. {
  540.     char **ptr;
  541.     if( !rtsp->p_private->scheduled ) return;
  542.     ptr = rtsp->p_private->scheduled;
  543.     while( *ptr )
  544.     {
  545.         free( *ptr );
  546.         *ptr = NULL;
  547.         ptr++;
  548.     }
  549. }
  550. /*
  551.  * free answers
  552.  */
  553. void rtsp_free_answers( rtsp_client_t *rtsp )
  554. {
  555.     char **answer;
  556.     if( !rtsp->p_private->answers ) return;
  557.     answer = rtsp->p_private->answers;
  558.     while( *answer )
  559.     {
  560.         free( *answer );
  561.         *answer = NULL;
  562.         answer++;
  563.     }
  564. }