- Fix very likely race condition
[vlc.git] / modules / access / mms / mmstu.c
1 /*****************************************************************************
2  * mms.c: MMS access plug-in
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 the VideoLAN team
5  * $Id$
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 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>
29 #include <vlc/vlc.h>
30 #include <string.h>
31 #include <vlc/input.h>
32 #include <errno.h>
33
34 #ifdef HAVE_UNISTD_H
35 #   include <unistd.h>
36 #endif
37 #ifdef HAVE_FCNTL_H
38 #   include <fcntl.h>
39 #endif
40 #ifdef HAVE_SYS_TIME_H
41 #   include <sys/time.h>
42 #endif
43 #ifdef HAVE_SYS_TYPES_H 
44 #   include <sys/types.h>
45 #endif
46 #ifdef HAVE_SYS_STAT_H
47 #   include <sys/stat.h>
48 #endif
49
50 #if defined( UNDER_CE )
51 #   include <winsock.h>
52 #elif WIN32
53 #   include <winsock2.h>
54 #   include <ws2tcpip.h>
55 #   ifndef IN_MULTICAST
56 #       define IN_MULTICAST(a) IN_CLASSD(a)
57 #   endif
58 #else
59 #   include <sys/socket.h>
60 #   include <netinet/in.h>
61 #   if HAVE_ARPA_INET_H
62 #      include <arpa/inet.h>
63 #   elif defined( SYS_BEOS )
64 #      include <net/netdb.h>
65 #   endif
66 #endif
67
68 #include "network.h"
69 #include "asf.h"
70 #include "buffer.h"
71
72 #include "mms.h"
73 #include "mmstu.h"
74
75 #undef MMS_DEBUG
76
77 /****************************************************************************
78  * NOTES:
79  *  MMSProtocole documentation found at http://get.to/sdp
80  ****************************************************************************/
81
82 /*****************************************************************************
83  * Local prototypes
84  *****************************************************************************/
85 int  E_( MMSTUOpen )  ( access_t * );
86 void E_( MMSTUClose ) ( access_t * );
87
88
89 static int Read( access_t *, uint8_t *, int );
90 static int Seek( access_t *, int64_t );
91 static int Control( access_t *, int, va_list );
92
93 static int  MMSOpen ( access_t *, vlc_url_t *, int );
94 static int  MMSStart( access_t *, uint32_t );
95 static int  MMSStop ( access_t * );
96 static void MMSClose( access_t * );
97
98
99 static int  mms_CommandRead( access_t *p_access, int i_command1, int i_command2 );
100 static int  mms_CommandSend( access_t *, int, uint32_t, uint32_t, uint8_t *, int );
101
102 static int  mms_HeaderMediaRead( access_t *, int );
103
104 static int  mms_ReceivePacket( access_t * );
105
106
107 /*
108  * XXX DON'T FREE MY MEMORY !!! XXX
109  * non mais :P
110  */
111 /*
112  * Ok, ok, j'le ferai plus...
113  */
114 /*
115  * Merci :))
116  */
117 /*
118  * Vous pourriez signer vos commentaires (même si on voit bien qui peut
119  * écrire ce genre de trucs :p), et écrire en anglais, bordel de
120  * merde :p.
121  */
122 /*
123  * Alors la ouai ç'est fou les gens qui écrivent des commentaires sans les
124  * signer. Ca mériterait un coup de pied dans le cul ça :)
125  */
126
127 int  E_(MMSTUOpen)( access_t *p_access )
128 {
129     access_sys_t   *p_sys;
130     int             i_proto;
131     int             i_status;
132
133     /* Set up p_access */
134     p_access->pf_read = Read;
135     p_access->pf_block = NULL;
136     p_access->pf_control = Control;
137     p_access->pf_seek = Seek;
138     p_access->info.i_update = 0;
139     p_access->info.i_size = 0;
140     p_access->info.i_pos = 0;
141     p_access->info.b_eof = VLC_FALSE;
142     p_access->info.i_title = 0;
143     p_access->info.i_seekpoint = 0;
144     p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) );
145     memset( p_sys, 0, sizeof( access_sys_t ) );
146
147     /* *** Parse URL and get server addr/port and path *** */
148     vlc_UrlParse( &p_sys->url, p_access->psz_path, 0 );
149     if( p_sys->url.psz_host == NULL || *p_sys->url.psz_host == '\0' )
150     {
151         msg_Err( p_access, "invalid server name" );
152         vlc_UrlClean( &p_sys->url );
153         return VLC_EGENERIC;
154     }
155     if( p_sys->url.i_port <= 0 )
156     {
157         p_sys->url.i_port = 1755;
158     }
159
160     /* *** connect to this server *** */
161     /* look at  requested protocol (udp/tcp) */
162     i_proto = MMS_PROTO_AUTO;
163     if( *p_access->psz_access )
164     {
165         if( !strncmp( p_access->psz_access, "mmsu", 4 ) )
166         {
167             i_proto = MMS_PROTO_UDP;
168         }
169         else if( !strncmp( p_access->psz_access, "mmst", 4 ) )
170         {
171             i_proto = MMS_PROTO_TCP;
172         }
173     }
174
175     /* connect */
176     if( i_proto == MMS_PROTO_AUTO )
177     {   /* first try with TCP and then UDP*/
178         if( ( i_status = MMSOpen( p_access, &p_sys->url, MMS_PROTO_TCP ) ) )
179         {
180             i_status = MMSOpen( p_access, &p_sys->url, MMS_PROTO_UDP );
181         }
182     }
183     else
184     {
185         i_status = MMSOpen( p_access, &p_sys->url, i_proto );
186     }
187
188     if( i_status )
189     {
190         msg_Err( p_access, "cannot connect to server" );
191         vlc_UrlClean( &p_sys->url );
192         return VLC_EGENERIC;
193     }
194
195     msg_Dbg( p_access, "connected to %s:%d", p_sys->url.psz_host, p_sys->url.i_port );
196     /*
197      * i_flags_broadcast
198      *  yy xx ?? ??
199      *  broadcast    yy=0x02, xx= 0x00
200      *  pre-recorded yy=0x01, xx= 0x80 if video, 0x00 no video
201      */
202     if( p_sys->i_packet_count <= 0 && p_sys->asfh.i_data_packets_count > 0 )
203     {
204         p_sys->i_packet_count = p_sys->asfh.i_data_packets_count;
205     }
206     if( p_sys->i_packet_count <= 0 || ( p_sys->i_flags_broadcast >> 24 ) == 0x02 )
207     {
208         p_sys->b_seekable = VLC_FALSE;
209     }
210     else
211     {
212         p_sys->b_seekable = VLC_TRUE;
213         p_access->info.i_size =
214             (uint64_t)p_sys->i_header +
215             (uint64_t)p_sys->i_packet_count * (uint64_t)p_sys->i_packet_length;
216     }
217
218     /* *** Start stream *** */
219     if( MMSStart( p_access, 0xffffffff ) < 0 )
220     {
221         msg_Err( p_access, "cannot start stream" );
222         MMSClose( p_access );
223         vlc_UrlClean( &p_sys->url );
224         return VLC_EGENERIC;
225     }
226     return VLC_SUCCESS;
227 }
228
229 /*****************************************************************************
230  * Close: free unused data structures
231  *****************************************************************************/
232 void E_(MMSTUClose)( access_t *p_access )
233 {
234     access_sys_t *p_sys = p_access->p_sys;
235
236     /* close connection with server */
237     MMSClose( p_access );
238
239     /* free memory */
240     vlc_UrlClean( &p_sys->url );
241
242     free( p_sys );
243 }
244
245 /*****************************************************************************
246  * Control:
247  *****************************************************************************/
248 static int Control( access_t *p_access, int i_query, va_list args )
249 {
250     access_sys_t *p_sys = p_access->p_sys;
251     vlc_bool_t   *pb_bool;
252     int          *pi_int;
253     int64_t      *pi_64;
254     int           i_int;
255     vlc_value_t  val;
256
257     switch( i_query )
258     {
259         /* */
260         case ACCESS_CAN_SEEK:
261             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
262             *pb_bool = p_sys->b_seekable;
263             break;
264
265         case ACCESS_CAN_FASTSEEK:
266         case ACCESS_CAN_PAUSE:
267             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
268             *pb_bool = VLC_FALSE;
269             break;
270
271         case ACCESS_CAN_CONTROL_PACE:
272             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
273
274 #if 0       /* Disable for now until we have a clock synchro algo
275              * which works with something else than MPEG over UDP */
276             *pb_bool = VLC_FALSE;
277 #endif
278             *pb_bool = VLC_TRUE;
279             break;
280
281         /* */
282         case ACCESS_GET_MTU:
283             pi_int = (int*)va_arg( args, int * );
284             *pi_int = 3 * p_sys->i_packet_length;
285             break;
286
287         case ACCESS_GET_PTS_DELAY:
288             pi_64 = (int64_t*)va_arg( args, int64_t * );
289             var_Get( p_access, "mms-caching", &val );
290             *pi_64 = (int64_t)var_GetInteger( p_access, "mms-caching" ) * I64C(1000);
291             break;
292
293         case ACCESS_GET_PRIVATE_ID_STATE:
294             i_int = (int)va_arg( args, int );
295             pb_bool = (vlc_bool_t *)va_arg( args, vlc_bool_t * );
296
297             if( i_int < 0 || i_int > 127 )
298                 return VLC_EGENERIC;
299             *pb_bool =  p_sys->asfh.stream[i_int].i_selected ? VLC_TRUE : VLC_FALSE;
300             break;
301
302         /* */
303         case ACCESS_SET_PAUSE_STATE:
304         case ACCESS_GET_TITLE_INFO:
305         case ACCESS_SET_TITLE:
306         case ACCESS_SET_SEEKPOINT:
307         case ACCESS_SET_PRIVATE_ID_STATE:
308             return VLC_EGENERIC;
309
310
311         default:
312             msg_Warn( p_access, "unimplemented query in control" );
313             return VLC_EGENERIC;
314
315     }
316     return VLC_SUCCESS;
317 }
318
319 /*****************************************************************************
320  * Seek: try to go at the right place
321  *****************************************************************************/
322 static int Seek( access_t * p_access, int64_t i_pos )
323 {
324     access_sys_t *p_sys = p_access->p_sys;
325     uint32_t    i_packet;
326     uint32_t    i_offset;
327     var_buffer_t buffer;
328
329     if( i_pos < 0 )
330         return VLC_EGENERIC;
331
332     if( i_pos < p_sys->i_header)
333     {
334
335         if( p_access->info.i_pos < p_sys->i_header )
336         {
337             /* no need to restart stream, it was already one
338              * or no stream was yet read */
339             p_access->info.i_pos = i_pos;
340             return VLC_SUCCESS;
341         }
342         else
343         {
344             i_packet = 0xffffffff;
345             i_offset = 0;
346         }
347     }
348     else
349     {
350         i_packet = ( i_pos - p_sys->i_header ) / p_sys->i_packet_length;
351         i_offset = ( i_pos - p_sys->i_header ) % p_sys->i_packet_length;
352     }
353     msg_Dbg( p_access, "seeking to "I64Fd " (packet:%d)", i_pos, i_packet );
354
355     MMSStop( p_access );
356     msg_Dbg( p_access, "stream stopped (seek)" );
357
358     /* *** restart stream *** */
359     var_buffer_initwrite( &buffer, 0 );
360     var_buffer_add64( &buffer, 0 ); /* seek point in second */
361     var_buffer_add32( &buffer, 0xffffffff );
362     var_buffer_add32( &buffer, i_packet ); // begin from start
363     var_buffer_add8( &buffer, 0xff ); // stream time limit
364     var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
365     var_buffer_add8( &buffer, 0xff ); //
366     var_buffer_add8( &buffer, 0x00 ); // don't use limit
367     var_buffer_add32( &buffer, p_sys->i_media_packet_id_type );
368
369     mms_CommandSend( p_access, 0x07, p_sys->i_command_level, 0x0001ffff,
370                      buffer.p_data, buffer.i_data );
371
372     var_buffer_free( &buffer );
373
374
375     while( !p_access->b_die )
376     {
377         mms_HeaderMediaRead( p_access, MMS_PACKET_CMD );
378         if( p_sys->i_command == 0x1e )
379         {
380             msg_Dbg( p_access, "received 0x1e (seek)" );
381             break;
382         }
383     }
384
385     while( !p_access->b_die )
386     {
387         mms_HeaderMediaRead( p_access, MMS_PACKET_CMD );
388         if( p_sys->i_command == 0x05 )
389         {
390             msg_Dbg( p_access, "received 0x05 (seek)" );
391             break;
392         }
393     }
394
395     /* get a packet */
396     mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA );
397     msg_Dbg( p_access, "Streaming restarted" );
398
399     p_sys->i_media_used += i_offset;
400     p_access->info.i_pos = i_pos;
401     p_access->info.b_eof = VLC_FALSE;
402
403     return VLC_SUCCESS;
404 }
405
406 /*****************************************************************************
407  * Read:
408  *****************************************************************************/
409 static int Read( access_t *p_access, uint8_t *p_buffer, int i_len )
410 {
411     access_sys_t *p_sys = p_access->p_sys;
412     size_t      i_data;
413     size_t      i_copy;
414
415     i_data = 0;
416
417     /* *** now send data if needed *** */
418     while( i_data < (size_t)i_len )
419     {
420         if( p_access->info.i_pos < p_sys->i_header )
421         {
422             i_copy = __MIN( i_len, p_sys->i_header - p_access->info.i_pos );
423             memcpy( &p_buffer[i_data], &p_sys->p_header[p_access->info.i_pos], i_copy );
424             i_data += i_copy;
425             p_access->info.i_pos += i_copy;
426         }
427         else if( p_sys->i_media_used < p_sys->i_media )
428         {
429             i_copy = __MIN( i_len - i_data ,
430                             p_sys->i_media - p_sys->i_media_used );
431             memcpy( &p_buffer[i_data], &p_sys->p_media[p_sys->i_media_used], i_copy );
432             i_data += i_copy;
433             p_sys->i_media_used += i_copy;
434             p_access->info.i_pos += i_copy;
435         }
436         else if( p_sys->p_media != NULL &&
437                  p_sys->i_media_used < p_sys->i_packet_length )
438         {
439             i_copy = __MIN( i_len - i_data,
440                             p_sys->i_packet_length - p_sys->i_media_used);
441             memset( &p_buffer[i_data], 0, i_copy );
442
443             i_data += i_copy;
444             p_sys->i_media_used += i_copy;
445             p_access->info.i_pos += i_copy;
446         }
447         else if( p_access->info.b_eof ||
448                  mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA ) < 0 )
449         {
450             break;
451         }
452     }
453
454     return i_data;
455 }
456
457 /****************************************************************************
458  * MMSOpen : Open a connection with the server over mmst or mmsu
459  ****************************************************************************/
460 static int MMSOpen( access_t  *p_access, vlc_url_t *p_url, int  i_proto )
461 {
462     access_sys_t *p_sys = p_access->p_sys;
463     int           b_udp = ( i_proto == MMS_PROTO_UDP ) ? 1 : 0;
464
465     var_buffer_t buffer;
466     char         tmp[4096];
467     uint16_t     *p;
468     int          i_server_version;
469     int          i_tool_version;
470     int          i_update_player_url;
471     int          i_encryption_type;
472     int          i;
473     int          i_streams;
474     int          i_first;
475
476
477     /* *** Open a TCP connection with server *** */
478     msg_Dbg( p_access, "waiting for connection..." );
479     p_sys->i_handle_tcp = net_OpenTCP( p_access, p_url->psz_host, p_url->i_port );
480     if( p_sys->i_handle_tcp < 0 )
481     {
482         msg_Err( p_access, "failed to open a connection (tcp)" );
483         return VLC_EGENERIC;
484     }
485     msg_Dbg( p_access,
486              "connection(tcp) with \"%s:%d\" successful",
487              p_url->psz_host,
488              p_url->i_port );
489
490     /* *** Bind port if UDP protocol is selected *** */
491     if( b_udp )
492     {
493         if( net_GetSockAddress( p_access, p_sys->i_handle_tcp,
494                                 p_sys->sz_bind_addr, NULL ) )
495         {
496             net_Close( p_sys->i_handle_tcp );
497             return VLC_EGENERIC;
498         }
499
500         p_sys->i_handle_udp = net_OpenUDP( p_access, p_sys->sz_bind_addr,
501                                            7000, "", 0 );
502         if( p_sys->i_handle_udp < 0 )
503         {
504             msg_Err( p_access, "failed to open a connection (udp)" );
505             net_Close( p_sys->i_handle_tcp );
506             return VLC_EGENERIC;
507         }
508         msg_Dbg( p_access,
509                  "connection(udp) at \"%s:%d\" successful",
510                  p_sys->sz_bind_addr, 7000 );
511     }
512
513     /* *** Init context for mms prototcol *** */
514     E_( GenerateGuid )( &p_sys->guid );    /* used to identify client by server */
515     msg_Dbg( p_access,
516              "generated guid: "GUID_FMT,
517              GUID_PRINT( p_sys->guid ) );
518     p_sys->i_command_level = 1;          /* updated after 0x1A command */
519     p_sys->i_seq_num = 0;
520     p_sys->i_media_packet_id_type  = 0x04;
521     p_sys->i_header_packet_id_type = 0x02;
522     p_sys->i_proto = i_proto;
523     p_sys->i_packet_seq_num = 0;
524     p_sys->p_header = NULL;
525     p_sys->i_header = 0;
526     p_sys->p_media = NULL;
527     p_sys->i_media = 0;
528     p_sys->i_media_used = 0;
529
530     p_access->info.i_pos = 0;
531     p_sys->i_buffer_tcp = 0;
532     p_sys->i_buffer_udp = 0;
533     p_sys->p_cmd = NULL;
534     p_sys->i_cmd = 0;
535     p_access->info.b_eof = 0;
536
537     /* *** send command 1 : connection request *** */
538     var_buffer_initwrite( &buffer, 0 );
539     var_buffer_add16( &buffer, 0x001c );
540     var_buffer_add16( &buffer, 0x0003 );
541     sprintf( tmp,
542              "NSPlayer/7.0.0.1956; {"GUID_FMT"}; Host: %s",
543              GUID_PRINT( p_sys->guid ),
544              p_url->psz_host );
545     var_buffer_addUTF16( &buffer, tmp );
546
547     mms_CommandSend( p_access,
548                      0x01,          /* connexion request */
549                      0x00000000,    /* flags, FIXME */
550                      0x0004000b,    /* ???? */
551                      buffer.p_data,
552                      buffer.i_data );
553
554     if( mms_CommandRead( p_access, 0x01, 0 ) < 0 )
555     {
556         var_buffer_free( &buffer );
557         MMSClose( p_access );
558         return VLC_EGENERIC;
559     }
560
561     i_server_version = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 32 );
562     i_tool_version = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 36 );
563     i_update_player_url = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 40 );
564     i_encryption_type = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 44 );
565     p = (uint16_t*)( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 48 );
566 #define GETUTF16( psz, size ) \
567     { \
568         int i; \
569         psz = malloc( size + 1); \
570         for( i = 0; i < size; i++ ) \
571         { \
572             psz[i] = p[i]; \
573         } \
574         psz[size] = '\0'; \
575         p += ( size ); \
576     }
577     GETUTF16( p_sys->psz_server_version, i_server_version );
578     GETUTF16( p_sys->psz_tool_version, i_tool_version );
579     GETUTF16( p_sys->psz_update_player_url, i_update_player_url );
580     GETUTF16( p_sys->psz_encryption_type, i_encryption_type );
581 #undef GETUTF16
582     msg_Dbg( p_access,
583              "0x01 --> server_version:\"%s\" tool_version:\"%s\" update_player_url:\"%s\" encryption_type:\"%s\"",
584              p_sys->psz_server_version,
585              p_sys->psz_tool_version,
586              p_sys->psz_update_player_url,
587              p_sys->psz_encryption_type );
588
589     /* *** should make an 18 command to make data timing *** */
590
591     /* *** send command 2 : transport protocol selection *** */
592     var_buffer_reinitwrite( &buffer, 0 );
593     var_buffer_add32( &buffer, 0x00000000 );
594     var_buffer_add32( &buffer, 0x000a0000 );
595     var_buffer_add32( &buffer, 0x00000002 );
596     if( b_udp )
597     {
598         sprintf( tmp,
599                  "\\\\%s\\UDP\\%d",
600                  p_sys->sz_bind_addr,
601                  7000 ); // FIXME
602     }
603     else
604     {
605         sprintf( tmp, "\\\\192.168.0.1\\TCP\\1242"  );
606     }
607     var_buffer_addUTF16( &buffer, tmp );
608     var_buffer_add16( &buffer, '0' );
609
610     mms_CommandSend( p_access,
611                      0x02,          /* connexion request */
612                      0x00000000,    /* flags, FIXME */
613                      0xffffffff,    /* ???? */
614                      buffer.p_data,
615                      buffer.i_data );
616
617     /* *** response from server, should be 0x02 or 0x03 *** */
618     mms_CommandRead( p_access, 0x02, 0x03 );
619     if( p_sys->i_command == 0x03 )
620     {
621         msg_Err( p_access,
622                  "%s protocol selection failed", b_udp ? "UDP" : "TCP" );
623         var_buffer_free( &buffer );
624         MMSClose( p_access );
625         return VLC_EGENERIC;
626     }
627     else if( p_sys->i_command != 0x02 )
628     {
629         msg_Warn( p_access, "received command isn't 0x02 in reponse to 0x02" );
630     }
631
632     /* *** send command 5 : media file name/path requested *** */
633     var_buffer_reinitwrite( &buffer, 0 );
634     var_buffer_add64( &buffer, 0 );
635     var_buffer_addUTF16( &buffer, p_url->psz_path );
636
637     mms_CommandSend( p_access,
638                      0x05,
639                      p_sys->i_command_level,
640                      0xffffffff,
641                      buffer.p_data,
642                      buffer.i_data );
643
644     /* *** wait for reponse *** */
645     mms_CommandRead( p_access, 0x1a, 0x06 );
646
647     /* test if server send 0x1A answer */
648     if( p_sys->i_command == 0x1A )
649     {
650         msg_Err( p_access, "id/password requested (not yet supported)" );
651         /*  FIXME */
652         var_buffer_free( &buffer );
653         MMSClose( p_access );
654         return VLC_EGENERIC;
655     }
656     if( p_sys->i_command != 0x06 )
657     {
658         msg_Err( p_access,
659                  "unknown answer (0x%x instead of 0x06)",
660                  p_sys->i_command );
661         var_buffer_free( &buffer );
662         MMSClose( p_access );
663         return( -1 );
664     }
665
666     /*  1 for file ok, 2 for authen ok */
667     switch( GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE ) )
668     {
669         case 0x0001:
670             msg_Dbg( p_access, "Media file name/path accepted" );
671             break;
672         case 0x0002:
673             msg_Dbg( p_access, "Authentication accepted" );
674             break;
675         case -1:
676         default:
677         msg_Err( p_access, "error while asking for file %d",
678                  GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE ) );
679         var_buffer_free( &buffer );
680         MMSClose( p_access );
681         return VLC_EGENERIC;
682     }
683
684     p_sys->i_flags_broadcast =
685         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 12 );
686     p_sys->i_media_length =
687         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 24 );
688     p_sys->i_packet_length =
689         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 44 );
690     p_sys->i_packet_count =
691         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 48 );
692     p_sys->i_max_bit_rate =
693         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 56 );
694     p_sys->i_header_size =
695         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 60 );
696
697     msg_Dbg( p_access,
698              "answer 0x06 flags:0x%8.8x media_length:%ds packet_length:%d packet_count:%d max_bit_rate:%d header_size:%d",
699              p_sys->i_flags_broadcast,
700              p_sys->i_media_length,
701              p_sys->i_packet_length,
702              p_sys->i_packet_count,
703              p_sys->i_max_bit_rate,
704              p_sys->i_header_size );
705
706     /* *** send command 15 *** */
707
708     var_buffer_reinitwrite( &buffer, 0 );
709     var_buffer_add32( &buffer, 0 );
710     var_buffer_add32( &buffer, 0x8000 );
711     var_buffer_add32( &buffer, 0xffffffff );
712     var_buffer_add32( &buffer, 0x00 );
713     var_buffer_add32( &buffer, 0x00 );
714     var_buffer_add32( &buffer, 0x00 );
715     var_buffer_add64( &buffer, (((uint64_t)0x40ac2000)<<32) );
716     var_buffer_add32( &buffer, p_sys->i_header_packet_id_type );
717     var_buffer_add32( &buffer, 0x00 );
718     mms_CommandSend( p_access, 0x15, p_sys->i_command_level, 0x00,
719                      buffer.p_data, buffer.i_data );
720
721     /* *** wait for reponse *** */
722     /* Commented out because it fails on some stream (no 0x11 answer) */
723 #if 0
724     mms_CommandRead( p_access, 0x11, 0 );
725
726     if( p_sys->i_command != 0x11 )
727     {
728         msg_Err( p_access,
729                  "unknown answer (0x%x instead of 0x11)",
730                  p_sys->i_command );
731         var_buffer_free( &buffer );
732         MMSClose( p_access );
733         return( -1 );
734     }
735 #endif
736
737     /* *** now read header packet *** */
738     /* XXX could be split over multiples packets */
739     msg_Dbg( p_access, "reading header" );
740     for( ;; )
741     {
742         if( mms_HeaderMediaRead( p_access, MMS_PACKET_HEADER ) < 0 )
743         {
744             msg_Err( p_access, "cannot receive header" );
745             var_buffer_free( &buffer );
746             MMSClose( p_access );
747             return VLC_EGENERIC;
748         }
749         if( p_sys->i_header >= p_sys->i_header_size )
750         {
751             msg_Dbg( p_access,
752                      "header complete(%d)",
753                      p_sys->i_header );
754             break;
755         }
756         msg_Dbg( p_access,
757                  "header incomplete (%d/%d), reading more",
758                  p_sys->i_header,
759                  p_sys->i_header_size );
760     }
761
762     /* *** parse header and get stream and their id *** */
763     /* get all streams properties,
764      *
765      * TODO : stream bitrates properties(optional)
766      *        and bitrate mutual exclusion(optional) */
767     E_( asf_HeaderParse )( &p_sys->asfh,
768                            p_sys->p_header, p_sys->i_header );
769     E_( asf_StreamSelect)( &p_sys->asfh,
770                            var_CreateGetInteger( p_access, "mms-maxbitrate" ),
771                            var_CreateGetInteger( p_access, "mms-all" ),
772                            var_CreateGetInteger( p_access, "audio" ),
773                            var_CreateGetInteger( p_access, "video" ) );
774
775     /* *** now select stream we want to receive *** */
776     /* TODO take care of stream bitrate TODO */
777     i_streams = 0;
778     i_first = -1;
779     var_buffer_reinitwrite( &buffer, 0 );
780     /* for now, select first audio and video stream */
781     for( i = 1; i < 128; i++ )
782     {
783
784         if( p_sys->asfh.stream[i].i_cat != ASF_STREAM_UNKNOWN )
785         {
786             i_streams++;
787             if( i_first != -1 )
788             {
789                 var_buffer_add16( &buffer, 0xffff );
790                 var_buffer_add16( &buffer, i );
791             }
792             else
793             {
794                 i_first = i;
795             }
796             if( p_sys->asfh.stream[i].i_selected )
797             {
798                 var_buffer_add16( &buffer, 0x0000 );
799                 msg_Info( p_access,
800                           "selecting stream[0x%x] %s (%d kb/s)",
801                           i,
802                           ( p_sys->asfh.stream[i].i_cat == ASF_STREAM_AUDIO  ) ?
803                                                   "audio" : "video" ,
804                           p_sys->asfh.stream[i].i_bitrate / 1024);
805             }
806             else
807             {
808                 var_buffer_add16( &buffer, 0x0002 );
809                 msg_Info( p_access,
810                           "ignoring stream[0x%x] %s (%d kb/s)",
811                           i,
812                           ( p_sys->asfh.stream[i].i_cat == ASF_STREAM_AUDIO  ) ?
813                                     "audio" : "video" ,
814                           p_sys->asfh.stream[i].i_bitrate / 1024);
815
816             }
817         }
818     }
819
820     if( i_streams == 0 )
821     {
822         msg_Err( p_access, "cannot find any stream" );
823         var_buffer_free( &buffer );
824         MMSClose( p_access );
825         return VLC_EGENERIC;
826     }
827     mms_CommandSend( p_access, 0x33,
828                      i_streams,
829                      0xffff | ( i_first << 16 ),
830                      buffer.p_data, buffer.i_data );
831
832     mms_CommandRead( p_access, 0x21, 0 );
833     if( p_sys->i_command != 0x21 )
834     {
835         msg_Err( p_access,
836                  "unknown answer (0x%x instead of 0x21)",
837                  p_sys->i_command );
838         var_buffer_free( &buffer );
839         MMSClose( p_access );
840         return VLC_EGENERIC;
841     }
842
843
844     var_buffer_free( &buffer );
845
846     msg_Info( p_access, "connection successful" );
847
848     return VLC_SUCCESS;
849 }
850
851 /****************************************************************************
852  * MMSStart : Start streaming
853  ****************************************************************************/
854 static int MMSStart( access_t  *p_access, uint32_t i_packet )
855 {
856     access_sys_t        *p_sys = p_access->p_sys;
857     var_buffer_t    buffer;
858
859     /* *** start stream from packet 0 *** */
860     var_buffer_initwrite( &buffer, 0 );
861     var_buffer_add64( &buffer, 0 ); /* seek point in second */
862     var_buffer_add32( &buffer, 0xffffffff );
863     var_buffer_add32( &buffer, i_packet ); // begin from start
864     var_buffer_add8( &buffer, 0xff ); // stream time limit
865     var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
866     var_buffer_add8( &buffer, 0xff ); //
867     var_buffer_add8( &buffer, 0x00 ); // don't use limit
868     var_buffer_add32( &buffer, p_sys->i_media_packet_id_type );
869
870     mms_CommandSend( p_access, 0x07, p_sys->i_command_level, 0x0001ffff,
871                      buffer.p_data, buffer.i_data );
872
873     var_buffer_free( &buffer );
874
875     mms_CommandRead( p_access, 0x05, 0 );
876
877     if( p_sys->i_command != 0x05 )
878     {
879         msg_Err( p_access,
880                  "unknown answer (0x%x instead of 0x05)",
881                  p_sys->i_command );
882         return( -1 );
883     }
884     else
885     {
886         /* get a packet */
887         mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA );
888         msg_Dbg( p_access, "Streaming started" );
889         return( 0 );
890     }
891 }
892
893 /****************************************************************************
894  * MMSStop : Stop streaming
895  ****************************************************************************/
896 static int MMSStop( access_t  *p_access )
897 {
898     access_sys_t *p_sys = p_access->p_sys;
899
900     /* *** stop stream but keep connection alive *** */
901     mms_CommandSend( p_access,
902                      0x09,
903                      p_sys->i_command_level,
904                      0x001fffff,
905                      NULL, 0 );
906     return( 0 );
907 }
908
909 /****************************************************************************
910  * MMSClose : Close streaming and connection
911  ****************************************************************************/
912 static void MMSClose( access_t  *p_access )
913 {
914     access_sys_t        *p_sys = p_access->p_sys;
915
916     msg_Dbg( p_access, "Connection closed" );
917
918     /* *** tell server that we will disconnect *** */
919     mms_CommandSend( p_access,
920                      0x0d,
921                      p_sys->i_command_level,
922                      0x00000001,
923                      NULL, 0 );
924
925     /* *** close sockets *** */
926     net_Close( p_sys->i_handle_tcp );
927     if( p_sys->i_proto == MMS_PROTO_UDP )
928     {
929         net_Close( p_sys->i_handle_udp );
930     }
931
932     FREE( p_sys->p_cmd );
933     FREE( p_sys->p_media );
934     FREE( p_sys->p_header );
935
936     FREE( p_sys->psz_server_version );
937     FREE( p_sys->psz_tool_version );
938     FREE( p_sys->psz_update_player_url );
939     FREE( p_sys->psz_encryption_type );
940 }
941
942 /****************************************************************************
943  *
944  * MMS specific functions
945  *
946  ****************************************************************************/
947 static int mms_CommandSend( access_t *p_access,
948                              int i_command,
949                              uint32_t i_prefix1, uint32_t i_prefix2,
950                              uint8_t *p_data, int i_data )
951 {
952     var_buffer_t buffer;
953
954     access_sys_t        *p_sys = p_access->p_sys;
955     int i_data_by8;
956
957     i_data_by8 = ( i_data + 7 ) / 8;
958
959     /* first init uffer */
960     var_buffer_initwrite( &buffer, 0 );
961
962     var_buffer_add32( &buffer, 0x00000001 );    /* start sequence */
963     var_buffer_add32( &buffer, 0xB00BFACE );
964     /* size after protocol type */
965     var_buffer_add32( &buffer, i_data + MMS_CMD_HEADERSIZE - 16 );
966     var_buffer_add32( &buffer, 0x20534d4d );    /* protocol "MMS " */
967     var_buffer_add32( &buffer, i_data_by8 + 4 );
968     var_buffer_add32( &buffer, p_sys->i_seq_num ); p_sys->i_seq_num++;
969     var_buffer_add64( &buffer, 0 );
970     var_buffer_add32( &buffer, i_data_by8 + 2 );
971     var_buffer_add32( &buffer, 0x00030000 | i_command ); /* dir | command */
972     var_buffer_add32( &buffer, i_prefix1 );    /* command specific */
973     var_buffer_add32( &buffer, i_prefix2 );    /* command specific */
974
975     /* specific command data */
976     if( p_data && i_data > 0 )
977     {
978         var_buffer_addmemory( &buffer, p_data, i_data );
979     }
980
981     /* send it */
982     if( send( p_sys->i_handle_tcp,
983               buffer.p_data,
984               buffer.i_data,
985               0 ) == -1 )
986     {
987         msg_Err( p_access, "failed to send command" );
988         return VLC_EGENERIC;
989     }
990
991     var_buffer_free( &buffer );
992     return VLC_SUCCESS;
993 }
994
995 static int NetFillBuffer( access_t *p_access )
996 {
997 #ifdef UNDER_CE
998     return -1;
999
1000 #else
1001     access_sys_t    *p_sys = p_access->p_sys;
1002     struct timeval  timeout;
1003     fd_set          fds_r, fds_e;
1004     int             i_ret;
1005
1006     /* FIXME when using udp */
1007     ssize_t i_tcp, i_udp;
1008     ssize_t i_tcp_read, i_udp_read;
1009     int i_handle_max;
1010     int i_try = 0;
1011
1012     i_tcp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_tcp;
1013
1014     if( p_sys->i_proto == MMS_PROTO_UDP )
1015     {
1016         i_udp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_udp;
1017     }
1018     else
1019     {
1020         i_udp = 0;  /* there isn't udp socket */
1021     }
1022
1023     i_handle_max = 0;
1024
1025     if( i_tcp > 0 )
1026         i_handle_max = __MAX( i_handle_max, p_sys->i_handle_tcp );
1027     if( i_udp > 0 )
1028         i_handle_max = __MAX( i_handle_max, p_sys->i_handle_udp );
1029
1030     if( i_handle_max == 0 )
1031     {
1032         msg_Warn( p_access, "nothing to read %d:%d", i_tcp, i_udp );
1033         return 0;
1034     }
1035     else
1036     {
1037         /* msg_Warn( p_access, "ask for tcp:%d udp:%d", i_tcp, i_udp ); */
1038     }
1039
1040     /* Find if some data is available */
1041     do
1042     {
1043         i_try++;
1044
1045         /* Initialize file descriptor set */
1046         FD_ZERO( &fds_r );
1047         FD_ZERO( &fds_e );
1048
1049         if( i_tcp > 0 )
1050         {
1051             FD_SET( p_sys->i_handle_tcp, &fds_r );
1052             FD_SET( p_sys->i_handle_tcp, &fds_e );
1053         }
1054         if( i_udp > 0 )
1055         {
1056             FD_SET( p_sys->i_handle_udp, &fds_r );
1057             FD_SET( p_sys->i_handle_udp, &fds_e );
1058         }
1059
1060         /* We'll wait 0.5 second if nothing happens */
1061         timeout.tv_sec = 0;
1062         timeout.tv_usec = 500000;
1063
1064         if( i_try > 3 && (p_sys->i_buffer_tcp > 0 || p_sys->i_buffer_udp > 0) )
1065         {
1066             return -1;
1067         }
1068
1069         if( p_access->b_die || p_access->b_error ) return -1;
1070
1071         //msg_Dbg( p_access, "NetFillBuffer: trying again (select)" );
1072
1073     } while( !(i_ret = select(i_handle_max +1, &fds_r, 0, &fds_e, &timeout)) ||
1074              (i_ret < 0 && errno == EINTR) );
1075
1076     if( i_ret < 0 )
1077     {
1078         msg_Err( p_access, "network select error (%s)", strerror(errno) );
1079         return -1;
1080     }
1081
1082     i_tcp_read = i_udp_read = 0;
1083
1084     if( i_tcp > 0 && FD_ISSET( p_sys->i_handle_tcp, &fds_r ) )
1085     {
1086         i_tcp_read =
1087             recv( p_sys->i_handle_tcp,
1088                   p_sys->buffer_tcp + p_sys->i_buffer_tcp,
1089                   i_tcp + MMS_BUFFER_SIZE/2, 0 );
1090     }
1091
1092     if( i_udp > 0 && FD_ISSET( p_sys->i_handle_udp, &fds_r ) )
1093     {
1094         i_udp_read = recv( p_sys->i_handle_udp,
1095                            p_sys->buffer_udp + p_sys->i_buffer_udp,
1096                            i_udp + MMS_BUFFER_SIZE/2, 0 );
1097     }
1098
1099 #if MMS_DEBUG
1100     if( p_sys->i_proto == MMS_PROTO_UDP )
1101     {
1102         msg_Dbg( p_access, "filling buffer TCP:%d+%d UDP:%d+%d",
1103                  p_sys->i_buffer_tcp, i_tcp_read,
1104                  p_sys->i_buffer_udp, i_udp_read );
1105     }
1106     else
1107     {
1108         msg_Dbg( p_access, "filling buffer TCP:%d+%d",
1109                  p_sys->i_buffer_tcp, i_tcp_read );
1110     }
1111 #endif
1112
1113     if( i_tcp_read > 0 ) p_sys->i_buffer_tcp += i_tcp_read;
1114     if( i_udp_read > 0 ) p_sys->i_buffer_udp += i_udp_read;
1115
1116     return i_tcp_read + i_udp_read;
1117 #endif
1118 }
1119
1120 static int  mms_ParseCommand( access_t *p_access,
1121                               uint8_t *p_data,
1122                               int i_data,
1123                               int *pi_used )
1124 {
1125  #define GET32( i_pos ) \
1126     ( p_sys->p_cmd[i_pos] + ( p_sys->p_cmd[i_pos +1] << 8 ) + \
1127       ( p_sys->p_cmd[i_pos + 2] << 16 ) + \
1128       ( p_sys->p_cmd[i_pos + 3] << 24 ) )
1129
1130     access_sys_t        *p_sys = p_access->p_sys;
1131     int         i_length;
1132     uint32_t    i_id;
1133
1134     if( p_sys->p_cmd )
1135     {
1136         free( p_sys->p_cmd );
1137     }
1138     p_sys->i_cmd = i_data;
1139     p_sys->p_cmd = malloc( i_data );
1140     memcpy( p_sys->p_cmd, p_data, i_data );
1141
1142     *pi_used = i_data; /* by default */
1143
1144     if( i_data < MMS_CMD_HEADERSIZE )
1145     {
1146         msg_Warn( p_access, "truncated command (header incomplete)" );
1147         p_sys->i_command = 0;
1148         return -1;
1149     }
1150     i_id =  GetDWLE( p_data + 4 );
1151     i_length = GetDWLE( p_data + 8 ) + 16;
1152
1153     if( i_id != 0xb00bface )
1154     {
1155         msg_Err( p_access,
1156                  "incorrect command header (0x%x)", i_id );
1157         p_sys->i_command = 0;
1158         return -1;
1159     }
1160
1161     if( i_length > p_sys->i_cmd )
1162     {
1163         msg_Warn( p_access,
1164                   "truncated command (missing %d bytes)",
1165                    i_length - i_data  );
1166         p_sys->i_command = 0;
1167         return -1;
1168     }
1169     else if( i_length < p_sys->i_cmd )
1170     {
1171         p_sys->i_cmd = i_length;
1172         *pi_used = i_length;
1173     }
1174
1175     msg_Dbg( p_access,
1176              "recv command start_sequence:0x%8.8x command_id:0x%8.8x length:%d len8:%d sequence 0x%8.8x len8_II:%d dir_comm:0x%8.8x",
1177              GET32( 0 ),
1178              GET32( 4 ),
1179              GET32( 8 ),
1180              /* 12: protocol type "MMS " */
1181              GET32( 16 ),
1182              GET32( 20 ),
1183              /* 24: unknown (0) */
1184              /* 28: unknown (0) */
1185              GET32( 32 ),
1186              GET32( 36 )
1187              /* 40: switches */
1188              /* 44: extra */ );
1189
1190     p_sys->i_command = GET32( 36 ) & 0xffff;
1191 #undef GET32
1192
1193     return MMS_PACKET_CMD;
1194 }
1195
1196 static int  mms_ParsePacket( access_t *p_access,
1197                              uint8_t *p_data, size_t i_data,
1198                              int *pi_used )
1199 {
1200     access_sys_t        *p_sys = p_access->p_sys;
1201     int i_packet_seq_num;
1202     size_t i_packet_length;
1203     uint32_t i_packet_id;
1204
1205     uint8_t  *p_packet;
1206
1207
1208     *pi_used = i_data; /* default */
1209     if( i_data <= 8 )
1210     {
1211         msg_Warn( p_access, "truncated packet (header incomplete)" );
1212         return -1;
1213     }
1214
1215     i_packet_id = p_data[4];
1216     i_packet_seq_num = GetDWLE( p_data );
1217     i_packet_length = GetWLE( p_data + 6 );
1218
1219     //msg_Warn( p_access, "------->i_packet_length=%d, i_data=%d", i_packet_length, i_data );
1220
1221     if( i_packet_length > i_data || i_packet_length <= 8)
1222     {
1223      /*   msg_Dbg( p_access,
1224                  "truncated packet (Declared %d bytes, Actual %d bytes)",
1225                  i_packet_length, i_data  ); */
1226         *pi_used = 0;
1227         return -1;
1228     }
1229     else if( i_packet_length < i_data )
1230     {
1231         *pi_used = i_packet_length;
1232     }
1233
1234     if( i_packet_id == 0xff )
1235     {
1236         msg_Warn( p_access,
1237                   "receive MMS UDP pair timing" );
1238         return( MMS_PACKET_UDP_TIMING );
1239     }
1240
1241     if( i_packet_id != p_sys->i_header_packet_id_type &&
1242         i_packet_id != p_sys->i_media_packet_id_type )
1243     {
1244         msg_Warn( p_access, "incorrect Packet Id Type (0x%x)", i_packet_id );
1245         return -1;
1246     }
1247
1248     /* we now have a media or a header packet */
1249     p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader
1250     memcpy( p_packet, p_data + 8, i_packet_length - 8 );
1251
1252     if( i_packet_seq_num != p_sys->i_packet_seq_num )
1253     {
1254         /* FIXME for udp could be just wrong order ? */
1255         msg_Warn( p_access,
1256                   "detected packet lost (%d != %d)",
1257                   i_packet_seq_num,
1258                   p_sys->i_packet_seq_num );
1259         p_sys->i_packet_seq_num = i_packet_seq_num;
1260     }
1261     p_sys->i_packet_seq_num++;
1262
1263     if( i_packet_id == p_sys->i_header_packet_id_type )
1264     {
1265         if( p_sys->p_header )
1266         {
1267             p_sys->p_header = realloc( p_sys->p_header,
1268                                           p_sys->i_header + i_packet_length - 8 );
1269             memcpy( &p_sys->p_header[p_sys->i_header],
1270                     p_packet,
1271                     i_packet_length - 8 );
1272             p_sys->i_header += i_packet_length - 8;
1273
1274             free( p_packet );
1275         }
1276         else
1277         {
1278             p_sys->p_header = p_packet;
1279             p_sys->i_header = i_packet_length - 8;
1280         }
1281 /*        msg_Dbg( p_access,
1282                  "receive header packet (%d bytes)",
1283                  i_packet_length - 8 ); */
1284
1285         return MMS_PACKET_HEADER;
1286     }
1287     else
1288     {
1289         FREE( p_sys->p_media );
1290         p_sys->p_media = p_packet;
1291         p_sys->i_media = i_packet_length - 8;
1292         p_sys->i_media_used = 0;
1293 /*        msg_Dbg( p_access,
1294                  "receive media packet (%d bytes)",
1295                  i_packet_length - 8 ); */
1296
1297         return MMS_PACKET_MEDIA;
1298     }
1299 }
1300
1301 static int mms_ReceivePacket( access_t *p_access )
1302 {
1303     access_sys_t *p_sys = p_access->p_sys;
1304     int i_packet_tcp_type;
1305     int i_packet_udp_type;
1306
1307     for( ;; )
1308     {
1309         vlc_bool_t b_refill = VLC_TRUE;
1310
1311         /* first if we need to refill buffer */
1312         if( p_sys->i_buffer_tcp >= MMS_CMD_HEADERSIZE )
1313         {
1314             if( GetDWLE( p_sys->buffer_tcp + 4 ) == 0xb00bface  )
1315             {
1316                 if( GetDWLE( p_sys->buffer_tcp + 8 ) + 16 <=
1317                     p_sys->i_buffer_tcp )
1318                 {
1319                     b_refill = VLC_FALSE;
1320                 }
1321             }
1322             else if( GetWLE( p_sys->buffer_tcp + 6 ) <= p_sys->i_buffer_tcp )
1323             {
1324                 b_refill = VLC_FALSE;
1325             }
1326         }
1327         if( p_sys->i_proto == MMS_PROTO_UDP && p_sys->i_buffer_udp >= 8 &&
1328             GetWLE( p_sys->buffer_udp + 6 ) <= p_sys->i_buffer_udp )
1329         {
1330             b_refill = VLC_FALSE;
1331         }
1332
1333         if( b_refill && NetFillBuffer( p_access ) < 0 )
1334         {
1335             msg_Warn( p_access, "cannot fill buffer" );
1336             return -1;
1337         }
1338
1339         i_packet_tcp_type = -1;
1340         i_packet_udp_type = -1;
1341
1342         if( p_sys->i_buffer_tcp > 0 )
1343         {
1344             int i_used;
1345
1346             if( GetDWLE( p_sys->buffer_tcp + 4 ) == 0xb00bface )
1347             {
1348                 i_packet_tcp_type =
1349                     mms_ParseCommand( p_access, p_sys->buffer_tcp,
1350                                       p_sys->i_buffer_tcp, &i_used );
1351
1352             }
1353             else
1354             {
1355                 i_packet_tcp_type =
1356                     mms_ParsePacket( p_access, p_sys->buffer_tcp,
1357                                      p_sys->i_buffer_tcp, &i_used );
1358             }
1359             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
1360             {
1361                 memmove( p_sys->buffer_tcp, p_sys->buffer_tcp + i_used,
1362                          MMS_BUFFER_SIZE - i_used );
1363             }
1364             p_sys->i_buffer_tcp -= i_used;
1365         }
1366         else if( p_sys->i_buffer_udp > 0 )
1367         {
1368             int i_used;
1369
1370             i_packet_udp_type =
1371                 mms_ParsePacket( p_access, p_sys->buffer_udp,
1372                                  p_sys->i_buffer_udp, &i_used );
1373
1374             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
1375             {
1376                 memmove( p_sys->buffer_udp, p_sys->buffer_udp + i_used,
1377                          MMS_BUFFER_SIZE - i_used );
1378             }
1379             p_sys->i_buffer_udp -= i_used;
1380         }
1381
1382         if( i_packet_tcp_type == MMS_PACKET_CMD && p_sys->i_command == 0x1b )
1383         {
1384             mms_CommandSend( p_access, 0x1b, 0, 0, NULL, 0 );
1385             i_packet_tcp_type = -1;
1386         }
1387
1388         if( i_packet_tcp_type != -1 )
1389         {
1390             return i_packet_tcp_type;
1391         }
1392         else if( i_packet_udp_type != -1 )
1393         {
1394             return i_packet_udp_type;
1395         }
1396     }
1397 }
1398
1399 static int mms_ReceiveCommand( access_t *p_access )
1400 {
1401     access_sys_t *p_sys = p_access->p_sys;
1402
1403     for( ;; )
1404     {
1405         int i_used;
1406         int i_status;
1407
1408         if( NetFillBuffer( p_access ) < 0 )
1409         {
1410             msg_Warn( p_access, "cannot fill buffer" );
1411             return VLC_EGENERIC;
1412         }
1413         if( p_sys->i_buffer_tcp > 0 )
1414         {
1415             i_status = mms_ParseCommand( p_access, p_sys->buffer_tcp,
1416                                          p_sys->i_buffer_tcp, &i_used );
1417             if( i_used < MMS_BUFFER_SIZE )
1418             {
1419                 memmove( p_sys->buffer_tcp, p_sys->buffer_tcp + i_used,
1420                          MMS_BUFFER_SIZE - i_used );
1421             }
1422             p_sys->i_buffer_tcp -= i_used;
1423
1424             if( i_status < 0 )
1425             {
1426                 return VLC_EGENERIC;
1427             }
1428
1429             if( p_sys->i_command == 0x1b )
1430             {
1431                 mms_CommandSend( p_access, 0x1b, 0, 0, NULL, 0 );
1432             }
1433             else
1434             {
1435                 break;
1436             }
1437         }
1438         else
1439         {
1440             return VLC_EGENERIC;
1441         }
1442     }
1443
1444     return VLC_SUCCESS;
1445 }
1446
1447 #define MMS_RETRY_MAX       10
1448 #define MMS_RETRY_SLEEP     50000
1449
1450 static int mms_CommandRead( access_t *p_access, int i_command1,
1451                             int i_command2 )
1452 {
1453     access_sys_t *p_sys = p_access->p_sys;
1454     int i_count;
1455     int i_status;
1456
1457     for( i_count = 0; i_count < MMS_RETRY_MAX; )
1458     {
1459         i_status = mms_ReceiveCommand( p_access );
1460         if( i_status < 0 || p_sys->i_command == 0 )
1461         {
1462             i_count++;
1463             msleep( MMS_RETRY_SLEEP );
1464         }
1465         else if( i_command1 == 0 && i_command2 == 0)
1466         {
1467             return VLC_SUCCESS;
1468         }
1469         else if( p_sys->i_command == i_command1 ||
1470                  p_sys->i_command == i_command2 )
1471         {
1472             return VLC_SUCCESS;
1473         }
1474         else
1475         {
1476             switch( p_sys->i_command )
1477             {
1478                 case 0x03:
1479                     msg_Warn( p_access, "socket closed by server" );
1480                     p_access->info.b_eof = 1;
1481                     return VLC_EGENERIC;
1482                 case 0x1e:
1483                     msg_Warn( p_access, "end of media stream" );
1484                     p_access->info.b_eof = 1;
1485                     return VLC_EGENERIC;
1486                 default:
1487                     break;
1488             }
1489         }
1490     }
1491     msg_Warn( p_access, "failed to receive command (aborting)" );
1492
1493     return VLC_EGENERIC;
1494 }
1495
1496
1497 static int mms_HeaderMediaRead( access_t *p_access, int i_type )
1498 {
1499     access_sys_t *p_sys = p_access->p_sys;
1500     int          i_count;
1501
1502     for( i_count = 0; i_count < MMS_RETRY_MAX; )
1503     {
1504         int i_status;
1505
1506         if( p_access->b_die )
1507             return -1;
1508
1509         i_status = mms_ReceivePacket( p_access );
1510         if( i_status < 0 )
1511         {
1512             i_count++;
1513             msg_Warn( p_access, "cannot receive header (%d/%d)",
1514                       i_count, MMS_RETRY_MAX );
1515             msleep( MMS_RETRY_SLEEP );
1516         }
1517         else if( i_status == i_type || i_type == MMS_PACKET_ANY )
1518         {
1519             return i_type;
1520         }
1521         else if( i_status == MMS_PACKET_CMD )
1522         {
1523             switch( p_sys->i_command )
1524             {
1525                 case 0x03:
1526                     msg_Warn( p_access, "socket closed by server" );
1527                     p_access->info.b_eof = 1;
1528                     return -1;
1529                 case 0x1e:
1530                     msg_Warn( p_access, "end of media stream" );
1531                     p_access->info.b_eof = 1;
1532                     return -1;
1533                 case 0x20:
1534                     /* XXX not too dificult to be done EXCEPT that we
1535                      * need to restart demuxer... and I don't see how we
1536                      * could do that :p */
1537                     msg_Err( p_access,
1538                              "reinitialization needed --> unsupported" );
1539                     p_access->info.b_eof = VLC_TRUE;
1540                     return -1;
1541                 default:
1542                     break;
1543             }
1544         }
1545     }
1546
1547     msg_Err( p_access, "cannot receive %s (aborting)",
1548              ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" );
1549     return -1;
1550 }
1551