* mms: removed some old stuff.
[vlc.git] / 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.27 2003/03/16 01:49:28 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/time.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <fcntl.h>
42
43 #include <vlc/vlc.h>
44 #include <vlc/input.h>
45
46 #ifdef HAVE_UNISTD_H
47 #   include <unistd.h>
48 #endif
49
50 #ifdef WIN32
51 #   include <winsock2.h>
52 #   include <ws2tcpip.h>
53 #   ifndef IN_MULTICAST
54 #       define IN_MULTICAST(a) IN_CLASSD(a)
55 #   endif
56 #else
57 #   include <sys/socket.h>
58 #   include <netinet/in.h>
59 #   if HAVE_ARPA_INET_H
60 #      include <arpa/inet.h>
61 #   elif defined( SYS_BEOS )
62 #      include <net/netdb.h>
63 #   endif
64 #endif
65
66 #include "network.h"
67 #include "asf.h"
68 #include "buffer.h"
69 #include "mms.h"
70
71 #undef MMS_DEBUG
72
73 /****************************************************************************
74  * NOTES:
75  *  MMSProtocole documentation found at http://get.to/sdp
76  ****************************************************************************/
77
78 /*****************************************************************************
79  * Local prototypes
80  *****************************************************************************/
81 static int  Open        ( vlc_object_t * );
82 static void Close       ( vlc_object_t * );
83
84 static int  Read        ( input_thread_t * p_input, byte_t * p_buffer,
85                           size_t i_len );
86 static void Seek        ( input_thread_t *, off_t );
87 static int  SetProgram  ( input_thread_t *, pgrm_descriptor_t * );
88
89
90 static int MMSOpen( input_thread_t  *, url_t *, int, char * );
91
92 static int MMSStart  ( input_thread_t  *, uint32_t );
93 static int MMSStop  ( input_thread_t  *p_input );
94
95 static int MMSClose  ( input_thread_t  * );
96
97
98 static int  mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 );
99 static int  mms_CommandSend( input_thread_t *, int, uint32_t, uint32_t, uint8_t *, int );
100
101 static int  mms_HeaderMediaRead( input_thread_t *, int );
102
103 static int  mms_ReceivePacket( input_thread_t * );
104
105 static void mms_ParseURL( url_t *p_url, char *psz_url );
106
107
108
109 /*
110  * XXX DON'T FREE MY MEMORY !!! XXX
111  * non mais :P
112  */
113
114 /*
115  * Ok, ok, j'le ferai plus...
116  */
117 /*
118  * Merci :))
119  */
120 /*
121  * Vous pourriez signer vos commentaires (même si on voit bien qui peut
122  * écrire ce genre de trucs :p), et écrire en anglais, bordel de
123  * merde :p.
124  */
125
126 /*****************************************************************************
127  * Module descriptor
128  *****************************************************************************/
129 #define CACHING_TEXT N_("caching value in ms")
130 #define CACHING_LONGTEXT N_( \
131     "Allows you to modify the default caching value for mms streams. This " \
132     "value should be set in miliseconds units." )
133
134 vlc_module_begin();
135     set_description( _("MMS access module") );
136     set_capability( "access", 0 );
137     add_category_hint( "stream", NULL, VLC_TRUE );
138         add_integer( "mms-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL,
139                      CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
140
141         add_bool( "mms-all", 0, NULL,
142                   "force selection of all streams",
143                   "force selection of all streams", VLC_TRUE );
144
145         add_string( "mms-stream", NULL, NULL,
146                     "streams selection",
147                     "force this stream selection", VLC_TRUE );
148         add_integer( "mms-maxbitrate", 0, NULL,
149                      "max bitrate",
150                      "set max bitrate for auto streams selections", VLC_FALSE );
151     add_shortcut( "mms" );
152     add_shortcut( "mmsu" );
153     add_shortcut( "mmst" );
154     set_callbacks( Open, Close );
155 vlc_module_end();
156
157 #define BUF_SIZE 200000
158
159 static int Open( vlc_object_t *p_this )
160 {
161     access_t    *p_access;
162     int         i_proto;
163     char        *psz_network;
164     int         i_status;
165
166     input_thread_t  *p_input = (input_thread_t*)p_this;
167
168     /* *** allocate p_access_data *** */
169     p_input->p_access_data =
170         (void*)p_access = malloc( sizeof( access_t ) );
171     memset( p_access, 0, sizeof( access_t ) );
172
173
174     /* *** Parse URL and get server addr/port and path *** */
175     mms_ParseURL( &p_access->url, p_input->psz_name );
176     if( p_access->url.psz_server_addr == NULL ||
177         !( *p_access->url.psz_server_addr ) )
178     {
179         FREE( p_access->url.psz_private );
180         msg_Err( p_input, "invalid server name" );
181         return( -1 );
182     }
183     if( p_access->url.i_server_port == 0 )
184     {
185         p_access->url.i_server_port = 1755; /* default port */
186     }
187     if( p_access->url.i_bind_port == 0 )
188     {
189         p_access->url.i_bind_port = 7000;   /* default port */
190     }
191
192
193     /* *** connect to this server *** */
194     /* 1: look at  requested protocol (udp/tcp) */
195     i_proto = MMS_PROTO_AUTO;
196     if( *p_input->psz_access )
197     {
198         if( !strncmp( p_input->psz_access, "mmsu", 4 ) )
199         {
200             i_proto = MMS_PROTO_UDP;
201         }
202         else if( !strncmp( p_input->psz_access, "mmst", 4 ) )
203         {
204             i_proto = MMS_PROTO_TCP;
205         }
206     }
207     /* 2: look at ip version ipv4/ipv6 */
208     psz_network = "";
209     if( config_GetInt( p_input, "ipv4" ) )
210     {
211         psz_network = "ipv4";
212     }
213     else if( config_GetInt( p_input, "ipv6" ) )
214     {
215         psz_network = "ipv6";
216     }
217     /* 3: connect */
218     if( i_proto == MMS_PROTO_AUTO )
219     {   /* first try with TCP */
220         i_status =
221             MMSOpen( p_input, &p_access->url, MMS_PROTO_TCP, psz_network );
222         if( i_status < 0 )
223         {   /* then with UDP */
224             i_status =
225              MMSOpen( p_input, &p_access->url, MMS_PROTO_UDP, psz_network );
226         }
227     }
228     else
229     {
230
231         i_status =
232             MMSOpen( p_input, &p_access->url, i_proto, psz_network );
233     }
234
235     if( i_status < 0 )
236     {
237         msg_Err( p_input, "cannot connect to server" );
238         FREE( p_access->url.psz_private );
239         return( -1 );
240     }
241     msg_Dbg( p_input, "connected to %s", p_access->url.psz_server_addr );
242
243
244     /* *** set exported functions *** */
245     p_input->pf_read = Read;
246     p_input->pf_seek = Seek;
247     p_input->pf_set_program = SetProgram;
248     p_input->pf_set_area = NULL;
249
250     p_input->p_private = NULL;
251
252     /* *** finished to set some variable *** */
253     vlc_mutex_lock( &p_input->stream.stream_lock );
254     p_input->stream.b_pace_control = 0;
255     if( p_access->i_proto == MMS_PROTO_UDP )
256     {
257         p_input->stream.b_connected = 0;
258     }
259     else
260     {
261         p_input->stream.b_connected = 1;
262     }
263     p_input->stream.p_selected_area->i_tell = 0;
264     /*
265      * i_flags_broadcast
266      *  yy xx ?? ??
267      *  broadcast    yy=0x02, xx= 0x00
268      *  pre-recorded yy=0x01, xx= 0x80 if video, 0x00 no video
269      */
270     if( p_access->i_packet_count <= 0 || ( p_access->i_flags_broadcast >> 24 ) == 0x02 )
271     {
272         p_input->stream.b_seekable = 0;
273         p_input->stream.p_selected_area->i_size = 0;
274     }
275     else
276     {
277         p_input->stream.b_seekable = 1;
278         p_input->stream.p_selected_area->i_size =
279             p_access->i_header +
280             p_access->i_packet_count * p_access->i_packet_length;
281     }
282
283     p_input->stream.i_method = INPUT_METHOD_NETWORK;
284     vlc_mutex_unlock( &p_input->stream.stream_lock );
285
286     /* *** Start stream *** */
287     if( MMSStart( p_input, 0xffffffff ) < 0 )
288     {
289         msg_Err( p_input, "cannot start stream" );
290         MMSClose( p_input );
291         FREE( p_access->url.psz_private );
292         return( -1 );
293     }
294
295     /* Update default_pts to a suitable value for mms access */
296     p_input->i_pts_delay = config_GetInt( p_input, "mms-caching" ) * 1000;
297
298     return( 0 );
299 }
300
301 /*****************************************************************************
302  * Close: free unused data structures
303  *****************************************************************************/
304 static void Close( vlc_object_t *p_this )
305 {
306     input_thread_t *  p_input = (input_thread_t *)p_this;
307     access_t    *p_access = (access_t*)p_input->p_access_data;
308
309     /* close connection with server */
310     MMSClose( p_input );
311
312     /* free memory */
313     FREE( p_access->url.psz_private );
314
315     FREE( p_input->p_access_data );
316 }
317
318 /*****************************************************************************
319  * SetProgram: do nothing
320  *****************************************************************************/
321 static int SetProgram( input_thread_t * p_input,
322                        pgrm_descriptor_t * p_program )
323 {
324     return( 0 );
325 }
326
327 /*****************************************************************************
328  * Seek: try to go at the right place
329  *****************************************************************************/
330 static void Seek( input_thread_t * p_input, off_t i_pos )
331 {
332     access_t    *p_access = (access_t*)p_input->p_access_data;
333     uint32_t    i_packet;
334     uint32_t    i_offset;
335     var_buffer_t    buffer;
336
337     if( i_pos < 0 )
338     {
339         return;
340     }
341
342     vlc_mutex_lock( &p_input->stream.stream_lock );
343
344     if( i_pos < p_access->i_header)
345     {
346
347         if( p_access->i_pos < p_access->i_header )
348         {
349             /* no need to restart stream, it was already one
350              * or no stream was yet read */
351             p_access->i_pos = i_pos;
352             return;
353         }
354         else
355         {
356             i_packet = 0xffffffff;
357             i_offset = 0;
358         }
359     }
360     else
361     {
362         i_packet = ( i_pos - p_access->i_header ) / p_access->i_packet_length;
363         i_offset = ( i_pos - p_access->i_header ) % p_access->i_packet_length;
364     }
365     msg_Dbg( p_input, "seeking to "I64Fd " (packet:%d)", i_pos, i_packet );
366
367     MMSStop( p_input );
368     msg_Dbg( p_input, "stream stopped (seek)" );
369
370     /* *** restart stream *** */
371     var_buffer_initwrite( &buffer, 0 );
372     var_buffer_add64( &buffer, 0 ); /* seek point in second */
373     var_buffer_add32( &buffer, 0xffffffff );
374     var_buffer_add32( &buffer, i_packet ); // begin from start
375     var_buffer_add8( &buffer, 0xff ); // stream time limit
376     var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
377     var_buffer_add8( &buffer, 0xff ); //
378     var_buffer_add8( &buffer, 0x00 ); // don't use limit
379     var_buffer_add32( &buffer, p_access->i_media_packet_id_type );
380
381     mms_CommandSend( p_input, 0x07, p_access->i_command_level, 0x0001ffff,
382                      buffer.p_data, buffer.i_data );
383
384     var_buffer_free( &buffer );
385
386
387     for( ;; )
388     {
389         mms_HeaderMediaRead( p_input, MMS_PACKET_CMD );
390         if( p_access->i_command == 0x1e )
391         {
392             msg_Dbg( p_input, "received 0x1e (seek)" );
393             break;
394         }
395     }
396
397     for( ;; )
398     {
399         mms_HeaderMediaRead( p_input, MMS_PACKET_CMD );
400         if( p_access->i_command == 0x05 )
401         {
402             msg_Dbg( p_input, "received 0x05 (seek)" );
403             break;
404         }
405     }
406
407     /* get a packet */
408     mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA );
409     msg_Dbg( p_input, "Streaming restarted" );
410
411     p_access->i_media_used += i_offset;
412     p_access->i_pos = i_pos;
413     p_input->stream.p_selected_area->i_tell = i_pos;
414     vlc_mutex_unlock( &p_input->stream.stream_lock );
415 }
416
417 static int  Read        ( input_thread_t * p_input, byte_t * p_buffer,
418                           size_t i_len )
419 {
420     access_t    *p_access = (access_t*)p_input->p_access_data;
421     size_t      i_data;
422     size_t      i_copy;
423
424     i_data = 0;
425
426     /* *** send header if needed ** */
427     if( p_access->i_pos < p_access->i_header )
428     {
429         i_copy = __MIN( i_len, p_access->i_header - p_access->i_pos );
430         if( i_copy > 0 )
431         {
432             memcpy( p_buffer,
433                     p_access->p_header + p_access->i_pos,
434                     i_copy );
435         }
436         i_data += i_copy;
437     }
438
439     /* *** now send data if needed *** */
440     while( i_data < i_len )
441     {
442         if( p_access->i_media_used < p_access->i_media )
443         {
444             i_copy = __MIN( i_len - i_data ,
445                             p_access->i_media - p_access->i_media_used );
446             memcpy( p_buffer + i_data,
447                     p_access->p_media + p_access->i_media_used,
448                     i_copy );
449             i_data += i_copy;
450             p_access->i_media_used += i_copy;
451         }
452         else if( p_access->p_media != NULL &&
453                  p_access->i_media_used < p_access->i_packet_length )
454         {
455             i_copy = __MIN( i_len - i_data,
456                             p_access->i_packet_length - p_access->i_media_used);
457             memset( p_buffer + i_data, 0, i_copy );
458
459             i_data += i_copy;
460             p_access->i_media_used += i_copy;
461         }
462         else
463         {
464             if( p_access->i_eos
465                  || mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA ) < 0 )
466             {
467                 p_access->i_pos += i_data;
468                 return( i_data );
469             }
470         }
471     }
472
473     p_access->i_pos += i_data;
474     return( i_data );
475 }
476
477 static void asf_HeaderParse( mms_stream_t stream[128],
478                              uint8_t *p_header, int i_header )
479 {
480     var_buffer_t buffer;
481     guid_t      guid;
482     uint64_t    i_size;
483     int         i;
484
485     for( i = 0; i < 128; i++ )
486     {
487         stream[i].i_cat = MMS_STREAM_UNKNOWN;
488     }
489
490     //fprintf( stderr, " ---------------------header:%d\n", i_header );
491     var_buffer_initread( &buffer, p_header, i_header );
492
493     var_buffer_getguid( &buffer, &guid );
494
495     if( !CmpGuid( &guid, &asf_object_header_guid ) )
496     {
497 //        XXX Error
498 //        fprintf( stderr, " ---------------------ERROR------\n" );
499     }
500     var_buffer_getmemory( &buffer, NULL, 30 - 16 );
501
502     for( ;; )
503     {
504         //fprintf( stderr, " ---------------------data:%d\n", buffer.i_data );
505
506         var_buffer_getguid( &buffer, &guid );
507         i_size = var_buffer_get64( &buffer );
508
509         //fprintf( stderr, "  guid=0x%8.8x-0x%4.4x-0x%4.4x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x size=%lld\n",
510         //                  guid.v1,guid.v2, guid.v3,
511         //                  guid.v4[0],guid.v4[1],guid.v4[2],guid.v4[3],
512         //                  guid.v4[4],guid.v4[5],guid.v4[6],guid.v4[7],
513         //                  i_size );
514
515         if( CmpGuid( &guid, &asf_object_stream_properties_guid ) )
516         {
517             int     i_stream_id;
518             guid_t  stream_type;
519             //msg_Dbg( p_input, "found stream_properties" );
520
521             var_buffer_getguid( &buffer, &stream_type );
522             var_buffer_getmemory( &buffer, NULL, 32 );
523             i_stream_id = var_buffer_get8( &buffer ) & 0x7f;
524
525             //fprintf( stderr, " 1---------------------skip:%lld\n", i_size - 24 - 32 - 16 - 1 );
526             var_buffer_getmemory( &buffer, NULL, i_size - 24 - 32 - 16 - 1);
527
528             if( CmpGuid( &stream_type, &asf_object_stream_type_video ) )
529             {
530                 //fprintf( stderr, "\nvideo stream[%d] found\n", i_stream_id );
531                 //msg_Dbg( p_input, "video stream[%d] found", i_stream_id );
532                 stream[i_stream_id].i_cat = MMS_STREAM_VIDEO;
533             }
534             else if( CmpGuid( &stream_type, &asf_object_stream_type_audio ) )
535             {
536                 //fprintf( stderr, "\naudio stream[%d] found\n", i_stream_id );
537                 //msg_Dbg( p_input, "audio stream[%d] found", i_stream_id );
538                 stream[i_stream_id].i_cat = MMS_STREAM_AUDIO;
539             }
540             else
541             {
542 //                msg_Dbg( p_input, "unknown stream[%d] found", i_stream_id );
543                 stream[i_stream_id].i_cat = MMS_STREAM_UNKNOWN;
544             }
545         }
546         else if ( CmpGuid( &guid, &asf_object_bitrate_properties_guid ) )
547         {
548             int     i_count;
549             uint8_t i_stream_id;
550
551             i_count = var_buffer_get16( &buffer );
552             i_size -= 2;
553             while( i_count > 0 )
554             {
555                 i_stream_id = var_buffer_get16( &buffer )&0x7f;
556                 stream[i_stream_id].i_bitrate =  var_buffer_get32( &buffer );
557                 i_count--;
558                 i_size -= 6;
559             }
560             //fprintf( stderr, " 2---------------------skip:%lld\n", i_size - 24);
561             var_buffer_getmemory( &buffer, NULL, i_size - 24 );
562         }
563         else
564         {
565             //fprintf( stderr, " 3---------------------skip:%lld\n", i_size - 24);
566             // skip unknown guid
567             var_buffer_getmemory( &buffer, NULL, i_size - 24 );
568         }
569
570         if( var_buffer_readempty( &buffer ) )
571         {
572             return;
573         }
574     }
575 }
576
577 static void mms_StreamSelect( input_thread_t * p_input,
578                               mms_stream_t stream[128] )
579 {
580     /* XXX FIXME use mututal eclusion information */
581     int i;
582     int i_audio, i_video;
583     int b_audio, b_video;
584     int i_bitrate_total;
585     int i_bitrate_max;
586     char *psz_stream;
587
588     i_audio = 0;
589     i_video = 0;
590     i_bitrate_total = 0;
591     i_bitrate_max = config_GetInt( p_input, "mms-maxbitrate" );
592     b_audio = config_GetInt( p_input, "audio" );
593     b_video = config_GetInt( p_input, "video" );
594     if( config_GetInt( p_input, "mms-all" ) )
595     {
596         /* select all valid stream */
597         for( i = 1; i < 128; i++ )
598         {
599             if( stream[i].i_cat != MMS_STREAM_UNKNOWN )
600             {
601                 stream[i].i_selected = 1;
602             }
603         }
604         return;
605     }
606     else
607     {
608         for( i = 0; i < 128; i++ )
609         {
610             stream[i].i_selected = 0; /* by default, not selected */
611         }
612     }
613     psz_stream = config_GetPsz( p_input, "mms-stream" );
614
615     if( psz_stream && *psz_stream )
616     {
617         char *psz_tmp = psz_stream;
618         while( *psz_tmp )
619         {
620             if( *psz_tmp == ',' )
621             {
622                 psz_tmp++;
623             }
624             else
625             {
626                 int i_stream;
627                 i_stream = atoi( psz_tmp );
628                 while( *psz_tmp != '\0' && *psz_tmp != ',' )
629                 {
630                     psz_tmp++;
631                 }
632
633                 if( i_stream > 0 && i_stream < 128 &&
634                     stream[i_stream].i_cat != MMS_STREAM_UNKNOWN )
635                 {
636                     stream[i_stream].i_selected = 1;
637                 }
638             }
639         }
640         FREE( psz_stream );
641         return;
642     }
643     FREE( psz_stream );
644
645     /* big test:
646      * select a stream if
647      *    - no audio nor video stream
648      *    - or:
649      *         - if i_bitrate_max not set keep the highest bitrate
650      *         - if i_bitrate_max is set, keep stream that make we used best
651      *           quality regarding i_bitrate_max
652      *
653      * XXX: little buggy:
654      *        - it doesn't use mutual exclusion info..
655      *        - when selecting a better stream we could select
656      *        something that make i_bitrate_total> i_bitrate_max
657      */
658     for( i = 1; i < 128; i++ )
659     {
660         if( stream[i].i_cat == MMS_STREAM_UNKNOWN )
661         {
662             continue;
663         }
664         else if( stream[i].i_cat == MMS_STREAM_AUDIO && b_audio &&
665                  ( i_audio <= 0 ||
666                     ( ( ( stream[i].i_bitrate > stream[i_audio].i_bitrate &&
667                           ( i_bitrate_total + stream[i].i_bitrate - stream[i_audio].i_bitrate
668                                             < i_bitrate_max || !i_bitrate_max) ) ||
669                         ( stream[i].i_bitrate < stream[i_audio].i_bitrate &&
670                               i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max )
671                       ) )  ) )
672         {
673             /* unselect old stream */
674             if( i_audio > 0 )
675             {
676                 stream[i_audio].i_selected = 0;
677                 if( stream[i_audio].i_bitrate> 0 )
678                 {
679                     i_bitrate_total -= stream[i_audio].i_bitrate;
680                 }
681             }
682
683             stream[i].i_selected = 1;
684             if( stream[i].i_bitrate> 0 )
685             {
686                 i_bitrate_total += stream[i].i_bitrate;
687             }
688             i_audio = i;
689         }
690         else if( stream[i].i_cat == MMS_STREAM_VIDEO && b_video &&
691                  ( i_video <= 0 ||
692                     (
693                         ( ( stream[i].i_bitrate > stream[i_video].i_bitrate &&
694                             ( i_bitrate_total + stream[i].i_bitrate - stream[i_video].i_bitrate
695                                             < i_bitrate_max || !i_bitrate_max) ) ||
696                           ( stream[i].i_bitrate < stream[i_video].i_bitrate &&
697                             i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max )
698                         ) ) )  )
699         {
700             /* unselect old stream */
701
702             stream[i_video].i_selected = 0;
703             if( stream[i_video].i_bitrate> 0 )
704             {
705                 i_bitrate_total -= stream[i_video].i_bitrate;
706             }
707
708             stream[i].i_selected = 1;
709             if( stream[i].i_bitrate> 0 )
710             {
711                 i_bitrate_total += stream[i].i_bitrate;
712             }
713             i_video = i;
714         }
715
716     }
717     if( i_bitrate_max > 0 )
718     {
719         msg_Dbg( p_input,
720                  "requested bitrate:%d real bitrate:%d",
721                  i_bitrate_max, i_bitrate_total );
722     }
723     else
724     {
725         msg_Dbg( p_input,
726                  "total bitrate:%d",
727                  i_bitrate_total );
728     }
729 }
730
731 /****************************************************************************
732  * MMSOpen : Open a connection with the server over mmst or mmsu(not yet)
733  ****************************************************************************/
734 static int MMSOpen( input_thread_t  *p_input,
735                        url_t *p_url,
736                        int  i_proto,
737                        char *psz_network ) /* "", "ipv4", "ipv6" */
738 {
739     module_t    *p_network;
740     access_t    *p_access = (access_t*)p_input->p_access_data;
741
742     network_socket_t    socket_desc;
743     int b_udp = ( i_proto == MMS_PROTO_UDP ) ? 1 : 0;
744
745     var_buffer_t buffer;
746     char         tmp[4096];
747     uint16_t     *p;
748     int          i_server_version;
749     int          i_tool_version;
750     int          i_update_player_url;
751     int          i_encryption_type;
752     int          i;
753     int          i_streams;
754     int          i_first;
755
756
757     /* *** Open a TCP connection with server *** */
758     msg_Dbg( p_input, "waiting for connection..." );
759     socket_desc.i_type = NETWORK_TCP;
760     socket_desc.psz_server_addr = p_url->psz_server_addr;
761     socket_desc.i_server_port   = p_url->i_server_port;
762     socket_desc.psz_bind_addr   = "";
763     socket_desc.i_bind_port     = 0;
764     p_input->p_private = (void*)&socket_desc;
765     if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
766     {
767         msg_Err( p_input, "failed to open a connection (tcp)" );
768         return( -1 );
769     }
770     module_Unneed( p_input, p_network );
771     p_access->socket_tcp.i_handle = socket_desc.i_handle;
772     p_input->i_mtu    = 0; /*socket_desc.i_mtu;*/
773     msg_Dbg( p_input,
774              "connection(tcp) with \"%s:%d\" successful",
775              p_url->psz_server_addr,
776              p_url->i_server_port );
777
778     /* *** Bind port if UDP protocol is selected *** */
779     if( b_udp )
780     {
781         if( !p_url->psz_bind_addr || !*p_url->psz_bind_addr )
782         {
783             struct sockaddr_in name;
784             socklen_t i_namelen = sizeof( struct sockaddr_in );
785
786             if( getsockname( p_access->socket_tcp.i_handle,
787                              (struct sockaddr*)&name, &i_namelen ) < 0 )
788             {
789
790                 msg_Err( p_input, "for udp you have to provide bind address (mms://<server_addr>@<bind_addr/<path> (FIXME)" );
791 #if defined( UNDER_CE )
792                 CloseHandle( (HANDLE)p_access->socket_tcp.i_handle );
793 #elif defined( WIN32 )
794                 closesocket( p_access->socket_tcp.i_handle );
795 #else
796                 close( p_access->socket_tcp.i_handle );
797 #endif
798                 return( -1 );
799             }
800             p_access->psz_bind_addr = inet_ntoa( name.sin_addr );
801         }
802         else
803         {
804             p_access->psz_bind_addr = strdup( p_url->psz_bind_addr );
805         }
806         socket_desc.i_type = NETWORK_UDP;
807         socket_desc.psz_server_addr = "";
808         socket_desc.i_server_port   = 0;
809         socket_desc.psz_bind_addr   = p_access->psz_bind_addr;
810         socket_desc.i_bind_port     = p_url->i_bind_port;
811         p_input->p_private = (void*)&socket_desc;
812         if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
813         {
814             msg_Err( p_input, "failed to open a connection (udp)" );
815 #if defined( UNDER_CE )
816             CloseHandle( (HANDLE)p_access->socket_tcp.i_handle );
817 #elif defined( WIN32 )
818             closesocket( p_access->socket_tcp.i_handle );
819 #else
820             close( p_access->socket_tcp.i_handle );
821 #endif
822             return( -1 );
823         }
824         module_Unneed( p_input, p_network );
825         p_access->socket_udp.i_handle = socket_desc.i_handle;
826         p_input->i_mtu    = 0;/*socket_desc.i_mtu;  FIXME */
827
828     }
829     else
830     {
831         p_access->psz_bind_addr = NULL;
832     }
833
834     /* *** Init context for mms prototcol *** */
835     GenerateGuid( &p_access->guid );    /* used to identify client by server */
836     msg_Dbg( p_input,
837              "generated guid: "GUID_FMT,
838              GUID_PRINT( p_access->guid ) );
839     p_access->i_command_level = 1;          /* updated after 0x1A command */
840     p_access->i_seq_num = 0;
841     p_access->i_media_packet_id_type  = 0x04;
842     p_access->i_header_packet_id_type = 0x02;
843     p_access->i_proto = i_proto;
844     p_access->i_packet_seq_num = 0;
845     p_access->p_header = NULL;
846     p_access->i_header = 0;
847     p_access->p_media = NULL;
848     p_access->i_media = 0;
849     p_access->i_media_used = 0;
850
851     p_access->i_pos = 0;
852     p_access->i_buffer_tcp = 0;
853     p_access->i_buffer_udp = 0;
854     p_access->p_cmd = NULL;
855     p_access->i_cmd = 0;
856     p_access->i_eos = 0;
857
858     /* *** send command 1 : connection request *** */
859     var_buffer_initwrite( &buffer, 0 );
860     var_buffer_add16( &buffer, 0x001c );
861     var_buffer_add16( &buffer, 0x0003 );
862     sprintf( tmp,
863              "NSPlayer/7.0.0.1956; {"GUID_FMT"}; Host: %s",
864              GUID_PRINT( p_access->guid ),
865              p_url->psz_server_addr );
866     var_buffer_addUTF16( &buffer, tmp );
867
868     mms_CommandSend( p_input,
869                      0x01,          /* connexion request */
870                      0x00000000,    /* flags, FIXME */
871                      0x0004000b,    /* ???? */
872                      buffer.p_data,
873                      buffer.i_data );
874
875     if( mms_CommandRead( p_input, 0x01, 0 ) < 0 )
876     {
877         var_buffer_free( &buffer );
878         MMSClose( p_input );
879         return( -1 );
880     }
881
882     i_server_version = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 32 );
883     i_tool_version = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 36 );
884     i_update_player_url = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 40 );
885     i_encryption_type = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 44 );
886     p = (uint16_t*)( p_access->p_cmd + MMS_CMD_HEADERSIZE + 48 );
887 #define GETUTF16( psz, size ) \
888     { \
889         int i; \
890         psz = malloc( size + 1); \
891         for( i = 0; i < size; i++ ) \
892         { \
893             psz[i] = p[i]; \
894         } \
895         psz[size] = '\0'; \
896         p += 2 * ( size ); \
897     }
898     GETUTF16( p_access->psz_server_version, i_server_version );
899     GETUTF16( p_access->psz_tool_version, i_tool_version );
900     GETUTF16( p_access->psz_update_player_url, i_update_player_url );
901     GETUTF16( p_access->psz_encryption_type, i_encryption_type );
902 #undef GETUTF16
903     msg_Dbg( p_input,
904              "0x01 --> server_version:\"%s\" tool_version:\"%s\" update_player_url:\"%s\" encryption_type:\"%s\"",
905              p_access->psz_server_version,
906              p_access->psz_tool_version,
907              p_access->psz_update_player_url,
908              p_access->psz_encryption_type );
909
910     /* *** should make an 18 command to make data timing *** */
911
912     /* *** send command 2 : transport protocol selection *** */
913     var_buffer_reinitwrite( &buffer, 0 );
914     var_buffer_add32( &buffer, 0x00000000 );
915     var_buffer_add32( &buffer, 0x000a0000 );
916     var_buffer_add32( &buffer, 0x00000002 );
917     if( b_udp )
918     {
919         sprintf( tmp,
920                  "\\\\%s\\UDP\\%d",
921                  p_access->psz_bind_addr,
922                  p_url->i_bind_port );
923     }
924     else
925     {
926         sprintf( tmp, "\\\\192.168.0.1\\TCP\\1242"  );
927     }
928     var_buffer_addUTF16( &buffer, tmp );
929     var_buffer_add16( &buffer, '0' );
930
931     mms_CommandSend( p_input,
932                      0x02,          /* connexion request */
933                      0x00000000,    /* flags, FIXME */
934                      0xffffffff,    /* ???? */
935                      buffer.p_data,
936                      buffer.i_data );
937
938     /* *** response from server, should be 0x02 or 0x03 *** */
939     mms_CommandRead( p_input, 0x02, 0x03 );
940     if( p_access->i_command == 0x03 )
941     {
942         msg_Err( p_input,
943                  "%s protocol selection failed", b_udp ? "UDP" : "TCP" );
944         var_buffer_free( &buffer );
945         MMSClose( p_input );
946         return( -1 );
947     }
948     else if( p_access->i_command != 0x02 )
949     {
950         msg_Warn( p_input, "received command isn't 0x02 in reponse to 0x02" );
951     }
952
953     /* *** send command 5 : media file name/path requested *** */
954     var_buffer_reinitwrite( &buffer, 0 );
955     var_buffer_add64( &buffer, 0 );
956     var_buffer_addUTF16( &buffer, p_url->psz_path );
957
958     mms_CommandSend( p_input,
959                      0x05,
960                      p_access->i_command_level,
961                      0xffffffff,
962                      buffer.p_data,
963                      buffer.i_data );
964
965     /* *** wait for reponse *** */
966     mms_CommandRead( p_input, 0x1a, 0x06 );
967
968     /* test if server send 0x1A answer */
969     if( p_access->i_command == 0x1A )
970     {
971         msg_Err( p_input, "id/password requested (not yet supported)" );
972         /*  FIXME */
973         var_buffer_free( &buffer );
974         MMSClose( p_input );
975         return( -1 );
976     }
977     if( p_access->i_command != 0x06 )
978     {
979         msg_Err( p_input,
980                  "unknown answer (0x%x instead of 0x06)",
981                  p_access->i_command );
982         var_buffer_free( &buffer );
983         MMSClose( p_input );
984         return( -1 );
985     }
986
987     /*  1 for file ok, 2 for authen ok */
988     switch( GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE ) )
989     {
990         case 0x0001:
991             msg_Dbg( p_input, "Media file name/path accepted" );
992             break;
993         case 0x0002:
994             msg_Dbg( p_input, "Authentication accepted" );
995             break;
996         case -1:
997         default:
998         msg_Err( p_input, "error while asking for file %d",
999                  GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE ) );
1000         var_buffer_free( &buffer );
1001         MMSClose( p_input );
1002         return( -1 );
1003     }
1004
1005     p_access->i_flags_broadcast =
1006         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 12 );
1007     p_access->i_media_length =
1008         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 24 );
1009     p_access->i_packet_length =
1010         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 44 );
1011     p_access->i_packet_count =
1012         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 48 );
1013     p_access->i_max_bit_rate =
1014         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 56 );
1015     p_access->i_header_size =
1016         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 60 );
1017
1018     msg_Dbg( p_input,
1019              "answer 0x06 flags:0x%8.8x media_length:%ds packet_length:%d packet_count:%d max_bit_rate:%d header_size:%d",
1020              p_access->i_flags_broadcast,
1021              p_access->i_media_length,
1022              p_access->i_packet_length,
1023              p_access->i_packet_count,
1024              p_access->i_max_bit_rate,
1025              p_access->i_header_size );
1026
1027     /* XXX XXX dirty hack XXX XXX */
1028     p_input->i_mtu    = 3 * p_access->i_packet_length;
1029
1030     /* *** send command 15 *** */
1031
1032     var_buffer_reinitwrite( &buffer, 0 );
1033     var_buffer_add32( &buffer, 0 );
1034     var_buffer_add32( &buffer, 0x8000 );
1035     var_buffer_add32( &buffer, 0xffffffff );
1036     var_buffer_add32( &buffer, 0x00 );
1037     var_buffer_add32( &buffer, 0x00 );
1038     var_buffer_add32( &buffer, 0x00 );
1039     var_buffer_add64( &buffer, 0x40ac200000000000 );
1040     var_buffer_add32( &buffer, p_access->i_header_packet_id_type );
1041     mms_CommandSend( p_input, 0x15, p_access->i_command_level, 0x00,
1042                      buffer.p_data, buffer.i_data );
1043
1044     /* *** wait for reponse *** */
1045     mms_CommandRead( p_input, 0x11, 0 );
1046
1047     if( p_access->i_command != 0x11 )
1048     {
1049         msg_Err( p_input,
1050                  "unknown answer (0x%x instead of 0x11)",
1051                  p_access->i_command );
1052         var_buffer_free( &buffer );
1053         MMSClose( p_input );
1054         return( -1 );
1055     }
1056     /* *** now read header packet *** */
1057     /* XXX could be split over multiples packets */
1058     for( ;; )
1059     {
1060         if( mms_HeaderMediaRead( p_input, MMS_PACKET_HEADER ) < 0 )
1061         {
1062             msg_Err( p_input, "cannot receive header" );
1063             var_buffer_free( &buffer );
1064             MMSClose( p_input );
1065             return( -1 );
1066         }
1067         if( p_access->i_header >= p_access->i_header_size )
1068         {
1069             msg_Dbg( p_input,
1070                      "header complete(%d)",
1071                      p_access->i_header );
1072             break;
1073         }
1074         msg_Dbg( p_input,
1075                  "header incomplete (%d/%d), reading more",
1076                  p_access->i_header,
1077                  p_access->i_header_size );
1078     }
1079
1080     /* *** parse header and get stream and their id *** */
1081     /* get all streams properties,
1082      *
1083      * TODO : stream bitrates properties(optional)
1084      *        and bitrate mutual exclusion(optional) */
1085     asf_HeaderParse( p_access->stream,
1086                      p_access->p_header, p_access->i_header );
1087     mms_StreamSelect( p_input, p_access->stream );
1088     /* *** now select stream we want to receive *** */
1089     /* TODO take care of stream bitrate TODO */
1090     i_streams = 0;
1091     i_first = -1;
1092     var_buffer_reinitwrite( &buffer, 0 );
1093     /* for now, select first audio and video stream */
1094     for( i = 1; i < 128; i++ )
1095     {
1096
1097         if( p_access->stream[i].i_cat != MMS_STREAM_UNKNOWN )
1098         {
1099             i_streams++;
1100             if( i_first != -1 )
1101             {
1102                 var_buffer_add16( &buffer, 0xffff );
1103                 var_buffer_add16( &buffer, i );
1104             }
1105             else
1106             {
1107                 i_first = i;
1108             }
1109             if( p_access->stream[i].i_selected )
1110             {
1111                 var_buffer_add16( &buffer, 0x0000 );
1112                 msg_Info( p_input,
1113                           "selecting stream[0x%x] %s (%d kb/s)",
1114                           i,
1115                           ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO  ) ?
1116                                                   "audio" : "video" ,
1117                           p_access->stream[i].i_bitrate / 1024);
1118             }
1119             else
1120             {
1121                 var_buffer_add16( &buffer, 0x0002 );
1122                 msg_Info( p_input,
1123                           "ignoring stream[0x%x] %s (%d kb/s)",
1124                           i,
1125                           ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO  ) ?
1126                                     "audio" : "video" ,
1127                           p_access->stream[i].i_bitrate / 1024);
1128
1129             }
1130         }
1131     }
1132
1133     if( i_streams == 0 )
1134     {
1135         msg_Err( p_input, "cannot find any stream" );
1136         var_buffer_free( &buffer );
1137         MMSClose( p_input );
1138         return( -1 );
1139     }
1140     mms_CommandSend( p_input, 0x33,
1141                      i_streams,
1142                      0xffff | ( i_first << 16 ),
1143                      buffer.p_data, buffer.i_data );
1144
1145     mms_CommandRead( p_input, 0x21, 0 );
1146     if( p_access->i_command != 0x21 )
1147     {
1148         msg_Err( p_input,
1149                  "unknown answer (0x%x instead of 0x21)",
1150                  p_access->i_command );
1151         var_buffer_free( &buffer );
1152         MMSClose( p_input );
1153         return( -1 );
1154     }
1155
1156
1157     var_buffer_free( &buffer );
1158
1159     msg_Info( p_input, "connection sucessful" );
1160
1161     return( 0 );
1162 }
1163
1164 /****************************************************************************
1165  * MMSStart : Start streaming
1166  ****************************************************************************/
1167 static int MMSStart  ( input_thread_t  *p_input, uint32_t i_packet )
1168 {
1169     access_t        *p_access = (access_t*)p_input->p_access_data;
1170     var_buffer_t    buffer;
1171
1172     /* *** start stream from packet 0 *** */
1173     var_buffer_initwrite( &buffer, 0 );
1174     var_buffer_add64( &buffer, 0 ); /* seek point in second */
1175     var_buffer_add32( &buffer, 0xffffffff );
1176     var_buffer_add32( &buffer, i_packet ); // begin from start
1177     var_buffer_add8( &buffer, 0xff ); // stream time limit
1178     var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
1179     var_buffer_add8( &buffer, 0xff ); //
1180     var_buffer_add8( &buffer, 0x00 ); // don't use limit
1181     var_buffer_add32( &buffer, p_access->i_media_packet_id_type );
1182
1183     mms_CommandSend( p_input, 0x07, p_access->i_command_level, 0x0001ffff,
1184                      buffer.p_data, buffer.i_data );
1185
1186     var_buffer_free( &buffer );
1187
1188     mms_CommandRead( p_input, 0x05, 0 );
1189
1190     if( p_access->i_command != 0x05 )
1191     {
1192         msg_Err( p_input,
1193                  "unknown answer (0x%x instead of 0x05)",
1194                  p_access->i_command );
1195         return( -1 );
1196     }
1197     else
1198     {
1199         /* get a packet */
1200         mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA );
1201         msg_Dbg( p_input, "Streaming started" );
1202         return( 0 );
1203     }
1204 }
1205
1206 /****************************************************************************
1207  * MMSStop : Stop streaming
1208  ****************************************************************************/
1209 static int MMSStop  ( input_thread_t  *p_input )
1210 {
1211     access_t        *p_access = (access_t*)p_input->p_access_data;
1212
1213     /* *** stop stream but keep connection alive *** */
1214     mms_CommandSend( p_input,
1215                      0x09,
1216                      p_access->i_command_level,
1217                      0x001fffff,
1218                      NULL, 0 );
1219     return( 0 );
1220 }
1221
1222 /****************************************************************************
1223  * MMSClose : Close streaming and connection
1224  ****************************************************************************/
1225 static int MMSClose  ( input_thread_t  *p_input )
1226 {
1227     access_t        *p_access = (access_t*)p_input->p_access_data;
1228
1229     msg_Dbg( p_input, "Connection closed" );
1230
1231     /* *** tell server that we will disconnect *** */
1232     mms_CommandSend( p_input,
1233                      0x0d,
1234                      p_access->i_command_level,
1235                      0x00000001,
1236                      NULL, 0 );
1237     /* *** close sockets *** */
1238 #if defined( UNDER_CE )
1239     CloseHandle( (HANDLE)p_access->socket_tcp.i_handle );
1240 #elif defined( WIN32 )
1241     closesocket( p_access->socket_tcp.i_handle );
1242 #else
1243     close( p_access->socket_tcp.i_handle );
1244 #endif
1245
1246     if( p_access->i_proto == MMS_PROTO_UDP )
1247     {
1248 #if defined( UNDER_CE )
1249         CloseHandle( (HANDLE)p_access->socket_udp.i_handle );
1250 #elif defined( WIN32 )
1251         closesocket( p_access->socket_udp.i_handle );
1252 #else
1253         close( p_access->socket_udp.i_handle );
1254 #endif
1255     }
1256
1257     FREE( p_access->p_cmd );
1258     FREE( p_access->p_media );
1259     FREE( p_access->p_header );
1260
1261     FREE( p_access->psz_server_version );
1262     FREE( p_access->psz_tool_version );
1263     FREE( p_access->psz_update_player_url );
1264     FREE( p_access->psz_encryption_type );
1265
1266     return( 0 );
1267 }
1268
1269 /*****************************************************************************
1270  * mms_ParseURL : parse an url string and fill an url_t
1271  *****************************************************************************/
1272 static void mms_ParseURL( url_t *p_url, char *psz_url )
1273 {
1274     char *psz_parser;
1275     char *psz_server_port;
1276
1277     p_url->psz_private = strdup( psz_url );
1278
1279     psz_parser = p_url->psz_private;
1280
1281     while( *psz_parser == '/' )
1282     {
1283         psz_parser++;
1284     }
1285     p_url->psz_server_addr = psz_parser;
1286
1287     while( *psz_parser &&
1288            *psz_parser != ':' &&  *psz_parser != '/' && *psz_parser != '@' )
1289     {
1290         psz_parser++;
1291     }
1292
1293     if( *psz_parser == ':' )
1294     {
1295         *psz_parser = '\0';
1296         psz_parser++;
1297         psz_server_port = psz_parser;
1298
1299         while( *psz_parser && *psz_parser != '/' )
1300         {
1301             psz_parser++;
1302         }
1303     }
1304     else
1305     {
1306         psz_server_port = "";
1307     }
1308
1309     if( *psz_parser == '@' )
1310     {
1311         char *psz_bind_port;
1312
1313         *psz_parser = '\0';
1314         psz_parser++;
1315
1316         p_url->psz_bind_addr = psz_parser;
1317
1318         while( *psz_parser && *psz_parser != ':' && *psz_parser != '/' )
1319         {
1320             psz_parser++;
1321         }
1322
1323         if( *psz_parser == ':' )
1324         {
1325             *psz_parser = '\0';
1326             psz_parser++;
1327             psz_bind_port = psz_parser;
1328
1329             while( *psz_parser && *psz_parser != '/' )
1330             {
1331                 psz_parser++;
1332             }
1333         }
1334         else
1335         {
1336             psz_bind_port = "";
1337         }
1338         if( *psz_bind_port )
1339         {
1340             p_url->i_bind_port = strtol( psz_bind_port, &psz_parser, 10 );
1341         }
1342         else
1343         {
1344             p_url->i_bind_port = 0;
1345         }
1346     }
1347     else
1348     {
1349         p_url->psz_bind_addr = "";
1350         p_url->i_bind_port = 0;
1351     }
1352
1353     if( *psz_parser == '/' )
1354     {
1355         *psz_parser = '\0';
1356         psz_parser++;
1357         p_url->psz_path = psz_parser;
1358     }
1359
1360     if( *psz_server_port )
1361     {
1362         p_url->i_server_port = strtol( psz_server_port, &psz_parser, 10 );
1363     }
1364     else
1365     {
1366         p_url->i_server_port = 0;
1367     }
1368 }
1369
1370 /****************************************************************************
1371  *
1372  * MMS specific functions
1373  *
1374  ****************************************************************************/
1375
1376 static int mms_CommandSend( input_thread_t *p_input,
1377                              int i_command,
1378                              uint32_t i_prefix1, uint32_t i_prefix2,
1379                              uint8_t *p_data, int i_data )
1380 {
1381     var_buffer_t buffer;
1382
1383     access_t    *p_access = (access_t*)p_input->p_access_data;
1384     int i_data_by8;
1385
1386     i_data_by8 = ( i_data + 7 ) / 8;
1387
1388     /* first init uffer */
1389     var_buffer_initwrite( &buffer, 0 );
1390
1391     var_buffer_add32( &buffer, 0x00000001 );    /* start sequence */
1392     var_buffer_add32( &buffer, 0xB00BFACE );
1393     /* size after protocol type */
1394     var_buffer_add32( &buffer, i_data + MMS_CMD_HEADERSIZE - 16 );
1395     var_buffer_add32( &buffer, 0x20534d4d );    /* protocol "MMS " */
1396     var_buffer_add32( &buffer, i_data_by8 + 4 );
1397     var_buffer_add32( &buffer, p_access->i_seq_num ); p_access->i_seq_num++;
1398     var_buffer_add64( &buffer, 0 );
1399     var_buffer_add32( &buffer, i_data_by8 + 2 );
1400     var_buffer_add32( &buffer, 0x00030000 | i_command ); /* dir | command */
1401     var_buffer_add32( &buffer, i_prefix1 );    /* command specific */
1402     var_buffer_add32( &buffer, i_prefix2 );    /* command specific */
1403
1404     /* specific command data */
1405     if( p_data && i_data > 0 )
1406     {
1407         var_buffer_addmemory( &buffer, p_data, i_data );
1408     }
1409
1410     /* send it */
1411     if( send( p_access->socket_tcp.i_handle,
1412               buffer.p_data,
1413               buffer.i_data,
1414               0 ) == -1 )
1415     {
1416         msg_Err( p_input, "failed to send command" );
1417         return( -1 );
1418     }
1419
1420     var_buffer_free( &buffer );
1421     return( 0 );
1422 }
1423
1424 static int  NetFillBuffer( input_thread_t *p_input )
1425 {
1426 #ifdef UNDER_CE
1427     return -1;
1428 #else
1429     access_t    *p_access = (access_t*)p_input->p_access_data;
1430     struct timeval  timeout;
1431     fd_set          fds;
1432     int             i_ret;
1433
1434     /* FIXME when using udp */
1435     ssize_t i_tcp, i_udp;
1436     ssize_t i_tcp_read, i_udp_read;
1437     int i_handle_max;
1438
1439     /* Initialize file descriptor set */
1440     FD_ZERO( &fds );
1441
1442     i_tcp = MMS_BUFFER_SIZE/2 - p_access->i_buffer_tcp;
1443
1444     if( p_access->i_proto == MMS_PROTO_UDP )
1445     {
1446         i_udp = MMS_BUFFER_SIZE/2 - p_access->i_buffer_udp;
1447     }
1448     else
1449     {
1450         i_udp = 0;  /* there isn't udp socket */
1451     }
1452
1453     i_handle_max = 0;
1454     if( i_tcp > 0 )
1455     {
1456         FD_SET( p_access->socket_tcp.i_handle, &fds );
1457         i_handle_max = __MAX( i_handle_max, p_access->socket_tcp.i_handle );
1458     }
1459     if( i_udp > 0 )
1460     {
1461         FD_SET( p_access->socket_udp.i_handle, &fds );
1462         i_handle_max = __MAX( i_handle_max, p_access->socket_udp.i_handle );
1463     }
1464
1465     if( i_handle_max == 0 )
1466     {
1467         msg_Warn( p_input, "nothing to read %d:%d", i_tcp, i_udp );
1468         return( 0 );
1469     }
1470     else
1471     {
1472 //        msg_Warn( p_input, "ask for tcp:%d udp:%d", i_tcp, i_udp );
1473     }
1474
1475     /* We'll wait 0.5 second if nothing happens */
1476     timeout.tv_sec = 0;
1477     timeout.tv_usec = 500000;
1478
1479     /* Find if some data is available */
1480     i_ret = select( i_handle_max + 1,
1481                     &fds,
1482                     NULL, NULL, &timeout );
1483
1484     if( i_ret == -1 && errno != EINTR )
1485     {
1486         msg_Err( p_input, "network select error (%s)", strerror(errno) );
1487         return -1;
1488     }
1489
1490     if( i_tcp > 0 && FD_ISSET( p_access->socket_tcp.i_handle, &fds ) )
1491     {
1492         i_tcp_read =
1493             recv( p_access->socket_tcp.i_handle,
1494                   p_access->buffer_tcp + p_access->i_buffer_tcp,
1495                   i_tcp + MMS_BUFFER_SIZE/2, 0 );
1496     }
1497     else
1498     {
1499         i_tcp_read = 0;
1500     }
1501
1502     if( i_udp > 0 && FD_ISSET( p_access->socket_udp.i_handle, &fds ) )
1503     {
1504         i_udp_read = recv( p_access->socket_udp.i_handle,
1505                            p_access->buffer_udp + p_access->i_buffer_udp,
1506                            i_udp + MMS_BUFFER_SIZE/2, 0 );
1507     }
1508     else
1509     {
1510         i_udp_read = 0;
1511     }
1512
1513 #if MMS_DEBUG
1514     if( p_access->i_proto == MMS_PROTO_UDP )
1515     {
1516         msg_Dbg( p_input,
1517                  "filling buffer TCP:%d+%d UDP:%d+%d",
1518                  p_access->i_buffer_tcp,
1519                  i_tcp_read,
1520                  p_access->i_buffer_udp,
1521                  i_udp_read );
1522     }
1523     else
1524     {
1525         msg_Dbg( p_input,
1526                  "filling buffer TCP:%d+%d",
1527                  p_access->i_buffer_tcp,
1528                  i_tcp_read );
1529     }
1530 #endif
1531     if( i_tcp_read > 0 )
1532     {
1533         p_access->i_buffer_tcp += i_tcp_read;
1534     }
1535     if( i_udp_read > 0 )
1536     {
1537         p_access->i_buffer_udp += i_udp_read;
1538     }
1539
1540     return( i_tcp_read + i_udp_read);
1541 #endif
1542 }
1543
1544 static int  mms_ParseCommand( input_thread_t *p_input,
1545                               uint8_t *p_data,
1546                               int i_data,
1547                               int *pi_used )
1548 {
1549  #define GET32( i_pos ) \
1550     ( p_access->p_cmd[i_pos] + ( p_access->p_cmd[i_pos +1] << 8 ) + \
1551       ( p_access->p_cmd[i_pos + 2] << 16 ) + \
1552       ( p_access->p_cmd[i_pos + 3] << 24 ) )
1553
1554     access_t    *p_access = (access_t*)p_input->p_access_data;
1555     int         i_length;
1556     uint32_t    i_id;
1557
1558     if( p_access->p_cmd )
1559     {
1560         free( p_access->p_cmd );
1561     }
1562     p_access->i_cmd = i_data;
1563     p_access->p_cmd = malloc( i_data );
1564     memcpy( p_access->p_cmd, p_data, i_data );
1565
1566     *pi_used = i_data; /* by default */
1567
1568     if( i_data < MMS_CMD_HEADERSIZE )
1569     {
1570         msg_Warn( p_input, "truncated command (header incomplete)" );
1571         p_access->i_command = 0;
1572         return( -1 );
1573     }
1574     i_id =  GetDWLE( p_data + 4 );
1575     i_length = GetDWLE( p_data + 8 ) + 16;
1576
1577     if( i_id != 0xb00bface )
1578     {
1579         msg_Err( p_input,
1580                  "incorrect command header (0x%x)", i_id );
1581         p_access->i_command = 0;
1582         return( -1 );
1583     }
1584
1585     if( i_length > p_access->i_cmd )
1586     {
1587         msg_Warn( p_input,
1588                   "truncated command (missing %d bytes)",
1589                    i_length - i_data  );
1590         p_access->i_command = 0;
1591         return( -1 );
1592     }
1593     else if( i_length < p_access->i_cmd )
1594     {
1595         p_access->i_cmd = i_length;
1596         *pi_used = i_length;
1597     }
1598
1599     msg_Dbg( p_input,
1600              "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",
1601              GET32( 0 ),
1602              GET32( 4 ),
1603              GET32( 8 ),
1604              /* 12: protocol type "MMS " */
1605              GET32( 16 ),
1606              GET32( 20 ),
1607              /* 24: unknown (0) */
1608              /* 28: unknown (0) */
1609              GET32( 32 ),
1610              GET32( 36 )
1611              /* 40: switches */
1612              /* 44: extra */ );
1613
1614     p_access->i_command = GET32( 36 ) & 0xffff;
1615
1616     return( MMS_PACKET_CMD );
1617 }
1618
1619 static int  mms_ParsePacket( input_thread_t *p_input,
1620                              uint8_t *p_data, size_t i_data,
1621                              int *pi_used )
1622 {
1623     access_t    *p_access = (access_t*)p_input->p_access_data;
1624     int i_packet_seq_num;
1625     size_t i_packet_length;
1626     uint32_t i_packet_id;
1627
1628     uint8_t  *p_packet;
1629
1630
1631     *pi_used = i_data; /* default */
1632     if( i_data <= 8 )
1633     {
1634         msg_Warn( p_input, "truncated packet (header incomplete)" );
1635         return( -1 );
1636     }
1637
1638     i_packet_id = p_data[4];
1639     i_packet_seq_num = GetDWLE( p_data );
1640     i_packet_length = GetWLE( p_data + 6 );
1641
1642     //msg_Warn( p_input, "------->i_packet_length=%d, i_data=%d", i_packet_length, i_data );
1643
1644     if( i_packet_length > i_data || i_packet_length <= 8)
1645     {
1646         msg_Dbg( p_input,
1647                  "truncated packet (missing %d bytes)",
1648                  i_packet_length - i_data  );
1649         *pi_used = 0;
1650         return( -1 );
1651     }
1652     else if( i_packet_length < i_data )
1653     {
1654         *pi_used = i_packet_length;
1655     }
1656
1657     if( i_packet_id == 0xff )
1658     {
1659         msg_Warn( p_input,
1660                   "receive MMS UDP pair timing" );
1661         return( MMS_PACKET_UDP_TIMING );
1662     }
1663
1664     if( i_packet_id != p_access->i_header_packet_id_type &&
1665         i_packet_id != p_access->i_media_packet_id_type )
1666     {
1667         msg_Warn( p_input, "incorrect Packet Id Type (0x%x)", i_packet_id );
1668         return( -1 );
1669     }
1670
1671     /* we now have a media or a header packet */
1672     p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader
1673     memcpy( p_packet, p_data + 8, i_packet_length - 8 );
1674
1675     if( i_packet_seq_num != p_access->i_packet_seq_num )
1676     {
1677         /* FIXME for udp could be just wrong order ? */
1678         msg_Warn( p_input,
1679                   "detected packet lost (%d != %d)",
1680                   i_packet_seq_num,
1681                   p_access->i_packet_seq_num );
1682         p_access->i_packet_seq_num = i_packet_seq_num;
1683     }
1684     p_access->i_packet_seq_num++;
1685
1686     if( i_packet_id == p_access->i_header_packet_id_type )
1687     {
1688         if( p_access->p_header )
1689         {
1690             p_access->p_header = realloc( p_access->p_header,
1691                                           p_access->i_header + i_packet_length - 8 );
1692             memcpy( &p_access->p_header[p_access->i_header],
1693                     p_packet,
1694                     i_packet_length - 8 );
1695             p_access->i_header += i_packet_length - 8;
1696
1697             free( p_packet );
1698         }
1699         else
1700         {
1701             p_access->p_header = p_packet;
1702             p_access->i_header = i_packet_length - 8;
1703         }
1704 /*        msg_Dbg( p_input,
1705                  "receive header packet (%d bytes)",
1706                  i_packet_length - 8 ); */
1707
1708         return( MMS_PACKET_HEADER );
1709     }
1710     else
1711     {
1712         FREE( p_access->p_media );
1713         p_access->p_media = p_packet;
1714         p_access->i_media = i_packet_length - 8;
1715         p_access->i_media_used = 0;
1716 /*        msg_Dbg( p_input,
1717                  "receive media packet (%d bytes)",
1718                  i_packet_length - 8 ); */
1719
1720         return( MMS_PACKET_MEDIA );
1721     }
1722 }
1723
1724 static int mms_ReceivePacket( input_thread_t *p_input )
1725 {
1726     access_t    *p_access = (access_t*)p_input->p_access_data;
1727     int i_packet_tcp_type;
1728     int i_packet_udp_type;
1729
1730     for( ;; )
1731     {
1732         if( NetFillBuffer( p_input ) < 0 )
1733         {
1734             msg_Warn( p_input, "cannot fill buffer" );
1735             continue;
1736         }
1737
1738         i_packet_tcp_type = -1;
1739         i_packet_udp_type = -1;
1740
1741         if( p_access->i_buffer_tcp > 0 )
1742         {
1743             int i_used;
1744
1745             if( GetDWLE( p_access->buffer_tcp + 4 ) == 0xb00bface )
1746             {
1747                 i_packet_tcp_type =
1748                     mms_ParseCommand( p_input,
1749                                       p_access->buffer_tcp,
1750                                       p_access->i_buffer_tcp,
1751                                       &i_used );
1752
1753             }
1754             else
1755             {
1756                 i_packet_tcp_type =
1757                     mms_ParsePacket( p_input,
1758                                      p_access->buffer_tcp,
1759                                      p_access->i_buffer_tcp,
1760                                      &i_used );
1761             }
1762             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
1763             {
1764                 memmove( p_access->buffer_tcp,
1765                          p_access->buffer_tcp + i_used,
1766                          MMS_BUFFER_SIZE - i_used );
1767             }
1768             p_access->i_buffer_tcp -= i_used;
1769         }
1770         else if( p_access->i_buffer_udp > 0 )
1771         {
1772             int i_used;
1773
1774             i_packet_udp_type =
1775                 mms_ParsePacket( p_input,
1776                                  p_access->buffer_udp,
1777                                  p_access->i_buffer_udp,
1778                                  &i_used );
1779
1780             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
1781             {
1782                 memmove( p_access->buffer_udp,
1783                          p_access->buffer_udp + i_used,
1784                          MMS_BUFFER_SIZE - i_used );
1785             }
1786             p_access->i_buffer_udp -= i_used;
1787         }
1788
1789         if( i_packet_tcp_type == MMS_PACKET_CMD &&
1790                 p_access->i_command == 0x1b )
1791         {
1792             mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
1793             i_packet_tcp_type = -1;
1794         }
1795
1796         if( i_packet_tcp_type != -1 )
1797         {
1798             return( i_packet_tcp_type );
1799         }
1800         else if( i_packet_udp_type != -1 )
1801         {
1802             return( i_packet_udp_type );
1803         }
1804
1805     }
1806 }
1807
1808 static int  mms_ReceiveCommand( input_thread_t *p_input )
1809 {
1810     access_t    *p_access = (access_t*)p_input->p_access_data;
1811
1812     for( ;; )
1813     {
1814         int i_used;
1815         int i_status;
1816
1817         if( NetFillBuffer( p_input ) < 0 )
1818         {
1819             msg_Warn( p_input, "cannot fill buffer" );
1820             continue;
1821         }
1822         if( p_access->i_buffer_tcp > 0 )
1823         {
1824             i_status = mms_ParseCommand( p_input,
1825                                   p_access->buffer_tcp,
1826                                   p_access->i_buffer_tcp,
1827                                   &i_used );
1828             if( i_used < MMS_BUFFER_SIZE )
1829             {
1830                 memmove( p_access->buffer_tcp,
1831                          p_access->buffer_tcp + i_used,
1832                          MMS_BUFFER_SIZE - i_used );
1833             }
1834             p_access->i_buffer_tcp -= i_used;
1835
1836             if( i_status < 0 )
1837             {
1838                 return( -1 );
1839             }
1840
1841             if( p_access->i_command == 0x1b )
1842             {
1843                 mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
1844             }
1845             else
1846             {
1847                 break;
1848             }
1849         }
1850         else
1851         {
1852             return( -1 );
1853         }
1854     }
1855
1856     return( 0 );
1857 }
1858
1859 #define MMS_RETRY_MAX       10
1860 #define MMS_RETRY_SLEEP     50000
1861
1862 static int mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 )
1863 {
1864     access_t    *p_access = (access_t*)p_input->p_access_data;
1865     int i_count;
1866     int i_status;
1867
1868     for( i_count = 0; i_count < MMS_RETRY_MAX; )
1869     {
1870
1871         i_status = mms_ReceiveCommand( p_input );
1872         if( i_status < 0 || p_access->i_command == 0 )
1873         {
1874             i_count++;
1875             msleep( MMS_RETRY_SLEEP );
1876         }
1877         else if( i_command1 == 0 && i_command2 == 0)
1878         {
1879             return( 0 );
1880         }
1881         else if( p_access->i_command == i_command1 || p_access->i_command == i_command2 )
1882         {
1883             return( 0 );
1884         }
1885         else
1886         {
1887             switch( p_access->i_command )
1888             {
1889                 case 0x03:
1890                     msg_Warn( p_input, "socket closed by server" );
1891                     p_access->i_eos = 1;
1892                     return( -1 );
1893                 case 0x1e:
1894                     msg_Warn( p_input, "end of media stream" );
1895                     p_access->i_eos = 1;
1896                     return( -1 );
1897                 default:
1898                     break;
1899             }
1900         }
1901     }
1902     msg_Warn( p_input, "failed to receive command (abording)" );
1903
1904     return( -1 );
1905 }
1906
1907
1908 static int mms_HeaderMediaRead( input_thread_t *p_input, int i_type )
1909 {
1910     access_t    *p_access = (access_t*)p_input->p_access_data;
1911     int         i_count;
1912
1913     for( i_count = 0; i_count < MMS_RETRY_MAX; )
1914     {
1915         int i_status;
1916
1917         i_status = mms_ReceivePacket( p_input );
1918         if( i_status < 0 )
1919         {
1920             i_count++;
1921             msg_Warn( p_input,
1922                       "cannot receive header (%d/%d)", i_count, MMS_RETRY_MAX );
1923             msleep( MMS_RETRY_SLEEP );
1924         }
1925         else if( i_status == i_type || i_type == MMS_PACKET_ANY )
1926         {
1927             return( i_type );
1928         }
1929         else if( i_status == MMS_PACKET_CMD )
1930         {
1931             switch( p_access->i_command )
1932             {
1933                 case 0x03:
1934                     msg_Warn( p_input, "socket closed by server" );
1935                     p_access->i_eos = 1;
1936                     return( -1 );
1937                 case 0x1e:
1938                     msg_Warn( p_input, "end of media stream" );
1939                     p_access->i_eos = 1;
1940                     return( -1 );
1941                 case 0x20:
1942                     /* XXX not too dificult to be done EXCEPT that we
1943                      * need to restart demuxer... and I don't see how we
1944                      * could do that :p */
1945                     msg_Err( p_input,
1946                              "reinitialization needed --> unsupported" );
1947                     p_access->i_eos = 1;
1948                     return( -1 );
1949                 default:
1950                     break;
1951             }
1952         }
1953     }
1954     msg_Err( p_input,
1955              "cannot receive %s (abording)",
1956                ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" );
1957     return( -1 );
1958 }
1959