]> git.sesse.net Git - vlc/blob - modules/access/mms/mmsh.c
* all: moved Get(D/Q)WLE and Get(D/Q)WBE to include/vlc_common.h.
[vlc] / modules / access / mms / mmsh.c
1 /*****************************************************************************
2  * mmsh.c:
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: mmsh.c,v 1.5 2003/08/17 23:02:51 fenrir Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@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  * TODO:
26  *  * http_proxy
27  *
28  */
29
30 /*****************************************************************************
31  * Preamble
32  *****************************************************************************/
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <vlc/vlc.h>
37 #include <vlc/input.h>
38
39 #ifdef HAVE_ERRNO_H
40 #   include <errno.h>
41 #endif
42 #ifdef HAVE_FCNTL_H
43 #   include <fcntl.h>
44 #endif
45 #ifdef HAVE_SYS_TIME_H
46 #    include <sys/time.h>
47 #endif
48
49 #ifdef HAVE_UNISTD_H
50 #   include <unistd.h>
51 #endif
52
53 #if defined( UNDER_CE )
54 #   include <winsock.h>
55 #elif defined( WIN32 )
56 #   include <winsock2.h>
57 #   include <ws2tcpip.h>
58 #   ifndef IN_MULTICAST
59 #       define IN_MULTICAST(a) IN_CLASSD(a)
60 #   endif
61 #else
62 #   include <sys/socket.h>
63 #endif
64
65 #include "network.h"
66 #include "asf.h"
67 #include "buffer.h"
68
69 #include "mms.h"
70 #include "mmsh.h"
71
72 /*****************************************************************************
73  * Local prototypes
74  *****************************************************************************/
75 int  E_( MMSHOpen )  ( input_thread_t * );
76 void E_( MMSHClose ) ( input_thread_t * );
77
78 static ssize_t Read        ( input_thread_t * p_input, byte_t * p_buffer,
79                              size_t i_len );
80 static void    Seek        ( input_thread_t *, off_t );
81
82 /****************************************************************************
83  ****************************************************************************
84  *******************                                      *******************
85  *******************       Main functions                 *******************
86  *******************                                      *******************
87  ****************************************************************************
88  ****************************************************************************/
89
90 /****************************************************************************
91  * Open: connect to ftp server and ask for file
92  ****************************************************************************/
93 int  E_( MMSHOpen )  ( input_thread_t *p_input )
94 {
95     access_sys_t    *p_sys;
96
97     uint8_t         *p;
98     http_answer_t   *p_ans;
99     http_field_t    *p_field;
100     chunk_t         ck;
101
102     /* init p_sys */
103     p_sys = malloc( sizeof( access_sys_t ) );
104     p_sys->i_proto = MMS_PROTO_HTTP;
105
106     p_sys->p_socket = NULL;
107     p_sys->i_request_context = 1;
108     p_sys->i_buffer = 0;
109     p_sys->i_buffer_pos = 0;
110     p_sys->b_broadcast = VLC_TRUE;
111     p_sys->p_packet = NULL;
112     p_sys->i_packet_sequence = 0;
113     p_sys->i_packet_used = 0;
114     p_sys->i_packet_length = 0;
115     p_sys->i_pos = 0;
116     E_( GenerateGuid )( &p_sys->guid );
117
118     /* open a tcp connection */
119     p_sys->p_url = E_( url_new )( p_input->psz_name );
120
121     if( *p_sys->p_url->psz_host == '\0' )
122     {
123         msg_Err( p_input, "invalid server addresse" );
124         goto exit_error;
125     }
126     if( p_sys->p_url->i_port <= 0 )
127     {
128         p_sys->p_url->i_port = 80;
129     }
130
131     p_sys->p_socket = NetOpenTCP( p_input, p_sys->p_url );
132     if( !p_sys->p_socket )
133     {
134         msg_Err( p_input, "cannot connect" );
135         goto exit_error;
136     }
137     p_sys->i_request_context = 1;
138
139     /* *** send first request *** */
140     p = &p_sys->buffer[0];
141     p += sprintf( p, "GET %s HTTP/1.0\r\n", p_sys->p_url->psz_path );
142     p += sprintf( p,"Accept: */*\r\n" );
143     p += sprintf( p, "User-Agent: NSPlayer/4.1.0.3856\r\n" );
144     p += sprintf( p, "Host: %s:%d\r\n", p_sys->p_url->psz_host, p_sys->p_url->i_port );
145     p += sprintf( p, "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=0:0,request-context=%d,max-duration=0\r\n", p_sys->i_request_context++ );
146     //p += sprintf( p, "Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}\r\n" );
147     p += sprintf( p, "Pragma: xClientGUID={"GUID_FMT"}\r\n", GUID_PRINT( p_sys->guid ) );
148     p += sprintf( p, "Connection: Close\r\n\r\n" );
149     NetWrite( p_input, p_sys->p_socket, p_sys->buffer,  p - p_sys->buffer );
150
151
152     if( NetFill ( p_input, p_sys, BUFFER_SIZE ) <= 0 )
153     {
154         msg_Err( p_input, "cannot read answer" );
155         goto exit_error;
156     }
157     NetClose( p_input, p_sys->p_socket );
158
159     p_ans = http_answer_parse( p_sys->buffer, p_sys->i_buffer );
160     if( !p_ans )
161     {
162         msg_Err( p_input, "cannot parse answer" );
163         goto exit_error;
164     }
165
166     if( p_ans->i_error >= 400 )
167     {
168         msg_Err( p_input, "error %d (server return=`%s')", p_ans->i_error, p_ans->psz_answer );
169         http_answer_free( p_ans );
170         goto exit_error;
171     }
172     else if( p_ans->i_error >= 300 )
173     {
174         msg_Err( p_input, "FIXME redirec unsuported %d (server return=`%s')", p_ans->i_error, p_ans->psz_answer );
175         http_answer_free( p_ans );
176         goto exit_error;
177     }
178     else if( p_ans->i_body <= 0 )
179     {
180         msg_Err( p_input, "empty answer" );
181         http_answer_free( p_ans );
182         goto exit_error;
183     }
184
185     /* now get features */
186     /* FIXME FIXME test Content-Type to see if it's a plain stream or an asx FIXME */
187     for( p_field = p_ans->p_fields; p_field != NULL; p_field = http_field_find( p_field->p_next, "Pragma" ) )
188     {
189         if( !strncasecmp( p_field->psz_value, "features", 8 ) )
190         {
191             if( strstr( p_field->psz_value, "broadcast" ) )
192             {
193                 msg_Dbg( p_input, "stream type = broadcast" );
194                 p_sys->b_broadcast = VLC_TRUE;
195             }
196             else if( strstr( p_field->psz_value, "seekable" ) )
197             {
198                 msg_Dbg( p_input, "stream type = seekable" );
199                 p_sys->b_broadcast = VLC_FALSE;
200             }
201             else
202             {
203                 msg_Warn( p_input, "unknow stream types (%s)", p_field->psz_value );
204                 p_sys->b_broadcast = VLC_FALSE;
205             }
206         }
207     }
208
209     /* gather header */
210     p_sys->i_header = 0;
211     p_sys->p_header = malloc( p_ans->i_body );
212     do
213     {
214         if( chunk_parse( &ck, p_ans->p_body, p_ans->i_body ) )
215         {
216             msg_Err( p_input, "invalid chunk answer" );
217             goto exit_error;
218         }
219         if( ck.i_type != 0x4824 )
220         {
221             msg_Err( p_input, "invalid chunk (0x%x)", ck.i_type );
222             break;
223         }
224         if( ck.i_data > 0 )
225         {
226             memcpy( &p_sys->p_header[p_sys->i_header],
227                     ck.p_data,
228                     ck.i_data );
229
230             p_sys->i_header += ck.i_data;
231         }
232
233         /* BEURK */
234         p_ans->p_body   += 12 + ck.i_data;
235         p_ans->i_body   -= 12 + ck.i_data;
236
237     } while( p_ans->i_body > 12 );
238
239     http_answer_free( p_ans );
240
241     msg_Dbg( p_input, "complete header size=%d", p_sys->i_header );
242     if( p_sys->i_header <= 0 )
243     {
244         msg_Err( p_input, "header size == 0" );
245         goto exit_error;
246     }
247     /* *** parse header and get stream and their id *** */
248     /* get all streams properties,
249      *
250      * TODO : stream bitrates properties(optional)
251      *        and bitrate mutual exclusion(optional) */
252     E_( asf_HeaderParse )( &p_sys->asfh,
253                            p_sys->p_header, p_sys->i_header );
254     msg_Dbg( p_input, "packet count=%lld packet size=%d",p_sys->asfh.i_data_packets_count, p_sys->asfh.i_min_data_packet_size );
255
256     E_( asf_StreamSelect)( &p_sys->asfh,
257                            config_GetInt( p_input, "mms-maxbitrate" ),
258                            config_GetInt( p_input, "mms-all" ),
259                            config_GetInt( p_input, "audio" ),
260                            config_GetInt( p_input, "video" ) );
261
262     if( mmsh_start( p_input, p_sys, 0 ) )
263     {
264         msg_Err( p_input, "cannot start stream" );
265         goto exit_error;
266     }
267
268     /* *** set exported functions *** */
269     p_input->pf_read = Read;
270     p_input->pf_seek = Seek;
271     p_input->pf_set_program = input_SetProgram;
272     p_input->pf_set_area = NULL;
273
274     p_input->p_private = NULL;
275     p_input->i_mtu = 3 * p_sys->asfh.i_min_data_packet_size;
276
277     /* *** finished to set some variable *** */
278     vlc_mutex_lock( &p_input->stream.stream_lock );
279     p_input->stream.b_pace_control = 0;
280     if( p_sys->b_broadcast )
281     {
282         p_input->stream.p_selected_area->i_size = 0;
283         p_input->stream.b_seekable = 0;
284     }
285     else
286     {
287         p_input->stream.p_selected_area->i_size = p_sys->asfh.i_file_size;
288         p_input->stream.b_seekable = 1;
289     }
290     p_input->stream.p_selected_area->i_tell = 0;
291     p_input->stream.i_method = INPUT_METHOD_NETWORK;
292     vlc_mutex_unlock( &p_input->stream.stream_lock );
293
294     /* Update default_pts to a suitable value for ftp access */
295     p_input->i_pts_delay = config_GetInt( p_input, "mms-caching" ) * 1000;
296
297     p_input->p_access_data = p_sys;
298
299     return( VLC_SUCCESS );
300
301 exit_error:
302     E_( url_free )( p_sys->p_url );
303
304     if( p_sys->p_socket )
305     {
306         NetClose( p_input, p_sys->p_socket );
307     }
308     free( p_sys );
309     return( VLC_EGENERIC );
310 }
311
312 /*****************************************************************************
313  * Close: free unused data structures
314  *****************************************************************************/
315 void E_( MMSHClose ) ( input_thread_t *p_input )
316 {
317     access_sys_t    *p_sys   = p_input->p_access_data;
318
319     msg_Dbg( p_input, "stopping stream" );
320
321     mmsh_stop( p_input, p_sys );
322
323     free( p_sys );
324 }
325
326 static int mmsh_get_packet( input_thread_t * p_input, access_sys_t *p_sys, chunk_t *p_ck )
327 {
328     int i_mov = p_sys->i_buffer - p_sys->i_buffer_pos;
329
330     if( p_sys->i_buffer_pos > BUFFER_SIZE / 2 )
331     {
332         if( i_mov > 0 )
333         {
334             memmove( &p_sys->buffer[0], 
335                      &p_sys->buffer[p_sys->i_buffer_pos],
336                      i_mov );
337         }
338
339         p_sys->i_buffer     = i_mov;
340         p_sys->i_buffer_pos = 0;
341     }
342
343     if( NetFill( p_input, p_sys, 12 ) < 12 )
344     {
345         msg_Warn( p_input, "cannot fill buffer" );
346         return VLC_EGENERIC;
347     }
348
349     chunk_parse( p_ck, &p_sys->buffer[p_sys->i_buffer_pos], p_sys->i_buffer - p_sys->i_buffer_pos );
350
351     if( p_ck->i_type == 0x4524 )   // Transfer complete
352     {
353         msg_Warn( p_input, "EOF" );
354         return VLC_EGENERIC;
355     }
356     else if( p_ck->i_type != 0x4824 && p_ck->i_type != 0x4424 )
357     {
358         msg_Err( p_input, "invalid chunk FATAL" );
359         return VLC_EGENERIC;
360     }
361
362     if( p_ck->i_data < p_ck->i_size2 - 8 )
363     {
364         if( NetFill( p_input, p_sys, p_ck->i_size2 - 8 - p_ck->i_data ) <= 0 )
365         {
366             msg_Warn( p_input, "cannot fill buffer" );
367             return VLC_EGENERIC;
368         }
369         chunk_parse( p_ck, &p_sys->buffer[p_sys->i_buffer_pos], p_sys->i_buffer - p_sys->i_buffer_pos );
370     }
371
372     if( p_sys->i_packet_sequence != 0 && p_ck->i_sequence != p_sys->i_packet_sequence )
373     {
374         msg_Warn( p_input, "packet lost ?" );
375     }
376
377     p_sys->i_packet_sequence = p_ck->i_sequence + 1;
378     p_sys->i_packet_used   = 0;
379     p_sys->i_packet_length = p_ck->i_data;
380     p_sys->p_packet        = p_ck->p_data;
381
382     p_sys->i_buffer_pos += 12 + p_ck->i_data;
383
384     return VLC_SUCCESS;
385 }
386
387
388 /*****************************************************************************
389  * Seek: try to go at the right place
390  *****************************************************************************/
391 static void Seek( input_thread_t * p_input, off_t i_pos )
392 {
393     access_sys_t *p_sys = p_input->p_access_data;
394     chunk_t      ck;
395     off_t        i_offset;
396     off_t        i_packet;
397
398     i_packet = ( i_pos - p_sys->i_header ) / p_sys->asfh.i_min_data_packet_size;
399     i_offset = ( i_pos - p_sys->i_header ) % p_sys->asfh.i_min_data_packet_size;
400
401     msg_Err( p_input, "seeking to "I64Fd, i_pos );
402
403     vlc_mutex_lock( &p_input->stream.stream_lock );
404
405     mmsh_stop( p_input, p_sys );
406     mmsh_start( p_input, p_sys, i_packet * p_sys->asfh.i_min_data_packet_size );
407
408     for( ;; )
409     {
410         if( mmsh_get_packet( p_input, p_sys, &ck ) )
411         {
412             break;
413         }
414
415         /* skip headers */
416         if( ck.i_type != 0x4824 )
417         {
418             break;
419         }
420         msg_Warn( p_input, "skipping header" );
421     }
422
423     p_sys->i_pos = i_pos;
424     p_sys->i_packet_used += i_offset;
425
426
427     p_input->stream.p_selected_area->i_tell = i_pos;
428     vlc_mutex_unlock( &p_input->stream.stream_lock );
429
430 }
431
432 /*****************************************************************************
433  * Read:
434  *****************************************************************************/
435 static ssize_t Read        ( input_thread_t * p_input, byte_t * p_buffer,
436                              size_t i_len )
437 {
438     access_sys_t *p_sys = p_input->p_access_data;
439     size_t       i_copy;
440     size_t       i_data = 0;
441
442     while( i_data < i_len )
443     {
444         if( p_sys->i_packet_used < p_sys->i_packet_length )
445         {
446             i_copy = __MIN( p_sys->i_packet_length - p_sys->i_packet_used, i_len - i_data );
447
448             memcpy( &p_buffer[i_data],
449                     &p_sys->p_packet[p_sys->i_packet_used],
450                     i_copy );
451
452             i_data += i_copy;
453             p_sys->i_packet_used += i_copy;
454         }
455         else if( p_sys->i_pos + i_data > p_sys->i_header &&
456                  (int)p_sys->i_packet_used < p_sys->asfh.i_min_data_packet_size )
457         {
458             i_copy = __MIN( p_sys->asfh.i_min_data_packet_size - p_sys->i_packet_used, i_len - i_data );
459
460             memset( &p_buffer[i_data], 0, i_copy );
461
462             i_data += i_copy;
463             p_sys->i_packet_used += i_copy;
464         }
465         else
466         {
467             chunk_t ck;
468             /* get a new packet */
469             /* fill enought data (>12) */
470             msg_Dbg( p_input, "waiting data (buffer = %d bytes", p_sys->i_buffer );
471
472             if( mmsh_get_packet( p_input, p_sys, &ck ) )
473             {
474                 return 0;
475             }
476
477             //fprintf( stderr, "type=0x%x size=%d sequence=%d unknown=%d size2=%d data=%d\n",
478             //         ck.i_type, ck.i_size, ck.i_sequence, ck.i_unknown, ck.i_size2, ck.i_data );
479         }
480     }
481
482     p_sys->i_pos += i_data;
483
484
485     return( i_data );
486 }
487
488
489 /****************************************************************************/
490 /****************************************************************************/
491 /****************************************************************************/
492 /****************************************************************************/
493 /****************************************************************************/
494
495 static int mmsh_start( input_thread_t *p_input, access_sys_t *p_sys, off_t i_pos )
496 {
497     uint8_t *p;
498     int i_streams = 0;
499     int i;
500     http_answer_t *p_ans;
501
502     msg_Dbg( p_input, "starting stream" );
503
504     p_sys->p_socket = NetOpenTCP( p_input, p_sys->p_url );
505
506     for( i = 1; i < 128; i++ )
507     {
508         if( p_sys->asfh.stream[i].i_selected )
509         {
510             i_streams++;
511         }
512     }
513
514     if( i_streams <= 0 )
515     {
516         msg_Err( p_input, "no stream selected" );
517         return VLC_EGENERIC;
518     }
519
520     p = &p_sys->buffer[0];
521     p += sprintf( p, "GET %s HTTP/1.0\r\n", p_sys->p_url->psz_path );
522     p += sprintf( p,"Accept: */*\r\n" );
523     p += sprintf( p, "User-Agent: NSPlayer/4.1.0.3856\r\n" );
524     p += sprintf( p, "Host: %s:%d\r\n", p_sys->p_url->psz_host, p_sys->p_url->i_port );
525     if( p_sys->b_broadcast )
526     {
527         p += sprintf( p, "Pragma: no-cache,rate=1.000000,request-context=%d\r\n", p_sys->i_request_context++ );
528     }
529     else
530     {
531         p += sprintf( p, "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=%u:%u,request-context=%d,max-duration=0\r\n",
532                          (uint32_t)((i_pos >> 32)&0xffffffff), (uint32_t)(i_pos&0xffffffff), p_sys->i_request_context++ );
533     }
534     p += sprintf( p, "Pragma: xPlayStrm=1\r\n" );
535     //p += sprintf( p, "Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}\r\n" );
536     p += sprintf( p, "Pragma: xClientGUID={"GUID_FMT"}\r\n", GUID_PRINT( p_sys->guid ) );
537     p += sprintf( p, "Pragma: stream-switch-count=%d\r\n", i_streams );
538     p += sprintf( p, "Pragma: stream-switch-entry=" );
539     for( i = 0; i < i_streams; i++ )
540     {
541         if( p_sys->asfh.stream[i].i_selected )
542         {
543             p += sprintf( p, "ffff:%d:0 ", p_sys->asfh.stream[i].i_id );
544         }
545         else
546         {
547             p += sprintf( p, "ffff:%d:2 ", p_sys->asfh.stream[i].i_id );
548         }
549     }
550     p += sprintf( p, "\r\n" );
551     p += sprintf( p, "Connection: Close\r\n\r\n" );
552
553
554     NetWrite( p_input, p_sys->p_socket, p_sys->buffer,  p - p_sys->buffer );
555
556     msg_Dbg( p_input, "filling buffer" );
557     /* we read until we found a \r\n\r\n or \n\n */
558     p_sys->i_buffer = 0;
559     p_sys->i_buffer_pos = 0;
560     for( ;; )
561     {
562         int     i_try = 0;
563         int     i_read;
564         uint8_t *p;
565
566         p = &p_sys->buffer[p_sys->i_buffer];
567         i_read =
568             NetRead( p_input, p_sys->p_socket,
569                      &p_sys->buffer[p_sys->i_buffer],
570                       1024 );
571
572         if( i_read == 0 )
573         {
574             if( i_try++ > 12 )
575             {
576                 break;
577             }
578             msg_Dbg( p_input, "another try (%d/12)", i_try );
579             continue;
580         }
581
582         if( i_read <= 0 || p_input->b_die || p_input->b_error )
583         {
584             break;
585         }
586         p_sys->i_buffer += i_read;
587         p_sys->buffer[p_sys->i_buffer] = '\0';
588
589         if( strstr( p, "\r\n\r\n" ) || strstr( p, "\n\n" ) )
590         {
591             msg_Dbg( p_input, "body found" );
592             break;
593         }
594         if( p_sys->i_buffer >= BUFFER_SIZE - 1024 )
595         {
596             msg_Dbg( p_input, "buffer size exeded" );
597             break;
598         }
599     }
600
601     p_ans = http_answer_parse( p_sys->buffer, p_sys->i_buffer );
602     if( !p_ans )
603     {
604         msg_Err( p_input, "cannot parse answer" );
605         return VLC_EGENERIC;
606     }
607
608     if( p_ans->i_error < 200 || p_ans->i_error >= 300 )
609     {
610         msg_Err( p_input, "error %d (server return=`%s')", p_ans->i_error, p_ans->psz_answer );
611         http_answer_free( p_ans );
612         return VLC_EGENERIC;
613     }
614
615     if( !p_ans->p_body )
616     {
617         p_sys->i_buffer_pos = 0;
618         p_sys->i_buffer = 0;
619     }
620     else
621     {
622         p_sys->i_buffer_pos = p_ans->p_body - p_sys->buffer;
623     }
624     http_answer_free( p_ans );
625
626     return VLC_SUCCESS;
627 }
628
629 static void mmsh_stop( input_thread_t *p_input, access_sys_t *p_sys )
630 {
631     msg_Dbg( p_input, "closing stream" );
632     NetClose( p_input, p_sys->p_socket );
633 }
634
635 static ssize_t NetFill( input_thread_t *p_input,
636                         access_sys_t   *p_sys, int i_size )
637 {
638     int i_try   = 0;
639     int i_total = 0;
640
641     i_size = __MIN( i_size, BUFFER_SIZE - p_sys->i_buffer );
642     if( i_size <= 0 )
643     {
644         return 0;
645     }
646     
647
648     for( ;; )
649     {
650         int i_read;
651
652         i_read =
653             NetRead( p_input, p_sys->p_socket, &p_sys->buffer[p_sys->i_buffer], i_size );
654
655         if( i_read == 0 )
656         {
657             if( i_try++ > 2 )
658             {
659                 break;
660             }
661             msg_Dbg( p_input, "another try %d/2", i_try );
662             continue;
663         }
664
665         if( i_read < 0 || p_input->b_die || p_input->b_error )
666         {
667             break;
668         }
669         i_total += i_read;
670
671         p_sys->i_buffer += i_read;
672         if( i_total >= i_size )
673         {
674             break;
675         }
676     }
677
678     p_sys->buffer[p_sys->i_buffer] = '\0';
679
680     return i_total;
681 }
682
683 /****************************************************************************
684  * NetOpenTCP:
685  ****************************************************************************/
686 static input_socket_t * NetOpenTCP( input_thread_t *p_input, url_t *p_url )
687 {
688     input_socket_t   *p_socket;
689     char             *psz_network;
690     module_t         *p_network;
691     network_socket_t socket_desc;
692
693
694     p_socket = malloc( sizeof( input_socket_t ) );
695     memset( p_socket, 0, sizeof( input_socket_t ) );
696
697     psz_network = "";
698     if( config_GetInt( p_input, "ipv4" ) )
699     {
700         psz_network = "ipv4";
701     }
702     else if( config_GetInt( p_input, "ipv6" ) )
703     {
704         psz_network = "ipv6";
705     }
706
707     msg_Dbg( p_input, "waiting for connection..." );
708
709     socket_desc.i_type = NETWORK_TCP;
710     socket_desc.psz_server_addr = p_url->psz_host;
711     socket_desc.i_server_port   = p_url->i_port;
712     socket_desc.psz_bind_addr   = "";
713     socket_desc.i_bind_port     = 0;
714     socket_desc.i_ttl           = 0;
715     p_input->p_private = (void*)&socket_desc;
716     if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
717     {
718         msg_Err( p_input, "failed to connect with server" );
719         return NULL;
720     }
721     module_Unneed( p_input, p_network );
722     p_socket->i_handle = socket_desc.i_handle;
723     p_input->i_mtu     = socket_desc.i_mtu;
724
725     msg_Dbg( p_input,
726              "connection with \"%s:%d\" successful",
727              p_url->psz_host,
728              p_url->i_port );
729
730     return p_socket;
731 }
732
733 /*****************************************************************************
734  * Read: read on a file descriptor, checking b_die periodically
735  *****************************************************************************/
736 static ssize_t NetRead( input_thread_t *p_input,
737                         input_socket_t *p_socket,
738                         byte_t *p_buffer, size_t i_len )
739 {
740     struct timeval  timeout;
741     fd_set          fds;
742     ssize_t         i_recv;
743     int             i_ret;
744
745     /* Initialize file descriptor set */
746     FD_ZERO( &fds );
747     FD_SET( p_socket->i_handle, &fds );
748
749     /* We'll wait 1 second if nothing happens */
750     timeout.tv_sec  = 1;
751     timeout.tv_usec = 0;
752
753     /* Find if some data is available */
754     while( ( i_ret = select( p_socket->i_handle + 1, &fds,
755                              NULL, NULL, &timeout )) == 0 ||
756 #ifdef HAVE_ERRNO_H
757            ( i_ret < 0 && errno == EINTR )
758 #endif
759          )
760     {
761         FD_ZERO( &fds );
762         FD_SET( p_socket->i_handle, &fds );
763         timeout.tv_sec  = 1;
764         timeout.tv_usec = 0;
765
766         if( p_input->b_die || p_input->b_error )
767         {
768             return 0;
769         }
770     }
771
772     if( i_ret < 0 )
773     {
774         msg_Err( p_input, "network select error (%s)", strerror(errno) );
775         return -1;
776     }
777
778     i_recv = recv( p_socket->i_handle, p_buffer, i_len, 0 );
779
780     if( i_recv < 0 )
781     {
782         msg_Err( p_input, "recv failed (%s)", strerror(errno) );
783     }
784
785     return i_recv;
786 }
787
788 static ssize_t NetWrite( input_thread_t *p_input,
789                          input_socket_t *p_socket,
790                          byte_t *p_buffer, size_t i_len )
791 {
792     struct timeval  timeout;
793     fd_set          fds;
794     ssize_t         i_send;
795     int             i_ret;
796
797     /* Initialize file descriptor set */
798     FD_ZERO( &fds );
799     FD_SET( p_socket->i_handle, &fds );
800
801     /* We'll wait 1 second if nothing happens */
802     timeout.tv_sec  = 1;
803     timeout.tv_usec = 0;
804
805     /* Find if some data is available */
806     while( ( i_ret = select( p_socket->i_handle + 1, NULL, &fds, NULL, &timeout ) ) == 0 ||
807 #ifdef HAVE_ERRNO_H
808            ( i_ret < 0 && errno == EINTR )
809 #endif
810          )
811     {
812         FD_ZERO( &fds );
813         FD_SET( p_socket->i_handle, &fds );
814         timeout.tv_sec  = 1;
815         timeout.tv_usec = 0;
816
817         if( p_input->b_die || p_input->b_error )
818         {
819             return 0;
820         }
821     }
822
823     if( i_ret < 0 )
824     {
825         msg_Err( p_input, "network select error (%s)", strerror(errno) );
826         return -1;
827     }
828
829     i_send = send( p_socket->i_handle, p_buffer, i_len, 0 );
830
831     if( i_send < 0 )
832     {
833         msg_Err( p_input, "send failed (%s)", strerror(errno) );
834     }
835
836     return i_send;
837 }
838
839 static void NetClose( input_thread_t *p_input, input_socket_t *p_socket )
840 {
841 #if defined( WIN32 ) || defined( UNDER_CE )
842     closesocket( p_socket->i_handle );
843 #else
844     close( p_socket->i_handle );
845 #endif
846
847     free( p_socket );
848 }
849
850 static int http_next_line( uint8_t **pp_data, int *pi_data )
851 {
852     char *p, *p_end = *pp_data + *pi_data;
853
854     for( p = *pp_data; p < p_end; p++ )
855     {
856         if( p + 1 < p_end && *p == '\n' )
857         {
858             *pi_data = p_end - p - 1;
859             *pp_data = p + 1;
860             return VLC_SUCCESS;
861         }
862         if( p + 2 < p_end && p[0] == '\r' && p[1] == '\n' )
863         {
864             *pi_data = p_end - p - 2;
865             *pp_data = p + 2;
866             return VLC_SUCCESS;
867         }
868     }
869     *pi_data = 0;
870     *pp_data = p_end;
871     return VLC_EGENERIC;
872 }
873
874 static http_answer_t *http_answer_parse( uint8_t *p_data, int i_data )
875 {
876     http_answer_t *ans = malloc( sizeof( http_answer_t ) );
877     http_field_t  **pp_last;
878     char          buffer[1024];
879
880     if( sscanf( p_data, "HTTP/1.%d %d %s", &ans-> i_version, &ans->i_error, buffer ) < 3 )
881     {
882         free( ans );
883         return NULL;
884     }
885     ans->psz_answer = strdup( buffer );
886     fprintf( stderr, "version=%d error=%d answer=%s\n", ans-> i_version, ans->i_error, ans->psz_answer );
887     ans->p_fields = NULL;
888     ans->i_body   = 0;
889     ans->p_body   = 0;
890
891     pp_last = &ans->p_fields;
892
893     for( ;; )
894     {
895         http_field_t  *p_field;
896         uint8_t       *colon;
897
898         if( http_next_line( &p_data, &i_data ) )
899         {
900             return ans;
901         }
902         if( !strncmp( p_data, "\r\n", 2 ) || !strncmp( p_data, "\n", 1 ) )
903         {
904             break;
905         }
906
907         colon = strstr( p_data, ": " );
908         if( colon )
909         {
910             uint8_t *end;
911
912             end = strstr( colon, "\n" ) - 1;
913             if( *end != '\r' )
914             {
915                 end++;
916             }
917
918             p_field             = malloc( sizeof( http_field_t ) );
919             p_field->psz_name   = strndup( p_data, colon - p_data );
920             p_field->psz_value  = strndup( colon + 2, end - colon - 2 );
921             p_field->p_next     = NULL;
922
923             *pp_last = p_field;
924             pp_last = &p_field->p_next;
925
926             fprintf( stderr, "field name=`%s' value=`%s'\n", p_field->psz_name, p_field->psz_value );
927         }
928     }
929
930     if( http_next_line( &p_data, &i_data ) )
931     {
932         return ans;
933     }
934
935     ans->p_body = p_data;
936     ans->i_body = i_data;
937     fprintf( stderr, "body size=%d\n", i_data );
938
939     return ans;
940 }
941
942 static void http_answer_free( http_answer_t *ans )
943 {
944     http_field_t  *p_field = ans->p_fields;
945
946     while( p_field )
947     {
948         http_field_t *p_next;
949
950         p_next = p_field->p_next;
951         free( p_field->psz_name );
952         free( p_field->psz_value );
953         free( p_field );
954
955         p_field = p_next;
956     }
957
958     free( ans->psz_answer );
959     free( ans );
960 }
961
962 static http_field_t *http_field_find( http_field_t *p_field, char *psz_name )
963 {
964
965     while( p_field )
966     {
967         if( !strcasecmp( p_field->psz_name, psz_name ) )
968         {
969             return p_field;
970         }
971
972         p_field = p_field->p_next;
973     }
974
975     return NULL;
976 }
977 #if 0
978 static char *http_field_get_value( http_answer_t *ans, char *psz_name )
979 {
980     http_field_t  *p_field = ans->p_fields;
981
982     while( p_field )
983     {
984         if( !strcasecmp( p_field->psz_name, psz_name ) )
985         {
986             return p_field->psz_value;
987         }
988
989         p_field = p_field->p_next;
990     }
991
992     return NULL;
993 }
994 #endif
995
996
997 static int chunk_parse( chunk_t *ck, uint8_t *p_data, int i_data )
998 {
999     if( i_data < 12 )
1000     {
1001         return VLC_EGENERIC;
1002     }
1003
1004     ck->i_type      = GetWLE( p_data );
1005     ck->i_size      = GetWLE( p_data + 2);
1006     ck->i_sequence  = GetDWLE( p_data  + 4);
1007     ck->i_unknown   = GetWLE( p_data + 8);
1008     ck->i_size2     = GetWLE( p_data + 10);
1009
1010     ck->p_data      = p_data + 12;
1011     ck->i_data      = __MIN( i_data - 12, ck->i_size2 - 8 );
1012
1013 #if 0
1014     fprintf( stderr, "type=0x%x size=%d sequence=%d unknown=%d size2=%d data=%d\n",
1015              ck->i_type, ck->i_size, ck->i_sequence, ck->i_unknown, ck->i_size2, ck->i_data );
1016 #endif
1017     return VLC_SUCCESS;
1018 }
1019