1 /*****************************************************************************
2 * input.c: input thread
3 * Read an MPEG2 stream, demultiplex and parse it before sending it to
5 *****************************************************************************
6 * Copyright (C) 1998-2001 VideoLAN
7 * $Id: input.c,v 1.176 2002/02/24 20:51:10 gbazin Exp $
9 * Authors: Christophe Massiot <massiot@via.ecp.fr>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
30 #include <sys/types.h>
34 #include <videolan/vlc.h>
38 #elif defined( _MSC_VER ) && defined( _WIN32 )
45 #ifdef STRNCASECMP_IN_STRINGS_H
50 # include <winsock2.h>
51 # include <ws2tcpip.h>
52 #elif !defined( SYS_BEOS ) && !defined( SYS_NTO )
53 # include <netdb.h> /* hostent ... */
54 # include <sys/socket.h>
55 # include <netinet/in.h>
56 # ifdef HAVE_ARPA_INET_H
57 # include <arpa/inet.h> /* inet_ntoa(), inet_aton() */
61 #ifdef HAVE_SYS_TIMES_H
62 # include <sys/times.h>
67 #include "intf_playlist.h"
69 #include "stream_control.h"
70 #include "input_ext-intf.h"
71 #include "input_ext-dec.h"
72 #include "input_ext-plugins.h"
74 #include "interface.h"
76 /*****************************************************************************
78 *****************************************************************************/
79 static void RunThread ( input_thread_t *p_input );
80 static int InitThread ( input_thread_t *p_input );
81 static void ErrorThread ( input_thread_t *p_input );
82 static void CloseThread ( input_thread_t *p_input );
83 static void DestroyThread ( input_thread_t *p_input );
84 static void EndThread ( input_thread_t *p_input );
86 static void FileOpen ( input_thread_t *p_input );
87 static void StdOpen ( input_thread_t *p_input );
88 static void FileClose ( input_thread_t *p_input );
89 #if !defined( SYS_BEOS ) && !defined( SYS_NTO )
90 static void NetworkOpen ( input_thread_t *p_input );
91 static void HTTPOpen ( input_thread_t *p_input );
92 static void NetworkClose ( input_thread_t *p_input );
95 /*****************************************************************************
96 * input_InitBank: initialize the input bank.
97 *****************************************************************************/
98 void input_InitBank ( void )
100 p_input_bank->i_count = 0;
102 /* XXX: Workaround for old interface modules */
103 p_input_bank->pp_input[0] = NULL;
105 vlc_mutex_init( &p_input_bank->lock );
108 /*****************************************************************************
109 * input_EndBank: empty the input bank.
110 *****************************************************************************
111 * This function ends all unused inputs and empties the bank in
113 *****************************************************************************/
114 void input_EndBank ( void )
118 /* Ask all remaining video outputs to die */
119 for( i_input = 0; i_input < p_input_bank->i_count; i_input++ )
122 p_input_bank->pp_input[ i_input ], NULL );
124 p_input_bank->pp_input[ i_input ] );
127 vlc_mutex_destroy( &p_input_bank->lock );
130 /*****************************************************************************
131 * input_CreateThread: creates a new input thread
132 *****************************************************************************
133 * This function creates a new input, and returns a pointer
134 * to its description. On error, it returns NULL.
135 * If pi_status is NULL, then the function will block until the thread is ready.
136 * If not, it will be updated using one of the THREAD_* constants.
137 *****************************************************************************/
138 input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
140 input_thread_t * p_input; /* thread descriptor */
142 /* Allocate descriptor */
143 p_input = (input_thread_t *)malloc( sizeof(input_thread_t) );
144 if( p_input == NULL )
146 intf_ErrMsg( "input error: can't allocate input thread (%s)",
151 /* Initialize thread properties */
153 p_input->b_error = 0;
157 p_input->p_source = p_item->psz_name;
160 p_input->i_status = THREAD_CREATE;
162 /* Initialize statistics */
163 p_input->c_loops = 0;
164 p_input->stream.c_packets_read = 0;
165 p_input->stream.c_packets_trashed = 0;
166 p_input->p_stream = NULL;
169 vlc_mutex_init( &p_input->stream.stream_lock );
170 vlc_cond_init( &p_input->stream.stream_wait );
171 vlc_mutex_init( &p_input->stream.control.control_lock );
173 /* Initialize stream description */
174 p_input->stream.b_changed = 0;
175 p_input->stream.i_es_number = 0;
176 p_input->stream.i_selected_es_number = 0;
177 p_input->stream.i_pgrm_number = 0;
178 p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
179 p_input->stream.b_new_mute = MUTE_NO_CHANGE;
180 p_input->stream.i_mux_rate = 0;
182 /* no stream, no program, no area, no es */
183 p_input->stream.p_new_program = NULL;
185 p_input->stream.i_area_nb = 0;
186 p_input->stream.pp_areas = NULL;
187 p_input->stream.p_selected_area = NULL;
188 p_input->stream.p_new_area = NULL;
190 p_input->stream.pp_selected_es = NULL;
191 p_input->stream.p_removed_es = NULL;
192 p_input->stream.p_newly_selected_es = NULL;
194 /* By default there is one area in a stream */
195 input_AddArea( p_input );
196 p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
198 /* Initialize stream control properties. */
199 p_input->stream.control.i_status = PLAYING_S;
200 p_input->stream.control.i_rate = DEFAULT_RATE;
201 p_input->stream.control.b_mute = 0;
202 p_input->stream.control.b_grayscale = config_GetIntVariable(
203 VOUT_GRAYSCALE_VAR );
204 p_input->stream.control.i_smp = config_GetIntVariable( VDEC_SMP_VAR );
206 intf_WarnMsg( 1, "input: playlist item `%s'", p_input->p_source );
209 if( vlc_thread_create( &p_input->thread_id, "input", (void *) RunThread,
212 intf_ErrMsg( "input error: can't create input thread (%s)",
219 /* If status is NULL, wait until the thread is created */
220 if( pi_status == NULL )
224 msleep( THREAD_SLEEP );
225 } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
226 && (i_status != THREAD_FATAL) );
233 /*****************************************************************************
234 * input_StopThread: mark an input thread as zombie
235 *****************************************************************************
236 * This function should not return until the thread is effectively cancelled.
237 *****************************************************************************/
238 void input_StopThread( input_thread_t *p_input, int *pi_status )
240 /* Make the thread exit from a possible vlc_cond_wait() */
241 vlc_mutex_lock( &p_input->stream.stream_lock );
243 /* Request thread destruction */
246 vlc_cond_signal( &p_input->stream.stream_wait );
247 vlc_mutex_unlock( &p_input->stream.stream_lock );
249 /* If status is NULL, wait until thread has been destroyed */
251 if( pi_status == NULL )
255 msleep( THREAD_SLEEP );
256 } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
257 && (i_status != THREAD_FATAL) );
262 /*****************************************************************************
263 * input_DestroyThread: mark an input thread as zombie
264 *****************************************************************************
265 * This function should not return until the thread is effectively cancelled.
266 *****************************************************************************/
267 void input_DestroyThread( input_thread_t *p_input )
269 /* Join the thread */
270 vlc_thread_join( p_input->thread_id );
272 /* Destroy Mutex locks */
273 vlc_mutex_destroy( &p_input->stream.control.control_lock );
274 vlc_mutex_destroy( &p_input->stream.stream_lock );
276 /* Free input structure */
280 /*****************************************************************************
281 * RunThread: main thread loop
282 *****************************************************************************
283 * Thread in charge of processing the network packets and demultiplexing.
284 *****************************************************************************/
285 static void RunThread( input_thread_t *p_input )
287 if( InitThread( p_input ) )
289 /* If we failed, wait before we are killed, and exit */
290 p_input->i_status = THREAD_ERROR;
291 p_input->b_error = 1;
292 ErrorThread( p_input );
293 DestroyThread( p_input );
297 p_input->i_status = THREAD_READY;
299 /* initialization is complete */
300 vlc_mutex_lock( &p_input->stream.stream_lock );
301 p_input->stream.b_changed = 1;
302 vlc_mutex_unlock( &p_input->stream.stream_lock );
304 while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
306 data_packet_t * p_data;
311 vlc_mutex_lock( &p_input->stream.stream_lock );
313 if( p_input->stream.p_new_program )
315 if( p_input->pf_set_program != NULL )
318 p_input->pf_set_program( p_input,
319 p_input->stream.p_new_program );
321 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
323 pgrm_descriptor_t * p_pgrm
324 = p_input->stream.pp_programs[i];
325 /* Escape all decoders for the stream discontinuity they
327 input_EscapeDiscontinuity( p_input, p_pgrm );
329 /* Reinitialize synchro. */
330 p_pgrm->i_synchro_state = SYNCHRO_REINIT;
333 p_input->stream.p_new_program = NULL;
336 if( p_input->stream.p_new_area )
338 if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
341 p_input->pf_set_area( p_input, p_input->stream.p_new_area );
343 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
345 pgrm_descriptor_t * p_pgrm
346 = p_input->stream.pp_programs[i];
347 /* Escape all decoders for the stream discontinuity they
349 input_EscapeDiscontinuity( p_input, p_pgrm );
351 /* Reinitialize synchro. */
352 p_pgrm->i_synchro_state = SYNCHRO_REINIT;
355 p_input->stream.p_new_area = NULL;
358 if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
360 if( p_input->stream.b_seekable && p_input->pf_seek != NULL )
362 p_input->pf_seek( p_input,
363 p_input->stream.p_selected_area->i_seek );
365 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
367 pgrm_descriptor_t * p_pgrm
368 = p_input->stream.pp_programs[i];
369 /* Escape all decoders for the stream discontinuity they
371 input_EscapeDiscontinuity( p_input, p_pgrm );
373 /* Reinitialize synchro. */
374 p_pgrm->i_synchro_state = SYNCHRO_REINIT;
377 p_input->stream.p_selected_area->i_seek = NO_SEEK;
380 if( p_input->stream.p_removed_es )
382 input_UnselectES( p_input, p_input->stream.p_removed_es );
383 p_input->stream.p_removed_es = NULL;
386 if( p_input->stream.p_newly_selected_es )
388 input_SelectES( p_input, p_input->stream.p_newly_selected_es );
389 p_input->stream.p_newly_selected_es = NULL;
392 if( p_input->stream.b_new_mute != MUTE_NO_CHANGE )
394 if( p_input->stream.b_new_mute )
396 input_EscapeAudioDiscontinuity( p_input );
399 vlc_mutex_lock( &p_input->stream.control.control_lock );
400 p_input->stream.control.b_mute = p_input->stream.b_new_mute;
401 vlc_mutex_unlock( &p_input->stream.control.control_lock );
403 p_input->stream.b_new_mute = MUTE_NO_CHANGE;
406 vlc_mutex_unlock( &p_input->stream.stream_lock );
408 i_count = p_input->pf_read( p_input, &p_data );
410 /* Demultiplex read packets. */
411 while( p_data != NULL )
413 data_packet_t * p_next = p_data->p_next;
414 p_data->p_next = NULL;
416 p_input->stream.c_packets_read++;
417 p_input->pf_demux( p_input, p_data );
422 if( i_count == 0 && p_input->stream.b_seekable )
424 /* End of file - we do not set b_die because only the
425 * interface is allowed to do so. */
426 intf_WarnMsg( 3, "input: EOF reached" );
429 else if( i_count < 0 )
431 p_input->b_error = 1;
435 if( p_input->b_error || p_input->b_eof )
437 ErrorThread( p_input );
440 EndThread( p_input );
442 DestroyThread( p_input );
445 /*****************************************************************************
446 * InitThread: init the input Thread
447 *****************************************************************************/
448 static int InitThread( input_thread_t * p_input )
452 /* Find appropriate module. */
453 psz_name = config_GetPszVariable( INPUT_METHOD_VAR );
454 p_input->p_input_module = module_Need( MODULE_CAPABILITY_INPUT, psz_name,
457 if( psz_name ) free( psz_name );
458 if( p_input->p_input_module == NULL )
460 intf_ErrMsg( "input error: no suitable input module for `%s'",
465 #define f p_input->p_input_module->p_functions->input.functions.input
466 p_input->pf_probe = f.pf_probe;
467 p_input->pf_init = f.pf_init;
468 p_input->pf_end = f.pf_end;
469 p_input->pf_read = f.pf_read;
470 p_input->pf_set_area = f.pf_set_area;
471 p_input->pf_set_program = f.pf_set_program;
472 p_input->pf_demux = f.pf_demux;
473 p_input->pf_new_packet = f.pf_new_packet;
474 p_input->pf_new_pes = f.pf_new_pes;
475 p_input->pf_delete_packet = f.pf_delete_packet;
476 p_input->pf_delete_pes = f.pf_delete_pes;
477 p_input->pf_rewind = f.pf_rewind;
478 p_input->pf_seek = f.pf_seek;
480 if( f.pf_open != NULL )
482 f.pf_open( p_input );
484 #if !defined( SYS_BEOS ) && !defined( SYS_NTO )
485 /* FIXME : this is waaaay too kludgy */
486 else if( ( strlen( p_input->p_source ) >= 10
487 && !strncasecmp( p_input->p_source, "udpstream:", 10 ) )
488 || ( strlen( p_input->p_source ) >= 4
489 && !strncasecmp( p_input->p_source, "udp:", 4 ) ) )
492 NetworkOpen( p_input );
493 p_input->stream.i_method = INPUT_METHOD_NETWORK;
495 else if( ( strlen( p_input->p_source ) > 5 )
496 && !strncasecmp( p_input->p_source, "http:", 5 ) )
500 p_input->stream.i_method = INPUT_METHOD_NETWORK;
503 else if( ( strlen( p_input->p_source ) == 1 )
504 && *p_input->p_source == '-' )
513 p_input->stream.i_method = INPUT_METHOD_FILE;
517 if( p_input->b_error )
519 /* We barfed -- exit nicely */
520 module_Unneed( p_input->p_input_module );
524 p_input->pf_init( p_input );
526 if( p_input->b_error )
528 /* We barfed -- exit nicely */
529 CloseThread( p_input );
530 module_Unneed( p_input->p_input_module );
537 /*****************************************************************************
538 * ErrorThread: RunThread() error loop
539 *****************************************************************************
540 * This function is called when an error occured during thread main's loop.
541 *****************************************************************************/
542 static void ErrorThread( input_thread_t *p_input )
544 while( !p_input->b_die )
547 msleep( INPUT_IDLE_SLEEP );
551 /*****************************************************************************
552 * EndThread: end the input thread
553 *****************************************************************************/
554 static void EndThread( input_thread_t * p_input )
557 p_input->i_status = THREAD_END;
559 if( p_main->b_stats )
561 #ifdef HAVE_SYS_TIMES_H
562 /* Display statistics */
563 struct tms cpu_usage;
566 intf_StatMsg( "input stats: %d loops consuming user: %d, system: %d",
568 cpu_usage.tms_utime, cpu_usage.tms_stime );
570 intf_StatMsg( "input stats: %d loops", p_input->c_loops );
573 input_DumpStream( p_input );
576 /* Free all ES and destroy all decoder threads */
577 input_EndStream( p_input );
579 /* Free demultiplexer's data */
580 p_input->pf_end( p_input );
582 /* Close the input method */
583 CloseThread( p_input );
585 /* Release modules */
586 module_Unneed( p_input->p_input_module );
589 /*****************************************************************************
590 * CloseThread: close the target
591 *****************************************************************************/
592 static void CloseThread( input_thread_t * p_input )
594 #define f p_input->p_input_module->p_functions->input.functions.input
596 if( f.pf_close != NULL )
598 f.pf_close( p_input );
600 #if !defined( SYS_BEOS ) && !defined( SYS_NTO )
602 else if( ( strlen( p_input->p_source ) > 10
603 && !strncasecmp( p_input->p_source, "udpstream:", 10 ) )
604 || ( strlen( p_input->p_source ) > 4
605 && !strncasecmp( p_input->p_source, "udp:", 4 ) ) )
607 NetworkClose( p_input );
609 else if( ( strlen( p_input->p_source ) > 5 )
610 && !strncasecmp( p_input->p_source, "http:", 5 ) )
612 NetworkClose( p_input );
617 FileClose( p_input );
622 /*****************************************************************************
623 * DestroyThread: destroy the input thread
624 *****************************************************************************/
625 static void DestroyThread( input_thread_t * p_input )
628 p_input->i_status = THREAD_OVER;
631 /*****************************************************************************
632 * StdOpen : open standard input
633 *****************************************************************************/
634 static void StdOpen( input_thread_t * p_input )
636 vlc_mutex_lock( &p_input->stream.stream_lock );
638 /* Suppose we can control the pace - this won't work in some cases ! */
639 p_input->stream.b_pace_control = 1;
641 p_input->stream.b_seekable = 0;
642 p_input->stream.p_selected_area->i_size = 0;
643 p_input->stream.p_selected_area->i_tell = 0;
644 vlc_mutex_unlock( &p_input->stream.stream_lock );
646 intf_WarnMsg( 2, "input: opening stdin" );
647 p_input->i_handle = 0;
650 /*****************************************************************************
651 * FileOpen : open a file descriptor
652 *****************************************************************************/
653 static void FileOpen( input_thread_t * p_input )
655 struct stat stat_info;
658 char *psz_name = p_input->p_source;
660 if( ( i_stat = stat( psz_name, &stat_info ) ) == (-1) )
662 int i_size = strlen( psz_name );
665 && !strncasecmp( psz_name, "dvdread:", 8 ) )
667 /* get rid of the 'dvdread:' stuff and try again */
669 i_stat = stat( psz_name, &stat_info );
671 else if( ( i_size > 4 )
672 && !strncasecmp( psz_name, "dvd:", 4 ) )
674 /* get rid of the 'dvd:' stuff and try again */
676 i_stat = stat( psz_name, &stat_info );
678 else if( ( i_size > 4 )
679 && !strncasecmp( psz_name, "vcd:", 4 ) )
681 /* get rid of the 'vcd:' stuff and try again */
683 i_stat = stat( psz_name, &stat_info );
685 else if( ( i_size > 5 )
686 && !strncasecmp( psz_name, "file:", 5 ) )
688 /* get rid of the 'file:' stuff and try again */
690 i_stat = stat( psz_name, &stat_info );
695 intf_ErrMsg( "input error: cannot stat() file `%s' (%s)",
696 psz_name, strerror(errno));
697 p_input->b_error = 1;
702 vlc_mutex_lock( &p_input->stream.stream_lock );
704 /* If we are here we can control the pace... */
705 p_input->stream.b_pace_control = 1;
707 if( S_ISREG(stat_info.st_mode) || S_ISCHR(stat_info.st_mode)
708 || S_ISBLK(stat_info.st_mode) )
710 p_input->stream.b_seekable = 1;
711 p_input->stream.p_selected_area->i_size = stat_info.st_size;
713 else if( S_ISFIFO(stat_info.st_mode)
714 #if !defined( SYS_BEOS ) && !defined( WIN32 )
715 || S_ISSOCK(stat_info.st_mode)
719 p_input->stream.b_seekable = 0;
720 p_input->stream.p_selected_area->i_size = 0;
724 vlc_mutex_unlock( &p_input->stream.stream_lock );
725 intf_ErrMsg( "input error: unknown file type for `%s'",
727 p_input->b_error = 1;
731 p_input->stream.p_selected_area->i_tell = 0;
732 vlc_mutex_unlock( &p_input->stream.stream_lock );
734 intf_WarnMsg( 2, "input: opening file `%s'", p_input->p_source );
735 if( (p_input->i_handle = open( psz_name,
736 /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
738 intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
739 p_input->b_error = 1;
745 /*****************************************************************************
746 * FileClose : close a file descriptor
747 *****************************************************************************/
748 static void FileClose( input_thread_t * p_input )
750 intf_WarnMsg( 2, "input: closing file `%s'", p_input->p_source );
752 close( p_input->i_handle );
757 #if !defined( SYS_BEOS ) && !defined( SYS_NTO )
758 /*****************************************************************************
759 * NetworkOpen : open a network socket
760 *****************************************************************************/
761 static void NetworkOpen( input_thread_t * p_input )
763 char *psz_server = NULL;
764 char *psz_bind = NULL;
765 int i_server_port = 0;
769 struct sockaddr_in sock;
771 /* Get the remote server. Syntax is :
772 * udp[stream]:[/][/][serveraddr[:serverport]][@[bindaddr]:[bindport]] */
773 if( p_input->p_source != NULL )
775 char * psz_parser = p_input->p_source;
776 char * psz_server_port = NULL;
777 char * psz_bind_port = NULL;
779 /* Skip the protocol name */
780 while( *psz_parser && *psz_parser != ':' )
785 /* Skip the "://" part */
786 while( *psz_parser && (*psz_parser == ':' || *psz_parser == '/') )
791 if( *psz_parser && *psz_parser != '@' )
794 psz_server = psz_parser;
796 while( *psz_parser && *psz_parser != ':' && *psz_parser != '@' )
801 if( *psz_parser == ':' )
803 /* Found server port */
804 *psz_parser = '\0'; /* Terminate server name */
806 psz_server_port = psz_parser;
808 while( *psz_parser && *psz_parser != '@' )
815 if( *psz_parser == '@' )
817 /* Found bind address or bind port */
818 *psz_parser = '\0'; /* Terminate server port or name if necessary */
821 if( *psz_parser && *psz_parser != ':' )
823 /* Found bind address */
824 psz_bind = psz_parser;
826 while( *psz_parser && *psz_parser != ':' )
832 if( *psz_parser == ':' )
834 /* Found bind port */
835 *psz_parser = '\0'; /* Terminate bind address if necessary */
838 psz_bind_port = psz_parser;
842 /* Convert ports format */
843 if( psz_server_port != NULL )
845 i_server_port = strtol( psz_server_port, &psz_parser, 10 );
848 intf_ErrMsg( "input error: cannot parse server port near %s",
850 p_input->b_error = 1;
855 if( psz_bind_port != NULL )
857 i_bind_port = strtol( psz_bind_port, &psz_parser, 10 );
860 intf_ErrMsg( "input error: cannot parse bind port near %s",
862 p_input->b_error = 1;
869 /* This is required or NetworkClose will never be called */
870 p_input->p_source = "ts: network input";
873 /* Check that we got a valid port */
874 if( i_bind_port == 0 )
876 i_bind_port = config_GetIntVariable( INPUT_PORT_VAR );
879 intf_WarnMsg( 2, "input: server=%s:%d local=%s:%d",
880 psz_server, i_server_port, psz_bind, i_bind_port );
882 /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET domain, automatic (0)
884 p_input->i_handle = socket( AF_INET, SOCK_DGRAM, 0 );
885 if( p_input->i_handle == -1 )
887 intf_ErrMsg( "input error: can't create socket (%s)", strerror(errno) );
888 p_input->b_error = 1;
892 /* We may want to reuse an already used socket */
894 if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
895 (void *) &i_opt, sizeof( i_opt ) ) == -1 )
897 intf_ErrMsg( "input error: can't configure socket (SO_REUSEADDR: %s)",
899 close( p_input->i_handle );
900 p_input->b_error = 1;
904 /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
905 * packet loss caused by scheduling problems */
907 if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF,
908 (void *) &i_opt, sizeof( i_opt ) ) == -1 )
910 intf_WarnMsg( 1, "input warning: can't configure socket (SO_RCVBUF: %s)",
914 /* Check if we really got what we have asked for, because Linux, etc.
915 * will silently limit the max buffer size to net.core.rmem_max which
916 * is typically only 65535 bytes */
918 i_opt_size = sizeof( i_opt );
919 if( getsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF,
920 (void*) &i_opt, &i_opt_size ) == -1 )
922 intf_WarnMsg( 1, "input warning: can't query socket (SO_RCVBUF: %s)",
925 else if( i_opt < 0x80000 )
927 intf_WarnMsg( 1, "input warning: socket buffer size is 0x%x"
928 " instead of 0x%x", i_opt, 0x80000 );
931 /* Build the local socket */
932 if ( network_BuildAddr( &sock, psz_bind, i_bind_port ) == -1 )
934 intf_ErrMsg( "input error: can't build local address" );
935 close( p_input->i_handle );
936 p_input->b_error = 1;
941 if( bind( p_input->i_handle, (struct sockaddr *)&sock,
942 sizeof( sock ) ) < 0 )
944 intf_ErrMsg( "input error: can't bind socket (%s)", strerror(errno) );
945 close( p_input->i_handle );
946 p_input->b_error = 1;
950 /* Allow broadcast reception if we bound on INADDR_ANY */
951 if( psz_bind == NULL )
954 if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_BROADCAST,
955 (void*) &i_opt, sizeof( i_opt ) ) == -1 )
957 intf_WarnMsg( 1, "input warning: can't configure socket (SO_BROADCAST: %s)",
962 /* Join the multicast group if the socket is a multicast address */
964 # define IN_MULTICAST(a) IN_CLASSD(a)
967 if( IN_MULTICAST( ntohl(sock.sin_addr.s_addr) ) )
971 imr.imr_interface.s_addr = INADDR_ANY;
972 imr.imr_multiaddr.s_addr = sock.sin_addr.s_addr;
973 if( setsockopt( p_input->i_handle, IPPROTO_IP, IP_ADD_MEMBERSHIP,
974 (char*)&imr, sizeof(struct ip_mreq) ) == -1 )
976 intf_ErrMsg( "input error: failed to join IP multicast group (%s)",
978 close( p_input->i_handle );
979 p_input->b_error = 1;
984 if( psz_server != NULL )
986 /* Build socket for remote connection */
987 if ( network_BuildAddr( &sock, psz_server, i_server_port ) == -1 )
989 intf_ErrMsg( "input error: can't build remote address" );
990 close( p_input->i_handle );
991 p_input->b_error = 1;
995 /* Connect the socket */
996 if( connect( p_input->i_handle, (struct sockaddr *) &sock,
997 sizeof( sock ) ) == (-1) )
999 intf_ErrMsg( "input error: can't connect socket (%s)",
1001 close( p_input->i_handle );
1002 p_input->b_error = 1;
1007 p_input->stream.b_pace_control = 0;
1008 p_input->stream.b_seekable = 0;
1010 intf_WarnMsg( 3, "input: successfully opened network mode" );
1015 /*****************************************************************************
1016 * NetworkClose : close a network socket
1017 *****************************************************************************/
1018 static void NetworkClose( input_thread_t * p_input )
1020 intf_WarnMsg( 2, "input: closing network target `%s'", p_input->p_source );
1022 close( p_input->i_handle );
1025 /*****************************************************************************
1026 * HTTPOpen : make an HTTP request
1027 *****************************************************************************/
1028 static void HTTPOpen( input_thread_t * p_input )
1030 char *psz_server = NULL;
1031 char *psz_path = NULL;
1035 struct sockaddr_in sock;
1036 char psz_buffer[256];
1038 /* Get the remote server */
1039 if( p_input->p_source != NULL )
1041 psz_server = p_input->p_source;
1043 /* Skip the protocol name */
1044 while( *psz_server && *psz_server != ':' )
1049 /* Skip the "://" part */
1050 while( *psz_server && (*psz_server == ':' || *psz_server == '/') )
1055 /* Found a server name */
1058 char *psz_port = psz_server;
1060 /* Skip the hostname part */
1061 while( *psz_port && *psz_port != ':' && *psz_port != '/' )
1066 /* Found a port name */
1069 if( *psz_port == ':' )
1071 /* Replace ':' with '\0' */
1076 psz_path = psz_port;
1077 while( *psz_path && *psz_path != '/' )
1092 if( *psz_port != '\0' )
1094 i_port = atoi( psz_port );
1104 /* Check that we got a valid server */
1105 if( psz_server == NULL )
1107 intf_ErrMsg( "input error: No server given" );
1108 p_input->b_error = 1;
1112 /* Check that we got a valid port */
1115 i_port = 80; /* FIXME */
1118 intf_WarnMsg( 2, "input: server=%s port=%d path=%s", psz_server,
1121 /* Open a SOCK_STREAM (TCP) socket, in the AF_INET domain, automatic (0)
1123 p_input->i_handle = socket( AF_INET, SOCK_STREAM, 0 );
1124 if( p_input->i_handle == -1 )
1126 intf_ErrMsg( "input error: can't create socket (%s)", strerror(errno) ); p_input->b_error = 1;
1130 /* We may want to reuse an already used socket */
1132 if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
1133 (void *) &i_opt, sizeof( i_opt ) ) == -1 )
1135 intf_ErrMsg( "input error: can't configure socket (SO_REUSEADDR: %s)",
1137 close( p_input->i_handle );
1138 p_input->b_error = 1;
1143 if( (psz_proxy = getenv( "http_proxy" )) != NULL )
1145 /* http://myproxy.mydomain:myport/ */
1146 int i_proxy_port = 0;
1148 /* Skip the protocol name */
1149 while( *psz_proxy && *psz_proxy != ':' )
1154 /* Skip the "://" part */
1155 while( *psz_proxy && (*psz_proxy == ':' || *psz_proxy == '/') )
1160 /* Found a proxy name */
1163 char *psz_port = psz_proxy;
1165 /* Skip the hostname part */
1166 while( *psz_port && *psz_port != ':' && *psz_port != '/' )
1171 /* Found a port name */
1176 /* Replace ':' with '\0' */
1180 psz_junk = psz_port;
1181 while( *psz_junk && *psz_junk != '/' )
1191 if( *psz_port != '\0' )
1193 i_proxy_port = atoi( psz_port );
1199 intf_ErrMsg( "input error: http_proxy environment variable is invalid !" );
1200 close( p_input->i_handle );
1201 p_input->b_error = 1;
1205 /* Build socket for proxy connection */
1206 if ( network_BuildAddr( &sock, psz_proxy, i_proxy_port ) == -1 )
1208 intf_ErrMsg( "input error: can't build remote address" );
1209 close( p_input->i_handle );
1210 p_input->b_error = 1;
1216 /* No proxy, direct connection */
1217 if ( network_BuildAddr( &sock, psz_server, i_port ) == -1 )
1219 intf_ErrMsg( "input error: can't build remote address" );
1220 close( p_input->i_handle );
1221 p_input->b_error = 1;
1226 /* Connect the socket */
1227 if( connect( p_input->i_handle, (struct sockaddr *) &sock,
1228 sizeof( sock ) ) == (-1) )
1230 intf_ErrMsg( "input error: can't connect socket (%s)",
1232 close( p_input->i_handle );
1233 p_input->b_error = 1;
1237 p_input->stream.b_seekable = 0;
1238 p_input->stream.b_pace_control = 1; /* TCP/IP... */
1240 # define HTTP_USERAGENT "User-Agent: " COPYRIGHT_MESSAGE "\r\n"
1241 # define HTTP_END "\r\n"
1243 /* Prepare GET ... */
1244 if( psz_proxy != NULL )
1246 snprintf( psz_buffer, sizeof(psz_buffer),
1247 "GET http://%s:%d/%s HTTP/1.0\r\n"
1248 HTTP_USERAGENT HTTP_END,
1249 psz_server, i_port, psz_path );
1253 snprintf( psz_buffer, sizeof(psz_buffer),
1254 "GET /%s HTTP/1.0\r\nHost: %s\r\n"
1255 HTTP_USERAGENT HTTP_END,
1256 psz_path, psz_server );
1258 psz_buffer[sizeof(psz_buffer) - 1] = '\0';
1261 if( write( p_input->i_handle, psz_buffer, strlen( psz_buffer ) ) == (-1) )
1263 intf_ErrMsg( "input error: can't send request (%s)", strerror(errno) );
1264 close( p_input->i_handle );
1265 p_input->b_error = 1;
1269 /* Read HTTP header - this is gonna be fun with plug-ins which do not
1270 * use p_input->p_stream :-( */
1271 if( (p_input->p_stream = fdopen( p_input->i_handle, "r+" )) == NULL )
1273 intf_ErrMsg( "input error: can't reopen socket (%s)", strerror(errno) );
1274 close( p_input->i_handle );
1275 p_input->b_error = 1;
1279 while( !feof( p_input->p_stream ) && !ferror( p_input->p_stream ) )
1281 if( fgets( psz_buffer, sizeof(psz_buffer), p_input->p_stream ) == NULL
1282 || *psz_buffer == '\r' || *psz_buffer == '\0' )
1286 /* FIXME : check Content-Type one day */
1289 intf_WarnMsg( 3, "input: successfully opened HTTP mode" );
1292 #endif /* !defined( SYS_BEOS ) && !defined( SYS_NTO ) */