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