1 /*
2  * Copyright (C) 2002-2004 the xine project
3  *
4  * This file is part of LibMMS, an MMS protocol handling library.
5  *
6  * xine is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the ree Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * xine is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
19  *
20  * $Id: mms.c,v 1.31 2007/12/11 20:35:01 jwrdegoede Exp $
21  *
22  * MMS over TCP protocol
23  *   based on work from major mms
24  *   utility functions to handle communication with an mms server
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 
31 #include <unistd.h>
32 #include <stdio.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <netdb.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <errno.h>
41 #include <stdlib.h>
42 #include <time.h>
43 
44 //#define USE_ICONV
45 
46 #ifdef USE_ICONV
47 #include <iconv.h>
48 #else
49 // use deadbeef's charset conversion instead of iconv
50 #include "../../../deadbeef.h"
51 extern DB_functions_t *deadbeef;
52 #endif
53 
54 /********** logging **********/
55 #define lprintf(...) if (getenv("LIBMMS_DEBUG")) fprintf(stderr, __VA_ARGS__)
56 
57 #define __MMS_C__
58 
59 #include "bswap.h"
60 #include "mms.h"
61 #include "asfheader.h"
62 #include "uri.h"
63 #include "mms-common.h"
64 
65 /*
66  * mms specific types
67  */
68 
69 #define MMST_PORT 1755
70 
71 #define BUF_SIZE 102400
72 
73 #define CMD_HEADER_LEN   40
74 #define CMD_PREFIX_LEN    8
75 #define CMD_BODY_LEN   1024 * 16 /* FIXME: make this dynamic */
76 
77 #define ASF_HEADER_LEN (8192 * 2)
78 
79 
80 #define MMS_PACKET_ERR        0
81 #define MMS_PACKET_COMMAND    1
82 #define MMS_PACKET_ASF_HEADER 2
83 #define MMS_PACKET_ASF_PACKET 3
84 
85 #define ASF_HEADER_PACKET_ID_TYPE 2
86 #define ASF_MEDIA_PACKET_ID_TYPE  4
87 
88 
89 typedef struct mms_buffer_s mms_buffer_t;
90 struct mms_buffer_s {
91   uint8_t *buffer;
92   int pos;
93 };
94 
95 typedef struct mms_packet_header_s mms_packet_header_t;
96 struct mms_packet_header_s {
97   uint32_t  packet_len;
98   uint8_t   flags;
99   uint8_t   packet_id_type;
100   uint32_t  packet_seq;
101 };
102 
103 struct mms_s {
104 
105   int           s;
106 
107   /* url parsing */
108   GURI         *guri;
109   char         *url;
110   char         *proto;
111   char         *host;
112   int           port;
113   char         *user;
114   char         *password;
115   char         *uri;
116 
117   /* command to send */
118   char          scmd[CMD_HEADER_LEN + CMD_BODY_LEN];
119   char         *scmd_body; /* pointer to &scmd[CMD_HEADER_LEN] */
120   int           scmd_len; /* num bytes written in header */
121 
122   char          str[1024]; /* scratch buffer to built strings */
123 
124   /* receive buffer */
125   uint8_t       buf[BUF_SIZE];
126   int           buf_size;
127   int           buf_read;
128   off_t         buf_packet_seq_offset; /* packet sequence offset residing in
129                                           buf */
130 
131   uint8_t       asf_header[ASF_HEADER_LEN];
132   uint32_t      asf_header_len;
133   uint32_t      asf_header_read;
134   int           seq_num;
135   int           num_stream_ids;
136   mms_stream_t  streams[ASF_MAX_NUM_STREAMS];
137   uint8_t       packet_id_type;
138   off_t         start_packet_seq; /* for live streams != 0, need to keep it around */
139   int           need_discont; /* whether we need to set start_packet_seq */
140   uint32_t      asf_packet_len;
141   uint64_t      file_len;
142   uint64_t      time_len; /* playback time in 100 nanosecs (10^-7) */
143   uint64_t      preroll;
144   uint64_t      asf_num_packets;
145   char          guid[37];
146   int           bandwidth;
147 
148   int           has_audio;
149   int           has_video;
150   int           live_flag;
151   int           seekable;
152   off_t         current_pos;
153   int           eos;
154 
155   int *need_abort;
156 };
157 
fallback_io_select(void * data,int socket,int state,int timeout_msec)158 static int fallback_io_select(void *data, int socket, int state, int timeout_msec)
159 {
160   fd_set set;
161   struct timeval tv = { timeout_msec / 1000, (timeout_msec % 1000) * 1000};
162   FD_ZERO(&set);
163   FD_SET(socket, &set);
164   return select(1, (state == MMS_IO_READ_READY) ? &set : NULL,
165                    (state == MMS_IO_WRITE_READY) ? &set : NULL, NULL, &tv);
166 }
167 
fallback_io_read(void * data,int socket,char * buf,off_t num,int * need_abort)168 static off_t fallback_io_read(void *data, int socket, char *buf, off_t num, int *need_abort)
169 {
170   off_t len = 0, ret;
171 /*   lprintf("%d\n", fallback_io_select(data, socket, MMS_IO_READ_READY, 1000)); */
172   errno = 0;
173   int nretry = 600;
174   lprintf ("mms: fallback_io_read: need_abort ptr = %p\n", need_abort);
175   while (len < num && nretry > 0 && (!need_abort || !(*need_abort)))
176   {
177     // original read from upstream libmms
178     //ret = (off_t)read(socket, buf + len, num - len);
179     for (;;) {
180         ret = (off_t)recv(socket, buf + len, num - len, MSG_DONTWAIT);
181         if ((ret != EAGAIN && ret != EWOULDBLOCK) || (need_abort && *need_abort)) {
182             break;
183         }
184     }
185     if (need_abort && *need_abort) {
186         return 0;
187     }
188     if(ret == 0)
189       break; /* EOF */
190     if(ret < 0) {
191       lprintf("mms: read error @ len = %lld: %s\n", (long long int) len,
192               strerror(errno));
193       switch(errno)
194       {
195           case EAGAIN:
196               usleep (30000); // sleeping 30ms 200 times will give us about 6 sec of time to complete the request
197               nretry--;
198             continue;
199           default:
200             /* if already read something, return it, we will fail next time */
201             return len ? len : ret;
202       }
203     }
204     len += ret;
205   }
206   return len;
207 }
208 
fallback_io_write(void * data,int socket,char * buf,off_t num)209 static off_t fallback_io_write(void *data, int socket, char *buf, off_t num)
210 {
211   return (off_t)write(socket, buf, num);
212 }
213 
fallback_io_tcp_connect(void * data,const char * host,int port,int * need_abort)214 static int fallback_io_tcp_connect(void *data, const char *host, int port, int *need_abort)
215 {
216 
217   struct hostent *h;
218   int i, s;
219 
220 #ifdef USE_GETHOSTBYNAME
221   h = gethostbyname(host);
222   if (h == NULL) {
223     lprintf("mms: unable to resolve host: %s\n", host);
224     return -1;
225   }
226   char **h_addr_list = h->h_addr_list;
227 #else
228   char sport[10];
229   snprintf (sport, 10, "%d", port);
230   struct addrinfo *res;
231   for (;;) {
232       int err = getaddrinfo (host, sport, NULL, &res);
233       if (need_abort && *need_abort) {
234           if (res) {
235               freeaddrinfo(res);
236           }
237           return -1;
238       }
239 
240       if (err == EAI_AGAIN) {
241           lprintf ("getaddrinfo again\n");
242           continue;
243       }
244       else if (err == 0) {
245           lprintf ("getaddrinfo success\n");
246           break;
247       }
248       lprintf ("getaddrinfo err: %d\n", err);
249       return -1;
250   }
251 #endif
252 
253   s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
254   if (s == -1) {
255     lprintf("mms: failed to create socket: %s\n", strerror(errno));
256     return -1;
257   }
258 
259   if (fcntl (s, F_SETFL, fcntl (s, F_GETFL) | O_NONBLOCK) == -1) {
260     lprintf("mms: failed to set socket flags: %s\n", strerror(errno));
261     return -1;
262   }
263 
264 #ifdef USE_GETHOSTBYNAME
265   for (i = 0; h_addr_list[i]; i++) {
266     struct in_addr ia;
267     struct sockaddr_in sin;
268 
269     memcpy (&ia, h_addr_list[i], 4);
270     sin.sin_family = AF_INET;
271     sin.sin_addr   = ia;
272     sin.sin_port   = htons(port);
273 #else
274   struct addrinfo *rp;
275   for (rp = res; rp != NULL; rp = rp->ai_next) {
276     struct sockaddr_in sin;
277     memset (&sin, 0, sizeof (sin));
278     int l = rp->ai_addrlen;
279     if (l > sizeof (sin)) {
280         l = sizeof (sin);
281     }
282     memcpy (&sin, rp->ai_addr, l);
283 #endif
284 
285     time_t t = time (NULL);
286     int error = 0;
287     while (!need_abort || !(*need_abort)) {
288         int res = connect(s, (struct sockaddr *)&sin, sizeof(sin));
289         if (res == -1 && (errno == EINPROGRESS || errno == EALREADY)) {
290             if (time (NULL) - t > 3) {
291                 error = -1;
292                 break;
293             }
294             usleep(100000);
295             continue;
296         }
297         else if (res == -1 && errno == EISCONN) {
298             break;
299         }
300         else if (res == -1) {
301             error = -1;
302             break;
303         }
304     }
305     if (need_abort && *need_abort) {
306         lprintf ("fallback_io_tcp_connect: aborted\n");
307         s = -1;
308         break;
309     }
310 //        if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) ==-1 && errno != EINPROGRESS) {
311 //            continue;
312 //        }
313     if (error) {
314         continue;
315     }
316 
317 #ifndef USE_GETHOSTBYNAME
318     if (res) {
319         freeaddrinfo(res);
320     }
321 #endif
322     return s;
323   }
324 #ifndef USE_GETHOSTBYNAME
325   if (res) {
326       freeaddrinfo(res);
327   }
328 #endif
329   close(s);
330   return -1;
331 }
332 
333 
334 static mms_io_t fallback_io =
335   {
336     &fallback_io_select,
337     NULL,
338     &fallback_io_read,
339     NULL,
340     &fallback_io_write,
341     NULL,
342     &fallback_io_tcp_connect,
343     NULL,
344   };
345 
346 static mms_io_t default_io =   {
347     &fallback_io_select,
348     NULL,
349     &fallback_io_read,
350     NULL,
351     &fallback_io_write,
352     NULL,
353     &fallback_io_tcp_connect,
354     NULL,
355   };
356 
357 
358 #define io_read(io, args...) ((io) ? (io)->read(io->read_data , ## args) : default_io.read(NULL , ## args))
359 #define io_write(io, args...) ((io) ? (io)->write(io->write_data , ## args) : default_io.write(NULL , ## args))
360 #define io_select(io, args...) ((io) ? (io)->select(io->select_data , ## args) : default_io.select(NULL , ## args))
361 #define io_connect(io, args...) ((io) ? (io)->connect(io->connect_data , ## args) : default_io.connect(NULL , ## args))
362 
363 const mms_io_t* mms_get_default_io_impl()
364 {
365   return &default_io;
366 }
367 
368 void mms_set_default_io_impl(const mms_io_t *io)
369 {
370   if(io->select)
371   {
372     default_io.select = io->select;
373     default_io.select_data = io->select_data;
374   } else
375   {
376     default_io.select = fallback_io.select;
377     default_io.select_data = fallback_io.select_data;
378   }
379   if(io->read)
380   {
381     default_io.read = io->read;
382     default_io.read_data = io->read_data;
383   } else
384   {
385     default_io.read = fallback_io.read;
386     default_io.read_data = fallback_io.read_data;
387   }
388   if(io->write)
389   {
390     default_io.write = io->write;
391     default_io.write_data = io->write_data;
392   } else
393   {
394     default_io.write = fallback_io.write;
395     default_io.write_data = fallback_io.write_data;
396   }
397   if(io->connect)
398   {
399     default_io.connect = io->connect;
400     default_io.connect_data = io->connect_data;
401   } else
402   {
403     default_io.connect = fallback_io.connect;
404     default_io.connect_data = fallback_io.connect_data;
405   }
406 }
407 
408 static void mms_buffer_init (mms_buffer_t *mms_buffer, uint8_t *buffer) {
409   mms_buffer->buffer = buffer;
410   mms_buffer->pos = 0;
411 }
412 
413 static void mms_buffer_put_8 (mms_buffer_t *mms_buffer, uint8_t value) {
414 
415   mms_buffer->buffer[mms_buffer->pos]     = value          & 0xff;
416 
417   mms_buffer->pos += 1;
418 }
419 
420 #if 0
421 static void mms_buffer_put_16 (mms_buffer_t *mms_buffer, uint16_t value) {
422 
423   mms_buffer->buffer[mms_buffer->pos]     = value          & 0xff;
424   mms_buffer->buffer[mms_buffer->pos + 1] = (value  >> 8)  & 0xff;
425 
426   mms_buffer->pos += 2;
427 }
428 #endif
429 
430 static void mms_buffer_put_32 (mms_buffer_t *mms_buffer, uint32_t value) {
431 
432   mms_buffer->buffer[mms_buffer->pos]     = value          & 0xff;
433   mms_buffer->buffer[mms_buffer->pos + 1] = (value  >> 8)  & 0xff;
434   mms_buffer->buffer[mms_buffer->pos + 2] = (value  >> 16) & 0xff;
435   mms_buffer->buffer[mms_buffer->pos + 3] = (value  >> 24) & 0xff;
436 
437   mms_buffer->pos += 4;
438 }
439 
440 static int get_guid (unsigned char *buffer, int offset) {
441   int i;
442   GUID g;
443 
444   g.Data1 = LE_32(buffer + offset);
445   g.Data2 = LE_16(buffer + offset + 4);
446   g.Data3 = LE_16(buffer + offset + 6);
447   for(i = 0; i < 8; i++) {
448     g.Data4[i] = buffer[offset + 8 + i];
449   }
450 
451   for (i = 1; i < GUID_END; i++) {
452     if (!memcmp(&g, &guids[i].guid, sizeof(GUID))) {
453       lprintf("mms: GUID: %s\n", guids[i].name);
454       return i;
455     }
456   }
457 
458   lprintf("mms: unknown GUID: 0x%x, 0x%x, 0x%x, "
459            "{ 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx }\n",
460            g.Data1, g.Data2, g.Data3,
461            g.Data4[0], g.Data4[1], g.Data4[2], g.Data4[3],
462            g.Data4[4], g.Data4[5], g.Data4[6], g.Data4[7]);
463 
464   return GUID_ERROR;
465 }
466 
467 
468 static void print_command (char *data, int len) {
469 
470 #ifdef DEBUG
471   int i;
472   int dir = LE_32 (data + 36) >> 16;
473   int comm = LE_32 (data + 36) & 0xFFFF;
474 
475   lprintf ("----------------------------------------------\n");
476   if (dir == 3) {
477     lprintf ("send command 0x%02x, %d bytes\n", comm, len);
478   } else {
479     lprintf ("receive command 0x%02x, %d bytes\n", comm, len);
480   }
481   lprintf ("  start sequence %08x\n", LE_32 (data +  0));
482   lprintf ("  command id     %08x\n", LE_32 (data +  4));
483   lprintf ("  length         %8x \n", LE_32 (data +  8));
484   lprintf ("  protocol       %08x\n", LE_32 (data + 12));
485   lprintf ("  len8           %8x \n", LE_32 (data + 16));
486   lprintf ("  sequence #     %08x\n", LE_32 (data + 20));
487   lprintf ("  len8  (II)     %8x \n", LE_32 (data + 32));
488   lprintf ("  dir | comm     %08x\n", LE_32 (data + 36));
489   if (len >= 4)
490     lprintf ("  prefix1        %08x\n", LE_32 (data + 40));
491   if (len >= 8)
492     lprintf ("  prefix2        %08x\n", LE_32 (data + 44));
493 
494   for (i = (CMD_HEADER_LEN + CMD_PREFIX_LEN); i < (CMD_HEADER_LEN + CMD_PREFIX_LEN + len); i += 1) {
495     unsigned char c = data[i];
496 
497     if ((c >= 32) && (c < 128))
498       lprintf ("%c", c);
499     else
500       lprintf (" %02x ", c);
501 
502   }
503   if (len > CMD_HEADER_LEN)
504     lprintf ("\n");
505   lprintf ("----------------------------------------------\n");
506 #endif
507 }
508 
509 
510 
511 static int send_command (mms_io_t *io, mms_t *this, int command,
512                          uint32_t prefix1, uint32_t prefix2,
513                          int length) {
514   int    len8;
515   off_t  n;
516   mms_buffer_t command_buffer;
517 
518   len8 = (length + 7) / 8;
519 
520   this->scmd_len = 0;
521 
522   mms_buffer_init(&command_buffer, this->scmd);
523   mms_buffer_put_32 (&command_buffer, 0x00000001);   /* start sequence */
524   mms_buffer_put_32 (&command_buffer, 0xB00BFACE);   /* #-)) */
525   mms_buffer_put_32 (&command_buffer, len8 * 8 + 32);
526   mms_buffer_put_32 (&command_buffer, 0x20534d4d);   /* protocol type "MMS " */
527   mms_buffer_put_32 (&command_buffer, len8 + 4);
528   mms_buffer_put_32 (&command_buffer, this->seq_num);
529   this->seq_num++;
530   mms_buffer_put_32 (&command_buffer, 0x0);          /* timestamp */
531   mms_buffer_put_32 (&command_buffer, 0x0);
532   mms_buffer_put_32 (&command_buffer, len8 + 2);
533   mms_buffer_put_32 (&command_buffer, 0x00030000 | command); /* dir | command */
534   /* end of the 40 byte command header */
535 
536   mms_buffer_put_32 (&command_buffer, prefix1);
537   mms_buffer_put_32 (&command_buffer, prefix2);
538 
539   if (length & 7)
540           memset(this->scmd + length + CMD_HEADER_LEN + CMD_PREFIX_LEN, 0, 8 - (length & 7));
541 
542   n = io_write(io,  this->s, this->scmd, len8 * 8 + CMD_HEADER_LEN + CMD_PREFIX_LEN);
543   if (n != (len8 * 8 + CMD_HEADER_LEN + CMD_PREFIX_LEN)) {
544     return 0;
545   }
546 
547   print_command (this->scmd, length);
548 
549   return 1;
550 }
551 
552 static int string_utf16(char *dest, char *src, int dest_len)
553 {
554 #ifdef USE_ICONV
555   char *ip = src, *op = dest;
556   size_t ip_len = strlen(src);
557   size_t op_len = dest_len - 2; /* reserve 2 bytes for 0 termination */
558 
559   iconv_t url_conv = iconv_open("UTF-16LE", "UTF-8");
560   if (iconv(url_conv, &ip, &ip_len, &op, &op_len) == (size_t)-1) {
561       iconv_close(url_conv);
562     lprintf("mms: Error converting uri to unicode: %s\n", strerror(errno));
563     return 0;
564   }
565   iconv_close(url_conv);
566   /* 0 terminate the string */
567   *op++ = 0;
568   *op++ = 0;
569 
570   return op - dest;
571 #else
572   char *ip = src, *op = dest;
573   size_t ip_len = strlen(src);
574   size_t op_len = dest_len - 2;
575 
576   int res = deadbeef->junk_iconv (ip, ip_len, op, ip_len * 2, "UTF-8", "UTF-16LE");
577   if (res == -1) {
578     lprintf("mms: Error converting uri to unicode: %s\n", strerror(errno));
579     return 0;
580   }
581   op += res;
582   *op++ = 0;
583   *op++ = 0;
584 
585   return op - dest;
586 #endif
587 }
588 
589 /*
590  * return packet type
591  */
592 static int get_packet_header (mms_io_t *io, mms_t *this, mms_packet_header_t *header) {
593   size_t len;
594   int packet_type;
595   lprintf ("mms: get_packet_header: need_abort ptr = %p\n", this->need_abort);
596 
597   header->packet_len     = 0;
598   header->packet_seq     = 0;
599   header->flags          = 0;
600   header->packet_id_type = 0;
601   len = io_read(io,  this->s, this->buf, 8, this->need_abort);
602   this->buf_packet_seq_offset = -1;
603   if (len != 8)
604     goto error;
605 
606   if (LE_32(this->buf + 4) == 0xb00bface) {
607     /* command packet */
608     header->flags = this->buf[3];
609     len = io_read(io,  this->s, this->buf + 8, 4, this->need_abort);
610     if (len != 4)
611       goto error;
612 
613     header->packet_len = LE_32(this->buf + 8) + 4;
614     if (header->packet_len > BUF_SIZE - 12) {
615         lprintf("mms: get_packet_header error cmd packet length > bufsize\n");
616         header->packet_len = 0;
617         return MMS_PACKET_ERR;
618     }
619     packet_type = MMS_PACKET_COMMAND;
620   } else {
621     header->packet_seq     = LE_32(this->buf);
622     header->packet_id_type = this->buf[4];
623     header->flags          = this->buf[5];
624     header->packet_len     = (LE_16(this->buf + 6) - 8) & 0xffff;
625     if (header->packet_id_type == ASF_HEADER_PACKET_ID_TYPE) {
626       packet_type = MMS_PACKET_ASF_HEADER;
627     } else {
628       packet_type = MMS_PACKET_ASF_PACKET;
629     }
630   }
631 
632   return packet_type;
633 
634 error:
635   lprintf("mms: error reading packet header\n");
636   return MMS_PACKET_ERR;
637 }
638 
639 
640 static int get_packet_command (mms_io_t *io, mms_t *this, uint32_t packet_len) {
641 
642 
643   int  command = 0;
644   size_t len;
645 
646   len = io_read(io,  this->s, this->buf + 12, packet_len, this->need_abort) ;
647   //this->buf_packet_seq_offset = -1; // already set in get_packet_header
648   if (len != packet_len) {
649     lprintf("mms: error reading command packet\n");
650     return 0;
651   }
652 
653   print_command (this->buf, len);
654 
655   /* check protocol type ("MMS ") */
656   if (LE_32(this->buf + 12) != 0x20534D4D) {
657     lprintf("mms: unknown protocol type: %c%c%c%c (0x%08X)\n",
658             this->buf[12], this->buf[13], this->buf[14], this->buf[15],
659             LE_32(this->buf + 12));
660     return 0;
661   }
662 
663   command = LE_32 (this->buf + 36) & 0xFFFF;
664   lprintf("mms: received command = %02x, len: %d\n", command, packet_len);
665 
666   return command;
667 }
668 
669 static int get_answer (mms_io_t *io, mms_t *this) {
670   int command = 0;
671   mms_packet_header_t header;
672 
673   lprintf ("mms: get_answer: need_abort ptr = %p\n", this->need_abort);
674   switch (get_packet_header (io, this, &header)) {
675     case MMS_PACKET_ERR:
676       break;
677     case MMS_PACKET_COMMAND:
678       command = get_packet_command (io, this, header.packet_len);
679       if (command == 0)
680         return 0;
681 
682       if (command == 0x1b) {
683         if (!send_command (io, this, 0x1b, 0, 0, 0)) {
684           lprintf("mms: error sending ping reply\n");
685           return 0;
686         }
687         /* FIXME: limit recursion */
688         command = get_answer (io, this);
689       }
690       break;
691     case MMS_PACKET_ASF_HEADER:
692       lprintf("mms: unexpected asf header packet\n");
693       break;
694     case MMS_PACKET_ASF_PACKET:
695       lprintf("mms: unexpected asf packet\n");
696       break;
697   }
698 
699   return command;
700 }
701 
702 
703 static int get_asf_header (mms_io_t *io, mms_t *this) {
704 
705   off_t len;
706   int stop = 0;
707 
708   this->asf_header_read = 0;
709   this->asf_header_len = 0;
710 
711   while (!stop) {
712     mms_packet_header_t header;
713     int command;
714 
715     switch (get_packet_header (io, this, &header)) {
716       case MMS_PACKET_ERR:
717         return 0;
718       case MMS_PACKET_COMMAND:
719         command = get_packet_command (io, this, header.packet_len);
720         if (command == 0)
721           return 0;
722 
723         if (command == 0x1b) {
724           if (!send_command (io, this, 0x1b, 0, 0, 0)) {
725             lprintf("mms: error sending ping reply\n");
726             return 0;
727           }
728           command = get_answer (io, this);
729         } else {
730           lprintf("mms: unexpected command packet\n");
731         }
732         break;
733       case MMS_PACKET_ASF_HEADER:
734       case MMS_PACKET_ASF_PACKET:
735         if (header.packet_len + this->asf_header_len > ASF_HEADER_LEN) {
736             lprintf("mms: asf packet too large: %d\n",
737                     header.packet_len + this->asf_header_len);
738             return 0;
739         }
740         len = io_read(io,  this->s,
741                               this->asf_header + this->asf_header_len, header.packet_len, this->need_abort);
742         if (len != header.packet_len) {
743            lprintf("mms: error reading asf header\n");
744            return 0;
745         }
746         this->asf_header_len += header.packet_len;
747         lprintf("mms: header flags: %d\n", header.flags);
748         if ((header.flags == 0X08) || (header.flags == 0X0C))
749           stop = 1;
750         break;
751     }
752   }
753   return 1;
754 }
755 
756 static void interp_stream_properties(mms_t *this, int i)
757 {
758   uint16_t flags;
759   uint16_t stream_id;
760   int      type;
761   int      encrypted;
762   int      guid;
763 
764   guid = get_guid(this->asf_header, i);
765   switch (guid) {
766     case GUID_ASF_AUDIO_MEDIA:
767       type = ASF_STREAM_TYPE_AUDIO;
768       this->has_audio = 1;
769       break;
770 
771     case GUID_ASF_VIDEO_MEDIA:
772     case GUID_ASF_JFIF_MEDIA:
773     case GUID_ASF_DEGRADABLE_JPEG_MEDIA:
774       type = ASF_STREAM_TYPE_VIDEO;
775       this->has_video = 1;
776       break;
777 
778     case GUID_ASF_COMMAND_MEDIA:
779       type = ASF_STREAM_TYPE_CONTROL;
780       break;
781 
782     default:
783       type = ASF_STREAM_TYPE_UNKNOWN;
784   }
785 
786   flags = LE_16(this->asf_header + i + 48);
787   stream_id = flags & 0x7F;
788   encrypted = flags >> 15;
789 
790   lprintf("mms: stream object, stream id: %d, type: %d, encrypted: %d\n",
791           stream_id, type, encrypted);
792 
793   if (this->num_stream_ids < ASF_MAX_NUM_STREAMS) {
794     this->streams[this->num_stream_ids].stream_type = type;
795     this->streams[this->num_stream_ids].stream_id = stream_id;
796     this->num_stream_ids++;
797   } else {
798     lprintf("mms: too many streams, skipping\n");
799   }
800 }
801 
802 static void interp_asf_header (mms_t *this) {
803 
804   int i;
805 
806   this->asf_packet_len = 0;
807   this->num_stream_ids = 0;
808   this->asf_num_packets = 0;
809   /*
810    * parse header
811    */
812 
813   i = 30;
814   while ((i + 24) <= this->asf_header_len) {
815 
816     int guid;
817     uint64_t length;
818 
819     guid = get_guid(this->asf_header, i);
820     length = LE_64(this->asf_header + i + 16);
821 
822     if ((i + length) > this->asf_header_len) return;
823 
824     switch (guid) {
825 
826       case GUID_ASF_FILE_PROPERTIES:
827 
828         this->asf_packet_len = LE_32(this->asf_header + i + 92);
829         if (this->asf_packet_len > BUF_SIZE) {
830           lprintf("mms: asf packet len too large: %d\n", this->asf_packet_len);
831           this->asf_packet_len = 0;
832           break;
833         }
834         this->file_len       = LE_64(this->asf_header + i + 40);
835         this->time_len       = LE_64(this->asf_header + i + 64);
836         //this->time_len       = LE_64(this->asf_header + i + 72);
837         this->preroll        = LE_64(this->asf_header + i + 80);
838         lprintf("mms: file object, packet length = %d (%d)\n",
839                 this->asf_packet_len, LE_32(this->asf_header + i + 96));
840         break;
841 
842       case GUID_ASF_STREAM_PROPERTIES:
843         interp_stream_properties(this, i + 24);
844         break;
845 
846       case GUID_ASF_STREAM_BITRATE_PROPERTIES:
847         {
848           uint16_t streams = LE_16(this->asf_header + i + 24);
849           uint16_t stream_id;
850           int j;
851 
852           for(j = 0; j < streams; j++) {
853             int stream_index;
854             stream_id = LE_16(this->asf_header + i + 24 + 2 + j * 6);
855             for(stream_index = 0; stream_index < this->num_stream_ids; stream_index++) {
856               if (this->streams[stream_index].stream_id == stream_id)
857                 break;
858             }
859             if (stream_index < this->num_stream_ids) {
860               this->streams[stream_index].bitrate = LE_32(this->asf_header + i + 24 + 4 + j * 6);
861               this->streams[stream_index].bitrate_pos = i + 24 + 4 + j * 6;
862               lprintf("mms: stream id %d, bitrate %d\n", stream_id,
863                       this->streams[stream_index].bitrate);
864             } else
865               lprintf ("mms: unknown stream id %d in bitrate properties\n",
866                         stream_id);
867           }
868         }
869         break;
870 
871       case GUID_ASF_HEADER_EXTENSION:
872         {
873           if ((24 + 18 + 4) > length)
874             break;
875 
876           int size = LE_32(this->asf_header + i + 24 + 18);
877           int j = 24 + 18 + 4;
878           int l;
879           lprintf("mms: Extension header data size: %d\n", size);
880 
881           while ((j + 24) <= length) {
882             guid = get_guid(this->asf_header, i + j);
883             l = LE_64(this->asf_header + i + j + 16);
884 
885             if ((j + l) > length)
886               break;
887 
888             if (guid == GUID_ASF_EXTENDED_STREAM_PROPERTIES &&
889                 (24 + 64) <= l) {
890                   int stream_no = LE_16(this->asf_header + i + j + 24 + 48);
891                   int name_count = LE_16(this->asf_header + i + j + 24 + 60);
892                   int ext_count = LE_16(this->asf_header + i + j + 24 + 62);
893                   int ext_j = 24 + 64;
894                   int x;
895 
896                   lprintf("mms: l: %d\n", l);
897                   lprintf("mms: Stream No: %d\n", stream_no);
898                   lprintf("mms: ext_count: %d\n", ext_count);
899 
900                   // Loop through the number of stream names
901                   for (x = 0; x < name_count && (ext_j + 4) <= l; x++) {
902                     int lang_id_index;
903                     int stream_name_len;
904 
905                     lang_id_index = LE_16(this->asf_header + i + j + ext_j);
906                     ext_j += 2;
907 
908                     stream_name_len = LE_16(this->asf_header + i + j + ext_j);
909                     ext_j += stream_name_len + 2;
910 
911                     lprintf("mms: Language id index: %d\n", lang_id_index);
912                     lprintf("mms: Stream name Len: %d\n", stream_name_len);
913                   }
914 
915                   // Loop through the number of extension system info
916                   for (x = 0; x < ext_count && (ext_j + 22) <= l; x++) {
917                     ext_j += 18;
918                     int len = LE_16(this->asf_header + i + j + ext_j);
919                     ext_j += 4 + len;
920                   }
921 
922                   lprintf("mms: ext_j: %d\n", ext_j);
923                   // Finally, we arrive at the interesting point: The optional Stream Property Object
924                   if ((ext_j + 24) <= l) {
925                     guid = get_guid(this->asf_header, i + j + ext_j);
926                     int len = LE_64(this->asf_header + i + j + ext_j + 16);
927                     if (guid == GUID_ASF_STREAM_PROPERTIES &&
928                         (ext_j + len) <= l) {
929                       interp_stream_properties(this, i + j + ext_j + 24);
930                     }
931                   } else {
932                     lprintf("mms: Sorry, field not long enough\n");
933                   }
934             }
935             j += l;
936           }
937         }
938         break;
939 
940       case GUID_ASF_DATA:
941         this->asf_num_packets = LE_64(this->asf_header + i + 40 - 24);
942         break;
943     }
944 
945     lprintf("mms: length: %llu\n", (unsigned long long)length);
946     i += length;
947   }
948 }
949 
950 const static char *const mmst_proto_s[] = { "mms", "mmst", NULL };
951 
952 static int mmst_valid_proto (char *proto) {
953   int i = 0;
954 
955   if (!proto)
956     return 0;
957 
958   while(mmst_proto_s[i]) {
959     if (!strcasecmp(proto, mmst_proto_s[i])) {
960       return 1;
961     }
962     i++;
963   }
964   return 0;
965 }
966 
967 /*
968  * returns 1 on error
969  */
970 static int mms_tcp_connect(mms_io_t *io, mms_t *this) {
971   if (!this->port) this->port = MMST_PORT;
972 
973   /*
974    * try to connect
975    */
976   lprintf("mms: trying to connect to %s on port %d\n", this->host, this->port);
977   this->s = io_connect(io,  this->host, this->port, this->need_abort);
978   if (this->s == -1) {
979     lprintf("mms: failed to connect to %s\n", this->host);
980     return 1;
981   }
982 
983   lprintf("mms: connected\n");
984   return 0;
985 }
986 
987 static void mms_gen_guid(char guid[]) {
988   static char digit[16] = "0123456789ABCDEF";
989   int i = 0;
990 
991   srand(time(NULL));
992   for (i = 0; i < 36; i++) {
993     guid[i] = digit[(int) ((16.0*rand())/(RAND_MAX+1.0))];
994   }
995   guid[8] = '-'; guid[13] = '-'; guid[18] = '-'; guid[23] = '-';
996   guid[36] = '\0';
997 }
998 
999 const char *status_to_string(int status)
1000 {
1001   switch (status) {
1002   case 0x80070003:
1003     return "Path not found";
1004   case 0x80070005:
1005     return "Access Denied";
1006   default:
1007     return "Unknown";
1008   }
1009 }
1010 
1011 /*
1012  * return 0 on error
1013  */
1014 int static mms_choose_best_streams(mms_io_t *io, mms_t *this) {
1015   int     i;
1016   int     video_stream = -1;
1017   int     audio_stream = -1;
1018   int     max_arate    = 0;
1019   int     min_vrate    = 0;
1020   int     min_bw_left  = 0;
1021   int     bandwitdh_left;
1022   int     res;
1023 
1024   /* command 0x33 */
1025   /* choose the best quality for the audio stream */
1026   /* i've never seen more than one audio stream */
1027   for (i = 0; i < this->num_stream_ids; i++) {
1028     switch (this->streams[i].stream_type) {
1029       case ASF_STREAM_TYPE_AUDIO:
1030         if (this->streams[i].bitrate > max_arate) {
1031           audio_stream = this->streams[i].stream_id;
1032           max_arate = this->streams[i].bitrate;
1033         }
1034         break;
1035       default:
1036         break;
1037     }
1038   }
1039 
1040   /* choose a video stream adapted to the user bandwidth */
1041   bandwitdh_left = this->bandwidth - max_arate;
1042   if (bandwitdh_left < 0) {
1043     bandwitdh_left = 0;
1044   }
1045   lprintf("mms: bandwidth %d, left %d\n", this->bandwidth, bandwitdh_left);
1046 
1047   min_bw_left = bandwitdh_left;
1048   for (i = 0; i < this->num_stream_ids; i++) {
1049     switch (this->streams[i].stream_type) {
1050       case ASF_STREAM_TYPE_VIDEO:
1051         if (((bandwitdh_left - this->streams[i].bitrate) < min_bw_left) &&
1052             (bandwitdh_left >= this->streams[i].bitrate)) {
1053           video_stream = this->streams[i].stream_id;
1054           min_bw_left = bandwitdh_left - this->streams[i].bitrate;
1055         }
1056         break;
1057       default:
1058         break;
1059     }
1060   }
1061 
1062   /* choose the lower bitrate of */
1063   if (video_stream == -1 && this->has_video) {
1064     for (i = 0; i < this->num_stream_ids; i++) {
1065       switch (this->streams[i].stream_type) {
1066         case ASF_STREAM_TYPE_VIDEO:
1067           if ((this->streams[i].bitrate < min_vrate) ||
1068               (!min_vrate)) {
1069             video_stream = this->streams[i].stream_id;
1070             min_vrate = this->streams[i].bitrate;
1071           }
1072           break;
1073         default:
1074           break;
1075       }
1076     }
1077   }
1078 
1079   lprintf("mms: selected streams: audio %d, video %d\n", audio_stream, video_stream);
1080   memset (this->scmd_body, 0, 40);
1081   for (i = 1; i < this->num_stream_ids; i++) {
1082     this->scmd_body [ (i - 1) * 6 + 2 ] = 0xFF;
1083     this->scmd_body [ (i - 1) * 6 + 3 ] = 0xFF;
1084     this->scmd_body [ (i - 1) * 6 + 4 ] = this->streams[i].stream_id ;
1085     this->scmd_body [ (i - 1) * 6 + 5 ] = this->streams[i].stream_id >> 8;
1086     if ((this->streams[i].stream_id == audio_stream) ||
1087         (this->streams[i].stream_id == video_stream)) {
1088       this->scmd_body [ (i - 1) * 6 + 6 ] = 0x00;
1089       this->scmd_body [ (i - 1) * 6 + 7 ] = 0x00;
1090     } else {
1091       lprintf("mms: disabling stream %d\n", this->streams[i].stream_id);
1092       this->scmd_body [ (i - 1) * 6 + 6 ] = 0x02;
1093       this->scmd_body [ (i - 1) * 6 + 7 ] = 0x00;
1094 
1095       /* forces the asf demuxer to not choose this stream */
1096       if (this->streams[i].bitrate_pos) {
1097         if (this->streams[i].bitrate_pos+3 < ASF_HEADER_LEN) {
1098           this->asf_header[this->streams[i].bitrate_pos    ] = 0;
1099           this->asf_header[this->streams[i].bitrate_pos + 1] = 0;
1100           this->asf_header[this->streams[i].bitrate_pos + 2] = 0;
1101           this->asf_header[this->streams[i].bitrate_pos + 3] = 0;
1102         } else {
1103           lprintf("mms: attempt to write beyond asf header limit\n");
1104         }
1105       }
1106     }
1107   }
1108 
1109   lprintf("mms: send command 0x33\n");
1110   if (!send_command (io, this, 0x33, this->num_stream_ids,
1111                      0xFFFF | this->streams[0].stream_id << 16,
1112                      this->num_stream_ids * 6 + 2)) {
1113     lprintf("mms: mms_choose_best_streams failed\n");
1114     return 0;
1115   }
1116 
1117   if ((res = get_answer (io, this)) != 0x21) {
1118     lprintf("mms: unexpected response: %02x (0x21)\n", res);
1119     return 0;
1120   }
1121 
1122   res = LE_32(this->buf + 40);
1123   if (res != 0) {
1124     lprintf("mms: error answer 0x21 status: %08x (%s)\n",
1125             res, status_to_string(res));
1126     return 0;
1127   }
1128 
1129   return 1;
1130 }
1131 
1132 /*
1133  * TODO: error messages
1134  *       network timing request
1135  */
1136 /* FIXME: got somewhat broken during xine_stream_t->(void*) conversion */
1137 mms_t *mms_connect (mms_io_t *io, void *data, const char *url, int bandwidth, int *need_abort) {
1138   mms_t  *this;
1139   int     res;
1140   uint32_t openid;
1141   mms_buffer_t command_buffer;
1142 
1143   if (!url)
1144     return NULL;
1145 
1146   /* FIXME: needs proper error-signalling work */
1147   this = (mms_t*) malloc (sizeof (mms_t));
1148 
1149   this->url             = strdup (url);
1150   this->s               = -1;
1151   this->seq_num         = 0;
1152   this->scmd_body       = this->scmd + CMD_HEADER_LEN + CMD_PREFIX_LEN;
1153   this->asf_header_len  = 0;
1154   this->asf_header_read = 0;
1155   this->num_stream_ids  = 0;
1156   this->asf_packet_len  = 0;
1157   this->start_packet_seq= 0;
1158   this->need_discont    = 1;
1159   this->buf_size        = 0;
1160   this->buf_read        = 0;
1161   this->buf_packet_seq_offset = -1;
1162   this->has_audio       = 0;
1163   this->has_video       = 0;
1164   this->bandwidth       = bandwidth;
1165   this->current_pos     = 0;
1166   this->eos             = 0;
1167   this->need_abort      = need_abort;
1168 
1169   this->guri = gnet_uri_new(this->url);
1170   if(!this->guri) {
1171     lprintf("mms: invalid url\n");
1172     goto fail;
1173   }
1174 
1175   /* MMS wants unescaped (so not percent coded) strings */
1176   gnet_uri_unescape(this->guri);
1177 
1178   this->proto = this->guri->scheme;
1179   this->user = this->guri->user;
1180   this->host = this->guri->hostname;
1181   this->port = this->guri->port;
1182   this->password = this->guri->passwd;
1183   this->uri = gnet_mms_helper(this->guri, 0);
1184 
1185   if(!this->uri)
1186         goto fail;
1187 
1188   if (!mmst_valid_proto(this->proto)) {
1189     lprintf("mms: unsupported protocol: %s\n", this->proto);
1190     goto fail;
1191   }
1192 
1193   if (mms_tcp_connect(io, this)) {
1194     goto fail;
1195   }
1196 
1197   /*
1198    * let the negotiations begin...
1199    */
1200 
1201   /* command 0x1 */
1202   lprintf("mms: send command 0x01\n");
1203   mms_buffer_init(&command_buffer, this->scmd_body);
1204   mms_buffer_put_32 (&command_buffer, 0x0003001C);
1205   mms_gen_guid(this->guid);
1206   sprintf(this->str, "NSPlayer/7.0.0.1956; {%s}; Host: %s", this->guid,
1207           this->host);
1208   res = string_utf16(this->scmd_body + command_buffer.pos, this->str,
1209                      CMD_BODY_LEN - command_buffer.pos);
1210 
1211   if(!res)
1212     goto fail;
1213 
1214   if (!send_command(io, this, 1, 0, 0x0004000b, command_buffer.pos + res)) {
1215     lprintf("mms: failed to send command 0x01\n");
1216     goto fail;
1217   }
1218 
1219   if ((res = get_answer (io, this)) != 0x01) {
1220     lprintf("mms: unexpected response: %02x (0x01)\n", res);
1221     goto fail;
1222   }
1223 
1224   res = LE_32(this->buf + 40);
1225   if (res != 0) {
1226     lprintf("mms: error answer 0x01 status: %08x (%s)\n",
1227             res, status_to_string(res));
1228     goto fail;
1229   }
1230 
1231   /* TODO: insert network timing request here */
1232   /* command 0x2 */
1233   lprintf("mms: send command 0x02\n");
1234   mms_buffer_init(&command_buffer, this->scmd_body);
1235   mms_buffer_put_32 (&command_buffer, 0x00000000);
1236   mms_buffer_put_32 (&command_buffer, 0x00989680);
1237   mms_buffer_put_32 (&command_buffer, 0x00000002);
1238   res = string_utf16(this->scmd_body + command_buffer.pos,
1239                      "\\\\192.168.0.129\\TCP\\1037",
1240                      CMD_BODY_LEN - command_buffer.pos);
1241   if(!res)
1242     goto fail;
1243 
1244   if (!send_command(io, this, 2, 0, 0xffffffff, command_buffer.pos + res)) {
1245     lprintf("mms: failed to send command 0x02\n");
1246     goto fail;
1247   }
1248 
1249   switch (res = get_answer (io, this)) {
1250     case 0x02:
1251       /* protocol accepted */
1252       break;
1253     case 0x03:
1254       lprintf("mms: protocol failed\n");
1255       goto fail;
1256     default:
1257       lprintf("mms: unexpected response: %02x (0x02 or 0x03)\n", res);
1258       goto fail;
1259   }
1260 
1261   res = LE_32(this->buf + 40);
1262   if (res != 0) {
1263     lprintf("mms: error answer 0x02 status: %08x (%s)\n",
1264             res, status_to_string(res));
1265     goto fail;
1266   }
1267 
1268   /* command 0x5 */
1269   {
1270     mms_buffer_t command_buffer;
1271 
1272     lprintf("mms: send command 0x05\n");
1273     mms_buffer_init(&command_buffer, this->scmd_body);
1274     mms_buffer_put_32 (&command_buffer, 0x00000000); /* ?? */
1275     mms_buffer_put_32 (&command_buffer, 0x00000000); /* ?? */
1276 
1277     res = string_utf16(this->scmd_body + command_buffer.pos,
1278                        this->uri, CMD_BODY_LEN - command_buffer.pos);
1279     if(!res)
1280       goto fail;
1281 
1282     if (!send_command(io, this, 5, 1, 0, command_buffer.pos + res)) {
1283       lprintf("mms: failed to send command 0x05\n");
1284       goto fail;
1285     }
1286   }
1287 
1288   switch (res = get_answer (io, this)) {
1289     case 0x06:
1290       {
1291         int xx, yy;
1292         /* no authentication required */
1293         openid = LE_32(this->buf + 48);
1294 
1295         /* Warning: sdp is not right here */
1296         xx = this->buf[62];
1297         yy = this->buf[63];
1298         this->live_flag = ((xx == 0) && ((yy & 0xf) == 2));
1299         this->seekable = !this->live_flag;
1300         lprintf("mms: openid=%d, live: live_flag=%d, xx=%d, yy=%d\n", openid, this->live_flag, xx, yy);
1301       }
1302       break;
1303     case 0x1A:
1304       /* authentication request, not yet supported */
1305       lprintf("mms: authentication request, not yet supported\n");
1306       goto fail;
1307       break;
1308     default:
1309       lprintf("mms: unexpected response: %02x (0x06 or 0x1A)\n", res);
1310       goto fail;
1311   }
1312 
1313   res = LE_32(this->buf + 40);
1314   if (res != 0) {
1315     lprintf("mms: error answer 0x06 status: %08x (%s)\n",
1316             res, status_to_string(res));
1317     goto fail;
1318   }
1319 
1320   /* command 0x15 */
1321   lprintf("mms: send command 0x15\n");
1322   {
1323     mms_buffer_t command_buffer;
1324     mms_buffer_init(&command_buffer, this->scmd_body);
1325     mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* ?? */
1326     mms_buffer_put_32 (&command_buffer, 0x00008000);                  /* ?? */
1327     mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF);                  /* ?? */
1328     mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* ?? */
1329     mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* ?? */
1330     mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* ?? */
1331     mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* ?? */
1332     mms_buffer_put_32 (&command_buffer, 0x40AC2000);                  /* ?? */
1333     mms_buffer_put_32 (&command_buffer, ASF_HEADER_PACKET_ID_TYPE);   /* Header Packet ID type */
1334     mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* ?? */
1335     if (!send_command (io, this, 0x15, openid, 0, command_buffer.pos)) {
1336       lprintf("mms: failed to send command 0x15\n");
1337       goto fail;
1338     }
1339   }
1340 
1341   if ((res = get_answer (io, this)) != 0x11) {
1342     lprintf("mms: unexpected response: %02x (0x11)\n", res);
1343     goto fail;
1344   }
1345 
1346   res = LE_32(this->buf + 40);
1347   if (res != 0) {
1348     lprintf("mms: error answer 0x11 status: %08x (%s)\n",
1349             res, status_to_string(res));
1350     goto fail;
1351   }
1352 
1353   this->num_stream_ids = 0;
1354 
1355   if (!get_asf_header (io, this))
1356     goto fail;
1357 
1358   interp_asf_header (this);
1359   if (!this->asf_packet_len || !this->num_stream_ids)
1360     goto fail;
1361 
1362   if (!mms_choose_best_streams(io, this)) {
1363     lprintf("mms: mms_choose_best_streams failed\n");
1364     goto fail;
1365   }
1366 
1367   /* command 0x07 */
1368   this->packet_id_type = ASF_MEDIA_PACKET_ID_TYPE;
1369   {
1370     mms_buffer_t command_buffer;
1371     mms_buffer_init(&command_buffer, this->scmd_body);
1372     mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* 64 byte float timestamp */
1373     mms_buffer_put_32 (&command_buffer, 0x00000000);
1374     mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF);                  /* ?? */
1375     mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF);                  /* first packet sequence */
1376     mms_buffer_put_8  (&command_buffer, 0xFF);                        /* max stream time limit (3 bytes) */
1377     mms_buffer_put_8  (&command_buffer, 0xFF);
1378     mms_buffer_put_8  (&command_buffer, 0xFF);
1379     mms_buffer_put_8  (&command_buffer, 0x00);                        /* stream time limit flag */
1380     mms_buffer_put_32 (&command_buffer, this->packet_id_type);    /* asf media packet id type */
1381     if (!send_command (io, this, 0x07, 1, 0x0001FFFF, command_buffer.pos)) {
1382       lprintf("mms: failed to send command 0x07\n");
1383       goto fail;
1384     }
1385   }
1386 
1387   lprintf("mms: connect: passed\n");
1388 
1389   return this;
1390 
1391 fail:
1392   if (this->s != -1)
1393     close (this->s);
1394   if (this->url)
1395     free(this->url);
1396   if (this->guri)
1397     gnet_uri_delete(this->guri);
1398   if (this->uri)
1399     free(this->uri);
1400 
1401   free (this);
1402   return NULL;
1403 }
1404 
1405 static int get_media_packet (mms_io_t *io, mms_t *this) {
1406   mms_packet_header_t header;
1407   off_t len;
1408 
1409   switch (get_packet_header (io, this, &header)) {
1410     case MMS_PACKET_ERR:
1411       return 0;
1412 
1413     case MMS_PACKET_COMMAND:
1414       {
1415         int command;
1416         command = get_packet_command (io, this, header.packet_len);
1417 
1418         switch (command) {
1419           case 0:
1420             return 0;
1421 
1422           case 0x1e:
1423             {
1424               uint32_t error_code;
1425 
1426               /* Warning: sdp is incomplete. Do not stop if error_code==1 */
1427               error_code = LE_32(this->buf + CMD_HEADER_LEN);
1428               lprintf("mms: End of the current stream. Continue=%d\n", error_code);
1429 
1430               if (error_code == 0) {
1431                 this->eos = 1;
1432                 return 0;
1433               }
1434 
1435             }
1436             break;
1437 
1438           case 0x20:
1439             {
1440               lprintf("mms: new stream.\n");
1441               /* asf header */
1442               if (!get_asf_header (io, this)) {
1443                 lprintf("mms: failed to read new ASF header\n");
1444                 return 0;
1445               }
1446 
1447               interp_asf_header (this);
1448               if (!this->asf_packet_len || !this->num_stream_ids)
1449                 return 0;
1450 
1451               if (!mms_choose_best_streams(io, this))
1452                 return 0;
1453 
1454               /* send command 0x07 */
1455               /* TODO: ugly */
1456               /* command 0x07 */
1457               {
1458                 mms_buffer_t command_buffer;
1459                 mms_buffer_init(&command_buffer, this->scmd_body);
1460                 mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* 64 byte float timestamp */
1461                 mms_buffer_put_32 (&command_buffer, 0x00000000);
1462                 mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF);                  /* ?? */
1463                 mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF);                  /* first packet sequence */
1464                 mms_buffer_put_8  (&command_buffer, 0xFF);                        /* max stream time limit (3 bytes) */
1465                 mms_buffer_put_8  (&command_buffer, 0xFF);
1466                 mms_buffer_put_8  (&command_buffer, 0xFF);
1467                 mms_buffer_put_8  (&command_buffer, 0x00);                        /* stream time limit flag */
1468                 mms_buffer_put_32 (&command_buffer, ASF_MEDIA_PACKET_ID_TYPE);    /* asf media packet id type */
1469                 if (!send_command (io, this, 0x07, 1, 0x0001FFFF, command_buffer.pos)) {
1470                   lprintf("mms: failed to send command 0x07\n");
1471                   return 0;
1472                 }
1473               }
1474               this->current_pos = 0;
1475 
1476               /* I don't know if this ever happens with none live (and thus
1477                  seekable streams), but I do know that if it happens all bets
1478                  with regards to seeking are off */
1479               this->seekable = 0;
1480             }
1481             break;
1482 
1483           case 0x1b:
1484             {
1485               if (!send_command (io, this, 0x1b, 0, 0, 0)) {
1486                 lprintf("mms: error sending ping reply\n");
1487                 return 0;
1488               }
1489             }
1490             break;
1491 
1492           case 0x05:
1493             break;
1494 
1495           default:
1496             lprintf("mms: unexpected mms command %02x\n", command);
1497         }
1498         this->buf_size = 0;
1499       }
1500       break;
1501 
1502     case MMS_PACKET_ASF_HEADER:
1503       lprintf("mms: unexpected asf header packet\n");
1504       this->buf_size = 0;
1505       break;
1506 
1507     case MMS_PACKET_ASF_PACKET:
1508       {
1509         /* media packet */
1510 
1511         /* FIXME: probably needs some more sophisticated logic, but
1512            until we do seeking, this should work */
1513         if(this->need_discont &&
1514            header.packet_id_type == ASF_MEDIA_PACKET_ID_TYPE)
1515         {
1516           this->need_discont = 0;
1517           this->start_packet_seq = header.packet_seq;
1518         }
1519 
1520         if (header.packet_len > this->asf_packet_len) {
1521           lprintf("mms: invalid asf packet len: %d bytes\n", header.packet_len);
1522           return 0;
1523         }
1524 
1525         /* simulate a seek */
1526         this->current_pos = (off_t)this->asf_header_len +
1527           ((off_t)header.packet_seq - this->start_packet_seq) * (off_t)this->asf_packet_len;
1528 
1529         len = io_read(io,  this->s, this->buf, header.packet_len, this->need_abort);
1530         if (len != header.packet_len) {
1531           lprintf("mms: error reading asf packet\n");
1532           return 0;
1533         }
1534 
1535         /* explicit padding with 0 */
1536         memset(this->buf + header.packet_len, 0, this->asf_packet_len - header.packet_len);
1537         if (header.packet_id_type == this->packet_id_type) {
1538           this->buf_size = this->asf_packet_len;
1539           this->buf_packet_seq_offset =
1540             header.packet_seq - this->start_packet_seq;
1541         } else {
1542           this->buf_size = 0;
1543           // Don't set this packet sequence for reuse in seek(), since the
1544           // subsequence packet may be discontinued.
1545           //this->buf_packet_seq_offset = header.packet_seq;
1546           // already set to -1 in get_packet_header
1547           //this->buf_packet_seq_offset = -1;
1548         }
1549       }
1550       break;
1551   }
1552 
1553   return 1;
1554 }
1555 
1556 
1557 int mms_peek_header (mms_t *this, char *data, int maxsize) {
1558 
1559   int len;
1560 
1561   len = (this->asf_header_len < maxsize) ? this->asf_header_len : maxsize;
1562 
1563   memcpy(data, this->asf_header, len);
1564   return len;
1565 }
1566 
1567 int mms_read (mms_io_t *io, mms_t *this, char *data, int len, int *need_abort) {
1568   int total;
1569 
1570   total = 0;
1571   while (total < len && !this->eos && (!need_abort || !(*need_abort))) {
1572 
1573     if (this->asf_header_read < this->asf_header_len) {
1574       int n, bytes_left;
1575 
1576       bytes_left = this->asf_header_len - this->asf_header_read ;
1577 
1578       if ((len - total) < bytes_left)
1579         n = len-total;
1580       else
1581         n = bytes_left;
1582 
1583       memcpy (&data[total], &this->asf_header[this->asf_header_read], n);
1584 
1585       this->asf_header_read += n;
1586       total += n;
1587       this->current_pos += n;
1588     } else {
1589 
1590       int n, bytes_left;
1591 
1592       bytes_left = this->buf_size - this->buf_read;
1593       if (bytes_left == 0) {
1594         this->buf_size = this->buf_read = 0;
1595         if (!get_media_packet (io, this)) {
1596           lprintf("mms: get_media_packet failed\n");
1597           return total;
1598         }
1599         bytes_left = this->buf_size;
1600       }
1601 
1602       if ((len - total) < bytes_left)
1603         n = len - total;
1604       else
1605         n = bytes_left;
1606 
1607       memcpy (&data[total], &this->buf[this->buf_read], n);
1608 
1609       this->buf_read += n;
1610       total += n;
1611       this->current_pos += n;
1612     }
1613   }
1614 
1615   if (need_abort && *need_abort) {
1616       lprintf ("mms_read aborted\n");
1617       return -1;
1618   }
1619   return total;
1620 }
1621 
1622 // To be inline function?
1623 static int mms_request_data_packet (mms_io_t *io, mms_t *this,
1624   double time_sec, unsigned long first_packet, unsigned long time_msec_limit) {
1625   /* command 0x07 */
1626   {
1627     mms_buffer_t command_buffer;
1628     //mms_buffer_init(&command_buffer, this->scmd_body);
1629     //mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* 64 byte float timestamp */
1630     //mms_buffer_put_32 (&command_buffer, 0x00000000);
1631     memcpy(this->scmd_body, &time_sec, 8);
1632     mms_buffer_init(&command_buffer, this->scmd_body+8);
1633     mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF);                  /* ?? */
1634     //mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF);                  /* first packet sequence */
1635     mms_buffer_put_32 (&command_buffer, first_packet);                  /* first packet sequence */
1636     //mms_buffer_put_8  (&command_buffer, 0xFF);                        /* max stream time limit (3 bytes) */
1637     //mms_buffer_put_8  (&command_buffer, 0xFF);
1638     //mms_buffer_put_8  (&command_buffer, 0xFF);
1639     //mms_buffer_put_8  (&command_buffer, 0x00);                        /* stream time limit flag */
1640     mms_buffer_put_32 (&command_buffer, time_msec_limit & 0x00FFFFFF);/* max stream time limit (3 bytes) */
1641     mms_buffer_put_32 (&command_buffer, this->packet_id_type);    /* asf media packet id type */
1642     if (!send_command (io, this, 0x07, 1, 0x0001FFFF, 8+command_buffer.pos)) {
1643       lprintf("mms: failed to send command 0x07\n");
1644       return 0;
1645     }
1646   }
1647   /* TODO: adjust current_pos, considering asf_header_read */
1648   return 1;
1649 }
1650 
1651 int mms_request_time_seek (mms_io_t *io, mms_t *this, double time_sec) {
1652   if (++this->packet_id_type <= ASF_MEDIA_PACKET_ID_TYPE)
1653     this->packet_id_type = ASF_MEDIA_PACKET_ID_TYPE+1;
1654   //return mms_request_data_packet (io, this, time_sec, 0xFFFFFFFF, 0x00FFFFFF);
1655   // also adjust time by preroll
1656   return mms_request_data_packet (io, this,
1657                                   time_sec+(double)(this->preroll)/1000,
1658                                   0xFFFFFFFF, 0x00FFFFFF);
1659 }
1660 
1661 // set current_pos to the first byte of the requested packet by peeking at
1662 // the first packet.
1663 // To be inline function?
1664 static int peek_and_set_pos (mms_io_t *io, mms_t *this) {
1665   uint8_t saved_buf[BUF_SIZE];
1666   int     saved_buf_size;
1667   off_t   saved_buf_packet_seq_offset;
1668   // save buf and buf_size that may be changed in get_media_packet()
1669   memcpy(saved_buf, this->buf, this->buf_size);
1670   saved_buf_size = this->buf_size;
1671   saved_buf_packet_seq_offset = this->buf_packet_seq_offset;
1672   //this->buf_size = this->buf_read = 0; // reset buf, only if success peeking
1673   this->buf_size = 0;
1674   while (!this->eos) {
1675     // get_media_packet() will set current_pos if data packet is read.
1676     if (!get_media_packet (io, this)) {
1677       lprintf("mms: get_media_packet failed\n");
1678       // restore buf and buf_size that may be changed in get_media_packet()
1679       memcpy(this->buf, saved_buf, saved_buf_size);
1680       this->buf_size = saved_buf_size;
1681       this->buf_packet_seq_offset = saved_buf_packet_seq_offset;
1682       return 0;
1683     }
1684     if (this->buf_size > 0) break;
1685   }
1686   // flush header and reset buf_read, only if success peeking
1687   this->asf_header_read = this->asf_header_len;
1688   this->buf_read = 0;
1689   return 1;
1690   //return this->current_pos;
1691 }
1692 
1693 // send time seek request, and update current_pos corresponding to the next
1694 // requested packet
1695 // Note that, the current_pos will always does not less than asf_header_len
1696 int mms_time_seek (mms_io_t *io, mms_t *this, double time_sec) {
1697   if (!this->seekable)
1698     return 0;
1699 
1700   if (!mms_request_time_seek (io, this, time_sec)) return 0;
1701   return peek_and_set_pos (io, this);
1702 }
1703 
1704 // http://sdp.ppona.com/zipfiles/MMSprotocol_pdf.zip said that, this
1705 // packet_seq value make no difference in version 9 servers.
1706 // But from my experiment with
1707 // mms://202.142.200.130/tltk/56k/tltkD2006-08-08ID-7209.wmv and
1708 // mms://202.142.200.130/tltk/56k/tltkD2006-09-01ID-7467.wmv (the url may valid
1709 // in only 2-3 months) whose server is version 9, it does response and return
1710 // the requested packet.
1711 int mms_request_packet_seek (mms_io_t *io, mms_t *this,
1712                              unsigned long packet_seq) {
1713   if (++this->packet_id_type <= ASF_MEDIA_PACKET_ID_TYPE)
1714     this->packet_id_type = ASF_MEDIA_PACKET_ID_TYPE+1;
1715   return mms_request_data_packet (io, this, 0, packet_seq, 0x00FFFFFF);
1716 }
1717 
1718 // send packet seek request, and update current_pos corresponding to the next
1719 // requested packet
1720 // Note that, the current_pos will always does not less than asf_header_len
1721 // Not export this function.  Let user use mms_seek() instead?
1722 static int mms_packet_seek (mms_io_t *io, mms_t *this,
1723                             unsigned long packet_seq) {
1724   if (!mms_request_packet_seek (io, this, packet_seq)) return 0;
1725   return peek_and_set_pos (io, this);
1726 }
1727 
1728 /*
1729 TODO: To use this table to calculate buf_packet_seq_offset rather than store
1730 and retrieve it from this->buf_packet_seq_offset?
1731 current_packet_seq == (current_pos - asf_header_len) / asf_packet_len
1732 current_packet_seq == -1 if current_pos < asf_header_len
1733 buf_packet_seq_offset indicating which packet sequence are residing in the buf.
1734 Possible status after read(), "last" means last value or unchange.
1735 current_packet_seq | buf_read       | buf_size  | buf_packet_seq_offset
1736 -------------------+----------------+-----------+---------------
1737 <= 0               | 0 (last)       | 0 (last)  | none
1738 <= 0               | 0 (last)       | 0 (last)  | eos at #0
1739 <= 0               | 0 (last)       | 0 (last)  | eos at > #0
1740 <= 0               | 0 (last)       | > 0 (last)| #0
1741 <= 0               | buf_size (last)| > 0 (last)| > #0
1742 > 0                | 0              | 0         | eos at current_packet_seq
1743 > 0                | 0(never happen)| > 0       | (never happen)
1744 > 0                | buf_size       | > 0       | current_packet_seq-1
1745 */
1746 // TODO: How to handle seek() in multi stream source?
1747 // The stream that follows 0x20 ("new stream") command.
1748 off_t mms_seek (mms_io_t *io, mms_t *this, off_t offset, int origin) {
1749   off_t dest;
1750   off_t dest_packet_seq;
1751   //off_t buf_packet_seq_offset;
1752 
1753   if (!this->seekable)
1754     return this->current_pos;
1755 
1756   switch (origin) {
1757     case SEEK_SET:
1758       dest = offset;
1759       break;
1760     case SEEK_CUR:
1761       dest = this->current_pos + offset;
1762       break;
1763     case SEEK_END:
1764       //if (this->asf_num_packets == 0) {
1765       //  //printf ("input_mms: unknown end position in seek!\n");
1766       //  return this->current_pos;
1767       //}
1768       dest = mms_get_length (this) + offset;
1769     default:
1770       fprintf (stderr, "input_mms: unknown origin in seek!\n");
1771       return this->current_pos;
1772   }
1773 
1774   dest_packet_seq = dest - this->asf_header_len;
1775   //if (dest_packet_seq > 0) dest_packet_seq /= this->asf_packet_len;
1776   dest_packet_seq = dest_packet_seq >= 0 ?
1777     dest_packet_seq / this->asf_packet_len : -1;
1778 #if 0
1779   // buf_packet_seq_offset will identify which packet sequence are residing in
1780   // the buf.
1781 #if 1 /* To show both of the alternate styles :D */
1782   buf_packet_seq_offset = this->current_pos - this->asf_header_len;
1783   //if (buf_packet_seq_offset > 0) buf_packet_seq_offset /= this->asf_packet_len;
1784   buf_packet_seq_offset = buf_packet_seq_offset >= 0 ?
1785     buf_packet_seq_offset / this->asf_packet_len : -1;
1786   // Note: buf_read == buf_size == 0 may means that it is eos,
1787   //       eos means that the packet has been peek'ed.
1788   if (this->buf_read >= this->buf_size && this->buf_size > 0 &&
1789       buf_packet_seq_offset >= 0 ||
1790       // assuming packet not peek'ed in the following condition
1791       /*this->buf_read >= this->buf_size && */this->buf_size == 0 &&
1792       buf_packet_seq_offset == 0)
1793     // The buf is all read but the packet has not been peek'ed.
1794     --buf_packet_seq_offset;
1795 #else
1796   buf_packet_seq_offset = this->current_pos - this->asf_header_len - 1;
1797   //if (buf_packet_seq_offset > 0) buf_packet_seq_offset /= this->asf_packet_len;
1798   buf_packet_seq_offset = buf_packet_seq_offset >= 0 ?
1799     buf_packet_seq_offset / this->asf_packet_len : -1;
1800   // Note: buf_read == buf_size == 0 may means that it is eos,
1801   //       eos means that the packet has been peek'ed.
1802   if (this->buf_read == 0/* && buf_packet_seq_offset >= 0*/)
1803     // Since the packet has just been peek'ed.
1804     ++buf_packet_seq_offset;
1805 #endif
1806 #endif
1807 
1808   if (dest_packet_seq < 0) {
1809     if (this->buf_packet_seq_offset > 0) {
1810       if (!mms_request_packet_seek (io, this, 0xFFFFFFFF))
1811         return this->current_pos;
1812 #if 1
1813       // clear buf
1814       this->buf_read = this->buf_size = 0;
1815       this->buf_packet_seq_offset = -1;
1816     } else {
1817 #else
1818       // clear buf
1819       this->buf_read = this->buf_size;
1820       // Set this packet sequence not to be reused, since the subsequence
1821       // packet may be discontinued.
1822       this->buf_packet_seq_offset = -1;
1823     // don't reset buf_read if buf_packet_seq_offset < 0, since the previous
1824     // buf may not be cleared.
1825     } else if (this->buf_packet_seq_offset == 0) {
1826 #endif
1827       // reset buf_read
1828       this->buf_read = 0;
1829     }
1830     this->asf_header_read = dest;
1831     return this->current_pos = dest;
1832   }
1833   // dest_packet_seq >= 0
1834   if (this->asf_num_packets && dest == this->asf_header_len +
1835       this->asf_num_packets*this->asf_packet_len) {
1836     // Requesting the packet beyond the last packet, can cause the server to
1837     // not return any packet or any eos command.  This can cause
1838     // mms_packet_seek() to hang.
1839     // This is to allow seeking at end of stream, and avoid hanging.
1840     --dest_packet_seq;
1841   }
1842   if (dest_packet_seq != this->buf_packet_seq_offset) {
1843     if (this->asf_num_packets && dest_packet_seq >= this->asf_num_packets) {
1844       // Do not seek beyond the last packet.
1845       return this->current_pos;
1846     }
1847     if (!mms_packet_seek (io, this, this->start_packet_seq + dest_packet_seq))
1848       return this->current_pos;
1849     // Check if current_pos is correct.
1850     // This can happen if the server ignore packet seek command.
1851     // If so, just return unchanged current_pos, rather than trying to
1852     // mms_read() to reach the destination pos.
1853     // It should let the caller to decide to choose the alternate method, such
1854     // as, mms_time_seek() and/or mms_read() until the destination pos is
1855     // reached.
1856     if (dest_packet_seq != this->buf_packet_seq_offset)
1857       return this->current_pos;
1858     // This has already been set in mms_packet_seek().
1859     //if (current_packet_seq < 0)
1860     //  this->asf_header_read = this->asf_header_len;
1861     //this->asf_header_read = this->asf_header_len;
1862   }
1863   // eos is reached ?
1864   //if (this->buf_size <= 0) return this->current_pos;
1865   //this->buf_read = (dest - this->asf_header_len) % this->asf_packet_len;
1866   this->buf_read = dest -
1867     (this->asf_header_len + dest_packet_seq*this->asf_packet_len);
1868   // will never happen ?
1869   //if (this->buf_size <= this->buf_read) return this->current_pos;
1870   return this->current_pos = dest;
1871 }
1872 
1873 
1874 void mms_close (mms_t *this) {
1875   if (this->s != -1)
1876     close (this->s);
1877   if (this->url)
1878     free(this->url);
1879   if (this->guri)
1880     gnet_uri_delete(this->guri);
1881   if (this->uri)
1882     free(this->uri);
1883 
1884   free (this);
1885 }
1886 
1887 double mms_get_time_length (mms_t *this) {
1888   return (double)(this->time_len) / 1e7;
1889 }
1890 
1891 uint64_t mms_get_raw_time_length (mms_t *this) {
1892   return this->time_len;
1893 }
1894 
1895 uint32_t mms_get_length (mms_t *this) {
1896   /* we could / should return this->file_len here, but usually this->file_len
1897      is longer then the calculation below, as usually an asf file contains an
1898      asf index object after the data stream. However since we do not have a
1899      (known) way to get to this index object through mms, we return a
1900      calculated size of what we can get to when we know. */
1901   if (this->asf_num_packets)
1902     return this->asf_header_len + this->asf_num_packets*this->asf_packet_len;
1903   else
1904     return this->file_len;
1905 }
1906 
1907 off_t mms_get_current_pos (mms_t *this) {
1908   return this->current_pos;
1909 }
1910 
1911 uint32_t mms_get_asf_header_len (mms_t *this) {
1912   return this->asf_header_len;
1913 }
1914 
1915 uint64_t mms_get_asf_packet_len (mms_t *this) {
1916   return this->asf_packet_len;
1917 }
1918 
1919 int mms_get_seekable (mms_t *this) {
1920   return this->seekable;
1921 }
1922