Added DVB scan capability.
[vlc.git] / modules / access / dvb / http.c
1 /*****************************************************************************
2  * http.c: HTTP interface
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  *
6  * Authors: Christophe Massiot <massiot@via.ecp.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_access.h>
33
34 #ifdef HAVE_UNISTD_H
35 #   include <unistd.h>
36 #endif
37
38 #include <fcntl.h>
39 #include <sys/types.h>
40
41 #include <errno.h>
42
43 /* Include dvbpsi headers */
44 #ifdef HAVE_DVBPSI_DR_H
45 #   include <dvbpsi/dvbpsi.h>
46 #   include <dvbpsi/descriptor.h>
47 #   include <dvbpsi/pat.h>
48 #   include <dvbpsi/pmt.h>
49 #   include <dvbpsi/dr.h>
50 #   include <dvbpsi/psi.h>
51 #   include <dvbpsi/demux.h>
52 #   include <dvbpsi/sdt.h>
53 #   include <dvbpsi/nit.h>
54 #else
55 #   include "dvbpsi.h"
56 #   include "descriptor.h"
57 #   include "tables/pat.h"
58 #   include "tables/pmt.h"
59 #   include "descriptors/dr.h"
60 #   include "psi.h"
61 #   include "demux.h"
62 #   include "sdt.h"
63 #   include "nit.h"
64 #endif
65
66 #ifdef ENABLE_HTTPD
67 #   include "vlc_httpd.h"
68 #   include "vlc_acl.h"
69 #endif
70
71 #include "dvb.h"
72
73 #ifdef ENABLE_HTTPD
74 struct httpd_file_sys_t
75 {
76     access_t         *p_access;
77     httpd_file_t     *p_file;
78 };
79
80 static int HttpCallback( httpd_file_sys_t *p_args,
81                          httpd_file_t *p_file,
82                          uint8_t *_p_request,
83                          uint8_t **_pp_data, int *pi_data );
84
85 /*****************************************************************************
86  * HTTPOpen: Start the internal HTTP server
87  *****************************************************************************/
88 int HTTPOpen( access_t *p_access )
89 {
90     access_sys_t *p_sys = p_access->p_sys;
91     char          *psz_address, *psz_cert = NULL, *psz_key = NULL,
92                   *psz_ca = NULL, *psz_crl = NULL, *psz_user = NULL,
93                   *psz_password = NULL, *psz_acl = NULL;
94     int           i_port       = 0;
95     char          psz_tmp[10];
96     vlc_acl_t     *p_acl = NULL;
97     httpd_file_sys_t *f;
98
99     vlc_mutex_init( &p_sys->httpd_mutex );
100     vlc_cond_init( p_access, &p_sys->httpd_cond );
101     p_sys->b_request_frontend_info = p_sys->b_request_mmi_info = false;
102     p_sys->i_httpd_timeout = 0;
103
104     psz_address = var_GetNonEmptyString( p_access, "dvb-http-host" );
105     if( psz_address != NULL )
106     {
107         char *psz_parser = strchr( psz_address, ':' );
108         if( psz_parser )
109         {
110             *psz_parser++ = '\0';
111             i_port = atoi( psz_parser );
112         }
113     }
114     else
115         return VLC_SUCCESS;
116
117     /* determine SSL configuration */
118     psz_cert = var_GetNonEmptyString( p_access, "dvb-http-intf-cert" );
119     if ( psz_cert != NULL )
120     {
121         msg_Dbg( p_access, "enabling TLS for HTTP interface (cert file: %s)",
122                  psz_cert );
123         psz_key = config_GetPsz( p_access, "dvb-http-intf-key" );
124         psz_ca = config_GetPsz( p_access, "dvb-http-intf-ca" );
125         psz_crl = config_GetPsz( p_access, "dvb-http-intf-crl" );
126
127         if ( i_port <= 0 )
128             i_port = 8443;
129     }
130     else
131     {
132         if ( i_port <= 0 )
133             i_port= 8082;
134     }
135
136     /* Ugly hack to allow to run several HTTP servers on different ports. */
137     sprintf( psz_tmp, ":%d", i_port + 1 );
138     config_PutPsz( p_access, "dvb-http-host", psz_tmp );
139
140     msg_Dbg( p_access, "base %s:%d", psz_address, i_port );
141
142     p_sys->p_httpd_host = httpd_TLSHostNew( VLC_OBJECT(p_access), psz_address,
143                                             i_port, psz_cert, psz_key, psz_ca,
144                                             psz_crl );
145     free( psz_cert );
146     free( psz_key );
147     free( psz_ca );
148     free( psz_crl );
149
150     if ( p_sys->p_httpd_host == NULL )
151     {
152         msg_Err( p_access, "cannot listen on %s:%d", psz_address, i_port );
153         free( psz_address );
154         return VLC_EGENERIC;
155     }
156     free( psz_address );
157
158     psz_user = var_GetNonEmptyString( p_access, "dvb-http-user" );
159     psz_password = var_GetNonEmptyString( p_access, "dvb-http-password" );
160     psz_acl = var_GetNonEmptyString( p_access, "dvb-http-acl" );
161
162     if ( psz_acl != NULL )
163     {
164         p_acl = ACL_Create( p_access, false );
165         if( ACL_LoadFile( p_acl, psz_acl ) )
166         {
167             ACL_Destroy( p_acl );
168             p_acl = NULL;
169         }
170     }
171
172     /* Declare an index.html file. */
173     f = malloc( sizeof(httpd_file_sys_t) );
174     f->p_access = p_access;
175     f->p_file = httpd_FileNew( p_sys->p_httpd_host, "/index.html",
176                                "text/html; charset=UTF-8",
177                                psz_user, psz_password, p_acl,
178                                HttpCallback, f );
179
180     free( psz_user );
181     free( psz_password );
182     free( psz_acl );
183     if ( p_acl != NULL )
184         ACL_Destroy( p_acl );
185
186     if ( f->p_file == NULL )
187     {
188         free( f );
189         p_sys->p_httpd_file = NULL;
190         return VLC_EGENERIC;
191     }
192
193     p_sys->p_httpd_file = f;
194     p_sys->p_httpd_redir = httpd_RedirectNew( p_sys->p_httpd_host,
195                                               "/index.html", "/" );
196
197     return VLC_SUCCESS;
198 }
199
200 /*****************************************************************************
201  * HTTPClose: Stop the internal HTTP server
202  *****************************************************************************/
203 void HTTPClose( access_t *p_access )
204 {
205     access_sys_t *p_sys = p_access->p_sys;
206
207     if ( p_sys->p_httpd_host != NULL )
208     {
209         if ( p_sys->p_httpd_file != NULL )
210         {
211             /* Unlock the thread if it is stuck in HttpCallback */
212             vlc_mutex_lock( &p_sys->httpd_mutex );
213             if ( p_sys->b_request_frontend_info == true )
214             {
215                 p_sys->b_request_frontend_info = false;
216                 p_sys->psz_frontend_info = strdup("");
217             }
218             if ( p_sys->b_request_mmi_info == true )
219             {
220                 p_sys->b_request_mmi_info = false;
221                 p_sys->psz_mmi_info = strdup("");
222             }
223             vlc_cond_signal( &p_sys->httpd_cond );
224             vlc_mutex_unlock( &p_sys->httpd_mutex );
225
226             httpd_FileDelete( p_sys->p_httpd_file->p_file );
227             httpd_RedirectDelete( p_sys->p_httpd_redir );
228         }
229
230         httpd_HostDelete( p_sys->p_httpd_host );
231     }
232
233     vlc_mutex_destroy( &p_sys->httpd_mutex );
234     vlc_cond_destroy( &p_sys->httpd_cond );
235 }
236
237
238 static const char *psz_constant_header =
239     "<html>\n"
240     "<head><title>VLC DVB monitoring interface</title></head>\n"
241     "<body><a href=\"index.html\">Reload this page</a>\n"
242     "<h1>CAM info</h1>\n";
243
244 static const char *psz_constant_middle =
245     "<hr><h1>Frontend Info</h1>\n";
246
247 static const char *psz_constant_footer =
248     "</body></html>\n";
249
250 /****************************************************************************
251  * HttpCallback: Return the index.html file
252  ****************************************************************************/
253 static int HttpCallback( httpd_file_sys_t *p_args,
254                          httpd_file_t *p_file,
255                          uint8_t *_psz_request,
256                          uint8_t **_pp_data, int *pi_data )
257 {
258     access_sys_t *p_sys = p_args->p_access->p_sys;
259     char *psz_request = (char *)_psz_request;
260     char **pp_data = (char **)_pp_data;
261
262     vlc_mutex_lock( &p_sys->httpd_mutex );
263
264     p_sys->i_httpd_timeout = mdate() + INT64_C(3000000); /* 3 s */
265     p_sys->psz_request = psz_request;
266     p_sys->b_request_frontend_info = true;
267     if ( p_sys->i_ca_handle )
268     {
269         p_sys->b_request_mmi_info = true;
270     }
271     else
272     {
273         p_sys->psz_mmi_info = strdup( "No available CAM interface\n" );
274     }
275
276     do
277     {
278         vlc_cond_wait( &p_sys->httpd_cond, &p_sys->httpd_mutex );
279     }
280     while ( p_sys->b_request_frontend_info || p_sys->b_request_mmi_info );
281
282     p_sys->i_httpd_timeout = 0;
283     vlc_mutex_unlock( &p_sys->httpd_mutex );
284
285     *pi_data = strlen( psz_constant_header )
286                 + strlen( p_sys->psz_mmi_info )
287                 + strlen( psz_constant_middle )
288                 + strlen( p_sys->psz_frontend_info )
289                 + strlen( psz_constant_footer ) + 1;
290     *pp_data = malloc( *pi_data );
291
292     sprintf( *pp_data, "%s%s%s%s%s", psz_constant_header,
293              p_sys->psz_mmi_info, psz_constant_middle,
294              p_sys->psz_frontend_info, psz_constant_footer );
295     free( p_sys->psz_frontend_info );
296     free( p_sys->psz_mmi_info );
297
298     return VLC_SUCCESS;
299 }
300
301 /****************************************************************************
302  * HTTPExtractValue: Extract a GET variable from psz_request
303  ****************************************************************************/
304 char *HTTPExtractValue( char *psz_uri, const char *psz_name,
305                             char *psz_value, int i_value_max )
306 {
307     char *p = psz_uri;
308
309     while( (p = strstr( p, psz_name )) )
310     {
311         /* Verify that we are dealing with a post/get argument */
312         if( (p == psz_uri || *(p - 1) == '&' || *(p - 1) == '\n')
313               && p[strlen(psz_name)] == '=' )
314             break;
315         p++;
316     }
317
318     if( p )
319     {
320         int i_len;
321
322         p += strlen( psz_name );
323         if( *p == '=' ) p++;
324
325         if( strchr( p, '&' ) )
326         {
327             i_len = strchr( p, '&' ) - p;
328         }
329         else
330         {
331             /* for POST method */
332             if( strchr( p, '\n' ) )
333             {
334                 i_len = strchr( p, '\n' ) - p;
335                 if( i_len && *(p+i_len-1) == '\r' ) i_len--;
336             }
337             else
338             {
339                 i_len = strlen( p );
340             }
341         }
342         i_len = __MIN( i_value_max - 1, i_len );
343         if( i_len > 0 )
344         {
345             strncpy( psz_value, p, i_len );
346             psz_value[i_len] = '\0';
347         }
348         else
349         {
350             strncpy( psz_value, "", i_value_max );
351         }
352         p += i_len;
353     }
354     else
355     {
356         strncpy( psz_value, "", i_value_max );
357     }
358
359     return p;
360 }
361
362 #endif /* ENABLE_HTTPD */