* modules/access_output/http : http output.
[vlc.git] / modules / access_output / http.c
1 /*****************************************************************************
2  * http.c
3  *****************************************************************************
4  * Copyright (C) 2001-2003 VideoLAN
5  * $Id: http.c,v 1.1 2003/02/23 19:05:22 fenrir Exp $
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 #include <string.h>
29 #include <errno.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/input.h>
33 #include <vlc/sout.h>
34
35 #include "httpd.h"
36
37 #define FREE( p ) if( p ) { free( p); (p) = NULL; }
38
39 #define DEFAULT_PORT 8080
40
41 /*****************************************************************************
42  * Exported prototypes
43  *****************************************************************************/
44 static int     Open   ( vlc_object_t * );
45 static void    Close  ( vlc_object_t * );
46
47 static int     Write( sout_access_out_t *, sout_buffer_t * );
48 static int     Seek ( sout_access_out_t *, off_t  );
49
50 /*****************************************************************************
51  * Module descriptor
52  *****************************************************************************/
53 vlc_module_begin();
54     set_description( _("HTTP stream ouput") );
55     set_capability( "sout access", 0 );
56     add_shortcut( "http" );
57     set_callbacks( Open, Close );
58 vlc_module_end();
59
60 struct sout_access_out_sys_t
61 {
62     httpd_t             *p_httpd;
63
64     /* host */
65     httpd_host_t        *p_httpd_host;
66
67     /* stream */
68     httpd_stream_t      *p_httpd_stream;
69 };
70
71 /*****************************************************************************
72  * Open: open the file
73  *****************************************************************************/
74 static int Open( vlc_object_t *p_this )
75 {
76     sout_access_out_t       *p_access = (sout_access_out_t*)p_this;
77     sout_access_out_sys_t   *p_sys;
78
79     char                *psz_parser, *psz_name;
80
81     char                *psz_bind_addr;
82     int                 i_bind_port;
83     char                *psz_file_name;
84
85     if( !( p_sys = p_access->p_sys =
86                 malloc( sizeof( sout_access_out_sys_t ) ) ) )
87     {
88         msg_Err( p_access, "Not enough memory" );
89         return( VLC_EGENERIC );
90     }
91
92     /* *** parse p_access->psz_name to extract bind address, port and file name *** */
93     /* p_access->psz_name host.name:port/filename */
94     psz_name = psz_parser = strdup( p_access->psz_name );
95
96     psz_bind_addr = psz_parser;
97     i_bind_port = 0;
98     psz_file_name = "";
99
100     while( *psz_parser && *psz_parser != ':' && *psz_parser != '/' )
101     {
102         psz_parser++;
103     }
104     if( *psz_parser == ':' )
105     {
106         *psz_parser = '\0';
107         psz_parser++;
108         i_bind_port = atoi( psz_parser );
109
110         while( *psz_parser && *psz_parser != '/' )
111         {
112             psz_parser++;
113         }
114     }
115     if( *psz_parser == '/' )
116     {
117         *psz_parser = '\0';
118         psz_parser++;
119         psz_file_name = psz_parser;
120     }
121
122     if( i_bind_port <= 0 )
123     {
124         i_bind_port = DEFAULT_PORT;
125     }
126
127     if( !*psz_file_name )
128     {
129         psz_file_name = strdup( "/" );
130     }
131     else if( *psz_file_name != '/' )
132     {
133         char *p = psz_file_name;
134
135         psz_file_name = malloc( strlen( p ) + 2 );
136         strcpy( psz_file_name, "/" );
137         strcat( psz_file_name, p );
138     }
139
140     p_sys->p_httpd = httpd_Find( VLC_OBJECT(p_access), VLC_TRUE );
141     if( !p_sys->p_httpd )
142     {
143         msg_Err( p_access, "cannot start httpd daemon" );
144
145         free( psz_name );
146         free( psz_file_name );
147         free( p_access );
148         return( VLC_EGENERIC );
149     }
150
151     p_sys->p_httpd_host =
152         p_sys->p_httpd->pf_register_host( p_sys->p_httpd,
153                                           psz_bind_addr, i_bind_port );
154
155     if( !p_sys->p_httpd_host )
156     {
157         msg_Err( p_access, "cannot listen on %s:%d", psz_bind_addr, i_bind_port );
158         httpd_Release( p_sys->p_httpd );
159
160         free( psz_name );
161         free( psz_file_name );
162         free( p_access );
163         return( VLC_EGENERIC );
164     }
165
166     p_sys->p_httpd_stream =
167         p_sys->p_httpd->pf_register_stream( p_sys->p_httpd,
168                                             psz_file_name, "application/x-octet_stream",
169                                             NULL, NULL );
170
171     if( !p_sys->p_httpd_stream )
172     {
173         msg_Err( p_access, "cannot add stream %s", psz_file_name );
174         p_sys->p_httpd->pf_unregister_host( p_sys->p_httpd, p_sys->p_httpd_host );
175         httpd_Release( p_sys->p_httpd );
176
177         free( psz_name );
178         free( psz_file_name );
179         free( p_access );
180
181         return( VLC_EGENERIC );
182     }
183
184     p_access->pf_write       = Write;
185     p_access->pf_seek        = Seek;
186
187     return VLC_SUCCESS;
188 }
189
190 /*****************************************************************************
191  * Close: close the target
192  *****************************************************************************/
193 static void Close( vlc_object_t * p_this )
194 {
195     sout_access_out_t       *p_access = (sout_access_out_t*)p_this;
196     sout_access_out_sys_t   *p_sys = p_access->p_sys;
197
198     p_sys->p_httpd->pf_unregister_stream( p_sys->p_httpd, p_sys->p_httpd_stream );
199     p_sys->p_httpd->pf_unregister_host( p_sys->p_httpd, p_sys->p_httpd_host );
200
201     httpd_Release( p_sys->p_httpd );
202
203     msg_Info( p_access, "Close" );
204
205     free( p_sys );
206 }
207
208 /*****************************************************************************
209  * Write:
210  *****************************************************************************/
211 static int Write( sout_access_out_t *p_access, sout_buffer_t *p_buffer )
212 {
213     sout_access_out_sys_t   *p_sys = p_access->p_sys;
214     int i_err = 0;
215
216     while( p_buffer )
217     {
218         sout_buffer_t *p_next;
219
220         i_err = p_sys->p_httpd->pf_send_stream( p_sys->p_httpd, p_sys->p_httpd_stream,
221                                                 p_buffer->p_buffer, p_buffer->i_size );
222
223         p_next = p_buffer->p_next;
224         sout_BufferDelete( p_access->p_sout, p_buffer );
225         p_buffer = p_next;
226
227         if( i_err < 0 )
228         {
229             break;
230         }
231     }
232     if( i_err < 0 )
233     {
234         sout_buffer_t *p_next;
235         while( p_buffer )
236         {
237             p_next = p_buffer->p_next;
238             sout_BufferDelete( p_access->p_sout, p_buffer );
239             p_buffer = p_next;
240         }
241     }
242
243     return( i_err < 0 ? VLC_EGENERIC : VLC_SUCCESS );
244 }
245
246 /*****************************************************************************
247  * Seek: seek to a specific location in a file
248  *****************************************************************************/
249 static int Seek( sout_access_out_t *p_access, off_t i_pos )
250 {
251     msg_Err( p_access, "http sout access cannot seek" );
252     return( VLC_EGENERIC );
253 }
254