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