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