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