1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2001-2003 VideoLAN
5 * $Id: httpd.c,v 1.7 2003/03/06 11:09:56 fenrir Exp $
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
29 #include <sys/types.h>
39 #ifdef HAVE_SYS_TIME_H
40 # include <sys/time.h>
47 #if defined( UNDER_CE )
49 #elif defined( WIN32 )
50 # include <winsock2.h>
51 # include <ws2tcpip.h>
53 # define IN_MULTICAST(a) IN_CLASSD(a)
56 # include <netdb.h> /* hostent ... */
57 # include <sys/socket.h>
58 # include <netinet/in.h>
59 # ifdef HAVE_ARPA_INET_H
60 # include <arpa/inet.h> /* inet_ntoa(), inet_aton() */
67 # define INADDR_ANY 0x00000000
70 # define INADDR_NONE 0xFFFFFFFF
73 #define LISTEN_BACKLOG 100
74 #define HTTPD_MAX_CONNECTION 512
75 #define HTTPD_CONNECTION_MAX_UNUSED 10000000
77 #define FREE( p ) if( p ) { free( p); (p) = NULL; }
79 #if defined( WIN32 ) || defined( UNDER_CE )
80 #define SOCKET_CLOSE(a) closesocket(a)
82 #define SOCKET_CLOSE(a) close(a)
85 /*****************************************************************************
87 *****************************************************************************/
88 static int Open ( vlc_object_t * );
89 static void Close ( vlc_object_t * );
91 /*****************************************************************************
93 *****************************************************************************/
95 set_description( _("HTTP 1.0 daemon") );
96 set_capability( "httpd", 42 );
97 set_callbacks( Open, Close );
100 /*****************************************************************************
102 *****************************************************************************/
103 static httpd_host_t *RegisterHost ( httpd_t *, char *, int );
104 static void UnregisterHost ( httpd_t *, httpd_host_t * );
106 static httpd_file_t *RegisterFile ( httpd_t *,
107 char *psz_file, char *psz_mime,
108 char *psz_user, char *psz_password,
109 httpd_file_callback pf_fill,
110 httpd_file_callback_args_t *p_args );
111 static void UnregisterFile ( httpd_t *, httpd_file_t * );
113 //#define httpd_stream_t httpd_file_t
114 static httpd_stream_t *RegisterStream ( httpd_t *,
115 char *psz_file, char *psz_mime,
116 char *psz_user, char *psz_password );
117 static int SendStream ( httpd_t *, httpd_stream_t *, uint8_t *, int );
118 static int HeaderStream ( httpd_t *, httpd_stream_t *, uint8_t *, int );
119 static void UnregisterStream( httpd_t *, httpd_stream_t* );
121 /*****************************************************************************
122 * Internal definitions
123 *****************************************************************************/
131 struct sockaddr_in sock;
136 #define HTTPD_AUTHENTICATE_NONE 0
137 #define HTTPD_AUTHENTICATE_BASIC 1
139 //typedef httpd_file_t httpd_stream_t;
149 int i_authenticate_method;
150 char *psz_user; /* NULL if no auth */
151 char *psz_password; /* NULL if no auth */
153 vlc_bool_t b_stream; /* if false: httpd will retreive data by a callback
154 true: it's up to the program to give data to httpd */
155 void *p_sys; /* provided for user */
156 httpd_file_callback pf_fill; /* it should allocate and fill *pp_data and *pi_data */
160 /* circular buffer for stream only */
161 int i_buffer_size; /* buffer size, can't be reallocated smaller */
162 uint8_t *p_buffer; /* buffer */
163 int64_t i_buffer_pos; /* absolute position from begining */
164 int i_buffer_last_pos; /* a new connection will start with that */
166 /* data to be send at connection time (if any) */
172 #define HTTPD_CONNECTION_RECEIVING_REQUEST 1
173 #define HTTPD_CONNECTION_SENDING_HEADER 2
174 #define HTTPD_CONNECTION_SENDING_FILE 3
175 #define HTTPD_CONNECTION_SENDING_STREAM 4
177 typedef struct httpd_connection_s
179 struct httpd_connection_s *p_next;
180 struct httpd_connection_s *p_prev;
182 struct sockaddr_in sock;
184 mtime_t i_last_activity_date;
188 char *psz_file; // file to be send
189 int i_http_error; // error to be send with the file
190 char *psz_user; // if Authorization in the request header
193 httpd_file_t *p_file;
195 /* used while sending header and file */
198 int i_buffer; /* private */
200 /* used for stream */
201 int64_t i_stream_pos; /* absolute pos in stream */
202 } httpd_connection_t;
211 vlc_mutex_t host_lock;
212 volatile int i_host_count;
215 vlc_mutex_t file_lock;
219 vlc_mutex_t connection_lock;
220 int i_connection_count;
221 httpd_connection_t *p_first_connection;
224 static void httpd_Thread( httpd_sys_t *p_httpt );
225 static void httpd_ConnnectionNew( httpd_sys_t *, int , struct sockaddr_in * );
226 static void httpd_ConnnectionClose( httpd_sys_t *, httpd_connection_t * );
228 /*****************************************************************************
230 *****************************************************************************/
232 static int Open( vlc_object_t *p_this )
234 httpd_t *p_httpd = (httpd_t*)p_this;
235 httpd_sys_t *p_httpt;
237 /* Launch httpt thread */
238 if( !( p_httpt = vlc_object_create( p_this, sizeof( httpd_sys_t ) ) ) )
240 msg_Err( p_this, "out of memory" );
241 return( VLC_EGENERIC );
247 /* init httpt_t structure */
248 vlc_mutex_init( p_httpd, &p_httpt->host_lock );
249 p_httpt->i_host_count = 0;
250 p_httpt->host = NULL;
252 vlc_mutex_init( p_httpd, &p_httpt->file_lock );
253 p_httpt->i_file_count = 0;
254 p_httpt->file = NULL;
256 vlc_mutex_init( p_httpd, &p_httpt->connection_lock );
257 p_httpt->i_connection_count = 0;
258 p_httpt->p_first_connection = NULL;
260 /* start the thread */
261 if( vlc_thread_create( p_httpt, "httpd thread",
262 httpd_Thread, VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
264 msg_Err( p_this, "cannot spawn http thread" );
266 vlc_mutex_destroy( &p_httpt->host_lock );
267 vlc_mutex_destroy( &p_httpt->file_lock );
268 vlc_mutex_destroy( &p_httpt->connection_lock );
270 vlc_object_destroy( p_httpt );
271 return( VLC_EGENERIC );
274 msg_Info( p_httpd, "http thread launched" );
276 p_httpd->p_sys = p_httpt;
277 p_httpd->pf_register_host = RegisterHost;
278 p_httpd->pf_unregister_host = UnregisterHost;
279 p_httpd->pf_register_file = RegisterFile;
280 p_httpd->pf_unregister_file = UnregisterFile;
281 p_httpd->pf_register_stream = RegisterStream;
282 p_httpd->pf_header_stream = HeaderStream;
283 p_httpd->pf_send_stream = SendStream;
284 p_httpd->pf_unregister_stream=UnregisterStream;
286 return( VLC_SUCCESS );
289 /*****************************************************************************
290 * Close: close the target
291 *****************************************************************************/
292 static void Close( vlc_object_t * p_this )
294 httpd_t *p_httpd = (httpd_t*)p_this;
295 httpd_sys_t *p_httpt = p_httpd->p_sys;
297 httpd_connection_t *p_con;
301 vlc_thread_join( p_httpt );
303 /* first close all host */
304 vlc_mutex_destroy( &p_httpt->host_lock );
305 if( p_httpt->i_host_count )
307 msg_Err( p_httpd, "still have %d hosts registered !", p_httpt->i_host_count );
309 for( i = 0; i < p_httpt->i_host_count; i++ )
311 #define p_host p_httpt->host[i]
312 FREE( p_host->psz_host_addr );
313 SOCKET_CLOSE( p_host->fd );
318 FREE( p_httpt->host );
321 vlc_mutex_destroy( &p_httpt->file_lock );
322 if( p_httpt->i_file_count )
324 msg_Err( p_httpd, "still have %d files registered !", p_httpt->i_file_count );
326 for( i = 0; i < p_httpt->i_file_count; i++ )
328 #define p_file p_httpt->file[i]
329 FREE( p_file->psz_file );
330 FREE( p_file->psz_mime );
331 if( p_file->i_authenticate_method != HTTPD_AUTHENTICATE_NONE )
333 FREE( p_file->psz_user );
334 FREE( p_file->psz_password );
336 FREE( p_file->p_buffer );
341 FREE( p_httpt->file );
343 /* andd close all connection */
344 vlc_mutex_destroy( &p_httpt->connection_lock );
345 if( p_httpt->i_connection_count )
347 msg_Warn( p_httpd, "%d connections still in use", p_httpt->i_connection_count );
349 while( ( p_con = p_httpt->p_first_connection ) )
351 httpd_ConnnectionClose( p_httpt, p_con );
354 msg_Info( p_httpd, "httpd instance closed" );
355 vlc_object_destroy( p_httpt );
359 /****************************************************************************
360 ****************************************************************************
363 ****************************************************************************
364 ****************************************************************************/
365 static int BuildAddr( struct sockaddr_in * p_socket,
366 const char * psz_address, int i_port )
369 memset( p_socket, 0, sizeof( struct sockaddr_in ) );
370 p_socket->sin_family = AF_INET; /* family */
371 p_socket->sin_port = htons( (uint16_t)i_port );
374 p_socket->sin_addr.s_addr = INADDR_ANY;
378 struct hostent * p_hostent;
380 /* Try to convert address directly from in_addr - this will work if
381 * psz_address is dotted decimal. */
382 #ifdef HAVE_ARPA_INET_H
383 if( !inet_aton( psz_address, &p_socket->sin_addr ) )
385 p_socket->sin_addr.s_addr = inet_addr( psz_address );
386 if( p_socket->sin_addr.s_addr == INADDR_NONE )
389 /* We have a fqdn, try to find its address */
390 if ( (p_hostent = gethostbyname( psz_address )) == NULL )
395 /* Copy the first address of the host in the socket address */
396 memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0],
397 p_hostent->h_length );
405 * listen on a host for a httpd instance
408 static httpd_host_t *_RegisterHost( httpd_sys_t *p_httpt, char *psz_host_addr, int i_port )
410 httpd_host_t *p_host;
411 struct sockaddr_in sock;
415 #if !defined( WIN32 ) && !defined( UNDER_CE )
419 if( BuildAddr( &sock, psz_host_addr, i_port ) )
421 msg_Err( p_httpt, "cannot build address for %s:%d", psz_host_addr, i_port );
425 /* is it already declared ? */
426 vlc_mutex_lock( &p_httpt->host_lock );
427 for( i = 0; i < p_httpt->i_host_count; i++ )
429 if( p_httpt->host[i]->sock.sin_port == sock.sin_port &&
430 p_httpt->host[i]->sock.sin_addr.s_addr == sock.sin_addr.s_addr )
436 if( i < p_httpt->i_host_count )
438 /* yes, increment ref count and succed */
439 p_httpt->host[i]->i_ref++;
440 vlc_mutex_unlock( &p_httpt->host_lock );
441 return( p_httpt->host[i] );
444 /* need to add a new listening socket */
447 fd = socket( AF_INET, SOCK_STREAM, 0 );
450 msg_Err( p_httpt, "cannot open socket" );
455 if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
456 (void *) &i_opt, sizeof( i_opt ) ) < 0 )
458 msg_Warn( p_httpt, "cannot configure socket (SO_REUSEADDR)" );
461 if( bind( fd, (struct sockaddr *)&sock, sizeof( struct sockaddr_in ) ) < 0 )
463 msg_Err( p_httpt, "cannot bind socket" );
466 /* set to non-blocking */
467 #if defined( WIN32 ) || defined( UNDER_CE )
469 unsigned long i_dummy = 1;
470 if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
472 msg_Err( p_httpt, "cannot set socket to non-blocking mode" );
477 if( ( i_flags = fcntl( fd, F_GETFL, 0 ) ) < 0 )
479 msg_Err( p_httpt, "cannot F_GETFL socket" );
482 if( fcntl( fd, F_SETFL, i_flags | O_NONBLOCK ) < 0 )
484 msg_Err( p_httpt, "cannot F_SETFL O_NONBLOCK" );
489 if( listen( fd, LISTEN_BACKLOG ) < 0 )
491 msg_Err( p_httpt, "cannot listen socket" );
497 p_httpt->host = realloc( p_httpt->host, sizeof( httpd_host_t *) * ( p_httpt->i_host_count + 1 ) );
501 p_httpt->host = malloc( sizeof( httpd_host_t *) );
503 p_host = malloc( sizeof( httpd_host_t ) );
505 p_host->psz_host_addr = strdup( psz_host_addr );
506 p_host->i_port = i_port;
510 p_httpt->host[p_httpt->i_host_count++] = p_host;
511 vlc_mutex_unlock( &p_httpt->host_lock );
516 vlc_mutex_unlock( &p_httpt->host_lock );
523 static httpd_host_t *RegisterHost( httpd_t *p_httpd, char *psz_host_addr, int i_port )
525 return( _RegisterHost( p_httpd->p_sys, psz_host_addr, i_port ) );
529 * remove a listening host for an httpd instance
531 static void _UnregisterHost( httpd_sys_t *p_httpt, httpd_host_t *p_host )
535 vlc_mutex_lock( &p_httpt->host_lock );
536 for( i = 0; i < p_httpt->i_host_count; i++ )
538 if( p_httpt->host[i] == p_host )
543 if( i >= p_httpt->i_host_count )
545 vlc_mutex_unlock( &p_httpt->host_lock );
546 msg_Err( p_httpt, "cannot unregister host" );
552 if( p_host->i_ref > 0 )
555 vlc_mutex_unlock( &p_httpt->host_lock );
560 FREE( p_host->psz_host_addr );
561 SOCKET_CLOSE( p_host->fd );
565 if( p_httpt->i_host_count <= 1 )
567 FREE( p_httpt->host );
568 p_httpt->i_host_count = 0;
574 i_move = p_httpt->i_host_count - i - 1;
578 memmove( &p_httpt->host[i],
580 i_move * sizeof( httpd_host_t * ) );
583 p_httpt->i_host_count--;
584 p_httpt->host = realloc( p_httpt->host,
585 p_httpt->i_host_count * sizeof( httpd_host_t * ) );
588 vlc_mutex_unlock( &p_httpt->host_lock );
590 static void UnregisterHost( httpd_t *p_httpd, httpd_host_t *p_host )
592 _UnregisterHost( p_httpd->p_sys, p_host );
596 static void __RegisterFile( httpd_sys_t *p_httpt, httpd_file_t *p_file )
599 if( p_httpt->i_file_count )
601 p_httpt->file = realloc( p_httpt->file, sizeof( httpd_file_t *) * ( p_httpt->i_file_count + 1 ) );
605 p_httpt->file = malloc( sizeof( httpd_file_t *) );
608 p_httpt->file[p_httpt->i_file_count++] = p_file;
611 static httpd_file_t *_RegisterFile( httpd_sys_t *p_httpt,
612 char *psz_file, char *psz_mime,
613 char *psz_user, char *psz_password,
614 httpd_file_callback pf_fill,
615 httpd_file_callback_args_t *p_args )
617 httpd_file_t *p_file;
620 vlc_mutex_lock( &p_httpt->file_lock );
621 for( i = 0; i < p_httpt->i_file_count; i++ )
623 if( !strcmp( psz_file, p_httpt->file[i]->psz_file ) )
628 if( i < p_httpt->i_file_count )
630 vlc_mutex_unlock( &p_httpt->file_lock );
631 msg_Err( p_httpt, "%s already registered", psz_file );
635 p_file = malloc( sizeof( httpd_file_t ) );
637 p_file->psz_file = strdup( psz_file );
638 p_file->psz_mime = strdup( psz_mime );
639 if( psz_user && *psz_user )
641 p_file->i_authenticate_method = HTTPD_AUTHENTICATE_BASIC;
642 p_file->psz_user = strdup( psz_user );
643 p_file->psz_password = strdup( psz_password );
647 p_file->i_authenticate_method = HTTPD_AUTHENTICATE_NONE;
648 p_file->psz_user = NULL;
649 p_file->psz_password = NULL;
652 p_file->b_stream = VLC_FALSE;
653 p_file->p_sys = p_args;
654 p_file->pf_fill = pf_fill;
656 p_file->i_buffer_size = 0;
657 p_file->i_buffer_last_pos = 0;
658 p_file->i_buffer_pos = 0;
659 p_file->p_buffer = NULL;
661 p_file->i_header_size = 0;
662 p_file->p_header = NULL;
664 __RegisterFile( p_httpt, p_file );
666 vlc_mutex_unlock( &p_httpt->file_lock );
670 static httpd_file_t *RegisterFile( httpd_t *p_httpd,
671 char *psz_file, char *psz_mime,
672 char *psz_user, char *psz_password,
673 httpd_file_callback pf_fill,
674 httpd_file_callback_args_t *p_args )
676 return( _RegisterFile( p_httpd->p_sys,
677 psz_file, psz_mime, psz_user, psz_password,
681 static httpd_stream_t *_RegisterStream( httpd_sys_t *p_httpt,
682 char *psz_file, char *psz_mime,
683 char *psz_user, char *psz_password )
685 httpd_stream_t *p_stream;
688 vlc_mutex_lock( &p_httpt->file_lock );
689 for( i = 0; i < p_httpt->i_file_count; i++ )
691 if( !strcmp( psz_file, p_httpt->file[i]->psz_file ) )
696 if( i < p_httpt->i_file_count )
698 vlc_mutex_unlock( &p_httpt->file_lock );
699 msg_Err( p_httpt, "%s already registered", psz_file );
703 p_stream = malloc( sizeof( httpd_stream_t ) );
705 p_stream->psz_file = strdup( psz_file );
706 p_stream->psz_mime = strdup( psz_mime );
707 if( psz_user && *psz_user )
709 p_stream->i_authenticate_method = HTTPD_AUTHENTICATE_BASIC;
710 p_stream->psz_user = strdup( psz_user );
711 p_stream->psz_password = strdup( psz_password );
715 p_stream->i_authenticate_method = HTTPD_AUTHENTICATE_NONE;
716 p_stream->psz_user = NULL;
717 p_stream->psz_password = NULL;
720 p_stream->b_stream = VLC_TRUE;
721 p_stream->p_sys = NULL;
722 p_stream->pf_fill = NULL;
724 p_stream->i_buffer_size = 1024*1024*10;
725 p_stream->i_buffer_pos = 0;
726 p_stream->i_buffer_last_pos = 0;
727 p_stream->p_buffer = malloc( p_stream->i_buffer_size );
729 p_stream->i_header_size = 0;
730 p_stream->p_header = NULL;
732 __RegisterFile( p_httpt, p_stream );
734 vlc_mutex_unlock( &p_httpt->file_lock );
738 static httpd_stream_t *RegisterStream( httpd_t *p_httpd,
739 char *psz_file, char *psz_mime,
740 char *psz_user, char *psz_password )
742 return( _RegisterStream( p_httpd->p_sys,
743 psz_file, psz_mime, psz_user, psz_password ) );
746 static void _UnregisterFile( httpd_sys_t *p_httpt, httpd_file_t *p_file )
750 vlc_mutex_lock( &p_httpt->file_lock );
751 for( i = 0; i < p_httpt->i_file_count; i++ )
753 if( !strcmp( p_file->psz_file, p_httpt->file[i]->psz_file ) )
758 if( i >= p_httpt->i_file_count )
760 vlc_mutex_unlock( &p_httpt->file_lock );
761 msg_Err( p_httpt, "cannot unregister file" );
765 if( p_file->i_ref > 0 )
767 httpd_connection_t *p_con;
768 /* force closing all connection for this file */
769 msg_Err( p_httpt, "closing all client connection" );
771 vlc_mutex_lock( &p_httpt->connection_lock );
772 for( p_con = p_httpt->p_first_connection; p_con != NULL; )
774 httpd_connection_t *p_next;
776 p_next = p_con->p_next;
777 if( p_con->p_file == p_file )
779 httpd_ConnnectionClose( p_httpt, p_con );
783 vlc_mutex_unlock( &p_httpt->connection_lock );
786 FREE( p_file->psz_file );
787 FREE( p_file->psz_mime );
788 if( p_file->i_authenticate_method != HTTPD_AUTHENTICATE_NONE )
790 FREE( p_file->psz_user );
791 FREE( p_file->psz_password );
793 FREE( p_file->p_buffer );
794 FREE( p_file->p_header );
799 if( p_httpt->i_file_count == 1 )
801 FREE( p_httpt->file );
802 p_httpt->i_file_count = 0;
808 i_move = p_httpt->i_file_count - i - 1;
811 memmove( &p_httpt->file[i], &p_httpt->file[i + 1], sizeof( httpd_file_t *) * i_move );
813 p_httpt->i_file_count--;
814 p_httpt->file = realloc( p_httpt->file, sizeof( httpd_file_t *) * p_httpt->i_file_count );
817 vlc_mutex_unlock( &p_httpt->file_lock );
819 static void UnregisterFile( httpd_t *p_httpd, httpd_file_t *p_file )
821 _UnregisterFile( p_httpd->p_sys, p_file );
824 static void UnregisterStream( httpd_t *p_httpd, httpd_stream_t *p_stream )
826 _UnregisterFile( p_httpd->p_sys, p_stream );
831 static int _SendStream( httpd_sys_t *p_httpt, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
836 if( i_data <= 0 || p_data == NULL )
838 return( VLC_SUCCESS );
840 //fprintf( stderr, "## i_data=%d pos=%lld\n", i_data, p_stream->i_buffer_pos );
842 vlc_mutex_lock( &p_httpt->file_lock );
844 /* save this pointer (to be used by new connection) */
845 p_stream->i_buffer_last_pos = p_stream->i_buffer_pos;
847 i_pos = p_stream->i_buffer_pos % p_stream->i_buffer_size;
853 i_copy = __MIN( i_data, p_stream->i_buffer_size - i_pos );
855 memcpy( &p_stream->p_buffer[i_pos],
859 i_pos = ( i_pos + i_copy ) % p_stream->i_buffer_size;
864 p_stream->i_buffer_pos += i_data;
865 vlc_mutex_unlock( &p_httpt->file_lock );
867 return( VLC_SUCCESS );
869 static int SendStream( httpd_t *p_httpd, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
871 return( _SendStream( p_httpd->p_sys, p_stream, p_data, i_data ) );
874 static int HeaderStream( httpd_t *p_httpd, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
876 httpd_sys_t *p_httpt = p_httpd->p_sys;
878 vlc_mutex_lock( &p_httpt->file_lock );
880 FREE( p_stream->p_header );
881 if( p_data == NULL || i_data <= 0 )
883 p_stream->i_header_size = 0;
887 p_stream->i_header_size = i_data;
888 p_stream->p_header = malloc( i_data );
889 memcpy( p_stream->p_header,
893 vlc_mutex_unlock( &p_httpt->file_lock );
895 return( VLC_SUCCESS );
898 /****************************************************************************/
899 /****************************************************************************/
900 /****************************************************************************/
901 /****************************************************************************/
902 /****************************************************************************/
904 static int httpd_page_401_fill( httpd_file_callback_args_t *p_args, uint8_t **pp_data, int *pi_data )
908 p = *pp_data = malloc( 1024 );
910 p += sprintf( p, "<html>\n" );
911 p += sprintf( p, "<head>\n" );
912 p += sprintf( p, "<title>Error 401</title>\n" );
913 p += sprintf( p, "</head>\n" );
914 p += sprintf( p, "<body>\n" );
915 p += sprintf( p, "<h1><center> 401 authentification needed</center></h1>\n" );
916 p += sprintf( p, "<hr />\n" );
917 p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
918 p += sprintf( p, "</body>\n" );
919 p += sprintf( p, "</html>\n" );
921 *pi_data = strlen( *pp_data ) + 1;
925 static int httpd_page_404_fill( httpd_file_callback_args_t *p_args, uint8_t **pp_data, int *pi_data )
929 p = *pp_data = malloc( 1024 );
931 p += sprintf( p, "<html>\n" );
932 p += sprintf( p, "<head>\n" );
933 p += sprintf( p, "<title>Error 404</title>\n" );
934 p += sprintf( p, "</head>\n" );
935 p += sprintf( p, "<body>\n" );
936 p += sprintf( p, "<h1><center> 404 Ressource not found</center></h1>\n" );
937 p += sprintf( p, "<hr />\n" );
938 p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
939 p += sprintf( p, "</body>\n" );
940 p += sprintf( p, "</html>\n" );
942 *pi_data = strlen( *pp_data ) + 1;
947 static int httpd_page_admin_fill( httpd_file_callback_args_t *p_args, uint8_t **pp_data, int *pi_data )
949 httpd_sys_t *p_httpt = (httpd_sys_t*)p_args;
950 httpd_connection_t *p_con;
954 /* FIXME FIXME do not use static size FIXME FIXME*/
955 p = *pp_data = malloc( 8096 );
957 p += sprintf( p, "<html>\n" );
958 p += sprintf( p, "<head>\n" );
959 p += sprintf( p, "<title>VideoLAN Client Stream Output</title>\n" );
960 p += sprintf( p, "</head>\n" );
961 p += sprintf( p, "<body>\n" );
962 p += sprintf( p, "<h1><center>VideoLAN Client Stream Output</center></h1>\n" );
963 p += sprintf( p, "<h2><center>Admin page</center></h2>\n" );
966 p += sprintf( p, "<h3>General state</h3>\n" );
967 p += sprintf( p, "<ul>\n" );
968 p += sprintf( p, "<li>Connection count: %d</li>\n", p_httpt->i_connection_count );
969 //p += sprintf( p, "<li>Total bandwith: %d</li>\n", -1 );
970 /*p += sprintf( p, "<li></li>\n" );*/
971 p += sprintf( p, "</ul>\n" );
973 vlc_mutex_lock( &p_httpt->host_lock );
974 p += sprintf( p, "<h3>Host list</h3>\n" );
975 p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
976 p += sprintf( p, "<tr>\n<th>Host</th><th>Port</th><th>IP</th>\n</tr>\n" );
978 for( i = 0; i < p_httpt->i_host_count; i++ )
980 p += sprintf( p, "<tr>\n" );
981 p += sprintf( p, "<td>%s</td>\n", p_httpt->host[i]->psz_host_addr );
982 p += sprintf( p, "<td>%d</td>\n", p_httpt->host[i]->i_port );
983 p += sprintf( p, "<td>%s</td>\n", inet_ntoa( p_httpt->host[i]->sock.sin_addr ) );
984 p += sprintf( p, "</tr>\n" );
986 p += sprintf( p, "</table>\n" );
987 vlc_mutex_unlock( &p_httpt->host_lock );
990 /* XXX do not take lock on file_lock */
991 p += sprintf( p, "<h3>File list</h3>\n" );
992 p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
993 p += sprintf( p, "<tr>\n<th>Name</th><th>Mime</th><th>Protected</th><th>Used</th>\n</tr>\n" );
995 for( i = 0; i < p_httpt->i_file_count; i++ )
997 if( !p_httpt->file[i]->b_stream )
999 p += sprintf( p, "<tr>\n" );
1000 p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_file );
1001 p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_mime );
1002 p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_user ? "Yes" : "No" );
1003 p += sprintf( p, "<td>%d</td>\n", p_httpt->file[i]->i_ref);
1004 p += sprintf( p, "</tr>\n" );
1007 p += sprintf( p, "</table>\n" );
1010 /* XXX do not take lock on file_lock */
1011 p += sprintf( p, "<h3>Stream list</h3>\n" );
1012 p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
1013 p += sprintf( p, "<tr>\n<th>Name</th><th>Mime</th><th>Protected</th><th>Used</th>\n</tr>\n" );
1015 for( i = 0; i < p_httpt->i_file_count; i++ )
1017 if( p_httpt->file[i]->b_stream )
1019 p += sprintf( p, "<tr>\n" );
1020 p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_file );
1021 p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_mime );
1022 p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_user ? "Yes" : "No" );
1023 p += sprintf( p, "<td>%d</td>\n", p_httpt->file[i]->i_ref);
1024 p += sprintf( p, "</tr>\n" );
1027 p += sprintf( p, "</table>\n" );
1029 /* connection list */
1030 /* XXX do not take lock on connection_lock */
1031 p += sprintf( p, "<h3>Connection list</h3>\n" );
1032 p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
1033 p += sprintf( p, "<tr>\n<th>IP</th><th>Requested File</th><th>Status</th>\n</tr>\n" );
1035 for( p_con = p_httpt->p_first_connection;p_con != NULL; p_con = p_con->p_next )
1037 p += sprintf( p, "<tr>\n" );
1038 p += sprintf( p, "<td>%s</td>\n", inet_ntoa( p_con->sock.sin_addr ) );
1039 p += sprintf( p, "<td>%s</td>\n", p_con->psz_file );
1040 p += sprintf( p, "<td>%d</td>\n", p_con->i_http_error );
1041 p += sprintf( p, "</tr>\n" );
1043 p += sprintf( p, "</table>\n" );
1046 /* www.videolan.org */
1047 p += sprintf( p, "<hr />\n" );
1048 p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
1049 p += sprintf( p, "</body>\n" );
1050 p += sprintf( p, "</html>\n" );
1052 *pi_data = strlen( *pp_data ) + 1;
1058 static void httpd_ConnnectionNew( httpd_sys_t *p_httpt, int fd, struct sockaddr_in *p_sock )
1060 httpd_connection_t *p_con;
1062 msg_Dbg( p_httpt, "new connection from %s", inet_ntoa( p_sock->sin_addr ) );
1064 /* create a new connection and link it */
1065 p_con = malloc( sizeof( httpd_connection_t ) );
1066 p_con->i_state = HTTPD_CONNECTION_RECEIVING_REQUEST;
1068 p_con->i_last_activity_date = mdate();
1070 p_con->sock = *p_sock;
1071 p_con->psz_file = NULL;
1072 p_con->i_http_error = 0;
1073 p_con->psz_user = NULL;
1074 p_con->psz_password = NULL;
1075 p_con->p_file = NULL;
1077 p_con->i_buffer = 0;
1078 p_con->i_buffer_size = 8096;
1079 p_con->p_buffer = malloc( p_con->i_buffer_size );
1081 p_con->i_stream_pos = 0; // updated by httpd_thread */
1082 p_con->p_next = NULL;
1084 if( p_httpt->p_first_connection )
1086 httpd_connection_t *p_last;
1088 p_last = p_httpt->p_first_connection;
1089 while( p_last->p_next )
1091 p_last = p_last->p_next;
1094 p_last->p_next = p_con;
1095 p_con->p_prev = p_last;
1099 p_con->p_prev = NULL;
1101 p_httpt->p_first_connection = p_con;
1104 p_httpt->i_connection_count++;
1107 static void httpd_ConnnectionClose( httpd_sys_t *p_httpt, httpd_connection_t *p_con )
1109 msg_Dbg( p_httpt, "close connection from %s", inet_ntoa( p_con->sock.sin_addr ) );
1111 p_httpt->i_connection_count--;
1112 /* first cut out from list */
1115 p_con->p_prev->p_next = p_con->p_next;
1119 p_httpt->p_first_connection = p_con->p_next;
1124 p_con->p_next->p_prev = p_con->p_prev;
1127 if( p_con->p_file ) p_con->p_file->i_ref--;
1128 FREE( p_con->psz_file );
1130 FREE( p_con->p_buffer );
1131 SOCKET_CLOSE( p_con->fd );
1134 FREE( p_con->psz_user );
1135 FREE( p_con->psz_password );
1140 static void httpd_RequestGetWord( char *word, int i_word_max, char **pp_buffer, char *p_end )
1142 char *p = *pp_buffer;
1145 while( p < p_end && *p && ( *p == ' ' || *p == '\t' ) )
1151 for( i = 0; i < i_word_max && p < p_end && *p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r'; i++,p++)
1156 word[__MIN( i, i_word_max -1 )] = '\0';
1161 static int httpd_RequestNextLine( char **pp_buffer, char *p_end )
1165 for( p = *pp_buffer; p < p_end; p++ )
1167 if( p + 1 < p_end && *p == '\n' )
1172 if( p + 2 < p_end && p[0] == '\r' && p[1] == '\n' )
1179 return VLC_EGENERIC;
1182 //char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1183 static void b64_decode( char *dest, char *src )
1188 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */
1189 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */
1190 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */
1191 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */
1192 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */
1193 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */
1194 -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */
1195 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */
1196 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */
1197 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */
1198 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */
1199 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */
1200 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */
1201 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */
1202 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */
1203 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */
1206 for( i_level = 0; *src != '\0'; src++ )
1210 c = b64[(unsigned int)*src];
1223 *dest++ = ( last << 2 ) | ( ( c >> 4)&0x03 );
1227 *dest++ = ( ( last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f );
1231 *dest++ = ( ( last &0x03 ) << 6 ) | c;
1240 static void httpd_ConnectionParseRequest( httpd_sys_t *p_httpt, httpd_connection_t *p_con )
1249 char user[512] = "";
1250 char password[512] = "";
1252 //msg_Dbg( p_httpt, "new request=\n%s", p_con->p_buffer );
1254 p = p_con->p_buffer;
1255 p_end = p + strlen( p ) + 1;
1257 httpd_RequestGetWord( command, 32, &p, p_end );
1258 httpd_RequestGetWord( url, 1024, &p, p_end );
1259 httpd_RequestGetWord( version, 32, &p, p_end );
1260 //msg_Dbg( p_httpt, "ask =%s= =%s= =%s=", command, url, version );
1262 if( strcmp( command, "GET" ) )
1265 p_con->psz_file = strdup( "/501.html" );
1266 p_con->i_http_error = 501;
1270 if( strcmp( version, "HTTP/1.0" ) && strcmp( version, "HTTP/1.1" ) )
1272 p_con->psz_file = strdup( "/505.html" );
1273 p_con->i_http_error = 505;
1283 if( httpd_RequestNextLine( &p, p_end ) )
1285 //msg_Dbg( p_httpt, "failled new line" );
1288 //msg_Dbg( p_httpt, "new line=%s", p );
1290 httpd_RequestGetWord( header, 1024, &p, p_end );
1292 if( !strcmp( header, "Authorization:" ) )
1296 httpd_RequestGetWord( method, 32, &p, p_end );
1297 if( !strcasecmp( method, "BASIC" ) )
1302 httpd_RequestGetWord( basic, 1024, &p, p_end );
1303 //msg_Dbg( p_httpt, "Authorization: basic:%s", basic );
1304 b64_decode( decoded, basic );
1306 //msg_Dbg( p_httpt, "Authorization: decoded:%s", decoded );
1307 if( strchr( decoded, ':' ) )
1309 char *p = strchr( decoded, ':' );
1312 strcpy( user, decoded );
1313 strcpy( password, p );
1319 p_con->psz_file = strdup( url );
1320 p_con->i_http_error = 200;
1323 //msg_Dbg( p_httpt, "ask %s %s %d", command, p_con->psz_file, p_con->i_http_error );
1324 FREE( p_con->p_buffer );
1325 p_con->i_buffer = 0;
1326 p_con->i_buffer_size = 0;
1328 //vlc_mutex_lock( &p_httpt->file_lock );
1331 for( i = 0, p_con->p_file = NULL; i < p_httpt->i_file_count; i++ )
1333 if( !strcmp( p_httpt->file[i]->psz_file, p_con->psz_file ) )
1335 p_con->p_file = p_httpt->file[i];
1339 if( !p_con->p_file )
1341 p_con->psz_file = strdup( "/404.html" );
1342 p_con->i_http_error = 404;
1344 /* XXX be sure that "/404.html" exist else ... */
1348 if( p_con->p_file->i_authenticate_method == HTTPD_AUTHENTICATE_BASIC )
1350 if( strcmp( user, p_con->p_file->psz_user ) || strcmp( password, p_con->p_file->psz_password ) )
1352 p_con->psz_file = strdup( "/401.html" );
1353 strcpy( user, p_con->p_file->psz_user );
1354 p_con->i_http_error = 401;
1356 /* XXX do not put password on 404 else ... */
1361 p_con->p_file->i_ref++;
1362 // vlc_mutex_unlock( &p_httpt->file_lock );
1364 switch( p_con->i_http_error )
1371 psz_status = "Authorization Required";
1374 psz_status = "Unknown";
1378 p_con->i_state = HTTPD_CONNECTION_SENDING_HEADER;
1380 /* we send stream header with this one */
1381 if( p_con->i_http_error == 200 && p_con->p_file->b_stream )
1383 p_con->i_buffer_size = 4096 + p_con->p_file->i_header_size;
1386 p_con->i_buffer_size = 4096;
1387 p_con->i_buffer = 0;
1388 p = p_con->p_buffer = malloc( p_con->i_buffer_size );
1390 p += sprintf( p, "HTTP/1.0 %d %s\r\n", p_con->i_http_error, psz_status );
1391 p += sprintf( p, "Content-type: %s\r\n", p_con->p_file->psz_mime );
1392 if( p_con->i_http_error == 401 )
1394 p += sprintf( p, "WWW-Authenticate: Basic realm=\"%s\"\r\n", user );
1396 p += sprintf( p, "\r\n" );
1398 p_con->i_buffer_size = strlen( p_con->p_buffer );// + 1;
1400 if( p_con->i_http_error == 200 && p_con->p_file->b_stream && p_con->p_file->i_header_size > 0 )
1402 /* add stream header */
1403 memcpy( &p_con->p_buffer[p_con->i_buffer_size],
1404 p_con->p_file->p_header,
1405 p_con->p_file->i_header_size );
1406 p_con->i_buffer_size += p_con->p_file->i_header_size;
1409 //msg_Dbg( p_httpt, "answer=\n%s", p_con->p_buffer );
1411 #define HTTPD_STREAM_PACKET 10000
1412 static void httpd_Thread( httpd_sys_t *p_httpt )
1414 httpd_file_t *p_page_admin;
1415 httpd_file_t *p_page_401;
1416 httpd_file_t *p_page_404;
1418 httpd_connection_t *p_con;
1420 msg_Info( p_httpt, "httpd started" );
1422 p_page_401 = _RegisterFile( p_httpt,
1423 "/401.html", "text/html",
1425 httpd_page_401_fill,
1426 (httpd_file_callback_args_t*)NULL );
1427 p_page_404 = _RegisterFile( p_httpt,
1428 "/404.html", "text/html",
1430 httpd_page_404_fill,
1431 (httpd_file_callback_args_t*)NULL );
1432 p_page_admin = _RegisterFile( p_httpt,
1433 "/admin.html", "text/html",
1435 httpd_page_admin_fill,
1436 (httpd_file_callback_args_t*)p_httpt );
1438 while( !p_httpt->b_die )
1440 struct timeval timeout;
1443 int i_handle_max = 0;
1446 if( p_httpt->i_host_count <= 0 )
1448 msleep( 100 * 1000 );
1452 /* we will create a socket set with host and connection */
1453 FD_ZERO( &fds_read );
1454 FD_ZERO( &fds_write );
1456 vlc_mutex_lock( &p_httpt->host_lock );
1457 vlc_mutex_lock( &p_httpt->connection_lock );
1458 for( i = 0; i < p_httpt->i_host_count; i++ )
1460 FD_SET( p_httpt->host[i]->fd, &fds_read );
1461 i_handle_max = __MAX( i_handle_max, p_httpt->host[i]->fd );
1463 for( p_con = p_httpt->p_first_connection; p_con != NULL; )
1465 /* no more than 10s of inactivity */
1466 if( p_con->i_last_activity_date + (mtime_t)HTTPD_CONNECTION_MAX_UNUSED < mdate() )
1468 httpd_connection_t *p_next = p_con->p_next;
1470 msg_Dbg( p_httpt, "close unused connection" );
1471 httpd_ConnnectionClose( p_httpt, p_con );
1476 if( p_con->i_state == HTTPD_CONNECTION_SENDING_STREAM && p_con->i_stream_pos + HTTPD_STREAM_PACKET >= p_con->p_file->i_buffer_pos )
1478 p_con = p_con->p_next;
1482 if( p_con->i_state == HTTPD_CONNECTION_RECEIVING_REQUEST )
1484 FD_SET( p_con->fd, &fds_read );
1488 FD_SET( p_con->fd, &fds_write );
1490 i_handle_max = __MAX( i_handle_max, p_con->fd );
1492 p_con = p_con->p_next;
1494 vlc_mutex_unlock( &p_httpt->host_lock );
1495 vlc_mutex_unlock( &p_httpt->connection_lock );
1497 /* we will wait 0.5s */
1499 timeout.tv_usec = 500*1000;
1501 i_ret = select( i_handle_max + 1,
1506 if( i_ret == -1 && errno != EINTR )
1508 msg_Warn( p_httpt, "cannot select sockets" );
1514 // msg_Dbg( p_httpt, "waiting..." );
1518 vlc_mutex_lock( &p_httpt->host_lock );
1519 /* accept/refuse new connection */
1520 for( i = 0; i < p_httpt->i_host_count; i++ )
1522 int i_sock_size = sizeof( struct sockaddr_in );
1523 struct sockaddr_in sock;
1526 fd = accept( p_httpt->host[i]->fd, (struct sockaddr *)&sock,
1530 #if defined( WIN32 ) || defined( UNDER_CE )
1532 unsigned long i_dummy = 1;
1533 ioctlsocket( fd, FIONBIO, &i_dummy );
1536 fcntl( fd, F_SETFL, O_NONBLOCK );
1539 if( p_httpt->i_connection_count >= HTTPD_MAX_CONNECTION )
1541 msg_Warn( p_httpt, "max connection reached" );
1545 /* create a new connection and link it */
1546 httpd_ConnnectionNew( p_httpt, fd, &sock );
1550 vlc_mutex_unlock( &p_httpt->host_lock );
1552 vlc_mutex_lock( &p_httpt->file_lock );
1553 /* now do work for all connections */
1554 for( p_con = p_httpt->p_first_connection; p_con != NULL; )
1556 if( p_con->i_state == HTTPD_CONNECTION_RECEIVING_REQUEST )
1560 i_len = recv( p_con->fd,
1561 p_con->p_buffer + p_con->i_buffer,
1562 p_con->i_buffer_size - p_con->i_buffer, 0 );
1564 if( ( i_len < 0 && errno != EAGAIN && errno != EINTR )||
1567 httpd_connection_t *p_next = p_con->p_next;
1569 httpd_ConnnectionClose( p_httpt, p_con );
1572 else if( i_len > 0 )
1575 p_con->i_last_activity_date = mdate();
1576 p_con->i_buffer += i_len;
1578 ptr = p_con->p_buffer + p_con->i_buffer;
1580 if( ( p_con->i_buffer >= 2 && !strncmp( ptr - 2, "\n\n", 2 ) )||
1581 ( p_con->i_buffer >= 4 && !strncmp( ptr - 4, "\r\n\r\n", 4 ) ) ||
1582 p_con->i_buffer >= p_con->i_buffer_size )
1584 p_con->p_buffer[__MIN( p_con->i_buffer, p_con->i_buffer_size - 1 )] = '\0';
1585 httpd_ConnectionParseRequest( p_httpt, p_con );
1588 p_con = p_con->p_next;
1592 p_con = p_con->p_next;
1594 continue; /* just for clarity */
1596 else if( p_con->i_state == HTTPD_CONNECTION_SENDING_HEADER || p_con->i_state == HTTPD_CONNECTION_SENDING_FILE )
1601 i_len = send( p_con->fd, p_con->p_buffer + p_con->i_buffer, p_con->i_buffer_size - p_con->i_buffer, 0 );
1603 // 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 );
1605 if( ( i_len < 0 && errno != EAGAIN && errno != EINTR )||
1608 httpd_connection_t *p_next = p_con->p_next;
1610 httpd_ConnnectionClose( p_httpt, p_con );
1613 else if( i_len > 0 )
1615 p_con->i_last_activity_date = mdate();
1616 p_con->i_buffer += i_len;
1618 if( p_con->i_buffer >= p_con->i_buffer_size )
1620 if( p_con->i_state == HTTPD_CONNECTION_SENDING_HEADER )
1622 p_con->i_buffer_size = 0;
1623 p_con->i_buffer = 0;
1624 FREE( p_con->p_buffer );
1626 if( !p_con->p_file->b_stream )
1628 p_con->i_state = HTTPD_CONNECTION_SENDING_FILE; // be sure to out from HTTPD_CONNECTION_SENDING_HEADER
1629 p_con->p_file->pf_fill( p_con->p_file->p_sys, &p_con->p_buffer, &p_con->i_buffer_size );
1633 p_con->i_state = HTTPD_CONNECTION_SENDING_STREAM;
1634 p_con->i_stream_pos = p_con->p_file->i_buffer_last_pos;
1636 p_con = p_con->p_next;
1640 httpd_connection_t *p_next = p_con->p_next;
1642 httpd_ConnnectionClose( p_httpt, p_con );
1648 p_con = p_con->p_next;
1653 p_con = p_con->p_next;
1655 continue; /* just for clarity */
1657 else if( p_con->i_state == HTTPD_CONNECTION_SENDING_STREAM )
1659 httpd_stream_t *p_stream = p_con->p_file;
1663 if( p_con->i_stream_pos < p_stream->i_buffer_pos )
1666 /* check if this p_con aren't to late */
1667 if( p_con->i_stream_pos + p_stream->i_buffer_size < p_stream->i_buffer_pos )
1669 fprintf(stderr, "fixing i_stream_pos (old=%lld i_buffer_pos=%lld\n", p_con->i_stream_pos, p_stream->i_buffer_pos );
1670 p_con->i_stream_pos = p_stream->i_buffer_last_pos;
1673 i_pos = p_con->i_stream_pos % p_stream->i_buffer_size;
1674 /* size until end of buffer */
1675 i_write = p_stream->i_buffer_size - i_pos;
1676 /* is it more than valid data */
1677 if( i_write >= p_stream->i_buffer_pos - p_con->i_stream_pos )
1679 i_write = p_stream->i_buffer_pos - p_con->i_stream_pos;
1681 /* limit to HTTPD_STREAM_PACKET */
1682 if( i_write > HTTPD_STREAM_PACKET )
1684 i_write = HTTPD_STREAM_PACKET;
1686 i_send = send( p_con->fd, &p_stream->p_buffer[i_pos], i_write, 0 );
1688 if( ( i_send < 0 && errno != EAGAIN && errno != EINTR )|| ( i_send == 0 ) )
1690 httpd_connection_t *p_next = p_con->p_next;
1692 httpd_ConnnectionClose( p_httpt, p_con );
1696 else if( i_send > 0 )
1698 p_con->i_last_activity_date = mdate();
1699 p_con->i_stream_pos += i_send;
1702 p_con = p_con->p_next;
1703 continue; /* just for clarity */
1707 msg_Warn( p_httpt, "cannot occur (Invalid p_con->i_state)" );
1708 p_con = p_con->p_next;
1710 } /* for over connection */
1712 vlc_mutex_unlock( &p_httpt->file_lock );
1714 msg_Info( p_httpt, "httpd stopped" );
1716 _UnregisterFile( p_httpt, p_page_401 );
1717 _UnregisterFile( p_httpt, p_page_404 );
1718 _UnregisterFile( p_httpt, p_page_admin );