1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2001, 2002 the VideoLAN team
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_access.h>
34 #include <vlc_strings.h>
35 #include <vlc_input.h>
37 #include <vlc_network.h>
49 /*****************************************************************************
51 *****************************************************************************/
52 int MMSHOpen ( access_t
* );
53 void MMSHClose ( access_t
* );
55 static block_t
*Block( access_t
*p_access
);
56 static ssize_t
ReadRedirect( access_t
*, uint8_t *, size_t );
57 static int Seek( access_t
*, uint64_t );
58 static int Control( access_t
*, int, va_list );
60 static int Describe( access_t
*, char **ppsz_location
);
61 static int Start( access_t
*, uint64_t );
62 static void Stop( access_t
* );
64 static int GetPacket( access_t
*, chunk_t
* );
65 static void GetHeader( access_t
*p_access
, int i_content_length
);
67 static int Restart( access_t
* );
68 static int Reset( access_t
* );
70 //#define MMSH_USER_AGENT "NSPlayer/4.1.0.3856"
71 #define MMSH_USER_AGENT "NSPlayer/7.10.0.3059"
73 /****************************************************************************
74 * Open: connect to ftp server and ask for file
75 ****************************************************************************/
76 int MMSHOpen( access_t
*p_access
)
79 char *psz_location
= NULL
;
82 STANDARD_BLOCK_ACCESS_INIT
84 p_sys
->i_proto
= MMS_PROTO_HTTP
;
88 p_sys
->b_proxy
= false;
89 memset( &p_sys
->proxy
, 0, sizeof(p_sys
->proxy
) );
92 /* TODO reuse instead http-proxy from http access ? */
93 psz_proxy
= var_CreateGetNonEmptyString( p_access
, "mmsh-proxy" );
96 char *psz_http_proxy
= var_InheritString( p_access
, "http-proxy" );
99 psz_proxy
= psz_http_proxy
;
100 var_SetString( p_access
, "mmsh-proxy", psz_proxy
);
106 p_sys
->b_proxy
= true;
107 vlc_UrlParse( &p_sys
->proxy
, psz_proxy
, 0 );
112 const char *http_proxy
= getenv( "http_proxy" );
115 p_sys
->b_proxy
= true;
116 vlc_UrlParse( &p_sys
->proxy
, http_proxy
, 0 );
122 if( ( p_sys
->proxy
.psz_host
== NULL
) ||
123 ( *p_sys
->proxy
.psz_host
== '\0' ) )
125 msg_Warn( p_access
, "invalid proxy host" );
126 vlc_UrlClean( &p_sys
->proxy
);
131 if( p_sys
->proxy
.i_port
<= 0 )
132 p_sys
->proxy
.i_port
= 80;
133 msg_Dbg( p_access
, "Using http proxy %s:%d",
134 p_sys
->proxy
.psz_host
, p_sys
->proxy
.i_port
);
137 /* open a tcp connection */
138 vlc_UrlParse( &p_sys
->url
, p_access
->psz_location
, 0 );
139 if( ( p_sys
->url
.psz_host
== NULL
) ||
140 ( *p_sys
->url
.psz_host
== '\0' ) )
142 msg_Err( p_access
, "invalid host" );
145 if( p_sys
->url
.i_port
<= 0 )
146 p_sys
->url
.i_port
= 80;
148 if( Describe( p_access
, &psz_location
) )
151 /* Handle redirection */
152 if( psz_location
&& *psz_location
)
154 msg_Dbg( p_access
, "redirection to %s", psz_location
);
156 input_thread_t
* p_input
= access_GetParentInput( p_access
);
157 input_item_t
* p_new_loc
;
161 free( psz_location
);
164 /** \bug we do not autodelete here */
165 p_new_loc
= input_item_New( psz_location
, psz_location
);
166 input_item_t
*p_item
= input_GetItem( p_input
);
167 input_item_PostSubItem( p_item
, p_new_loc
);
169 vlc_gc_decref( p_new_loc
);
170 vlc_object_release( p_input
);
172 free( psz_location
);
174 p_access
->pf_block
= NULL
;
175 p_access
->pf_read
= ReadRedirect
;
178 free( psz_location
);
181 if( Start( p_access
, 0 ) )
183 msg_Err( p_access
, "cannot start stream" );
184 free( p_sys
->p_header
);
188 if( !p_sys
->b_broadcast
)
190 p_access
->info
.i_size
= p_sys
->asfh
.i_file_size
;
196 vlc_UrlClean( &p_sys
->proxy
);
197 vlc_UrlClean( &p_sys
->url
);
202 /*****************************************************************************
203 * Close: free unused data structures
204 *****************************************************************************/
205 void MMSHClose ( access_t
*p_access
)
207 access_sys_t
*p_sys
= p_access
->p_sys
;
211 free( p_sys
->p_header
);
213 vlc_UrlClean( &p_sys
->proxy
);
214 vlc_UrlClean( &p_sys
->url
);
218 /*****************************************************************************
220 *****************************************************************************/
221 static int Control( access_t
*p_access
, int i_query
, va_list args
)
223 access_sys_t
*p_sys
= p_access
->p_sys
;
232 case ACCESS_CAN_SEEK
:
233 pb_bool
= (bool*)va_arg( args
, bool* );
234 *pb_bool
= !p_sys
->b_broadcast
;
237 case ACCESS_CAN_FASTSEEK
:
238 pb_bool
= (bool*)va_arg( args
, bool* );
242 case ACCESS_CAN_PAUSE
:
243 case ACCESS_CAN_CONTROL_PACE
:
244 pb_bool
= (bool*)va_arg( args
, bool* );
249 case ACCESS_GET_PTS_DELAY
:
250 pi_64
= (int64_t*)va_arg( args
, int64_t * );
251 *pi_64
= INT64_C(1000)
252 * var_InheritInteger( p_access
, "network-caching" );
255 case ACCESS_GET_PRIVATE_ID_STATE
:
256 i_int
= (int)va_arg( args
, int );
257 pb_bool
= (bool *)va_arg( args
, bool * );
259 if( (i_int
< 0) || (i_int
> 127) )
261 *pb_bool
= p_sys
->asfh
.stream
[i_int
].i_selected
? true : false;
265 case ACCESS_SET_PAUSE_STATE
:
266 b_bool
= (bool)va_arg( args
, int );
270 Seek( p_access
, p_access
->info
.i_pos
);
273 case ACCESS_GET_TITLE_INFO
:
274 case ACCESS_SET_TITLE
:
275 case ACCESS_SET_SEEKPOINT
:
276 case ACCESS_SET_PRIVATE_ID_STATE
:
277 case ACCESS_GET_CONTENT_TYPE
:
281 msg_Warn( p_access
, "unimplemented query in control" );
288 /*****************************************************************************
289 * Seek: try to go at the right place
290 *****************************************************************************/
291 static int Seek( access_t
*p_access
, uint64_t i_pos
)
293 access_sys_t
*p_sys
= p_access
->p_sys
;
298 msg_Dbg( p_access
, "seeking to %"PRId64
, i_pos
);
300 i_packet
= ( i_pos
- p_sys
->i_header
) / p_sys
->asfh
.i_min_data_packet_size
;
301 i_offset
= ( i_pos
- p_sys
->i_header
) % p_sys
->asfh
.i_min_data_packet_size
;
304 Start( p_access
, i_packet
* p_sys
->asfh
.i_min_data_packet_size
);
306 while( vlc_object_alive (p_access
) )
308 if( GetPacket( p_access
, &ck
) )
312 if( ck
.i_type
!= 0x4824 )
315 msg_Warn( p_access
, "skipping header" );
318 p_access
->info
.i_pos
= i_pos
;
319 p_access
->info
.b_eof
= false;
320 p_sys
->i_packet_used
+= i_offset
;
325 /*****************************************************************************
327 *****************************************************************************/
328 static ssize_t
ReadRedirect( access_t
*p_access
, uint8_t *p
, size_t i_len
)
330 VLC_UNUSED(p_access
); VLC_UNUSED(p
); VLC_UNUSED(i_len
);
334 /*****************************************************************************
336 *****************************************************************************/
337 static block_t
*Block( access_t
*p_access
)
339 access_sys_t
*p_sys
= p_access
->p_sys
;
340 const unsigned i_packet_min
= p_sys
->asfh
.i_min_data_packet_size
;
342 if( p_access
->info
.i_pos
< p_sys
->i_start
+ p_sys
->i_header
)
344 const size_t i_offset
= p_access
->info
.i_pos
- p_sys
->i_start
;
345 const size_t i_copy
= p_sys
->i_header
- i_offset
;
347 block_t
*p_block
= block_New( p_access
, i_copy
);
351 memcpy( p_block
->p_buffer
, &p_sys
->p_header
[i_offset
], i_copy
);
352 p_access
->info
.i_pos
+= i_copy
;
355 else if( p_sys
->i_packet_length
> 0 &&
356 p_sys
->i_packet_used
< __MAX( p_sys
->i_packet_length
, i_packet_min
) )
359 size_t i_padding
= 0;
361 if( p_sys
->i_packet_used
< p_sys
->i_packet_length
)
362 i_copy
= p_sys
->i_packet_length
- p_sys
->i_packet_used
;
363 if( __MAX( p_sys
->i_packet_used
, p_sys
->i_packet_length
) < i_packet_min
)
364 i_padding
= i_packet_min
- __MAX( p_sys
->i_packet_used
, p_sys
->i_packet_length
);
366 block_t
*p_block
= block_New( p_access
, i_copy
+ i_padding
);
371 memcpy( &p_block
->p_buffer
[0], &p_sys
->p_packet
[p_sys
->i_packet_used
], i_copy
);
373 memset( &p_block
->p_buffer
[i_copy
], 0, i_padding
);
375 p_sys
->i_packet_used
+= i_copy
+ i_padding
;
376 p_access
->info
.i_pos
+= i_copy
+ i_padding
;
382 if( GetPacket( p_access
, &ck
) )
385 if( p_sys
->b_broadcast
)
387 if( (ck
.i_type
== 0x4524) && (ck
.i_sequence
!= 0) )
388 i_ret
= Restart( p_access
);
389 else if( ck
.i_type
== 0x4324 )
390 i_ret
= Reset( p_access
);
394 p_access
->info
.b_eof
= true;
398 if( ck
.i_type
!= 0x4424 )
400 p_sys
->i_packet_used
= 0;
401 p_sys
->i_packet_length
= 0;
408 static int Restart( access_t
*p_access
)
410 access_sys_t
*p_sys
= p_access
->p_sys
;
411 char *psz_location
= NULL
;
413 msg_Dbg( p_access
, "Restart the stream" );
414 p_sys
->i_start
= p_access
->info
.i_pos
;
417 msg_Dbg( p_access
, "stoping the stream" );
421 msg_Dbg( p_access
, "describe the stream" );
422 if( Describe( p_access
, &psz_location
) )
424 msg_Err( p_access
, "describe failed" );
427 free( psz_location
);
430 if( Start( p_access
, 0 ) )
432 msg_Err( p_access
, "Start failed" );
437 static int Reset( access_t
*p_access
)
439 access_sys_t
*p_sys
= p_access
->p_sys
;
440 asf_header_t old_asfh
= p_sys
->asfh
;
443 msg_Dbg( p_access
, "Reset the stream" );
444 p_sys
->i_start
= p_access
->info
.i_pos
;
447 p_sys
->i_packet_sequence
= 0;
448 p_sys
->i_packet_used
= 0;
449 p_sys
->i_packet_length
= 0;
450 p_sys
->p_packet
= NULL
;
452 /* Get the next header FIXME memory loss ? */
453 GetHeader( p_access
, -1 );
454 if( p_sys
->i_header
<= 0 )
457 asf_HeaderParse ( &p_sys
->asfh
,
458 p_sys
->p_header
, p_sys
->i_header
);
459 msg_Dbg( p_access
, "packet count=%"PRId64
" packet size=%d",
460 p_sys
->asfh
.i_data_packets_count
,
461 p_sys
->asfh
.i_min_data_packet_size
);
463 asf_StreamSelect( &p_sys
->asfh
,
464 var_InheritInteger( p_access
, "mms-maxbitrate" ),
465 var_InheritBool( p_access
, "mms-all" ),
466 var_InheritBool( p_access
, "audio" ),
467 var_InheritBool( p_access
, "video" ) );
469 /* Check we have comptible asfh */
470 for( i
= 1; i
< 128; i
++ )
472 asf_stream_t
*p_old
= &old_asfh
.stream
[i
];
473 asf_stream_t
*p_new
= &p_sys
->asfh
.stream
[i
];
475 if( p_old
->i_cat
!= p_new
->i_cat
|| p_old
->i_selected
!= p_new
->i_selected
)
480 msg_Warn( p_access
, "incompatible asf header, restart" );
481 return Restart( p_access
);
485 p_sys
->i_packet_used
= 0;
486 p_sys
->i_packet_length
= 0;
490 static int OpenConnection( access_t
*p_access
)
492 access_sys_t
*p_sys
= p_access
->p_sys
;
493 vlc_url_t srv
= p_sys
->b_proxy
? p_sys
->proxy
: p_sys
->url
;
495 if( ( p_sys
->fd
= net_ConnectTCP( p_access
,
496 srv
.psz_host
, srv
.i_port
) ) < 0 )
498 msg_Err( p_access
, "cannot connect to %s:%d",
499 srv
.psz_host
, srv
.i_port
);
505 net_Printf( p_access
, p_sys
->fd
, NULL
,
506 "GET http://%s:%d%s HTTP/1.0\r\n",
507 p_sys
->url
.psz_host
, p_sys
->url
.i_port
,
508 ( (p_sys
->url
.psz_path
== NULL
) ||
509 (*p_sys
->url
.psz_path
== '\0') ) ?
510 "/" : p_sys
->url
.psz_path
);
512 /* Proxy Authentication */
513 if( p_sys
->proxy
.psz_username
&& *p_sys
->proxy
.psz_username
)
518 if( asprintf( &buf
, "%s:%s", p_sys
->proxy
.psz_username
,
519 p_sys
->proxy
.psz_password
? p_sys
->proxy
.psz_password
: "" ) == -1 )
522 b64
= vlc_b64_encode( buf
);
525 net_Printf( p_access
, p_sys
->fd
, NULL
,
526 "Proxy-Authorization: Basic %s\r\n", b64
);
532 net_Printf( p_access
, p_sys
->fd
, NULL
,
533 "GET %s HTTP/1.0\r\n"
535 ( (p_sys
->url
.psz_path
== NULL
) ||
536 (*p_sys
->url
.psz_path
== '\0') ) ?
537 "/" : p_sys
->url
.psz_path
,
538 p_sys
->url
.psz_host
, p_sys
->url
.i_port
);
543 /*****************************************************************************
545 *****************************************************************************/
546 static int Describe( access_t
*p_access
, char **ppsz_location
)
548 access_sys_t
*p_sys
= p_access
->p_sys
;
549 char *psz_location
= NULL
;
550 int i_content_length
= -1;
551 bool b_keepalive
= false;
556 p_sys
->b_broadcast
= true;
557 p_sys
->i_request_context
= 1;
558 p_sys
->i_packet_sequence
= 0;
559 p_sys
->i_packet_used
= 0;
560 p_sys
->i_packet_length
= 0;
561 p_sys
->p_packet
= NULL
;
563 GenerateGuid ( &p_sys
->guid
);
565 if( OpenConnection( p_access
) )
568 net_Printf( p_access
, p_sys
->fd
, NULL
,
570 "User-Agent: "MMSH_USER_AGENT
"\r\n"
571 "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=0:0,request-context=%d,max-duration=0\r\n"
572 "Pragma: xClientGUID={"GUID_FMT
"}\r\n"
573 "Connection: Close\r\n",
574 p_sys
->i_request_context
++,
575 GUID_PRINT( p_sys
->guid
) );
577 if( net_Printf( p_access
, p_sys
->fd
, NULL
, "\r\n" ) < 0 )
579 msg_Err( p_access
, "failed to send request" );
583 /* Receive the http header */
584 if( ( psz
= net_Gets( p_access
, p_sys
->fd
, NULL
) ) == NULL
)
586 msg_Err( p_access
, "failed to read answer" );
590 if( strncmp( psz
, "HTTP/1.", 7 ) )
592 msg_Err( p_access
, "invalid HTTP reply '%s'", psz
);
596 i_code
= atoi( &psz
[9] );
599 msg_Err( p_access
, "error: %s", psz
);
604 msg_Dbg( p_access
, "HTTP reply '%s'", psz
);
608 char *psz
= net_Gets( p_access
, p_sys
->fd
, NULL
);
613 msg_Err( p_access
, "failed to read answer" );
623 if( ( p
= strchr( psz
, ':' ) ) == NULL
)
625 msg_Err( p_access
, "malformed header line: %s", psz
);
630 while( *p
== ' ' ) p
++;
632 /* FIXME FIXME test Content-Type to see if it's a plain stream or an
634 if( !strcasecmp( psz
, "Pragma" ) )
636 if( strstr( p
, "features" ) )
638 /* FIXME, it is a bit badly done here ..... */
639 if( strstr( p
, "broadcast" ) )
641 msg_Dbg( p_access
, "stream type = broadcast" );
642 p_sys
->b_broadcast
= true;
644 else if( strstr( p
, "seekable" ) )
646 msg_Dbg( p_access
, "stream type = seekable" );
647 p_sys
->b_broadcast
= false;
651 msg_Warn( p_access
, "unknow stream types (%s)", p
);
652 p_sys
->b_broadcast
= false;
656 else if( !strcasecmp( psz
, "Location" ) )
658 psz_location
= strdup( p
);
660 else if( !strcasecmp( psz
, "Content-Length" ) )
662 i_content_length
= atoi( p
);
663 msg_Dbg( p_access
, "content-length = %d", i_content_length
);
665 else if( !strcasecmp( psz
, "Connection" ) )
667 if( strcasestr( p
, "Keep-Alive" ) )
669 msg_Dbg( p_access
, "Keep-Alive header found" );
678 /* Handle the redirection */
679 if( ( (i_code
== 301) || (i_code
== 302) ||
680 (i_code
== 303) || (i_code
== 307) ) &&
681 psz_location
&& *psz_location
)
683 msg_Dbg( p_access
, "redirection to %s", psz_location
);
684 net_Close( p_sys
->fd
); p_sys
->fd
= -1;
686 *ppsz_location
= psz_location
;
689 free( psz_location
);
691 /* Read the asf header */
692 GetHeader( p_access
, b_keepalive
? i_content_length
: -1);
693 if( p_sys
->i_header
<= 0 )
695 msg_Err( p_access
, "header size == 0" );
698 /* close this connection */
699 net_Close( p_sys
->fd
);
702 /* *** parse header and get stream and their id *** */
703 /* get all streams properties,
705 * TODO : stream bitrates properties(optional)
706 * and bitrate mutual exclusion(optional) */
707 asf_HeaderParse ( &p_sys
->asfh
,
708 p_sys
->p_header
, p_sys
->i_header
);
709 msg_Dbg( p_access
, "packet count=%"PRId64
" packet size=%d",
710 p_sys
->asfh
.i_data_packets_count
,
711 p_sys
->asfh
.i_min_data_packet_size
);
713 if( p_sys
->asfh
.i_min_data_packet_size
<= 0 )
716 asf_StreamSelect( &p_sys
->asfh
,
717 var_InheritInteger( p_access
, "mms-maxbitrate" ),
718 var_InheritBool( p_access
, "mms-all" ),
719 var_InheritBool( p_access
, "audio" ),
720 var_InheritBool( p_access
, "video" ) );
726 net_Close( p_sys
->fd
);
732 static void GetHeader( access_t
*p_access
, int i_content_length
)
734 access_sys_t
*p_sys
= p_access
->p_sys
;
735 int i_read_content
= 0;
737 /* Read the asf header */
739 free( p_sys
->p_header
);
740 p_sys
->p_header
= NULL
;
744 if( (i_content_length
>= 0 && i_read_content
>= i_content_length
) || GetPacket( p_access
, &ck
) || ck
.i_type
!= 0x4824 )
747 i_read_content
+= (4+ck
.i_size
);
751 p_sys
->i_header
+= ck
.i_data
;
752 p_sys
->p_header
= xrealloc( p_sys
->p_header
, p_sys
->i_header
);
753 memcpy( &p_sys
->p_header
[p_sys
->i_header
- ck
.i_data
],
754 ck
.p_data
, ck
.i_data
);
757 msg_Dbg( p_access
, "complete header size=%d", p_sys
->i_header
);
761 /*****************************************************************************
763 ****************************************************************************/
764 static int Start( access_t
*p_access
, uint64_t i_pos
)
766 access_sys_t
*p_sys
= p_access
->p_sys
;
768 int i_streams_selected
= 0;
772 msg_Dbg( p_access
, "starting stream" );
774 for( i
= 1; i
< 128; i
++ )
776 if( p_sys
->asfh
.stream
[i
].i_cat
== ASF_STREAM_UNKNOWN
)
779 if( p_sys
->asfh
.stream
[i
].i_selected
)
780 i_streams_selected
++;
782 if( i_streams_selected
<= 0 )
784 msg_Err( p_access
, "no stream selected" );
788 if( OpenConnection( p_access
) )
791 net_Printf( p_access
, p_sys
->fd
, NULL
,
793 "User-Agent: "MMSH_USER_AGENT
"\r\n" );
794 if( p_sys
->b_broadcast
)
796 net_Printf( p_access
, p_sys
->fd
, NULL
,
797 "Pragma: no-cache,rate=1.000000,request-context=%d\r\n",
798 p_sys
->i_request_context
++ );
802 net_Printf( p_access
, p_sys
->fd
, NULL
,
803 "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=%u:%u,request-context=%d,max-duration=0\r\n",
804 (uint32_t)((i_pos
>> 32)&0xffffffff),
805 (uint32_t)(i_pos
&0xffffffff),
806 p_sys
->i_request_context
++ );
808 net_Printf( p_access
, p_sys
->fd
, NULL
,
809 "Pragma: xPlayStrm=1\r\n"
810 "Pragma: xClientGUID={"GUID_FMT
"}\r\n"
811 "Pragma: stream-switch-count=%d\r\n"
812 "Pragma: stream-switch-entry=",
813 GUID_PRINT( p_sys
->guid
),
816 for( i
= 1; i
< 128; i
++ )
818 if( p_sys
->asfh
.stream
[i
].i_cat
!= ASF_STREAM_UNKNOWN
)
821 if( p_sys
->asfh
.stream
[i
].i_selected
)
825 net_Printf( p_access
, p_sys
->fd
, NULL
,
826 "ffff:%d:%d ", i
, i_select
);
829 net_Printf( p_access
, p_sys
->fd
, NULL
, "\r\n" );
830 net_Printf( p_access
, p_sys
->fd
, NULL
,
831 "Connection: Close\r\n" );
833 if( net_Printf( p_access
, p_sys
->fd
, NULL
, "\r\n" ) < 0 )
835 msg_Err( p_access
, "failed to send request" );
839 psz
= net_Gets( p_access
, p_sys
->fd
, NULL
);
842 msg_Err( p_access
, "cannot read data 0" );
846 if( atoi( &psz
[9] ) >= 400 )
848 msg_Err( p_access
, "error: %s", psz
);
852 msg_Dbg( p_access
, "HTTP reply '%s'", psz
);
855 /* FIXME check HTTP code */
858 char *psz
= net_Gets( p_access
, p_sys
->fd
, NULL
);
861 msg_Err( p_access
, "cannot read data 1" );
869 msg_Dbg( p_access
, "%s", psz
);
873 p_sys
->i_packet_used
= 0;
874 p_sys
->i_packet_length
= 0;
879 /*****************************************************************************
881 *****************************************************************************/
882 static void Stop( access_t
*p_access
)
884 access_sys_t
*p_sys
= p_access
->p_sys
;
886 msg_Dbg( p_access
, "closing stream" );
889 net_Close( p_sys
->fd
);
894 /*****************************************************************************
896 *****************************************************************************/
897 static int GetPacket( access_t
* p_access
, chunk_t
*p_ck
)
899 access_sys_t
*p_sys
= p_access
->p_sys
;
903 memset( p_ck
, 0, sizeof( chunk_t
) );
905 /* Read the chunk header */
906 /* Some headers are short, like 0x4324. Reading 12 bytes will cause us
907 * to lose synchronization with the stream. Just read to the length
908 * (4 bytes), decode and then read up to 8 additional bytes to get the
911 if( net_Read( p_access
, p_sys
->fd
, NULL
, p_sys
->buffer
, 4, true ) < 4 )
913 msg_Err( p_access
, "cannot read data 2" );
917 p_ck
->i_type
= GetWLE( p_sys
->buffer
);
918 p_ck
->i_size
= GetWLE( p_sys
->buffer
+ 2);
920 restsize
= p_ck
->i_size
;
924 if( net_Read( p_access
, p_sys
->fd
, NULL
, p_sys
->buffer
+ 4, restsize
, true ) < restsize
)
926 msg_Err( p_access
, "cannot read data 3" );
929 p_ck
->i_sequence
= GetDWLE( p_sys
->buffer
+ 4);
930 p_ck
->i_unknown
= GetWLE( p_sys
->buffer
+ 8);
932 /* Set i_size2 to 8 if this header was short, since a real value won't be
933 * present in the buffer. Using 8 avoid reading additional data for the
939 p_ck
->i_size2
= GetWLE( p_sys
->buffer
+ 10);
941 p_ck
->p_data
= p_sys
->buffer
+ 12;
942 p_ck
->i_data
= p_ck
->i_size2
- 8;
944 if( p_ck
->i_type
== 0x4524 ) // Transfer complete
946 if( p_ck
->i_sequence
== 0 )
948 msg_Warn( p_access
, "EOF" );
953 msg_Warn( p_access
, "next stream following" );
957 else if( p_ck
->i_type
== 0x4324 )
959 /* 0x4324 is CHUNK_TYPE_RESET: a new stream will follow with a sequence of 0 */
960 msg_Warn( p_access
, "next stream following (reset) seq=%d", p_ck
->i_sequence
);
963 else if( (p_ck
->i_type
!= 0x4824) && (p_ck
->i_type
!= 0x4424) )
965 msg_Err( p_access
, "invalid chunk FATAL (0x%x)", p_ck
->i_type
);
969 if( (p_ck
->i_data
> 0) &&
970 (net_Read( p_access
, p_sys
->fd
, NULL
, &p_sys
->buffer
[12],
971 p_ck
->i_data
, true ) < p_ck
->i_data
) )
973 msg_Err( p_access
, "cannot read data 4" );
978 if( (p_sys
->i_packet_sequence
!= 0) &&
979 (p_ck
->i_sequence
!= p_sys
->i_packet_sequence
) )
981 msg_Warn( p_access
, "packet lost ? (%d != %d)", p_ck
->i_sequence
, p_sys
->i_packet_sequence
);
985 p_sys
->i_packet_sequence
= p_ck
->i_sequence
+ 1;
986 p_sys
->i_packet_used
= 0;
987 p_sys
->i_packet_length
= p_ck
->i_data
;
988 p_sys
->p_packet
= p_ck
->p_data
;