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
);
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 );
113 const char *http_proxy
= getenv( "http_proxy" );
116 p_sys
->b_proxy
= true;
117 vlc_UrlParse( &p_sys
->proxy
, http_proxy
, 0 );
124 if( ( p_sys
->proxy
.psz_host
== NULL
) ||
125 ( *p_sys
->proxy
.psz_host
== '\0' ) )
127 msg_Warn( p_access
, "invalid proxy host" );
128 vlc_UrlClean( &p_sys
->proxy
);
133 if( p_sys
->proxy
.i_port
<= 0 )
134 p_sys
->proxy
.i_port
= 80;
135 msg_Dbg( p_access
, "Using http proxy %s:%d",
136 p_sys
->proxy
.psz_host
, p_sys
->proxy
.i_port
);
139 /* open a tcp connection */
140 vlc_UrlParse( &p_sys
->url
, p_access
->psz_path
, 0 );
141 if( ( p_sys
->url
.psz_host
== NULL
) ||
142 ( *p_sys
->url
.psz_host
== '\0' ) )
144 msg_Err( p_access
, "invalid host" );
147 if( p_sys
->url
.i_port
<= 0 )
148 p_sys
->url
.i_port
= 80;
150 if( Describe( p_access
, &psz_location
) )
153 /* Handle redirection */
154 if( psz_location
&& *psz_location
)
156 msg_Dbg( p_access
, "redirection to %s", psz_location
);
158 input_thread_t
* p_input
= access_GetParentInput( p_access
);
159 input_item_t
* p_new_loc
;
163 free( psz_location
);
166 /** \bug we do not autodelete here */
167 p_new_loc
= input_item_New( p_access
, psz_location
, psz_location
);
168 input_item_t
*p_item
= input_GetItem( p_input
);
169 input_item_AddSubItem( p_item
, p_new_loc
);
170 input_item_AddSubItem2( p_item
, p_new_loc
);
172 vlc_gc_decref( p_new_loc
);
173 vlc_object_release( p_input
);
175 free( psz_location
);
177 p_access
->pf_block
= NULL
;
178 p_access
->pf_read
= ReadRedirect
;
181 free( psz_location
);
184 if( Start( p_access
, 0 ) )
186 msg_Err( p_access
, "cannot start stream" );
187 free( p_sys
->p_header
);
191 if( !p_sys
->b_broadcast
)
193 p_access
->info
.i_size
= p_sys
->asfh
.i_file_size
;
199 vlc_UrlClean( &p_sys
->proxy
);
200 vlc_UrlClean( &p_sys
->url
);
205 /*****************************************************************************
206 * Close: free unused data structures
207 *****************************************************************************/
208 void MMSHClose ( access_t
*p_access
)
210 access_sys_t
*p_sys
= p_access
->p_sys
;
214 free( p_sys
->p_header
);
216 vlc_UrlClean( &p_sys
->proxy
);
217 vlc_UrlClean( &p_sys
->url
);
221 /*****************************************************************************
223 *****************************************************************************/
224 static int Control( access_t
*p_access
, int i_query
, va_list args
)
226 access_sys_t
*p_sys
= p_access
->p_sys
;
235 case ACCESS_CAN_SEEK
:
236 pb_bool
= (bool*)va_arg( args
, bool* );
237 *pb_bool
= !p_sys
->b_broadcast
;
240 case ACCESS_CAN_FASTSEEK
:
241 pb_bool
= (bool*)va_arg( args
, bool* );
245 case ACCESS_CAN_PAUSE
:
246 case ACCESS_CAN_CONTROL_PACE
:
247 pb_bool
= (bool*)va_arg( args
, bool* );
252 case ACCESS_GET_PTS_DELAY
:
253 pi_64
= (int64_t*)va_arg( args
, int64_t * );
254 *pi_64
= (int64_t)var_GetInteger( p_access
, "mms-caching" ) * INT64_C(1000);
257 case ACCESS_GET_PRIVATE_ID_STATE
:
258 i_int
= (int)va_arg( args
, int );
259 pb_bool
= (bool *)va_arg( args
, bool * );
261 if( (i_int
< 0) || (i_int
> 127) )
263 *pb_bool
= p_sys
->asfh
.stream
[i_int
].i_selected
? true : false;
267 case ACCESS_SET_PAUSE_STATE
:
268 b_bool
= (bool)va_arg( args
, int );
272 Seek( p_access
, p_access
->info
.i_pos
);
275 case ACCESS_GET_TITLE_INFO
:
276 case ACCESS_SET_TITLE
:
277 case ACCESS_SET_SEEKPOINT
:
278 case ACCESS_SET_PRIVATE_ID_STATE
:
279 case ACCESS_GET_CONTENT_TYPE
:
283 msg_Warn( p_access
, "unimplemented query in control" );
290 /*****************************************************************************
291 * Seek: try to go at the right place
292 *****************************************************************************/
293 static int Seek( access_t
*p_access
, uint64_t i_pos
)
295 access_sys_t
*p_sys
= p_access
->p_sys
;
300 msg_Dbg( p_access
, "seeking to %"PRId64
, i_pos
);
302 i_packet
= ( i_pos
- p_sys
->i_header
) / p_sys
->asfh
.i_min_data_packet_size
;
303 i_offset
= ( i_pos
- p_sys
->i_header
) % p_sys
->asfh
.i_min_data_packet_size
;
306 Start( p_access
, i_packet
* p_sys
->asfh
.i_min_data_packet_size
);
308 while( vlc_object_alive (p_access
) )
310 if( GetPacket( p_access
, &ck
) )
314 if( ck
.i_type
!= 0x4824 )
317 msg_Warn( p_access
, "skipping header" );
320 p_access
->info
.i_pos
= i_pos
;
321 p_access
->info
.b_eof
= false;
322 p_sys
->i_packet_used
+= i_offset
;
327 /*****************************************************************************
329 *****************************************************************************/
330 static ssize_t
ReadRedirect( access_t
*p_access
, uint8_t *p
, size_t i_len
)
332 VLC_UNUSED(p_access
); VLC_UNUSED(p
); VLC_UNUSED(i_len
);
336 /*****************************************************************************
338 *****************************************************************************/
339 static block_t
*Block( access_t
*p_access
)
341 access_sys_t
*p_sys
= p_access
->p_sys
;
342 const unsigned i_packet_min
= p_sys
->asfh
.i_min_data_packet_size
;
344 if( p_access
->info
.i_pos
< p_sys
->i_start
+ p_sys
->i_header
)
346 const size_t i_offset
= p_access
->info
.i_pos
- p_sys
->i_start
;
347 const size_t i_copy
= p_sys
->i_header
- i_offset
;
349 block_t
*p_block
= block_New( p_access
, i_copy
);
353 memcpy( p_block
->p_buffer
, &p_sys
->p_header
[i_offset
], i_copy
);
354 p_access
->info
.i_pos
+= i_copy
;
357 else if( p_sys
->i_packet_length
> 0 &&
358 p_sys
->i_packet_used
< __MAX( p_sys
->i_packet_length
, i_packet_min
) )
361 size_t i_padding
= 0;
363 if( p_sys
->i_packet_used
< p_sys
->i_packet_length
)
364 i_copy
= p_sys
->i_packet_length
- p_sys
->i_packet_used
;
365 if( __MAX( p_sys
->i_packet_used
, p_sys
->i_packet_length
) < i_packet_min
)
366 i_padding
= i_packet_min
- __MAX( p_sys
->i_packet_used
, p_sys
->i_packet_length
);
368 block_t
*p_block
= block_New( p_access
, i_copy
+ i_padding
);
373 memcpy( &p_block
->p_buffer
[0], &p_sys
->p_packet
[p_sys
->i_packet_used
], i_copy
);
375 memset( &p_block
->p_buffer
[i_copy
], 0, i_padding
);
377 p_sys
->i_packet_used
+= i_copy
+ i_padding
;
378 p_access
->info
.i_pos
+= i_copy
+ i_padding
;
384 if( GetPacket( p_access
, &ck
) )
387 if( p_sys
->b_broadcast
)
389 if( (ck
.i_type
== 0x4524) && (ck
.i_sequence
!= 0) )
390 i_ret
= Restart( p_access
);
391 else if( ck
.i_type
== 0x4324 )
392 i_ret
= Reset( p_access
);
396 p_access
->info
.b_eof
= true;
400 if( ck
.i_type
!= 0x4424 )
402 p_sys
->i_packet_used
= 0;
403 p_sys
->i_packet_length
= 0;
410 static int Restart( access_t
*p_access
)
412 access_sys_t
*p_sys
= p_access
->p_sys
;
413 char *psz_location
= NULL
;
415 msg_Dbg( p_access
, "Restart the stream" );
416 p_sys
->i_start
= p_access
->info
.i_pos
;
419 msg_Dbg( p_access
, "stoping the stream" );
423 msg_Dbg( p_access
, "describe the stream" );
424 if( Describe( p_access
, &psz_location
) )
426 msg_Err( p_access
, "describe failed" );
429 free( psz_location
);
432 if( Start( p_access
, 0 ) )
434 msg_Err( p_access
, "Start failed" );
439 static int Reset( access_t
*p_access
)
441 access_sys_t
*p_sys
= p_access
->p_sys
;
442 asf_header_t old_asfh
= p_sys
->asfh
;
445 msg_Dbg( p_access
, "Reset the stream" );
446 p_sys
->i_start
= p_access
->info
.i_pos
;
449 p_sys
->i_packet_sequence
= 0;
450 p_sys
->i_packet_used
= 0;
451 p_sys
->i_packet_length
= 0;
452 p_sys
->p_packet
= NULL
;
454 /* Get the next header FIXME memory loss ? */
455 GetHeader( p_access
);
456 if( p_sys
->i_header
<= 0 )
459 asf_HeaderParse ( &p_sys
->asfh
,
460 p_sys
->p_header
, p_sys
->i_header
);
461 msg_Dbg( p_access
, "packet count=%"PRId64
" packet size=%d",
462 p_sys
->asfh
.i_data_packets_count
,
463 p_sys
->asfh
.i_min_data_packet_size
);
465 asf_StreamSelect( &p_sys
->asfh
,
466 var_CreateGetInteger( p_access
, "mms-maxbitrate" ),
467 var_CreateGetBool( p_access
, "mms-all" ),
468 var_CreateGetInteger( p_access
, "audio" ),
469 var_CreateGetInteger( p_access
, "video" ) );
471 /* Check we have comptible asfh */
472 for( i
= 1; i
< 128; i
++ )
474 asf_stream_t
*p_old
= &old_asfh
.stream
[i
];
475 asf_stream_t
*p_new
= &p_sys
->asfh
.stream
[i
];
477 if( p_old
->i_cat
!= p_new
->i_cat
|| p_old
->i_selected
!= p_new
->i_selected
)
482 msg_Warn( p_access
, "incompatible asf header, restart" );
483 return Restart( p_access
);
487 p_sys
->i_packet_used
= 0;
488 p_sys
->i_packet_length
= 0;
492 static int OpenConnection( access_t
*p_access
)
494 access_sys_t
*p_sys
= p_access
->p_sys
;
495 vlc_url_t srv
= p_sys
->b_proxy
? p_sys
->proxy
: p_sys
->url
;
497 if( ( p_sys
->fd
= net_ConnectTCP( p_access
,
498 srv
.psz_host
, srv
.i_port
) ) < 0 )
500 msg_Err( p_access
, "cannot connect to %s:%d",
501 srv
.psz_host
, srv
.i_port
);
507 net_Printf( VLC_OBJECT(p_access
), p_sys
->fd
, NULL
,
508 "GET http://%s:%d%s HTTP/1.0\r\n",
509 p_sys
->url
.psz_host
, p_sys
->url
.i_port
,
510 ( (p_sys
->url
.psz_path
== NULL
) ||
511 (*p_sys
->url
.psz_path
== '\0') ) ?
512 "/" : p_sys
->url
.psz_path
);
514 /* Proxy Authentication */
515 if( p_sys
->proxy
.psz_username
&& *p_sys
->proxy
.psz_username
)
520 if( asprintf( &buf
, "%s:%s", p_sys
->proxy
.psz_username
,
521 p_sys
->proxy
.psz_password
? p_sys
->proxy
.psz_password
: "" ) == -1 )
524 b64
= vlc_b64_encode( buf
);
527 net_Printf( VLC_OBJECT(p_access
), p_sys
->fd
, NULL
,
528 "Proxy-Authorization: Basic %s\r\n", b64
);
534 net_Printf( VLC_OBJECT(p_access
), p_sys
->fd
, NULL
,
535 "GET %s HTTP/1.0\r\n"
537 ( (p_sys
->url
.psz_path
== NULL
) ||
538 (*p_sys
->url
.psz_path
== '\0') ) ?
539 "/" : p_sys
->url
.psz_path
,
540 p_sys
->url
.psz_host
, p_sys
->url
.i_port
);
545 /*****************************************************************************
547 *****************************************************************************/
548 static int Describe( access_t
*p_access
, char **ppsz_location
)
550 access_sys_t
*p_sys
= p_access
->p_sys
;
551 char *psz_location
= NULL
;
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( VLC_OBJECT(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( VLC_OBJECT(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
);
664 /* Handle the redirection */
665 if( ( (i_code
== 301) || (i_code
== 302) ||
666 (i_code
== 303) || (i_code
== 307) ) &&
667 psz_location
&& *psz_location
)
669 msg_Dbg( p_access
, "redirection to %s", psz_location
);
670 net_Close( p_sys
->fd
); p_sys
->fd
= -1;
672 *ppsz_location
= psz_location
;
675 free( psz_location
);
677 /* Read the asf header */
678 GetHeader( p_access
);
679 if( p_sys
->i_header
<= 0 )
681 msg_Err( p_access
, "header size == 0" );
684 /* close this connection */
685 net_Close( p_sys
->fd
);
688 /* *** parse header and get stream and their id *** */
689 /* get all streams properties,
691 * TODO : stream bitrates properties(optional)
692 * and bitrate mutual exclusion(optional) */
693 asf_HeaderParse ( &p_sys
->asfh
,
694 p_sys
->p_header
, p_sys
->i_header
);
695 msg_Dbg( p_access
, "packet count=%"PRId64
" packet size=%d",
696 p_sys
->asfh
.i_data_packets_count
,
697 p_sys
->asfh
.i_min_data_packet_size
);
699 if( p_sys
->asfh
.i_min_data_packet_size
<= 0 )
702 asf_StreamSelect( &p_sys
->asfh
,
703 var_CreateGetInteger( p_access
, "mms-maxbitrate" ),
704 var_CreateGetBool( p_access
, "mms-all" ),
705 var_CreateGetInteger( p_access
, "audio" ),
706 var_CreateGetInteger( p_access
, "video" ) );
712 net_Close( p_sys
->fd
);
718 static void GetHeader( access_t
*p_access
)
720 access_sys_t
*p_sys
= p_access
->p_sys
;
722 /* Read the asf header */
724 free( p_sys
->p_header
);
725 p_sys
->p_header
= NULL
;
729 if( GetPacket( p_access
, &ck
) || ck
.i_type
!= 0x4824 )
734 p_sys
->i_header
+= ck
.i_data
;
735 p_sys
->p_header
= xrealloc( p_sys
->p_header
, p_sys
->i_header
);
736 memcpy( &p_sys
->p_header
[p_sys
->i_header
- ck
.i_data
],
737 ck
.p_data
, ck
.i_data
);
740 msg_Dbg( p_access
, "complete header size=%d", p_sys
->i_header
);
744 /*****************************************************************************
746 ****************************************************************************/
747 static int Start( access_t
*p_access
, uint64_t i_pos
)
749 access_sys_t
*p_sys
= p_access
->p_sys
;
751 int i_streams_selected
= 0;
755 msg_Dbg( p_access
, "starting stream" );
757 for( i
= 1; i
< 128; i
++ )
759 if( p_sys
->asfh
.stream
[i
].i_cat
== ASF_STREAM_UNKNOWN
)
762 if( p_sys
->asfh
.stream
[i
].i_selected
)
763 i_streams_selected
++;
765 if( i_streams_selected
<= 0 )
767 msg_Err( p_access
, "no stream selected" );
771 if( OpenConnection( p_access
) )
774 net_Printf( VLC_OBJECT(p_access
), p_sys
->fd
, NULL
,
776 "User-Agent: "MMSH_USER_AGENT
"\r\n" );
777 if( p_sys
->b_broadcast
)
779 net_Printf( VLC_OBJECT(p_access
), p_sys
->fd
, NULL
,
780 "Pragma: no-cache,rate=1.000000,request-context=%d\r\n",
781 p_sys
->i_request_context
++ );
785 net_Printf( VLC_OBJECT(p_access
), p_sys
->fd
, NULL
,
786 "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=%u:%u,request-context=%d,max-duration=0\r\n",
787 (uint32_t)((i_pos
>> 32)&0xffffffff),
788 (uint32_t)(i_pos
&0xffffffff),
789 p_sys
->i_request_context
++ );
791 net_Printf( VLC_OBJECT(p_access
), p_sys
->fd
, NULL
,
792 "Pragma: xPlayStrm=1\r\n"
793 "Pragma: xClientGUID={"GUID_FMT
"}\r\n"
794 "Pragma: stream-switch-count=%d\r\n"
795 "Pragma: stream-switch-entry=",
796 GUID_PRINT( p_sys
->guid
),
799 for( i
= 1; i
< 128; i
++ )
801 if( p_sys
->asfh
.stream
[i
].i_cat
!= ASF_STREAM_UNKNOWN
)
804 if( p_sys
->asfh
.stream
[i
].i_selected
)
808 net_Printf( VLC_OBJECT(p_access
), p_sys
->fd
, NULL
,
809 "ffff:%d:%d ", i
, i_select
);
812 net_Printf( VLC_OBJECT(p_access
), p_sys
->fd
, NULL
, "\r\n" );
813 net_Printf( VLC_OBJECT(p_access
), p_sys
->fd
, NULL
,
814 "Connection: Close\r\n" );
816 if( net_Printf( VLC_OBJECT(p_access
), p_sys
->fd
, NULL
, "\r\n" ) < 0 )
818 msg_Err( p_access
, "failed to send request" );
822 psz
= net_Gets( p_access
, p_sys
->fd
, NULL
);
825 msg_Err( p_access
, "cannot read data 0" );
829 if( atoi( &psz
[9] ) >= 400 )
831 msg_Err( p_access
, "error: %s", psz
);
835 msg_Dbg( p_access
, "HTTP reply '%s'", psz
);
838 /* FIXME check HTTP code */
841 char *psz
= net_Gets( p_access
, p_sys
->fd
, NULL
);
844 msg_Err( p_access
, "cannot read data 1" );
852 msg_Dbg( p_access
, "%s", psz
);
856 p_sys
->i_packet_used
= 0;
857 p_sys
->i_packet_length
= 0;
862 /*****************************************************************************
864 *****************************************************************************/
865 static void Stop( access_t
*p_access
)
867 access_sys_t
*p_sys
= p_access
->p_sys
;
869 msg_Dbg( p_access
, "closing stream" );
872 net_Close( p_sys
->fd
);
877 /*****************************************************************************
879 *****************************************************************************/
880 static int GetPacket( access_t
* p_access
, chunk_t
*p_ck
)
882 access_sys_t
*p_sys
= p_access
->p_sys
;
886 memset( p_ck
, 0, sizeof( chunk_t
) );
888 /* Read the chunk header */
889 /* Some headers are short, like 0x4324. Reading 12 bytes will cause us
890 * to lose synchronization with the stream. Just read to the length
891 * (4 bytes), decode and then read up to 8 additional bytes to get the
894 if( net_Read( p_access
, p_sys
->fd
, NULL
, p_sys
->buffer
, 4, true ) < 4 )
896 msg_Err( p_access
, "cannot read data 2" );
900 p_ck
->i_type
= GetWLE( p_sys
->buffer
);
901 p_ck
->i_size
= GetWLE( p_sys
->buffer
+ 2);
903 restsize
= p_ck
->i_size
;
907 if( net_Read( p_access
, p_sys
->fd
, NULL
, p_sys
->buffer
+ 4, restsize
, true ) < restsize
)
909 msg_Err( p_access
, "cannot read data 3" );
912 p_ck
->i_sequence
= GetDWLE( p_sys
->buffer
+ 4);
913 p_ck
->i_unknown
= GetWLE( p_sys
->buffer
+ 8);
915 /* Set i_size2 to 8 if this header was short, since a real value won't be
916 * present in the buffer. Using 8 avoid reading additional data for the
922 p_ck
->i_size2
= GetWLE( p_sys
->buffer
+ 10);
924 p_ck
->p_data
= p_sys
->buffer
+ 12;
925 p_ck
->i_data
= p_ck
->i_size2
- 8;
927 if( p_ck
->i_type
== 0x4524 ) // Transfer complete
929 if( p_ck
->i_sequence
== 0 )
931 msg_Warn( p_access
, "EOF" );
936 msg_Warn( p_access
, "next stream following" );
940 else if( p_ck
->i_type
== 0x4324 )
942 /* 0x4324 is CHUNK_TYPE_RESET: a new stream will follow with a sequence of 0 */
943 msg_Warn( p_access
, "next stream following (reset) seq=%d", p_ck
->i_sequence
);
946 else if( (p_ck
->i_type
!= 0x4824) && (p_ck
->i_type
!= 0x4424) )
948 msg_Err( p_access
, "invalid chunk FATAL (0x%x)", p_ck
->i_type
);
952 if( (p_ck
->i_data
> 0) &&
953 (net_Read( p_access
, p_sys
->fd
, NULL
, &p_sys
->buffer
[12],
954 p_ck
->i_data
, true ) < p_ck
->i_data
) )
956 msg_Err( p_access
, "cannot read data 4" );
961 if( (p_sys
->i_packet_sequence
!= 0) &&
962 (p_ck
->i_sequence
!= p_sys
->i_packet_sequence
) )
964 msg_Warn( p_access
, "packet lost ? (%d != %d)", p_ck
->i_sequence
, p_sys
->i_packet_sequence
);
968 p_sys
->i_packet_sequence
= p_ck
->i_sequence
+ 1;
969 p_sys
->i_packet_used
= 0;
970 p_sys
->i_packet_length
= p_ck
->i_data
;
971 p_sys
->p_packet
= p_ck
->p_data
;