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.170 2002/01/10 04:11:25 sam 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 stream description */
163 p_input->stream.i_es_number = 0;
164 p_input->stream.i_selected_es_number = 0;
165 p_input->stream.i_pgrm_number = 0;
166 p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
167 p_input->stream.b_new_mute = MUTE_NO_CHANGE;
168 p_input->stream.i_mux_rate = 0;
170 /* no stream, no program, no area, no es */
171 p_input->stream.p_new_program = NULL;
173 p_input->stream.i_area_nb = 0;
174 p_input->stream.pp_areas = NULL;
175 p_input->stream.p_selected_area = NULL;
176 p_input->stream.p_new_area = NULL;
178 p_input->stream.pp_selected_es = NULL;
179 p_input->stream.p_removed_es = NULL;
180 p_input->stream.p_newly_selected_es = NULL;
182 /* By default there is one area in a stream */
183 input_AddArea( p_input );
184 p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
186 /* Initialize stream control properties. */
187 p_input->stream.control.i_status = PLAYING_S;
188 p_input->stream.control.i_rate = DEFAULT_RATE;
189 p_input->stream.control.b_mute = 0;
190 p_input->stream.control.b_grayscale = main_GetIntVariable(
191 VOUT_GRAYSCALE_VAR, VOUT_GRAYSCALE_DEFAULT );
192 p_input->stream.control.i_smp = main_GetIntVariable(
193 VDEC_SMP_VAR, VDEC_SMP_DEFAULT );
195 intf_WarnMsg( 1, "input: playlist item `%s'", p_input->p_source );
198 if( vlc_thread_create( &p_input->thread_id, "input", (void *) RunThread,
201 intf_ErrMsg( "input error: can't create input thread (%s)",
208 /* If status is NULL, wait until the thread is created */
209 if( pi_status == NULL )
213 msleep( THREAD_SLEEP );
214 } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
215 && (i_status != THREAD_FATAL) );
222 /*****************************************************************************
223 * input_StopThread: mark an input thread as zombie
224 *****************************************************************************
225 * This function should not return until the thread is effectively cancelled.
226 *****************************************************************************/
227 void input_StopThread( input_thread_t *p_input, int *pi_status )
229 /* Make the thread exit from a possible vlc_cond_wait() */
230 vlc_mutex_lock( &p_input->stream.stream_lock );
232 /* Request thread destruction */
235 vlc_cond_signal( &p_input->stream.stream_wait );
236 vlc_mutex_unlock( &p_input->stream.stream_lock );
238 /* If status is NULL, wait until thread has been destroyed */
240 if( pi_status == NULL )
244 msleep( THREAD_SLEEP );
245 } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
246 && (i_status != THREAD_FATAL) );
251 /*****************************************************************************
252 * input_DestroyThread: mark an input thread as zombie
253 *****************************************************************************
254 * This function should not return until the thread is effectively cancelled.
255 *****************************************************************************/
256 void input_DestroyThread( input_thread_t *p_input )
258 /* Join the thread */
259 vlc_thread_join( p_input->thread_id );
261 /* Destroy Mutex locks */
262 vlc_mutex_destroy( &p_input->stream.control.control_lock );
263 vlc_mutex_destroy( &p_input->stream.stream_lock );
265 /* Free input structure */
269 /*****************************************************************************
270 * RunThread: main thread loop
271 *****************************************************************************
272 * Thread in charge of processing the network packets and demultiplexing.
273 *****************************************************************************/
274 static void RunThread( input_thread_t *p_input )
276 if( InitThread( p_input ) )
278 /* If we failed, wait before we are killed, and exit */
279 p_input->i_status = THREAD_ERROR;
280 p_input->b_error = 1;
281 ErrorThread( p_input );
282 DestroyThread( p_input );
286 p_input->i_status = THREAD_READY;
288 /* initialization is complete */
289 vlc_mutex_lock( &p_input->stream.stream_lock );
290 p_input->stream.b_changed = 1;
291 vlc_mutex_unlock( &p_input->stream.stream_lock );
293 while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
295 data_packet_t * p_data;
300 vlc_mutex_lock( &p_input->stream.stream_lock );
302 if( p_input->stream.p_new_program )
304 if( p_input->pf_set_program != NULL )
307 p_input->pf_set_program( p_input,
308 p_input->stream.p_new_program );
310 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
312 pgrm_descriptor_t * p_pgrm
313 = p_input->stream.pp_programs[i];
314 /* Escape all decoders for the stream discontinuity they
316 input_EscapeDiscontinuity( p_input, p_pgrm );
318 /* Reinitialize synchro. */
319 p_pgrm->i_synchro_state = SYNCHRO_REINIT;
322 p_input->stream.p_new_program = NULL;
325 if( p_input->stream.p_new_area )
327 if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
330 p_input->pf_set_area( p_input, p_input->stream.p_new_area );
332 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
334 pgrm_descriptor_t * p_pgrm
335 = p_input->stream.pp_programs[i];
336 /* Escape all decoders for the stream discontinuity they
338 input_EscapeDiscontinuity( p_input, p_pgrm );
340 /* Reinitialize synchro. */
341 p_pgrm->i_synchro_state = SYNCHRO_REINIT;
344 p_input->stream.p_new_area = NULL;
347 if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
349 if( p_input->stream.b_seekable && p_input->pf_seek != NULL )
351 p_input->pf_seek( p_input,
352 p_input->stream.p_selected_area->i_seek );
354 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
356 pgrm_descriptor_t * p_pgrm
357 = p_input->stream.pp_programs[i];
358 /* Escape all decoders for the stream discontinuity they
360 input_EscapeDiscontinuity( p_input, p_pgrm );
362 /* Reinitialize synchro. */
363 p_pgrm->i_synchro_state = SYNCHRO_REINIT;
366 p_input->stream.p_selected_area->i_seek = NO_SEEK;
369 if( p_input->stream.p_removed_es )
371 input_UnselectES( p_input, p_input->stream.p_removed_es );
372 p_input->stream.p_removed_es = NULL;
375 if( p_input->stream.p_newly_selected_es )
377 input_SelectES( p_input, p_input->stream.p_newly_selected_es );
378 p_input->stream.p_newly_selected_es = NULL;
381 if( p_input->stream.b_new_mute != MUTE_NO_CHANGE )
383 if( p_input->stream.b_new_mute )
385 input_EscapeAudioDiscontinuity( p_input );
388 vlc_mutex_lock( &p_input->stream.control.control_lock );
389 p_input->stream.control.b_mute = p_input->stream.b_new_mute;
390 vlc_mutex_unlock( &p_input->stream.control.control_lock );
392 p_input->stream.b_new_mute = MUTE_NO_CHANGE;
395 vlc_mutex_unlock( &p_input->stream.stream_lock );
397 i_count = p_input->pf_read( p_input, &p_data );
399 /* Demultiplex read packets. */
400 while( p_data != NULL )
402 data_packet_t * p_next = p_data->p_next;
403 p_data->p_next = NULL;
405 p_input->stream.c_packets_read++;
406 p_input->pf_demux( p_input, p_data );
411 if( i_count == 0 && p_input->stream.b_seekable )
413 /* End of file - we do not set b_die because only the
414 * interface is allowed to do so. */
415 intf_WarnMsg( 3, "input: EOF reached" );
418 else if( i_count < 0 )
420 p_input->b_error = 1;
424 if( p_input->b_error || p_input->b_eof )
426 ErrorThread( p_input );
429 EndThread( p_input );
431 DestroyThread( p_input );
433 intf_DbgMsg("input: Thread end");
436 /*****************************************************************************
437 * InitThread: init the input Thread
438 *****************************************************************************/
439 static int InitThread( input_thread_t * p_input )
441 /* Initialize statistics */
442 p_input->c_loops = 0;
443 p_input->stream.c_packets_read = 0;
444 p_input->stream.c_packets_trashed = 0;
445 p_input->p_stream = NULL;
448 vlc_mutex_init( &p_input->stream.stream_lock );
449 vlc_cond_init( &p_input->stream.stream_wait );
450 vlc_mutex_init( &p_input->stream.control.control_lock );
452 /* Find appropriate module. */
453 p_input->p_input_module = module_Need( MODULE_CAPABILITY_INPUT,
454 main_GetPszVariable( INPUT_METHOD_VAR, NULL ),
455 (probedata_t *)p_input );
457 if( p_input->p_input_module == NULL )
459 intf_ErrMsg( "input error: no suitable input module for `%s'",
464 #define f p_input->p_input_module->p_functions->input.functions.input
465 p_input->pf_init = f.pf_init;
466 p_input->pf_end = f.pf_end;
467 p_input->pf_init_bit_stream= f.pf_init_bit_stream;
468 p_input->pf_read = f.pf_read;
469 p_input->pf_set_area = f.pf_set_area;
470 p_input->pf_set_program = f.pf_set_program;
471 p_input->pf_demux = f.pf_demux;
472 p_input->pf_new_packet = f.pf_new_packet;
473 p_input->pf_new_pes = f.pf_new_pes;
474 p_input->pf_delete_packet = f.pf_delete_packet;
475 p_input->pf_delete_pes = f.pf_delete_pes;
476 p_input->pf_rewind = f.pf_rewind;
477 p_input->pf_seek = f.pf_seek;
479 if( f.pf_open != NULL )
481 f.pf_open( p_input );
483 #if !defined( SYS_BEOS ) && !defined( SYS_NTO )
484 /* FIXME : this is waaaay too kludgy */
485 else if( ( strlen( p_input->p_source ) >= 10
486 && !strncasecmp( p_input->p_source, "udpstream:", 10 ) )
487 || ( strlen( p_input->p_source ) >= 4
488 && !strncasecmp( p_input->p_source, "udp:", 4 ) ) )
491 NetworkOpen( p_input );
492 p_input->stream.i_method = INPUT_METHOD_NETWORK;
494 else if( ( strlen( p_input->p_source ) > 5 )
495 && !strncasecmp( p_input->p_source, "http:", 5 ) )
499 p_input->stream.i_method = INPUT_METHOD_NETWORK;
502 else if( ( strlen( p_input->p_source ) == 1 )
503 && *p_input->p_source == '-' )
512 p_input->stream.i_method = INPUT_METHOD_FILE;
516 if( p_input->b_error )
518 /* We barfed -- exit nicely */
519 module_Unneed( p_input->p_input_module );
523 p_input->pf_init( p_input );
525 if( p_input->b_error )
527 /* We barfed -- exit nicely */
528 CloseThread( p_input );
529 module_Unneed( p_input->p_input_module );
536 /*****************************************************************************
537 * ErrorThread: RunThread() error loop
538 *****************************************************************************
539 * This function is called when an error occured during thread main's loop.
540 *****************************************************************************/
541 static void ErrorThread( input_thread_t *p_input )
543 while( !p_input->b_die )
546 msleep( INPUT_IDLE_SLEEP );
550 /*****************************************************************************
551 * EndThread: end the input thread
552 *****************************************************************************/
553 static void EndThread( input_thread_t * p_input )
556 p_input->i_status = THREAD_END;
558 if( p_main->b_stats )
560 #ifdef HAVE_SYS_TIMES_H
561 /* Display statistics */
562 struct tms cpu_usage;
565 intf_StatMsg( "input stats: %d loops consuming user: %d, system: %d",
567 cpu_usage.tms_utime, cpu_usage.tms_stime );
569 intf_StatMsg( "input stats: %d loops", p_input->c_loops );
572 input_DumpStream( p_input );
575 /* Free all ES and destroy all decoder threads */
576 input_EndStream( p_input );
578 /* Free demultiplexer's data */
579 p_input->pf_end( p_input );
581 /* Close the input method */
582 CloseThread( p_input );
584 /* Release modules */
585 module_Unneed( p_input->p_input_module );
588 /*****************************************************************************
589 * CloseThread: close the target
590 *****************************************************************************/
591 static void CloseThread( input_thread_t * p_input )
593 #define f p_input->p_input_module->p_functions->input.functions.input
595 if( f.pf_close != NULL )
597 f.pf_close( p_input );
599 #if !defined( SYS_BEOS ) && !defined( SYS_NTO )
601 else if( ( strlen( p_input->p_source ) > 10
602 && !strncasecmp( p_input->p_source, "udpstream:", 10 ) )
603 || ( strlen( p_input->p_source ) > 4
604 && !strncasecmp( p_input->p_source, "udp:", 4 ) ) )
606 NetworkClose( p_input );
608 else if( ( strlen( p_input->p_source ) > 5 )
609 && !strncasecmp( p_input->p_source, "http:", 5 ) )
611 NetworkClose( p_input );
616 FileClose( p_input );
621 /*****************************************************************************
622 * DestroyThread: destroy the input thread
623 *****************************************************************************/
624 static void DestroyThread( input_thread_t * p_input )
627 p_input->i_status = THREAD_OVER;
630 /*****************************************************************************
631 * StdOpen : open standard input
632 *****************************************************************************/
633 static void StdOpen( input_thread_t * p_input )
635 vlc_mutex_lock( &p_input->stream.stream_lock );
637 /* Suppose we can control the pace - this won't work in some cases ! */
638 p_input->stream.b_pace_control = 1;
640 p_input->stream.b_seekable = 0;
641 p_input->stream.p_selected_area->i_size = 0;
642 p_input->stream.p_selected_area->i_tell = 0;
643 vlc_mutex_unlock( &p_input->stream.stream_lock );
645 intf_WarnMsg( 2, "input: opening stdin" );
646 p_input->i_handle = 0;
649 /*****************************************************************************
650 * FileOpen : open a file descriptor
651 *****************************************************************************/
652 static void FileOpen( input_thread_t * p_input )
654 struct stat stat_info;
657 char *psz_name = p_input->p_source;
659 if( ( i_stat = stat( psz_name, &stat_info ) ) == (-1) )
661 int i_size = strlen( psz_name );
664 && !strncasecmp( psz_name, "dvdread:", 8 ) )
666 /* get rid of the 'dvdread:' stuff and try again */
668 i_stat = stat( psz_name, &stat_info );
670 else if( ( i_size > 4 )
671 && !strncasecmp( psz_name, "dvd:", 4 ) )
673 /* get rid of the 'dvd:' stuff and try again */
675 i_stat = stat( psz_name, &stat_info );
677 else if( ( i_size > 4 )
678 && !strncasecmp( psz_name, "vcd:", 4 ) )
680 /* get rid of the 'vcd:' stuff and try again */
682 i_stat = stat( psz_name, &stat_info );
684 else if( ( i_size > 5 )
685 && !strncasecmp( psz_name, "file:", 5 ) )
687 /* get rid of the 'file:' stuff and try again */
689 i_stat = stat( psz_name, &stat_info );
694 intf_ErrMsg( "input error: cannot stat() file `%s' (%s)",
695 psz_name, strerror(errno));
696 p_input->b_error = 1;
701 vlc_mutex_lock( &p_input->stream.stream_lock );
703 /* If we are here we can control the pace... */
704 p_input->stream.b_pace_control = 1;
706 if( S_ISREG(stat_info.st_mode) || S_ISCHR(stat_info.st_mode)
707 || S_ISBLK(stat_info.st_mode) )
709 p_input->stream.b_seekable = 1;
710 p_input->stream.p_selected_area->i_size = stat_info.st_size;
712 else if( S_ISFIFO(stat_info.st_mode)
713 #if !defined( SYS_BEOS ) && !defined( WIN32 )
714 || S_ISSOCK(stat_info.st_mode)
718 p_input->stream.b_seekable = 0;
719 p_input->stream.p_selected_area->i_size = 0;
723 vlc_mutex_unlock( &p_input->stream.stream_lock );
724 intf_ErrMsg( "input error: unknown file type for `%s'",
726 p_input->b_error = 1;
730 p_input->stream.p_selected_area->i_tell = 0;
731 vlc_mutex_unlock( &p_input->stream.stream_lock );
733 intf_WarnMsg( 2, "input: opening file `%s'", p_input->p_source );
734 if( (p_input->i_handle = open( psz_name,
735 /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
737 intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
738 p_input->b_error = 1;
744 /*****************************************************************************
745 * FileClose : close a file descriptor
746 *****************************************************************************/
747 static void FileClose( input_thread_t * p_input )
749 intf_WarnMsg( 2, "input: closing file `%s'", p_input->p_source );
751 close( p_input->i_handle );
756 #if !defined( SYS_BEOS ) && !defined( SYS_NTO )
757 /*****************************************************************************
758 * NetworkOpen : open a network socket
759 *****************************************************************************/
760 static void NetworkOpen( input_thread_t * p_input )
762 char *psz_server = NULL;
763 char *psz_bind = NULL;
764 int i_server_port = 0;
768 struct sockaddr_in sock;
770 /* Get the remote server. Syntax is :
771 * udp[stream]:[/][/][serveraddr[:serverport]][@[bindaddr]:[bindport]] */
772 if( p_input->p_source != NULL )
774 char * psz_parser = p_input->p_source;
775 char * psz_server_port = NULL;
776 char * psz_bind_port = NULL;
778 /* Skip the protocol name */
779 while( *psz_parser && *psz_parser != ':' )
784 /* Skip the "://" part */
785 while( *psz_parser && (*psz_parser == ':' || *psz_parser == '/') )
790 if( *psz_parser && *psz_parser != '@' )
793 psz_server = psz_parser;
795 while( *psz_parser && *psz_parser != ':' && *psz_parser != '@' )
800 if( *psz_parser == ':' )
802 /* Found server port */
803 *psz_parser = '\0'; /* Terminate server name */
805 psz_server_port = psz_parser;
807 while( *psz_parser && *psz_parser != '@' )
814 if( *psz_parser == '@' )
816 /* Found bind address or bind port */
817 *psz_parser = '\0'; /* Terminate server port or name if necessary */
820 if( *psz_parser && *psz_parser != ':' )
822 /* Found bind address */
823 psz_bind = psz_parser;
825 while( *psz_parser && *psz_parser != ':' )
831 if( *psz_parser == ':' )
833 /* Found bind port */
834 *psz_parser = '\0'; /* Terminate bind address if necessary */
837 psz_bind_port = psz_parser;
841 /* Convert ports format */
842 if( psz_server_port != NULL )
844 i_server_port = strtol( psz_server_port, &psz_parser, 10 );
847 intf_ErrMsg( "input error: cannot parse server port near %s",
849 p_input->b_error = 1;
854 if( psz_bind_port != NULL )
856 i_bind_port = strtol( psz_bind_port, &psz_parser, 10 );
859 intf_ErrMsg( "input error: cannot parse bind port near %s",
861 p_input->b_error = 1;
868 /* This is required or NetworkClose will never be called */
869 p_input->p_source = "ts: network input";
872 /* Check that we got a valid port */
873 if( i_bind_port == 0 )
875 i_bind_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT );
878 intf_WarnMsg( 2, "input: server=%s:%d local=%s:%d",
879 psz_server, i_server_port, psz_bind, i_bind_port );
881 /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET domain, automatic (0)
883 p_input->i_handle = socket( AF_INET, SOCK_DGRAM, 0 );
884 if( p_input->i_handle == -1 )
886 intf_ErrMsg( "input error: can't create socket (%s)", strerror(errno) );
887 p_input->b_error = 1;
891 /* We may want to reuse an already used socket */
893 if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
894 (void *) &i_opt, sizeof( i_opt ) ) == -1 )
896 intf_ErrMsg( "input error: can't configure socket (SO_REUSEADDR: %s)",
898 close( p_input->i_handle );
899 p_input->b_error = 1;
903 /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
904 * packet loss caused by scheduling problems */
906 if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF,
907 (void *) &i_opt, sizeof( i_opt ) ) == -1 )
909 intf_WarnMsg( 1, "input warning: can't configure socket (SO_RCVBUF: %s)",
913 /* Check if we really got what we have asked for, because Linux, etc.
914 * will silently limit the max buffer size to net.core.rmem_max which
915 * is typically only 65535 bytes */
917 i_opt_size = sizeof( i_opt );
918 if( getsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF,
919 (void*) &i_opt, &i_opt_size ) == -1 )
921 intf_WarnMsg( 1, "input warning: can't query socket (SO_RCVBUF: %s)",
924 else if( i_opt < 0x80000 )
926 intf_WarnMsg( 1, "input warning: socket buffer size is 0x%x"
927 " instead of 0x%x", i_opt, 0x80000 );
930 /* Build the local socket */
931 if ( network_BuildAddr( &sock, psz_bind, i_bind_port ) == -1 )
933 intf_ErrMsg( "input error: can't build local address" );
934 close( p_input->i_handle );
935 p_input->b_error = 1;
940 if( bind( p_input->i_handle, (struct sockaddr *)&sock,
941 sizeof( sock ) ) < 0 )
943 intf_ErrMsg( "input error: can't bind socket (%s)", strerror(errno) );
944 close( p_input->i_handle );
945 p_input->b_error = 1;
949 /* Allow broadcast reception if we bound on INADDR_ANY */
950 if( psz_bind == NULL )
953 if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_BROADCAST,
954 (void*) &i_opt, sizeof( i_opt ) ) == -1 )
956 intf_WarnMsg( 1, "input warning: can't configure socket (SO_BROADCAST: %s)",
961 /* Join the multicast group if the socket is a multicast address */
963 # define IN_MULTICAST(a) IN_CLASSD(a)
966 if( IN_MULTICAST( ntohl(sock.sin_addr.s_addr) ) )
970 imr.imr_interface.s_addr = INADDR_ANY;
971 imr.imr_multiaddr.s_addr = sock.sin_addr.s_addr;
972 if( setsockopt( p_input->i_handle, IPPROTO_IP, IP_ADD_MEMBERSHIP,
973 (char*)&imr, sizeof(struct ip_mreq) ) == -1 )
975 intf_ErrMsg( "input error: failed to join IP multicast group (%s)",
977 close( p_input->i_handle );
978 p_input->b_error = 1;
983 if( psz_server != NULL )
985 /* Build socket for remote connection */
986 if ( network_BuildAddr( &sock, psz_server, i_server_port ) == -1 )
988 intf_ErrMsg( "input error: can't build remote address" );
989 close( p_input->i_handle );
990 p_input->b_error = 1;
994 /* Connect the socket */
995 if( connect( p_input->i_handle, (struct sockaddr *) &sock,
996 sizeof( sock ) ) == (-1) )
998 intf_ErrMsg( "input error: can't connect socket (%s)",
1000 close( p_input->i_handle );
1001 p_input->b_error = 1;
1006 p_input->stream.b_pace_control = 0;
1007 p_input->stream.b_seekable = 0;
1009 intf_WarnMsg( 3, "input: successfully opened network mode" );
1014 /*****************************************************************************
1015 * NetworkClose : close a network socket
1016 *****************************************************************************/
1017 static void NetworkClose( input_thread_t * p_input )
1019 intf_WarnMsg( 2, "input: closing network target `%s'", p_input->p_source );
1021 close( p_input->i_handle );
1024 /*****************************************************************************
1025 * HTTPOpen : make an HTTP request
1026 *****************************************************************************/
1027 static void HTTPOpen( input_thread_t * p_input )
1029 char *psz_server = NULL;
1030 char *psz_path = NULL;
1034 struct sockaddr_in sock;
1035 char psz_buffer[256];
1037 /* Get the remote server */
1038 if( p_input->p_source != NULL )
1040 psz_server = p_input->p_source;
1042 /* Skip the protocol name */
1043 while( *psz_server && *psz_server != ':' )
1048 /* Skip the "://" part */
1049 while( *psz_server && (*psz_server == ':' || *psz_server == '/') )
1054 /* Found a server name */
1057 char *psz_port = psz_server;
1059 /* Skip the hostname part */
1060 while( *psz_port && *psz_port != ':' && *psz_port != '/' )
1065 /* Found a port name */
1068 if( *psz_port == ':' )
1070 /* Replace ':' with '\0' */
1075 psz_path = psz_port;
1076 while( *psz_path && *psz_path != '/' )
1091 if( *psz_port != '\0' )
1093 i_port = atoi( psz_port );
1103 /* Check that we got a valid server */
1104 if( psz_server == NULL )
1106 intf_ErrMsg( "input error: No server given" );
1107 p_input->b_error = 1;
1111 /* Check that we got a valid port */
1114 i_port = 80; /* FIXME */
1117 intf_WarnMsg( 2, "input: server=%s port=%d path=%s", psz_server,
1120 /* Open a SOCK_STREAM (TCP) socket, in the AF_INET domain, automatic (0)
1122 p_input->i_handle = socket( AF_INET, SOCK_STREAM, 0 );
1123 if( p_input->i_handle == -1 )
1125 intf_ErrMsg( "input error: can't create socket (%s)", strerror(errno) ); p_input->b_error = 1;
1129 /* We may want to reuse an already used socket */
1131 if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
1132 (void *) &i_opt, sizeof( i_opt ) ) == -1 )
1134 intf_ErrMsg( "input error: can't configure socket (SO_REUSEADDR: %s)",
1136 close( p_input->i_handle );
1137 p_input->b_error = 1;
1142 if( (psz_proxy = main_GetPszVariable( "http_proxy", NULL )) != NULL )
1144 /* http://myproxy.mydomain:myport/ */
1145 int i_proxy_port = 0;
1147 /* Skip the protocol name */
1148 while( *psz_proxy && *psz_proxy != ':' )
1153 /* Skip the "://" part */
1154 while( *psz_proxy && (*psz_proxy == ':' || *psz_proxy == '/') )
1159 /* Found a proxy name */
1162 char *psz_port = psz_proxy;
1164 /* Skip the hostname part */
1165 while( *psz_port && *psz_port != ':' && *psz_port != '/' )
1170 /* Found a port name */
1175 /* Replace ':' with '\0' */
1179 psz_junk = psz_port;
1180 while( *psz_junk && *psz_junk != '/' )
1190 if( *psz_port != '\0' )
1192 i_proxy_port = atoi( psz_port );
1198 intf_ErrMsg( "input error: http_proxy environment variable is invalid !" );
1199 close( p_input->i_handle );
1200 p_input->b_error = 1;
1204 /* Build socket for proxy connection */
1205 if ( network_BuildAddr( &sock, psz_proxy, i_proxy_port ) == -1 )
1207 intf_ErrMsg( "input error: can't build remote address" );
1208 close( p_input->i_handle );
1209 p_input->b_error = 1;
1215 /* No proxy, direct connection */
1216 if ( network_BuildAddr( &sock, psz_server, i_port ) == -1 )
1218 intf_ErrMsg( "input error: can't build remote address" );
1219 close( p_input->i_handle );
1220 p_input->b_error = 1;
1225 /* Connect the socket */
1226 if( connect( p_input->i_handle, (struct sockaddr *) &sock,
1227 sizeof( sock ) ) == (-1) )
1229 intf_ErrMsg( "input error: can't connect socket (%s)",
1231 close( p_input->i_handle );
1232 p_input->b_error = 1;
1236 p_input->stream.b_seekable = 0;
1237 p_input->stream.b_pace_control = 1; /* TCP/IP... */
1239 # define HTTP_USERAGENT "User-Agent: " COPYRIGHT_MESSAGE "\r\n"
1240 # define HTTP_END "\r\n"
1242 /* Prepare GET ... */
1243 if( psz_proxy != NULL )
1245 snprintf( psz_buffer, sizeof(psz_buffer),
1246 "GET http://%s:%d/%s HTTP/1.0\r\n"
1247 HTTP_USERAGENT HTTP_END,
1248 psz_server, i_port, psz_path );
1252 snprintf( psz_buffer, sizeof(psz_buffer),
1253 "GET /%s HTTP/1.0\r\nHost: %s\r\n"
1254 HTTP_USERAGENT HTTP_END,
1255 psz_path, psz_server );
1257 psz_buffer[sizeof(psz_buffer) - 1] = '\0';
1260 if( write( p_input->i_handle, psz_buffer, strlen( psz_buffer ) ) == (-1) )
1262 intf_ErrMsg( "input error: can't send request (%s)", strerror(errno) );
1263 close( p_input->i_handle );
1264 p_input->b_error = 1;
1268 /* Read HTTP header - this is gonna be fun with plug-ins which do not
1269 * use p_input->p_stream :-( */
1270 if( (p_input->p_stream = fdopen( p_input->i_handle, "r+" )) == NULL )
1272 intf_ErrMsg( "input error: can't reopen socket (%s)", strerror(errno) );
1273 close( p_input->i_handle );
1274 p_input->b_error = 1;
1278 while( !feof( p_input->p_stream ) && !ferror( p_input->p_stream ) )
1280 if( fgets( psz_buffer, sizeof(psz_buffer), p_input->p_stream ) == NULL
1281 || *psz_buffer == '\r' || *psz_buffer == '\0' )
1285 /* FIXME : check Content-Type one day */
1288 intf_WarnMsg( 3, "input: successfully opened HTTP mode" );
1291 #endif /* !defined( SYS_BEOS ) && !defined( SYS_NTO ) */