1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2001-2003 VideoLAN
5 * $Id: httpd.c,v 1.4 2003/02/27 15:07:48 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 *****************************************************************************/
30 #include <sys/types.h>
42 #elif defined( _MSC_VER ) && defined( _WIN32 ) && !defined( UNDER_CE )
46 #if defined( UNDER_CE )
48 #elif defined( WIN32 )
49 # include <winsock2.h>
50 # include <ws2tcpip.h>
52 # define IN_MULTICAST(a) IN_CLASSD(a)
55 # include <netdb.h> /* hostent ... */
56 # include <sys/socket.h>
57 # include <netinet/in.h>
58 # ifdef HAVE_ARPA_INET_H
59 # include <arpa/inet.h> /* inet_ntoa(), inet_aton() */
66 # define INADDR_ANY 0x00000000
69 # define INADDR_NONE 0xFFFFFFFF
72 #define LISTEN_BACKLOG 100
73 #define HTTPD_MAX_CONNECTION 512
74 #define HTTPD_CONNECTION_MAX_UNUSED 10000000
76 #define FREE( p ) if( p ) { free( p); (p) = NULL; }
78 #if defined( WIN32 ) || defined( UNDER_CE )
79 #define SOCKET_CLOSE(a) closesocket(a)
81 #define SOCKET_CLOSE(a) close(a)
84 /*****************************************************************************
86 *****************************************************************************/
87 static int Open ( vlc_object_t * );
88 static void Close ( vlc_object_t * );
90 /*****************************************************************************
92 *****************************************************************************/
94 set_description( _("HTTP 1.0 daemon") );
95 set_capability( "httpd", 42 );
96 set_callbacks( Open, Close );
99 /*****************************************************************************
101 *****************************************************************************/
102 static httpd_host_t *RegisterHost ( httpd_t *, char *, int );
103 static void UnregisterHost ( httpd_t *, httpd_host_t * );
105 static httpd_file_t *RegisterFile ( httpd_t *,
106 char *psz_file, char *psz_mime,
107 char *psz_user, char *psz_password,
108 httpd_file_callback pf_fill,
109 httpd_file_callback_args_t *p_args );
110 static void UnregisterFile ( httpd_t *, httpd_file_t * );
112 //#define httpd_stream_t httpd_file_t
113 static httpd_stream_t *RegisterStream ( httpd_t *,
114 char *psz_file, char *psz_mime,
115 char *psz_user, char *psz_password );
116 static int SendStream ( httpd_t *, httpd_stream_t *, uint8_t *, int );
117 static int HeaderStream ( httpd_t *, httpd_stream_t *, uint8_t *, int );
118 static void UnregisterStream( httpd_t *, httpd_stream_t* );
120 /*****************************************************************************
121 * Internal definitions
122 *****************************************************************************/
130 struct sockaddr_in sock;
135 #define HTTPD_AUTHENTICATE_NONE 0
136 #define HTTPD_AUTHENTICATE_BASIC 1
138 //typedef httpd_file_t httpd_stream_t;
148 int i_authenticate_method;
149 char *psz_user; /* NULL if no auth */
150 char *psz_password; /* NULL if no auth */
152 vlc_bool_t b_stream; /* if false: httpd will retreive data by a callback
153 true: it's up to the program to give data to httpd */
154 void *p_sys; /* provided for user */
155 httpd_file_callback pf_fill; /* it should allocate and fill *pp_data and *pi_data */
159 /* circular buffer for stream only */
160 int i_buffer_size; /* buffer size, can't be reallocated smaller */
161 uint8_t *p_buffer; /* buffer */
162 int64_t i_buffer_pos; /* absolute position from begining */
163 int i_buffer_last_pos; /* a new connection will start with that */
165 /* data to be send at connection time (if any) */
171 #define HTTPD_CONNECTION_RECEIVING_REQUEST 1
172 #define HTTPD_CONNECTION_SENDING_HEADER 2
173 #define HTTPD_CONNECTION_SENDING_FILE 3
174 #define HTTPD_CONNECTION_SENDING_STREAM 4
176 typedef struct httpd_connection_s
178 struct httpd_connection_s *p_next;
179 struct httpd_connection_s *p_prev;
181 struct sockaddr_in sock;
183 mtime_t i_last_activity_date;
187 char *psz_file; // file to be send
188 int i_http_error; // error to be send with the file
189 char *psz_user; // if Authorization in the request header
192 httpd_file_t *p_file;
194 /* used while sending header and file */
197 int i_buffer; /* private */
199 /* used for stream */
200 int64_t i_stream_pos; /* absolute pos in stream */
201 } httpd_connection_t;
210 vlc_mutex_t host_lock;
211 volatile int i_host_count;
214 vlc_mutex_t file_lock;
218 vlc_mutex_t connection_lock;
219 int i_connection_count;
220 httpd_connection_t *p_first_connection;
223 static void httpd_Thread( httpd_sys_t *p_httpt );
224 static void httpd_ConnnectionNew( httpd_sys_t *, int , struct sockaddr_in * );
225 static void httpd_ConnnectionClose( httpd_sys_t *, httpd_connection_t * );
227 /*****************************************************************************
229 *****************************************************************************/
231 static int Open( vlc_object_t *p_this )
233 httpd_t *p_httpd = (httpd_t*)p_this;
234 httpd_sys_t *p_httpt;
236 /* Launch httpt thread */
237 if( !( p_httpt = vlc_object_create( p_this, sizeof( httpd_sys_t ) ) ) )
239 msg_Err( p_this, "out of memory" );
240 return( VLC_EGENERIC );
246 /* init httpt_t structure */
247 vlc_mutex_init( p_httpd, &p_httpt->host_lock );
248 p_httpt->i_host_count = 0;
249 p_httpt->host = NULL;
251 vlc_mutex_init( p_httpd, &p_httpt->file_lock );
252 p_httpt->i_file_count = 0;
253 p_httpt->file = NULL;
255 vlc_mutex_init( p_httpd, &p_httpt->connection_lock );
256 p_httpt->i_connection_count = 0;
257 p_httpt->p_first_connection = NULL;
259 /* start the thread */
260 if( vlc_thread_create( p_httpt, "httpd thread",
261 httpd_Thread, VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
263 msg_Err( p_this, "cannot spawn http thread" );
265 vlc_mutex_destroy( &p_httpt->host_lock );
266 vlc_mutex_destroy( &p_httpt->file_lock );
267 vlc_mutex_destroy( &p_httpt->connection_lock );
269 vlc_object_destroy( p_httpt );
270 return( VLC_EGENERIC );
273 msg_Info( p_httpd, "http thread launched" );
275 p_httpd->p_sys = p_httpt;
276 p_httpd->pf_register_host = RegisterHost;
277 p_httpd->pf_unregister_host = UnregisterHost;
278 p_httpd->pf_register_file = RegisterFile;
279 p_httpd->pf_unregister_file = UnregisterFile;
280 p_httpd->pf_register_stream = RegisterStream;
281 p_httpd->pf_header_stream = HeaderStream;
282 p_httpd->pf_send_stream = SendStream;
283 p_httpd->pf_unregister_stream=UnregisterStream;
285 return( VLC_SUCCESS );
288 /*****************************************************************************
289 * Close: close the target
290 *****************************************************************************/
291 static void Close( vlc_object_t * p_this )
293 httpd_t *p_httpd = (httpd_t*)p_this;
294 httpd_sys_t *p_httpt = p_httpd->p_sys;
296 httpd_connection_t *p_con;
300 vlc_thread_join( p_httpt );
302 /* first close all host */
303 vlc_mutex_destroy( &p_httpt->host_lock );
304 if( p_httpt->i_host_count )
306 msg_Err( p_httpd, "still have %d hosts registered !", p_httpt->i_host_count );
308 for( i = 0; i < p_httpt->i_host_count; i++ )
310 #define p_host p_httpt->host[i]
311 FREE( p_host->psz_host_addr );
312 SOCKET_CLOSE( p_host->fd );
317 FREE( p_httpt->host );
320 vlc_mutex_destroy( &p_httpt->file_lock );
321 if( p_httpt->i_file_count )
323 msg_Err( p_httpd, "still have %d files registered !", p_httpt->i_file_count );
325 for( i = 0; i < p_httpt->i_file_count; i++ )
327 #define p_file p_httpt->file[i]
328 FREE( p_file->psz_file );
329 FREE( p_file->psz_mime );
330 if( p_file->i_authenticate_method != HTTPD_AUTHENTICATE_NONE )
332 FREE( p_file->psz_user );
333 FREE( p_file->psz_password );
335 FREE( p_file->p_buffer );
340 FREE( p_httpt->file );
342 /* andd close all connection */
343 vlc_mutex_destroy( &p_httpt->connection_lock );
344 if( p_httpt->i_connection_count )
346 msg_Warn( p_httpd, "%d connections still in use", p_httpt->i_connection_count );
348 while( ( p_con = p_httpt->p_first_connection ) )
350 httpd_ConnnectionClose( p_httpt, p_con );
353 msg_Info( p_httpd, "httpd instance closed" );
354 vlc_object_destroy( p_httpt );
358 /****************************************************************************
359 ****************************************************************************
362 ****************************************************************************
363 ****************************************************************************/
364 static int BuildAddr( struct sockaddr_in * p_socket,
365 const char * psz_address, int i_port )
368 memset( p_socket, 0, sizeof( struct sockaddr_in ) );
369 p_socket->sin_family = AF_INET; /* family */
370 p_socket->sin_port = htons( (uint16_t)i_port );
373 p_socket->sin_addr.s_addr = INADDR_ANY;
377 struct hostent * p_hostent;
379 /* Try to convert address directly from in_addr - this will work if
380 * psz_address is dotted decimal. */
381 #ifdef HAVE_ARPA_INET_H
382 if( !inet_aton( psz_address, &p_socket->sin_addr ) )
384 p_socket->sin_addr.s_addr = inet_addr( psz_address );
385 if( p_socket->sin_addr.s_addr == INADDR_NONE )
388 /* We have a fqdn, try to find its address */
389 if ( (p_hostent = gethostbyname( psz_address )) == NULL )
394 /* Copy the first address of the host in the socket address */
395 memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0],
396 p_hostent->h_length );
404 * listen on a host for a httpd instance
407 static httpd_host_t *_RegisterHost( httpd_sys_t *p_httpt, char *psz_host_addr, int i_port )
409 httpd_host_t *p_host;
410 struct sockaddr_in sock;
414 #if !defined( WIN32 ) && !defined( UNDER_CE )
418 if( BuildAddr( &sock, psz_host_addr, i_port ) )
420 msg_Err( p_httpt, "cannot build address for %s:%d", psz_host_addr, i_port );
424 /* is it already declared ? */
425 vlc_mutex_lock( &p_httpt->host_lock );
426 for( i = 0; i < p_httpt->i_host_count; i++ )
428 if( p_httpt->host[i]->sock.sin_port == sock.sin_port &&
429 p_httpt->host[i]->sock.sin_addr.s_addr == sock.sin_addr.s_addr )
435 if( i < p_httpt->i_host_count )
437 /* yes, increment ref count and succed */
438 p_httpt->host[i]->i_ref++;
439 vlc_mutex_unlock( &p_httpt->host_lock );
443 /* need to add a new listening socket */
446 fd = socket( AF_INET, SOCK_STREAM, 0 );
449 msg_Err( p_httpt, "cannot open socket" );
454 if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
455 (void *) &i_opt, sizeof( i_opt ) ) < 0 )
457 msg_Warn( p_httpt, "cannot configure socket (SO_REUSEADDR)" );
460 if( bind( fd, (struct sockaddr *)&sock, sizeof( struct sockaddr_in ) ) < 0 )
462 msg_Err( p_httpt, "cannot bind socket" );
465 /* set to non-blocking */
466 #if defined( WIN32 ) || defined( UNDER_CE )
468 unsigned long i_dummy = 1;
469 if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
471 msg_Err( p_httpt, "cannot set socket to non-blocking mode" );
476 if( ( i_flags = fcntl( fd, F_GETFL, 0 ) ) < 0 )
478 msg_Err( p_httpt, "cannot F_GETFL socket" );
481 if( fcntl( fd, F_SETFL, i_flags | O_NONBLOCK ) < 0 )
483 msg_Err( p_httpt, "cannot F_SETFL O_NONBLOCK" );
488 if( listen( fd, LISTEN_BACKLOG ) < 0 )
490 msg_Err( p_httpt, "cannot listen socket" );
496 p_httpt->host = realloc( p_httpt->host, sizeof( httpd_host_t *) * ( p_httpt->i_host_count + 1 ) );
500 p_httpt->host = malloc( sizeof( httpd_host_t *) );
502 p_host = malloc( sizeof( httpd_host_t ) );
504 p_host->psz_host_addr = strdup( psz_host_addr );
505 p_host->i_port = i_port;
509 p_httpt->host[p_httpt->i_host_count++] = p_host;
510 vlc_mutex_unlock( &p_httpt->host_lock );
515 vlc_mutex_unlock( &p_httpt->host_lock );
522 static httpd_host_t *RegisterHost( httpd_t *p_httpd, char *psz_host_addr, int i_port )
524 return( _RegisterHost( p_httpd->p_sys, psz_host_addr, i_port ) );
528 * remove a listening host for an httpd instance
530 static void _UnregisterHost( httpd_sys_t *p_httpt, httpd_host_t *p_host )
534 vlc_mutex_lock( &p_httpt->host_lock );
535 for( i = 0; i < p_httpt->i_host_count; i++ )
537 if( p_httpt->host[i] == p_host )
542 if( i >= p_httpt->i_host_count )
544 vlc_mutex_unlock( &p_httpt->host_lock );
545 msg_Err( p_httpt, "cannot unregister host" );
551 if( p_host->i_ref > 0 )
554 vlc_mutex_unlock( &p_httpt->host_lock );
559 FREE( p_host->psz_host_addr );
560 SOCKET_CLOSE( p_host->fd );
564 if( p_httpt->i_host_count <= 1 )
566 FREE( p_httpt->host );
567 p_httpt->i_host_count = 0;
573 i_move = p_httpt->i_host_count - i - 1;
577 memmove( &p_httpt->host[i],
579 i_move * sizeof( httpd_host_t * ) );
582 p_httpt->i_host_count--;
583 p_httpt->host = realloc( p_httpt->host,
584 p_httpt->i_host_count * sizeof( httpd_host_t * ) );
587 vlc_mutex_unlock( &p_httpt->host_lock );
589 static void UnregisterHost( httpd_t *p_httpd, httpd_host_t *p_host )
591 _UnregisterHost( p_httpd->p_sys, p_host );
595 static void __RegisterFile( httpd_sys_t *p_httpt, httpd_file_t *p_file )
598 if( p_httpt->i_file_count )
600 p_httpt->file = realloc( p_httpt->file, sizeof( httpd_file_t *) * ( p_httpt->i_file_count + 1 ) );
604 p_httpt->file = malloc( sizeof( httpd_file_t *) );
607 p_httpt->file[p_httpt->i_file_count++] = p_file;
610 static httpd_file_t *_RegisterFile( httpd_sys_t *p_httpt,
611 char *psz_file, char *psz_mime,
612 char *psz_user, char *psz_password,
613 httpd_file_callback pf_fill,
614 httpd_file_callback_args_t *p_args )
616 httpd_file_t *p_file;
619 vlc_mutex_lock( &p_httpt->file_lock );
620 for( i = 0; i < p_httpt->i_file_count; i++ )
622 if( !strcmp( psz_file, p_httpt->file[i]->psz_file ) )
627 if( i < p_httpt->i_file_count )
629 vlc_mutex_unlock( &p_httpt->file_lock );
630 msg_Err( p_httpt, "%s already registered", psz_file );
634 p_file = malloc( sizeof( httpd_file_t ) );
636 p_file->psz_file = strdup( psz_file );
637 p_file->psz_mime = strdup( psz_mime );
638 if( psz_user && *psz_user )
640 p_file->i_authenticate_method = HTTPD_AUTHENTICATE_BASIC;
641 p_file->psz_user = strdup( psz_user );
642 p_file->psz_password = strdup( psz_password );
646 p_file->i_authenticate_method = HTTPD_AUTHENTICATE_NONE;
647 p_file->psz_user = NULL;
648 p_file->psz_password = NULL;
651 p_file->b_stream = VLC_FALSE;
652 p_file->p_sys = p_args;
653 p_file->pf_fill = pf_fill;
655 p_file->i_buffer_size = 0;
656 p_file->i_buffer_last_pos = 0;
657 p_file->i_buffer_pos = 0;
658 p_file->p_buffer = NULL;
660 p_file->i_header_size = 0;
661 p_file->p_header = NULL;
663 __RegisterFile( p_httpt, p_file );
665 vlc_mutex_unlock( &p_httpt->file_lock );
669 static httpd_file_t *RegisterFile( httpd_t *p_httpd,
670 char *psz_file, char *psz_mime,
671 char *psz_user, char *psz_password,
672 httpd_file_callback pf_fill,
673 httpd_file_callback_args_t *p_args )
675 return( _RegisterFile( p_httpd->p_sys,
676 psz_file, psz_mime, psz_user, psz_password,
680 static httpd_stream_t *_RegisterStream( httpd_sys_t *p_httpt,
681 char *psz_file, char *psz_mime,
682 char *psz_user, char *psz_password )
684 httpd_stream_t *p_stream;
687 vlc_mutex_lock( &p_httpt->file_lock );
688 for( i = 0; i < p_httpt->i_file_count; i++ )
690 if( !strcmp( psz_file, p_httpt->file[i]->psz_file ) )
695 if( i < p_httpt->i_file_count )
697 vlc_mutex_unlock( &p_httpt->file_lock );
698 msg_Err( p_httpt, "%s already registered", psz_file );
702 p_stream = malloc( sizeof( httpd_stream_t ) );
704 p_stream->psz_file = strdup( psz_file );
705 p_stream->psz_mime = strdup( psz_mime );
706 if( psz_user && *psz_user )
708 p_stream->i_authenticate_method = HTTPD_AUTHENTICATE_BASIC;
709 p_stream->psz_user = strdup( psz_user );
710 p_stream->psz_password = strdup( psz_password );
714 p_stream->i_authenticate_method = HTTPD_AUTHENTICATE_NONE;
715 p_stream->psz_user = NULL;
716 p_stream->psz_password = NULL;
719 p_stream->b_stream = VLC_TRUE;
720 p_stream->p_sys = NULL;
721 p_stream->pf_fill = NULL;
723 p_stream->i_buffer_size = 1024*1024*10;
724 p_stream->i_buffer_pos = 0;
725 p_stream->i_buffer_last_pos = 0;
726 p_stream->p_buffer = malloc( p_stream->i_buffer_size );
728 p_stream->i_header_size = 0;
729 p_stream->p_header = NULL;
731 __RegisterFile( p_httpt, p_stream );
733 vlc_mutex_unlock( &p_httpt->file_lock );
737 static httpd_stream_t *RegisterStream( httpd_t *p_httpd,
738 char *psz_file, char *psz_mime,
739 char *psz_user, char *psz_password )
741 return( _RegisterStream( p_httpd->p_sys,
742 psz_file, psz_mime, psz_user, psz_password ) );
745 static void _UnregisterFile( httpd_sys_t *p_httpt, httpd_file_t *p_file )
749 vlc_mutex_lock( &p_httpt->file_lock );
750 for( i = 0; i < p_httpt->i_file_count; i++ )
752 if( !strcmp( p_file->psz_file, p_httpt->file[i]->psz_file ) )
757 if( i >= p_httpt->i_file_count )
759 vlc_mutex_unlock( &p_httpt->file_lock );
760 msg_Err( p_httpt, "cannot unregister file" );
764 if( p_file->i_ref > 0 )
766 httpd_connection_t *p_con;
767 /* force closing all connection for this file */
768 msg_Err( p_httpt, "closing all client connection" );
770 vlc_mutex_lock( &p_httpt->connection_lock );
771 for( p_con = p_httpt->p_first_connection; p_con != NULL; )
773 httpd_connection_t *p_next;
775 p_next = p_con->p_next;
776 if( p_con->p_file == p_file )
778 httpd_ConnnectionClose( p_httpt, p_con );
782 vlc_mutex_unlock( &p_httpt->connection_lock );
785 FREE( p_file->psz_file );
786 FREE( p_file->psz_mime );
787 if( p_file->i_authenticate_method != HTTPD_AUTHENTICATE_NONE )
789 FREE( p_file->psz_user );
790 FREE( p_file->psz_password );
792 FREE( p_file->p_buffer );
793 FREE( p_file->p_header );
798 if( p_httpt->i_file_count == 1 )
800 FREE( p_httpt->file );
801 p_httpt->i_file_count = 0;
807 i_move = p_httpt->i_file_count - i - 1;
810 memmove( &p_httpt->file[i], &p_httpt->file[i + 1], sizeof( httpd_file_t *) * i_move );
812 p_httpt->i_file_count--;
813 p_httpt->file = realloc( p_httpt->file, sizeof( httpd_file_t *) * p_httpt->i_file_count );
816 vlc_mutex_unlock( &p_httpt->file_lock );
818 static void UnregisterFile( httpd_t *p_httpd, httpd_file_t *p_file )
820 _UnregisterFile( p_httpd->p_sys, p_file );
823 static void UnregisterStream( httpd_t *p_httpd, httpd_stream_t *p_stream )
825 _UnregisterFile( p_httpd->p_sys, p_stream );
830 static int _SendStream( httpd_sys_t *p_httpt, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
835 if( i_data <= 0 || p_data == NULL )
837 return( VLC_SUCCESS );
839 //fprintf( stderr, "## i_data=%d pos=%lld\n", i_data, p_stream->i_buffer_pos );
841 vlc_mutex_lock( &p_httpt->file_lock );
843 /* save this pointer (to be used by new connection) */
844 p_stream->i_buffer_last_pos = p_stream->i_buffer_pos;
846 i_pos = p_stream->i_buffer_pos % p_stream->i_buffer_size;
852 i_copy = __MIN( i_data, p_stream->i_buffer_size - i_pos );
854 memcpy( &p_stream->p_buffer[i_pos],
858 i_pos = ( i_pos + i_copy ) % p_stream->i_buffer_size;
863 p_stream->i_buffer_pos += i_data;
864 vlc_mutex_unlock( &p_httpt->file_lock );
866 return( VLC_SUCCESS );
868 static int SendStream( httpd_t *p_httpd, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
870 return( _SendStream( p_httpd->p_sys, p_stream, p_data, i_data ) );
873 static int HeaderStream( httpd_t *p_httpd, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
875 httpd_sys_t *p_httpt = p_httpd->p_sys;
877 vlc_mutex_lock( &p_httpt->file_lock );
879 FREE( p_stream->p_header );
880 if( p_data == NULL || i_data <= 0 )
882 p_stream->i_header_size = 0;
886 p_stream->i_header_size = i_data;
887 p_stream->p_header = malloc( i_data );
888 memcpy( p_stream->p_header,
892 vlc_mutex_unlock( &p_httpt->file_lock );
894 return( VLC_SUCCESS );
897 /****************************************************************************/
898 /****************************************************************************/
899 /****************************************************************************/
900 /****************************************************************************/
901 /****************************************************************************/
903 static int httpd_page_401_fill( httpd_file_callback_args_t *p_args, uint8_t **pp_data, int *pi_data )
907 p = *pp_data = malloc( 1024 );
909 p += sprintf( p, "<html>\n" );
910 p += sprintf( p, "<head>\n" );
911 p += sprintf( p, "<title>Error 401</title>\n" );
912 p += sprintf( p, "</head>\n" );
913 p += sprintf( p, "<body>\n" );
914 p += sprintf( p, "<h1><center> 401 authentification needed</center></h1>\n" );
915 p += sprintf( p, "<hr />\n" );
916 p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
917 p += sprintf( p, "</body>\n" );
918 p += sprintf( p, "</html>\n" );
920 *pi_data = strlen( *pp_data ) + 1;
924 static int httpd_page_404_fill( httpd_file_callback_args_t *p_args, uint8_t **pp_data, int *pi_data )
928 p = *pp_data = malloc( 1024 );
930 p += sprintf( p, "<html>\n" );
931 p += sprintf( p, "<head>\n" );
932 p += sprintf( p, "<title>Error 404</title>\n" );
933 p += sprintf( p, "</head>\n" );
934 p += sprintf( p, "<body>\n" );
935 p += sprintf( p, "<h1><center> 404 Ressource not found</center></h1>\n" );
936 p += sprintf( p, "<hr />\n" );
937 p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
938 p += sprintf( p, "</body>\n" );
939 p += sprintf( p, "</html>\n" );
941 *pi_data = strlen( *pp_data ) + 1;
946 static int httpd_page_admin_fill( httpd_file_callback_args_t *p_args, uint8_t **pp_data, int *pi_data )
948 httpd_sys_t *p_httpt = (httpd_sys_t*)p_args;
949 httpd_connection_t *p_con;
953 /* FIXME FIXME do not use static size FIXME FIXME*/
954 p = *pp_data = malloc( 8096 );
956 p += sprintf( p, "<html>\n" );
957 p += sprintf( p, "<head>\n" );
958 p += sprintf( p, "<title>VideoLAN Client Stream Output</title>\n" );
959 p += sprintf( p, "</head>\n" );
960 p += sprintf( p, "<body>\n" );
961 p += sprintf( p, "<h1><center>VideoLAN Client Stream Output</center></h1>\n" );
962 p += sprintf( p, "<h2><center>Admin page</center></h2>\n" );
965 p += sprintf( p, "<h3>General state</h3>\n" );
966 p += sprintf( p, "<ul>\n" );
967 p += sprintf( p, "<li>Connection count: %d</li>\n", p_httpt->i_connection_count );
968 //p += sprintf( p, "<li>Total bandwith: %d</li>\n", -1 );
969 /*p += sprintf( p, "<li></li>\n" );*/
970 p += sprintf( p, "</ul>\n" );
972 vlc_mutex_lock( &p_httpt->host_lock );
973 p += sprintf( p, "<h3>Host list</h3>\n" );
974 p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
975 p += sprintf( p, "<tr>\n<th>Host</th><th>Port</th><th>IP</th>\n</tr>\n" );
977 for( i = 0; i < p_httpt->i_host_count; i++ )
979 p += sprintf( p, "<tr>\n" );
980 p += sprintf( p, "<td>%s</td>\n", p_httpt->host[i]->psz_host_addr );
981 p += sprintf( p, "<td>%d</td>\n", p_httpt->host[i]->i_port );
982 p += sprintf( p, "<td>%s</td>\n", inet_ntoa( p_httpt->host[i]->sock.sin_addr ) );
983 p += sprintf( p, "</tr>\n" );
985 p += sprintf( p, "</table>\n" );
986 vlc_mutex_unlock( &p_httpt->host_lock );
989 /* XXX do not take lock on file_lock */
990 p += sprintf( p, "<h3>File list</h3>\n" );
991 p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
992 p += sprintf( p, "<tr>\n<th>Name</th><th>Mime</th><th>Protected</th><th>Used</th>\n</tr>\n" );
994 for( i = 0; i < p_httpt->i_file_count; i++ )
996 if( !p_httpt->file[i]->b_stream )
998 p += sprintf( p, "<tr>\n" );
999 p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_file );
1000 p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_mime );
1001 p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_user ? "Yes" : "No" );
1002 p += sprintf( p, "<td>%d</td>\n", p_httpt->file[i]->i_ref);
1003 p += sprintf( p, "</tr>\n" );
1006 p += sprintf( p, "</table>\n" );
1009 /* XXX do not take lock on file_lock */
1010 p += sprintf( p, "<h3>Stream list</h3>\n" );
1011 p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
1012 p += sprintf( p, "<tr>\n<th>Name</th><th>Mime</th><th>Protected</th><th>Used</th>\n</tr>\n" );
1014 for( i = 0; i < p_httpt->i_file_count; i++ )
1016 if( p_httpt->file[i]->b_stream )
1018 p += sprintf( p, "<tr>\n" );
1019 p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_file );
1020 p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_mime );
1021 p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_user ? "Yes" : "No" );
1022 p += sprintf( p, "<td>%d</td>\n", p_httpt->file[i]->i_ref);
1023 p += sprintf( p, "</tr>\n" );
1026 p += sprintf( p, "</table>\n" );
1028 /* connection list */
1029 /* XXX do not take lock on connection_lock */
1030 p += sprintf( p, "<h3>Connection list</h3>\n" );
1031 p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
1032 p += sprintf( p, "<tr>\n<th>IP</th><th>Requested File</th><th>Status</th>\n</tr>\n" );
1034 for( p_con = p_httpt->p_first_connection;p_con != NULL; p_con = p_con->p_next )
1036 p += sprintf( p, "<tr>\n" );
1037 p += sprintf( p, "<td>%s</td>\n", inet_ntoa( p_con->sock.sin_addr ) );
1038 p += sprintf( p, "<td>%s</td>\n", p_con->psz_file );
1039 p += sprintf( p, "<td>%d</td>\n", p_con->i_http_error );
1040 p += sprintf( p, "</tr>\n" );
1042 p += sprintf( p, "</table>\n" );
1045 /* www.videolan.org */
1046 p += sprintf( p, "<hr />\n" );
1047 p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
1048 p += sprintf( p, "</body>\n" );
1049 p += sprintf( p, "</html>\n" );
1051 *pi_data = strlen( *pp_data ) + 1;
1057 static void httpd_ConnnectionNew( httpd_sys_t *p_httpt, int fd, struct sockaddr_in *p_sock )
1059 httpd_connection_t *p_con;
1061 msg_Dbg( p_httpt, "new connection from %s", inet_ntoa( p_sock->sin_addr ) );
1063 /* create a new connection and link it */
1064 p_con = malloc( sizeof( httpd_connection_t ) );
1065 p_con->i_state = HTTPD_CONNECTION_RECEIVING_REQUEST;
1067 p_con->i_last_activity_date = mdate();
1069 p_con->sock = *p_sock;
1070 p_con->psz_file = NULL;
1071 p_con->i_http_error = 0;
1072 p_con->psz_user = NULL;
1073 p_con->psz_password = NULL;
1074 p_con->p_file = NULL;
1076 p_con->i_buffer = 0;
1077 p_con->i_buffer_size = 8096;
1078 p_con->p_buffer = malloc( p_con->i_buffer_size );
1080 p_con->i_stream_pos = 0; // updated by httpd_thread */
1081 p_con->p_next = NULL;
1083 if( p_httpt->p_first_connection )
1085 httpd_connection_t *p_last;
1087 p_last = p_httpt->p_first_connection;
1088 while( p_last->p_next )
1090 p_last = p_last->p_next;
1093 p_last->p_next = p_con;
1094 p_con->p_prev = p_last;
1098 p_con->p_prev = NULL;
1100 p_httpt->p_first_connection = p_con;
1103 p_httpt->i_connection_count++;
1106 static void httpd_ConnnectionClose( httpd_sys_t *p_httpt, httpd_connection_t *p_con )
1108 msg_Dbg( p_httpt, "close connection from %s", inet_ntoa( p_con->sock.sin_addr ) );
1110 p_httpt->i_connection_count--;
1111 /* first cut out from list */
1114 p_con->p_prev->p_next = p_con->p_next;
1118 p_httpt->p_first_connection = p_con->p_next;
1123 p_con->p_next->p_prev = p_con->p_prev;
1126 if( p_con->p_file ) p_con->p_file->i_ref--;
1127 FREE( p_con->psz_file );
1129 FREE( p_con->p_buffer );
1130 SOCKET_CLOSE( p_con->fd );
1133 FREE( p_con->psz_user );
1134 FREE( p_con->psz_password );
1139 static void httpd_RequestGetWord( char *word, int i_word_max, char **pp_buffer, char *p_end )
1141 char *p = *pp_buffer;
1144 while( p < p_end && *p && ( *p == ' ' || *p == '\t' ) )
1150 for( i = 0; i < i_word_max && p < p_end && *p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r'; i++,p++)
1155 word[__MIN( i, i_word_max -1 )] = '\0';
1160 static int httpd_RequestNextLine( char **pp_buffer, char *p_end )
1164 for( p = *pp_buffer; p < p_end; p++ )
1166 if( p + 1 < p_end && *p == '\n' )
1171 if( p + 2 < p_end && p[0] == '\r' && p[1] == '\n' )
1178 return VLC_EGENERIC;
1181 //char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1182 static void b64_decode( char *dest, char *src )
1187 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */
1188 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */
1189 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */
1190 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */
1191 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */
1192 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */
1193 -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */
1194 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */
1195 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */
1196 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */
1197 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */
1198 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */
1199 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */
1200 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */
1201 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */
1202 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */
1205 for( i_level = 0; *src != '\0' > 0; src++ )
1209 c = b64[(unsigned int)*src];
1222 *dest++ = ( last << 2 ) | ( ( c >> 4)&0x03 );
1226 *dest++ = ( ( last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f );
1230 *dest++ = ( ( last &0x03 ) << 6 ) | c;
1239 static void httpd_ConnectionParseRequest( httpd_sys_t *p_httpt, httpd_connection_t *p_con )
1248 char user[512] = "";
1249 char password[512] = "";
1251 //msg_Dbg( p_httpt, "new request=\n%s", p_con->p_buffer );
1253 p = p_con->p_buffer;
1254 p_end = p + strlen( p ) + 1;
1256 httpd_RequestGetWord( command, 32, &p, p_end );
1257 httpd_RequestGetWord( url, 1024, &p, p_end );
1258 httpd_RequestGetWord( version, 32, &p, p_end );
1259 //msg_Dbg( p_httpt, "ask =%s= =%s= =%s=", command, url, version );
1261 if( strcmp( command, "GET" ) )
1264 p_con->psz_file = strdup( "/501.html" );
1265 p_con->i_http_error = 501;
1269 if( strcmp( version, "HTTP/1.0" ) && strcmp( version, "HTTP/1.1" ) )
1271 p_con->psz_file = strdup( "/505.html" );
1272 p_con->i_http_error = 505;
1282 if( httpd_RequestNextLine( &p, p_end ) )
1284 //msg_Dbg( p_httpt, "failled new line" );
1287 //msg_Dbg( p_httpt, "new line=%s", p );
1289 httpd_RequestGetWord( header, 1024, &p, p_end );
1291 if( !strcmp( header, "Authorization:" ) )
1295 httpd_RequestGetWord( method, 32, &p, p_end );
1296 if( !strcasecmp( method, "BASIC" ) )
1301 httpd_RequestGetWord( basic, 1024, &p, p_end );
1302 //msg_Dbg( p_httpt, "Authorization: basic:%s", basic );
1303 b64_decode( decoded, basic );
1305 //msg_Dbg( p_httpt, "Authorization: decoded:%s", decoded );
1306 if( strchr( decoded, ':' ) )
1308 char *p = strchr( decoded, ':' );
1311 strcpy( user, decoded );
1312 strcpy( password, p );
1318 p_con->psz_file = strdup( url );
1319 p_con->i_http_error = 200;
1322 //msg_Dbg( p_httpt, "ask %s %s %d", command, p_con->psz_file, p_con->i_http_error );
1323 FREE( p_con->p_buffer );
1324 p_con->i_buffer = 0;
1325 p_con->i_buffer_size = 0;
1327 //vlc_mutex_lock( &p_httpt->file_lock );
1330 for( i = 0, p_con->p_file = NULL; i < p_httpt->i_file_count; i++ )
1332 if( !strcmp( p_httpt->file[i]->psz_file, p_con->psz_file ) )
1334 p_con->p_file = p_httpt->file[i];
1338 if( !p_con->p_file )
1340 p_con->psz_file = strdup( "/404.html" );
1341 p_con->i_http_error = 404;
1343 /* XXX be sure that "/404.html" exist else ... */
1347 if( p_con->p_file->i_authenticate_method == HTTPD_AUTHENTICATE_BASIC )
1349 if( strcmp( user, p_con->p_file->psz_user ) || strcmp( password, p_con->p_file->psz_password ) )
1351 p_con->psz_file = strdup( "/401.html" );
1352 strcpy( user, p_con->p_file->psz_user );
1353 p_con->i_http_error = 401;
1355 /* XXX do not put password on 404 else ... */
1360 p_con->p_file->i_ref++;
1361 // vlc_mutex_unlock( &p_httpt->file_lock );
1363 switch( p_con->i_http_error )
1370 psz_status = "Authorization Required";
1373 psz_status = "Unknown";
1377 p_con->i_state = HTTPD_CONNECTION_SENDING_HEADER;
1379 /* we send stream header with this one */
1380 if( p_con->i_http_error == 200 && p_con->p_file->b_stream )
1382 p_con->i_buffer_size = 4096 + p_con->p_file->i_header_size;
1385 p_con->i_buffer_size = 4096;
1386 p_con->i_buffer = 0;
1387 p = p_con->p_buffer = malloc( p_con->i_buffer_size );
1389 p += sprintf( p, "HTTP/1.0 %d %s\r\n", p_con->i_http_error, psz_status );
1390 p += sprintf( p, "Content-type: %s\r\n", p_con->p_file->psz_mime );
1391 if( p_con->i_http_error == 401 )
1393 p += sprintf( p, "WWW-Authenticate: Basic realm=\"%s\"\r\n", user );
1395 p += sprintf( p, "\r\n" );
1397 p_con->i_buffer_size = strlen( p_con->p_buffer );// + 1;
1399 if( p_con->i_http_error == 200 && p_con->p_file->b_stream && p_con->p_file->i_header_size > 0 )
1401 /* add stream header */
1402 memcpy( &p_con->p_buffer[p_con->i_buffer_size],
1403 p_con->p_file->p_header,
1404 p_con->p_file->i_header_size );
1405 p_con->i_buffer_size += p_con->p_file->i_header_size;
1408 //msg_Dbg( p_httpt, "answer=\n%s", p_con->p_buffer );
1410 #define HTTPD_STREAM_PACKET 10000
1411 static void httpd_Thread( httpd_sys_t *p_httpt )
1413 httpd_file_t *p_page_admin;
1414 httpd_file_t *p_page_401;
1415 httpd_file_t *p_page_404;
1417 httpd_connection_t *p_con;
1419 msg_Info( p_httpt, "httpd started" );
1421 p_page_401 = _RegisterFile( p_httpt,
1422 "/401.html", "text/html",
1424 httpd_page_401_fill,
1425 (httpd_file_callback_args_t*)NULL );
1426 p_page_404 = _RegisterFile( p_httpt,
1427 "/404.html", "text/html",
1429 httpd_page_404_fill,
1430 (httpd_file_callback_args_t*)NULL );
1431 p_page_admin = _RegisterFile( p_httpt,
1432 "/admin.html", "text/html",
1434 httpd_page_admin_fill,
1435 (httpd_file_callback_args_t*)p_httpt );
1437 while( !p_httpt->b_die )
1439 struct timeval timeout;
1442 int i_handle_max = 0;
1445 if( p_httpt->i_host_count <= 0 )
1447 msleep( 100 * 1000 );
1451 /* we will create a socket set with host and connection */
1452 FD_ZERO( &fds_read );
1453 FD_ZERO( &fds_write );
1455 vlc_mutex_lock( &p_httpt->host_lock );
1456 vlc_mutex_lock( &p_httpt->connection_lock );
1457 for( i = 0; i < p_httpt->i_host_count; i++ )
1459 FD_SET( p_httpt->host[i]->fd, &fds_read );
1460 i_handle_max = __MAX( i_handle_max, p_httpt->host[i]->fd );
1462 for( p_con = p_httpt->p_first_connection; p_con != NULL; )
1464 /* no more than 10s of inactivity */
1465 if( p_con->i_last_activity_date + (mtime_t)HTTPD_CONNECTION_MAX_UNUSED < mdate() )
1467 httpd_connection_t *p_next = p_con->p_next;
1469 msg_Dbg( p_httpt, "close unused connection" );
1470 httpd_ConnnectionClose( p_httpt, p_con );
1475 if( p_con->i_state == HTTPD_CONNECTION_SENDING_STREAM && p_con->i_stream_pos + HTTPD_STREAM_PACKET >= p_con->p_file->i_buffer_pos )
1477 p_con = p_con->p_next;
1481 if( p_con->i_state == HTTPD_CONNECTION_RECEIVING_REQUEST )
1483 FD_SET( p_con->fd, &fds_read );
1487 FD_SET( p_con->fd, &fds_write );
1489 i_handle_max = __MAX( i_handle_max, p_con->fd );
1491 p_con = p_con->p_next;
1493 vlc_mutex_unlock( &p_httpt->host_lock );
1494 vlc_mutex_unlock( &p_httpt->connection_lock );
1496 /* we will wait 0.5s */
1498 timeout.tv_usec = 500*1000;
1500 i_ret = select( i_handle_max + 1,
1505 if( i_ret == -1 && errno != EINTR )
1507 msg_Warn( p_httpt, "cannot select sockets" );
1513 // msg_Dbg( p_httpt, "waiting..." );
1517 vlc_mutex_lock( &p_httpt->host_lock );
1518 /* accept/refuse new connection */
1519 for( i = 0; i < p_httpt->i_host_count; i++ )
1521 int i_sock_size = sizeof( struct sockaddr_in );
1522 struct sockaddr_in sock;
1525 fd = accept( p_httpt->host[i]->fd, (struct sockaddr *)&sock,
1529 #if defined( WIN32 ) || defined( UNDER_CE )
1531 unsigned long i_dummy = 1;
1532 ioctlsocket( fd, FIONBIO, &i_dummy );
1535 fcntl( fd, F_SETFL, O_NONBLOCK );
1538 if( p_httpt->i_connection_count >= HTTPD_MAX_CONNECTION )
1540 msg_Warn( p_httpt, "max connection reached" );
1544 /* create a new connection and link it */
1545 httpd_ConnnectionNew( p_httpt, fd, &sock );
1549 vlc_mutex_unlock( &p_httpt->host_lock );
1551 vlc_mutex_lock( &p_httpt->file_lock );
1552 /* now do work for all connections */
1553 for( p_con = p_httpt->p_first_connection; p_con != NULL; )
1555 if( p_con->i_state == HTTPD_CONNECTION_RECEIVING_REQUEST )
1559 i_len = recv( p_con->fd,
1560 p_con->p_buffer + p_con->i_buffer,
1561 p_con->i_buffer_size - p_con->i_buffer, 0 );
1563 if( ( i_len < 0 && errno != EAGAIN && errno != EINTR )||
1566 httpd_connection_t *p_next = p_con->p_next;
1568 httpd_ConnnectionClose( p_httpt, p_con );
1571 else if( i_len > 0 )
1574 p_con->i_last_activity_date = mdate();
1575 p_con->i_buffer += i_len;
1577 ptr = p_con->p_buffer + p_con->i_buffer;
1579 if( ( p_con->i_buffer >= 2 && !strncmp( ptr - 2, "\n\n", 2 ) )||
1580 ( p_con->i_buffer >= 4 && !strncmp( ptr - 4, "\r\n\r\n", 4 ) ) ||
1581 p_con->i_buffer >= p_con->i_buffer_size )
1583 p_con->p_buffer[__MIN( p_con->i_buffer, p_con->i_buffer_size - 1 )] = '\0';
1584 httpd_ConnectionParseRequest( p_httpt, p_con );
1587 p_con = p_con->p_next;
1591 p_con = p_con->p_next;
1593 continue; /* just for clarity */
1595 else if( p_con->i_state == HTTPD_CONNECTION_SENDING_HEADER || p_con->i_state == HTTPD_CONNECTION_SENDING_FILE )
1600 i_len = send( p_con->fd, p_con->p_buffer + p_con->i_buffer, p_con->i_buffer_size - p_con->i_buffer, 0 );
1602 // 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 );
1604 if( ( i_len < 0 && errno != EAGAIN && errno != EINTR )||
1607 httpd_connection_t *p_next = p_con->p_next;
1609 httpd_ConnnectionClose( p_httpt, p_con );
1612 else if( i_len > 0 )
1614 p_con->i_last_activity_date = mdate();
1615 p_con->i_buffer += i_len;
1617 if( p_con->i_buffer >= p_con->i_buffer_size )
1619 if( p_con->i_state == HTTPD_CONNECTION_SENDING_HEADER )
1621 p_con->i_buffer_size = 0;
1622 p_con->i_buffer = 0;
1623 FREE( p_con->p_buffer );
1625 if( !p_con->p_file->b_stream )
1627 p_con->i_state = HTTPD_CONNECTION_SENDING_FILE; // be sure to out from HTTPD_CONNECTION_SENDING_HEADER
1628 p_con->p_file->pf_fill( p_con->p_file->p_sys, &p_con->p_buffer, &p_con->i_buffer_size );
1632 p_con->i_state = HTTPD_CONNECTION_SENDING_STREAM;
1633 p_con->i_stream_pos = p_con->p_file->i_buffer_last_pos;
1635 p_con = p_con->p_next;
1639 httpd_connection_t *p_next = p_con->p_next;
1641 httpd_ConnnectionClose( p_httpt, p_con );
1647 p_con = p_con->p_next;
1652 p_con = p_con->p_next;
1654 continue; /* just for clarity */
1656 else if( p_con->i_state == HTTPD_CONNECTION_SENDING_STREAM )
1658 httpd_stream_t *p_stream = p_con->p_file;
1662 if( p_con->i_stream_pos < p_stream->i_buffer_pos )
1665 /* check if this p_con aren't to late */
1666 if( p_con->i_stream_pos + p_stream->i_buffer_size < p_stream->i_buffer_pos )
1668 fprintf(stderr, "fixing i_stream_pos (old=%lld i_buffer_pos=%lld\n", p_con->i_stream_pos, p_stream->i_buffer_pos );
1669 p_con->i_stream_pos = p_stream->i_buffer_last_pos;
1672 i_pos = p_con->i_stream_pos % p_stream->i_buffer_size;
1673 /* size until end of buffer */
1674 i_write = p_stream->i_buffer_size - i_pos;
1675 /* is it more than valid data */
1676 if( i_write >= p_stream->i_buffer_pos - p_con->i_stream_pos )
1678 i_write = p_stream->i_buffer_pos - p_con->i_stream_pos;
1680 /* limit to HTTPD_STREAM_PACKET */
1681 if( i_write > HTTPD_STREAM_PACKET )
1683 i_write = HTTPD_STREAM_PACKET;
1685 i_send = send( p_con->fd, &p_stream->p_buffer[i_pos], i_write, 0 );
1687 if( ( i_send < 0 && errno != EAGAIN && errno != EINTR )|| ( i_send == 0 ) )
1689 httpd_connection_t *p_next = p_con->p_next;
1691 httpd_ConnnectionClose( p_httpt, p_con );
1695 else if( i_send > 0 )
1697 p_con->i_last_activity_date = mdate();
1698 p_con->i_stream_pos += i_send;
1701 p_con = p_con->p_next;
1702 continue; /* just for clarity */
1706 msg_Warn( p_httpt, "cannot occur (Invalid p_con->i_state)" );
1707 p_con = p_con->p_next;
1709 } /* for over connection */
1711 vlc_mutex_unlock( &p_httpt->file_lock );
1713 msg_Info( p_httpt, "httpd stopped" );
1715 _UnregisterFile( p_httpt, p_page_401 );
1716 _UnregisterFile( p_httpt, p_page_404 );
1717 _UnregisterFile( p_httpt, p_page_admin );