* configure.ac.in, modules/misc/httpd.c: compilation fixes for win32.
[vlc.git] / modules / misc / httpd.c
1 /*****************************************************************************
2  * httpd.c
3  *****************************************************************************
4  * Copyright (C) 2001-2003 VideoLAN
5  * $Id: httpd.c,v 1.2 2003/02/24 11:14:16 gbazin 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(a)    closesocket(a)
77 #else
78 #define SOCKET_CLOSE(a)    close(a)
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 #if !defined( WIN32 ) && !defined( UNDER_CE )
400     int i_flags;
401 #endif
402
403     if( BuildAddr( &sock, psz_host_addr, i_port ) )
404     {
405         msg_Err( p_httpt, "cannot build address for %s:%d", psz_host_addr, i_port );
406         return NULL;
407     }
408
409     /* is it already declared ? */
410     vlc_mutex_lock( &p_httpt->host_lock );
411     for( i = 0; i < p_httpt->i_host_count; i++ )
412     {
413         if( p_httpt->host[i]->sock.sin_port == sock.sin_port &&
414             p_httpt->host[i]->sock.sin_addr.s_addr == sock.sin_addr.s_addr )
415         {
416             break;
417         }
418     }
419
420     if( i < p_httpt->i_host_count )
421     {
422         /* yes, increment ref count and succed */
423         p_httpt->host[i]->i_ref++;
424         vlc_mutex_unlock( &p_httpt->host_lock );
425         return NULL;
426     }
427
428     /* need to add a new listening socket */
429
430     /* open socket */
431     fd = socket( AF_INET, SOCK_STREAM, 0 );
432     if( fd < 0 )
433     {
434         msg_Err( p_httpt, "cannot open socket" );
435         goto socket_failed;
436     }
437     /* reuse socket */
438     i_opt = 1;
439     if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
440                     (void *) &i_opt, sizeof( i_opt ) ) < 0 )
441     {
442         msg_Warn( p_httpt, "cannot configure socket (SO_REUSEADDR)" );
443     }
444     /* bind it */
445     if( bind( fd, (struct sockaddr *)&sock, sizeof( struct sockaddr_in ) ) < 0 )
446     {
447         msg_Err( p_httpt, "cannot bind socket" );
448         goto socket_failed;
449     }
450     /* set to non-blocking */
451 #if defined( WIN32 ) || defined( UNDER_CE )
452     {
453         unsigned long i_dummy = 1;
454         if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
455         {
456             msg_Err( p_httpt, "cannot set socket to non-blocking mode" );
457             goto socket_failed;
458         }
459     }
460 #else
461     if( ( i_flags = fcntl( fd, F_GETFL, 0 ) ) < 0 )
462     {
463         msg_Err( p_httpt, "cannot F_GETFL socket" );
464         goto socket_failed;
465     }
466     if( fcntl( fd, F_SETFL, i_flags | O_NONBLOCK ) < 0 )
467     {
468         msg_Err( p_httpt, "cannot F_SETFL O_NONBLOCK" );
469         goto socket_failed;
470     }
471 #endif
472     /* listen */
473     if( listen( fd, LISTEN_BACKLOG ) < 0 )
474     {
475         msg_Err( p_httpt, "cannot listen socket" );
476         goto socket_failed;
477     }
478
479     if( p_httpt->host )
480     {
481         p_httpt->host = realloc( p_httpt->host, sizeof( httpd_host_t *)  * ( p_httpt->i_host_count + 1 ) );
482     }
483     else
484     {
485         p_httpt->host = malloc( sizeof( httpd_host_t *) );
486     }
487     p_host                = malloc( sizeof( httpd_host_t ) );
488     p_host->i_ref         = 1;
489     p_host->psz_host_addr = strdup( psz_host_addr );
490     p_host->i_port        = i_port;
491     p_host->sock          = sock;
492     p_host->fd            = fd;
493
494     p_httpt->host[p_httpt->i_host_count++] = p_host;
495     vlc_mutex_unlock( &p_httpt->host_lock );
496
497     return p_host;
498
499 socket_failed:
500     vlc_mutex_unlock( &p_httpt->host_lock );
501     if( fd >= 0 )
502     {
503         SOCKET_CLOSE( fd );
504     }
505     return NULL;
506 }
507 static httpd_host_t     *RegisterHost( httpd_t *p_httpd, char *psz_host_addr, int i_port )
508 {
509     return( _RegisterHost( p_httpd->p_sys, psz_host_addr, i_port ) );
510 }
511
512 /*
513  * remove a listening host for an httpd instance
514  */
515 static void            _UnregisterHost( httpd_sys_t *p_httpt, httpd_host_t *p_host )
516 {
517     int i;
518
519     vlc_mutex_lock( &p_httpt->host_lock );
520     for( i = 0; i < p_httpt->i_host_count; i++ )
521     {
522         if( p_httpt->host[i] == p_host )
523         {
524             break;
525         }
526     }
527     if( i >= p_httpt->i_host_count )
528     {
529         vlc_mutex_unlock( &p_httpt->host_lock );
530         msg_Err( p_httpt, "cannot unregister host" );
531         return;
532     }
533
534     p_host->i_ref--;
535
536     if( p_host->i_ref > 0 )
537     {
538         /* still in use */
539         vlc_mutex_unlock( &p_httpt->host_lock );
540         return;
541     }
542
543     /* no more used */
544     FREE( p_host->psz_host_addr );
545     SOCKET_CLOSE( p_host->fd );
546
547     FREE( p_host );
548
549     if( p_httpt->i_host_count <= 1 )
550     {
551         FREE( p_httpt->host );
552         p_httpt->i_host_count = 0;
553     }
554     else
555     {
556         int i_move;
557
558         i_move = p_httpt->i_host_count - i - 1;
559
560         if( i_move > 0 )
561         {
562             memmove( &p_httpt->host[i],
563                      &p_httpt->host[i+1],
564                      i_move * sizeof( httpd_host_t * ) );
565         }
566
567         p_httpt->i_host_count--;
568         p_httpt->host = realloc( p_httpt->host,
569                                  p_httpt->i_host_count * sizeof( httpd_host_t * ) );
570     }
571
572     vlc_mutex_unlock( &p_httpt->host_lock );
573 }
574 static void             UnregisterHost( httpd_t *p_httpd, httpd_host_t *p_host )
575 {
576     _UnregisterHost( p_httpd->p_sys, p_host );
577 }
578
579
580 static void __RegisterFile( httpd_sys_t *p_httpt, httpd_file_t *p_file )
581 {
582     /* add a new file */
583     if( p_httpt->i_file_count )
584     {
585         p_httpt->file = realloc( p_httpt->file, sizeof( httpd_file_t *)  * ( p_httpt->i_file_count + 1 ) );
586     }
587     else
588     {
589         p_httpt->file = malloc( sizeof( httpd_file_t *) );
590     }
591
592     p_httpt->file[p_httpt->i_file_count++] = p_file;
593 }
594
595 static httpd_file_t    *_RegisterFile( httpd_sys_t *p_httpt,
596                                        char *psz_file, char *psz_mime,
597                                        char *psz_user, char *psz_password,
598                                        httpd_file_callback pf_fill,
599                                        httpd_file_callback_args_t *p_args )
600 {
601     httpd_file_t    *p_file;
602     int i;
603
604     vlc_mutex_lock( &p_httpt->file_lock );
605     for( i = 0; i < p_httpt->i_file_count; i++ )
606     {
607         if( !strcmp( psz_file, p_httpt->file[i]->psz_file ) )
608         {
609             break;
610         }
611     }
612     if( i < p_httpt->i_file_count )
613     {
614         vlc_mutex_unlock( &p_httpt->file_lock );
615         msg_Err( p_httpt, "%s already registered", psz_file );
616         return NULL;
617     }
618
619     p_file              = malloc( sizeof( httpd_file_t ) );
620     p_file->i_ref       = 0;
621     p_file->psz_file    = strdup( psz_file );
622     p_file->psz_mime    = strdup( psz_mime );
623     if( psz_user && *psz_user )
624     {
625         p_file->i_authenticate_method = HTTPD_AUTHENTICATE_BASIC;
626         p_file->psz_user              = strdup( psz_user );
627         p_file->psz_password          = strdup( psz_password );
628     }
629     else
630     {
631         p_file->i_authenticate_method = HTTPD_AUTHENTICATE_NONE;
632         p_file->psz_user              = NULL;
633         p_file->psz_password          = NULL;
634     }
635
636     p_file->b_stream        = VLC_FALSE;
637     p_file->p_sys           = p_args;
638     p_file->pf_fill         = pf_fill;
639
640     p_file->i_buffer_size   = 0;
641     p_file->i_buffer_valid  = 0;
642     p_file->i_buffer        = 0;
643     p_file->p_buffer        = NULL;
644
645     __RegisterFile( p_httpt, p_file );
646
647     vlc_mutex_unlock( &p_httpt->file_lock );
648
649     return p_file;
650 }
651 static httpd_file_t     *RegisterFile( httpd_t *p_httpd,
652                                        char *psz_file, char *psz_mime,
653                                        char *psz_user, char *psz_password,
654                                        httpd_file_callback pf_fill,
655                                        httpd_file_callback_args_t *p_args )
656 {
657     return( _RegisterFile( p_httpd->p_sys,
658                            psz_file, psz_mime, psz_user, psz_password,
659                            pf_fill, p_args ) );
660 }
661
662 static httpd_stream_t  *_RegisterStream( httpd_sys_t *p_httpt,
663                                          char *psz_file, char *psz_mime,
664                                          char *psz_user, char *psz_password )
665 {
666     httpd_stream_t    *p_stream;
667     int i;
668
669     vlc_mutex_lock( &p_httpt->file_lock );
670     for( i = 0; i < p_httpt->i_file_count; i++ )
671     {
672         if( !strcmp( psz_file, p_httpt->file[i]->psz_file ) )
673         {
674             break;
675         }
676     }
677     if( i < p_httpt->i_file_count )
678     {
679         vlc_mutex_unlock( &p_httpt->file_lock );
680         msg_Err( p_httpt, "%s already registeret", psz_file );
681         return NULL;
682     }
683
684     p_stream              = malloc( sizeof( httpd_stream_t ) );
685     p_stream->i_ref       = 0;
686     p_stream->psz_file    = strdup( psz_file );
687     p_stream->psz_mime    = strdup( psz_mime );
688     if( psz_user && *psz_user )
689     {
690         p_stream->i_authenticate_method = HTTPD_AUTHENTICATE_BASIC;
691         p_stream->psz_user              = strdup( psz_user );
692         p_stream->psz_password          = strdup( psz_password );
693     }
694     else
695     {
696         p_stream->i_authenticate_method = HTTPD_AUTHENTICATE_NONE;
697         p_stream->psz_user              = NULL;
698         p_stream->psz_password          = NULL;
699     }
700
701     p_stream->b_stream        = VLC_TRUE;
702     p_stream->p_sys           = NULL;
703     p_stream->pf_fill         = NULL;
704     p_stream->i_buffer_size   = 1024*1024;
705     p_stream->i_buffer_valid  = 0;
706     p_stream->i_buffer        = 0;
707     p_stream->p_buffer        = malloc( p_stream->i_buffer_size );
708
709     __RegisterFile( p_httpt, p_stream );
710
711     vlc_mutex_unlock( &p_httpt->file_lock );
712
713     return p_stream;
714 }
715 static httpd_stream_t   *RegisterStream( httpd_t *p_httpd,
716                                          char *psz_file, char *psz_mime,
717                                          char *psz_user, char *psz_password )
718 {
719     return( _RegisterStream( p_httpd->p_sys,
720                              psz_file, psz_mime, psz_user, psz_password ) );
721 }
722
723 static void            _UnregisterFile( httpd_sys_t *p_httpt, httpd_file_t *p_file )
724 {
725     int i;
726
727     vlc_mutex_lock( &p_httpt->file_lock );
728     for( i = 0; i < p_httpt->i_file_count; i++ )
729     {
730         if( !strcmp( p_file->psz_file, p_httpt->file[i]->psz_file ) )
731         {
732             break;
733         }
734     }
735     if( i >= p_httpt->i_file_count )
736     {
737         vlc_mutex_unlock( &p_httpt->file_lock );
738         msg_Err( p_httpt, "cannot unregister file" );
739         return;
740     }
741
742     if( p_file->i_ref > 0 )
743     {
744         httpd_connection_t *p_con;
745         /* force closing all connection for this file */
746         msg_Err( p_httpt, "closing all client connection" );
747
748         vlc_mutex_lock( &p_httpt->connection_lock );
749         for( p_con = p_httpt->p_first_connection; p_con != NULL; )
750         {
751             httpd_connection_t *p_next;
752
753             p_next = p_con->p_next;
754             if( p_con->p_file == p_file )
755             {
756                 httpd_ConnnectionClose( p_httpt, p_con );
757             }
758             p_con = p_next;
759         }
760         vlc_mutex_unlock( &p_httpt->connection_lock );
761     }
762
763     FREE( p_file->psz_file );
764     FREE( p_file->psz_mime );
765     if( p_file->i_authenticate_method != HTTPD_AUTHENTICATE_NONE )
766     {
767         FREE( p_file->psz_user );
768         FREE( p_file->psz_password );
769     }
770     FREE( p_file->p_buffer );
771
772     FREE( p_file );
773
774
775     if( p_httpt->i_file_count == 1 )
776     {
777         FREE( p_httpt->file );
778         p_httpt->i_file_count = 0;
779     }
780     else
781     {
782         int i_move;
783
784         i_move = p_httpt->i_file_count - i - 1;
785         if( i_move > 0  )
786         {
787             memmove( &p_httpt->file[i], &p_httpt->file[i + 1], sizeof( httpd_file_t *) * i_move );
788         }
789         p_httpt->i_file_count--;
790         p_httpt->file = realloc( p_httpt->file, sizeof( httpd_file_t *) * p_httpt->i_file_count );
791     }
792
793     vlc_mutex_unlock( &p_httpt->file_lock );
794 }
795 static void            UnregisterFile( httpd_t *p_httpd, httpd_file_t *p_file )
796 {
797     _UnregisterFile( p_httpd->p_sys, p_file );
798 }
799
800 static void             UnregisterStream( httpd_t *p_httpd, httpd_stream_t *p_stream )
801 {
802     _UnregisterFile( p_httpd->p_sys, p_stream );
803 }
804
805
806
807 static int             _SendStream( httpd_sys_t *p_httpt, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
808 {
809     if( i_data <= 0 )
810     {
811         return( VLC_SUCCESS );
812     }
813
814     vlc_mutex_lock( &p_httpt->file_lock );
815     if( p_stream->i_buffer_size < p_stream->i_buffer_valid + i_data )
816     {
817         /* not enough room */
818         if( p_stream->i_buffer < p_stream->i_buffer_valid )
819         {
820             memmove( p_stream->p_buffer,
821                      p_stream->p_buffer + p_stream->i_buffer,
822                      p_stream->i_buffer_valid - p_stream->i_buffer );
823         }
824         p_stream->i_buffer_valid -= p_stream->i_buffer;
825
826         p_stream->i_buffer = 0;
827     }
828     i_data = __MIN( i_data, p_stream->i_buffer_size - p_stream->i_buffer_valid );
829     memcpy( p_stream->p_buffer + p_stream->i_buffer_valid, p_data, i_data );
830     p_stream->i_buffer_valid += i_data;
831
832     vlc_mutex_unlock( &p_httpt->file_lock );
833
834     return( VLC_SUCCESS );
835 }
836 static int             SendStream( httpd_t *p_httpd, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
837 {
838     return( _SendStream( p_httpd->p_sys, p_stream, p_data, i_data ) );
839 }
840
841 /****************************************************************************/
842 /****************************************************************************/
843 /****************************************************************************/
844 /****************************************************************************/
845 /****************************************************************************/
846
847 static int  httpd_page_401_fill( httpd_file_callback_args_t *p_args, uint8_t **pp_data, int *pi_data )
848 {
849     char *p;
850
851     p = *pp_data = malloc( 1024 );
852
853     p += sprintf( p, "<html>\n" );
854     p += sprintf( p, "<head>\n" );
855     p += sprintf( p, "<title>Error 401</title>\n" );
856     p += sprintf( p, "</head>\n" );
857     p += sprintf( p, "<body>\n" );
858     p += sprintf( p, "<h1><center> 401 authentification needed</center></h1>\n" );
859     p += sprintf( p, "<hr />\n" );
860     p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
861     p += sprintf( p, "</body>\n" );
862     p += sprintf( p, "</html>\n" );
863
864     *pi_data = strlen( *pp_data ) + 1;
865
866     return VLC_SUCCESS;
867 }
868 static int  httpd_page_404_fill( httpd_file_callback_args_t *p_args, uint8_t **pp_data, int *pi_data )
869 {
870     char *p;
871
872     p = *pp_data = malloc( 1024 );
873
874     p += sprintf( p, "<html>\n" );
875     p += sprintf( p, "<head>\n" );
876     p += sprintf( p, "<title>Error 404</title>\n" );
877     p += sprintf( p, "</head>\n" );
878     p += sprintf( p, "<body>\n" );
879     p += sprintf( p, "<h1><center> 404 Ressource not found</center></h1>\n" );
880     p += sprintf( p, "<hr />\n" );
881     p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
882     p += sprintf( p, "</body>\n" );
883     p += sprintf( p, "</html>\n" );
884
885     *pi_data = strlen( *pp_data ) + 1;
886
887     return VLC_SUCCESS;
888 }
889
890 static int  httpd_page_admin_fill( httpd_file_callback_args_t *p_args, uint8_t **pp_data, int *pi_data )
891 {
892     httpd_sys_t *p_httpt = (httpd_sys_t*)p_args;
893     httpd_connection_t *p_con;
894     char *p;
895     int i;
896
897     /* FIXME FIXME do not use static size FIXME FIXME*/
898     p = *pp_data = malloc( 8096 );
899
900     p += sprintf( p, "<html>\n" );
901     p += sprintf( p, "<head>\n" );
902     p += sprintf( p, "<title>VideoLAN Client Stream Output</title>\n" );
903     p += sprintf( p, "</head>\n" );
904     p += sprintf( p, "<body>\n" );
905     p += sprintf( p, "<h1><center>VideoLAN Client Stream Output</center></h1>\n" );
906     p += sprintf( p, "<h2><center>Admin page</center></h2>\n" );
907
908     /* host list */
909     vlc_mutex_lock( &p_httpt->host_lock );
910     p += sprintf( p, "<h3>Host list</h3>\n" );
911     p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
912     p += sprintf( p, "<tr>\n<th>Host</th><th>Port</th><th>IP</th>\n</tr>\n" );
913
914     for( i = 0; i < p_httpt->i_host_count; i++ )
915     {
916         p += sprintf( p, "<tr>\n" );
917         p += sprintf( p, "<td>%s</td>\n", p_httpt->host[i]->psz_host_addr );
918         p += sprintf( p, "<td>%d</td>\n", p_httpt->host[i]->i_port );
919         p += sprintf( p, "<td>%s</td>\n", inet_ntoa( p_httpt->host[i]->sock.sin_addr ) );
920         p += sprintf( p, "</tr>\n" );
921     }
922     p += sprintf( p, "</table>\n" );
923     vlc_mutex_unlock( &p_httpt->host_lock );
924
925     /* file list */
926     /* XXX do not take lock on file_lock */
927     p += sprintf( p, "<h3>File list</h3>\n" );
928     p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
929     p += sprintf( p, "<tr>\n<th>Name</th><th>Mime</th><th>Protected</th><th>Used</th>\n</tr>\n" );
930
931     for( i = 0; i < p_httpt->i_file_count; i++ )
932     {
933         if( !p_httpt->file[i]->b_stream )
934         {
935             p += sprintf( p, "<tr>\n" );
936             p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_file );
937             p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_mime );
938             p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_user ? "Yes" : "No" );
939             p += sprintf( p, "<td>%d</td>\n", p_httpt->file[i]->i_ref);
940             p += sprintf( p, "</tr>\n" );
941         }
942     }
943     p += sprintf( p, "</table>\n" );
944
945     /* stream list */
946     /* XXX do not take lock on file_lock */
947     p += sprintf( p, "<h3>Stream list</h3>\n" );
948     p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
949     p += sprintf( p, "<tr>\n<th>Name</th><th>Mime</th><th>Protected</th><th>Used</th>\n</tr>\n" );
950
951     for( i = 0; i < p_httpt->i_file_count; i++ )
952     {
953         if( p_httpt->file[i]->b_stream )
954         {
955             p += sprintf( p, "<tr>\n" );
956             p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_file );
957             p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_mime );
958             p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_user ? "Yes" : "No" );
959             p += sprintf( p, "<td>%d</td>\n", p_httpt->file[i]->i_ref);
960             p += sprintf( p, "</tr>\n" );
961         }
962     }
963     p += sprintf( p, "</table>\n" );
964
965     /* connection list */
966     /* XXX do not take lock on connection_lock */
967     p += sprintf( p, "<h3>Connection list</h3>\n" );
968     p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
969     p += sprintf( p, "<tr>\n<th>IP</th><th>Requested File</th><th>Status</th>\n</tr>\n" );
970
971     for( p_con = p_httpt->p_first_connection;p_con != NULL; p_con = p_con->p_next )
972     {
973         p += sprintf( p, "<tr>\n" );
974         p += sprintf( p, "<td>%s</td>\n", inet_ntoa( p_con->sock.sin_addr ) );
975         p += sprintf( p, "<td>%s</td>\n", p_con->psz_file );
976         p += sprintf( p, "<td>%d</td>\n", p_con->i_http_error );
977         p += sprintf( p, "</tr>\n" );
978     }
979     p += sprintf( p, "</table>\n" );
980
981
982     /* www.videolan.org */
983     p += sprintf( p, "<hr />\n" );
984     p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
985     p += sprintf( p, "</body>\n" );
986     p += sprintf( p, "</html>\n" );
987
988     *pi_data = strlen( *pp_data ) + 1;
989
990     return VLC_SUCCESS;
991 }
992
993
994 static void httpd_ConnnectionNew( httpd_sys_t *p_httpt, int fd, struct sockaddr_in *p_sock )
995 {
996     httpd_connection_t *p_con;
997
998     msg_Dbg( p_httpt, "new connection from %s", inet_ntoa( p_sock->sin_addr ) );
999
1000     /* create a new connection and link it */
1001     p_con = malloc( sizeof( httpd_connection_t ) );
1002     p_con->i_state  = HTTPD_CONNECTION_RECEIVING_REQUEST;
1003     p_con->fd       = fd;
1004     p_con->sock     = *p_sock;
1005     p_con->psz_file = NULL;
1006     p_con->i_http_error = 0;
1007     p_con->psz_user = NULL;
1008     p_con->psz_password = NULL;
1009     p_con->p_file   = NULL;
1010
1011     p_con->i_buffer = 0;
1012     p_con->i_buffer_size = 8096;
1013     p_con->p_buffer = malloc( p_con->i_buffer_size );
1014
1015     p_con->p_next = NULL;
1016
1017     if( p_httpt->p_first_connection )
1018     {
1019         httpd_connection_t *p_last;
1020
1021         p_last = p_httpt->p_first_connection;
1022         while( p_last->p_next )
1023         {
1024             p_last = p_last->p_next;
1025         }
1026
1027         p_last->p_next = p_con;
1028         p_con->p_prev = p_last;
1029     }
1030     else
1031     {
1032         p_con->p_prev = NULL;
1033
1034         p_httpt->p_first_connection = p_con;
1035     }
1036
1037     p_httpt->i_connection_count++;
1038 }
1039
1040 static void httpd_ConnnectionClose( httpd_sys_t *p_httpt, httpd_connection_t *p_con )
1041 {
1042     msg_Dbg( p_httpt, "close connection from %s", inet_ntoa( p_con->sock.sin_addr ) );
1043
1044     p_httpt->i_connection_count--;
1045     /* first cut out from list */
1046     if( p_con->p_prev )
1047     {
1048         p_con->p_prev->p_next = p_con->p_next;
1049     }
1050     else
1051     {
1052         p_httpt->p_first_connection = p_con->p_next;
1053     }
1054
1055     if( p_con->p_next )
1056     {
1057         p_con->p_next->p_prev = p_con->p_prev;
1058     }
1059
1060     if( p_con->p_file ) p_con->p_file->i_ref--;
1061     FREE( p_con->psz_file );
1062
1063     FREE( p_con->p_buffer );
1064     SOCKET_CLOSE( p_con->fd );
1065
1066
1067     FREE( p_con->psz_user );
1068     FREE( p_con->psz_password );
1069
1070     free( p_con );
1071 }
1072
1073 static void httpd_RequestGetWord( char *word, int i_word_max, char **pp_buffer, char *p_end )
1074 {
1075     char *p = *pp_buffer;
1076     int i;
1077
1078     while( p < p_end && *p && ( *p == ' ' || *p == '\t' ) )
1079     {
1080         p++;
1081     }
1082
1083     i = 0;
1084     for( i = 0; i < i_word_max && p < p_end && *p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r'; i++,p++)
1085     {
1086         word[i] = *p;
1087     }
1088
1089     word[__MIN( i, i_word_max -1 )] = '\0';
1090
1091     *pp_buffer = p;
1092
1093 }
1094 static int httpd_RequestNextLine( char **pp_buffer, char *p_end )
1095 {
1096     char *p;
1097
1098     for( p = *pp_buffer; p < p_end; p++ )
1099     {
1100         if( p + 1 < p_end && *p == '\n' )
1101         {
1102             *pp_buffer = p + 1;
1103             return VLC_SUCCESS;
1104         }
1105         if( p + 2 < p_end && p[0] == '\r' && p[1] == '\n' )
1106         {
1107             *pp_buffer = p + 2;
1108             return VLC_SUCCESS;
1109         }
1110     }
1111     *pp_buffer = p_end;
1112     return VLC_EGENERIC;
1113 }
1114
1115 //char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1116 static void b64_decode( char *dest, char *src )
1117 {
1118     int  i_level;
1119     int  last = 0;
1120     int  b64[256] = {
1121         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 00-0F */
1122         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 10-1F */
1123         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,  /* 20-2F */
1124         52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,  /* 30-3F */
1125         -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,  /* 40-4F */
1126         15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,  /* 50-5F */
1127         -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,  /* 60-6F */
1128         41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,  /* 70-7F */
1129         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 80-8F */
1130         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 90-9F */
1131         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* A0-AF */
1132         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* B0-BF */
1133         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* C0-CF */
1134         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* D0-DF */
1135         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* E0-EF */
1136         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1   /* F0-FF */
1137         };
1138
1139     for( i_level = 0; *src != '\0' > 0; src++ )
1140     {
1141         int  c;
1142
1143         c = b64[(unsigned int)*src];
1144         if( c == -1 )
1145         {
1146             src++;
1147             continue;
1148         }
1149
1150         switch( i_level )
1151         {
1152             case 0:
1153                 i_level++;
1154                 break;
1155             case 1:
1156                 *dest++ = ( last << 2 ) | ( ( c >> 4)&0x03 );
1157                 i_level++;
1158                 break;
1159             case 2:
1160                 *dest++ = ( ( last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f );
1161                 i_level++;
1162                 break;
1163             case 3:
1164                 *dest++ = ( ( last &0x03 ) << 6 ) | c;
1165                 i_level = 0;
1166         }
1167         last = c;
1168     }
1169
1170     *dest = '\0';
1171 }
1172
1173 static void httpd_ConnectionParseRequest( httpd_sys_t *p_httpt, httpd_connection_t *p_con )
1174 {
1175     char *psz_status;
1176     char *p, *p_end;
1177
1178     int  i;
1179     char command[32];
1180     char url[1024];
1181     char version[32];
1182     char user[512] = "";
1183     char password[512] = "";
1184
1185     //msg_Dbg( p_httpt, "new request=\n%s", p_con->p_buffer );
1186
1187     p = p_con->p_buffer;
1188     p_end = p + strlen( p ) + 1;
1189
1190     httpd_RequestGetWord( command, 32, &p, p_end );
1191     httpd_RequestGetWord( url, 1024, &p, p_end );
1192     httpd_RequestGetWord( version, 32, &p, p_end );
1193     //msg_Dbg( p_httpt, "ask =%s= =%s= =%s=", command, url, version );
1194
1195     if( strcmp( command, "GET" ) )
1196     {
1197         /* unimplemented */
1198         p_con->psz_file = strdup( "/501.html" );
1199         p_con->i_http_error = 501;
1200         goto create_header;
1201     }
1202
1203     if( strcmp( version, "HTTP/1.0" ) && strcmp( version, "HTTP/1.1" ) )
1204     {
1205         p_con->psz_file = strdup( "/505.html" );
1206         p_con->i_http_error = 505;
1207
1208         goto create_header;
1209     }
1210
1211     /* parse headers */
1212     for( ;; )
1213     {
1214         char header[1024];
1215
1216         if( httpd_RequestNextLine( &p, p_end ) )
1217         {
1218             //msg_Dbg( p_httpt, "failled new line" );
1219             break;;
1220         }
1221         //msg_Dbg( p_httpt, "new line=%s", p );
1222
1223         httpd_RequestGetWord( header, 1024, &p, p_end );
1224
1225         if( !strcmp( header, "Authorization:" ) )
1226         {
1227             char method[32];
1228
1229             httpd_RequestGetWord( method, 32, &p, p_end );
1230             if( !strcasecmp( method, "BASIC" ) )
1231             {
1232                 char basic[1024];
1233                 char decoded[1024];
1234
1235                 httpd_RequestGetWord( basic, 1024, &p, p_end );
1236                 //msg_Dbg( p_httpt, "Authorization: basic:%s", basic );
1237                 b64_decode( decoded, basic );
1238
1239                 //msg_Dbg( p_httpt, "Authorization: decoded:%s", decoded );
1240                 if( strchr( decoded, ':' ) )
1241                 {
1242                     char *p = strchr( decoded, ':' );
1243
1244                     p[0] = '\0'; p++;
1245                     strcpy( user, decoded );
1246                     strcpy( password, p );
1247                 }
1248             }
1249         }
1250     }
1251
1252     p_con->psz_file = strdup( url );
1253     p_con->i_http_error = 200;
1254
1255 create_header:
1256     //msg_Dbg( p_httpt, "ask %s %s %d", command, p_con->psz_file, p_con->i_http_error );
1257     FREE( p_con->p_buffer );
1258     p_con->i_buffer = 0;
1259     p_con->i_buffer_size = 0;
1260
1261     //vlc_mutex_lock( &p_httpt->file_lock );
1262 search_file:
1263     /* search file */
1264     for( i = 0, p_con->p_file = NULL; i < p_httpt->i_file_count; i++ )
1265     {
1266         if( !strcmp( p_httpt->file[i]->psz_file, p_con->psz_file ) )
1267         {
1268             p_con->p_file = p_httpt->file[i];
1269         }
1270     }
1271
1272     if( !p_con->p_file )
1273     {
1274         p_con->psz_file = strdup( "/404.html" );
1275         p_con->i_http_error = 404;
1276
1277         /* XXX be sure that "/404.html" exist else ... */
1278         goto search_file;
1279     }
1280
1281     if( p_con->p_file->i_authenticate_method == HTTPD_AUTHENTICATE_BASIC )
1282     {
1283         if( strcmp( user, p_con->p_file->psz_user ) || strcmp( password, p_con->p_file->psz_password ) )
1284         {
1285             p_con->psz_file = strdup( "/401.html" );
1286             strcpy( user, p_con->p_file->psz_user );
1287             p_con->i_http_error = 401;
1288
1289             /* XXX do not put password on 404 else ... */
1290             goto search_file;
1291         }
1292     }
1293
1294     p_con->p_file->i_ref++;
1295 //    vlc_mutex_unlock( &p_httpt->file_lock );
1296
1297     switch( p_con->i_http_error )
1298     {
1299         case 200:
1300             psz_status = "OK";
1301             break;
1302
1303         case 401:
1304             psz_status = "Authorization Required";
1305             break;
1306         default:
1307             psz_status = "Unknown";
1308             break;
1309     }
1310
1311     p_con->i_state = HTTPD_CONNECTION_SENDING_HEADER;
1312
1313     p_con->i_buffer_size = 4096;
1314     p_con->i_buffer = 0;
1315     p = p_con->p_buffer = malloc( p_con->i_buffer_size );
1316
1317     p += sprintf( p, "HTTP/1.0 %d %s\r\n", p_con->i_http_error, psz_status );
1318     p += sprintf( p, "Content-type: %s\r\n", p_con->p_file->psz_mime );
1319     if( p_con->i_http_error == 401 )
1320     {
1321         p += sprintf( p, "WWW-Authenticate: Basic realm=\"%s\"\r\n", user );
1322     }
1323     p += sprintf( p, "\r\n" );
1324
1325     p_con->i_buffer_size = strlen( p_con->p_buffer ) + 1;
1326
1327     //msg_Dbg( p_httpt, "answer=\n%s", p_con->p_buffer );
1328 }
1329 #define HTTPD_STREAM_PACKET 1300
1330 static void httpd_Thread( httpd_sys_t *p_httpt )
1331 {
1332     httpd_file_t    *p_page_admin;
1333     httpd_file_t    *p_page_401;
1334     httpd_file_t    *p_page_404;
1335
1336     httpd_connection_t *p_con;
1337     vlc_bool_t         b_wait;
1338
1339     msg_Info( p_httpt, "httpd started" );
1340
1341     p_page_401 = _RegisterFile( p_httpt,
1342                                 "/401.html", "text/html",
1343                                 NULL, NULL,
1344                                 httpd_page_401_fill,
1345                                 (httpd_file_callback_args_t*)NULL );
1346     p_page_404 = _RegisterFile( p_httpt,
1347                                 "/404.html", "text/html",
1348                                 NULL, NULL,
1349                                 httpd_page_404_fill,
1350                                 (httpd_file_callback_args_t*)NULL );
1351     p_page_admin = _RegisterFile( p_httpt,
1352                                   "/admin.html", "text/html",
1353                                   "admin", "salut",
1354                                   httpd_page_admin_fill,
1355                                   (httpd_file_callback_args_t*)p_httpt );
1356
1357     while( !p_httpt->b_die )
1358     {
1359         int i;
1360         if( p_httpt->i_host_count <= 0 )
1361         {
1362             msleep( 100 * 1000 );
1363             continue;
1364         }
1365         vlc_mutex_lock( &p_httpt->host_lock );
1366         /* accept/refuse new connection */
1367         for( i = 0; i < p_httpt->i_host_count; i++ )
1368         {
1369             int     i_sock_size = sizeof( struct sockaddr_in );
1370             struct  sockaddr_in sock;
1371             int     fd;
1372
1373             fd = accept( p_httpt->host[i]->fd, (struct sockaddr *)&sock,
1374                          &i_sock_size );
1375             if( fd > 0 )
1376             {
1377 #if defined( WIN32 ) || defined( UNDER_CE )
1378                 {
1379                     unsigned long i_dummy = 1;
1380                     ioctlsocket( fd, FIONBIO, &i_dummy );
1381                 }
1382 #else
1383                 fcntl( fd, F_SETFL, O_NONBLOCK );
1384 #endif
1385
1386                 if( p_httpt->i_connection_count >= HTTPD_MAX_CONNECTION )
1387                 {
1388                     msg_Warn( p_httpt, "max connection reached" );
1389                     SOCKET_CLOSE( fd );
1390                     continue;
1391                 }
1392                 /* create a new connection and link it */
1393                 httpd_ConnnectionNew( p_httpt, fd, &sock );
1394
1395             }
1396         }
1397         vlc_mutex_unlock( &p_httpt->host_lock );
1398
1399         vlc_mutex_lock( &p_httpt->file_lock );
1400         /* now do work for all connections */
1401         for( p_con = p_httpt->p_first_connection; p_con != NULL; )
1402         {
1403             if( p_con->i_state == HTTPD_CONNECTION_RECEIVING_REQUEST )
1404             {
1405                 int i_len;
1406                 /* read data */
1407                 i_len = recv( p_con->fd,
1408                               p_con->p_buffer + p_con->i_buffer,
1409                               p_con->i_buffer_size - p_con->i_buffer, 0 );
1410
1411                 if( ( i_len < 0 && errno != EAGAIN && errno != EINTR )||
1412                     ( i_len == 0 ) )
1413                 {
1414                     httpd_connection_t *p_next = p_con->p_next;
1415
1416                     httpd_ConnnectionClose( p_httpt, p_con );
1417                     p_con = p_next;
1418                 }
1419                 else if( i_len > 0 )
1420                 {
1421                     uint8_t *ptr;
1422
1423                     p_con->i_buffer += i_len;
1424
1425                     ptr = p_con->p_buffer + p_con->i_buffer;
1426
1427                     if( ( p_con->i_buffer >= 2 && !strncmp( ptr - 2, "\n\n", 2 ) )||
1428                         ( p_con->i_buffer >= 4 && !strncmp( ptr - 4, "\r\n\r\n", 4 ) ) ||
1429                         p_con->i_buffer >= p_con->i_buffer_size )
1430                     {
1431                         p_con->p_buffer[__MIN( p_con->i_buffer, p_con->i_buffer_size - 1 )] = '\0';
1432                         httpd_ConnectionParseRequest( p_httpt, p_con );
1433                     }
1434
1435                     p_con = p_con->p_next;
1436                 }
1437                 else
1438                 {
1439                     p_con = p_con->p_next;
1440                 }
1441                 continue;   /* just for clarity */
1442             }
1443             else if( p_con->i_state == HTTPD_CONNECTION_SENDING_HEADER || p_con->i_state == HTTPD_CONNECTION_SENDING_FILE )
1444             {
1445                 int i_len;
1446
1447                 /* write data */
1448                 i_len = send( p_con->fd, p_con->p_buffer + p_con->i_buffer, p_con->i_buffer_size - p_con->i_buffer, 0 );
1449
1450 //                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 );
1451
1452                 if( ( i_len < 0 && errno != EAGAIN && errno != EINTR )||
1453                     ( i_len == 0 ) )
1454                 {
1455                     httpd_connection_t *p_next = p_con->p_next;
1456
1457                     httpd_ConnnectionClose( p_httpt, p_con );
1458                     p_con = p_next;
1459                 }
1460                 else if( i_len > 0 )
1461                 {
1462                     p_con->i_buffer += i_len;
1463
1464                     if( p_con->i_buffer >= p_con->i_buffer_size )
1465                     {
1466                         if( p_con->i_state == HTTPD_CONNECTION_SENDING_HEADER )
1467                         {
1468                             p_con->i_buffer_size = 0;
1469                             p_con->i_buffer = 0;
1470                             FREE( p_con->p_buffer );
1471
1472                             if( !p_con->p_file->b_stream )
1473                             {
1474                                 p_con->i_state = HTTPD_CONNECTION_SENDING_FILE; // be sure to out from HTTPD_CONNECTION_SENDING_HEADER
1475                                 p_con->p_file->pf_fill( p_con->p_file->p_sys, &p_con->p_buffer, &p_con->i_buffer_size );
1476                             }
1477                             else
1478                             {
1479                                 p_con->i_state = HTTPD_CONNECTION_SENDING_STREAM;
1480                             }
1481                             p_con = p_con->p_next;
1482                         }
1483                         else
1484                         {
1485                             httpd_connection_t *p_next = p_con->p_next;
1486
1487                             httpd_ConnnectionClose( p_httpt, p_con );
1488                             p_con = p_next;
1489                         }
1490                     }
1491                     else
1492                     {
1493                         p_con = p_con->p_next;
1494                     }
1495                 }
1496                 else
1497                 {
1498                     p_con = p_con->p_next;
1499                 }
1500                 continue;   /* just for clarity */
1501             }
1502             else if( p_con->i_state == HTTPD_CONNECTION_SENDING_STREAM )
1503             {
1504                 httpd_file_t *p_file = p_con->p_file;
1505                 int i_len;
1506
1507                 //msg_Dbg( p_httpt, "buffer=%d buffer_size=%d", p_file->i_buffer, p_file->i_buffer_size );
1508                 if( p_file->i_buffer < p_file->i_buffer_valid )
1509                 {
1510                     int i_write;
1511                     /* write data */
1512                     i_write = __MIN( p_file->i_buffer_valid - p_file->i_buffer, HTTPD_STREAM_PACKET );
1513                     i_len = send( p_con->fd, p_file->p_buffer + p_file->i_buffer, i_write, 0 );
1514
1515                     if( ( i_len < 0 && errno != EAGAIN && errno != EINTR )||
1516                         ( i_len == 0 ) )
1517                     {
1518                         httpd_connection_t *p_next = p_con->p_next;
1519
1520                         httpd_ConnnectionClose( p_httpt, p_con );
1521                         p_con = p_next;
1522                     }
1523                     else
1524                     {
1525                         p_con = p_con->p_next;
1526                     }
1527                 }
1528                 else
1529                 {
1530                     p_con = p_con->p_next;
1531                 }
1532                 continue;   /* just for clarity */
1533             }
1534             else
1535             {
1536                 msg_Warn( p_httpt, "cannot occur (Invalid p_con->i_state)" );
1537                 p_con = p_con->p_next;
1538             }
1539         }   /* for over connection */
1540
1541
1542         b_wait = VLC_TRUE;
1543         /* update position for stream based file */
1544         for( i = 0; i < p_httpt->i_file_count; i++ )
1545         {
1546             if( p_httpt->file[i]->b_stream )
1547             {
1548                 p_httpt->file[i]->i_buffer += __MIN( p_httpt->file[i]->i_buffer_valid - p_httpt->file[i]->i_buffer,
1549                                                      HTTPD_STREAM_PACKET );
1550                 if( p_httpt->file[i]->i_buffer < p_httpt->file[i]->i_buffer_valid )
1551                 {
1552                     /* there is data */
1553                     b_wait = VLC_FALSE;
1554                 }
1555             }
1556         }
1557         vlc_mutex_unlock( &p_httpt->file_lock );
1558         if( b_wait ) msleep( 100 );
1559     }
1560     msg_Info( p_httpt, "httpd stopped" );
1561
1562     _UnregisterFile( p_httpt, p_page_401 );
1563     _UnregisterFile( p_httpt, p_page_404 );
1564     _UnregisterFile( p_httpt, p_page_admin );
1565 }