* modules/access_output/http : http output.
[vlc.git] / modules / misc / httpd.c
1 /*****************************************************************************
2  * httpd.c
3  *****************************************************************************
4  * Copyright (C) 2001-2003 VideoLAN
5  * $Id: httpd.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 <sys/types.h>
29 #include <sys/stat.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <fcntl.h>
33
34 #include <vlc/vlc.h>
35 #include "httpd.h"
36
37 #ifdef HAVE_UNISTD_H
38 #   include <unistd.h>
39 #elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE )
40 #   include <io.h>
41 #endif
42
43 #if defined( UNDER_CE )
44 #   include <winsock.h>
45 #elif defined( WIN32 )
46 #   include <winsock2.h>
47 #   include <ws2tcpip.h>
48 #   ifndef IN_MULTICAST
49 #       define IN_MULTICAST(a) IN_CLASSD(a)
50 #   endif
51 #else
52 #   include <netdb.h>                                         /* hostent ... */
53 #   include <sys/socket.h>
54 #   include <netinet/in.h>
55 #   ifdef HAVE_ARPA_INET_H
56 #       include <arpa/inet.h>                    /* inet_ntoa(), inet_aton() */
57 #   endif
58 #endif
59
60 #include "network.h"
61
62 #ifndef INADDR_ANY
63 #   define INADDR_ANY  0x00000000
64 #endif
65 #ifndef INADDR_NONE
66 #   define INADDR_NONE 0xFFFFFFFF
67 #endif
68
69 #define LISTEN_BACKLOG  100
70 #define HTTPD_MAX_CONNECTION    1024
71
72
73 #define FREE( p ) if( p ) { free( p); (p) = NULL; }
74
75 #if defined( WIN32 ) || defined( UNDER_CE )
76 #define SOCKET_CLOSE    closesocket;
77 #else
78 #define SOCKET_CLOSE    close
79 #endif
80
81 /*****************************************************************************
82  * Exported prototypes
83  *****************************************************************************/
84 static int              Open   ( vlc_object_t * );
85 static void             Close  ( vlc_object_t * );
86
87 /*****************************************************************************
88  * Module descriptor
89  *****************************************************************************/
90 vlc_module_begin();
91     set_description( _("HTTP 1.0 daemon") );
92     set_capability( "httpd", 42 );
93     set_callbacks( Open, Close );
94 vlc_module_end();
95
96 /*****************************************************************************
97  * Prototypes
98  *****************************************************************************/
99 static httpd_host_t     *RegisterHost( httpd_t *, char *, int );
100 static void             UnregisterHost( httpd_t *, httpd_host_t * );
101
102 static httpd_file_t     *RegisterFile( httpd_t *,
103                                        char *psz_file, char *psz_mime,
104                                        char *psz_user, char *psz_password,
105                                        httpd_file_callback pf_fill,
106                                        httpd_file_callback_args_t *p_args );
107 static void             UnregisterFile( httpd_t *, httpd_file_t * );
108
109 //#define httpd_stream_t              httpd_file_t
110 static httpd_stream_t   *RegisterStream( httpd_t *,
111                                          char *psz_file, char *psz_mime,
112                                          char *psz_user, char *psz_password );
113 static int              SendStream( httpd_t *, httpd_stream_t *, uint8_t *, int );
114 static void             UnregisterStream( httpd_t *, httpd_stream_t* );
115
116 /*****************************************************************************
117  * Internal definitions
118  *****************************************************************************/
119 struct httpd_host_t
120 {
121     int    i_ref;
122
123     char   *psz_host_addr;
124     int    i_port;
125
126     struct sockaddr_in sock;
127     int    fd;
128
129 };
130
131 #define HTTPD_AUTHENTICATE_NONE     0
132 #define HTTPD_AUTHENTICATE_BASIC    1
133
134 //typedef httpd_file_t httpd_stream_t;
135
136 struct httpd_file_t
137 {
138     int         i_ref;
139
140     char        *psz_file;
141     char        *psz_mime;
142
143
144     int         i_authenticate_method;
145         char        *psz_user;          /* NULL if no auth */
146         char        *psz_password;      /* NULL if no auth */
147
148     vlc_bool_t  b_stream;               /* if false: httpd will retreive data by a callback
149                                               true:  it's up to the program to give data to httpd */
150     void                *p_sys;         /* provided for user */
151     httpd_file_callback pf_fill;       /* it should allocate and fill *pp_data and *pi_data */
152
153     /* private */
154     int         i_buffer_size;  /* buffer size */
155     uint8_t     *p_buffer;      /* buffer */
156     int         i_buffer;       /* reading pointer */
157     int         i_buffer_valid; /* valid data from 0 */
158
159 };
160
161
162 #define HTTPD_CONNECTION_RECEIVING_REQUEST      1
163 #define HTTPD_CONNECTION_SENDING_HEADER         2
164 #define HTTPD_CONNECTION_SENDING_FILE           3
165 #define HTTPD_CONNECTION_SENDING_STREAM         4
166
167 typedef struct httpd_connection_s
168 {
169     struct httpd_connection_s *p_next;
170     struct httpd_connection_s *p_prev;
171
172     struct sockaddr_in sock;
173     int    fd;
174
175     int    i_state;
176
177     char    *psz_file;      // file to be send
178     int     i_http_error;   // error to be send with the file
179     char    *psz_user;      // if Authorization in the request header
180     char    *psz_password;
181
182     httpd_file_t    *p_file;
183
184     int     i_buffer_size;
185     uint8_t *p_buffer;
186     int     i_buffer;                   /* private */
187 } httpd_connection_t;
188
189 /*
190  * The httpd thread
191  */
192 struct httpd_sys_t
193 {
194     VLC_COMMON_MEMBERS
195
196     vlc_mutex_t             host_lock;
197     volatile int            i_host_count;
198     httpd_host_t            **host;
199
200     vlc_mutex_t             file_lock;
201     int                     i_file_count;
202     httpd_file_t            **file;
203
204     vlc_mutex_t             connection_lock;
205     int                     i_connection_count;
206     httpd_connection_t      *p_first_connection;
207 };
208
209 static void httpd_Thread( httpd_sys_t *p_httpt );
210 static void httpd_ConnnectionNew( httpd_sys_t *, int , struct sockaddr_in * );
211 static void httpd_ConnnectionClose( httpd_sys_t *, httpd_connection_t * );
212
213 /*****************************************************************************
214  * Open:
215  *****************************************************************************/
216
217 static int Open( vlc_object_t *p_this )
218 {
219     httpd_t     *p_httpd = (httpd_t*)p_this;
220     httpd_sys_t *p_httpt;
221
222     /* Launch httpt thread */
223     if( !( p_httpt = vlc_object_create( p_this, sizeof( httpd_sys_t ) ) ) )
224     {
225         msg_Err( p_this, "out of memory" );
226         return( VLC_EGENERIC );
227     }
228
229     p_httpt->b_die  = 0;
230     p_httpt->b_error= 0;
231
232     /* init httpt_t structure */
233     vlc_mutex_init( p_httpd, &p_httpt->host_lock );
234     p_httpt->i_host_count = 0;
235     p_httpt->host = NULL;
236
237     vlc_mutex_init( p_httpd, &p_httpt->file_lock );
238     p_httpt->i_file_count = 0;
239     p_httpt->file = NULL;
240
241     vlc_mutex_init( p_httpd, &p_httpt->connection_lock );
242     p_httpt->i_connection_count = 0;
243     p_httpt->p_first_connection = NULL;
244
245     /* start the thread */
246     if( vlc_thread_create( p_httpt, "httpd thread",
247                            httpd_Thread, VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
248     {
249         msg_Err( p_this, "cannot spawn http thread" );
250
251         vlc_mutex_destroy( &p_httpt->host_lock );
252         vlc_mutex_destroy( &p_httpt->file_lock );
253         vlc_mutex_destroy( &p_httpt->connection_lock );
254
255         vlc_object_destroy( p_httpt );
256         return( VLC_EGENERIC );
257     }
258
259     msg_Info( p_httpd, "http thread launched" );
260
261     p_httpd->p_sys = p_httpt;
262     p_httpd->pf_register_host   = RegisterHost;
263     p_httpd->pf_unregister_host = UnregisterHost;
264     p_httpd->pf_register_file   = RegisterFile;
265     p_httpd->pf_unregister_file = UnregisterFile;
266     p_httpd->pf_register_stream = RegisterStream;
267     p_httpd->pf_send_stream     = SendStream;
268     p_httpd->pf_unregister_stream=UnregisterStream;
269
270     return( VLC_SUCCESS );
271 }
272
273 /*****************************************************************************
274  * Close: close the target
275  *****************************************************************************/
276 static void Close( vlc_object_t * p_this )
277 {
278     httpd_t     *p_httpd = (httpd_t*)p_this;
279     httpd_sys_t *p_httpt = p_httpd->p_sys;
280
281     httpd_connection_t *p_con;
282     int i;
283
284     p_httpt->b_die = 1;
285     vlc_thread_join( p_httpt );
286
287     /* first close all host */
288     vlc_mutex_destroy( &p_httpt->host_lock );
289     if( p_httpt->i_host_count )
290     {
291         msg_Err( p_httpd, "still have %d hosts registered !", p_httpt->i_host_count );
292     }
293     for( i = 0; i < p_httpt->i_host_count; i++ )
294     {
295 #define p_host p_httpt->host[i]
296         FREE( p_host->psz_host_addr );
297         SOCKET_CLOSE( p_host->fd );
298
299         FREE( p_host );
300 #undef p_host
301     }
302     FREE( p_httpt->host );
303
304     /* now all file */
305     vlc_mutex_destroy( &p_httpt->file_lock );
306     if( p_httpt->i_file_count )
307     {
308         msg_Err( p_httpd, "still have %d files registered !", p_httpt->i_file_count );
309     }
310     for( i = 0; i < p_httpt->i_file_count; i++ )
311     {
312 #define p_file p_httpt->file[i]
313         FREE( p_file->psz_file );
314         FREE( p_file->psz_mime );
315         if( p_file->i_authenticate_method != HTTPD_AUTHENTICATE_NONE )
316         {
317             FREE( p_file->psz_user );
318             FREE( p_file->psz_password );
319         }
320         FREE( p_file->p_buffer );
321
322         FREE( p_file );
323 #undef p_file
324     }
325     FREE( p_httpt->file );
326
327     /* andd close all connection */
328     vlc_mutex_destroy( &p_httpt->connection_lock );
329     if( p_httpt->i_connection_count )
330     {
331         msg_Warn( p_httpd, "%d connections still in use", p_httpt->i_connection_count );
332     }
333     while( ( p_con = p_httpt->p_first_connection ) )
334     {
335         httpd_ConnnectionClose( p_httpt, p_con );
336     }
337
338     msg_Info( p_httpd, "httpd instance closed" );
339     vlc_object_destroy( p_httpt );
340 }
341
342
343 /****************************************************************************
344  ****************************************************************************
345  ***
346  ***
347  ****************************************************************************
348  ****************************************************************************/
349 static int BuildAddr( struct sockaddr_in * p_socket,
350                       const char * psz_address, int i_port )
351 {
352     /* Reset struct */
353     memset( p_socket, 0, sizeof( struct sockaddr_in ) );
354     p_socket->sin_family = AF_INET;                                /* family */
355     p_socket->sin_port = htons( (uint16_t)i_port );
356     if( !*psz_address )
357     {
358         p_socket->sin_addr.s_addr = INADDR_ANY;
359     }
360     else
361     {
362         struct hostent    * p_hostent;
363
364         /* Try to convert address directly from in_addr - this will work if
365          * psz_address is dotted decimal. */
366 #ifdef HAVE_ARPA_INET_H
367         if( !inet_aton( psz_address, &p_socket->sin_addr ) )
368 #else
369         p_socket->sin_addr.s_addr = inet_addr( psz_address );
370         if( p_socket->sin_addr.s_addr == INADDR_NONE )
371 #endif
372         {
373             /* We have a fqdn, try to find its address */
374             if ( (p_hostent = gethostbyname( psz_address )) == NULL )
375             {
376                 return( -1 );
377             }
378
379             /* Copy the first address of the host in the socket address */
380             memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0],
381                      p_hostent->h_length );
382         }
383     }
384     return( 0 );
385 }
386
387
388 /*
389  * listen on a host for a httpd instance
390  */
391
392 static httpd_host_t     *_RegisterHost( httpd_sys_t *p_httpt, char *psz_host_addr, int i_port )
393 {
394     httpd_host_t    *p_host;
395     struct sockaddr_in  sock;
396     int i;
397     int fd = -1;
398     int i_opt;
399     int i_flags;
400
401     if( BuildAddr( &sock, psz_host_addr, i_port ) )
402     {
403         msg_Err( p_httpt, "cannot build address for %s:%d", psz_host_addr, i_port );
404         return NULL;
405     }
406
407     /* is it already declared ? */
408     vlc_mutex_lock( &p_httpt->host_lock );
409     for( i = 0; i < p_httpt->i_host_count; i++ )
410     {
411         if( p_httpt->host[i]->sock.sin_port == sock.sin_port &&
412             p_httpt->host[i]->sock.sin_addr.s_addr == sock.sin_addr.s_addr )
413         {
414             break;
415         }
416     }
417
418     if( i < p_httpt->i_host_count )
419     {
420         /* yes, increment ref count and succed */
421         p_httpt->host[i]->i_ref++;
422         vlc_mutex_unlock( &p_httpt->host_lock );
423         return NULL;
424     }
425
426     /* need to add a new listening socket */
427
428     /* open socket */
429     fd = socket( AF_INET, SOCK_STREAM, 0 );
430     if( fd < 0 )
431     {
432         msg_Err( p_httpt, "cannot open socket" );
433         goto socket_failed;
434     }
435     /* reuse socket */
436     i_opt = 1;
437     if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
438                     (void *) &i_opt, sizeof( i_opt ) ) < 0 )
439     {
440         msg_Warn( p_httpt, "cannot configure socket (SO_REUSEADDR)" );
441     }
442     /* bind it */
443     if( bind( fd, &sock, sizeof( struct sockaddr_in ) ) < 0 )
444     {
445         msg_Err( p_httpt, "cannot bind socket" );
446         goto socket_failed;
447     }
448     /* set to non-blocking */
449     if( ( i_flags = fcntl( fd, F_GETFL, 0 ) ) < 0 )
450     {
451         msg_Err( p_httpt, "cannot F_GETFL socket" );
452         goto socket_failed;
453     }
454     if( fcntl( fd, F_SETFL, i_flags | O_NONBLOCK ) < 0 )
455     {
456         msg_Err( p_httpt, "cannot F_SETFL O_NONBLOCK" );
457         goto socket_failed;
458     }
459     /* listen */
460     if( listen( fd, LISTEN_BACKLOG ) < 0 )
461     {
462         msg_Err( p_httpt, "cannot listen socket" );
463         goto socket_failed;
464     }
465
466     if( p_httpt->host )
467     {
468         p_httpt->host = realloc( p_httpt->host, sizeof( httpd_host_t *)  * ( p_httpt->i_host_count + 1 ) );
469     }
470     else
471     {
472         p_httpt->host = malloc( sizeof( httpd_host_t *) );
473     }
474     p_host                = malloc( sizeof( httpd_host_t ) );
475     p_host->i_ref         = 1;
476     p_host->psz_host_addr = strdup( psz_host_addr );
477     p_host->i_port        = i_port;
478     p_host->sock          = sock;
479     p_host->fd            = fd;
480
481     p_httpt->host[p_httpt->i_host_count++] = p_host;
482     vlc_mutex_unlock( &p_httpt->host_lock );
483
484     return p_host;
485
486 socket_failed:
487     vlc_mutex_unlock( &p_httpt->host_lock );
488     if( fd >= 0 )
489     {
490         SOCKET_CLOSE( fd );
491     }
492     return NULL;
493 }
494 static httpd_host_t     *RegisterHost( httpd_t *p_httpd, char *psz_host_addr, int i_port )
495 {
496     return( _RegisterHost( p_httpd->p_sys, psz_host_addr, i_port ) );
497 }
498
499 /*
500  * remove a listening host for an httpd instance
501  */
502 static void            _UnregisterHost( httpd_sys_t *p_httpt, httpd_host_t *p_host )
503 {
504     int i;
505
506     vlc_mutex_lock( &p_httpt->host_lock );
507     for( i = 0; i < p_httpt->i_host_count; i++ )
508     {
509         if( p_httpt->host[i] == p_host )
510         {
511             break;
512         }
513     }
514     if( i >= p_httpt->i_host_count )
515     {
516         vlc_mutex_unlock( &p_httpt->host_lock );
517         msg_Err( p_httpt, "cannot unregister host" );
518         return;
519     }
520
521     p_host->i_ref--;
522
523     if( p_host->i_ref > 0 )
524     {
525         /* still in use */
526         vlc_mutex_unlock( &p_httpt->host_lock );
527         return;
528     }
529
530     /* no more used */
531     FREE( p_host->psz_host_addr );
532     SOCKET_CLOSE( p_host->fd );
533
534     FREE( p_host );
535
536     if( p_httpt->i_host_count <= 1 )
537     {
538         FREE( p_httpt->host );
539         p_httpt->i_host_count = 0;
540     }
541     else
542     {
543         int i_move;
544
545         i_move = p_httpt->i_host_count - i - 1;
546
547         if( i_move > 0 )
548         {
549             memmove( &p_httpt->host[i],
550                      &p_httpt->host[i+1],
551                      i_move * sizeof( httpd_host_t * ) );
552         }
553
554         p_httpt->i_host_count--;
555         p_httpt->host = realloc( p_httpt->host,
556                                  p_httpt->i_host_count * sizeof( httpd_host_t * ) );
557     }
558
559     vlc_mutex_unlock( &p_httpt->host_lock );
560 }
561 static void             UnregisterHost( httpd_t *p_httpd, httpd_host_t *p_host )
562 {
563     _UnregisterHost( p_httpd->p_sys, p_host );
564 }
565
566
567 static void __RegisterFile( httpd_sys_t *p_httpt, httpd_file_t *p_file )
568 {
569     /* add a new file */
570     if( p_httpt->i_file_count )
571     {
572         p_httpt->file = realloc( p_httpt->file, sizeof( httpd_file_t *)  * ( p_httpt->i_file_count + 1 ) );
573     }
574     else
575     {
576         p_httpt->file = malloc( sizeof( httpd_file_t *) );
577     }
578
579     p_httpt->file[p_httpt->i_file_count++] = p_file;
580 }
581
582 static httpd_file_t    *_RegisterFile( httpd_sys_t *p_httpt,
583                                        char *psz_file, char *psz_mime,
584                                        char *psz_user, char *psz_password,
585                                        httpd_file_callback pf_fill,
586                                        httpd_file_callback_args_t *p_args )
587 {
588     httpd_file_t    *p_file;
589     int i;
590
591     vlc_mutex_lock( &p_httpt->file_lock );
592     for( i = 0; i < p_httpt->i_file_count; i++ )
593     {
594         if( !strcmp( psz_file, p_httpt->file[i]->psz_file ) )
595         {
596             break;
597         }
598     }
599     if( i < p_httpt->i_file_count )
600     {
601         vlc_mutex_unlock( &p_httpt->file_lock );
602         msg_Err( p_httpt, "%s already registered", psz_file );
603         return NULL;
604     }
605
606     p_file              = malloc( sizeof( httpd_file_t ) );
607     p_file->i_ref       = 0;
608     p_file->psz_file    = strdup( psz_file );
609     p_file->psz_mime    = strdup( psz_mime );
610     if( psz_user && *psz_user )
611     {
612         p_file->i_authenticate_method = HTTPD_AUTHENTICATE_BASIC;
613         p_file->psz_user              = strdup( psz_user );
614         p_file->psz_password          = strdup( psz_password );
615     }
616     else
617     {
618         p_file->i_authenticate_method = HTTPD_AUTHENTICATE_NONE;
619         p_file->psz_user              = NULL;
620         p_file->psz_password          = NULL;
621     }
622
623     p_file->b_stream        = VLC_FALSE;
624     p_file->p_sys           = p_args;
625     p_file->pf_fill         = pf_fill;
626
627     p_file->i_buffer_size   = 0;
628     p_file->i_buffer_valid  = 0;
629     p_file->i_buffer        = 0;
630     p_file->p_buffer        = NULL;
631
632     __RegisterFile( p_httpt, p_file );
633
634     vlc_mutex_unlock( &p_httpt->file_lock );
635
636     return p_file;
637 }
638 static httpd_file_t     *RegisterFile( httpd_t *p_httpd,
639                                        char *psz_file, char *psz_mime,
640                                        char *psz_user, char *psz_password,
641                                        httpd_file_callback pf_fill,
642                                        httpd_file_callback_args_t *p_args )
643 {
644     return( _RegisterFile( p_httpd->p_sys,
645                            psz_file, psz_mime, psz_user, psz_password,
646                            pf_fill, p_args ) );
647 }
648
649 static httpd_stream_t  *_RegisterStream( httpd_sys_t *p_httpt,
650                                          char *psz_file, char *psz_mime,
651                                          char *psz_user, char *psz_password )
652 {
653     httpd_stream_t    *p_stream;
654     int i;
655
656     vlc_mutex_lock( &p_httpt->file_lock );
657     for( i = 0; i < p_httpt->i_file_count; i++ )
658     {
659         if( !strcmp( psz_file, p_httpt->file[i]->psz_file ) )
660         {
661             break;
662         }
663     }
664     if( i < p_httpt->i_file_count )
665     {
666         vlc_mutex_unlock( &p_httpt->file_lock );
667         msg_Err( p_httpt, "%s already registeret", psz_file );
668         return NULL;
669     }
670
671     p_stream              = malloc( sizeof( httpd_stream_t ) );
672     p_stream->i_ref       = 0;
673     p_stream->psz_file    = strdup( psz_file );
674     p_stream->psz_mime    = strdup( psz_mime );
675     if( psz_user && *psz_user )
676     {
677         p_stream->i_authenticate_method = HTTPD_AUTHENTICATE_BASIC;
678         p_stream->psz_user              = strdup( psz_user );
679         p_stream->psz_password          = strdup( psz_password );
680     }
681     else
682     {
683         p_stream->i_authenticate_method = HTTPD_AUTHENTICATE_NONE;
684         p_stream->psz_user              = NULL;
685         p_stream->psz_password          = NULL;
686     }
687
688     p_stream->b_stream        = VLC_TRUE;
689     p_stream->p_sys           = NULL;
690     p_stream->pf_fill         = NULL;
691     p_stream->i_buffer_size   = 1024*1024;
692     p_stream->i_buffer_valid  = 0;
693     p_stream->i_buffer        = 0;
694     p_stream->p_buffer        = malloc( p_stream->i_buffer_size );
695
696     __RegisterFile( p_httpt, p_stream );
697
698     vlc_mutex_unlock( &p_httpt->file_lock );
699
700     return p_stream;
701 }
702 static httpd_stream_t   *RegisterStream( httpd_t *p_httpd,
703                                          char *psz_file, char *psz_mime,
704                                          char *psz_user, char *psz_password )
705 {
706     return( _RegisterStream( p_httpd->p_sys,
707                              psz_file, psz_mime, psz_user, psz_password ) );
708 }
709
710 static void            _UnregisterFile( httpd_sys_t *p_httpt, httpd_file_t *p_file )
711 {
712     int i;
713
714     vlc_mutex_lock( &p_httpt->file_lock );
715     for( i = 0; i < p_httpt->i_file_count; i++ )
716     {
717         if( !strcmp( p_file->psz_file, p_httpt->file[i]->psz_file ) )
718         {
719             break;
720         }
721     }
722     if( i >= p_httpt->i_file_count )
723     {
724         vlc_mutex_unlock( &p_httpt->file_lock );
725         msg_Err( p_httpt, "cannot unregister file" );
726         return;
727     }
728
729     if( p_file->i_ref > 0 )
730     {
731         httpd_connection_t *p_con;
732         /* force closing all connection for this file */
733         msg_Err( p_httpt, "closing all client connection" );
734
735         vlc_mutex_lock( &p_httpt->connection_lock );
736         for( p_con = p_httpt->p_first_connection; p_con != NULL; )
737         {
738             httpd_connection_t *p_next;
739
740             p_next = p_con->p_next;
741             if( p_con->p_file == p_file )
742             {
743                 httpd_ConnnectionClose( p_httpt, p_con );
744             }
745             p_con = p_next;
746         }
747         vlc_mutex_unlock( &p_httpt->connection_lock );
748     }
749
750     FREE( p_file->psz_file );
751     FREE( p_file->psz_mime );
752     if( p_file->i_authenticate_method != HTTPD_AUTHENTICATE_NONE )
753     {
754         FREE( p_file->psz_user );
755         FREE( p_file->psz_password );
756     }
757     FREE( p_file->p_buffer );
758
759     FREE( p_file );
760
761
762     if( p_httpt->i_file_count == 1 )
763     {
764         FREE( p_httpt->file );
765         p_httpt->i_file_count = 0;
766     }
767     else
768     {
769         int i_move;
770
771         i_move = p_httpt->i_file_count - i - 1;
772         if( i_move > 0  )
773         {
774             memmove( &p_httpt->file[i], &p_httpt->file[i + 1], sizeof( httpd_file_t *) * i_move );
775         }
776         p_httpt->i_file_count--;
777         p_httpt->file = realloc( p_httpt->file, sizeof( httpd_file_t *) * p_httpt->i_file_count );
778     }
779
780     vlc_mutex_unlock( &p_httpt->file_lock );
781 }
782 static void            UnregisterFile( httpd_t *p_httpd, httpd_file_t *p_file )
783 {
784     _UnregisterFile( p_httpd->p_sys, p_file );
785 }
786
787 static void             UnregisterStream( httpd_t *p_httpd, httpd_stream_t *p_stream )
788 {
789     _UnregisterFile( p_httpd->p_sys, p_stream );
790 }
791
792
793
794 static int             _SendStream( httpd_sys_t *p_httpt, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
795 {
796     if( i_data <= 0 )
797     {
798         return( VLC_SUCCESS );
799     }
800
801     vlc_mutex_lock( &p_httpt->file_lock );
802     if( p_stream->i_buffer_size < p_stream->i_buffer_valid + i_data )
803     {
804         /* not enough room */
805         if( p_stream->i_buffer < p_stream->i_buffer_valid )
806         {
807             memmove( p_stream->p_buffer,
808                      p_stream->p_buffer + p_stream->i_buffer,
809                      p_stream->i_buffer_valid - p_stream->i_buffer );
810         }
811         p_stream->i_buffer_valid -= p_stream->i_buffer;
812
813         p_stream->i_buffer = 0;
814     }
815     i_data = __MIN( i_data, p_stream->i_buffer_size - p_stream->i_buffer_valid );
816     memcpy( p_stream->p_buffer + p_stream->i_buffer_valid, p_data, i_data );
817     p_stream->i_buffer_valid += i_data;
818
819     vlc_mutex_unlock( &p_httpt->file_lock );
820
821     return( VLC_SUCCESS );
822 }
823 static int             SendStream( httpd_t *p_httpd, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
824 {
825     return( _SendStream( p_httpd->p_sys, p_stream, p_data, i_data ) );
826 }
827
828 /****************************************************************************/
829 /****************************************************************************/
830 /****************************************************************************/
831 /****************************************************************************/
832 /****************************************************************************/
833
834 static int  httpd_page_401_fill( httpd_file_callback_args_t *p_args, uint8_t **pp_data, int *pi_data )
835 {
836     char *p;
837
838     p = *pp_data = malloc( 1024 );
839
840     p += sprintf( p, "<html>\n" );
841     p += sprintf( p, "<head>\n" );
842     p += sprintf( p, "<title>Error 401</title>\n" );
843     p += sprintf( p, "</head>\n" );
844     p += sprintf( p, "<body>\n" );
845     p += sprintf( p, "<h1><center> 401 authentification needed</center></h1>\n" );
846     p += sprintf( p, "<hr />\n" );
847     p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
848     p += sprintf( p, "</body>\n" );
849     p += sprintf( p, "</html>\n" );
850
851     *pi_data = strlen( *pp_data ) + 1;
852
853     return VLC_SUCCESS;
854 }
855 static int  httpd_page_404_fill( httpd_file_callback_args_t *p_args, uint8_t **pp_data, int *pi_data )
856 {
857     char *p;
858
859     p = *pp_data = malloc( 1024 );
860
861     p += sprintf( p, "<html>\n" );
862     p += sprintf( p, "<head>\n" );
863     p += sprintf( p, "<title>Error 404</title>\n" );
864     p += sprintf( p, "</head>\n" );
865     p += sprintf( p, "<body>\n" );
866     p += sprintf( p, "<h1><center> 404 Ressource not found</center></h1>\n" );
867     p += sprintf( p, "<hr />\n" );
868     p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
869     p += sprintf( p, "</body>\n" );
870     p += sprintf( p, "</html>\n" );
871
872     *pi_data = strlen( *pp_data ) + 1;
873
874     return VLC_SUCCESS;
875 }
876
877 static int  httpd_page_admin_fill( httpd_file_callback_args_t *p_args, uint8_t **pp_data, int *pi_data )
878 {
879     httpd_sys_t *p_httpt = (httpd_sys_t*)p_args;
880     httpd_connection_t *p_con;
881     char *p;
882     int i;
883
884     /* FIXME FIXME do not use static size FIXME FIXME*/
885     p = *pp_data = malloc( 8096 );
886
887     p += sprintf( p, "<html>\n" );
888     p += sprintf( p, "<head>\n" );
889     p += sprintf( p, "<title>VideoLAN Client Stream Output</title>\n" );
890     p += sprintf( p, "</head>\n" );
891     p += sprintf( p, "<body>\n" );
892     p += sprintf( p, "<h1><center>VideoLAN Client Stream Output</center></h1>\n" );
893     p += sprintf( p, "<h2><center>Admin page</center></h2>\n" );
894
895     /* host list */
896     vlc_mutex_lock( &p_httpt->host_lock );
897     p += sprintf( p, "<h3>Host list</h3>\n" );
898     p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
899     p += sprintf( p, "<tr>\n<th>Host</th><th>Port</th><th>IP</th>\n</tr>\n" );
900
901     for( i = 0; i < p_httpt->i_host_count; i++ )
902     {
903         p += sprintf( p, "<tr>\n" );
904         p += sprintf( p, "<td>%s</td>\n", p_httpt->host[i]->psz_host_addr );
905         p += sprintf( p, "<td>%d</td>\n", p_httpt->host[i]->i_port );
906         p += sprintf( p, "<td>%s</td>\n", inet_ntoa( p_httpt->host[i]->sock.sin_addr ) );
907         p += sprintf( p, "</tr>\n" );
908     }
909     p += sprintf( p, "</table>\n" );
910     vlc_mutex_unlock( &p_httpt->host_lock );
911
912     /* file list */
913     /* XXX do not take lock on file_lock */
914     p += sprintf( p, "<h3>File list</h3>\n" );
915     p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
916     p += sprintf( p, "<tr>\n<th>Name</th><th>Mime</th><th>Protected</th><th>Used</th>\n</tr>\n" );
917
918     for( i = 0; i < p_httpt->i_file_count; i++ )
919     {
920         if( !p_httpt->file[i]->b_stream )
921         {
922             p += sprintf( p, "<tr>\n" );
923             p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_file );
924             p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_mime );
925             p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_user ? "Yes" : "No" );
926             p += sprintf( p, "<td>%d</td>\n", p_httpt->file[i]->i_ref);
927             p += sprintf( p, "</tr>\n" );
928         }
929     }
930     p += sprintf( p, "</table>\n" );
931
932     /* stream list */
933     /* XXX do not take lock on file_lock */
934     p += sprintf( p, "<h3>Stream list</h3>\n" );
935     p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
936     p += sprintf( p, "<tr>\n<th>Name</th><th>Mime</th><th>Protected</th><th>Used</th>\n</tr>\n" );
937
938     for( i = 0; i < p_httpt->i_file_count; i++ )
939     {
940         if( p_httpt->file[i]->b_stream )
941         {
942             p += sprintf( p, "<tr>\n" );
943             p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_file );
944             p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_mime );
945             p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_user ? "Yes" : "No" );
946             p += sprintf( p, "<td>%d</td>\n", p_httpt->file[i]->i_ref);
947             p += sprintf( p, "</tr>\n" );
948         }
949     }
950     p += sprintf( p, "</table>\n" );
951
952     /* connection list */
953     /* XXX do not take lock on connection_lock */
954     p += sprintf( p, "<h3>Connection list</h3>\n" );
955     p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
956     p += sprintf( p, "<tr>\n<th>IP</th><th>Requested File</th><th>Status</th>\n</tr>\n" );
957
958     for( p_con = p_httpt->p_first_connection;p_con != NULL; p_con = p_con->p_next )
959     {
960         p += sprintf( p, "<tr>\n" );
961         p += sprintf( p, "<td>%s</td>\n", inet_ntoa( p_con->sock.sin_addr ) );
962         p += sprintf( p, "<td>%s</td>\n", p_con->psz_file );
963         p += sprintf( p, "<td>%d</td>\n", p_con->i_http_error );
964         p += sprintf( p, "</tr>\n" );
965     }
966     p += sprintf( p, "</table>\n" );
967
968
969     /* www.videolan.org */
970     p += sprintf( p, "<hr />\n" );
971     p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
972     p += sprintf( p, "</body>\n" );
973     p += sprintf( p, "</html>\n" );
974
975     *pi_data = strlen( *pp_data ) + 1;
976
977     return VLC_SUCCESS;
978 }
979
980
981 static void httpd_ConnnectionNew( httpd_sys_t *p_httpt, int fd, struct sockaddr_in *p_sock )
982 {
983     httpd_connection_t *p_con;
984
985     msg_Dbg( p_httpt, "new connection from %s", inet_ntoa( p_sock->sin_addr ) );
986
987     /* create a new connection and link it */
988     p_con = malloc( sizeof( httpd_connection_t ) );
989     p_con->i_state  = HTTPD_CONNECTION_RECEIVING_REQUEST;
990     p_con->fd       = fd;
991     p_con->sock     = *p_sock;
992     p_con->psz_file = NULL;
993     p_con->i_http_error = 0;
994     p_con->psz_user = NULL;
995     p_con->psz_password = NULL;
996     p_con->p_file   = NULL;
997
998     p_con->i_buffer = 0;
999     p_con->i_buffer_size = 8096;
1000     p_con->p_buffer = malloc( p_con->i_buffer_size );
1001
1002     p_con->p_next = NULL;
1003
1004     if( p_httpt->p_first_connection )
1005     {
1006         httpd_connection_t *p_last;
1007
1008         p_last = p_httpt->p_first_connection;
1009         while( p_last->p_next )
1010         {
1011             p_last = p_last->p_next;
1012         }
1013
1014         p_last->p_next = p_con;
1015         p_con->p_prev = p_last;
1016     }
1017     else
1018     {
1019         p_con->p_prev = NULL;
1020
1021         p_httpt->p_first_connection = p_con;
1022     }
1023
1024     p_httpt->i_connection_count++;
1025 }
1026
1027 static void httpd_ConnnectionClose( httpd_sys_t *p_httpt, httpd_connection_t *p_con )
1028 {
1029     msg_Dbg( p_httpt, "close connection from %s", inet_ntoa( p_con->sock.sin_addr ) );
1030
1031     p_httpt->i_connection_count--;
1032     /* first cut out from list */
1033     if( p_con->p_prev )
1034     {
1035         p_con->p_prev->p_next = p_con->p_next;
1036     }
1037     else
1038     {
1039         p_httpt->p_first_connection = p_con->p_next;
1040     }
1041
1042     if( p_con->p_next )
1043     {
1044         p_con->p_next->p_prev = p_con->p_prev;
1045     }
1046
1047     if( p_con->p_file ) p_con->p_file->i_ref--;
1048     FREE( p_con->psz_file );
1049
1050     FREE( p_con->p_buffer );
1051     SOCKET_CLOSE( p_con->fd );
1052
1053
1054     FREE( p_con->psz_user );
1055     FREE( p_con->psz_password );
1056
1057     free( p_con );
1058 }
1059
1060 static void httpd_RequestGetWord( char *word, int i_word_max, char **pp_buffer, char *p_end )
1061 {
1062     char *p = *pp_buffer;
1063     int i;
1064
1065     while( p < p_end && *p && ( *p == ' ' || *p == '\t' ) )
1066     {
1067         p++;
1068     }
1069
1070     i = 0;
1071     for( i = 0; i < i_word_max && p < p_end && *p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r'; i++,p++)
1072     {
1073         word[i] = *p;
1074     }
1075
1076     word[__MIN( i, i_word_max -1 )] = '\0';
1077
1078     *pp_buffer = p;
1079
1080 }
1081 static int httpd_RequestNextLine( char **pp_buffer, char *p_end )
1082 {
1083     char *p;
1084
1085     for( p = *pp_buffer; p < p_end; p++ )
1086     {
1087         if( p + 1 < p_end && *p == '\n' )
1088         {
1089             *pp_buffer = p + 1;
1090             return VLC_SUCCESS;
1091         }
1092         if( p + 2 < p_end && p[0] == '\r' && p[1] == '\n' )
1093         {
1094             *pp_buffer = p + 2;
1095             return VLC_SUCCESS;
1096         }
1097     }
1098     *pp_buffer = p_end;
1099     return VLC_EGENERIC;
1100 }
1101
1102 //char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1103 static void b64_decode( char *dest, char *src )
1104 {
1105     int  i_level;
1106     int  last = 0;
1107     int  b64[256] = {
1108         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 00-0F */
1109         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 10-1F */
1110         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,  /* 20-2F */
1111         52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,  /* 30-3F */
1112         -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,  /* 40-4F */
1113         15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,  /* 50-5F */
1114         -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,  /* 60-6F */
1115         41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,  /* 70-7F */
1116         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 80-8F */
1117         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 90-9F */
1118         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* A0-AF */
1119         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* B0-BF */
1120         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* C0-CF */
1121         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* D0-DF */
1122         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* E0-EF */
1123         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1   /* F0-FF */
1124         };
1125
1126     for( i_level = 0; *src != '\0' > 0; src++ )
1127     {
1128         int  c;
1129
1130         c = b64[(unsigned int)*src];
1131         if( c == -1 )
1132         {
1133             src++;
1134             continue;
1135         }
1136
1137         switch( i_level )
1138         {
1139             case 0:
1140                 i_level++;
1141                 break;
1142             case 1:
1143                 *dest++ = ( last << 2 ) | ( ( c >> 4)&0x03 );
1144                 i_level++;
1145                 break;
1146             case 2:
1147                 *dest++ = ( ( last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f );
1148                 i_level++;
1149                 break;
1150             case 3:
1151                 *dest++ = ( ( last &0x03 ) << 6 ) | c;
1152                 i_level = 0;
1153         }
1154         last = c;
1155     }
1156
1157     *dest = '\0';
1158 }
1159
1160 static void httpd_ConnectionParseRequest( httpd_sys_t *p_httpt, httpd_connection_t *p_con )
1161 {
1162     char *psz_status;
1163     char *p, *p_end;
1164
1165     int  i;
1166     char command[32];
1167     char url[1024];
1168     char version[32];
1169     char user[512] = "";
1170     char password[512] = "";
1171
1172     //msg_Dbg( p_httpt, "new request=\n%s", p_con->p_buffer );
1173
1174     p = p_con->p_buffer;
1175     p_end = p + strlen( p ) + 1;
1176
1177     httpd_RequestGetWord( command, 32, &p, p_end );
1178     httpd_RequestGetWord( url, 1024, &p, p_end );
1179     httpd_RequestGetWord( version, 32, &p, p_end );
1180     //msg_Dbg( p_httpt, "ask =%s= =%s= =%s=", command, url, version );
1181
1182     if( strcmp( command, "GET" ) )
1183     {
1184         /* unimplemented */
1185         p_con->psz_file = strdup( "/501.html" );
1186         p_con->i_http_error = 501;
1187         goto create_header;
1188     }
1189
1190     if( strcmp( version, "HTTP/1.0" ) && strcmp( version, "HTTP/1.1" ) )
1191     {
1192         p_con->psz_file = strdup( "/505.html" );
1193         p_con->i_http_error = 505;
1194
1195         goto create_header;
1196     }
1197
1198     /* parse headers */
1199     for( ;; )
1200     {
1201         char header[1024];
1202
1203         if( httpd_RequestNextLine( &p, p_end ) )
1204         {
1205             //msg_Dbg( p_httpt, "failled new line" );
1206             break;;
1207         }
1208         //msg_Dbg( p_httpt, "new line=%s", p );
1209
1210         httpd_RequestGetWord( header, 1024, &p, p_end );
1211
1212         if( !strcmp( header, "Authorization:" ) )
1213         {
1214             char method[32];
1215
1216             httpd_RequestGetWord( method, 32, &p, p_end );
1217             if( !strcasecmp( method, "BASIC" ) )
1218             {
1219                 char basic[1024];
1220                 char decoded[1024];
1221
1222                 httpd_RequestGetWord( basic, 1024, &p, p_end );
1223                 //msg_Dbg( p_httpt, "Authorization: basic:%s", basic );
1224                 b64_decode( decoded, basic );
1225
1226                 //msg_Dbg( p_httpt, "Authorization: decoded:%s", decoded );
1227                 if( strchr( decoded, ':' ) )
1228                 {
1229                     char *p = strchr( decoded, ':' );
1230
1231                     p[0] = '\0'; p++;
1232                     strcpy( user, decoded );
1233                     strcpy( password, p );
1234                 }
1235             }
1236         }
1237     }
1238
1239     p_con->psz_file = strdup( url );
1240     p_con->i_http_error = 200;
1241
1242 create_header:
1243     //msg_Dbg( p_httpt, "ask %s %s %d", command, p_con->psz_file, p_con->i_http_error );
1244     FREE( p_con->p_buffer );
1245     p_con->i_buffer = 0;
1246     p_con->i_buffer_size = 0;
1247
1248     //vlc_mutex_lock( &p_httpt->file_lock );
1249 search_file:
1250     /* search file */
1251     for( i = 0, p_con->p_file = NULL; i < p_httpt->i_file_count; i++ )
1252     {
1253         if( !strcmp( p_httpt->file[i]->psz_file, p_con->psz_file ) )
1254         {
1255             p_con->p_file = p_httpt->file[i];
1256         }
1257     }
1258
1259     if( !p_con->p_file )
1260     {
1261         p_con->psz_file = strdup( "/404.html" );
1262         p_con->i_http_error = 404;
1263
1264         /* XXX be sure that "/404.html" exist else ... */
1265         goto search_file;
1266     }
1267
1268     if( p_con->p_file->i_authenticate_method == HTTPD_AUTHENTICATE_BASIC )
1269     {
1270         if( strcmp( user, p_con->p_file->psz_user ) || strcmp( password, p_con->p_file->psz_password ) )
1271         {
1272             p_con->psz_file = strdup( "/401.html" );
1273             strcpy( user, p_con->p_file->psz_user );
1274             p_con->i_http_error = 401;
1275
1276             /* XXX do not put password on 404 else ... */
1277             goto search_file;
1278         }
1279     }
1280
1281     p_con->p_file->i_ref++;
1282 //    vlc_mutex_unlock( &p_httpt->file_lock );
1283
1284     switch( p_con->i_http_error )
1285     {
1286         case 200:
1287             psz_status = "OK";
1288             break;
1289
1290         case 401:
1291             psz_status = "Authorization Required";
1292             break;
1293         default:
1294             psz_status = "Unknown";
1295             break;
1296     }
1297
1298     p_con->i_state = HTTPD_CONNECTION_SENDING_HEADER;
1299
1300     p_con->i_buffer_size = 4096;
1301     p_con->i_buffer = 0;
1302     p = p_con->p_buffer = malloc( p_con->i_buffer_size );
1303
1304     p += sprintf( p, "HTTP/1.0 %d %s\r\n", p_con->i_http_error, psz_status );
1305     p += sprintf( p, "Content-type: %s\r\n", p_con->p_file->psz_mime );
1306     if( p_con->i_http_error == 401 )
1307     {
1308         p += sprintf( p, "WWW-Authenticate: Basic realm=\"%s\"\r\n", user );
1309     }
1310     p += sprintf( p, "\r\n" );
1311
1312     p_con->i_buffer_size = strlen( p_con->p_buffer ) + 1;
1313
1314     //msg_Dbg( p_httpt, "answer=\n%s", p_con->p_buffer );
1315 }
1316 #define HTTPD_STREAM_PACKET 1300
1317 static void httpd_Thread( httpd_sys_t *p_httpt )
1318 {
1319     httpd_file_t    *p_page_admin;
1320     httpd_file_t    *p_page_401;
1321     httpd_file_t    *p_page_404;
1322
1323     httpd_connection_t *p_con;
1324     vlc_bool_t         b_wait;
1325
1326     msg_Info( p_httpt, "httpd started" );
1327
1328     p_page_401 = _RegisterFile( p_httpt,
1329                                 "/401.html", "text/html",
1330                                 NULL, NULL,
1331                                 httpd_page_401_fill,
1332                                 (httpd_file_callback_args_t*)NULL );
1333     p_page_404 = _RegisterFile( p_httpt,
1334                                 "/404.html", "text/html",
1335                                 NULL, NULL,
1336                                 httpd_page_404_fill,
1337                                 (httpd_file_callback_args_t*)NULL );
1338     p_page_admin = _RegisterFile( p_httpt,
1339                                   "/admin.html", "text/html",
1340                                   "admin", "salut",
1341                                   httpd_page_admin_fill,
1342                                   (httpd_file_callback_args_t*)p_httpt );
1343
1344     while( !p_httpt->b_die )
1345     {
1346         int i;
1347         if( p_httpt->i_host_count <= 0 )
1348         {
1349             msleep( 100 * 1000 );
1350             continue;
1351         }
1352         vlc_mutex_lock( &p_httpt->host_lock );
1353         /* accept/refuse new connection */
1354         for( i = 0; i < p_httpt->i_host_count; i++ )
1355         {
1356             int     i_sock_size = sizeof( struct sockaddr_in );
1357             struct  sockaddr_in sock;
1358             int     fd;
1359
1360             fd = accept( p_httpt->host[i]->fd, &sock, &i_sock_size );
1361             if( fd > 0 )
1362             {
1363                 fcntl( fd, F_SETFL, O_NONBLOCK );
1364
1365                 if( p_httpt->i_connection_count >= HTTPD_MAX_CONNECTION )
1366                 {
1367                     msg_Warn( p_httpt, "max connection reached" );
1368                     SOCKET_CLOSE( fd );
1369                     continue;
1370                 }
1371                 /* create a new connection and link it */
1372                 httpd_ConnnectionNew( p_httpt, fd, &sock );
1373
1374             }
1375         }
1376         vlc_mutex_unlock( &p_httpt->host_lock );
1377
1378         vlc_mutex_lock( &p_httpt->file_lock );
1379         /* now do work for all connections */
1380         for( p_con = p_httpt->p_first_connection; p_con != NULL; )
1381         {
1382             if( p_con->i_state == HTTPD_CONNECTION_RECEIVING_REQUEST )
1383             {
1384                 int i_len;
1385                 /* read data */
1386                 i_len = recv( p_con->fd,
1387                               p_con->p_buffer + p_con->i_buffer,
1388                               p_con->i_buffer_size - p_con->i_buffer, 0 );
1389
1390                 if( ( i_len < 0 && errno != EAGAIN && errno != EINTR )||
1391                     ( i_len == 0 ) )
1392                 {
1393                     httpd_connection_t *p_next = p_con->p_next;
1394
1395                     httpd_ConnnectionClose( p_httpt, p_con );
1396                     p_con = p_next;
1397                 }
1398                 else if( i_len > 0 )
1399                 {
1400                     uint8_t *ptr;
1401
1402                     p_con->i_buffer += i_len;
1403
1404                     ptr = p_con->p_buffer + p_con->i_buffer;
1405
1406                     if( ( p_con->i_buffer >= 2 && !strncmp( ptr - 2, "\n\n", 2 ) )||
1407                         ( p_con->i_buffer >= 4 && !strncmp( ptr - 4, "\r\n\r\n", 4 ) ) ||
1408                         p_con->i_buffer >= p_con->i_buffer_size )
1409                     {
1410                         p_con->p_buffer[__MIN( p_con->i_buffer, p_con->i_buffer_size - 1 )] = '\0';
1411                         httpd_ConnectionParseRequest( p_httpt, p_con );
1412                     }
1413
1414                     p_con = p_con->p_next;
1415                 }
1416                 else
1417                 {
1418                     p_con = p_con->p_next;
1419                 }
1420                 continue;   /* just for clarity */
1421             }
1422             else if( p_con->i_state == HTTPD_CONNECTION_SENDING_HEADER || p_con->i_state == HTTPD_CONNECTION_SENDING_FILE )
1423             {
1424                 int i_len;
1425
1426                 /* write data */
1427                 i_len = send( p_con->fd, p_con->p_buffer + p_con->i_buffer, p_con->i_buffer_size - p_con->i_buffer, 0 );
1428
1429 //                msg_Warn( p_httpt, "on %d send %d bytes %s", p_con->i_buffer_size, i_len, p_con->p_buffer + p_con->i_buffer );
1430
1431                 if( ( i_len < 0 && errno != EAGAIN && errno != EINTR )||
1432                     ( i_len == 0 ) )
1433                 {
1434                     httpd_connection_t *p_next = p_con->p_next;
1435
1436                     httpd_ConnnectionClose( p_httpt, p_con );
1437                     p_con = p_next;
1438                 }
1439                 else if( i_len > 0 )
1440                 {
1441                     p_con->i_buffer += i_len;
1442
1443                     if( p_con->i_buffer >= p_con->i_buffer_size )
1444                     {
1445                         if( p_con->i_state == HTTPD_CONNECTION_SENDING_HEADER )
1446                         {
1447                             p_con->i_buffer_size = 0;
1448                             p_con->i_buffer = 0;
1449                             FREE( p_con->p_buffer );
1450
1451                             if( !p_con->p_file->b_stream )
1452                             {
1453                                 p_con->i_state = HTTPD_CONNECTION_SENDING_FILE; // be sure to out from HTTPD_CONNECTION_SENDING_HEADER
1454                                 p_con->p_file->pf_fill( p_con->p_file->p_sys, &p_con->p_buffer, &p_con->i_buffer_size );
1455                             }
1456                             else
1457                             {
1458                                 p_con->i_state = HTTPD_CONNECTION_SENDING_STREAM;
1459                             }
1460                             p_con = p_con->p_next;
1461                         }
1462                         else
1463                         {
1464                             httpd_connection_t *p_next = p_con->p_next;
1465
1466                             httpd_ConnnectionClose( p_httpt, p_con );
1467                             p_con = p_next;
1468                         }
1469                     }
1470                     else
1471                     {
1472                         p_con = p_con->p_next;
1473                     }
1474                 }
1475                 else
1476                 {
1477                     p_con = p_con->p_next;
1478                 }
1479                 continue;   /* just for clarity */
1480             }
1481             else if( p_con->i_state == HTTPD_CONNECTION_SENDING_STREAM )
1482             {
1483                 httpd_file_t *p_file = p_con->p_file;
1484                 int i_len;
1485
1486                 //msg_Dbg( p_httpt, "buffer=%d buffer_size=%d", p_file->i_buffer, p_file->i_buffer_size );
1487                 if( p_file->i_buffer < p_file->i_buffer_valid )
1488                 {
1489                     int i_write;
1490                     /* write data */
1491                     i_write = __MIN( p_file->i_buffer_valid - p_file->i_buffer, HTTPD_STREAM_PACKET );
1492                     i_len = send( p_con->fd, p_file->p_buffer + p_file->i_buffer, i_write, 0 );
1493
1494                     if( ( i_len < 0 && errno != EAGAIN && errno != EINTR )||
1495                         ( i_len == 0 ) )
1496                     {
1497                         httpd_connection_t *p_next = p_con->p_next;
1498
1499                         httpd_ConnnectionClose( p_httpt, p_con );
1500                         p_con = p_next;
1501                     }
1502                     else
1503                     {
1504                         p_con = p_con->p_next;
1505                     }
1506                 }
1507                 else
1508                 {
1509                     p_con = p_con->p_next;
1510                 }
1511                 continue;   /* just for clarity */
1512             }
1513             else
1514             {
1515                 msg_Warn( p_httpt, "cannot occur (Invalid p_con->i_state)" );
1516                 p_con = p_con->p_next;
1517             }
1518         }   /* for over connection */
1519
1520
1521         b_wait = VLC_TRUE;
1522         /* update position for stream based file */
1523         for( i = 0; i < p_httpt->i_file_count; i++ )
1524         {
1525             if( p_httpt->file[i]->b_stream )
1526             {
1527                 p_httpt->file[i]->i_buffer += __MIN( p_httpt->file[i]->i_buffer_valid - p_httpt->file[i]->i_buffer,
1528                                                      HTTPD_STREAM_PACKET );
1529                 if( p_httpt->file[i]->i_buffer < p_httpt->file[i]->i_buffer_valid )
1530                 {
1531                     /* there is data */
1532                     b_wait = VLC_FALSE;
1533                 }
1534             }
1535         }
1536         vlc_mutex_unlock( &p_httpt->file_lock );
1537         if( b_wait ) msleep( 100 );
1538     }
1539     msg_Info( p_httpt, "httpd stopped" );
1540
1541     _UnregisterFile( p_httpt, p_page_401 );
1542     _UnregisterFile( p_httpt, p_page_404 );
1543     _UnregisterFile( p_httpt, p_page_admin );
1544 }
1545