]> git.sesse.net Git - vlc/blob - modules/access/mms/mmstu.c
3f15bf9e1193f10153879aff43f732cd8f77ef84
[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.4 2003/07/10 23:55:14 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     p_input->p_private = (void*)&socket_desc;
453     if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
454     {
455         msg_Err( p_input, "failed to open a connection (tcp)" );
456         return( -1 );
457     }
458     module_Unneed( p_input, p_network );
459     p_sys->socket_tcp.i_handle = socket_desc.i_handle;
460     p_input->i_mtu    = 0; /*socket_desc.i_mtu;*/
461     msg_Dbg( p_input,
462              "connection(tcp) with \"%s:%d\" successful",
463              p_url->psz_host,
464              p_url->i_port );
465
466     /* *** Bind port if UDP protocol is selected *** */
467     if( b_udp )
468     {
469         struct sockaddr_in name;
470         socklen_t i_namelen = sizeof( struct sockaddr_in );
471
472         if( getsockname( p_sys->socket_tcp.i_handle,
473                          (struct sockaddr*)&name, &i_namelen ) < 0 )
474         {
475
476             msg_Err( p_input, "for udp you have to provide bind address (mms://<server_addr>@<bind_addr/<path> (FIXME)" );
477 #if defined( UNDER_CE )
478             CloseHandle( (HANDLE)p_sys->socket_tcp.i_handle );
479 #elif defined( WIN32 )
480             closesocket( p_sys->socket_tcp.i_handle );
481 #else
482             close( p_sys->socket_tcp.i_handle );
483 #endif
484             return( -1 );
485         }
486         p_sys->psz_bind_addr = inet_ntoa( name.sin_addr );
487
488         socket_desc.i_type = NETWORK_UDP;
489         socket_desc.psz_server_addr = "";
490         socket_desc.i_server_port   = 0;
491         socket_desc.psz_bind_addr   = p_sys->psz_bind_addr;
492         socket_desc.i_bind_port     = 7000; //p_url->i_bind_port; FIXME
493         p_input->p_private = (void*)&socket_desc;
494         if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
495         {
496             msg_Err( p_input, "failed to open a connection (udp)" );
497 #if defined( UNDER_CE )
498             CloseHandle( (HANDLE)p_sys->socket_tcp.i_handle );
499 #elif defined( WIN32 )
500             closesocket( p_sys->socket_tcp.i_handle );
501 #else
502             close( p_sys->socket_tcp.i_handle );
503 #endif
504             return( -1 );
505         }
506         module_Unneed( p_input, p_network );
507         p_sys->socket_udp.i_handle = socket_desc.i_handle;
508         p_input->i_mtu    = 0;/*socket_desc.i_mtu;  FIXME */
509
510         msg_Dbg( p_input,
511                  "connection(udp) at \"%s:%d\" successful",
512                  p_sys->psz_bind_addr,
513                  7000 );
514     }
515     else
516     {
517         p_sys->psz_bind_addr = NULL;
518     }
519
520     /* *** Init context for mms prototcol *** */
521     E_( GenerateGuid )( &p_sys->guid );    /* used to identify client by server */
522     msg_Dbg( p_input,
523              "generated guid: "GUID_FMT,
524              GUID_PRINT( p_sys->guid ) );
525     p_sys->i_command_level = 1;          /* updated after 0x1A command */
526     p_sys->i_seq_num = 0;
527     p_sys->i_media_packet_id_type  = 0x04;
528     p_sys->i_header_packet_id_type = 0x02;
529     p_sys->i_proto = i_proto;
530     p_sys->i_packet_seq_num = 0;
531     p_sys->p_header = NULL;
532     p_sys->i_header = 0;
533     p_sys->p_media = NULL;
534     p_sys->i_media = 0;
535     p_sys->i_media_used = 0;
536
537     p_sys->i_pos = 0;
538     p_sys->i_buffer_tcp = 0;
539     p_sys->i_buffer_udp = 0;
540     p_sys->p_cmd = NULL;
541     p_sys->i_cmd = 0;
542     p_sys->i_eos = 0;
543
544     /* *** send command 1 : connection request *** */
545     var_buffer_initwrite( &buffer, 0 );
546     var_buffer_add16( &buffer, 0x001c );
547     var_buffer_add16( &buffer, 0x0003 );
548     sprintf( tmp,
549              "NSPlayer/7.0.0.1956; {"GUID_FMT"}; Host: %s",
550              GUID_PRINT( p_sys->guid ),
551              p_url->psz_host );
552     var_buffer_addUTF16( &buffer, tmp );
553
554     mms_CommandSend( p_input,
555                      0x01,          /* connexion request */
556                      0x00000000,    /* flags, FIXME */
557                      0x0004000b,    /* ???? */
558                      buffer.p_data,
559                      buffer.i_data );
560
561     if( mms_CommandRead( p_input, 0x01, 0 ) < 0 )
562     {
563         var_buffer_free( &buffer );
564         MMSClose( p_input );
565         return( -1 );
566     }
567
568     i_server_version = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 32 );
569     i_tool_version = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 36 );
570     i_update_player_url = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 40 );
571     i_encryption_type = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 44 );
572     p = (uint16_t*)( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 48 );
573 #define GETUTF16( psz, size ) \
574     { \
575         int i; \
576         psz = malloc( size + 1); \
577         for( i = 0; i < size; i++ ) \
578         { \
579             psz[i] = p[i]; \
580         } \
581         psz[size] = '\0'; \
582         p += 2 * ( size ); \
583     }
584     GETUTF16( p_sys->psz_server_version, i_server_version );
585     GETUTF16( p_sys->psz_tool_version, i_tool_version );
586     GETUTF16( p_sys->psz_update_player_url, i_update_player_url );
587     GETUTF16( p_sys->psz_encryption_type, i_encryption_type );
588 #undef GETUTF16
589     msg_Dbg( p_input,
590              "0x01 --> server_version:\"%s\" tool_version:\"%s\" update_player_url:\"%s\" encryption_type:\"%s\"",
591              p_sys->psz_server_version,
592              p_sys->psz_tool_version,
593              p_sys->psz_update_player_url,
594              p_sys->psz_encryption_type );
595
596     /* *** should make an 18 command to make data timing *** */
597
598     /* *** send command 2 : transport protocol selection *** */
599     var_buffer_reinitwrite( &buffer, 0 );
600     var_buffer_add32( &buffer, 0x00000000 );
601     var_buffer_add32( &buffer, 0x000a0000 );
602     var_buffer_add32( &buffer, 0x00000002 );
603     if( b_udp )
604     {
605         sprintf( tmp,
606                  "\\\\%s\\UDP\\%d",
607                  p_sys->psz_bind_addr,
608                  7000 ); // FIXME
609     }
610     else
611     {
612         sprintf( tmp, "\\\\192.168.0.1\\TCP\\1242"  );
613     }
614     var_buffer_addUTF16( &buffer, tmp );
615     var_buffer_add16( &buffer, '0' );
616
617     mms_CommandSend( p_input,
618                      0x02,          /* connexion request */
619                      0x00000000,    /* flags, FIXME */
620                      0xffffffff,    /* ???? */
621                      buffer.p_data,
622                      buffer.i_data );
623
624     /* *** response from server, should be 0x02 or 0x03 *** */
625     mms_CommandRead( p_input, 0x02, 0x03 );
626     if( p_sys->i_command == 0x03 )
627     {
628         msg_Err( p_input,
629                  "%s protocol selection failed", b_udp ? "UDP" : "TCP" );
630         var_buffer_free( &buffer );
631         MMSClose( p_input );
632         return( -1 );
633     }
634     else if( p_sys->i_command != 0x02 )
635     {
636         msg_Warn( p_input, "received command isn't 0x02 in reponse to 0x02" );
637     }
638
639     /* *** send command 5 : media file name/path requested *** */
640     var_buffer_reinitwrite( &buffer, 0 );
641     var_buffer_add64( &buffer, 0 );
642     var_buffer_addUTF16( &buffer, p_url->psz_path );
643
644     mms_CommandSend( p_input,
645                      0x05,
646                      p_sys->i_command_level,
647                      0xffffffff,
648                      buffer.p_data,
649                      buffer.i_data );
650
651     /* *** wait for reponse *** */
652     mms_CommandRead( p_input, 0x1a, 0x06 );
653
654     /* test if server send 0x1A answer */
655     if( p_sys->i_command == 0x1A )
656     {
657         msg_Err( p_input, "id/password requested (not yet supported)" );
658         /*  FIXME */
659         var_buffer_free( &buffer );
660         MMSClose( p_input );
661         return( -1 );
662     }
663     if( p_sys->i_command != 0x06 )
664     {
665         msg_Err( p_input,
666                  "unknown answer (0x%x instead of 0x06)",
667                  p_sys->i_command );
668         var_buffer_free( &buffer );
669         MMSClose( p_input );
670         return( -1 );
671     }
672
673     /*  1 for file ok, 2 for authen ok */
674     switch( GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE ) )
675     {
676         case 0x0001:
677             msg_Dbg( p_input, "Media file name/path accepted" );
678             break;
679         case 0x0002:
680             msg_Dbg( p_input, "Authentication accepted" );
681             break;
682         case -1:
683         default:
684         msg_Err( p_input, "error while asking for file %d",
685                  GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE ) );
686         var_buffer_free( &buffer );
687         MMSClose( p_input );
688         return( -1 );
689     }
690
691     p_sys->i_flags_broadcast =
692         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 12 );
693     p_sys->i_media_length =
694         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 24 );
695     p_sys->i_packet_length =
696         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 44 );
697     p_sys->i_packet_count =
698         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 48 );
699     p_sys->i_max_bit_rate =
700         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 56 );
701     p_sys->i_header_size =
702         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 60 );
703
704     msg_Dbg( p_input,
705              "answer 0x06 flags:0x%8.8x media_length:%ds packet_length:%d packet_count:%d max_bit_rate:%d header_size:%d",
706              p_sys->i_flags_broadcast,
707              p_sys->i_media_length,
708              p_sys->i_packet_length,
709              p_sys->i_packet_count,
710              p_sys->i_max_bit_rate,
711              p_sys->i_header_size );
712
713     /* XXX XXX dirty hack XXX XXX */
714     p_input->i_mtu    = 3 * p_sys->i_packet_length;
715
716     /* *** send command 15 *** */
717
718     var_buffer_reinitwrite( &buffer, 0 );
719     var_buffer_add32( &buffer, 0 );
720     var_buffer_add32( &buffer, 0x8000 );
721     var_buffer_add32( &buffer, 0xffffffff );
722     var_buffer_add32( &buffer, 0x00 );
723     var_buffer_add32( &buffer, 0x00 );
724     var_buffer_add32( &buffer, 0x00 );
725     var_buffer_add64( &buffer, 0x40ac200000000000 );
726     var_buffer_add32( &buffer, p_sys->i_header_packet_id_type );
727     var_buffer_add32( &buffer, 0x00 );
728     mms_CommandSend( p_input, 0x15, p_sys->i_command_level, 0x00,
729                      buffer.p_data, buffer.i_data );
730
731     /* *** wait for reponse *** */
732     /* Commented out because it fails on some stream (no 0x11 answer) */
733 #if 0
734     mms_CommandRead( p_input, 0x11, 0 );
735
736     if( p_sys->i_command != 0x11 )
737     {
738         msg_Err( p_input,
739                  "unknown answer (0x%x instead of 0x11)",
740                  p_sys->i_command );
741         var_buffer_free( &buffer );
742         MMSClose( p_input );
743         return( -1 );
744     }
745 #endif
746
747     /* *** now read header packet *** */
748     /* XXX could be split over multiples packets */
749     msg_Dbg( p_input, "reading header" );
750     for( ;; )
751     {
752         if( mms_HeaderMediaRead( p_input, MMS_PACKET_HEADER ) < 0 )
753         {
754             msg_Err( p_input, "cannot receive header" );
755             var_buffer_free( &buffer );
756             MMSClose( p_input );
757             return( -1 );
758         }
759         if( p_sys->i_header >= p_sys->i_header_size )
760         {
761             msg_Dbg( p_input,
762                      "header complete(%d)",
763                      p_sys->i_header );
764             break;
765         }
766         msg_Dbg( p_input,
767                  "header incomplete (%d/%d), reading more",
768                  p_sys->i_header,
769                  p_sys->i_header_size );
770     }
771
772     /* *** parse header and get stream and their id *** */
773     /* get all streams properties,
774      *
775      * TODO : stream bitrates properties(optional)
776      *        and bitrate mutual exclusion(optional) */
777     E_( asf_HeaderParse )( &p_sys->asfh,
778                            p_sys->p_header, p_sys->i_header );
779     E_( asf_StreamSelect)( &p_sys->asfh,
780                            config_GetInt( p_input, "mms-maxbitrate" ),
781                            config_GetInt( p_input, "mms-all" ),
782                            config_GetInt( p_input, "audio" ),
783                            config_GetInt( p_input, "video" ) );
784
785     /* *** now select stream we want to receive *** */
786     /* TODO take care of stream bitrate TODO */
787     i_streams = 0;
788     i_first = -1;
789     var_buffer_reinitwrite( &buffer, 0 );
790     /* for now, select first audio and video stream */
791     for( i = 1; i < 128; i++ )
792     {
793
794         if( p_sys->asfh.stream[i].i_cat != ASF_STREAM_UNKNOWN )
795         {
796             i_streams++;
797             if( i_first != -1 )
798             {
799                 var_buffer_add16( &buffer, 0xffff );
800                 var_buffer_add16( &buffer, i );
801             }
802             else
803             {
804                 i_first = i;
805             }
806             if( p_sys->asfh.stream[i].i_selected )
807             {
808                 var_buffer_add16( &buffer, 0x0000 );
809                 msg_Info( p_input,
810                           "selecting stream[0x%x] %s (%d kb/s)",
811                           i,
812                           ( p_sys->asfh.stream[i].i_cat == ASF_STREAM_AUDIO  ) ?
813                                                   "audio" : "video" ,
814                           p_sys->asfh.stream[i].i_bitrate / 1024);
815             }
816             else
817             {
818                 var_buffer_add16( &buffer, 0x0002 );
819                 msg_Info( p_input,
820                           "ignoring stream[0x%x] %s (%d kb/s)",
821                           i,
822                           ( p_sys->asfh.stream[i].i_cat == ASF_STREAM_AUDIO  ) ?
823                                     "audio" : "video" ,
824                           p_sys->asfh.stream[i].i_bitrate / 1024);
825
826             }
827         }
828     }
829
830     if( i_streams == 0 )
831     {
832         msg_Err( p_input, "cannot find any stream" );
833         var_buffer_free( &buffer );
834         MMSClose( p_input );
835         return( -1 );
836     }
837     mms_CommandSend( p_input, 0x33,
838                      i_streams,
839                      0xffff | ( i_first << 16 ),
840                      buffer.p_data, buffer.i_data );
841
842     mms_CommandRead( p_input, 0x21, 0 );
843     if( p_sys->i_command != 0x21 )
844     {
845         msg_Err( p_input,
846                  "unknown answer (0x%x instead of 0x21)",
847                  p_sys->i_command );
848         var_buffer_free( &buffer );
849         MMSClose( p_input );
850         return( -1 );
851     }
852
853
854     var_buffer_free( &buffer );
855
856     msg_Info( p_input, "connection sucessful" );
857
858     return( 0 );
859 }
860
861 /****************************************************************************
862  * MMSStart : Start streaming
863  ****************************************************************************/
864 static int MMSStart  ( input_thread_t  *p_input, uint32_t i_packet )
865 {
866     access_sys_t        *p_sys = p_input->p_access_data;
867     var_buffer_t    buffer;
868
869     /* *** start stream from packet 0 *** */
870     var_buffer_initwrite( &buffer, 0 );
871     var_buffer_add64( &buffer, 0 ); /* seek point in second */
872     var_buffer_add32( &buffer, 0xffffffff );
873     var_buffer_add32( &buffer, i_packet ); // begin from start
874     var_buffer_add8( &buffer, 0xff ); // stream time limit
875     var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
876     var_buffer_add8( &buffer, 0xff ); //
877     var_buffer_add8( &buffer, 0x00 ); // don't use limit
878     var_buffer_add32( &buffer, p_sys->i_media_packet_id_type );
879
880     mms_CommandSend( p_input, 0x07, p_sys->i_command_level, 0x0001ffff,
881                      buffer.p_data, buffer.i_data );
882
883     var_buffer_free( &buffer );
884
885     mms_CommandRead( p_input, 0x05, 0 );
886
887     if( p_sys->i_command != 0x05 )
888     {
889         msg_Err( p_input,
890                  "unknown answer (0x%x instead of 0x05)",
891                  p_sys->i_command );
892         return( -1 );
893     }
894     else
895     {
896         /* get a packet */
897         mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA );
898         msg_Dbg( p_input, "Streaming started" );
899         return( 0 );
900     }
901 }
902
903 /****************************************************************************
904  * MMSStop : Stop streaming
905  ****************************************************************************/
906 static int MMSStop  ( input_thread_t  *p_input )
907 {
908     access_sys_t        *p_sys = p_input->p_access_data;
909
910     /* *** stop stream but keep connection alive *** */
911     mms_CommandSend( p_input,
912                      0x09,
913                      p_sys->i_command_level,
914                      0x001fffff,
915                      NULL, 0 );
916     return( 0 );
917 }
918
919 /****************************************************************************
920  * MMSClose : Close streaming and connection
921  ****************************************************************************/
922 static int MMSClose  ( input_thread_t  *p_input )
923 {
924     access_sys_t        *p_sys = p_input->p_access_data;
925
926     msg_Dbg( p_input, "Connection closed" );
927
928     /* *** tell server that we will disconnect *** */
929     mms_CommandSend( p_input,
930                      0x0d,
931                      p_sys->i_command_level,
932                      0x00000001,
933                      NULL, 0 );
934     /* *** close sockets *** */
935 #if defined( UNDER_CE )
936     CloseHandle( (HANDLE)p_sys->socket_tcp.i_handle );
937 #elif defined( WIN32 )
938     closesocket( p_sys->socket_tcp.i_handle );
939 #else
940     close( p_sys->socket_tcp.i_handle );
941 #endif
942
943     if( p_sys->i_proto == MMS_PROTO_UDP )
944     {
945 #if defined( UNDER_CE )
946         CloseHandle( (HANDLE)p_sys->socket_udp.i_handle );
947 #elif defined( WIN32 )
948         closesocket( p_sys->socket_udp.i_handle );
949 #else
950         close( p_sys->socket_udp.i_handle );
951 #endif
952     }
953
954     FREE( p_sys->p_cmd );
955     FREE( p_sys->p_media );
956     FREE( p_sys->p_header );
957
958     FREE( p_sys->psz_server_version );
959     FREE( p_sys->psz_tool_version );
960     FREE( p_sys->psz_update_player_url );
961     FREE( p_sys->psz_encryption_type );
962
963     return( 0 );
964 }
965
966 /****************************************************************************
967  *
968  * MMS specific functions
969  *
970  ****************************************************************************/
971
972 static int mms_CommandSend( input_thread_t *p_input,
973                              int i_command,
974                              uint32_t i_prefix1, uint32_t i_prefix2,
975                              uint8_t *p_data, int i_data )
976 {
977     var_buffer_t buffer;
978
979     access_sys_t        *p_sys = p_input->p_access_data;
980     int i_data_by8;
981
982     i_data_by8 = ( i_data + 7 ) / 8;
983
984     /* first init uffer */
985     var_buffer_initwrite( &buffer, 0 );
986
987     var_buffer_add32( &buffer, 0x00000001 );    /* start sequence */
988     var_buffer_add32( &buffer, 0xB00BFACE );
989     /* size after protocol type */
990     var_buffer_add32( &buffer, i_data + MMS_CMD_HEADERSIZE - 16 );
991     var_buffer_add32( &buffer, 0x20534d4d );    /* protocol "MMS " */
992     var_buffer_add32( &buffer, i_data_by8 + 4 );
993     var_buffer_add32( &buffer, p_sys->i_seq_num ); p_sys->i_seq_num++;
994     var_buffer_add64( &buffer, 0 );
995     var_buffer_add32( &buffer, i_data_by8 + 2 );
996     var_buffer_add32( &buffer, 0x00030000 | i_command ); /* dir | command */
997     var_buffer_add32( &buffer, i_prefix1 );    /* command specific */
998     var_buffer_add32( &buffer, i_prefix2 );    /* command specific */
999
1000     /* specific command data */
1001     if( p_data && i_data > 0 )
1002     {
1003         var_buffer_addmemory( &buffer, p_data, i_data );
1004     }
1005
1006     /* send it */
1007     if( send( p_sys->socket_tcp.i_handle,
1008               buffer.p_data,
1009               buffer.i_data,
1010               0 ) == -1 )
1011     {
1012         msg_Err( p_input, "failed to send command" );
1013         return( -1 );
1014     }
1015
1016     var_buffer_free( &buffer );
1017     return( 0 );
1018 }
1019
1020 static int  NetFillBuffer( input_thread_t *p_input )
1021 {
1022 #ifdef UNDER_CE
1023     return -1;
1024 #else
1025     access_sys_t        *p_sys = p_input->p_access_data;
1026     struct timeval  timeout;
1027     fd_set          fds;
1028     int             i_ret;
1029
1030     /* FIXME when using udp */
1031     ssize_t i_tcp, i_udp;
1032     ssize_t i_tcp_read, i_udp_read;
1033     int i_handle_max;
1034     int i_try;
1035
1036     /* Initialize file descriptor set */
1037     FD_ZERO( &fds );
1038
1039     i_tcp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_tcp;
1040
1041     if( p_sys->i_proto == MMS_PROTO_UDP )
1042     {
1043         i_udp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_udp;
1044     }
1045     else
1046     {
1047         i_udp = 0;  /* there isn't udp socket */
1048     }
1049
1050     i_handle_max = 0;
1051     if( i_tcp > 0 )
1052     {
1053         FD_SET( p_sys->socket_tcp.i_handle, &fds );
1054         i_handle_max = __MAX( i_handle_max, p_sys->socket_tcp.i_handle );
1055     }
1056     if( i_udp > 0 )
1057     {
1058         FD_SET( p_sys->socket_udp.i_handle, &fds );
1059         i_handle_max = __MAX( i_handle_max, p_sys->socket_udp.i_handle );
1060     }
1061
1062     if( i_handle_max == 0 )
1063     {
1064         msg_Warn( p_input, "nothing to read %d:%d", i_tcp, i_udp );
1065         return( 0 );
1066     }
1067     else
1068     {
1069 //        msg_Warn( p_input, "ask for tcp:%d udp:%d", i_tcp, i_udp );
1070     }
1071
1072     /* We'll wait 0.5 second if nothing happens */
1073     timeout.tv_sec = 0;
1074     timeout.tv_usec = 500000;
1075     i_try = 0;
1076     /* Find if some data is available */
1077     while( (i_ret = select( i_handle_max + 1, &fds,
1078                             NULL, NULL, &timeout )) == 0
1079            || (i_ret < 0 && errno == EINTR) )
1080     {
1081         i_try++;
1082         FD_ZERO( &fds );
1083         if( i_tcp > 0 ) FD_SET( p_sys->socket_tcp.i_handle, &fds );
1084         if( i_udp > 0 ) FD_SET( p_sys->socket_udp.i_handle, &fds );
1085         timeout.tv_sec = 0;
1086         timeout.tv_usec = 500000;
1087
1088         if( i_try > 2 && ( p_sys->i_buffer_tcp > 0 || p_sys->i_buffer_udp > 0 ) )
1089         {
1090             return 0;
1091         }
1092         if( p_input->b_die || p_input->b_error )
1093         {
1094             return 0;
1095         }
1096         msg_Dbg( p_input, "NetFillBuffer: trying again (select)" );
1097     }
1098
1099     if( i_ret < 0 )
1100     {
1101         msg_Err( p_input, "network select error (%s)", strerror(errno) );
1102         return -1;
1103     }
1104
1105     if( i_tcp > 0 && FD_ISSET( p_sys->socket_tcp.i_handle, &fds ) )
1106     {
1107         i_tcp_read =
1108             recv( p_sys->socket_tcp.i_handle,
1109                   p_sys->buffer_tcp + p_sys->i_buffer_tcp,
1110                   i_tcp + MMS_BUFFER_SIZE/2, 0 );
1111     }
1112     else
1113     {
1114         i_tcp_read = 0;
1115     }
1116
1117     if( i_udp > 0 && FD_ISSET( p_sys->socket_udp.i_handle, &fds ) )
1118     {
1119         i_udp_read = recv( p_sys->socket_udp.i_handle,
1120                            p_sys->buffer_udp + p_sys->i_buffer_udp,
1121                            i_udp + MMS_BUFFER_SIZE/2, 0 );
1122     }
1123     else
1124     {
1125         i_udp_read = 0;
1126     }
1127
1128 #if MMS_DEBUG
1129     if( p_sys->i_proto == MMS_PROTO_UDP )
1130     {
1131         msg_Dbg( p_input,
1132                  "filling buffer TCP:%d+%d UDP:%d+%d",
1133                  p_sys->i_buffer_tcp,
1134                  i_tcp_read,
1135                  p_sys->i_buffer_udp,
1136                  i_udp_read );
1137     }
1138     else
1139     {
1140         msg_Dbg( p_input,
1141                  "filling buffer TCP:%d+%d",
1142                  p_sys->i_buffer_tcp,
1143                  i_tcp_read );
1144     }
1145 #endif
1146     if( i_tcp_read > 0 )
1147     {
1148         p_sys->i_buffer_tcp += i_tcp_read;
1149     }
1150     if( i_udp_read > 0 )
1151     {
1152         p_sys->i_buffer_udp += i_udp_read;
1153     }
1154
1155     return( i_tcp_read + i_udp_read);
1156 #endif
1157 }
1158
1159 static int  mms_ParseCommand( input_thread_t *p_input,
1160                               uint8_t *p_data,
1161                               int i_data,
1162                               int *pi_used )
1163 {
1164  #define GET32( i_pos ) \
1165     ( p_sys->p_cmd[i_pos] + ( p_sys->p_cmd[i_pos +1] << 8 ) + \
1166       ( p_sys->p_cmd[i_pos + 2] << 16 ) + \
1167       ( p_sys->p_cmd[i_pos + 3] << 24 ) )
1168
1169     access_sys_t        *p_sys = p_input->p_access_data;
1170     int         i_length;
1171     uint32_t    i_id;
1172
1173     if( p_sys->p_cmd )
1174     {
1175         free( p_sys->p_cmd );
1176     }
1177     p_sys->i_cmd = i_data;
1178     p_sys->p_cmd = malloc( i_data );
1179     memcpy( p_sys->p_cmd, p_data, i_data );
1180
1181     *pi_used = i_data; /* by default */
1182
1183     if( i_data < MMS_CMD_HEADERSIZE )
1184     {
1185         msg_Warn( p_input, "truncated command (header incomplete)" );
1186         p_sys->i_command = 0;
1187         return( -1 );
1188     }
1189     i_id =  GetDWLE( p_data + 4 );
1190     i_length = GetDWLE( p_data + 8 ) + 16;
1191
1192     if( i_id != 0xb00bface )
1193     {
1194         msg_Err( p_input,
1195                  "incorrect command header (0x%x)", i_id );
1196         p_sys->i_command = 0;
1197         return( -1 );
1198     }
1199
1200     if( i_length > p_sys->i_cmd )
1201     {
1202         msg_Warn( p_input,
1203                   "truncated command (missing %d bytes)",
1204                    i_length - i_data  );
1205         p_sys->i_command = 0;
1206         return( -1 );
1207     }
1208     else if( i_length < p_sys->i_cmd )
1209     {
1210         p_sys->i_cmd = i_length;
1211         *pi_used = i_length;
1212     }
1213
1214     msg_Dbg( p_input,
1215              "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",
1216              GET32( 0 ),
1217              GET32( 4 ),
1218              GET32( 8 ),
1219              /* 12: protocol type "MMS " */
1220              GET32( 16 ),
1221              GET32( 20 ),
1222              /* 24: unknown (0) */
1223              /* 28: unknown (0) */
1224              GET32( 32 ),
1225              GET32( 36 )
1226              /* 40: switches */
1227              /* 44: extra */ );
1228
1229     p_sys->i_command = GET32( 36 ) & 0xffff;
1230
1231     return( MMS_PACKET_CMD );
1232 }
1233
1234 static int  mms_ParsePacket( input_thread_t *p_input,
1235                              uint8_t *p_data, size_t i_data,
1236                              int *pi_used )
1237 {
1238     access_sys_t        *p_sys = p_input->p_access_data;
1239     int i_packet_seq_num;
1240     size_t i_packet_length;
1241     uint32_t i_packet_id;
1242
1243     uint8_t  *p_packet;
1244
1245
1246     *pi_used = i_data; /* default */
1247     if( i_data <= 8 )
1248     {
1249         msg_Warn( p_input, "truncated packet (header incomplete)" );
1250         return( -1 );
1251     }
1252
1253     i_packet_id = p_data[4];
1254     i_packet_seq_num = GetDWLE( p_data );
1255     i_packet_length = GetWLE( p_data + 6 );
1256
1257     //msg_Warn( p_input, "------->i_packet_length=%d, i_data=%d", i_packet_length, i_data );
1258
1259     if( i_packet_length > i_data || i_packet_length <= 8)
1260     {
1261         msg_Dbg( p_input,
1262                  "truncated packet (missing %d bytes)",
1263                  i_packet_length - i_data  );
1264         *pi_used = 0;
1265         return( -1 );
1266     }
1267     else if( i_packet_length < i_data )
1268     {
1269         *pi_used = i_packet_length;
1270     }
1271
1272     if( i_packet_id == 0xff )
1273     {
1274         msg_Warn( p_input,
1275                   "receive MMS UDP pair timing" );
1276         return( MMS_PACKET_UDP_TIMING );
1277     }
1278
1279     if( i_packet_id != p_sys->i_header_packet_id_type &&
1280         i_packet_id != p_sys->i_media_packet_id_type )
1281     {
1282         msg_Warn( p_input, "incorrect Packet Id Type (0x%x)", i_packet_id );
1283         return( -1 );
1284     }
1285
1286     /* we now have a media or a header packet */
1287     p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader
1288     memcpy( p_packet, p_data + 8, i_packet_length - 8 );
1289
1290     if( i_packet_seq_num != p_sys->i_packet_seq_num )
1291     {
1292         /* FIXME for udp could be just wrong order ? */
1293         msg_Warn( p_input,
1294                   "detected packet lost (%d != %d)",
1295                   i_packet_seq_num,
1296                   p_sys->i_packet_seq_num );
1297         p_sys->i_packet_seq_num = i_packet_seq_num;
1298     }
1299     p_sys->i_packet_seq_num++;
1300
1301     if( i_packet_id == p_sys->i_header_packet_id_type )
1302     {
1303         if( p_sys->p_header )
1304         {
1305             p_sys->p_header = realloc( p_sys->p_header,
1306                                           p_sys->i_header + i_packet_length - 8 );
1307             memcpy( &p_sys->p_header[p_sys->i_header],
1308                     p_packet,
1309                     i_packet_length - 8 );
1310             p_sys->i_header += i_packet_length - 8;
1311
1312             free( p_packet );
1313         }
1314         else
1315         {
1316             p_sys->p_header = p_packet;
1317             p_sys->i_header = i_packet_length - 8;
1318         }
1319 /*        msg_Dbg( p_input,
1320                  "receive header packet (%d bytes)",
1321                  i_packet_length - 8 ); */
1322
1323         return( MMS_PACKET_HEADER );
1324     }
1325     else
1326     {
1327         FREE( p_sys->p_media );
1328         p_sys->p_media = p_packet;
1329         p_sys->i_media = i_packet_length - 8;
1330         p_sys->i_media_used = 0;
1331 /*        msg_Dbg( p_input,
1332                  "receive media packet (%d bytes)",
1333                  i_packet_length - 8 ); */
1334
1335         return( MMS_PACKET_MEDIA );
1336     }
1337 }
1338
1339 static int mms_ReceivePacket( input_thread_t *p_input )
1340 {
1341     access_sys_t        *p_sys = p_input->p_access_data;
1342     int i_packet_tcp_type;
1343     int i_packet_udp_type;
1344
1345     for( ;; )
1346     {
1347         if( NetFillBuffer( p_input ) < 0 )
1348         {
1349             msg_Warn( p_input, "cannot fill buffer" );
1350             continue;
1351         }
1352
1353         i_packet_tcp_type = -1;
1354         i_packet_udp_type = -1;
1355
1356         if( p_sys->i_buffer_tcp > 0 )
1357         {
1358             int i_used;
1359
1360             if( GetDWLE( p_sys->buffer_tcp + 4 ) == 0xb00bface )
1361             {
1362                 i_packet_tcp_type =
1363                     mms_ParseCommand( p_input,
1364                                       p_sys->buffer_tcp,
1365                                       p_sys->i_buffer_tcp,
1366                                       &i_used );
1367
1368             }
1369             else
1370             {
1371                 i_packet_tcp_type =
1372                     mms_ParsePacket( p_input,
1373                                      p_sys->buffer_tcp,
1374                                      p_sys->i_buffer_tcp,
1375                                      &i_used );
1376             }
1377             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
1378             {
1379                 memmove( p_sys->buffer_tcp,
1380                          p_sys->buffer_tcp + i_used,
1381                          MMS_BUFFER_SIZE - i_used );
1382             }
1383             p_sys->i_buffer_tcp -= i_used;
1384         }
1385         else if( p_sys->i_buffer_udp > 0 )
1386         {
1387             int i_used;
1388
1389             i_packet_udp_type =
1390                 mms_ParsePacket( p_input,
1391                                  p_sys->buffer_udp,
1392                                  p_sys->i_buffer_udp,
1393                                  &i_used );
1394
1395             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
1396             {
1397                 memmove( p_sys->buffer_udp,
1398                          p_sys->buffer_udp + i_used,
1399                          MMS_BUFFER_SIZE - i_used );
1400             }
1401             p_sys->i_buffer_udp -= i_used;
1402         }
1403
1404         if( i_packet_tcp_type == MMS_PACKET_CMD &&
1405                 p_sys->i_command == 0x1b )
1406         {
1407             mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
1408             i_packet_tcp_type = -1;
1409         }
1410
1411         if( i_packet_tcp_type != -1 )
1412         {
1413             return( i_packet_tcp_type );
1414         }
1415         else if( i_packet_udp_type != -1 )
1416         {
1417             return( i_packet_udp_type );
1418         }
1419
1420     }
1421 }
1422
1423 static int  mms_ReceiveCommand( input_thread_t *p_input )
1424 {
1425     access_sys_t        *p_sys = p_input->p_access_data;
1426
1427     for( ;; )
1428     {
1429         int i_used;
1430         int i_status;
1431
1432         if( NetFillBuffer( p_input ) < 0 )
1433         {
1434             msg_Warn( p_input, "cannot fill buffer" );
1435             continue;
1436         }
1437         if( p_sys->i_buffer_tcp > 0 )
1438         {
1439             i_status = mms_ParseCommand( p_input,
1440                                   p_sys->buffer_tcp,
1441                                   p_sys->i_buffer_tcp,
1442                                   &i_used );
1443             if( i_used < MMS_BUFFER_SIZE )
1444             {
1445                 memmove( p_sys->buffer_tcp,
1446                          p_sys->buffer_tcp + i_used,
1447                          MMS_BUFFER_SIZE - i_used );
1448             }
1449             p_sys->i_buffer_tcp -= i_used;
1450
1451             if( i_status < 0 )
1452             {
1453                 return( -1 );
1454             }
1455
1456             if( p_sys->i_command == 0x1b )
1457             {
1458                 mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
1459             }
1460             else
1461             {
1462                 break;
1463             }
1464         }
1465         else
1466         {
1467             return( -1 );
1468         }
1469     }
1470
1471     return( 0 );
1472 }
1473
1474 #define MMS_RETRY_MAX       10
1475 #define MMS_RETRY_SLEEP     50000
1476
1477 static int mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 )
1478 {
1479     access_sys_t        *p_sys = p_input->p_access_data;
1480     int i_count;
1481     int i_status;
1482
1483     for( i_count = 0; i_count < MMS_RETRY_MAX; )
1484     {
1485
1486         i_status = mms_ReceiveCommand( p_input );
1487         if( i_status < 0 || p_sys->i_command == 0 )
1488         {
1489             i_count++;
1490             msleep( MMS_RETRY_SLEEP );
1491         }
1492         else if( i_command1 == 0 && i_command2 == 0)
1493         {
1494             return( 0 );
1495         }
1496         else if( p_sys->i_command == i_command1 || p_sys->i_command == i_command2 )
1497         {
1498             return( 0 );
1499         }
1500         else
1501         {
1502             switch( p_sys->i_command )
1503             {
1504                 case 0x03:
1505                     msg_Warn( p_input, "socket closed by server" );
1506                     p_sys->i_eos = 1;
1507                     return( -1 );
1508                 case 0x1e:
1509                     msg_Warn( p_input, "end of media stream" );
1510                     p_sys->i_eos = 1;
1511                     return( -1 );
1512                 default:
1513                     break;
1514             }
1515         }
1516     }
1517     msg_Warn( p_input, "failed to receive command (abording)" );
1518
1519     return( -1 );
1520 }
1521
1522
1523 static int mms_HeaderMediaRead( input_thread_t *p_input, int i_type )
1524 {
1525     access_sys_t        *p_sys = p_input->p_access_data;
1526     int          i_count;
1527
1528     for( i_count = 0; i_count < MMS_RETRY_MAX; )
1529     {
1530         int i_status;
1531
1532         i_status = mms_ReceivePacket( p_input );
1533         if( i_status < 0 )
1534         {
1535             i_count++;
1536             msg_Warn( p_input,
1537                       "cannot receive header (%d/%d)", i_count, MMS_RETRY_MAX );
1538             msleep( MMS_RETRY_SLEEP );
1539         }
1540         else if( i_status == i_type || i_type == MMS_PACKET_ANY )
1541         {
1542             return( i_type );
1543         }
1544         else if( i_status == MMS_PACKET_CMD )
1545         {
1546             switch( p_sys->i_command )
1547             {
1548                 case 0x03:
1549                     msg_Warn( p_input, "socket closed by server" );
1550                     p_sys->i_eos = 1;
1551                     return( -1 );
1552                 case 0x1e:
1553                     msg_Warn( p_input, "end of media stream" );
1554                     p_sys->i_eos = 1;
1555                     return( -1 );
1556                 case 0x20:
1557                     /* XXX not too dificult to be done EXCEPT that we
1558                      * need to restart demuxer... and I don't see how we
1559                      * could do that :p */
1560                     msg_Err( p_input,
1561                              "reinitialization needed --> unsupported" );
1562                     p_sys->i_eos = 1;
1563                     return( -1 );
1564                 default:
1565                     break;
1566             }
1567         }
1568     }
1569     msg_Err( p_input,
1570              "cannot receive %s (abording)",
1571                ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" );
1572     return( -1 );
1573 }
1574