input.c 23.3 KB
Newer Older
1 2
/*****************************************************************************
 * input.c: input thread
Michel Kaempf's avatar
Michel Kaempf committed
3 4
 * Read an MPEG2 stream, demultiplex and parse it before sending it to
 * decoders.
5 6
 *****************************************************************************
 * Copyright (C) 1998, 1999, 2000 VideoLAN
7
 * $Id: input.c,v 1.90 2001/03/07 01:36:41 sam Exp $
8
 *
9
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
10 11 12 13 14
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
15
 * 
16 17
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
20
 *
21 22 23
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
25

26
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
27
 * Preamble
28
 *****************************************************************************/
29 30
#include "defs.h"

31 32 33 34 35 36 37
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
Michel Kaempf's avatar
Michel Kaempf committed
38

39 40
/* Network functions */

41
#ifndef SYS_BEOS
42 43 44 45 46 47
#include <netdb.h>                                             /* hostent ... */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
48
#endif
49

50 51 52 53
#ifdef STATS
#   include <sys/times.h>
#endif

Michel Kaempf's avatar
Michel Kaempf committed
54
#include "config.h"
55 56
#include "common.h"
#include "threads.h"
Michel Kaempf's avatar
Michel Kaempf committed
57
#include "mtime.h"
58
#include "modules.h"
59

60
#include "intf_msg.h"
61
#include "intf_plst.h"
62

63 64 65
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
Michel Lespinasse's avatar
Yop,  
Michel Lespinasse committed
66

67
#include "input.h"
68 69 70
#include "interface.h"

#include "main.h"
Michel Kaempf's avatar
Michel Kaempf committed
71

72
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
73
 * Local prototypes
74
 *****************************************************************************/
75 76 77 78 79
static void RunThread       ( input_thread_t *p_input );
static  int InitThread      ( input_thread_t *p_input );
static void ErrorThread     ( input_thread_t *p_input );
static void DestroyThread   ( input_thread_t *p_input );
static void EndThread       ( input_thread_t *p_input );
Michel Kaempf's avatar
Michel Kaempf committed
80

81
/*****************************************************************************
82
 * input_CreateThread: creates a new input thread
83
 *****************************************************************************
84 85 86 87
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
 * If pi_status is NULL, then the function will block until the thread is ready.
 * If not, it will be updated using one of the THREAD_* constants.
88
 *****************************************************************************/
89
input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
90
{
91 92 93
    input_thread_t *    p_input;                        /* thread descriptor */
    int                 i_status;                           /* thread status */

94 95 96
    /* Allocate descriptor */
    p_input = (input_thread_t *)malloc( sizeof(input_thread_t) );
    if( p_input == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
97
    {
98 99
        intf_ErrMsg( "input error: can't allocate input thread (%s)",
                     strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
100 101
        return( NULL );
    }
102

103 104 105
    /* Packets read once */
    p_input->i_read_once = INPUT_READ_ONCE;

106 107 108
    /* Initialize thread properties */
    p_input->b_die              = 0;
    p_input->b_error            = 0;
109 110 111 112 113
    p_input->b_eof              = 0;

    /* Set target */
    p_input->p_source           = p_item->psz_name;

114
    /* I have never understood that stuff --Meuuh */
115 116
    p_input->pi_status          = (pi_status != NULL) ? pi_status : &i_status;
    *p_input->pi_status         = THREAD_CREATE;
Michel Kaempf's avatar
Michel Kaempf committed
117

118
    /* Initialize stream description */
119 120
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
121
    p_input->stream.i_pgrm_number = 0;
122
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
Christophe Massiot's avatar
Christophe Massiot committed
123
    p_input->stream.i_mux_rate = 0;
Michel Kaempf's avatar
Michel Kaempf committed
124

125 126 127 128
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
    /* By default there is one areas in a stream */
    input_AddArea( p_input );
129 130
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
    p_input->stream.p_selected_area->i_seek = NO_SEEK;
131

132 133 134 135 136
    /* Initialize stream control properties. */
    p_input->stream.control.i_status = PLAYING_S;
    p_input->stream.control.i_rate = DEFAULT_RATE;
    p_input->stream.control.b_mute = 0;
    p_input->stream.control.b_bw = 0;
Michel Kaempf's avatar
Michel Kaempf committed
137

138 139
    /* Initialize default settings for spawned decoders */
    p_input->p_default_aout = p_main->p_aout;
Sam Hocevar's avatar
Sam Hocevar committed
140
    p_input->p_default_vout = p_main->p_vout;
141

Michel Kaempf's avatar
Michel Kaempf committed
142
    /* Create thread and set locks. */
143
    vlc_mutex_init( &p_input->stream.stream_lock );
144
    vlc_cond_init( &p_input->stream.stream_wait );
145 146 147
    vlc_mutex_init( &p_input->stream.control.control_lock );
    if( vlc_thread_create( &p_input->thread_id, "input", (void *) RunThread,
                           (void *) p_input ) )
Michel Kaempf's avatar
Michel Kaempf committed
148
    {
149 150
        intf_ErrMsg( "input error: can't create input thread (%s)",
                     strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
151 152 153
        free( p_input );
        return( NULL );
    }
154

155 156 157 158
    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
159
        {
160
            msleep( THREAD_SLEEP );
161
        } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
162
                && (i_status != THREAD_FATAL) );
163 164
        if( i_status != THREAD_READY )
        {
165 166
            return( NULL );
        }
167
    }
Michel Kaempf's avatar
Michel Kaempf committed
168 169 170
    return( p_input );
}

171
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
172
 * input_DestroyThread: mark an input thread as zombie
173
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
174
 * This function should not return until the thread is effectively cancelled.
175
 *****************************************************************************/
176
void input_DestroyThread( input_thread_t *p_input, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
177
{
178
    int         i_status;                                   /* thread status */
179 180 181

    /* Set status */
    p_input->pi_status = (pi_status != NULL) ? pi_status : &i_status;
182 183
    *p_input->pi_status = THREAD_DESTROY;

184 185
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
186

187 188 189 190 191
    /* Make the thread exit of an eventual vlc_cond_wait() */
    vlc_mutex_lock( &p_input->stream.stream_lock );
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );

192 193 194 195 196 197
    /* If status is NULL, wait until thread has been destroyed */
    if( pi_status == NULL )
    {
        do
        {
            msleep( THREAD_SLEEP );
198 199
        } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                  && (i_status != THREAD_FATAL) );
200
    }
Michel Kaempf's avatar
Michel Kaempf committed
201 202
}

203
/*****************************************************************************
204
 * RunThread: main thread loop
205
 *****************************************************************************
206
 * Thread in charge of processing the network packets and demultiplexing.
207
 *****************************************************************************/
208
static void RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
209
{
210
    int                     i_error, i;
Michel Kaempf's avatar
Michel Kaempf committed
211

212 213 214 215 216 217 218 219 220 221
    if( InitThread( p_input ) )
    {

        /* If we failed, wait before we are killed, and exit */
        *p_input->pi_status = THREAD_ERROR;
        p_input->b_error = 1;
        ErrorThread( p_input );
        DestroyThread( p_input );
        return;
    }
Michel Kaempf's avatar
Michel Kaempf committed
222

223
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
224
    {
225
        data_packet_t *         pp_packets[p_input->i_read_once];
226

227
#ifdef STATS
228
        p_input->c_loops++;
229 230
#endif

231
        vlc_mutex_lock( &p_input->stream.stream_lock );
232
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
233
        {
234 235
            if( p_input->stream.b_seekable && p_input->pf_seek != NULL )
            {
236 237
                p_input->pf_seek( p_input,
                                  p_input->stream.p_selected_area->i_seek );
238 239 240 241 242 243 244 245 246 247 248 249 250

                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
                    pgrm_descriptor_t * p_pgrm
                                            = p_input->stream.pp_programs[i];
                    /* Escape all decoders for the stream discontinuity they
                     * will encounter. */
                    input_EscapeDiscontinuity( p_input, p_pgrm );

                    /* Reinitialize synchro. */
                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
                }
            }
251
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
252
        }
253
        vlc_mutex_unlock( &p_input->stream.stream_lock );
254 255

        i_error = p_input->pf_read( p_input, pp_packets );
256

257
        /* Demultiplex read packets. */
258
        for( i = 0; i < p_input->i_read_once && pp_packets[i] != NULL; i++ )
259 260 261
        {
            p_input->pf_demux( p_input, pp_packets[i] );
        }
262

263 264 265
        if( i_error )
        {
            if( i_error == 1 )
266
            {
267 268 269 270
                /* End of file - we do not set b_die because only the
                 * interface is allowed to do so. */
                intf_WarnMsg( 1, "End of file reached" );
                p_input->b_eof = 1;
271
            }
272
            else
273
            {
274
                p_input->b_error = 1;
275
            }
276 277 278
        }
    }

279
    if( p_input->b_error || p_input->b_eof )
280 281 282
    {
        ErrorThread( p_input );
    }
283

284
    EndThread( p_input );
285 286 287

    DestroyThread( p_input );

288
    intf_DbgMsg("Thread end");
289 290
}

291
/*****************************************************************************
292
 * InitThread: init the input Thread
293
 *****************************************************************************/
294
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
295 296 297
{

#ifdef STATS
298 299 300 301 302 303
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->c_bytes                    = 0;
    p_input->c_payload_bytes            = 0;
    p_input->c_packets_read             = 0;
    p_input->c_packets_trashed          = 0;
Michel Kaempf's avatar
Michel Kaempf committed
304
#endif
305

Sam Hocevar's avatar
Sam Hocevar committed
306
    p_input->p_input_module = module_Need( p_main->p_bank,
307 308
                                           MODULE_CAPABILITY_INPUT,
                                           (probedata_t *)p_input );
309 310

    if( p_input->p_input_module == NULL )
311
    {
312
        intf_ErrMsg( "input error: no suitable input module" );
313
        return( -1 );
Michel Kaempf's avatar
Michel Kaempf committed
314
    }
315

316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
#define f p_input->p_input_module->p_functions->input.functions.input
    p_input->pf_init          = f.pf_init;
    p_input->pf_open          = f.pf_open;
    p_input->pf_close         = f.pf_close;
    p_input->pf_end           = f.pf_end;
    p_input->pf_read          = f.pf_read;
    p_input->pf_demux         = f.pf_demux;
    p_input->pf_new_packet    = f.pf_new_packet;
    p_input->pf_new_pes       = f.pf_new_pes;
    p_input->pf_delete_packet = f.pf_delete_packet;
    p_input->pf_delete_pes    = f.pf_delete_pes;
    p_input->pf_rewind        = f.pf_rewind;
    p_input->pf_seek          = f.pf_seek;
#undef f
    p_input->pf_open( p_input );
331

332
    if( p_input->b_error )
333
    {
334 335
        /* We barfed -- exit nicely */
        p_input->pf_close( p_input );
Sam Hocevar's avatar
Sam Hocevar committed
336
        module_Unneed( p_main->p_bank, p_input->p_input_module );
337
        return( -1 );
338
    }
339 340

    p_input->pf_init( p_input );
341

342
    *p_input->pi_status = THREAD_READY;
343 344

    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
345 346
}

347
/*****************************************************************************
348
 * ErrorThread: RunThread() error loop
349
 *****************************************************************************
350
 * This function is called when an error occured during thread main's loop.
351
 *****************************************************************************/
352
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
353
{
354
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
355
    {
356 357
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
358 359 360
    }
}

361
/*****************************************************************************
362
 * EndThread: end the input thread
363
 *****************************************************************************/
364
static void EndThread( input_thread_t * p_input )
365
{
366
    int *       pi_status;                                  /* thread status */
367

368 369 370
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
371

372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
#ifdef STATS
    {
        struct tms cpu_usage;
        times( &cpu_usage );

        intf_Msg("input stats: cpu usage (user: %d, system: %d)",
                 cpu_usage.tms_utime, cpu_usage.tms_stime);
    }
#endif

    /* Free all ES and destroy all decoder threads */
    input_EndStream( p_input );

    /* Free demultiplexer's data */
    p_input->pf_end( p_input );

388 389 390
    /* Close stream */
    p_input->pf_close( p_input );

391
    /* Release modules */
Sam Hocevar's avatar
Sam Hocevar committed
392
    module_Unneed( p_main->p_bank, p_input->p_input_module );
393

394 395 396 397 398 399 400 401 402 403 404
}

/*****************************************************************************
 * DestroyThread: destroy the input thread
 *****************************************************************************/
static void DestroyThread( input_thread_t * p_input )
{
    int *       pi_status;                                  /* thread status */

    /* Store status */
    pi_status = p_input->pi_status;
405

406 407
    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
408
    vlc_mutex_destroy( &p_input->stream.stream_lock );
409
    
410
    /* Free input structure */
411
    free( p_input );
412

413 414
    /* Update status */
    *pi_status = THREAD_OVER;
415
}
416

417
/*****************************************************************************
418
 * input_FileOpen : open a file descriptor
419
 *****************************************************************************/
420
void input_FileOpen( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
421
{
422
    struct stat         stat_info;
423 424 425
    int                 i_stat;

    char *psz_name = p_input->p_source;
Michel Kaempf's avatar
Michel Kaempf committed
426

427 428 429
    /* FIXME: this code ought to be in the plugin so that code can
     * be shared with the *_Probe function */
    if( ( i_stat = stat( psz_name, &stat_info ) ) == (-1) )
430
    {
431 432 433 434 435 436 437 438
        int i_size = strlen( psz_name );

        if( ( i_size > 4 )
            && !strncasecmp( psz_name, "dvd:", 4 ) )
        {
            /* get rid of the 'dvd:' stuff and try again */
            psz_name += 4;
            i_stat = stat( psz_name, &stat_info );
439
        }
440
        else if( ( i_size > 5 )
441 442 443 444 445
                 && !strncasecmp( psz_name, "file:", 5 ) )
        {
            /* get rid of the 'file:' stuff and try again */
            psz_name += 5;
            i_stat = stat( psz_name, &stat_info );
446
        }
447

448
        if( i_stat == (-1) )
449 450 451 452 453 454
        {
            intf_ErrMsg( "input error: cannot stat() file `%s' (%s)",
                         psz_name, strerror(errno));
            p_input->b_error = 1;
            return;
        }
455 456 457 458 459 460 461 462 463 464 465
    }

    vlc_mutex_lock( &p_input->stream.stream_lock );

    /* If we are here we can control the pace... */
    p_input->stream.b_pace_control = 1;

    if( S_ISREG(stat_info.st_mode) || S_ISCHR(stat_info.st_mode)
         || S_ISBLK(stat_info.st_mode) )
    {
        p_input->stream.b_seekable = 1;
466
        p_input->stream.p_selected_area->i_size = stat_info.st_size;
467
    }
468 469 470 471 472
    else if( S_ISFIFO(stat_info.st_mode)
#ifndef SYS_BEOS
             || S_ISSOCK(stat_info.st_mode)
#endif
             )
473
    {
474
        p_input->stream.b_seekable = 0;
475
        p_input->stream.p_selected_area->i_size = 0;
Benoit Steiner's avatar
Benoit Steiner committed
476 477 478
    }
    else
    {
479
        vlc_mutex_unlock( &p_input->stream.stream_lock );
480
        intf_ErrMsg( "input error: unknown file type for `%s'",
481
                     psz_name );
482 483 484
        p_input->b_error = 1;
        return;
    }
485

486
    p_input->stream.p_selected_area->i_tell = 0;
487 488
    vlc_mutex_unlock( &p_input->stream.stream_lock );

489 490
    intf_Msg( "input: opening %s", p_input->p_source );
    if( (p_input->i_handle = open( psz_name,
491 492
                                   /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
    {
493
        intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
494 495
        p_input->b_error = 1;
        return;
Michel Kaempf's avatar
Michel Kaempf committed
496 497 498
    }

}
Stéphane Borel's avatar
Stéphane Borel committed
499 500

/*****************************************************************************
501
 * input_FileClose : close a file descriptor
Stéphane Borel's avatar
Stéphane Borel committed
502
 *****************************************************************************/
503
void input_FileClose( input_thread_t * p_input )
Stéphane Borel's avatar
Stéphane Borel committed
504
{
505
    close( p_input->i_handle );
Stéphane Borel's avatar
Stéphane Borel committed
506

507
    return;
Stéphane Borel's avatar
Stéphane Borel committed
508
}
509

510
#ifndef SYS_BEOS
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
/*****************************************************************************
 * input_BuildLocalAddr : fill a sockaddr_in structure for local binding
 *****************************************************************************/
int input_BuildLocalAddr( struct sockaddr_in * p_socket, int i_port, 
                      boolean_t b_broadcast )
{
    char                psz_hostname[INPUT_MAX_SOURCE_LENGTH];
    struct hostent    * p_hostent;
    
    /* Reset struct */
    memset( p_socket, 0, sizeof( struct sockaddr_in ) );
    p_socket->sin_family = AF_INET;                                 /* family */
    p_socket->sin_port = htons( i_port );
    
    if( !b_broadcast )
    {
        /* Try to get our own IP */
        if( gethostname( psz_hostname, sizeof(psz_hostname) ) )
        {
            intf_ErrMsg( "BuildLocalAddr : unable to resolve local name : %s",
                         strerror( errno ) );
            return( -1 );
        }

    }
    else
    {
        /* Using broadcast address. There are many ways of doing it, one of
         * the simpliest being a #define ...
         * FIXME : this is ugly */ 
        strncpy( psz_hostname, INPUT_BCAST_ADDR,INPUT_MAX_SOURCE_LENGTH );
    }

    /* Try to convert address directly from in_addr - this will work if
     * psz_in_addr is dotted decimal. */

#ifdef HAVE_ARPA_INET_H
    if( !inet_aton( psz_hostname, &p_socket->sin_addr) )
#else
    if( (p_socket->sin_addr.s_addr = inet_addr( psz_hostname )) == -1 )
#endif
    {
        /* We have a fqdn, try to find its address */
        if ( (p_hostent = gethostbyname( psz_hostname )) == NULL )
        {
            intf_ErrMsg( "BuildLocalAddr: unknown host %s", psz_hostname );
            return( -1 );
        }
        
        /* Copy the first address of the host in the socket address */
        memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0], 
                 p_hostent->h_length );
    }

    return( 0 );
}

/*****************************************************************************
 * input_BuildRemoteAddr : fill a sockaddr_in structure for remote host
 *****************************************************************************/
int input_BuildRemoteAddr( input_thread_t * p_input, 
                           struct sockaddr_in * p_socket )
{
    struct hostent            * p_hostent;

    /* Reset structure */
    memset( p_socket, 0, sizeof( struct sockaddr_in ) );
    p_socket->sin_family = AF_INET;                                 /* family */
    p_socket->sin_port = htons( 0 );                /* This is for remote end */
    
    /* Get the remote server */
    if( p_input->p_source == NULL )
    {
        p_input->p_source = main_GetPszVariable( INPUT_SERVER_VAR, 
                                                 INPUT_SERVER_DEFAULT );
    }

     /* Try to convert address directly from in_addr - this will work if
      * psz_in_addr is dotted decimal. */
#ifdef HAVE_ARPA_INET_H
    if( !inet_aton( p_input->p_source, &p_socket->sin_addr) )
#else
    if( (p_socket->sin_addr.s_addr = inet_addr( p_input->p_source )) == -1 )
#endif
    {
        /* We have a fqdn, try to find its address */
        if ( (p_hostent = gethostbyname(p_input->p_source)) == NULL )
        {
            intf_ErrMsg( "BuildRemoteAddr: unknown host %s", 
                         p_input->p_source );
            return( -1 );
        }
        
        /* Copy the first address of the host in the socket address */
        memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0], 
                 p_hostent->h_length );
    }

    return( 0 );
}

/*****************************************************************************
 * input_NetworkOpen : open a network socket 
 *****************************************************************************/
void input_NetworkOpen( input_thread_t * p_input )
{
 
    int                 i_option_value, i_port;
    struct sockaddr_in  s_socket;
    boolean_t           b_broadcast;
    
    /* FIXME : we don't handle channels for the moment */

    /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET domain, automatic (0)
     * protocol */
    p_input->i_handle = socket( AF_INET, SOCK_DGRAM, 0 );
    if( p_input->i_handle == -1 )
    {
        intf_ErrMsg("NetworkOpen : can't create socket : %s", strerror(errno));
        p_input->b_error = 1;
        return;
    }

    /* We may want to reuse an already used socket */
    i_option_value = 1;
    if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
                    &i_option_value,sizeof( i_option_value ) ) == -1 )
    {
        intf_ErrMsg("NetworkOpen : can't configure socket (SO_REUSEADDR: %s)",
                    strerror(errno));
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

#ifndef SYS_BEOS
    /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
     * packet loss caused by scheduling problems */
    i_option_value = 524288;
    if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF, &i_option_value,
                    sizeof( i_option_value ) ) == -1 )
    {
        intf_ErrMsg("NetworkOpen : can't configure socket (SO_RCVBUF: %s)", 
                    strerror(errno));
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }
#endif /* SYS_BEOS */

    /* Get details about what we are supposed to do */
    b_broadcast = (boolean_t)main_GetIntVariable( INPUT_BROADCAST_VAR, 0 );
    i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT );

    /* TODO : here deal with channel stufs */

    /* Build the local socket */
    if ( input_BuildLocalAddr( &s_socket, i_port, b_broadcast ) 
         == -1 )
    {
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }
    
    /* Bind it */
    if( bind( p_input->i_handle, (struct sockaddr *)&s_socket, 
              sizeof( s_socket ) ) < 0 )
    {
        intf_ErrMsg("NetworkOpen: can't bind socket (%s)", strerror(errno));
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Build socket for remote connection */
    if ( input_BuildRemoteAddr( p_input, &s_socket ) 
         == -1 )
    {
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* And connect it ... should we really connect ? */
    if( connect( p_input->i_handle, (struct sockaddr *) &s_socket,
                 sizeof( s_socket ) ) == (-1) )
    {
        intf_ErrMsg("NetworkOpen: can't connect socket" );
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* We can't pace control, but FIXME : bug in meuuh's code to sync PCR
     * with the server. */
    p_input->stream.b_pace_control = 1;
    
    return;
}

/*****************************************************************************
 * input_NetworkClose : close a network socket
 *****************************************************************************/
void input_NetworkClose( input_thread_t * p_input )
{
    close( p_input->i_handle );
    /* FIXME: deal with channels */
}
720
#endif