* mms: reduce mtu (avoid too much delay with slow connection)
[vlc.git] / 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.1 2003/04/20 19:29:43 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 int  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 int  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     mms_CommandSend( p_input, 0x15, p_sys->i_command_level, 0x00,
728                      buffer.p_data, buffer.i_data );
729
730     /* *** wait for reponse *** */
731     mms_CommandRead( p_input, 0x11, 0 );
732
733     if( p_sys->i_command != 0x11 )
734     {
735         msg_Err( p_input,
736                  "unknown answer (0x%x instead of 0x11)",
737                  p_sys->i_command );
738         var_buffer_free( &buffer );
739         MMSClose( p_input );
740         return( -1 );
741     }
742     /* *** now read header packet *** */
743     /* XXX could be split over multiples packets */
744     for( ;; )
745     {
746         if( mms_HeaderMediaRead( p_input, MMS_PACKET_HEADER ) < 0 )
747         {
748             msg_Err( p_input, "cannot receive header" );
749             var_buffer_free( &buffer );
750             MMSClose( p_input );
751             return( -1 );
752         }
753         if( p_sys->i_header >= p_sys->i_header_size )
754         {
755             msg_Dbg( p_input,
756                      "header complete(%d)",
757                      p_sys->i_header );
758             break;
759         }
760         msg_Dbg( p_input,
761                  "header incomplete (%d/%d), reading more",
762                  p_sys->i_header,
763                  p_sys->i_header_size );
764     }
765
766     /* *** parse header and get stream and their id *** */
767     /* get all streams properties,
768      *
769      * TODO : stream bitrates properties(optional)
770      *        and bitrate mutual exclusion(optional) */
771     E_( asf_HeaderParse )( &p_sys->asfh,
772                            p_sys->p_header, p_sys->i_header );
773     E_( asf_StreamSelect)( &p_sys->asfh,
774                            config_GetInt( p_input, "mms-maxbitrate" ),
775                            config_GetInt( p_input, "mms-all" ),
776                            config_GetInt( p_input, "audio" ),
777                            config_GetInt( p_input, "video" ) );
778
779     /* *** now select stream we want to receive *** */
780     /* TODO take care of stream bitrate TODO */
781     i_streams = 0;
782     i_first = -1;
783     var_buffer_reinitwrite( &buffer, 0 );
784     /* for now, select first audio and video stream */
785     for( i = 1; i < 128; i++ )
786     {
787
788         if( p_sys->asfh.stream[i].i_cat != ASF_STREAM_UNKNOWN )
789         {
790             i_streams++;
791             if( i_first != -1 )
792             {
793                 var_buffer_add16( &buffer, 0xffff );
794                 var_buffer_add16( &buffer, i );
795             }
796             else
797             {
798                 i_first = i;
799             }
800             if( p_sys->asfh.stream[i].i_selected )
801             {
802                 var_buffer_add16( &buffer, 0x0000 );
803                 msg_Info( p_input,
804                           "selecting stream[0x%x] %s (%d kb/s)",
805                           i,
806                           ( p_sys->asfh.stream[i].i_cat == ASF_STREAM_AUDIO  ) ?
807                                                   "audio" : "video" ,
808                           p_sys->asfh.stream[i].i_bitrate / 1024);
809             }
810             else
811             {
812                 var_buffer_add16( &buffer, 0x0002 );
813                 msg_Info( p_input,
814                           "ignoring stream[0x%x] %s (%d kb/s)",
815                           i,
816                           ( p_sys->asfh.stream[i].i_cat == ASF_STREAM_AUDIO  ) ?
817                                     "audio" : "video" ,
818                           p_sys->asfh.stream[i].i_bitrate / 1024);
819
820             }
821         }
822     }
823
824     if( i_streams == 0 )
825     {
826         msg_Err( p_input, "cannot find any stream" );
827         var_buffer_free( &buffer );
828         MMSClose( p_input );
829         return( -1 );
830     }
831     mms_CommandSend( p_input, 0x33,
832                      i_streams,
833                      0xffff | ( i_first << 16 ),
834                      buffer.p_data, buffer.i_data );
835
836     mms_CommandRead( p_input, 0x21, 0 );
837     if( p_sys->i_command != 0x21 )
838     {
839         msg_Err( p_input,
840                  "unknown answer (0x%x instead of 0x21)",
841                  p_sys->i_command );
842         var_buffer_free( &buffer );
843         MMSClose( p_input );
844         return( -1 );
845     }
846
847
848     var_buffer_free( &buffer );
849
850     msg_Info( p_input, "connection sucessful" );
851
852     return( 0 );
853 }
854
855 /****************************************************************************
856  * MMSStart : Start streaming
857  ****************************************************************************/
858 static int MMSStart  ( input_thread_t  *p_input, uint32_t i_packet )
859 {
860     access_sys_t        *p_sys = p_input->p_access_data;
861     var_buffer_t    buffer;
862
863     /* *** start stream from packet 0 *** */
864     var_buffer_initwrite( &buffer, 0 );
865     var_buffer_add64( &buffer, 0 ); /* seek point in second */
866     var_buffer_add32( &buffer, 0xffffffff );
867     var_buffer_add32( &buffer, i_packet ); // begin from start
868     var_buffer_add8( &buffer, 0xff ); // stream time limit
869     var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
870     var_buffer_add8( &buffer, 0xff ); //
871     var_buffer_add8( &buffer, 0x00 ); // don't use limit
872     var_buffer_add32( &buffer, p_sys->i_media_packet_id_type );
873
874     mms_CommandSend( p_input, 0x07, p_sys->i_command_level, 0x0001ffff,
875                      buffer.p_data, buffer.i_data );
876
877     var_buffer_free( &buffer );
878
879     mms_CommandRead( p_input, 0x05, 0 );
880
881     if( p_sys->i_command != 0x05 )
882     {
883         msg_Err( p_input,
884                  "unknown answer (0x%x instead of 0x05)",
885                  p_sys->i_command );
886         return( -1 );
887     }
888     else
889     {
890         /* get a packet */
891         mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA );
892         msg_Dbg( p_input, "Streaming started" );
893         return( 0 );
894     }
895 }
896
897 /****************************************************************************
898  * MMSStop : Stop streaming
899  ****************************************************************************/
900 static int MMSStop  ( input_thread_t  *p_input )
901 {
902     access_sys_t        *p_sys = p_input->p_access_data;
903
904     /* *** stop stream but keep connection alive *** */
905     mms_CommandSend( p_input,
906                      0x09,
907                      p_sys->i_command_level,
908                      0x001fffff,
909                      NULL, 0 );
910     return( 0 );
911 }
912
913 /****************************************************************************
914  * MMSClose : Close streaming and connection
915  ****************************************************************************/
916 static int MMSClose  ( input_thread_t  *p_input )
917 {
918     access_sys_t        *p_sys = p_input->p_access_data;
919
920     msg_Dbg( p_input, "Connection closed" );
921
922     /* *** tell server that we will disconnect *** */
923     mms_CommandSend( p_input,
924                      0x0d,
925                      p_sys->i_command_level,
926                      0x00000001,
927                      NULL, 0 );
928     /* *** close sockets *** */
929 #if defined( UNDER_CE )
930     CloseHandle( (HANDLE)p_sys->socket_tcp.i_handle );
931 #elif defined( WIN32 )
932     closesocket( p_sys->socket_tcp.i_handle );
933 #else
934     close( p_sys->socket_tcp.i_handle );
935 #endif
936
937     if( p_sys->i_proto == MMS_PROTO_UDP )
938     {
939 #if defined( UNDER_CE )
940         CloseHandle( (HANDLE)p_sys->socket_udp.i_handle );
941 #elif defined( WIN32 )
942         closesocket( p_sys->socket_udp.i_handle );
943 #else
944         close( p_sys->socket_udp.i_handle );
945 #endif
946     }
947
948     FREE( p_sys->p_cmd );
949     FREE( p_sys->p_media );
950     FREE( p_sys->p_header );
951
952     FREE( p_sys->psz_server_version );
953     FREE( p_sys->psz_tool_version );
954     FREE( p_sys->psz_update_player_url );
955     FREE( p_sys->psz_encryption_type );
956
957     return( 0 );
958 }
959
960 /****************************************************************************
961  *
962  * MMS specific functions
963  *
964  ****************************************************************************/
965
966 static int mms_CommandSend( input_thread_t *p_input,
967                              int i_command,
968                              uint32_t i_prefix1, uint32_t i_prefix2,
969                              uint8_t *p_data, int i_data )
970 {
971     var_buffer_t buffer;
972
973     access_sys_t        *p_sys = p_input->p_access_data;
974     int i_data_by8;
975
976     i_data_by8 = ( i_data + 7 ) / 8;
977
978     /* first init uffer */
979     var_buffer_initwrite( &buffer, 0 );
980
981     var_buffer_add32( &buffer, 0x00000001 );    /* start sequence */
982     var_buffer_add32( &buffer, 0xB00BFACE );
983     /* size after protocol type */
984     var_buffer_add32( &buffer, i_data + MMS_CMD_HEADERSIZE - 16 );
985     var_buffer_add32( &buffer, 0x20534d4d );    /* protocol "MMS " */
986     var_buffer_add32( &buffer, i_data_by8 + 4 );
987     var_buffer_add32( &buffer, p_sys->i_seq_num ); p_sys->i_seq_num++;
988     var_buffer_add64( &buffer, 0 );
989     var_buffer_add32( &buffer, i_data_by8 + 2 );
990     var_buffer_add32( &buffer, 0x00030000 | i_command ); /* dir | command */
991     var_buffer_add32( &buffer, i_prefix1 );    /* command specific */
992     var_buffer_add32( &buffer, i_prefix2 );    /* command specific */
993
994     /* specific command data */
995     if( p_data && i_data > 0 )
996     {
997         var_buffer_addmemory( &buffer, p_data, i_data );
998     }
999
1000     /* send it */
1001     if( send( p_sys->socket_tcp.i_handle,
1002               buffer.p_data,
1003               buffer.i_data,
1004               0 ) == -1 )
1005     {
1006         msg_Err( p_input, "failed to send command" );
1007         return( -1 );
1008     }
1009
1010     var_buffer_free( &buffer );
1011     return( 0 );
1012 }
1013
1014 static int  NetFillBuffer( input_thread_t *p_input )
1015 {
1016 #ifdef UNDER_CE
1017     return -1;
1018 #else
1019     access_sys_t        *p_sys = p_input->p_access_data;
1020     struct timeval  timeout;
1021     fd_set          fds;
1022     int             i_ret;
1023
1024     /* FIXME when using udp */
1025     ssize_t i_tcp, i_udp;
1026     ssize_t i_tcp_read, i_udp_read;
1027     int i_handle_max;
1028
1029     /* Initialize file descriptor set */
1030     FD_ZERO( &fds );
1031
1032     i_tcp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_tcp;
1033
1034     if( p_sys->i_proto == MMS_PROTO_UDP )
1035     {
1036         i_udp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_udp;
1037     }
1038     else
1039     {
1040         i_udp = 0;  /* there isn't udp socket */
1041     }
1042
1043     i_handle_max = 0;
1044     if( i_tcp > 0 )
1045     {
1046         FD_SET( p_sys->socket_tcp.i_handle, &fds );
1047         i_handle_max = __MAX( i_handle_max, p_sys->socket_tcp.i_handle );
1048     }
1049     if( i_udp > 0 )
1050     {
1051         FD_SET( p_sys->socket_udp.i_handle, &fds );
1052         i_handle_max = __MAX( i_handle_max, p_sys->socket_udp.i_handle );
1053     }
1054
1055     if( i_handle_max == 0 )
1056     {
1057         msg_Warn( p_input, "nothing to read %d:%d", i_tcp, i_udp );
1058         return( 0 );
1059     }
1060     else
1061     {
1062 //        msg_Warn( p_input, "ask for tcp:%d udp:%d", i_tcp, i_udp );
1063     }
1064
1065     /* We'll wait 0.5 second if nothing happens */
1066     timeout.tv_sec = 0;
1067     timeout.tv_usec = 500000;
1068
1069     /* Find if some data is available */
1070     while( (i_ret = select( i_handle_max + 1, &fds,
1071                             NULL, NULL, &timeout )) == 0
1072            || (i_ret < 0 && errno == EINTR) )
1073     {
1074         FD_ZERO( &fds );
1075         if( i_tcp > 0 ) FD_SET( p_sys->socket_tcp.i_handle, &fds );
1076         if( i_udp > 0 ) FD_SET( p_sys->socket_udp.i_handle, &fds );
1077         timeout.tv_sec = 0;
1078         timeout.tv_usec = 500000;
1079
1080         if( p_input->b_die || p_input->b_error )
1081         {
1082             return 0;
1083         }
1084     }
1085
1086     if( i_ret < 0 )
1087     {
1088         msg_Err( p_input, "network select error (%s)", strerror(errno) );
1089         return -1;
1090     }
1091
1092     if( i_tcp > 0 && FD_ISSET( p_sys->socket_tcp.i_handle, &fds ) )
1093     {
1094         i_tcp_read =
1095             recv( p_sys->socket_tcp.i_handle,
1096                   p_sys->buffer_tcp + p_sys->i_buffer_tcp,
1097                   i_tcp + MMS_BUFFER_SIZE/2, 0 );
1098     }
1099     else
1100     {
1101         i_tcp_read = 0;
1102     }
1103
1104     if( i_udp > 0 && FD_ISSET( p_sys->socket_udp.i_handle, &fds ) )
1105     {
1106         i_udp_read = recv( p_sys->socket_udp.i_handle,
1107                            p_sys->buffer_udp + p_sys->i_buffer_udp,
1108                            i_udp + MMS_BUFFER_SIZE/2, 0 );
1109     }
1110     else
1111     {
1112         i_udp_read = 0;
1113     }
1114
1115 #if MMS_DEBUG
1116     if( p_sys->i_proto == MMS_PROTO_UDP )
1117     {
1118         msg_Dbg( p_input,
1119                  "filling buffer TCP:%d+%d UDP:%d+%d",
1120                  p_sys->i_buffer_tcp,
1121                  i_tcp_read,
1122                  p_sys->i_buffer_udp,
1123                  i_udp_read );
1124     }
1125     else
1126     {
1127         msg_Dbg( p_input,
1128                  "filling buffer TCP:%d+%d",
1129                  p_sys->i_buffer_tcp,
1130                  i_tcp_read );
1131     }
1132 #endif
1133     if( i_tcp_read > 0 )
1134     {
1135         p_sys->i_buffer_tcp += i_tcp_read;
1136     }
1137     if( i_udp_read > 0 )
1138     {
1139         p_sys->i_buffer_udp += i_udp_read;
1140     }
1141
1142     return( i_tcp_read + i_udp_read);
1143 #endif
1144 }
1145
1146 static int  mms_ParseCommand( input_thread_t *p_input,
1147                               uint8_t *p_data,
1148                               int i_data,
1149                               int *pi_used )
1150 {
1151  #define GET32( i_pos ) \
1152     ( p_sys->p_cmd[i_pos] + ( p_sys->p_cmd[i_pos +1] << 8 ) + \
1153       ( p_sys->p_cmd[i_pos + 2] << 16 ) + \
1154       ( p_sys->p_cmd[i_pos + 3] << 24 ) )
1155
1156     access_sys_t        *p_sys = p_input->p_access_data;
1157     int         i_length;
1158     uint32_t    i_id;
1159
1160     if( p_sys->p_cmd )
1161     {
1162         free( p_sys->p_cmd );
1163     }
1164     p_sys->i_cmd = i_data;
1165     p_sys->p_cmd = malloc( i_data );
1166     memcpy( p_sys->p_cmd, p_data, i_data );
1167
1168     *pi_used = i_data; /* by default */
1169
1170     if( i_data < MMS_CMD_HEADERSIZE )
1171     {
1172         msg_Warn( p_input, "truncated command (header incomplete)" );
1173         p_sys->i_command = 0;
1174         return( -1 );
1175     }
1176     i_id =  GetDWLE( p_data + 4 );
1177     i_length = GetDWLE( p_data + 8 ) + 16;
1178
1179     if( i_id != 0xb00bface )
1180     {
1181         msg_Err( p_input,
1182                  "incorrect command header (0x%x)", i_id );
1183         p_sys->i_command = 0;
1184         return( -1 );
1185     }
1186
1187     if( i_length > p_sys->i_cmd )
1188     {
1189         msg_Warn( p_input,
1190                   "truncated command (missing %d bytes)",
1191                    i_length - i_data  );
1192         p_sys->i_command = 0;
1193         return( -1 );
1194     }
1195     else if( i_length < p_sys->i_cmd )
1196     {
1197         p_sys->i_cmd = i_length;
1198         *pi_used = i_length;
1199     }
1200
1201     msg_Dbg( p_input,
1202              "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",
1203              GET32( 0 ),
1204              GET32( 4 ),
1205              GET32( 8 ),
1206              /* 12: protocol type "MMS " */
1207              GET32( 16 ),
1208              GET32( 20 ),
1209              /* 24: unknown (0) */
1210              /* 28: unknown (0) */
1211              GET32( 32 ),
1212              GET32( 36 )
1213              /* 40: switches */
1214              /* 44: extra */ );
1215
1216     p_sys->i_command = GET32( 36 ) & 0xffff;
1217
1218     return( MMS_PACKET_CMD );
1219 }
1220
1221 static int  mms_ParsePacket( input_thread_t *p_input,
1222                              uint8_t *p_data, size_t i_data,
1223                              int *pi_used )
1224 {
1225     access_sys_t        *p_sys = p_input->p_access_data;
1226     int i_packet_seq_num;
1227     size_t i_packet_length;
1228     uint32_t i_packet_id;
1229
1230     uint8_t  *p_packet;
1231
1232
1233     *pi_used = i_data; /* default */
1234     if( i_data <= 8 )
1235     {
1236         msg_Warn( p_input, "truncated packet (header incomplete)" );
1237         return( -1 );
1238     }
1239
1240     i_packet_id = p_data[4];
1241     i_packet_seq_num = GetDWLE( p_data );
1242     i_packet_length = GetWLE( p_data + 6 );
1243
1244     //msg_Warn( p_input, "------->i_packet_length=%d, i_data=%d", i_packet_length, i_data );
1245
1246     if( i_packet_length > i_data || i_packet_length <= 8)
1247     {
1248         msg_Dbg( p_input,
1249                  "truncated packet (missing %d bytes)",
1250                  i_packet_length - i_data  );
1251         *pi_used = 0;
1252         return( -1 );
1253     }
1254     else if( i_packet_length < i_data )
1255     {
1256         *pi_used = i_packet_length;
1257     }
1258
1259     if( i_packet_id == 0xff )
1260     {
1261         msg_Warn( p_input,
1262                   "receive MMS UDP pair timing" );
1263         return( MMS_PACKET_UDP_TIMING );
1264     }
1265
1266     if( i_packet_id != p_sys->i_header_packet_id_type &&
1267         i_packet_id != p_sys->i_media_packet_id_type )
1268     {
1269         msg_Warn( p_input, "incorrect Packet Id Type (0x%x)", i_packet_id );
1270         return( -1 );
1271     }
1272
1273     /* we now have a media or a header packet */
1274     p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader
1275     memcpy( p_packet, p_data + 8, i_packet_length - 8 );
1276
1277     if( i_packet_seq_num != p_sys->i_packet_seq_num )
1278     {
1279         /* FIXME for udp could be just wrong order ? */
1280         msg_Warn( p_input,
1281                   "detected packet lost (%d != %d)",
1282                   i_packet_seq_num,
1283                   p_sys->i_packet_seq_num );
1284         p_sys->i_packet_seq_num = i_packet_seq_num;
1285     }
1286     p_sys->i_packet_seq_num++;
1287
1288     if( i_packet_id == p_sys->i_header_packet_id_type )
1289     {
1290         if( p_sys->p_header )
1291         {
1292             p_sys->p_header = realloc( p_sys->p_header,
1293                                           p_sys->i_header + i_packet_length - 8 );
1294             memcpy( &p_sys->p_header[p_sys->i_header],
1295                     p_packet,
1296                     i_packet_length - 8 );
1297             p_sys->i_header += i_packet_length - 8;
1298
1299             free( p_packet );
1300         }
1301         else
1302         {
1303             p_sys->p_header = p_packet;
1304             p_sys->i_header = i_packet_length - 8;
1305         }
1306 /*        msg_Dbg( p_input,
1307                  "receive header packet (%d bytes)",
1308                  i_packet_length - 8 ); */
1309
1310         return( MMS_PACKET_HEADER );
1311     }
1312     else
1313     {
1314         FREE( p_sys->p_media );
1315         p_sys->p_media = p_packet;
1316         p_sys->i_media = i_packet_length - 8;
1317         p_sys->i_media_used = 0;
1318 /*        msg_Dbg( p_input,
1319                  "receive media packet (%d bytes)",
1320                  i_packet_length - 8 ); */
1321
1322         return( MMS_PACKET_MEDIA );
1323     }
1324 }
1325
1326 static int mms_ReceivePacket( input_thread_t *p_input )
1327 {
1328     access_sys_t        *p_sys = p_input->p_access_data;
1329     int i_packet_tcp_type;
1330     int i_packet_udp_type;
1331
1332     for( ;; )
1333     {
1334         if( NetFillBuffer( p_input ) < 0 )
1335         {
1336             msg_Warn( p_input, "cannot fill buffer" );
1337             continue;
1338         }
1339
1340         i_packet_tcp_type = -1;
1341         i_packet_udp_type = -1;
1342
1343         if( p_sys->i_buffer_tcp > 0 )
1344         {
1345             int i_used;
1346
1347             if( GetDWLE( p_sys->buffer_tcp + 4 ) == 0xb00bface )
1348             {
1349                 i_packet_tcp_type =
1350                     mms_ParseCommand( p_input,
1351                                       p_sys->buffer_tcp,
1352                                       p_sys->i_buffer_tcp,
1353                                       &i_used );
1354
1355             }
1356             else
1357             {
1358                 i_packet_tcp_type =
1359                     mms_ParsePacket( p_input,
1360                                      p_sys->buffer_tcp,
1361                                      p_sys->i_buffer_tcp,
1362                                      &i_used );
1363             }
1364             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
1365             {
1366                 memmove( p_sys->buffer_tcp,
1367                          p_sys->buffer_tcp + i_used,
1368                          MMS_BUFFER_SIZE - i_used );
1369             }
1370             p_sys->i_buffer_tcp -= i_used;
1371         }
1372         else if( p_sys->i_buffer_udp > 0 )
1373         {
1374             int i_used;
1375
1376             i_packet_udp_type =
1377                 mms_ParsePacket( p_input,
1378                                  p_sys->buffer_udp,
1379                                  p_sys->i_buffer_udp,
1380                                  &i_used );
1381
1382             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
1383             {
1384                 memmove( p_sys->buffer_udp,
1385                          p_sys->buffer_udp + i_used,
1386                          MMS_BUFFER_SIZE - i_used );
1387             }
1388             p_sys->i_buffer_udp -= i_used;
1389         }
1390
1391         if( i_packet_tcp_type == MMS_PACKET_CMD &&
1392                 p_sys->i_command == 0x1b )
1393         {
1394             mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
1395             i_packet_tcp_type = -1;
1396         }
1397
1398         if( i_packet_tcp_type != -1 )
1399         {
1400             return( i_packet_tcp_type );
1401         }
1402         else if( i_packet_udp_type != -1 )
1403         {
1404             return( i_packet_udp_type );
1405         }
1406
1407     }
1408 }
1409
1410 static int  mms_ReceiveCommand( input_thread_t *p_input )
1411 {
1412     access_sys_t        *p_sys = p_input->p_access_data;
1413
1414     for( ;; )
1415     {
1416         int i_used;
1417         int i_status;
1418
1419         if( NetFillBuffer( p_input ) < 0 )
1420         {
1421             msg_Warn( p_input, "cannot fill buffer" );
1422             continue;
1423         }
1424         if( p_sys->i_buffer_tcp > 0 )
1425         {
1426             i_status = mms_ParseCommand( p_input,
1427                                   p_sys->buffer_tcp,
1428                                   p_sys->i_buffer_tcp,
1429                                   &i_used );
1430             if( i_used < MMS_BUFFER_SIZE )
1431             {
1432                 memmove( p_sys->buffer_tcp,
1433                          p_sys->buffer_tcp + i_used,
1434                          MMS_BUFFER_SIZE - i_used );
1435             }
1436             p_sys->i_buffer_tcp -= i_used;
1437
1438             if( i_status < 0 )
1439             {
1440                 return( -1 );
1441             }
1442
1443             if( p_sys->i_command == 0x1b )
1444             {
1445                 mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
1446             }
1447             else
1448             {
1449                 break;
1450             }
1451         }
1452         else
1453         {
1454             return( -1 );
1455         }
1456     }
1457
1458     return( 0 );
1459 }
1460
1461 #define MMS_RETRY_MAX       10
1462 #define MMS_RETRY_SLEEP     50000
1463
1464 static int mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 )
1465 {
1466     access_sys_t        *p_sys = p_input->p_access_data;
1467     int i_count;
1468     int i_status;
1469
1470     for( i_count = 0; i_count < MMS_RETRY_MAX; )
1471     {
1472
1473         i_status = mms_ReceiveCommand( p_input );
1474         if( i_status < 0 || p_sys->i_command == 0 )
1475         {
1476             i_count++;
1477             msleep( MMS_RETRY_SLEEP );
1478         }
1479         else if( i_command1 == 0 && i_command2 == 0)
1480         {
1481             return( 0 );
1482         }
1483         else if( p_sys->i_command == i_command1 || p_sys->i_command == i_command2 )
1484         {
1485             return( 0 );
1486         }
1487         else
1488         {
1489             switch( p_sys->i_command )
1490             {
1491                 case 0x03:
1492                     msg_Warn( p_input, "socket closed by server" );
1493                     p_sys->i_eos = 1;
1494                     return( -1 );
1495                 case 0x1e:
1496                     msg_Warn( p_input, "end of media stream" );
1497                     p_sys->i_eos = 1;
1498                     return( -1 );
1499                 default:
1500                     break;
1501             }
1502         }
1503     }
1504     msg_Warn( p_input, "failed to receive command (abording)" );
1505
1506     return( -1 );
1507 }
1508
1509
1510 static int mms_HeaderMediaRead( input_thread_t *p_input, int i_type )
1511 {
1512     access_sys_t        *p_sys = p_input->p_access_data;
1513     int          i_count;
1514
1515     for( i_count = 0; i_count < MMS_RETRY_MAX; )
1516     {
1517         int i_status;
1518
1519         i_status = mms_ReceivePacket( p_input );
1520         if( i_status < 0 )
1521         {
1522             i_count++;
1523             msg_Warn( p_input,
1524                       "cannot receive header (%d/%d)", i_count, MMS_RETRY_MAX );
1525             msleep( MMS_RETRY_SLEEP );
1526         }
1527         else if( i_status == i_type || i_type == MMS_PACKET_ANY )
1528         {
1529             return( i_type );
1530         }
1531         else if( i_status == MMS_PACKET_CMD )
1532         {
1533             switch( p_sys->i_command )
1534             {
1535                 case 0x03:
1536                     msg_Warn( p_input, "socket closed by server" );
1537                     p_sys->i_eos = 1;
1538                     return( -1 );
1539                 case 0x1e:
1540                     msg_Warn( p_input, "end of media stream" );
1541                     p_sys->i_eos = 1;
1542                     return( -1 );
1543                 case 0x20:
1544                     /* XXX not too dificult to be done EXCEPT that we
1545                      * need to restart demuxer... and I don't see how we
1546                      * could do that :p */
1547                     msg_Err( p_input,
1548                              "reinitialization needed --> unsupported" );
1549                     p_sys->i_eos = 1;
1550                     return( -1 );
1551                 default:
1552                     break;
1553             }
1554         }
1555     }
1556     msg_Err( p_input,
1557              "cannot receive %s (abording)",
1558                ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" );
1559     return( -1 );
1560 }
1561