]> git.sesse.net Git - vlc/blob - src/input/input.c
d8ba850b4fc978d917ca03cab2d7b6de6301c8a3
[vlc] / src / input / input.c
1 /*****************************************************************************
2  * input.c: input thread
3  * Read an MPEG2 stream, demultiplex and parse it before sending it to
4  * decoders.
5  *****************************************************************************
6  * Copyright (C) 1998, 1999, 2000 VideoLAN
7  * $Id: input.c,v 1.133 2001/10/02 16:46:59 massiot Exp $
8  *
9  * Authors: Christophe Massiot <massiot@via.ecp.fr>
10  *
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.
15  * 
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.
20  *
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  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include "defs.h"
30
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35
36 #ifdef HAVE_UNISTD_H
37 #   include <unistd.h>
38 #elif defined( _MSC_VER ) && defined( _WIN32 )
39 #   include <io.h>
40 #endif
41
42 #include <string.h>
43 #include <errno.h>
44
45 #ifdef STRNCASECMP_IN_STRINGS_H
46 #   include <strings.h>
47 #endif
48
49 #ifdef WIN32
50 #   include <winsock2.h>
51 #elif !defined( SYS_BEOS ) && !defined( SYS_NTO )
52 #   include <netdb.h>                                         /* hostent ... */
53 #   include <sys/socket.h>
54 #   include <netinet/in.h>
55 #   include <arpa/inet.h>
56 #   include <sys/types.h>
57 #   include <sys/socket.h>
58 #endif
59
60 #include <sys/times.h>
61
62 #include "config.h"
63 #include "common.h"
64 #include "threads.h"
65 #include "mtime.h"
66 #include "netutils.h"
67 #include "modules.h"
68
69 #include "intf_msg.h"
70 #include "intf_playlist.h"
71
72 #include "stream_control.h"
73 #include "input_ext-intf.h"
74 #include "input_ext-dec.h"
75 #include "input_ext-plugins.h"
76
77 #include "interface.h"
78
79 #include "main.h"
80
81 /*****************************************************************************
82  * Local prototypes
83  *****************************************************************************/
84 static void RunThread       ( input_thread_t *p_input );
85 static  int InitThread      ( input_thread_t *p_input );
86 static void ErrorThread     ( input_thread_t *p_input );
87 static void DestroyThread   ( input_thread_t *p_input );
88 static void EndThread       ( input_thread_t *p_input );
89
90 static void FileOpen        ( input_thread_t *p_input );
91 static void FileClose       ( input_thread_t *p_input );
92 #if !defined( SYS_BEOS ) && !defined( SYS_NTO )
93 static void NetworkOpen     ( input_thread_t *p_input );
94 static void HTTPOpen        ( input_thread_t *p_input );
95 static void NetworkClose    ( input_thread_t *p_input );
96 #endif
97
98 /*****************************************************************************
99  * input_CreateThread: creates a new input thread
100  *****************************************************************************
101  * This function creates a new input, and returns a pointer
102  * to its description. On error, it returns NULL.
103  * If pi_status is NULL, then the function will block until the thread is ready.
104  * If not, it will be updated using one of the THREAD_* constants.
105  *****************************************************************************/
106 input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
107 {
108     input_thread_t *    p_input;                        /* thread descriptor */
109     int                 i_status;                           /* thread status */
110
111     /* Allocate descriptor */
112     p_input = (input_thread_t *)malloc( sizeof(input_thread_t) );
113     if( p_input == NULL )
114     {
115         intf_ErrMsg( "input error: can't allocate input thread (%s)",
116                      strerror(errno) );
117         return( NULL );
118     }
119
120     /* Packets read once */
121     p_input->i_read_once = INPUT_READ_ONCE;
122
123     /* Initialize thread properties */
124     p_input->b_die              = 0;
125     p_input->b_error            = 0;
126     p_input->b_eof              = 0;
127
128     /* Set target */
129     p_input->p_source           = p_item->psz_name;
130
131     /* I have never understood that stuff --Meuuh */
132     p_input->pi_status          = (pi_status != NULL) ? pi_status : &i_status;
133     *p_input->pi_status         = THREAD_CREATE;
134
135     /* Initialize stream description */
136     p_input->stream.i_es_number = 0;
137     p_input->stream.i_selected_es_number = 0;
138     p_input->stream.i_pgrm_number = 0;
139     p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
140     p_input->stream.b_new_mute = MUTE_NO_CHANGE;
141     p_input->stream.i_mux_rate = 0;
142
143     /* no stream, no area */
144     p_input->stream.i_area_nb = 0;
145     p_input->stream.pp_areas = NULL;
146     p_input->stream.p_selected_area = NULL;
147     p_input->stream.p_new_area = NULL;
148
149     /* By default there is one area in a stream */
150     input_AddArea( p_input );
151     p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
152
153     /* Initialize stream control properties. */
154     p_input->stream.control.i_status = PLAYING_S;
155     p_input->stream.control.i_rate = DEFAULT_RATE;
156     p_input->stream.control.b_mute = 0;
157     p_input->stream.control.b_grayscale = main_GetIntVariable(
158                             VOUT_GRAYSCALE_VAR, VOUT_GRAYSCALE_DEFAULT );
159     p_input->stream.control.i_smp = main_GetIntVariable(
160                             VDEC_SMP_VAR, VDEC_SMP_DEFAULT );
161
162     intf_WarnMsg( 1, "input: playlist item `%s'", p_input->p_source );
163
164     /* Create thread. */
165     if( vlc_thread_create( &p_input->thread_id, "input", (void *) RunThread,
166                            (void *) p_input ) )
167     {
168         intf_ErrMsg( "input error: can't create input thread (%s)",
169                      strerror(errno) );
170         free( p_input );
171         return( NULL );
172     }
173
174     /* If status is NULL, wait until the thread is created */
175     if( pi_status == NULL )
176     {
177         do
178         {
179             msleep( THREAD_SLEEP );
180         } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
181                 && (i_status != THREAD_FATAL) );
182         if( i_status != THREAD_READY )
183         {
184             return( NULL );
185         }
186     }
187     return( p_input );
188 }
189
190 /*****************************************************************************
191  * input_DestroyThread: mark an input thread as zombie
192  *****************************************************************************
193  * This function should not return until the thread is effectively cancelled.
194  *****************************************************************************/
195 void input_DestroyThread( input_thread_t *p_input, int *pi_status )
196 {
197     int         i_status;                                   /* thread status */
198
199     /* Set status */
200     p_input->pi_status = (pi_status != NULL) ? pi_status : &i_status;
201     *p_input->pi_status = THREAD_DESTROY;
202
203     /* Request thread destruction */
204     p_input->b_die = 1;
205
206     /* Make the thread exit of an eventual vlc_cond_wait() */
207     vlc_mutex_lock( &p_input->stream.stream_lock );
208     vlc_cond_signal( &p_input->stream.stream_wait );
209     vlc_mutex_unlock( &p_input->stream.stream_lock );
210
211     /* If status is NULL, wait until thread has been destroyed */
212     if( pi_status == NULL )
213     {
214         do
215         {
216             msleep( THREAD_SLEEP );
217         } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
218                   && (i_status != THREAD_FATAL) );
219     }
220 }
221
222 /*****************************************************************************
223  * RunThread: main thread loop
224  *****************************************************************************
225  * Thread in charge of processing the network packets and demultiplexing.
226  *****************************************************************************/
227 static void RunThread( input_thread_t *p_input )
228 {
229     int                     i_error, i;
230     data_packet_t **        pp_packets;
231
232     if( InitThread( p_input ) )
233     {
234         /* If we failed, wait before we are killed, and exit */
235         *p_input->pi_status = THREAD_ERROR;
236         p_input->b_error = 1;
237         ErrorThread( p_input );
238         DestroyThread( p_input );
239         return;
240     }
241
242     /* initialization is completed */
243     vlc_mutex_lock( &p_input->stream.stream_lock );
244     p_input->stream.b_changed = 1;
245     vlc_mutex_unlock( &p_input->stream.stream_lock );
246
247     pp_packets = (data_packet_t **) malloc( p_input->i_read_once *
248                                         sizeof( data_packet_t * ) );
249     if( pp_packets == NULL )
250     {
251         intf_ErrMsg( "input error: out of memory" );
252         free( pp_packets );
253         p_input->b_error = 1;
254     }
255
256     while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
257     {
258         p_input->c_loops++;
259
260         vlc_mutex_lock( &p_input->stream.stream_lock );
261
262         if( p_input->stream.p_new_area )
263         {
264             if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
265             {
266
267                 p_input->pf_set_area( p_input, p_input->stream.p_new_area );
268
269                 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
270                 {
271                     pgrm_descriptor_t * p_pgrm
272                                             = p_input->stream.pp_programs[i];
273                     /* Escape all decoders for the stream discontinuity they
274                      * will encounter. */
275                     input_EscapeDiscontinuity( p_input, p_pgrm );
276
277                     /* Reinitialize synchro. */
278                     p_pgrm->i_synchro_state = SYNCHRO_REINIT;
279                 }
280             }
281             p_input->stream.p_new_area = NULL;
282         }
283
284         if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
285         {
286             if( p_input->stream.b_seekable && p_input->pf_seek != NULL )
287             {
288                 p_input->pf_seek( p_input,
289                                   p_input->stream.p_selected_area->i_seek );
290
291                 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
292                 {
293                     pgrm_descriptor_t * p_pgrm
294                                             = p_input->stream.pp_programs[i];
295                     /* Escape all decoders for the stream discontinuity they
296                      * will encounter. */
297                     input_EscapeDiscontinuity( p_input, p_pgrm );
298
299                     /* Reinitialize synchro. */
300                     p_pgrm->i_synchro_state = SYNCHRO_REINIT;
301                 }
302             }
303             p_input->stream.p_selected_area->i_seek = NO_SEEK;
304         }
305
306         if( p_input->stream.p_removed_es )
307         {
308             input_UnselectES( p_input, p_input->stream.p_removed_es );
309             p_input->stream.p_removed_es = NULL;
310         }
311
312         if( p_input->stream.p_newly_selected_es )
313         {
314             input_SelectES( p_input, p_input->stream.p_newly_selected_es );
315             p_input->stream.p_newly_selected_es = NULL;
316         }
317
318         if( p_input->stream.b_new_mute != MUTE_NO_CHANGE )
319         {
320             if( p_input->stream.b_new_mute )
321             {
322                 input_EscapeAudioDiscontinuity( p_input );
323             }
324
325             vlc_mutex_lock( &p_input->stream.control.control_lock );
326             p_input->stream.control.b_mute = p_input->stream.b_new_mute;
327             vlc_mutex_unlock( &p_input->stream.control.control_lock );
328
329             p_input->stream.b_new_mute = MUTE_NO_CHANGE;
330         }
331
332         vlc_mutex_unlock( &p_input->stream.stream_lock );
333
334         i_error = p_input->pf_read( p_input, pp_packets );
335
336         /* Demultiplex read packets. */
337         for( i = 0; i < p_input->i_read_once && pp_packets[i] != NULL; i++ )
338         {
339             p_input->stream.c_packets_read++;
340             p_input->pf_demux( p_input, pp_packets[i] );
341         }
342
343         if( i_error )
344         {
345             if( i_error == 1 )
346             {
347                 /* End of file - we do not set b_die because only the
348                  * interface is allowed to do so. */
349                 intf_WarnMsg( 3, "input: EOF reached" );
350                 p_input->b_eof = 1;
351             }
352             else
353             {
354                 p_input->b_error = 1;
355             }
356         }
357     }
358
359     free( pp_packets );
360
361     if( p_input->b_error || p_input->b_eof )
362     {
363         ErrorThread( p_input );
364     }
365
366     EndThread( p_input );
367
368     DestroyThread( p_input );
369
370     intf_DbgMsg("input: Thread end");
371 }
372
373 /*****************************************************************************
374  * InitThread: init the input Thread
375  *****************************************************************************/
376 static int InitThread( input_thread_t * p_input )
377 {
378
379     /* Initialize statistics */
380     p_input->c_loops                    = 0;
381     p_input->stream.c_packets_read      = 0;
382     p_input->stream.c_packets_trashed   = 0;
383     p_input->p_stream                   = NULL;
384
385     /* Set locks. */
386     vlc_mutex_init( &p_input->stream.stream_lock );
387     vlc_cond_init( &p_input->stream.stream_wait );
388     vlc_mutex_init( &p_input->stream.control.control_lock );
389
390     /* Find appropriate module. */
391     p_input->p_input_module = module_Need( MODULE_CAPABILITY_INPUT,
392                                            (probedata_t *)p_input );
393
394     if( p_input->p_input_module == NULL )
395     {
396         intf_ErrMsg( "input error: no suitable input module for `%s'",
397                      p_input->p_source );
398         return( -1 );
399     }
400
401 #define f p_input->p_input_module->p_functions->input.functions.input
402     p_input->pf_init          = f.pf_init;
403     p_input->pf_end           = f.pf_end;
404     p_input->pf_init_bit_stream= f.pf_init_bit_stream;
405     p_input->pf_read          = f.pf_read;
406     p_input->pf_set_area      = f.pf_set_area;
407     p_input->pf_demux         = f.pf_demux;
408     p_input->pf_new_packet    = f.pf_new_packet;
409     p_input->pf_new_pes       = f.pf_new_pes;
410     p_input->pf_delete_packet = f.pf_delete_packet;
411     p_input->pf_delete_pes    = f.pf_delete_pes;
412     p_input->pf_rewind        = f.pf_rewind;
413     p_input->pf_seek          = f.pf_seek;
414 #undef f
415
416     /* FIXME : this is waaaay too kludgy */
417     if( (strlen( p_input->p_source ) > 3) && !strncasecmp( p_input->p_source, "ts:", 3 ) )
418     {
419         /* Network stream */
420         NetworkOpen( p_input );
421         p_input->stream.i_method = INPUT_METHOD_NETWORK;
422     }
423     else if( ( strlen( p_input->p_source ) > 5 ) && !strncasecmp( p_input->p_source, "http:", 5 ) )
424     {
425         /* HTTP stream */
426         HTTPOpen( p_input );
427         p_input->stream.i_method = INPUT_METHOD_NETWORK;
428     }
429     else if( ( strlen( p_input->p_source ) > 4 ) && !strncasecmp( p_input->p_source, "dvd:", 4 ) )
430     {
431         /* DVD - this is THE kludge */
432         p_input->p_input_module->p_functions->input.functions.input.pf_open( p_input );
433         p_input->stream.i_method = INPUT_METHOD_DVD;
434     }
435     else
436     {
437         /* File input */
438         FileOpen( p_input );
439         p_input->stream.i_method = INPUT_METHOD_FILE;
440     }
441
442     if( p_input->b_error )
443     {
444         /* We barfed -- exit nicely */
445         module_Unneed( p_input->p_input_module );
446         return( -1 );
447     }
448
449     p_input->pf_init( p_input );
450
451     if( p_input->b_error )
452     {
453         /* We barfed -- exit nicely */
454         p_input->pf_close( p_input );
455         module_Unneed( p_input->p_input_module );
456         return( -1 );
457     }
458
459     *p_input->pi_status = THREAD_READY;
460
461     return( 0 );
462 }
463
464 /*****************************************************************************
465  * ErrorThread: RunThread() error loop
466  *****************************************************************************
467  * This function is called when an error occured during thread main's loop.
468  *****************************************************************************/
469 static void ErrorThread( input_thread_t *p_input )
470 {
471     while( !p_input->b_die )
472     {
473         /* Sleep a while */
474         msleep( INPUT_IDLE_SLEEP );
475     }
476 }
477
478 /*****************************************************************************
479  * EndThread: end the input thread
480  *****************************************************************************/
481 static void EndThread( input_thread_t * p_input )
482 {
483     int *       pi_status;                                  /* thread status */
484
485     /* Store status */
486     pi_status = p_input->pi_status;
487     *pi_status = THREAD_END;
488
489     if( p_main->b_stats )
490     {
491         /* Display statistics */
492         struct tms  cpu_usage;
493         times( &cpu_usage );
494
495         intf_StatMsg( "input stats: %d loops consuming user: %d, system: %d",
496                       p_input->c_loops,
497                       cpu_usage.tms_utime, cpu_usage.tms_stime );
498
499         input_DumpStream( p_input );
500     }
501
502     /* Free all ES and destroy all decoder threads */
503     input_EndStream( p_input );
504
505     /* Free demultiplexer's data */
506     p_input->pf_end( p_input );
507
508     /* Close stream */
509     if( (strlen( p_input->p_source ) > 3) && !strncasecmp( p_input->p_source, "ts:", 3 ) )
510     {
511         NetworkClose( p_input );
512     }
513     else if( ( strlen( p_input->p_source ) > 5 ) && !strncasecmp( p_input->p_source, "http:", 5 ) )
514     {
515         NetworkClose( p_input );
516     }
517     else if( ( strlen( p_input->p_source ) > 4 ) && !strncasecmp( p_input->p_source, "dvd:", 4 ) )
518     {
519         p_input->p_input_module->p_functions->input.functions.input.pf_close( p_input );
520     }
521     else
522     {
523         FileClose( p_input );
524     }
525
526     /* Release modules */
527     module_Unneed( p_input->p_input_module );
528
529 }
530
531 /*****************************************************************************
532  * DestroyThread: destroy the input thread
533  *****************************************************************************/
534 static void DestroyThread( input_thread_t * p_input )
535 {
536     int *       pi_status;                                  /* thread status */
537
538     /* Store status */
539     pi_status = p_input->pi_status;
540
541     /* Destroy Mutex locks */
542     vlc_mutex_destroy( &p_input->stream.control.control_lock );
543     vlc_mutex_destroy( &p_input->stream.stream_lock );
544     
545     /* Free input structure */
546     free( p_input );
547
548     /* Update status */
549     *pi_status = THREAD_OVER;
550 }
551
552 /*****************************************************************************
553  * FileOpen : open a file descriptor
554  *****************************************************************************/
555 static void FileOpen( input_thread_t * p_input )
556 {
557     struct stat         stat_info;
558     int                 i_stat;
559
560     char *psz_name = p_input->p_source;
561
562     if( ( i_stat = stat( psz_name, &stat_info ) ) == (-1) )
563     {
564         int i_size = strlen( psz_name );
565
566         if( ( i_size > 4 )
567             && !strncasecmp( psz_name, "dvd:", 4 ) )
568         {
569             /* get rid of the 'dvd:' stuff and try again */
570             psz_name += 4;
571             i_stat = stat( psz_name, &stat_info );
572         }
573         else if( ( i_size > 5 )
574                  && !strncasecmp( psz_name, "file:", 5 ) )
575         {
576             /* get rid of the 'file:' stuff and try again */
577             psz_name += 5;
578             i_stat = stat( psz_name, &stat_info );
579         }
580
581         if( i_stat == (-1) )
582         {
583             intf_ErrMsg( "input error: cannot stat() file `%s' (%s)",
584                          psz_name, strerror(errno));
585             p_input->b_error = 1;
586             return;
587         }
588     }
589
590     vlc_mutex_lock( &p_input->stream.stream_lock );
591
592     /* If we are here we can control the pace... */
593     p_input->stream.b_pace_control = 1;
594
595     if( S_ISREG(stat_info.st_mode) || S_ISCHR(stat_info.st_mode)
596          || S_ISBLK(stat_info.st_mode) )
597     {
598         p_input->stream.b_seekable = 1;
599         p_input->stream.p_selected_area->i_size = stat_info.st_size;
600     }
601     else if( S_ISFIFO(stat_info.st_mode)
602 #if !defined( SYS_BEOS ) && !defined( WIN32 )
603              || S_ISSOCK(stat_info.st_mode)
604 #endif
605              )
606     {
607         p_input->stream.b_seekable = 0;
608         p_input->stream.p_selected_area->i_size = 0;
609     }
610     else
611     {
612         vlc_mutex_unlock( &p_input->stream.stream_lock );
613         intf_ErrMsg( "input error: unknown file type for `%s'",
614                      psz_name );
615         p_input->b_error = 1;
616         return;
617     }
618
619     p_input->stream.p_selected_area->i_tell = 0;
620     vlc_mutex_unlock( &p_input->stream.stream_lock );
621
622     intf_WarnMsg( 2, "input: opening file `%s'", p_input->p_source );
623     if( (p_input->i_handle = open( psz_name,
624                                    /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
625     {
626         intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
627         p_input->b_error = 1;
628         return;
629     }
630
631 }
632
633 /*****************************************************************************
634  * FileClose : close a file descriptor
635  *****************************************************************************/
636 static void FileClose( input_thread_t * p_input )
637 {
638     intf_WarnMsg( 2, "input: closing file `%s'", p_input->p_source );
639
640     close( p_input->i_handle );
641
642     return;
643 }
644
645 #if !defined( SYS_BEOS ) && !defined( SYS_NTO )
646 /*****************************************************************************
647  * NetworkOpen : open a network socket 
648  *****************************************************************************/
649 static void NetworkOpen( input_thread_t * p_input )
650 {
651     char                *psz_server = NULL;
652     char                *psz_broadcast = NULL;
653     int                 i_port = 0;
654     int                 i_opt;
655     int                 i_opt_size;
656     struct sockaddr_in  sock;
657     unsigned int        i_mc_group;
658
659 #ifdef WIN32
660     WSADATA Data;
661     int i_err;
662 #endif
663     
664 #ifdef WIN32
665     /* WinSock Library Init. */
666     i_err = WSAStartup( MAKEWORD( 1, 1 ), &Data );
667
668     if( i_err )
669     {
670         intf_ErrMsg( "input: can't initiate WinSocks, error %i", i_err );
671         return ;
672     }
673 #endif
674     
675     /* Get the remote server */
676     if( p_input->p_source != NULL )
677     {
678         psz_server = p_input->p_source;
679
680         /* Skip the protocol name */
681         while( *psz_server && *psz_server != ':' )
682         {
683             psz_server++;
684         }
685
686         /* Skip the "://" part */
687         while( *psz_server && (*psz_server == ':' || *psz_server == '/') )
688         {
689             psz_server++;
690         }
691
692         /* Found a server name */
693         if( *psz_server )
694         {
695             char *psz_port = psz_server;
696
697             /* Skip the hostname part */
698             while( *psz_port && *psz_port != ':' )
699             {
700                 psz_port++;
701             }
702
703             /* Found a port name */
704             if( *psz_port )
705             {
706                 /* Replace ':' with '\0' */
707                 *psz_port = '\0';
708                 psz_port++;
709
710                 psz_broadcast = psz_port;
711                 while( *psz_broadcast && *psz_broadcast != ':' )
712                 {
713                     psz_broadcast++;
714                 }
715
716                 if( *psz_broadcast )
717                 {
718                     *psz_broadcast = '\0';
719                     psz_broadcast++;
720                     while( *psz_broadcast && *psz_broadcast == ':' )
721                     {
722                         psz_broadcast++;
723                     }
724                 }
725                 else
726                 {
727                     psz_broadcast = NULL;
728                 }
729
730                 /* port before broadcast address */
731                 if( *psz_port != '\0' )
732                 {
733                     i_port = atoi( psz_port );
734                 }
735             }
736         }
737         else
738         {
739             psz_server = NULL;
740         }
741     }
742
743     /* Check that we got a valid server */
744     if( psz_server == NULL )
745     {
746         psz_server = main_GetPszVariable( INPUT_SERVER_VAR, 
747                                           INPUT_SERVER_DEFAULT );
748     }
749
750     /* Check that we got a valid port */
751     if( i_port == 0 )
752     {
753         i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT );
754     }
755
756     if( psz_broadcast == NULL )
757     {
758         /* Are we broadcasting ? */
759         if( main_GetIntVariable( INPUT_BROADCAST_VAR,
760                                  INPUT_BROADCAST_DEFAULT ) )
761         {
762             psz_broadcast = main_GetPszVariable( INPUT_BCAST_ADDR_VAR,
763                                                  INPUT_BCAST_ADDR_DEFAULT );
764         }
765         else
766         {
767            psz_broadcast = NULL; 
768         }
769     }
770
771     intf_WarnMsg( 2, "input: server=%s port=%d broadcast=%s",
772                      psz_server, i_port, psz_broadcast );
773
774     /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET domain, automatic (0)
775      * protocol */
776     p_input->i_handle = socket( AF_INET, SOCK_DGRAM, 0 );
777     if( p_input->i_handle == -1 )
778     {
779         intf_ErrMsg( "input error: can't create socket (%s)", strerror(errno) );
780         p_input->b_error = 1;
781         return;
782     }
783
784     /* We may want to reuse an already used socket */
785     i_opt = 1;
786     if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
787                     (void *) &i_opt, sizeof( i_opt ) ) == -1 )
788     {
789         intf_ErrMsg( "input error: can't configure socket (SO_REUSEADDR: %s)",
790                      strerror(errno));
791         close( p_input->i_handle );
792         p_input->b_error = 1;
793         return;
794     }
795
796     /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
797      * packet loss caused by scheduling problems */
798     i_opt = 0x80000;
799     if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF,
800                     (void *) &i_opt, sizeof( i_opt ) ) == -1 )
801     {
802         intf_ErrMsg( "input error: can't configure socket (SO_RCVBUF: %s)", 
803                      strerror(errno));
804         close( p_input->i_handle );
805         p_input->b_error = 1;
806         return;
807     }
808
809     /* Check if we really got what we have asked for, because Linux, etc.
810      * will silently limit the max buffer size to net.core.rmem_max which
811      * is typically only 65535 bytes */
812     i_opt = 0;
813     i_opt_size = sizeof( i_opt );
814     if( getsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF,
815                     (void*) &i_opt, &i_opt_size ) == -1 )
816     {
817         intf_ErrMsg( "input error: can't configure socket (SO_RCVBUF: %s)", 
818                      strerror(errno));
819         close( p_input->i_handle );
820         p_input->b_error = 1;
821         return;
822     }
823     
824     if( i_opt < 0x80000 )
825     {
826         intf_WarnMsg( 1, "input warning: socket receive buffer size just %d instead of %d bytes.",
827                      i_opt, 0x80000 );
828     }
829
830     /* Build the local socket */
831     if ( network_BuildLocalAddr( &sock, i_port, psz_broadcast ) == -1 )
832     {
833         intf_ErrMsg( "input error: can't build local address" );
834         close( p_input->i_handle );
835         p_input->b_error = 1;
836         return;
837     }
838
839     /* Required for IP_ADD_MEMBERSHIP */
840     i_mc_group = sock.sin_addr.s_addr;
841
842 #if defined( WIN32 )
843     if ( psz_broadcast != NULL )
844     {
845         sock.sin_addr.s_addr = INADDR_ANY;
846     }
847 #define IN_MULTICAST(a)         IN_CLASSD(a)
848 #endif
849     
850     /* Bind it */
851     if( bind( p_input->i_handle, (struct sockaddr *)&sock, 
852               sizeof( sock ) ) < 0 )
853     {
854         intf_ErrMsg( "input error: can't bind socket (%s)", strerror(errno) );
855         close( p_input->i_handle );
856         p_input->b_error = 1;
857         return;
858     }
859
860     /* Join the m/c group if sock is a multicast address */
861     if( IN_MULTICAST( ntohl(i_mc_group) ) )
862     {
863         struct ip_mreq imr;
864
865         imr.imr_interface.s_addr = htonl(INADDR_ANY);
866         imr.imr_multiaddr.s_addr = i_mc_group;
867         if( setsockopt( p_input->i_handle, IPPROTO_IP,IP_ADD_MEMBERSHIP,
868                         (char*)&imr, sizeof(struct ip_mreq) ) == -1 )
869         {
870             intf_ErrMsg( "input error: failed to join IP multicast group (%s)",
871                          strerror(errno) );
872             close( p_input->i_handle);
873             p_input->b_error = 1;
874             return;
875         }
876     }
877
878     /* Build socket for remote connection */
879     if ( network_BuildRemoteAddr( &sock, psz_server ) == -1 )
880     {
881         intf_ErrMsg( "input error: can't build remote address" );
882         close( p_input->i_handle );
883         p_input->b_error = 1;
884         return;
885     }
886
887     /* And connect it */
888     if( connect( p_input->i_handle, (struct sockaddr *) &sock,
889                  sizeof( sock ) ) == (-1) )
890     {
891         intf_ErrMsg( "input error: can't connect socket (%s)", 
892                      strerror(errno) );
893         close( p_input->i_handle );
894         p_input->b_error = 1;
895         return;
896     }
897
898     p_input->stream.b_pace_control = 0;
899     p_input->stream.b_seekable = 0;
900
901     intf_WarnMsg( 3, "input: successfully opened network mode" );
902     
903     return;
904 }
905
906 /*****************************************************************************
907  * NetworkClose : close a network socket
908  *****************************************************************************/
909 static void NetworkClose( input_thread_t * p_input )
910 {
911     close( p_input->i_handle );
912
913 #ifdef WIN32 
914     WSACleanup();
915 #endif
916 }
917
918 /*****************************************************************************
919  * HTTPOpen : make an HTTP request
920  *****************************************************************************/
921 static void HTTPOpen( input_thread_t * p_input )
922 {
923     char                *psz_server = NULL;
924     char                *psz_path = NULL;
925     char                *psz_proxy;
926     int                 i_port = 0;
927     int                 i_opt;
928     struct sockaddr_in  sock;
929     char                psz_buffer[256];
930
931 #ifdef WIN32
932     WSADATA Data;
933     int i_err;
934 #endif
935     
936 #ifdef WIN32
937     /* WinSock Library Init. */
938     i_err = WSAStartup( MAKEWORD( 1, 1 ), &Data );
939
940     if( i_err )
941     {
942         intf_ErrMsg( "input: can't initiate WinSocks, error %i", i_err );
943         return ;
944     }
945 #endif
946     
947     /* Get the remote server */
948     if( p_input->p_source != NULL )
949     {
950         psz_server = p_input->p_source;
951
952         /* Skip the protocol name */
953         while( *psz_server && *psz_server != ':' )
954         {
955             psz_server++;
956         }
957
958         /* Skip the "://" part */
959         while( *psz_server && (*psz_server == ':' || *psz_server == '/') )
960         {
961             psz_server++;
962         }
963
964         /* Found a server name */
965         if( *psz_server )
966         {
967             char *psz_port = psz_server;
968
969             /* Skip the hostname part */
970             while( *psz_port && *psz_port != ':' && *psz_port != '/' )
971             {
972                 psz_port++;
973             }
974
975             /* Found a port name */
976             if( *psz_port )
977             {
978                 if( *psz_port == ':' )
979                 {
980                     /* Replace ':' with '\0' */
981                     *psz_port = '\0';
982                     psz_port++;
983                 }
984
985                 psz_path = psz_port;
986                 while( *psz_path && *psz_path != '/' )
987                 {
988                     psz_path++;
989                 }
990
991                 if( *psz_path )
992                 {
993                     *psz_path = '\0';
994                     psz_path++;
995                 }
996                 else
997                 {
998                     psz_path = NULL;
999                 }
1000
1001                 if( *psz_port != '\0' )
1002                 {
1003                     i_port = atoi( psz_port );
1004                 }
1005             }
1006         }
1007         else
1008         {
1009             psz_server = NULL;
1010         }
1011     }
1012
1013     /* Check that we got a valid server */
1014     if( psz_server == NULL )
1015     {
1016         intf_ErrMsg( "input error: No server given" );
1017         p_input->b_error = 1;
1018         return;
1019     }
1020
1021     /* Check that we got a valid port */
1022     if( i_port == 0 )
1023     {
1024         i_port = 80; /* FIXME */
1025     }
1026
1027     intf_WarnMsg( 2, "input: server=%s port=%d path=%s", psz_server,
1028                   i_port, psz_path );
1029
1030     /* Open a SOCK_STREAM (TCP) socket, in the AF_INET domain, automatic (0)
1031      *      * protocol */
1032     p_input->i_handle = socket( AF_INET, SOCK_STREAM, 0 );
1033     if( p_input->i_handle == -1 )
1034     {
1035         intf_ErrMsg( "input error: can't create socket (%s)", strerror(errno) );        p_input->b_error = 1;
1036         return;
1037     }
1038
1039     /* We may want to reuse an already used socket */
1040     i_opt = 1;
1041     if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
1042                     (void *) &i_opt, sizeof( i_opt ) ) == -1 )
1043     {
1044         intf_ErrMsg( "input error: can't configure socket (SO_REUSEADDR: %s)",
1045                      strerror(errno));
1046         close( p_input->i_handle );
1047         p_input->b_error = 1;
1048         return;
1049     }
1050
1051     /* Check proxy */
1052     if( (psz_proxy = main_GetPszVariable( "http_proxy", NULL )) != NULL )
1053     {
1054         /* http://myproxy.mydomain:myport/ */
1055         int                 i_proxy_port = 0;
1056
1057         /* Skip the protocol name */
1058         while( *psz_proxy && *psz_proxy != ':' )
1059         {
1060             psz_proxy++;
1061         }
1062
1063         /* Skip the "://" part */
1064         while( *psz_proxy && (*psz_proxy == ':' || *psz_proxy == '/') )
1065         {
1066             psz_proxy++;
1067         }
1068
1069         /* Found a proxy name */
1070         if( *psz_proxy )
1071         {
1072             char *psz_port = psz_proxy;
1073
1074             /* Skip the hostname part */
1075             while( *psz_port && *psz_port != ':' && *psz_port != '/' )
1076             {
1077                 psz_port++;
1078             }
1079
1080             /* Found a port name */
1081             if( *psz_port )
1082             {
1083                 char * psz_junk;
1084
1085                 /* Replace ':' with '\0' */
1086                 *psz_port = '\0';
1087                 psz_port++;
1088
1089                 psz_junk = psz_port;
1090                 while( *psz_junk && *psz_junk != '/' )
1091                 {
1092                     psz_junk++;
1093                 }
1094
1095                 if( *psz_junk )
1096                 {
1097                     *psz_junk = '\0';
1098                 }
1099
1100                 if( *psz_port != '\0' )
1101                 {
1102                     i_proxy_port = atoi( psz_port );
1103                 }
1104             }
1105         }
1106         else
1107         {
1108             intf_ErrMsg( "input error: http_proxy environment variable is invalid !" );
1109             close( p_input->i_handle );
1110             p_input->b_error = 1;
1111             return;
1112         }
1113
1114         /* Build socket for proxy connection */
1115         if ( network_BuildRemoteAddr( &sock, psz_proxy ) == -1 )
1116         {
1117             intf_ErrMsg( "input error: can't build remote address" );
1118             close( p_input->i_handle );
1119             p_input->b_error = 1;
1120             return;
1121         }
1122         sock.sin_port = htons( i_proxy_port );
1123     }
1124     else
1125     {
1126         /* No proxy, direct connection */
1127         if ( network_BuildRemoteAddr( &sock, psz_server ) == -1 )
1128         {
1129             intf_ErrMsg( "input error: can't build remote address" );
1130             close( p_input->i_handle );
1131             p_input->b_error = 1;
1132             return;
1133         }
1134         sock.sin_port = htons( i_port );
1135     }
1136
1137     /* Connect the socket */
1138     if( connect( p_input->i_handle, (struct sockaddr *) &sock,
1139                  sizeof( sock ) ) == (-1) )
1140     {
1141         intf_ErrMsg( "input error: can't connect socket (%s)",
1142                      strerror(errno) );
1143         close( p_input->i_handle );
1144         p_input->b_error = 1;
1145         return;
1146     }
1147
1148     p_input->stream.b_seekable = 0;
1149     p_input->stream.b_pace_control = 1; /* TCP/IP... */
1150
1151     /* Prepare GET ... */
1152     if( psz_proxy != NULL )
1153     {
1154         snprintf( psz_buffer, sizeof(psz_buffer),
1155                   "GET http://%s:%d/%s HTTP/1.0\r\n\r\n", psz_server,
1156                   i_port, psz_path );
1157     }
1158     else
1159     {
1160         snprintf( psz_buffer, sizeof(psz_buffer), "GET /%s HTTP/1.0\r\n\r\n",
1161                   psz_path );
1162     }
1163     psz_buffer[sizeof(psz_buffer) - 1] = '\0';
1164
1165     /* Send GET ... */
1166     if( write( p_input->i_handle, psz_buffer, strlen( psz_buffer ) ) == (-1) )
1167     {
1168         intf_ErrMsg( "input error: can't send request (%s)", strerror(errno) );
1169         close( p_input->i_handle );
1170         p_input->b_error = 1;
1171         return;
1172     }
1173
1174     /* Read HTTP header - this is gonna be fun with plug-ins which do not
1175      * use p_input->p_stream :-( */
1176     if( (p_input->p_stream = fdopen( p_input->i_handle, "r+" )) == NULL )
1177     {
1178         intf_ErrMsg( "input error: can't reopen socket (%s)", strerror(errno) );
1179         close( p_input->i_handle );
1180         p_input->b_error = 1;
1181         return;
1182     }
1183
1184     while( !feof( p_input->p_stream ) && !ferror( p_input->p_stream ) )
1185     {
1186         if( fgets( psz_buffer, sizeof(psz_buffer), p_input->p_stream ) == NULL
1187              || *psz_buffer == '\r' || *psz_buffer == '\0' )
1188         {
1189             break;
1190         }
1191         /* FIXME : check Content-Type one day */
1192     }
1193
1194     intf_WarnMsg( 3, "input: successfully opened HTTP mode" );
1195 }
1196
1197 #endif /* !defined( SYS_BEOS ) && !defined( SYS_NTO ) */
1198