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