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