equalizer.c: compile fix for old compilers (thx sam)
[vlc.git] / modules / access_output / http.c
1 /*****************************************************************************
2  * http.c
3  *****************************************************************************
4  * Copyright (C) 2001-2003 VideoLAN
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28
29 #include <vlc/vlc.h>
30 #include <vlc/sout.h>
31
32 #include "vlc_httpd.h"
33
34 #define FREE( p ) if( p ) { free( p); (p) = NULL; }
35
36 #define DEFAULT_PORT 8080
37
38 /*****************************************************************************
39  * Module descriptor
40  *****************************************************************************/
41 static int  Open ( vlc_object_t * );
42 static void Close( vlc_object_t * );
43
44 #define SOUT_CFG_PREFIX "sout-http-"
45
46 #define USER_TEXT N_("Username")
47 #define USER_LONGTEXT N_("Allows you to give a user name that will be " \
48                          "requested to access the stream." )
49 #define PASS_TEXT N_("Password")
50 #define PASS_LONGTEXT N_("Allows you to give a password that will be " \
51                          "requested to access the stream." )
52 #define MIME_TEXT N_("Mime")
53 #define MIME_LONGTEXT N_("Allows you to give the mime returned by the server." )
54
55 vlc_module_begin();
56     set_description( _("HTTP stream output") );
57     set_capability( "sout access", 0 );
58     add_shortcut( "http" );
59     add_shortcut( "mmsh" );
60     add_string( SOUT_CFG_PREFIX "user", "", NULL, USER_TEXT, USER_LONGTEXT, VLC_TRUE );
61     add_string( SOUT_CFG_PREFIX "pwd", "", NULL, PASS_TEXT, PASS_LONGTEXT, VLC_TRUE );
62     add_string( SOUT_CFG_PREFIX "mime", "", NULL, MIME_TEXT, MIME_LONGTEXT, VLC_TRUE );
63     set_callbacks( Open, Close );
64 vlc_module_end();
65
66
67 /*****************************************************************************
68  * Exported prototypes
69  *****************************************************************************/
70 static const char *ppsz_sout_options[] = {
71     "user", "pwd", "mime", NULL
72 };
73
74 static int Write( sout_access_out_t *, block_t * );
75 static int Seek ( sout_access_out_t *, off_t  );
76
77 struct sout_access_out_sys_t
78 {
79     /* host */
80     httpd_host_t        *p_httpd_host;
81
82     /* stream */
83     httpd_stream_t      *p_httpd_stream;
84
85     /* gather header from stream */
86     int                 i_header_allocated;
87     int                 i_header_size;
88     uint8_t             *p_header;
89     vlc_bool_t          b_header_complete;
90 };
91
92 /*****************************************************************************
93  * Open: open the file
94  *****************************************************************************/
95 static int Open( vlc_object_t *p_this )
96 {
97     sout_access_out_t       *p_access = (sout_access_out_t*)p_this;
98     sout_access_out_sys_t   *p_sys;
99
100     char                *psz_parser, *psz_name;
101
102     char                *psz_bind_addr;
103     int                 i_bind_port;
104     char                *psz_file_name;
105     char                *psz_user = NULL;
106     char                *psz_pwd = NULL;
107     char                *psz_mime = NULL;
108     vlc_value_t         val;
109
110     if( !( p_sys = p_access->p_sys =
111                 malloc( sizeof( sout_access_out_sys_t ) ) ) )
112     {
113         msg_Err( p_access, "Not enough memory" );
114         return( VLC_EGENERIC );
115     }
116
117     sout_CfgParse( p_access, SOUT_CFG_PREFIX, ppsz_sout_options, p_access->p_cfg );
118
119     /* p_access->psz_name host.name:port/filename */
120     psz_name = psz_parser = strdup( p_access->psz_name );
121
122     psz_bind_addr = psz_parser;
123     i_bind_port = 0;
124     psz_file_name = "";
125
126     while( *psz_parser && *psz_parser != ':' && *psz_parser != '/' )
127     {
128         psz_parser++;
129     }
130     if( *psz_parser == ':' )
131     {
132         *psz_parser = '\0';
133         psz_parser++;
134         i_bind_port = atoi( psz_parser );
135
136         while( *psz_parser && *psz_parser != '/' )
137         {
138             psz_parser++;
139         }
140     }
141     if( *psz_parser == '/' )
142     {
143         *psz_parser = '\0';
144         psz_parser++;
145         psz_file_name = psz_parser;
146     }
147
148     if( i_bind_port <= 0 )
149     {
150         i_bind_port = DEFAULT_PORT;
151     }
152
153     if( !*psz_file_name )
154     {
155         psz_file_name = strdup( "/" );
156     }
157     else if( *psz_file_name != '/' )
158     {
159         char *p = psz_file_name;
160
161         psz_file_name = malloc( strlen( p ) + 2 );
162         strcpy( psz_file_name, "/" );
163         strcat( psz_file_name, p );
164     }
165     else
166     {
167         psz_file_name = strdup( psz_file_name );
168     }
169
170     p_sys->p_httpd_host = httpd_HostNew( VLC_OBJECT(p_access), psz_bind_addr,
171                                          i_bind_port );
172     if( p_sys->p_httpd_host == NULL )
173     {
174         msg_Err( p_access, "cannot listen on %s:%d",
175                  psz_bind_addr, i_bind_port );
176
177         free( psz_name );
178         free( psz_file_name );
179         free( p_sys );
180         return VLC_EGENERIC;
181     }
182
183     if( p_access->psz_access && !strcmp( p_access->psz_access, "mmsh" ) )
184     {
185         psz_mime = strdup( "video/x-ms-asf-stream" );
186     }
187     else
188     {
189         var_Get( p_access, SOUT_CFG_PREFIX "mime", &val );
190         if( *val.psz_string )
191             psz_mime = val.psz_string;
192         else
193             free( val.psz_string );
194     }
195
196     var_Get( p_access, SOUT_CFG_PREFIX "user", &val );
197     if( *val.psz_string )
198         psz_user = val.psz_string;
199     else
200         free( val.psz_string );
201
202     var_Get( p_access, SOUT_CFG_PREFIX "pwd", &val );
203     if( *val.psz_string )
204         psz_pwd = val.psz_string;
205     else
206         free( val.psz_string );
207
208     p_sys->p_httpd_stream =
209         httpd_StreamNew( p_sys->p_httpd_host, psz_file_name, psz_mime,
210                          psz_user, psz_pwd );
211     if( psz_user ) free( psz_user );
212     if( psz_pwd ) free( psz_pwd );
213     if( psz_mime ) free( psz_mime );
214
215     if( p_sys->p_httpd_stream == NULL )
216     {
217         msg_Err( p_access, "cannot add stream %s", psz_file_name );
218         httpd_HostDelete( p_sys->p_httpd_host );
219
220         free( psz_name );
221         free( psz_file_name );
222         free( p_sys );
223         return VLC_EGENERIC;
224     }
225
226     free( psz_file_name );
227     free( psz_name );
228
229     p_sys->i_header_allocated = 1024;
230     p_sys->i_header_size      = 0;
231     p_sys->p_header           = malloc( p_sys->i_header_allocated );
232     p_sys->b_header_complete  = VLC_FALSE;
233
234     p_access->pf_write       = Write;
235     p_access->pf_seek        = Seek;
236
237
238     /* update p_sout->i_out_pace_nocontrol */
239     p_access->p_sout->i_out_pace_nocontrol++;
240
241     return VLC_SUCCESS;
242 }
243
244 /*****************************************************************************
245  * Close: close the target
246  *****************************************************************************/
247 static void Close( vlc_object_t * p_this )
248 {
249     sout_access_out_t       *p_access = (sout_access_out_t*)p_this;
250     sout_access_out_sys_t   *p_sys = p_access->p_sys;
251
252     /* update p_sout->i_out_pace_nocontrol */
253     p_access->p_sout->i_out_pace_nocontrol--;
254
255     httpd_StreamDelete( p_sys->p_httpd_stream );
256     httpd_HostDelete( p_sys->p_httpd_host );
257
258     FREE( p_sys->p_header );
259
260     msg_Dbg( p_access, "Close" );
261
262     free( p_sys );
263 }
264
265 /*****************************************************************************
266  * Write:
267  *****************************************************************************/
268 static int Write( sout_access_out_t *p_access, block_t *p_buffer )
269 {
270     sout_access_out_sys_t *p_sys = p_access->p_sys;
271     int i_err = 0;
272
273     while( p_buffer )
274     {
275         block_t *p_next;
276
277         if( p_buffer->i_flags & BLOCK_FLAG_HEADER )
278         {
279             /* gather header */
280             if( p_sys->b_header_complete )
281             {
282                 /* free previously gathered header */
283                 p_sys->i_header_size = 0;
284                 p_sys->b_header_complete = VLC_FALSE;
285             }
286             if( (int)(p_buffer->i_buffer + p_sys->i_header_size) >
287                 p_sys->i_header_allocated )
288             {
289                 p_sys->i_header_allocated =
290                     p_buffer->i_buffer + p_sys->i_header_size + 1024;
291                 p_sys->p_header =
292                     realloc( p_sys->p_header, p_sys->i_header_allocated );
293             }
294             memcpy( &p_sys->p_header[p_sys->i_header_size],
295                     p_buffer->p_buffer,
296                     p_buffer->i_buffer );
297             p_sys->i_header_size += p_buffer->i_buffer;
298         }
299         else if( !p_sys->b_header_complete )
300         {
301             p_sys->b_header_complete = VLC_TRUE;
302
303             httpd_StreamHeader( p_sys->p_httpd_stream, p_sys->p_header,
304                                 p_sys->i_header_size );
305         }
306
307         /* send data */
308         i_err = httpd_StreamSend( p_sys->p_httpd_stream, p_buffer->p_buffer,
309                                   p_buffer->i_buffer );
310
311         p_next = p_buffer->p_next;
312         block_Release( p_buffer );
313         p_buffer = p_next;
314
315         if( i_err < 0 )
316         {
317             break;
318         }
319     }
320
321     if( i_err < 0 )
322     {
323         block_ChainRelease( p_buffer );
324     }
325
326     return( i_err < 0 ? VLC_EGENERIC : VLC_SUCCESS );
327 }
328
329 /*****************************************************************************
330  * Seek: seek to a specific location in a file
331  *****************************************************************************/
332 static int Seek( sout_access_out_t *p_access, off_t i_pos )
333 {
334     msg_Warn( p_access, "HTTP sout access cannot seek" );
335     return VLC_EGENERIC;
336 }