]> git.sesse.net Git - vlc/blob - src/input/input_ext-plugins.c
* ./src/input/input_ext-plugins.c: reverted my previous fix which wasn't
[vlc] / src / input / input_ext-plugins.c
1 /*****************************************************************************
2  * input_ext-plugins.c: useful functions for access and demux plug-ins
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: input_ext-plugins.c,v 1.16 2002/07/21 23:40:24 sam Exp $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <fcntl.h>
34
35 #include <vlc/vlc.h>
36
37 #ifdef HAVE_SYS_TIME_H
38 #    include <sys/time.h>
39 #endif
40
41 #ifdef HAVE_UNISTD_H
42 #   include <unistd.h>
43 #elif defined( _MSC_VER ) && defined( _WIN32 )
44 #   include <io.h>
45 #endif
46
47 #ifdef WIN32
48 #   include <winsock2.h>
49 #   include <ws2tcpip.h>
50 #elif !defined( SYS_BEOS ) && !defined( SYS_NTO )
51 #   include <netdb.h>                                         /* hostent ... */
52 #   include <sys/socket.h>
53 #   include <netinet/in.h>
54 #   ifdef HAVE_ARPA_INET_H
55 #       include <arpa/inet.h>                    /* inet_ntoa(), inet_aton() */
56 #   endif
57 #endif
58
59 #ifdef WIN32
60 #   include <winsock2.h>
61 #   include <ws2tcpip.h>
62 #elif !defined( SYS_BEOS ) && !defined( SYS_NTO )
63 #   include <netdb.h>                                         /* hostent ... */
64 #   include <sys/socket.h>
65 #   include <netinet/in.h>
66 #   ifdef HAVE_ARPA_INET_H
67 #       include <arpa/inet.h>                    /* inet_ntoa(), inet_aton() */
68 #   endif
69 #endif
70
71
72
73 #include "stream_control.h"
74 #include "input_ext-intf.h"
75 #include "input_ext-dec.h"
76 #include "input_ext-plugins.h"
77
78
79 /*
80  * Buffers management : internal functions
81  *
82  * All functions are static, but exported versions with mutex protection
83  * start with input_*. Not all of these exported functions are actually used,
84  * but they are included here for completeness.
85  */
86
87 #define BUFFERS_CACHE_SIZE 500
88 #define DATA_CACHE_SIZE 1000
89 #define PES_CACHE_SIZE 1000
90
91 /*****************************************************************************
92  * data_buffer_t: shared data type
93  *****************************************************************************/
94 struct data_buffer_t
95 {
96     data_buffer_t * p_next;
97
98     /* number of data packets this buffer is referenced from - when it falls
99      * down to 0, the buffer is freed */
100     int i_refcount;
101
102     /* size of the current buffer (starting right after this byte) */
103     size_t i_size;
104 };
105
106 /*****************************************************************************
107  * input_buffers_t: defines a LIFO per data type to keep
108  *****************************************************************************/
109 #define PACKETS_LIFO( TYPE, NAME )                                          \
110 struct                                                                      \
111 {                                                                           \
112     TYPE * p_stack;                                                         \
113     unsigned int i_depth;                                                   \
114 } NAME;
115
116 struct input_buffers_t
117 {
118     vlc_mutex_t lock;
119     PACKETS_LIFO( pes_packet_t, pes )
120     PACKETS_LIFO( data_packet_t, data )
121     PACKETS_LIFO( data_buffer_t, buffers )
122     size_t i_allocated;
123 };
124
125
126 /*****************************************************************************
127  * input_BuffersInit: initialize the cache structures, return a pointer to it
128  *****************************************************************************/
129 void * __input_BuffersInit( vlc_object_t *p_this )
130 {
131     input_buffers_t * p_buffers = malloc( sizeof( input_buffers_t ) );
132
133     if( p_buffers == NULL )
134     {
135         return( NULL );
136     }
137
138     memset( p_buffers, 0, sizeof( input_buffers_t ) );
139     vlc_mutex_init( p_this, &p_buffers->lock );
140
141     return( p_buffers );
142 }
143
144 /*****************************************************************************
145  * input_BuffersEnd: free all cached structures
146  *****************************************************************************/
147 #define BUFFERS_END_PACKETS_LOOP                                            \
148     while( p_packet != NULL )                                               \
149     {                                                                       \
150         p_next = p_packet->p_next;                                          \
151         free( p_packet );                                                   \
152         p_packet = p_next;                                                  \
153     }
154
155 void input_BuffersEnd( input_thread_t * p_input, input_buffers_t * p_buffers )
156 {
157     if( p_buffers != NULL )
158     {
159         msg_Dbg( p_input, "pes: %d packets", p_buffers->pes.i_depth );
160         msg_Dbg( p_input, "data: %d packets", p_buffers->data.i_depth );
161         msg_Dbg( p_input, "buffers: %d packets", p_buffers->buffers.i_depth );
162
163         {
164             /* Free PES */
165             pes_packet_t * p_next, * p_packet = p_buffers->pes.p_stack;
166             BUFFERS_END_PACKETS_LOOP;
167         }
168
169         {
170             /* Free data packets */
171             data_packet_t * p_next, * p_packet = p_buffers->data.p_stack;
172             BUFFERS_END_PACKETS_LOOP;
173         }
174
175         {
176             /* Free buffers */
177             data_buffer_t * p_next, * p_buf = p_buffers->buffers.p_stack;
178             while( p_buf != NULL )
179             {
180                 p_next = p_buf->p_next;
181                 p_buffers->i_allocated -= p_buf->i_size;
182                 free( p_buf );
183                 p_buf = p_next;
184             }
185         } 
186
187         if( p_buffers->i_allocated )
188         {
189             msg_Err( p_input, "%d bytes have not been freed, "
190                               "expect memory leak", p_buffers->i_allocated );
191         }
192
193         vlc_mutex_destroy( &p_buffers->lock );
194         free( p_buffers );
195     }
196 }
197
198 /*****************************************************************************
199  * input_NewBuffer: return a pointer to a data buffer of the appropriate size
200  *****************************************************************************/
201 static inline data_buffer_t * NewBuffer( input_buffers_t * p_buffers,
202                                          size_t i_size )
203 {
204     data_buffer_t * p_buf;
205
206     /* Safety check */
207     if( p_buffers->i_allocated > INPUT_MAX_ALLOCATION )
208     {
209 //X        intf_Err( "INPUT_MAX_ALLOCATION reached (%d)",
210 //X                     p_buffers->i_allocated );
211         return NULL;
212     } 
213
214     if( p_buffers->buffers.p_stack != NULL )
215     {
216         /* Take the buffer from the cache */
217         p_buf = p_buffers->buffers.p_stack;
218         p_buffers->buffers.p_stack = p_buf->p_next;
219         p_buffers->buffers.i_depth--;
220
221         /* Reallocate the packet if it is too small or too large */
222         if( p_buf->i_size < i_size || p_buf->i_size > 3 * i_size )
223         {
224             p_buffers->i_allocated -= p_buf->i_size;
225             free( p_buf );
226             p_buf = malloc( sizeof(input_buffers_t) + i_size );
227             if( p_buf == NULL )
228             {
229 //X                intf_ErrMsg( "Out of memory" );
230                 return NULL;
231             }
232             p_buf->i_size = i_size;
233             p_buffers->i_allocated += i_size;
234         }
235     }
236     else
237     {
238         /* Allocate a new buffer */
239         p_buf = malloc( sizeof(input_buffers_t) + i_size );
240         if( p_buf == NULL )
241         {
242 //X            intf_ErrMsg( "Out of memory" );
243             return NULL;
244         }
245         p_buf->i_size = i_size;
246         p_buffers->i_allocated += i_size;
247     }
248
249     /* Initialize data */
250     p_buf->p_next = NULL;
251     p_buf->i_refcount = 0;
252
253     return( p_buf );
254 }
255
256 data_buffer_t * input_NewBuffer( input_buffers_t * p_buffers, size_t i_size )
257 {
258     data_buffer_t * p_buf;
259
260     vlc_mutex_lock( &p_buffers->lock );
261     p_buf = NewBuffer( p_buffers, i_size );
262     vlc_mutex_unlock( &p_buffers->lock );
263
264     return( p_buf );
265 }
266
267 /*****************************************************************************
268  * input_ReleaseBuffer: put a buffer back into the cache
269  *****************************************************************************/
270 static inline void ReleaseBuffer( input_buffers_t * p_buffers,
271                                   data_buffer_t * p_buf )
272 {
273     /* Decrement refcount */
274     if( --p_buf->i_refcount > 0 )
275     {
276         return;
277     }
278
279     if( p_buffers->buffers.i_depth < BUFFERS_CACHE_SIZE )
280     {
281         /* Cache not full : store the buffer in it */
282         p_buf->p_next = p_buffers->buffers.p_stack;
283         p_buffers->buffers.p_stack = p_buf;
284         p_buffers->buffers.i_depth++;
285     }
286     else
287     {
288         p_buffers->i_allocated -= p_buf->i_size;
289         free( p_buf );
290     }
291 }
292
293 void input_ReleaseBuffer( input_buffers_t * p_buffers, data_buffer_t * p_buf )
294 {
295     vlc_mutex_lock( &p_buffers->lock );
296     ReleaseBuffer( p_buffers, p_buf );
297     vlc_mutex_unlock( &p_buffers->lock );
298 }
299
300 /*****************************************************************************
301  * input_ShareBuffer: allocate a data_packet_t pointing to a given buffer
302  *****************************************************************************/
303 static inline data_packet_t * ShareBuffer( input_buffers_t * p_buffers,
304                                            data_buffer_t * p_buf )
305 {
306     data_packet_t * p_data;
307
308     if( p_buffers->data.p_stack != NULL )
309     {
310         /* Take the packet from the cache */
311         p_data = p_buffers->data.p_stack;
312         p_buffers->data.p_stack = p_data->p_next;
313         p_buffers->data.i_depth--;
314     }
315     else
316     {
317         /* Allocate a new packet */
318         p_data = malloc( sizeof(data_packet_t) );
319         if( p_data == NULL )
320         {
321 //X            intf_ErrMsg( "Out of memory" );
322             return NULL;
323         }
324     }
325
326     p_data->p_buffer = p_buf;
327     p_data->p_next = NULL;
328     p_data->b_discard_payload = 0;
329     p_data->p_payload_start = p_data->p_demux_start
330                             = (byte_t *)p_buf + sizeof(input_buffers_t);
331     p_data->p_payload_end = p_data->p_demux_start + p_buf->i_size;
332     p_buf->i_refcount++;
333
334     return( p_data );
335 }
336
337 data_packet_t * input_ShareBuffer( input_buffers_t * p_buffers,
338                                    data_buffer_t * p_buf )
339 {
340     data_packet_t * p_data;
341
342     vlc_mutex_lock( &p_buffers->lock );
343     p_data = ShareBuffer( p_buffers, p_buf );
344     vlc_mutex_unlock( &p_buffers->lock );
345
346     return( p_data );
347 }
348
349 /*****************************************************************************
350  * input_NewPacket: allocate a packet along with a buffer
351  *****************************************************************************/
352 static inline data_packet_t * NewPacket( input_buffers_t * p_buffers,
353                                          size_t i_size )
354 {
355     data_buffer_t * p_buf = NewBuffer( p_buffers, i_size );
356     data_packet_t * p_data;
357
358     if( p_buf == NULL )
359     {
360         return( NULL );
361     }
362
363     p_data = ShareBuffer( p_buffers, p_buf );
364     if( p_data == NULL )
365     {
366         ReleaseBuffer( p_buffers, p_buf );
367     }
368     return( p_data );
369 }
370
371 data_packet_t * input_NewPacket( input_buffers_t * p_buffers, size_t i_size )
372 {
373     data_packet_t * p_data;
374
375     vlc_mutex_lock( &p_buffers->lock );
376     p_data = NewPacket( p_buffers, i_size );
377     vlc_mutex_unlock( &p_buffers->lock );
378
379     return( p_data );
380 }
381
382 /*****************************************************************************
383  * input_DeletePacket: deallocate a packet and its buffers
384  *****************************************************************************/
385 static inline void DeletePacket( input_buffers_t * p_buffers,
386                                  data_packet_t * p_data )
387 {
388     while( p_data != NULL )
389     {
390         data_packet_t * p_next = p_data->p_next;
391
392         ReleaseBuffer( p_buffers, p_data->p_buffer );
393
394         if( p_buffers->data.i_depth < DATA_CACHE_SIZE )
395         {
396             /* Cache not full : store the packet in it */
397             p_data->p_next = p_buffers->data.p_stack;
398             p_buffers->data.p_stack = p_data;
399             p_buffers->data.i_depth++;
400         }
401         else
402         {
403             free( p_data );
404         }
405
406         p_data = p_next;
407     }
408 }
409
410 void input_DeletePacket( input_buffers_t * p_buffers, data_packet_t * p_data )
411 {
412     vlc_mutex_lock( &p_buffers->lock );
413     DeletePacket( p_buffers, p_data );
414     vlc_mutex_unlock( &p_buffers->lock );
415 }
416
417 /*****************************************************************************
418  * input_NewPES: return a pointer to a new PES packet
419  *****************************************************************************/
420 static inline pes_packet_t * NewPES( input_buffers_t * p_buffers )
421 {
422     pes_packet_t * p_pes;
423
424     if( p_buffers->pes.p_stack != NULL )
425     {
426         /* Take the packet from the cache */
427         p_pes = p_buffers->pes.p_stack;
428         p_buffers->pes.p_stack = p_pes->p_next;
429         p_buffers->pes.i_depth--;
430     }
431     else
432     {
433         /* Allocate a new packet */
434         p_pes = malloc( sizeof(pes_packet_t) );
435         if( p_pes == NULL )
436         {
437 //X            intf_ErrMsg( "Out of memory" );
438             return NULL;
439         }
440     }
441
442     p_pes->p_next = NULL;
443     p_pes->b_data_alignment = p_pes->b_discontinuity =
444         p_pes->i_pts = p_pes->i_dts = 0;
445     p_pes->p_first = p_pes->p_last = NULL;
446     p_pes->i_pes_size = 0;
447     p_pes->i_nb_data = 0;
448
449     return( p_pes );
450 }
451
452 pes_packet_t * input_NewPES( input_buffers_t * p_buffers )
453 {
454     pes_packet_t * p_pes;
455
456     vlc_mutex_lock( &p_buffers->lock );
457     p_pes = NewPES( p_buffers );
458     vlc_mutex_unlock( &p_buffers->lock );
459
460     return( p_pes );
461 }
462
463 /*****************************************************************************
464  * input_DeletePES: put a pes and all data packets and all buffers back into
465  *                  the cache
466  *****************************************************************************/
467 static inline void DeletePES( input_buffers_t * p_buffers,
468                               pes_packet_t * p_pes )
469 {
470     while( p_pes != NULL )
471     {
472         pes_packet_t * p_next = p_pes->p_next;
473
474         /* Delete all data packets */
475         if( p_pes->p_first != NULL )
476         {
477             DeletePacket( p_buffers, p_pes->p_first );
478         }
479
480         if( p_buffers->pes.i_depth < PES_CACHE_SIZE )
481         {
482             /* Cache not full : store the packet in it */
483             p_pes->p_next = p_buffers->pes.p_stack;
484             p_buffers->pes.p_stack = p_pes;
485             p_buffers->pes.i_depth++;
486         }
487         else
488         {
489             free( p_pes );
490         }
491
492         p_pes = p_next;
493     }
494 }
495
496 void input_DeletePES( input_buffers_t * p_buffers, pes_packet_t * p_pes )
497 {
498     vlc_mutex_lock( &p_buffers->lock );
499     DeletePES( p_buffers, p_pes );
500     vlc_mutex_unlock( &p_buffers->lock );
501 }
502
503
504 /*
505  * Buffers management : external functions
506  *
507  * These functions make the glu between the access plug-in (pf_read) and
508  * the demux plug-in (pf_demux). We fill in a large buffer (approx. 10s kB)
509  * with a call to pf_read, then allow the demux plug-in to have a peep at
510  * it (input_Peek), and to split it in data_packet_t (input_SplitBuffer).
511  */
512 /*****************************************************************************
513  * input_FillBuffer: fill in p_data_buffer with data from pf_read
514  *****************************************************************************/
515 ssize_t input_FillBuffer( input_thread_t * p_input )
516 {
517     ptrdiff_t i_remains = p_input->p_last_data - p_input->p_current_data;
518     data_buffer_t * p_buf;
519     ssize_t i_ret;
520
521     vlc_mutex_lock( &p_input->p_method_data->lock );
522
523     p_buf = NewBuffer( p_input->p_method_data,
524                        i_remains + p_input->i_bufsize );
525     if( p_buf == NULL )
526     {
527         return( -1 );
528     }
529     p_buf->i_refcount = 1;
530
531     if( p_input->p_data_buffer != NULL )
532     {
533         if( i_remains )
534         {
535             p_input->p_vlc->pf_memcpy( (byte_t *)p_buf + sizeof(data_buffer_t),
536                                        p_input->p_current_data,
537                                        (size_t)i_remains );
538         }
539         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
540     }
541
542     /* Do not hold the lock during pf_read (blocking call). */
543     vlc_mutex_unlock( &p_input->p_method_data->lock );
544
545     i_ret = p_input->pf_read( p_input,
546                               (byte_t *)p_buf + sizeof(data_buffer_t)
547                                + i_remains,
548                               p_input->i_bufsize );
549     if( i_ret < 0 ) i_ret = 0;
550
551     /* We take back the lock before fiddling with buffers */
552     p_input->p_data_buffer = p_buf;
553     p_input->p_current_data = (byte_t *)p_buf + sizeof(data_buffer_t);
554     p_input->p_last_data = p_input->p_current_data + i_remains + i_ret;
555
556     return( (ssize_t)i_remains + i_ret );
557 }
558
559 /*****************************************************************************
560  * input_Peek: give a pointer to the next available bytes in the buffer
561  *             (min. i_size bytes)
562  * Returns the number of bytes read, or -1 in case of error
563  *****************************************************************************/
564 ssize_t input_Peek( input_thread_t * p_input, byte_t ** pp_byte, size_t i_size )
565 {
566     if( p_input->p_last_data - p_input->p_current_data < i_size )
567     {
568         /* Go to the next buffer */
569         ssize_t i_ret = input_FillBuffer( p_input );
570
571         if( i_size == -1 )
572         {
573             return( -1 );
574         }
575         else if( i_ret < i_size )
576         {
577             i_size = i_ret;
578         }
579     }
580     *pp_byte = p_input->p_current_data;
581     return( i_size );
582 }
583
584 /*****************************************************************************
585  * input_SplitBuffer: give a pointer to a data packet containing i_size bytes
586  * Returns the number of bytes read, or -1 in case of error
587  *****************************************************************************/
588 ssize_t input_SplitBuffer( input_thread_t * p_input,
589                            data_packet_t ** pp_data, size_t i_size )
590 {
591     if( p_input->p_last_data - p_input->p_current_data < i_size )
592     {
593         /* Go to the next buffer */
594         ssize_t i_ret = input_FillBuffer( p_input );
595
596         if( i_ret == -1 )
597         {
598             return( -1 );
599         }
600         else if( i_ret < i_size )
601         {
602             i_size = i_ret;
603         }
604     }
605
606     *pp_data = input_ShareBuffer( p_input->p_method_data,
607                                   p_input->p_data_buffer );
608
609     (*pp_data)->p_demux_start = (*pp_data)->p_payload_start
610         = p_input->p_current_data;
611     (*pp_data)->p_payload_end = (*pp_data)->p_demux_start + i_size;
612
613     p_input->p_current_data += i_size;
614
615     return( i_size );
616 }
617
618 /*****************************************************************************
619  * input_AccessInit: initialize access plug-in wrapper structures
620  *****************************************************************************/
621 int input_AccessInit( input_thread_t * p_input )
622 {
623     p_input->p_method_data = input_BuffersInit( p_input );
624     if( p_input->p_method_data == NULL ) return( -1 );
625     p_input->p_data_buffer = NULL;
626     p_input->p_current_data = NULL;
627     p_input->p_last_data = NULL;
628     return( 0 );
629 }
630
631 /*****************************************************************************
632  * input_AccessReinit: reinit structures after a random seek
633  *****************************************************************************/
634 void input_AccessReinit( input_thread_t * p_input )
635 {
636     if( p_input->p_data_buffer != NULL )
637     {
638         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
639     }
640     p_input->p_data_buffer = NULL;
641     p_input->p_current_data = NULL;
642     p_input->p_last_data = NULL;
643 }
644
645 /*****************************************************************************
646  * input_AccessEnd: free access plug-in wrapper structures
647  *****************************************************************************/
648 void input_AccessEnd( input_thread_t * p_input )
649 {
650     if( p_input->p_data_buffer != NULL )
651     {
652         ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
653     }
654
655     input_BuffersEnd( p_input, p_input->p_method_data );
656 }
657
658
659 /*
660  * Optional file descriptor management functions, for use by access plug-ins
661  * base on file descriptors (file, udp, http...).
662  */
663
664 /*****************************************************************************
665  * input_FDClose: close the target
666  *****************************************************************************/
667 void input_FDClose( input_thread_t * p_input )
668 {
669     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
670
671     msg_Info( p_input, "closing `%s/%s://%s'", 
672               p_input->psz_access, p_input->psz_demux, p_input->psz_name );
673  
674     close( p_access_data->i_handle );
675     free( p_access_data );
676 }
677
678 /*****************************************************************************
679  * input_FDNetworkClose: close a network target
680  *****************************************************************************/
681 void input_FDNetworkClose( input_thread_t * p_input )
682 {
683     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
684
685     msg_Info( p_input, "closing network `%s/%s://%s'", 
686               p_input->psz_access, p_input->psz_demux, p_input->psz_name );
687  
688 #ifdef WIN32
689     closesocket( p_access_data->i_handle );
690 #else
691     close( p_access_data->i_handle );
692 #endif
693
694     free( p_access_data );
695 }
696
697 /*****************************************************************************
698  * input_FDRead: standard read on a file descriptor.
699  *****************************************************************************/
700 ssize_t input_FDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
701 {
702     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
703  
704     ssize_t i_ret = read( p_access_data->i_handle, p_buffer, i_len );
705  
706     if( i_ret > 0 )
707     {
708         vlc_mutex_lock( &p_input->stream.stream_lock );
709         p_input->stream.p_selected_area->i_tell += i_ret;
710         vlc_mutex_unlock( &p_input->stream.stream_lock );
711     }
712  
713     if( i_ret < 0 )
714     {
715         msg_Err( p_input, "read failed (%s)", strerror(errno) );
716     }
717  
718     return( i_ret );
719 }
720
721 /*****************************************************************************
722  * NetworkSelect: Checks whether data is available on a file descriptor
723  *****************************************************************************/
724 static inline int NetworkSelect( input_thread_t * p_input )
725 {
726     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
727     struct timeval  timeout;
728     fd_set          fds;
729     int             i_ret;
730
731     /* Initialize file descriptor set */
732     FD_ZERO( &fds );
733     FD_SET( p_access_data->i_handle, &fds );
734
735     /* We'll wait 0.5 second if nothing happens */
736     timeout.tv_sec = 0;
737     timeout.tv_usec = 500000;
738  
739     /* Find if some data is available */
740     i_ret = select( p_access_data->i_handle + 1, &fds,
741                      NULL, NULL, &timeout );
742  
743     if( i_ret == -1 && errno != EINTR )
744     {
745         msg_Err( p_input, "network select error (%s)", strerror(errno) );
746     }
747
748     return( i_ret );
749 }
750
751 /*****************************************************************************
752  * input_FDNetworkRead: read on a file descriptor, checking periodically
753  * p_input->b_die
754  *****************************************************************************/
755 ssize_t input_FDNetworkRead( input_thread_t * p_input, byte_t * p_buffer,
756                              size_t i_len )
757 {
758     if( NetworkSelect( p_input ) > 0 )
759     {
760         input_socket_t * p_access_data
761                              = (input_socket_t *)p_input->p_access_data;
762
763         ssize_t i_ret = recv( p_access_data->i_handle, p_buffer, i_len, 0 );
764
765         if( i_ret > 0 )
766         {
767             vlc_mutex_lock( &p_input->stream.stream_lock );
768             p_input->stream.p_selected_area->i_tell += i_ret;
769             vlc_mutex_unlock( &p_input->stream.stream_lock );
770         }
771
772         if( i_ret < 0 )
773         {
774             msg_Err( p_input, "recv failed (%s)", strerror(errno) );
775         }
776
777         return( i_ret );
778     }
779     
780     return( 0 );
781 }
782
783 /*****************************************************************************
784  * input_FDSeek: seek to a specific location in a file
785  *****************************************************************************/
786 void input_FDSeek( input_thread_t * p_input, off_t i_pos )
787 {
788 #define S p_input->stream
789     input_socket_t * p_access_data = (input_socket_t *)p_input->p_access_data;
790
791     lseek( p_access_data->i_handle, i_pos, SEEK_SET );
792
793     vlc_mutex_lock( &S.stream_lock );
794     S.p_selected_area->i_tell = i_pos;
795     if( S.p_selected_area->i_tell > S.p_selected_area->i_size )
796     {
797         msg_Err( p_input, "seeking too far" );
798         S.p_selected_area->i_tell = S.p_selected_area->i_size;
799     }
800     else if( S.p_selected_area->i_tell < 0 )
801     {
802         msg_Err( p_input, "seeking too early" );
803         S.p_selected_area->i_tell = 0;
804     }
805     vlc_mutex_unlock( &S.stream_lock );
806 #undef S
807 }
808
809