]> git.sesse.net Git - vlc/blob - modules/access/mms/mms.c
* modules/demux/asf/.cvsignore : put the good one.
[vlc] / modules / access / mms / mms.c
1 /*****************************************************************************
2  * mms.c: MMS access plug-in
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: mms.c,v 1.1 2002/11/12 00:54:40 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  * TODO:
27  *  - clean code, break huge code block
28  *  - fix memory leak
29  *  - begin udp support...
30  */
31
32 /*****************************************************************************
33  * Preamble
34  *****************************************************************************/
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <fcntl.h>
41
42 #include <vlc/vlc.h>
43 #include <vlc/input.h>
44
45 #ifdef HAVE_UNISTD_H
46 #   include <unistd.h>
47 #elif defined( _MSC_VER ) && defined( _WIN32 )
48 #   include <io.h>
49 #endif
50
51 #ifdef WIN32
52 #   include <winsock2.h>
53 #   include <ws2tcpip.h>
54 #   ifndef IN_MULTICAST
55 #       define IN_MULTICAST(a) IN_CLASSD(a)
56 #   endif
57 #else
58 #   include <sys/socket.h>
59 #endif
60
61 #include "network.h"
62 #include "asf.h"
63 #include "var_buffer.h"
64 #include "mms.h"
65 /****************************************************************************
66  * NOTES: 
67  *  MMSProtocole documentation found at http://get.to/sdp
68  ****************************************************************************/
69
70 /*****************************************************************************
71  * Local prototypes
72  *****************************************************************************/
73 static int  Open        ( vlc_object_t * );
74 static void Close       ( vlc_object_t * );
75
76 static int  Read        ( input_thread_t * p_input, byte_t * p_buffer,
77                           size_t i_len );
78 static void Seek        ( input_thread_t *, off_t );
79 static int  SetProgram  ( input_thread_t *, pgrm_descriptor_t * );  
80
81
82 static int MMSOpen( input_thread_t  *, url_t *, int, char * );
83
84 static int MMSStart  ( input_thread_t  *, uint32_t );
85 static int MMSStop  ( input_thread_t  *p_input );   // Not used
86
87 static int MMSClose  ( input_thread_t  * );
88
89
90 static int  mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 );
91 static int  mms_CommandSend( input_thread_t *, int, uint32_t, uint32_t, uint8_t *, int );
92
93 static int  mms_HeaderMediaRead( input_thread_t *, int );
94
95 static int  mms_ReceivePacket( input_thread_t * );
96     
97 static void mms_ParseURL( url_t *p_url, char *psz_url );
98
99
100
101 /* 
102  * XXX DON'T FREE MY MEMORY !!! XXX
103  * non mais :P
104  */
105 #define INPUT_FDNETWORKCLOSE( p_input ) \
106     { \
107         void *__p_access = p_input->p_access_data; \
108         input_socket_t *__p_socket = malloc( sizeof( input_socket_t ) ); \
109         memcpy( __p_socket, __p_access, sizeof( input_socket_t ) ); \
110         p_input->p_access_data = (void*)__p_socket; \
111         input_FDNetworkClose( p_input ); \
112         p_input->p_access_data = __p_access; \
113     }
114         
115
116
117 /*****************************************************************************
118  * Module descriptor
119  *****************************************************************************/
120 vlc_module_begin();
121     set_description( _("MMS access module") );
122     set_capability( "access", 0 );
123     add_shortcut( "mms" );
124     add_shortcut( "mmsu" );
125     add_shortcut( "mmst" );
126     set_callbacks( Open, Close );
127 vlc_module_end();
128
129 #define BUF_SIZE 200000
130
131 static int Open( vlc_object_t *p_this )
132 {
133     access_t    *p_access;
134     int         i_proto;
135     char        *psz_network;
136     int         i_status;
137
138     input_thread_t  *p_input = (input_thread_t*)p_this;
139
140     /* *** allocate p_access_data *** */
141     p_input->p_access_data = 
142         (void*)p_access = malloc( sizeof( access_t ) );
143     memset( p_access, 0, sizeof( access_t ) );
144
145     p_access->p_cmd = malloc( BUF_SIZE );
146
147
148     /* *** Parse URL and get server addr/port and path *** */
149     mms_ParseURL( &p_access->url, p_input->psz_name );
150     if( p_access->url.psz_server_addr == NULL || 
151         !( *p_access->url.psz_server_addr ) )
152     {
153         FREE( p_access->url.psz_private );
154         FREE( p_access->p_cmd );
155         msg_Err( p_input, "invalid server name" );
156         return( -1 );
157     }
158     if( p_access->url.i_server_port == 0 )
159     {   
160         p_access->url.i_server_port = 1755; // default port
161     }
162     
163
164     /* *** connect to this server *** */
165     /* 1: look at  requested protocol (udp/tcp) */
166     i_proto = MMS_PROTO_AUTO;
167     if( *p_input->psz_access )
168     {
169         if( !strncmp( p_input->psz_access, "mmsu", 4 ) )
170         {
171             i_proto = MMS_PROTO_UDP;
172         }
173         else if( !strncmp( p_input->psz_access, "mmst", 4 ) )
174         {
175             i_proto = MMS_PROTO_TCP;
176         }
177     }
178     /* 2: look at ip version ipv4/ipv6 */
179     psz_network = "";
180     if( config_GetInt( p_input, "ipv4" ) )
181     {
182         psz_network = "ipv4";
183     }
184     else if( config_GetInt( p_input, "ipv6" ) )
185     {
186         psz_network = "ipv6";
187     }
188     /* 3: connect */
189     if( i_proto == MMS_PROTO_AUTO )
190     {   // first try with TCP
191         i_status = 
192             MMSOpen( p_input, &p_access->url, MMS_PROTO_TCP, psz_network );
193         if( i_status < 0 )
194         {   // then with UDP
195             i_status = 
196              MMSOpen( p_input, &p_access->url, MMS_PROTO_UDP, psz_network );
197         }
198     }
199     else
200     {
201
202         i_status = 
203             MMSOpen( p_input, &p_access->url, i_proto, psz_network );
204     }
205
206     if( i_status < 0 )
207     {
208         // all sockets are closed
209         msg_Err( p_input, "cannot connect to server" );
210         FREE( p_access->url.psz_private );
211         FREE( p_access->p_cmd );
212         return( -1 );
213     }
214     msg_Dbg( p_input, "connected to %s", p_access->url.psz_server_addr );
215
216     // all sockets are open
217     
218     
219     /* *** set exported functions *** */
220     p_input->pf_read = Read;
221     p_input->pf_seek = Seek;
222     p_input->pf_set_program = SetProgram;
223     p_input->pf_set_area = NULL;
224     
225     p_input->p_private = NULL; // XXX ??
226
227     /* *** finished to set some variable *** */
228     vlc_mutex_lock( &p_input->stream.stream_lock );
229     /* those data could be different for UDP/TCP */
230     p_input->stream.b_pace_control = 0;
231     p_input->stream.p_selected_area->i_tell = 0;
232     if( p_access->i_packet_count <= 0 )
233     {
234         p_input->stream.b_seekable = 0;
235         p_input->stream.p_selected_area->i_size = 0;
236     }
237     else
238     {
239         p_input->stream.b_seekable = 0;
240         p_input->stream.p_selected_area->i_size = 
241             p_access->i_header + 
242             p_access->i_packet_count * p_access->i_packet_length;
243     }
244     
245     p_input->stream.i_method = INPUT_METHOD_NETWORK;
246     vlc_mutex_unlock( &p_input->stream.stream_lock );
247
248     /* *** Start stream *** */
249     if( MMSStart( p_input, 0xffffffff ) < 0 )
250     {
251         msg_Err( p_input, "cannot start stream" );
252         MMSClose( p_input );
253         FREE( p_access->url.psz_private );
254         FREE( p_access->p_cmd );
255         return( -1 );
256     }
257                            
258     return( 0 );
259 }
260
261 /*****************************************************************************
262  * Close: free unused data structures
263  *****************************************************************************/
264 static void Close( vlc_object_t *p_this )
265 {
266     input_thread_t *  p_input = (input_thread_t *)p_this;
267     access_t    *p_access = (access_t*)p_input->p_access_data;
268     
269     /* close connection with server */
270     MMSClose( p_input );
271     
272     /* free memory */
273     FREE( p_access->url.psz_private );
274     FREE( p_access->p_cmd );
275 }
276
277 /*****************************************************************************
278  * SetProgram: do nothing
279  *****************************************************************************/
280 static int SetProgram( input_thread_t * p_input,
281                        pgrm_descriptor_t * p_program )
282 {
283     return( 0 );
284 }
285
286 /*****************************************************************************
287  * Seek: try to go at the right place
288  *****************************************************************************/
289 static void Seek( input_thread_t * p_input, off_t i_pos )
290 {
291     /* 
292      * FIXME  
293      * Don't work
294      * Probably some bad or missing command
295      *
296      * 
297      */
298 #if 0
299
300     access_t    *p_access = (access_t*)p_input->p_access_data;
301     uint32_t    i_packet;
302     uint32_t    i_offset;
303     
304     if( i_pos < 0 )
305     {
306         return;
307     }    
308     msg_Dbg( p_input, "seeking to %lld, header size:%d", i_pos, p_access->i_header );
309     if( i_pos < p_access->i_header)
310     {
311
312         if( p_access->i_pos < p_access->i_header )
313         {
314             /* no need to restart stream, it was already one 
315              * or no stream was yet read */
316             p_access->i_pos = i_pos;
317             return;
318         }
319         else
320         {
321             i_packet = 0xffffffff;
322             i_offset = 0;
323         }
324     }
325     else
326     {
327         i_packet = ( i_pos - p_access->i_header ) / p_access->i_packet_length;
328         i_offset = ( i_pos - p_access->i_header ) % p_access->i_packet_length;
329     }
330
331     MMSStop( p_input );
332     MMSStart( p_input, i_packet );
333     p_access->i_media_used += i_offset;
334     p_access->i_pos = i_pos;
335 #endif
336 }
337
338 static int  Read        ( input_thread_t * p_input, byte_t * p_buffer,
339                           size_t i_len )
340 {
341     access_t    *p_access = (access_t*)p_input->p_access_data;
342     size_t      i_data;
343     size_t      i_copy;
344
345     i_data = 0;
346     
347     /* *** send header if needed ** */
348     if( p_access->i_pos < p_access->i_header )
349     { 
350         i_copy = __MIN( i_len, p_access->i_header - p_access->i_pos );
351         if( i_copy > 0 )
352         {
353             memcpy( p_buffer, 
354                     p_access->p_header + p_access->i_pos,
355                     i_copy );
356         }
357         i_data += i_copy;
358     }
359
360     /* *** now send data if needed *** */
361     while( i_data < i_len )
362     {
363         if( p_access->i_media_used < p_access->i_media )
364         {
365             i_copy = __MIN( i_len - i_data , 
366                             p_access->i_media - p_access->i_media_used );
367             memcpy( p_buffer + i_data, 
368                     p_access->p_media + p_access->i_media_used,
369                     i_copy );
370             i_data += i_copy;
371             p_access->i_media_used += i_copy;
372         }
373         else if( p_access->p_media != NULL && 
374                  p_access->i_media_used < p_access->i_packet_length )
375         {
376             i_copy = __MIN( i_len - i_data,
377                             p_access->i_packet_length - p_access->i_media_used);
378             memset( p_buffer + i_data, 0, i_copy );
379
380             i_data += i_copy;
381             p_access->i_media_used += i_copy;
382         }
383         else
384         {
385             if( mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA ) < 0 );
386             {
387                 p_access->i_pos += i_data;
388                 return( i_data );
389             }
390         }
391     }
392
393     p_access->i_pos += i_data;
394     return( i_data );
395 }
396
397
398 static void asf_HeaderParse( mms_stream_t stream[128],
399                              uint8_t *p_header, int i_header )
400 {
401     var_buffer_t buffer;
402     guid_t      guid;
403     uint64_t    i_size;
404     int         i;
405     
406     for( i = 0; i < 128; i++ )
407     {
408         stream[i].i_cat = MMS_STREAM_UNKNOWN;
409     }
410
411     var_buffer_initread( &buffer, p_header, i_header );
412     
413     var_buffer_getguid( &buffer, &guid );
414     if( !CmpGuid( &guid, &asf_object_header_guid ) )
415     {
416 //        XXX Error
417     }
418     var_buffer_getmemory( &buffer, NULL, 30 - 16 );
419     
420     for( ;; )
421     {
422         if( var_buffer_readempty( &buffer ) )
423         {
424             return;
425         }
426
427         var_buffer_getguid( &buffer, &guid );
428         i_size = var_buffer_get64( &buffer );
429         if( CmpGuid( &guid, &asf_object_stream_properties_guid ) )
430         {
431             int     i_stream_id;
432             guid_t  stream_type;
433
434 //            msg_Dbg( p_input, "found stream_properties" );
435             
436             var_buffer_getguid( &buffer, &stream_type );
437             var_buffer_getmemory( &buffer, NULL, 32 );
438             i_stream_id = var_buffer_get8( &buffer ) & 0x7f;
439             var_buffer_getmemory( &buffer, NULL, i_size - 24 - 32 - 16 - 1 );
440             
441             if( CmpGuid( &stream_type, &asf_object_stream_type_video ) )
442             {
443 //                msg_Dbg( p_input, "video stream[%d] found", i_stream_id );
444                 stream[i_stream_id].i_cat = MMS_STREAM_VIDEO;
445             }
446             else if( CmpGuid( &stream_type, &asf_object_stream_type_audio ) )
447             {
448 //                msg_Dbg( p_input, "audio stream[%d] found", i_stream_id );
449                 stream[i_stream_id].i_cat = MMS_STREAM_AUDIO;
450             }
451             else
452             {
453 //                msg_Dbg( p_input, "unknown stream[%d] found", i_stream_id );
454                 stream[i_stream_id].i_cat = MMS_STREAM_UNKNOWN;
455             }
456         }
457         else if ( CmpGuid( &guid, &asf_object_bitrate_properties_guid ) )
458         {
459             int     i_count;
460             uint8_t i_stream_id;
461             
462             i_count = var_buffer_get16( &buffer );
463             i_size -= 2;
464             while( i_count > 0 )
465             {
466                 i_stream_id = var_buffer_get16( &buffer )&0x7f;
467                 stream[i_stream_id].i_bitrate =  var_buffer_get32( &buffer );
468                 i_count--;
469                 i_size -= 6;
470             }
471             var_buffer_getmemory( &buffer, NULL, i_size - 24 );
472         }
473         else            
474         {
475             // skip unknown guid
476             var_buffer_getmemory( &buffer, NULL, i_size - 24 );
477         }
478     }
479 }
480
481 /****************************************************************************
482  * MMSOpen : Open a connection with the server over mmst or mmsu(not yet)
483  ****************************************************************************/
484 static int MMSOpen( input_thread_t  *p_input,
485                        url_t *p_url,
486                        int  i_proto,
487                        char *psz_network ) /* "", "ipv4", "ipv6" */
488 {
489     module_t    *p_network;
490     access_t    *p_access = (access_t*)p_input->p_access_data;
491
492     network_socket_t    socket_desc;
493     int b_udp = ( i_proto == MMS_PROTO_UDP ) ? 1 : 0;
494
495     var_buffer_t buffer;
496     char         tmp[4096];
497     uint16_t     *p;
498     int          i_server_version;
499     int          i_tool_version;
500     int          i_update_player_url;
501     int          i_encryption_type;
502     int          i;
503     int          i_streams;
504     int          i_first;
505     int          b_audio;
506     int          b_video;
507
508
509     /* *** Open a TCP connection with server *** */
510     msg_Dbg( p_input, "waiting for connection..." );
511     socket_desc.i_type = NETWORK_TCP;
512     socket_desc.psz_server_addr = p_url->psz_server_addr;
513     socket_desc.i_server_port   = p_url->i_server_port;
514     socket_desc.psz_bind_addr   = "";
515     socket_desc.i_bind_port     = 0;
516     p_input->p_private = (void*)&socket_desc;
517     if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
518     {
519         msg_Err( p_input, "failed to open a connection" );
520         return( -1 );
521     }
522     module_Unneed( p_input, p_network );
523     p_access->socket_server.i_handle = socket_desc.i_handle;
524     p_input->i_mtu    = socket_desc.i_mtu;  // FIXME
525     msg_Dbg( p_input, 
526              "connection with \"%s:%d\" successful",
527              p_url->psz_server_addr,
528              p_url->i_server_port );
529
530     /* *** Bind port if UDP protocol is selected *** */
531     // TODO
532     if( b_udp )
533     {
534         msg_Err( p_input,
535                  "MMS/UDP not yet implemented" );
536         // close socket
537         p_access->_socket = p_access->socket_server;
538         INPUT_FDNETWORKCLOSE( p_input );
539         return( -1 );
540     }
541     /* *** Default socket is the one for server communication *** */
542     p_access->_socket = p_access->socket_server;
543
544     /* *** Init context for mms prototcol *** */
545     GenerateGuid( &p_access->guid );    // used to identify client by server
546     msg_Dbg( p_input, 
547              "generated guid: "GUID_FMT, 
548              GUID_PRINT( p_access->guid ) );
549     p_access->i_command_level = 1;          // updated after 0x1A command 
550     p_access->i_seq_num = 0;
551     p_access->i_media_packet_id_type  = 0x04;
552     p_access->i_header_packet_id_type = 0x02;
553     p_access->i_proto = i_proto;
554     p_access->i_packet_seq_num = 0;
555     p_access->p_header = NULL;
556     p_access->i_header = 0;
557     p_access->p_media = NULL;
558     p_access->i_media = 0;
559     p_access->i_media_used = 0;
560
561     p_access->i_pos = 0;
562
563     /* *** send command 1 : connection request *** */
564     var_buffer_initwrite( &buffer, 0 );
565     var_buffer_add16( &buffer, 0x001c );
566     var_buffer_add16( &buffer, 0x0003 );
567     sprintf( tmp, 
568              "NSPlayer/7.0.0.1956; {"GUID_FMT"}; Host: %s",
569              GUID_PRINT( p_access->guid ),
570              p_url->psz_server_addr );
571     var_buffer_addUTF16( &buffer, tmp );
572     
573     mms_CommandSend( p_input,
574                      0x01,          /* connexion request */
575                      0x00000000,    /* flags, FIXME */
576                      0x0004000b,    /* ???? */
577                      buffer.p_data,
578                      buffer.i_data );
579
580     mms_CommandRead( p_input, 0x01, 0 );
581     i_server_version = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 32 );
582     i_tool_version = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 36 );
583     i_update_player_url = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 40 );
584     i_encryption_type = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 44 );
585     p = (uint16_t*)( p_access->p_cmd + MMS_CMD_HEADERSIZE + 48 );
586 #define GETUTF16( psz, size ) \
587     { \
588         int i; \
589         psz = malloc( size + 1); \
590         for( i = 0; i < size; i++ ) \
591         { \
592             psz[i] = p[i]; \
593         } \
594         psz[size] = '\0'; \
595         p += 2 * ( size ); \
596     }
597     GETUTF16( p_access->psz_server_version, i_server_version );
598     GETUTF16( p_access->psz_tool_version, i_tool_version );
599     GETUTF16( p_access->psz_update_player_url, i_update_player_url );
600     GETUTF16( p_access->psz_encryption_type, i_encryption_type );
601 #undef GETUTF16
602     msg_Dbg( p_input, 
603              "0x01 --> server_version:\"%s\" tool_version:\"%s\" update_player_url:\"%s\" encryption_type:\"%s\"",
604              p_access->psz_server_version,
605              p_access->psz_tool_version,
606              p_access->psz_update_player_url,
607              p_access->psz_encryption_type );
608
609     /* *** should make an 18 command to make data timing *** */
610     
611     /* *** send command 2 : transport protocol selection *** */
612     var_buffer_reinitwrite( &buffer, 0 );
613     var_buffer_add32( &buffer, 0x00000000 );
614     var_buffer_add32( &buffer, 0x000a0000 );
615     var_buffer_add32( &buffer, 0x00000002 );
616     // FIXME wrong for UDP FIXME
617     sprintf( tmp, "\\\\127.0.0.1\\%s\\1242", b_udp ? "UDP" : "TCP" );
618     var_buffer_addUTF16( &buffer, tmp );
619     var_buffer_add16( &buffer, '0' );
620     
621     mms_CommandSend( p_input,
622                      0x02,          /* connexion request */
623                      0x00000000,    /* flags, FIXME */
624                      0xffffffff,    /* ???? */
625                      buffer.p_data,
626                      buffer.i_data );
627
628     /* *** response from server, should be 0x02 or 0x03 *** */
629     mms_CommandRead( p_input, 0x02, 0 );
630     if( p_access->i_command == 0x03 )
631     {
632         msg_Err( p_input, 
633                  "%s protocol selection failed", b_udp ? "UDP" : "TCP" );
634         var_buffer_free( &buffer );
635         MMSClose( p_input );
636         return( -1 );
637     }
638     else if( p_access->i_command != 0x02 )
639     {
640         msg_Warn( p_input, "received command isn't 0x02 in reponse to 0x02" );
641     }
642     
643     /* *** send command 5 : media file name/path requested *** */
644     var_buffer_reinitwrite( &buffer, 0 );
645     var_buffer_add64( &buffer, 0 );
646 //    var_buffer_addUTF16( &buffer, "/" );
647     var_buffer_addUTF16( &buffer, p_url->psz_path );
648     
649     mms_CommandSend( p_input, 
650                      0x05,
651                      p_access->i_command_level,
652                      0xffffffff,
653                      buffer.p_data,
654                      buffer.i_data );
655
656     /* *** wait for reponse *** */
657     mms_CommandRead( p_input, 0x1a, 0x06 );
658     
659     /* test if server send 0x1A answer */
660     if( p_access->i_command == 0x1A )
661     {
662         msg_Err( p_input, "id/password requested (not yet supported)" );
663         // FIXME
664         var_buffer_free( &buffer );
665         MMSClose( p_input );
666         return( -1 );
667     }
668     if( p_access->i_command != 0x06 )
669     {
670         msg_Err( p_input, 
671                  "unknown answer (0x%x instead of 0x06)",
672                  p_access->i_command );
673         var_buffer_free( &buffer );
674         MMSClose( p_input );
675         return( -1 );
676     }
677
678     // 1 for file ok, 2 for authen ok
679     switch( GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE ) )
680     {
681         case 0x0001:
682             msg_Dbg( p_input, "Media file name/path accepted" );
683             break;
684         case 0x0002:
685             msg_Dbg( p_input, "Authentication accepted" );
686             break;
687         case -1:
688         default:
689         msg_Err( p_input, "error while asking for file %d",
690                  GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE ) );
691         var_buffer_free( &buffer );
692         MMSClose( p_input );
693         return( -1 );
694     }
695
696     p_access->i_flags_broadcast = 
697         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 12 );
698     p_access->i_media_length =
699         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 24 );
700     p_access->i_packet_length =
701         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 44 );
702     p_access->i_packet_count =
703         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 48 );
704     p_access->i_max_bit_rate =
705         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 56 );
706     p_access->i_header_size =
707         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 60 );
708
709     msg_Dbg( p_input,
710              "answer 0x06 flags:0x%8.8x media_length:%ds packet_length:%d packet_count:%d max_bit_rate:%d header_size:%d",
711              p_access->i_flags_broadcast,
712              p_access->i_media_length,
713              p_access->i_packet_length,
714              p_access->i_packet_count,
715              p_access->i_max_bit_rate,
716              p_access->i_header_size );
717     
718     /* *** send command 15 *** */
719     
720     var_buffer_reinitwrite( &buffer, 0 );
721     var_buffer_add32( &buffer, 0 );
722     var_buffer_add32( &buffer, 0x8000 );
723     var_buffer_add32( &buffer, 0xffffffff );
724     var_buffer_add32( &buffer, 0x00 );
725     var_buffer_add32( &buffer, 0x00 );
726     var_buffer_add32( &buffer, 0x00 );
727     var_buffer_add64( &buffer, 0x40ac200000000000 );
728     var_buffer_add32( &buffer, p_access->i_header_packet_id_type );
729     mms_CommandSend( p_input, 0x15, p_access->i_command_level, 0x00, 
730                      buffer.p_data, buffer.i_data );
731
732     /* *** wait for reponse *** */
733     mms_CommandRead( p_input, 0x11, 0 );
734
735     if( p_access->i_command != 0x11 )
736     {
737         msg_Err( p_input, 
738                  "unknown answer (0x%x instead of 0x11)",
739                  p_access->i_command );
740         var_buffer_free( &buffer );
741         MMSClose( p_input );
742         return( -1 );
743     }
744     /* *** now read header packet *** */
745     if( mms_HeaderMediaRead( p_input, MMS_PACKET_HEADER ) < 0 )
746     {
747         msg_Err( p_input, "cannot receive header" );
748         var_buffer_free( &buffer );
749         MMSClose( p_input );
750         return( -1 );
751     }
752     /* *** parse header and get stream and their id *** */
753     // get all streams properties, 
754     // 
755     // TODO : stream bitrates properties(optional)
756     //        and bitrate mutual exclusion(optional)
757     asf_HeaderParse( p_access->stream, 
758                      p_access->p_header, p_access->i_header );
759     
760     /* *** now select stream we want to receive *** */
761     // TODO take care of stream bitrate TODO
762     i_streams = 0;
763     i_first = -1;
764     var_buffer_reinitwrite( &buffer, 0 );
765     /* for now, select first audio and video stream */
766     b_audio = 0;
767     b_video = 0;
768     for( i = 1; i < 128; i++ )
769     {
770
771         if( ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO && !b_audio )||
772             ( p_access->stream[i].i_cat == MMS_STREAM_VIDEO && !b_video ) )
773         {
774             i_streams++;
775             if( i_first == -1 )
776             {   
777                 i_first = i;
778                 var_buffer_add16( &buffer, 0x0000 ); // on
779             }   
780             else
781             {
782                 var_buffer_add16( &buffer, 0xffff );
783                 var_buffer_add16( &buffer, i );
784                 var_buffer_add16( &buffer, 0x0000 );
785             }
786             msg_Info( p_input, 
787                       "selecting stream[0x%x] %s (%d kb/s)",
788                       i,
789                       ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO  ) ? 
790                         "audio" : "video" ,
791                         p_access->stream[i].i_bitrate / 1024);
792             if( p_access->stream[i].i_cat == MMS_STREAM_AUDIO )
793             {
794                 b_audio = 1;
795             }
796             if( p_access->stream[i].i_cat == MMS_STREAM_VIDEO )
797             {
798                 b_video = 1;
799             }
800
801         }
802         else if( p_access->stream[i].i_cat != MMS_STREAM_UNKNOWN )
803         {
804             msg_Info( p_input, 
805                       "ignoring stream[0x%x] %s (%d kb/s)",
806                       i,
807                       ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO  ) ? 
808                         "audio" : "video" ,
809                        p_access->stream[i].i_bitrate / 1024);
810         }
811     } 
812
813     if( i_streams == 0 )
814     {
815         msg_Err( p_input, "cannot find any stream" );
816         var_buffer_free( &buffer );
817         MMSClose( p_input );
818         return( -1 );
819     }
820     mms_CommandSend( p_input, 0x33,
821                      i_streams,
822                      0xffff | ( i_first << 16 ),
823                      buffer.p_data, buffer.i_data );
824     
825     mms_CommandRead( p_input, 0x21, 0 );
826     if( p_access->i_command != 0x21 )
827     {
828         msg_Err( p_input, 
829                  "unknown answer (0x%x instead of 0x21)", 
830                  p_access->i_command );
831         var_buffer_free( &buffer );
832         MMSClose( p_input );
833         return( -1 );
834     }
835
836
837     var_buffer_free( &buffer );
838
839     msg_Info( p_input, "connection sucessful" );
840
841     return( 0 );
842 }
843
844 /****************************************************************************
845  * MMSStart : Start streaming
846  ****************************************************************************/
847 static int MMSStart  ( input_thread_t  *p_input, uint32_t i_packet )
848 {
849     access_t        *p_access = (access_t*)p_input->p_access_data;
850     var_buffer_t    buffer;
851
852     /* *** start stream from packet 0 *** */
853     var_buffer_initwrite( &buffer, 0 );
854     var_buffer_add64( &buffer, 0 ); // seek point in second
855     var_buffer_add32( &buffer, 0xffffffff ); 
856 //    var_buffer_add32( &buffer, 0xffffffff ); // begin from start
857     var_buffer_add32( &buffer, i_packet ); // begin from start
858     var_buffer_add8( &buffer, 0xff ); // stream time limit
859     var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
860     var_buffer_add8( &buffer, 0xff ); //
861     var_buffer_add8( &buffer, 0x00 ); // don't use limit
862     var_buffer_add32( &buffer, p_access->i_media_packet_id_type ); 
863     
864     mms_CommandSend( p_input, 0x07, p_access->i_command_level, 0x0001ffff, 
865                      buffer.p_data, buffer.i_data );
866     
867     var_buffer_free( &buffer );
868     
869     mms_CommandRead( p_input, 0x05, 0 );
870
871     if( p_access->i_command != 0x05 )
872     {
873         msg_Err( p_input, 
874                  "unknown answer (0x%x instead of 0x05)", 
875                  p_access->i_command );
876         return( -1 );
877     }
878     else
879     {   
880         /* get a packet */
881         mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA );
882         msg_Dbg( p_input, "Streaming started" );
883         return( 0 );
884     }
885 }
886
887 /****************************************************************************
888  * MMSStop : Stop streaming
889  ****************************************************************************/
890 static int MMSStop  ( input_thread_t  *p_input )
891 {
892     access_t        *p_access = (access_t*)p_input->p_access_data;
893
894     /* *** stop stream but keep connection alive *** */    
895     mms_CommandSend( p_input,
896                      0x09,
897                      p_access->i_command_level,
898                      0x001fffff,
899                      NULL, 0 );
900     return( 0 );
901 }
902
903 /****************************************************************************
904  * MMSClose : Close streaming and connection
905  ****************************************************************************/
906 static int MMSClose  ( input_thread_t  *p_input )
907 {
908     access_t        *p_access = (access_t*)p_input->p_access_data;
909
910     msg_Dbg( p_input, "Connection closed" );
911
912     /* *** tell server that we will disconnect *** */    
913     mms_CommandSend( p_input,
914                      0x0d,
915                      p_access->i_command_level,
916                      0x00000001,
917                      NULL, 0 );
918     /* *** close sockets *** */
919     p_access->_socket = p_access->socket_server;
920     INPUT_FDNETWORKCLOSE( p_input );
921
922     if( p_access->i_proto == MMS_PROTO_UDP )
923     {
924         p_access->_socket = p_access->socket_data;
925         INPUT_FDNETWORKCLOSE( p_input );
926     }
927     
928     FREE( p_access->p_media );
929     FREE( p_access->p_header );
930
931     FREE( p_access->psz_server_version );
932     FREE( p_access->psz_tool_version );
933     FREE( p_access->psz_update_player_url );
934     FREE( p_access->psz_encryption_type );
935
936     return( 0 );
937 }
938
939 /*****************************************************************************
940  * mms_ParseURL : parse an url string and fill an url_t 
941  *****************************************************************************/
942 static void mms_ParseURL( url_t *p_url, char *psz_url )
943 {
944     char *psz_parser;
945     char *psz_server_port;
946
947     p_url->psz_private = strdup( psz_url );
948     
949     psz_parser = p_url->psz_private;
950     
951     while( *psz_parser == '/' )
952     {
953         psz_parser++;
954     }
955     p_url->psz_server_addr = psz_parser;
956
957     while( *psz_parser && *psz_parser != ':' && *psz_parser != '/' )
958     {
959         psz_parser++;
960     } 
961
962     if( *psz_parser == ':' )
963     {
964         *psz_parser = '\0';
965         psz_parser++;
966         psz_server_port = psz_parser;
967
968         while( *psz_parser && *psz_parser != '/' )
969         {
970             psz_parser++;
971         }
972     }
973     else
974     {
975         psz_server_port = "";
976     }
977     if( *psz_parser == '/' )
978     {
979         *psz_parser = '\0';
980         psz_parser++;
981         p_url->psz_path = psz_parser;
982     }
983     
984     if( *psz_server_port )
985     {
986         p_url->i_server_port = strtol( psz_server_port, &psz_parser, 10 );
987     }
988     else
989     {
990         p_url->i_server_port = 0;
991     }
992 }
993
994 static int mms_ReadData( input_thread_t *p_input,
995                          uint8_t  *p_data,
996                          int i_data )
997 {
998     int i_read;
999
1000     while( i_data > 0 )
1001     {
1002         i_read = input_FDNetworkRead( p_input, p_data, i_data );
1003         if( i_read < 0 )
1004         {
1005             msg_Err( p_input, "failed to read data" );
1006             return( -1 );
1007         }
1008         i_data -= i_read;
1009         p_data += i_read;
1010     }
1011     return( 0 );
1012 }
1013
1014
1015 /****************************************************************************
1016  *
1017  * MMS specific functions
1018  *
1019  ****************************************************************************/
1020
1021 static int mms_CommandSend( input_thread_t *p_input, 
1022                              int i_command, 
1023                              uint32_t i_prefix1, uint32_t i_prefix2, 
1024                              uint8_t *p_data, int i_data )
1025 {
1026     var_buffer_t buffer;
1027
1028     access_t    *p_access = (access_t*)p_input->p_access_data;
1029     int i_data_by8;
1030     
1031     i_data_by8 = ( i_data + 7 ) / 8;
1032
1033     /* first init uffer */
1034     var_buffer_initwrite( &buffer, 0 );
1035
1036     var_buffer_add32( &buffer, 0x00000001 );    // start sequence
1037     var_buffer_add32( &buffer, 0xB00BFACE );    // ...
1038     // size after protocol type
1039     var_buffer_add32( &buffer, i_data + MMS_CMD_HEADERSIZE - 16 );     
1040     var_buffer_add32( &buffer, 0x20534d4d );    // protocol "MMS "
1041     var_buffer_add32( &buffer, i_data_by8 + 4 );
1042     var_buffer_add32( &buffer, p_access->i_seq_num ); p_access->i_seq_num++;
1043     var_buffer_add64( &buffer, 0 );
1044     var_buffer_add32( &buffer, i_data_by8 + 2 );
1045     var_buffer_add32( &buffer, 0x00030000 | i_command ); /* dir | command */
1046     var_buffer_add32( &buffer, i_prefix1 );    /* command specific */
1047     var_buffer_add32( &buffer, i_prefix2 );    /* command specific */
1048
1049     /* specific command data */
1050     if( p_data && i_data > 0 )
1051     {
1052         var_buffer_addmemory( &buffer, p_data, i_data );
1053     }
1054
1055     /* send it */
1056     if( send( p_access->_socket.i_handle, 
1057               buffer.p_data, 
1058               buffer.i_data,
1059               0 ) == -1 )
1060     {
1061         msg_Err( p_input, "failed to send command" );
1062         return( -1 );
1063     }
1064
1065     var_buffer_free( &buffer );
1066     return( 0 );
1067 }   
1068
1069 static int  mms_ReceiveCommand( input_thread_t *p_input )
1070 {
1071 #define GET32( i_pos ) \
1072     ( p_access->p_cmd[i_pos] + ( p_access->p_cmd[i_pos +1] << 8 ) + \
1073       ( p_access->p_cmd[i_pos + 2] << 16 ) + \
1074       ( p_access->p_cmd[i_pos + 3] << 24 ) )
1075
1076     access_t    *p_access = (access_t*)p_input->p_access_data;
1077
1078     do
1079     {
1080         int i_length;
1081         // see for UDP mode
1082
1083         /* *** Read complete command *** */
1084         p_access->i_cmd = 
1085             input_FDNetworkRead( p_input, p_access->p_cmd, BUF_SIZE );
1086         if( p_access->i_cmd < 12 )
1087         {
1088             msg_Warn( p_input, "failed to receive command" );
1089             p_access->i_command = 0;
1090             return( -1 );
1091         }
1092         i_length = GetDWLE( p_access->p_cmd + 8 ) + 16;
1093         if( i_length > p_access->i_cmd )
1094         {
1095             if( mms_ReadData( p_input, 
1096                               p_access->p_cmd + p_access->i_cmd,
1097                               i_length - p_access->i_cmd ) < 0 )
1098             {
1099                 msg_Warn( p_input, "failed to receive command" );
1100                 p_access->i_command = 0;
1101                 return( -1 );
1102             }
1103         }
1104
1105         msg_Dbg( p_input, "received %d bytes", p_access->i_cmd );
1106
1107         p_access->i_command = GET32( 36 ) & 0xffff;
1108         msg_Dbg( p_input, 
1109                  "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",
1110                  GET32( 0 ),
1111                  GET32( 4 ),
1112                  GET32( 8 ),
1113                  GET32( 16 ),
1114                  GET32( 20 ),
1115                  GET32( 32 ),
1116                  GET32( 36 ),
1117                  GET32( 40 ) );
1118
1119         if( p_access->i_command == 0x1b )
1120         {
1121             mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
1122         }
1123
1124     } while( p_access->i_command == 0x1b );
1125
1126     return( 0 );
1127 }
1128
1129 #define MMS_RETRY_MAX       10
1130 #define MMS_RETRY_SLEEP     50000
1131
1132 static int mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 )
1133 {
1134     access_t    *p_access = (access_t*)p_input->p_access_data;
1135     int i_count;
1136     int i_status;
1137
1138     for( i_count = 0; i_count < MMS_RETRY_MAX; )
1139     {
1140
1141         i_status = mms_ReceiveCommand( p_input );
1142         if( i_status < 0 || p_access->i_command == 0 )
1143         {
1144             i_count++;
1145             msleep( MMS_RETRY_SLEEP );
1146         }
1147         else if( i_command1 == 0 && i_command2 == 0)
1148         {
1149             return( 0 );
1150         }
1151         else if( p_access->i_command == i_command1 || p_access->i_command == i_command2 )
1152         {
1153             return( 0 );   
1154         }
1155         else
1156         {
1157             switch( p_access->i_command )
1158             {
1159                 case 0x03:
1160                     msg_Warn( p_input, "socket closed by server" );
1161                     return( -1 );
1162                 case 0x1e:
1163                     msg_Warn( p_input, "end of media stream" );
1164                     return( -1 );
1165                 default:
1166                     break;
1167             }
1168         }
1169     }
1170     msg_Warn( p_input, "failed to receive command (abording)" );
1171
1172     return( -1 );
1173 }
1174
1175
1176
1177 static int mms_ReceivePacket( input_thread_t *p_input )
1178 {
1179     access_t    *p_access = (access_t*)p_input->p_access_data;
1180     uint8_t     preheader[8];
1181     int         i_read;
1182
1183     if( p_access->i_proto == MMS_PROTO_UDP )
1184     {
1185         return( -1 );
1186     }
1187     else
1188     {
1189         for( ;; )
1190         {
1191             if( ( i_read = input_FDNetworkRead( p_input, preheader, 8 ) ) < 8 )
1192             {
1193                 msg_Warn( p_input, "cannot read preheader" );
1194                 return( -1 );
1195             }
1196             /* preheader format :
1197              * u32 i_sequence_number
1198              * u8  i_packet_id
1199              * u8  i_udp_sequence/i_tcp_flags
1200              * u16 i_length
1201              */
1202             if( preheader[4] == p_access->i_header_packet_id_type ||
1203                 preheader[4] == p_access->i_media_packet_id_type ||
1204                 preheader[4] == 0xff )// udp timing pair
1205             {
1206                 int i_packet_seq_num;
1207                 int i_packet_length;
1208                 int i_packet_id;
1209
1210                 uint8_t  *p_packet;
1211                 
1212                 i_packet_seq_num = GetDWLE( preheader );
1213                 i_packet_length = GetWLE( preheader + 6 );
1214                 i_packet_id = preheader[4];
1215                 
1216                 /* *** read complete packet *** */
1217                 if( i_packet_length <= 8 )
1218                 {
1219                     msg_Err( p_input,
1220                              "empty or broken packet" );
1221                     return( -1 );
1222                 }
1223                 p_packet = malloc( i_packet_length - 8 );
1224                 if( mms_ReadData( p_input, 
1225                                   p_packet,
1226                                   i_packet_length - 8 ) < 0 )
1227                 {
1228                     msg_Err( p_input,
1229                              "cannot read data" );
1230                 }
1231
1232                 
1233                 if( i_packet_id == 0xff )
1234                 {
1235                     msg_Warn( p_input,
1236                               "receive MMS UDP pair timing" );
1237                     free( p_packet );
1238                     return( MMS_PACKET_UDP_TIMING );
1239                 }
1240                 else
1241                 {
1242                     if( i_packet_seq_num != p_access->i_packet_seq_num )
1243                     {
1244                         // FIXME for udp could be just wrong order ?
1245                         msg_Warn( p_input, 
1246                                   "detected packet lost (%d != %d)",
1247                                   i_packet_seq_num,
1248                                   p_access->i_packet_seq_num );
1249                         p_access->i_packet_seq_num = i_packet_seq_num;
1250                     }
1251                     p_access->i_packet_seq_num++;
1252
1253                     if( i_packet_id == p_access->i_header_packet_id_type )
1254                     {
1255                         FREE( p_access->p_header );
1256                         p_access->p_header = p_packet;
1257                         p_access->i_header = i_packet_length - 8;
1258                         return( MMS_PACKET_HEADER );
1259                     }
1260                     else
1261                     {
1262                         FREE( p_access->p_media );
1263                         p_access->p_media = p_packet;
1264                         p_access->i_media = i_packet_length - 8;
1265                         p_access->i_media_used = 0;
1266                         return( MMS_PACKET_MEDIA );
1267                     }
1268                 }
1269             }
1270             else
1271             {
1272                 int i_packet_length;
1273                 // command ?
1274                 if( GetDWLE( preheader + 4 ) != 0xb00bface )
1275                 {
1276                     msg_Err( p_input, 
1277                              "incorrect command header (0x%x)",
1278                               GetDWLE( preheader + 4 ) );
1279                 }
1280                 memcpy( p_access->p_cmd, preheader, 8 );
1281                 if( mms_ReadData( p_input, 
1282                                   p_access->p_cmd + 8,
1283                                   8 ) < 0 )
1284                 {
1285                     msg_Err( p_input,
1286                              "cannot read data" );
1287                 }
1288                 p_access->i_cmd = 16;
1289                 i_packet_length = GetDWLE( p_access->p_cmd + 8 );
1290                 if( mms_ReadData( p_input, 
1291                                   p_access->p_cmd + 16,
1292                                   i_packet_length ) < 0 )
1293                 {
1294                     msg_Err( p_input,
1295                              "cannot read data" );
1296                 }
1297                 p_access->i_cmd += i_packet_length;
1298                 p_access->i_command = GetDWLE( p_access->p_cmd + 36 ) & 0xffff;
1299                 if( p_access->i_command == 0x1b )
1300                 {
1301                     mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
1302                 }
1303                 else
1304                 {
1305                     return( MMS_PACKET_CMD );
1306                 }
1307
1308             }
1309         }
1310     }
1311 }
1312
1313
1314 static int mms_HeaderMediaRead( input_thread_t *p_input, int i_type )
1315 {
1316     access_t    *p_access = (access_t*)p_input->p_access_data;
1317     int         i_count;
1318     
1319     for( i_count = 0; i_count < MMS_RETRY_MAX; )
1320     {
1321         int i_status;
1322
1323         i_status = mms_ReceivePacket( p_input );
1324         if( i_status < 0 )
1325         {
1326             i_count++;
1327             msg_Warn( p_input, 
1328                       "cannot receive header (%d/%d)", i_count, MMS_RETRY_MAX );
1329             msleep( MMS_RETRY_SLEEP );
1330         }
1331         else if( i_status == i_type )
1332         {
1333             return( 0 );
1334         }
1335         else if( i_status == MMS_PACKET_CMD )
1336         {
1337             switch( p_access->i_command )
1338             {
1339                 case 0x03:
1340                     msg_Warn( p_input, "socket closed by server" );
1341                     return( -1 );
1342                 case 0x1e:
1343                     msg_Warn( p_input, "end of media stream" );
1344                     return( -1 );
1345                 case 0x20:
1346                     /* XXX not too dificult to be done EXCEPT that we 
1347                      * need to restart demuxer... and I don't see how we 
1348                      * could do that :p */ 
1349                     msg_Err( p_input, 
1350                              "reinitialization needed --> unsupported" );
1351                     return( -1 );
1352                 default:
1353                     break;
1354             }
1355         }
1356     }
1357     msg_Err( p_input, 
1358              "cannot receive %s (abording)",
1359                ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" );
1360     return( -1 );
1361 }
1362
1363
1364
1365