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