http.c 22.2 KB
Newer Older
1
2
3
4
/*****************************************************************************
 * http.c: HTTP access plug-in
 *****************************************************************************
 * Copyright (C) 2001, 2002 VideoLAN
sigmunau's avatar
sigmunau committed
5
 * $Id: http.c,v 1.27 2003/03/22 23:03:02 sigmunau Exp $
6
7
8
9
10
11
12
 *
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
 *
 * 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.
13
 *
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * 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.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/input.h>

32
33
34
35
36
37
38
#ifdef HAVE_ERRNO_H
#   include <errno.h>
#endif
#ifdef HAVE_FCNTL_H
#   include <fcntl.h>
#endif

39
40
41
42
#ifdef HAVE_SYS_TIME_H
#    include <sys/time.h>
#endif

43
44
45
46
#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif

47
48
49
#if defined( UNDER_CE )
#   include <winsock.h>
#elif defined( WIN32 )
50
51
52
53
54
55
56
57
58
#   include <winsock2.h>
#   include <ws2tcpip.h>
#   ifndef IN_MULTICAST
#       define IN_MULTICAST(a) IN_CLASSD(a)
#   endif
#else
#   include <sys/socket.h>
#endif

59
#include "vlc_playlist.h"
60
61
62
63
64
65
66
67
#include "network.h"

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int  Open       ( vlc_object_t * );
static void Close      ( vlc_object_t * );

68
static int  SetProgram ( input_thread_t *, pgrm_descriptor_t * );
69
static void Seek       ( input_thread_t *, off_t );
70
static ssize_t Read    ( input_thread_t *, byte_t *, size_t );
71
72
73
74

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
75
#define PROXY_TEXT N_("specify an HTTP proxy")
gbazin's avatar
   
gbazin committed
76
#define PROXY_LONGTEXT N_( \
77
    "Specify an HTTP proxy to use. It must be in the form " \
78
    "http://myproxy.mydomain:myport. If none is specified, the HTTP_PROXY " \
79
80
    "environment variable will be tried." )

gbazin's avatar
   
gbazin committed
81
82
83
84
85
#define CACHING_TEXT N_("caching value in ms")
#define CACHING_LONGTEXT N_( \
    "Allows you to modify the default caching value for http streams. This " \
    "value should be set in miliseconds units." )

86
vlc_module_begin();
87
88
89
    add_category_hint( N_("http"), NULL, VLC_FALSE );
    add_string( "http-proxy", NULL, NULL, PROXY_TEXT, PROXY_LONGTEXT, VLC_FALSE );
    add_integer( "http-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
90
91
    set_description( _("HTTP access module") );
    set_capability( "access", 0 );
92
    add_shortcut( "http" );
93
94
95
96
97
98
99
100
101
    add_shortcut( "http4" );
    add_shortcut( "http6" );
    set_callbacks( Open, Close );
vlc_module_end();

/*****************************************************************************
 * _input_socket_t: private access plug-in data, modified to add private
 *                  fields
 *****************************************************************************/
102
103
104
#define MAX_ANSWER_SIZE 1024
#define MAX_QUERY_SIZE 1024

105
106
107
108
109
110
typedef struct _input_socket_s
{
    input_socket_t      _socket;

    char *              psz_network;
    network_socket_t    socket_desc;
111
    char                psz_buffer[MAX_QUERY_SIZE];
112
113
114
115
116
117
118
119
    char *              psz_name;
} _input_socket_t;

/*****************************************************************************
 * HTTPConnect: connect to the server and seek to i_tell
 *****************************************************************************/
static int HTTPConnect( input_thread_t * p_input, off_t i_tell )
{
120
121
122
123
124
125
126
127
    char psz_buffer[MAX_QUERY_SIZE];
    _input_socket_t * p_access_data;
    module_t * p_network;
    char * psz_parser, * psz_value, * psz_answer;
    int i_code, i_ret, i, i_size;

    enum { HTTP_PROTOCOL, ICY_PROTOCOL } i_protocol;

128
    /* Find an appropriate network module */
129
    p_access_data = (_input_socket_t *)p_input->p_access_data;
130
131
132
133
    p_input->p_private = (void*) &p_access_data->socket_desc;
    p_network = module_Need( p_input, "network", p_access_data->psz_network );
    if( p_network == NULL )
    {
134
        return VLC_ENOMOD;
135
136
137
138
139
140
141
    }
    module_Unneed( p_input, p_network );

    p_access_data->_socket.i_handle = p_access_data->socket_desc.i_handle;

#   define HTTP_USERAGENT "User-Agent: " COPYRIGHT_MESSAGE "\r\n"
#   define HTTP_END       "\r\n"
142
143

    /* Build the query string */
144
145
    if ( p_input->stream.b_seekable )
    {
146
         snprintf( psz_buffer, MAX_QUERY_SIZE,
147
                   "%s"
gbazin's avatar
   
gbazin committed
148
                   "Range: bytes="I64Fd"-\r\n"
149
                   HTTP_USERAGENT HTTP_END,
150
                   p_access_data->psz_buffer, i_tell );
151
152
153
    }
    else
    {
154
         snprintf( psz_buffer, MAX_QUERY_SIZE,
155
156
157
158
                   "%s"
                   HTTP_USERAGENT HTTP_END,
                   p_access_data->psz_buffer );
    }
159
160
161
162
163
164
    psz_buffer[MAX_QUERY_SIZE - 1] = '\0';

    /* Send GET query */
    i_ret = send( p_access_data->_socket.i_handle,
                  psz_buffer, strlen( psz_buffer ), 0 );
    if( i_ret == -1 )
165
    {
166
#ifdef HAVE_ERRNO_H
167
        msg_Err( p_input, "cannot send request (%s)", strerror(errno) );
168
169
170
#else
        msg_Err( p_input, "cannot send request" );
#endif
171
172
        Close( VLC_OBJECT(p_input) );
        return VLC_EGENERIC;
173
174
    }

175
    /* Prepare the input thread for reading. */
176
177
178
179
    p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;

    /* FIXME: we shouldn't have to do that ! It's UGLY but mandatory because
     * input_FillBuffer assumes p_input->pf_read exists */
180
    p_input->pf_read = Read;
181
182
183
184
185

    while( !input_FillBuffer( p_input ) )
    {
        if( p_input->b_die || p_input->b_error )
        {
186
187
            Close( VLC_OBJECT(p_input) );
            return VLC_EGENERIC;
188
189
190
        }
    }

191
192
    /* Get the HTTP returncode */
    i_size = input_Peek( p_input, (byte_t**)&psz_parser, MAX_ANSWER_SIZE );
193

194
    if( i_size <= 0 )
195
196
    {
        msg_Err( p_input, "not enough data" );
197
198
        Close( VLC_OBJECT(p_input) );
        return VLC_EGENERIC;
199
    }
200
201
202

    /* Guess the protocol */
    if( ( ( (size_t)i_size >= strlen("HTTP/1.x") ) &&
203
            !strncmp( psz_parser, "HTTP/1.", strlen("HTTP/1.") ) ) )
204
    {
205
206
207
208
        i_protocol = HTTP_PROTOCOL;

        psz_parser += strlen("HTTP/1.x");
        i_size -= strlen("HTTP/1.x");
209
    }
210
211
    else if( ( (size_t)i_size >= strlen("ICY") &&
             !strncmp( psz_parser, "ICY", strlen("ICY") ) ) )
212
    {
213
        i_protocol = ICY_PROTOCOL;
214
        if( !p_input->psz_demux || !*p_input->psz_demux  )
gbazin's avatar
   
gbazin committed
215
        {
216
            msg_Info( p_input, "ICY server found, mp3 demuxer selected" );
217
            p_input->psz_demux = "mp3";    // FIXME strdup ?
gbazin's avatar
   
gbazin committed
218
        }
219
220
221

        psz_parser += strlen("ICY");
        i_size -= strlen("ICY");
222
223
224
    }
    else
    {
225
        msg_Err( p_input, "invalid HTTP reply '%s'", psz_parser );
226
        return VLC_EGENERIC;
227
    }
228

229
230
231
232
    /* Check the HTTP return code */
    i_code = atoi( (char*)psz_parser );
    msg_Dbg( p_input, "%s server replied: %i",
             i_protocol == HTTP_PROTOCOL ? "HTTP" : "ICY", i_code );
233
234
    psz_parser += 4;
    i_size -= 4;
235
236

    /* Find the end of the line */
237
238
239
240
241
    for ( i = 0; (i < i_size -1) && ((psz_parser[i] != '\r') ||
      (psz_parser[i+1] != '\n')); i++ )
    {
        ;
    }
242
243
244

    /* Check we actually parsed something */
    if ( i+1 == i_size && psz_parser[i+1] != '\n' )
245
246
    {
        msg_Err( p_input, "stream not compliant with HTTP/1.x" );
247
        return VLC_EGENERIC;
248
249
    }

250
251
252
253
254
255
    /* Store the line we just parsed and skip it */
    psz_answer = strndup( psz_parser, i );
    if( !psz_answer )
    {
        return VLC_ENOMEM;
    }
gbazin's avatar
   
gbazin committed
256

257
258
259
    p_input->p_current_data = psz_parser + i + 2;

    /* Parse remaining headers */
260
    for ( ; ; )
261
    {
262
263
264
265
266
        char psz_line[MAX_ANSWER_SIZE];

        i_size = input_Peek( p_input, (byte_t**)&psz_parser, MAX_ANSWER_SIZE );

        if( i_size <= 0 )
267
268
        {
            msg_Err( p_input, "not enough data" );
269
            Close( VLC_OBJECT(p_input) );
270
            free( psz_answer );
271
            return VLC_EGENERIC;
272
        }
273
274
275
276
277

        /* Copy one line to psz_line */
        i = 0;
        while( i_size && psz_parser[i] != '\r'
                      && psz_parser[i + 1] != '\n' )
278
        {
279
280
            psz_line[i] = psz_parser[i];
            i++;
281
            i_size--;
282
        }
283
284
        p_input->p_current_data = psz_parser + i + 2;
        if( !i )
285
        {
286
            break; /* End of headers */
287
        }
288
        psz_line[i] = '\0';
289
290
291
292
        psz_parser = strchr( psz_line, ':' );
        if ( !psz_parser )
        {
            msg_Err( p_input, "malformed header line: %s", psz_line );
293
            free( psz_answer );
294
295
            return VLC_EGENERIC;
        }
296
        psz_parser[0] = '\0';
297
298
299
300
301
        psz_parser++;
        while ( *psz_parser == ' ' || *psz_parser == '\t' )
        {
            psz_parser++;
        }
302
303
304
        psz_value = psz_parser;

        if( !strcasecmp( psz_line, "Content-Length" ) )
305
        {
306
            off_t i_size = 0;
307
#ifdef HAVE_ATOLL
308
            i_size = i_tell + atoll( psz_value );
309
#else
310
311
312
313
314
315
316
            psz_parser = psz_value;
            while( psz_parser[0] >= '0' && psz_parser[0] <= '9' )
            {
                i_size *= 10;
                i_size += psz_parser[0] - '0';
            }
            i_size += i_tell;
317
#endif
318
319
320
321
            msg_Dbg( p_input, "stream size is "I64Fd, i_size );

            vlc_mutex_lock( &p_input->stream.stream_lock );
            p_input->stream.p_selected_area->i_size = i_size;
322
323
            vlc_mutex_unlock( &p_input->stream.stream_lock );
        }
324
325
326
327
        /* Redirection support */
        else if( ( i_code == 301 || i_code == 302 ||
                   i_code == 303 || i_code == 307 )
                    && !strcasecmp( psz_line, "location" ) )
328
        {
329
330
            playlist_t * p_playlist = (playlist_t *) vlc_object_find(
                                  p_input, VLC_OBJECT_PLAYLIST, FIND_PARENT );
331
332
333
            if( !p_playlist )
            {
                msg_Err( p_input, "redirection failed: can't find playlist" );
334
                free( psz_answer );
335
336
                return VLC_EGENERIC;
            }
337
338
339
340
341
            msg_Dbg( p_input, "%i %s: redirected to %s",
                              i_code, psz_answer, psz_value );
            p_playlist->pp_items[p_playlist->i_index]->b_autodeletion
                                                                  = VLC_TRUE;
            playlist_Add( p_playlist, psz_value,
342
343
                          PLAYLIST_INSERT | PLAYLIST_GO,
                          p_playlist->i_index + 1 );
344
345
            vlc_object_release( p_playlist );
        }
346
347

        /* TODO: parse other headers here */
348
    }
349
350
351

    /* Something went wrong */
    if ( i_code >= 400 )
352
    {
353
354
355
        msg_Err( p_input, "%i %s", i_code, psz_answer );
        p_input->p_current_data = psz_parser + i_size;
        free( psz_answer );
356
357
358
        return VLC_EGENERIC;
    }

359
    free( psz_answer );
360

361
    /* Set final stream properties */
362
    vlc_mutex_lock( &p_input->stream.stream_lock );
363
    if( i_protocol == ICY_PROTOCOL )
364
    {
365
        p_input->stream.b_seekable = VLC_FALSE;
366
367
368
    }
    else
    {
369
        p_input->stream.b_seekable = VLC_TRUE;
370
    }
371
372
373

    if( p_input->stream.p_selected_area->i_size )
    {
374
        p_input->stream.p_selected_area->i_tell = i_tell;
375
    }
376
377
    else
    {
378
        p_input->stream.b_seekable = VLC_FALSE;
379
    }
380
    p_input->stream.b_changed = VLC_TRUE;
381
    vlc_mutex_unlock( &p_input->stream.stream_lock );
382

383
    return VLC_SUCCESS;
384
385
386
387
388
389
390
391
392
393
394
395
396
397
}

/*****************************************************************************
 * Open: parse URL and open the remote file at the beginning
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
    input_thread_t *    p_input = (input_thread_t *)p_this;
    _input_socket_t *   p_access_data;
    char *              psz_name = strdup(p_input->psz_name);
    char *              psz_parser = psz_name;
    char *              psz_server_addr = "";
    char *              psz_server_port = "";
    char *              psz_path = "";
gbazin's avatar
   
gbazin committed
398
    char *              psz_proxy, *psz_proxy_orig;
399
400
    int                 i_server_port = 0;

401
402
    p_access_data = malloc( sizeof(_input_socket_t) );
    p_input->p_access_data = (access_sys_t *)p_access_data;
403
404
405
406
    if( p_access_data == NULL )
    {
        msg_Err( p_input, "out of memory" );
        free(psz_name);
407
        return VLC_ENOMEM;
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
    }

    p_access_data->psz_name = psz_name;
    p_access_data->psz_network = "";
    if( config_GetInt( p_input, "ipv4" ) )
    {
        p_access_data->psz_network = "ipv4";
    }
    if( config_GetInt( p_input, "ipv6" ) )
    {
        p_access_data->psz_network = "ipv6";
    }
    if( *p_input->psz_access )
    {
        /* Find out which shortcut was used */
        if( !strncmp( p_input->psz_access, "http6", 6 ) )
        {
            p_access_data->psz_network = "ipv6";
        }
        else if( !strncmp( p_input->psz_access, "http4", 6 ) )
        {
            p_access_data->psz_network = "ipv4";
        }
    }

    /* Parse psz_name syntax :
     * //<hostname>[:<port>][/<path>] */
    while( *psz_parser == '/' )
    {
        psz_parser++;
    }
    psz_server_addr = psz_parser;

    while( *psz_parser && *psz_parser != ':' && *psz_parser != '/' )
    {
443
444
445
446
447
448
449
450
        if( *psz_parser == '[' )
        {
            /* IPv6 address */
            while( *psz_parser && *psz_parser != ']' )
            {
                psz_parser++;
            }
        }
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
        psz_parser++;
    }

    if ( *psz_parser == ':' )
    {
        *psz_parser = '\0';
        psz_parser++;
        psz_server_port = psz_parser;

        while( *psz_parser && *psz_parser != '/' )
        {
            psz_parser++;
        }
    }

    if( *psz_parser == '/' )
    {
        *psz_parser = '\0';
        psz_parser++;
        psz_path = psz_parser;
    }

    /* Convert port format */
    if( *psz_server_port )
    {
        i_server_port = strtol( psz_server_port, &psz_parser, 10 );
        if( *psz_parser )
        {
            msg_Err( p_input, "cannot parse server port near %s", psz_parser );
            free( p_input->p_access_data );
            free( psz_name );
482
            return VLC_EGENERIC;
483
484
485
486
487
488
489
490
491
492
493
494
495
        }
    }

    if( i_server_port == 0 )
    {
        i_server_port = 80;
    }

    if( !*psz_server_addr )
    {
        msg_Err( p_input, "no server given" );
        free( p_input->p_access_data );
        free( psz_name );
496
        return VLC_EGENERIC;
497
498
    }

gbazin's avatar
   
gbazin committed
499
    /* Check proxy config variable */
500
501
502
    psz_proxy_orig = config_GetPsz( p_input, "http-proxy" );
    if( psz_proxy_orig == NULL )
    {
gbazin's avatar
   
gbazin committed
503
        /* Check proxy environment variable */
504
505
506
        psz_proxy_orig = getenv( "http_proxy" );
        if( psz_proxy_orig != NULL )
        {
gbazin's avatar
   
gbazin committed
507
            psz_proxy_orig = strdup( psz_proxy_orig );
508
509
        }
    }
gbazin's avatar
   
gbazin committed
510
511
512

    psz_proxy = psz_proxy_orig;
    if( psz_proxy != NULL && *psz_proxy )
513
514
    {
        /* http://myproxy.mydomain:myport/ */
gbazin's avatar
   
gbazin committed
515
        int i_proxy_port = 0;
516

517
518
519
520
521
        /* Skip the protocol name */
        while( *psz_proxy && *psz_proxy != ':' )
        {
            psz_proxy++;
        }
522

523
524
525
526
527
        /* Skip the "://" part */
        while( *psz_proxy && (*psz_proxy == ':' || *psz_proxy == '/') )
        {
            psz_proxy++;
        }
528

529
530
531
532
        /* Found a proxy name */
        if( *psz_proxy )
        {
            char *psz_port = psz_proxy;
533

534
535
536
537
538
            /* Skip the hostname part */
            while( *psz_port && *psz_port != ':' && *psz_port != '/' )
            {
                psz_port++;
            }
539

540
541
542
543
            /* Found a port name */
            if( *psz_port )
            {
                char * psz_junk;
544

545
546
547
                /* Replace ':' with '\0' */
                *psz_port = '\0';
                psz_port++;
548

549
550
551
552
553
                psz_junk = psz_port;
                while( *psz_junk && *psz_junk != '/' )
                {
                    psz_junk++;
                }
554

555
556
557
558
                if( *psz_junk )
                {
                    *psz_junk = '\0';
                }
559

560
561
562
563
564
                if( *psz_port != '\0' )
                {
                    i_proxy_port = atoi( psz_port );
                }
            }
gbazin's avatar
   
gbazin committed
565
566
567

            psz_proxy = strdup( psz_proxy );

568
            msg_Dbg( p_input, "using HTTP proxy server=%s port=%d",
gbazin's avatar
   
gbazin committed
569
                     psz_proxy, i_proxy_port );
570
571
572
        }
        else
        {
573
            msg_Err( p_input, "HTTP proxy %s is invalid!", psz_proxy_orig );
574
575
            free( p_input->p_access_data );
            free( psz_name );
gbazin's avatar
   
gbazin committed
576
            if( psz_proxy_orig ) free( psz_proxy_orig );
577
            return VLC_EGENERIC;
578
579
        }

gbazin's avatar
   
gbazin committed
580
581
        if( psz_proxy_orig ) free( psz_proxy_orig );

582
583
        p_access_data->socket_desc.psz_server_addr = psz_proxy;
        p_access_data->socket_desc.i_server_port = i_proxy_port;
gbazin's avatar
   
gbazin committed
584
        p_access_data->socket_desc.i_type = NETWORK_TCP;
585

586
        snprintf( p_access_data->psz_buffer, MAX_QUERY_SIZE,
587
                  "GET http://%s:%d/%s HTTP/1.0\r\n",
588
589
590
591
592
593
594
595
596
                  psz_server_addr, i_server_port, psz_path );
    }
    else
    {
        /* No proxy, direct connection. */
        p_access_data->socket_desc.i_type = NETWORK_TCP;
        p_access_data->socket_desc.psz_server_addr = psz_server_addr;
        p_access_data->socket_desc.i_server_port = i_server_port;

597
        snprintf( p_access_data->psz_buffer, MAX_QUERY_SIZE,
598
599
600
                  "GET /%s HTTP/1.1\r\nHost: %s\r\n",
                  psz_path, psz_server_addr );
    }
601
    p_access_data->psz_buffer[MAX_QUERY_SIZE - 1] = '\0';
602
603
604
605

    msg_Dbg( p_input, "opening server=%s port=%d path=%s",
                      psz_server_addr, i_server_port, psz_path );

606
    p_input->pf_read = Read;
607
608
609
610
611
    p_input->pf_set_program = SetProgram;
    p_input->pf_set_area = NULL;
    p_input->pf_seek = Seek;

    vlc_mutex_lock( &p_input->stream.stream_lock );
612
613
    p_input->stream.b_pace_control = VLC_TRUE;
    p_input->stream.b_seekable = VLC_TRUE;
614
    p_input->stream.b_connected = VLC_TRUE;
615
616
617
618
619
    p_input->stream.p_selected_area->i_tell = 0;
    p_input->stream.p_selected_area->i_size = 0;
    p_input->stream.i_method = INPUT_METHOD_NETWORK;
    vlc_mutex_unlock( &p_input->stream.stream_lock );
    p_input->i_mtu = 0;
620

621
622
    if( HTTPConnect( p_input, 0 ) )
    {
623
624
625
626
627
628
629
630
        /* Request failed, try again with HTTP/1.0 */
        char * psz_pos = strstr( p_access_data->psz_buffer, "HTTP/1.1" );

        if( !psz_pos )
        {
            return VLC_EGENERIC;
        }

631
        p_input->stream.b_seekable = VLC_FALSE;
632
633
634
635
636
        psz_pos[7] = '0';
        if( HTTPConnect( p_input, 0 ) )
        {
            free( p_input->p_access_data );
            free( psz_name );
637
            return VLC_EGENERIC;
638
639
        }
    }
640

gbazin's avatar
   
gbazin committed
641
642
643
    /* Update default_pts to a suitable value for http access */
    p_input->i_pts_delay = config_GetInt( p_input, "http-caching" ) * 1000;

644
    return VLC_SUCCESS;
645
646
647
648
649
650
651
652
}

/*****************************************************************************
 * Close: free unused data structures
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
    input_thread_t *  p_input = (input_thread_t *)p_this;
653
    int i_handle = ((network_socket_t *)p_input->p_access_data)->i_handle;
654
    _input_socket_t * p_access_data =
655
656
657
        (_input_socket_t *)p_input->p_access_data;

    free( p_access_data->psz_name );
658
659
660

    msg_Info( p_input, "closing HTTP target `%s'", p_input->psz_source );

661
#if defined( WIN32 ) || defined( UNDER_CE )
662
663
664
665
666
667
    closesocket( i_handle );
#else
    close( i_handle );
#endif

    free( p_access_data );
668
669
670
671
672
673
674
675
}

/*****************************************************************************
 * SetProgram: do nothing
 *****************************************************************************/
static int SetProgram( input_thread_t * p_input,
                       pgrm_descriptor_t * p_program )
{
676
    return VLC_SUCCESS;
677
678
679
680
681
682
683
}

/*****************************************************************************
 * Seek: close and re-open a connection at the right place
 *****************************************************************************/
static void Seek( input_thread_t * p_input, off_t i_pos )
{
684
    _input_socket_t *p_access_data = (_input_socket_t*)p_input->p_access_data;
685
#if defined( WIN32 ) || defined( UNDER_CE )
686
687
    closesocket( p_access_data->_socket.i_handle );
#else
688
    close( p_access_data->_socket.i_handle );
689
#endif
gbazin's avatar
   
gbazin committed
690
    msg_Dbg( p_input, "seeking to position "I64Fd, i_pos );
691
692
693
    HTTPConnect( p_input, i_pos );
}

694
/*****************************************************************************
sigmunau's avatar
sigmunau committed
695
696
 * Read: Read up to i_len bytes from the http connection and place in
 * p_buffer. Return the actual number of bytes read
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
 *****************************************************************************/
static ssize_t Read( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
{
    input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
    struct timeval  timeout;
    fd_set          fds;
    int             i_ret;

    /* Initialize file descriptor set */
    FD_ZERO( &fds );
    FD_SET( p_access_data->i_handle, &fds );

    /* We'll wait 0.5 second if nothing happens */
    timeout.tv_sec = 0;
    timeout.tv_usec = 500000;

    /* Find if some data is available */
    i_ret = select( p_access_data->i_handle + 1, &fds,
                    NULL, NULL, &timeout );

717
#ifdef HAVE_ERRNO_H
718
719
720
721
    if( i_ret == -1 && errno != EINTR )
    {
        msg_Err( p_input, "network select error (%s)", strerror(errno) );
    }
722
723
724
725
726
727
#else
    if( i_ret == -1 )
    {
        msg_Err( p_input, "network select error" );
    }
#endif
728
729
730
731
732
733
    else if( i_ret > 0 )
    {
        ssize_t i_recv = recv( p_access_data->i_handle, p_buffer, i_len, 0 );

        if( i_recv < 0 )
        {
734
#ifdef HAVE_ERRNO_H
735
            msg_Err( p_input, "recv failed (%s)", strerror(errno) );
736
737
738
#else
            msg_Err( p_input, "recv failed" );
#endif
739
        }
740

741
742
743
744
745
        return i_recv;
    }

    return 0;
}