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