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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * http.c
  3.  *****************************************************************************
  4.  * Copyright (C) 2001-2009 the VideoLAN team
  5.  * $Id: c6b930fcf06b16fe446a7c6cbbccc7ffcfa0d3a8 $
  6.  *
  7.  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  8.  *          Jon Lech Johansen <jon@nanocrew.net>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #ifdef HAVE_CONFIG_H
  28. # include "config.h"
  29. #endif
  30. #include <vlc_common.h>
  31. #include <vlc_plugin.h>
  32. #include <vlc_sout.h>
  33. #include <vlc_block.h>
  34. #include <vlc_input.h>
  35. #include <vlc_playlist.h>
  36. #if 0 //def HAVE_AVAHI_CLIENT
  37.     #include "bonjour.h"
  38.     #if defined( WIN32 )
  39.         #define DIRECTORY_SEPARATOR '\'
  40.     #else
  41.         #define DIRECTORY_SEPARATOR '/'
  42.     #endif
  43. #endif
  44. #include "vlc_httpd.h"
  45. #define DEFAULT_PORT        8080
  46. #define DEFAULT_SSL_PORT    8443
  47. /*****************************************************************************
  48.  * Module descriptor
  49.  *****************************************************************************/
  50. static int  Open ( vlc_object_t * );
  51. static void Close( vlc_object_t * );
  52. #define SOUT_CFG_PREFIX "sout-http-"
  53. #define USER_TEXT N_("Username")
  54. #define USER_LONGTEXT N_("User name that will be " 
  55.                          "requested to access the stream." )
  56. #define PASS_TEXT N_("Password")
  57. #define PASS_LONGTEXT N_("Password that will be " 
  58.                          "requested to access the stream." )
  59. #define MIME_TEXT N_("Mime")
  60. #define MIME_LONGTEXT N_("MIME returned by the server (autodetected " 
  61.                         "if not specified)." )
  62. #define CERT_TEXT N_( "Certificate file" )
  63. #define CERT_LONGTEXT N_( "Path to the x509 PEM certificate file that will "
  64.                           "be used for HTTPS." )
  65. #define KEY_TEXT N_( "Private key file" )
  66. #define KEY_LONGTEXT N_( "Path to the x509 PEM private key file that will " 
  67.                          "be used for HTTPS. Leave " 
  68.                          "empty if you don't have one." )
  69. #define CA_TEXT N_( "Root CA file" )
  70. #define CA_LONGTEXT N_( "Path to the x509 PEM trusted root CA certificates " 
  71.                         "(certificate authority) file that will be used for " 
  72.                         "HTTPS. Leave empty if you " 
  73.                         "don't have one." )
  74. #define CRL_TEXT N_( "CRL file" )
  75. #define CRL_LONGTEXT N_( "Path to the x509 PEM Certificates Revocation List " 
  76.                          "file that will be used for SSL. Leave " 
  77.                          "empty if you don't have one." )
  78. #define BONJOUR_TEXT N_( "Advertise with Bonjour")
  79. #define BONJOUR_LONGTEXT N_( "Advertise the stream with the Bonjour protocol." )
  80. vlc_module_begin ()
  81.     set_description( N_("HTTP stream output") )
  82.     set_capability( "sout access", 0 )
  83.     set_shortname( "HTTP" )
  84.     add_shortcut( "http" )
  85.     add_shortcut( "https" )
  86.     add_shortcut( "mmsh" )
  87.     set_category( CAT_SOUT )
  88.     set_subcategory( SUBCAT_SOUT_ACO )
  89.     add_string( SOUT_CFG_PREFIX "user", "", NULL,
  90.                 USER_TEXT, USER_LONGTEXT, true )
  91.     add_string( SOUT_CFG_PREFIX "pwd", "", NULL,
  92.                 PASS_TEXT, PASS_LONGTEXT, true )
  93.     add_string( SOUT_CFG_PREFIX "mime", "", NULL,
  94.                 MIME_TEXT, MIME_LONGTEXT, true )
  95.     add_string( SOUT_CFG_PREFIX "cert", "vlc.pem", NULL,
  96.                 CERT_TEXT, CERT_LONGTEXT, true )
  97.     add_string( SOUT_CFG_PREFIX "key", NULL, NULL,
  98.                 KEY_TEXT, KEY_LONGTEXT, true )
  99.     add_string( SOUT_CFG_PREFIX "ca", NULL, NULL,
  100.                 CA_TEXT, CA_LONGTEXT, true )
  101.     add_string( SOUT_CFG_PREFIX "crl", NULL, NULL,
  102.                 CRL_TEXT, CRL_LONGTEXT, true )
  103. #if 0 //def HAVE_AVAHI_CLIENT
  104.     add_bool( SOUT_CFG_PREFIX "bonjour", false, NULL,
  105.               BONJOUR_TEXT, BONJOUR_LONGTEXT, true);
  106. #endif
  107.     set_callbacks( Open, Close )
  108. vlc_module_end ()
  109. /*****************************************************************************
  110.  * Exported prototypes
  111.  *****************************************************************************/
  112. static const char *const ppsz_sout_options[] = {
  113.     "user", "pwd", "mime", "cert", "key", "ca", "crl", NULL
  114. };
  115. static ssize_t Write( sout_access_out_t *, block_t * );
  116. static int Seek ( sout_access_out_t *, off_t  );
  117. static int Control( sout_access_out_t *, int, va_list );
  118. struct sout_access_out_sys_t
  119. {
  120.     /* host */
  121.     httpd_host_t        *p_httpd_host;
  122.     /* stream */
  123.     httpd_stream_t      *p_httpd_stream;
  124.     /* gather header from stream */
  125.     int                 i_header_allocated;
  126.     int                 i_header_size;
  127.     uint8_t             *p_header;
  128.     bool          b_header_complete;
  129. #if 0 //def HAVE_AVAHI_CLIENT
  130.     void                *p_bonjour;
  131. #endif
  132. };
  133. /*****************************************************************************
  134.  * Open: open the file
  135.  *****************************************************************************/
  136. static int Open( vlc_object_t *p_this )
  137. {
  138.     sout_access_out_t       *p_access = (sout_access_out_t*)p_this;
  139.     sout_access_out_sys_t   *p_sys;
  140.     char                *psz_parser;
  141.     char                *psz_bind_addr;
  142.     int                 i_bind_port;
  143.     char                *psz_file_name;
  144.     char                *psz_user = NULL;
  145.     char                *psz_pwd = NULL;
  146.     char                *psz_mime = NULL;
  147.     char                *psz_cert = NULL, *psz_key = NULL, *psz_ca = NULL,
  148.                         *psz_crl = NULL;
  149.     vlc_value_t         val;
  150.     if( !( p_sys = p_access->p_sys =
  151.                 malloc( sizeof( sout_access_out_sys_t ) ) ) )
  152.         return VLC_ENOMEM ;
  153.     config_ChainParse( p_access, SOUT_CFG_PREFIX, ppsz_sout_options, p_access->p_cfg );
  154.     /* p_access->psz_path = "hostname:port/filename" */
  155.     psz_bind_addr = psz_parser = strdup( p_access->psz_path );
  156.     i_bind_port = 0;
  157.     psz_parser = strchr( psz_bind_addr, '/' );
  158.     if( psz_parser )
  159.     {
  160.         psz_file_name = strdup( psz_parser );
  161.         *psz_parser = '';
  162.     }
  163.     else
  164.         psz_file_name = strdup( "/" );
  165.     if( psz_bind_addr[0] == '[' )
  166.     {
  167.         psz_bind_addr++;
  168.         psz_parser = strstr( psz_bind_addr, "]:" );
  169.         if( psz_parser )
  170.         {
  171.             *psz_parser = '';
  172.             i_bind_port = atoi( psz_parser + 2 );
  173.         }
  174.         psz_parser = psz_bind_addr - 1;
  175.     }
  176.     else
  177.     {
  178.         psz_parser = strrchr( psz_bind_addr, ':' );
  179.         if( psz_parser )
  180.         {
  181.             *psz_parser = '';
  182.             i_bind_port = atoi( psz_parser + 1 );
  183.         }
  184.         psz_parser = psz_bind_addr;
  185.     }
  186.     /* SSL support */
  187.     if( p_access->psz_access && !strcmp( p_access->psz_access, "https" ) )
  188.     {
  189.         psz_cert = var_CreateGetNonEmptyString( p_this, SOUT_CFG_PREFIX"cert" );
  190.         psz_key = var_CreateGetNonEmptyString( p_this, SOUT_CFG_PREFIX"key" );
  191.         psz_ca = var_CreateGetNonEmptyString( p_this, SOUT_CFG_PREFIX"ca" );
  192.         psz_crl = var_CreateGetNonEmptyString( p_this, SOUT_CFG_PREFIX"crl" );
  193.         if( i_bind_port <= 0 )
  194.             i_bind_port = DEFAULT_SSL_PORT;
  195.     }
  196.     else
  197.     {
  198.         if( i_bind_port <= 0 )
  199.             i_bind_port = DEFAULT_PORT;
  200.     }
  201.     p_sys->p_httpd_host = httpd_TLSHostNew( VLC_OBJECT(p_access),
  202.                                             psz_bind_addr, i_bind_port,
  203.                                             psz_cert, psz_key, psz_ca,
  204.                                             psz_crl );
  205.     free( psz_cert );
  206.     free( psz_key );
  207.     free( psz_ca );
  208.     free( psz_crl );
  209.     if( p_sys->p_httpd_host == NULL )
  210.     {
  211.         msg_Err( p_access, "cannot listen on %s port %d",
  212.                  psz_bind_addr, i_bind_port );
  213.         free( psz_file_name );
  214.         free( psz_parser );
  215.         free( p_sys );
  216.         return VLC_EGENERIC;
  217.     }
  218.     free( psz_parser );
  219.     if( p_access->psz_access && !strcmp( p_access->psz_access, "mmsh" ) )
  220.     {
  221.         psz_mime = strdup( "video/x-ms-asf-stream" );
  222.     }
  223.     else
  224.     {
  225.         var_Get( p_access, SOUT_CFG_PREFIX "mime", &val );
  226.         if( *val.psz_string )
  227.             psz_mime = val.psz_string;
  228.         else
  229.             free( val.psz_string );
  230.     }
  231.     var_Get( p_access, SOUT_CFG_PREFIX "user", &val );
  232.     if( *val.psz_string )
  233.         psz_user = val.psz_string;
  234.     else
  235.         free( val.psz_string );
  236.     var_Get( p_access, SOUT_CFG_PREFIX "pwd", &val );
  237.     if( *val.psz_string )
  238.         psz_pwd = val.psz_string;
  239.     else
  240.         free( val.psz_string );
  241.     p_sys->p_httpd_stream =
  242.         httpd_StreamNew( p_sys->p_httpd_host, psz_file_name, psz_mime,
  243.                          psz_user, psz_pwd, NULL );
  244.     free( psz_user );
  245.     free( psz_pwd );
  246.     free( psz_mime );
  247.     if( p_sys->p_httpd_stream == NULL )
  248.     {
  249.         msg_Err( p_access, "cannot add stream %s", psz_file_name );
  250.         httpd_HostDelete( p_sys->p_httpd_host );
  251.         free( psz_file_name );
  252.         free( p_sys );
  253.         return VLC_EGENERIC;
  254.     }
  255. #if 0 //def HAVE_AVAHI_CLIENT
  256.     if( config_GetInt(p_this, SOUT_CFG_PREFIX "bonjour") )
  257.     {
  258.         char                *psz_txt, *psz_name;
  259.         playlist_t          *p_playlist = pl_Hold( p_access );
  260.         char *psz_uri = input_item_GetURI( p_playlist->status.p_item->p_input );
  261.         char *psz_newuri = psz_uri;
  262.         psz_name = strrchr( psz_newuri, DIRECTORY_SEPARATOR );
  263.         if( psz_name != NULL ) psz_name++;
  264.         else psz_name = psz_newuri;
  265.         if( psz_file_name &&
  266.             asprintf( &psz_txt, "path=%s", psz_file_name ) == -1 )
  267.             {
  268.                 pl_Release( p_access );
  269.                 free( psz_uri );
  270.                 return VLC_ENOMEM;
  271.             }
  272.         p_sys->p_bonjour = bonjour_start_service( (vlc_object_t *)p_access,
  273.                                     strcmp( p_access->psz_access, "https" )
  274.                                        ? "_vlc-http._tcp" : "_vlc-https._tcp",
  275.                                              psz_name, i_bind_port, psz_txt );
  276.         free( psz_uri );
  277.         free( psz_txt );
  278.         if( p_sys->p_bonjour == NULL )
  279.             msg_Err( p_access, "unable to start requested Bonjour announce" );
  280.         pl_Release( p_access );
  281.     }
  282.     else
  283.         p_sys->p_bonjour = NULL;
  284. #endif
  285.     free( psz_file_name );
  286.     p_sys->i_header_allocated = 1024;
  287.     p_sys->i_header_size      = 0;
  288.     p_sys->p_header           = malloc( p_sys->i_header_allocated );
  289.     p_sys->b_header_complete  = false;
  290.     p_access->pf_write       = Write;
  291.     p_access->pf_seek        = Seek;
  292.     p_access->pf_control     = Control;
  293.     return VLC_SUCCESS;
  294. }
  295. /*****************************************************************************
  296.  * Close: close the target
  297.  *****************************************************************************/
  298. static void Close( vlc_object_t * p_this )
  299. {
  300.     sout_access_out_t       *p_access = (sout_access_out_t*)p_this;
  301.     sout_access_out_sys_t   *p_sys = p_access->p_sys;
  302. #if 0 //def HAVE_AVAHI_CLIENT
  303.     if( p_sys->p_bonjour != NULL )
  304.         bonjour_stop_service( p_sys->p_bonjour );
  305. #endif
  306.     httpd_StreamDelete( p_sys->p_httpd_stream );
  307.     httpd_HostDelete( p_sys->p_httpd_host );
  308.     free( p_sys->p_header );
  309.     msg_Dbg( p_access, "Close" );
  310.     free( p_sys );
  311. }
  312. static int Control( sout_access_out_t *p_access, int i_query, va_list args )
  313. {
  314.     (void)p_access;
  315.     switch( i_query )
  316.     {
  317.         case ACCESS_OUT_CONTROLS_PACE:
  318.             *va_arg( args, bool * ) = false;
  319.             break;
  320.         default:
  321.             return VLC_EGENERIC;
  322.     }
  323.     return VLC_SUCCESS;
  324. }
  325. /*****************************************************************************
  326.  * Write:
  327.  *****************************************************************************/
  328. static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
  329. {
  330.     sout_access_out_sys_t *p_sys = p_access->p_sys;
  331.     int i_err = 0;
  332.     int i_len = 0;
  333.     while( p_buffer )
  334.     {
  335.         block_t *p_next;
  336.         if( p_buffer->i_flags & BLOCK_FLAG_HEADER )
  337.         {
  338.             /* gather header */
  339.             if( p_sys->b_header_complete )
  340.             {
  341.                 /* free previously gathered header */
  342.                 p_sys->i_header_size = 0;
  343.                 p_sys->b_header_complete = false;
  344.             }
  345.             if( (int)(p_buffer->i_buffer + p_sys->i_header_size) >
  346.                 p_sys->i_header_allocated )
  347.             {
  348.                 p_sys->i_header_allocated =
  349.                     p_buffer->i_buffer + p_sys->i_header_size + 1024;
  350.                 p_sys->p_header =
  351.                     realloc( p_sys->p_header, p_sys->i_header_allocated );
  352.             }
  353.             memcpy( &p_sys->p_header[p_sys->i_header_size],
  354.                     p_buffer->p_buffer,
  355.                     p_buffer->i_buffer );
  356.             p_sys->i_header_size += p_buffer->i_buffer;
  357.         }
  358.         else if( !p_sys->b_header_complete )
  359.         {
  360.             p_sys->b_header_complete = true;
  361.             httpd_StreamHeader( p_sys->p_httpd_stream, p_sys->p_header,
  362.                                 p_sys->i_header_size );
  363.         }
  364.         i_len += p_buffer->i_buffer;
  365.         /* send data */
  366.         i_err = httpd_StreamSend( p_sys->p_httpd_stream, p_buffer->p_buffer,
  367.                                   p_buffer->i_buffer );
  368.         p_next = p_buffer->p_next;
  369.         block_Release( p_buffer );
  370.         p_buffer = p_next;
  371.         if( i_err < 0 )
  372.         {
  373.             break;
  374.         }
  375.     }
  376.     if( i_err < 0 )
  377.     {
  378.         block_ChainRelease( p_buffer );
  379.     }
  380.     return( i_err < 0 ? VLC_EGENERIC : i_len );
  381. }
  382. /*****************************************************************************
  383.  * Seek: seek to a specific location in a file
  384.  *****************************************************************************/
  385. static int Seek( sout_access_out_t *p_access, off_t i_pos )
  386. {
  387.     (void)i_pos;
  388.     msg_Warn( p_access, "HTTP sout access cannot seek" );
  389.     return VLC_EGENERIC;
  390. }