📄 mmst.c
字号:
/*********************************************************************** * mmst.c: downloading via mmst (Microsoft Media Service over TCP) *********************************************************************** * Copyright (C) 2007 metro <me_t_ro@yahoo.com> * * This file is part of msdl, media stream downloader * * This file is based on mms implementation of mplayer, * and Windows Media Player transaction I saw through * packet monitoring program, wireshark (http://www.wireshark.org/) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. * ***********************************************************************//* * Copyright notice of MPlayer project * which some part of msdl is based on. * (from MPlayer-1.0rc2/stream/asf_mmst_streaming.c) *//* * MMST implementation taken from the xine-mms plugin made by * Major MMS (http://geocities.com/majormms/). * Ported to MPlayer by Abhijeet Phatak <abhijeetphatak@yahoo.com>. * * Information about the MMS protocol can be found at http://get.to/sdp * * copyright (C) 2002 Abhijeet Phatak <abhijeetphatak@yahoo.com> * copyright (C) 2002 the xine project * copyright (C) 2000-2001 major mms * * This file is part of MPlayer. * * MPlayer is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * MPlayer is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <ctype.h>#include <sys/types.h>#include <sys/socket.h>#include "msdl.h"#include "msdllib.h"#include "display.h"#include "network.h"#include "asf.h"#include "mmst.h"static struct mmst_ctrl_t *new_mmst_ctrl_t(void);static void free_mmst_ctrl_t(struct mmst_ctrl_t *mctrl);static int mmst_get_command_packet(struct stream_t *stream);static struct mmst_ctrl_t *new_mmst_ctrl_t(void){ struct mmst_ctrl_t *mctrl = xmalloc(sizeof(struct mmst_ctrl_t)); mctrl->seq_num = 0; mctrl->num_stream_ids = 0; mctrl->hinfo = new_asf_headerinfo_t(); return mctrl;}static void free_mmst_ctrl_t(struct mmst_ctrl_t *mctrl){ if(mctrl->hinfo) free_asf_headerinfo_t(mctrl->hinfo); if(mctrl) free(mctrl);}/* * send command */static void send_command(struct stream_t *stream,int command, uint32_t f1,uint32_t f2, int length,uint8_t *data){ int len8 = (length+7) / 8; uint8_t *cmd = (uint8_t *)xmalloc(len8 * 8 + 0x30); // 0x30 for header. /* put data in little endian */ put32_le(cmd + 0x00,0x00000001); /* rep | version | versionMinor | padding */ put32_le(cmd + 0x04,0xB00BFACE); /* sessionId */ put32_le(cmd + 0x08,len8*8 + 32); /* messageLength */ put32_le(cmd + 0x0C,0x20534d4d); /* "MMS " */ put32_le(cmd + 0x10,len8 + 4); /* chunkCount */ put32_le(cmd + 0x14,stream->stream_ctrl->mmst_ctrl->seq_num); /* seq | MBZ */ stream->stream_ctrl->mmst_ctrl->seq_num++; put32_le(cmd + 0x18,0x00); /* timeSent */ put32_le(cmd + 0x1C,0x00); /* timeSent */ put32_le(cmd + 0x20,len8+2); /* chunkLen */ put32_le(cmd + 0x24,0x00030000 | command); /* dir | command */ put32_le(cmd + 0x28,f1); put32_le(cmd + 0x2C,f2); memcpy(cmd + 0x30, data, length); if(length & 0x07) { /* do padding */ memset(cmd + 0x30 + length, 0, 8 - (length & 0x07)); } display(MSDL_DBG,"=-send-------------------------------------------=\n"); dbgdump(cmd,len8 * 8 + 0x30); display(MSDL_DBG,"\n=------------------------------------------------=\n"); if(xsend(stream->netsock->sock,cmd,len8*8+0x30) != (len8*8+0x30)){ perror("send() failed"); } free(cmd);}/* * convert string to UTF16, so that mms server can understand. */static void string_utf16(char *dst,char *src,int len){ int i; if(len > 499) len = 499; for(i = 0; i < len; i ++) { dst[i * 2] = src[i]; dst[i * 2 + 1] = 0; } dst[i * 2] = 0; dst[i * 2 + 1] = 0;}/* * get Micro$oft ASF header. * return value: asf header length : success * negative : failure */static int mmst_get_asf_header(struct stream_t *stream, uint8_t *header){ int header_len = 0; /* total header length. */ uint32_t packet_len = 0; /* length of this packet. */ int command; uint8_t pre_header[8]; /* pre_header, before header. */ while(1) { /* we have to collect all header packet together. */ /* first, for each packet,get pre_header and know packet length etc... */ if(read_data(stream,pre_header,8) <= 0) { /* read_data() failed. */ goto failed; } if(pre_header[4] == 0x02) { /* header packet */ packet_len = get16_le(((uint8_t *)&pre_header) + 6) - 8; if(packet_len < 0 || HDR_BUF_SIZE - header_len < packet_len) { display(MSDL_ERR,"invalid header size\n"); goto failed; } if(read_data(stream,header + header_len, packet_len) <= 0) { /* read_data failed */ goto failed; } header_len += packet_len; /* accumulate */ /* end of header. */ if(header[header_len - 1] == 1 && header[header_len - 2] == 1) { /* success, got M$ ASF header, in header packet */ return header_len; } } else { /* command packet received. */ uint8_t *combuf; if(read_data(stream,&packet_len,4) <= 0) { display(MSDL_ERR,"read_data for packet_len failed\n"); goto failed; } packet_len = get32_le(&packet_len) + 4; if(packet_len < 0 || BUF_SIZE < packet_len) { display(MSDL_ERR,"%x: invalid packet size\n",packet_len,BUF_SIZE); goto failed; } combuf = xmalloc(packet_len); if(read_data(stream,combuf,packet_len) <= 0) { /* error */ free(combuf); goto failed; } command = get32_le(combuf + 24) & 0xFFFF; if(command == 0x1b) { send_command(stream,0x1b, 0, 0, 0, combuf); } free(combuf); } } failed: return -1;}/* * start mmst streaming. * * return value : negative or 0 ... error * 1 ... success */int mmst_streaming_start(struct stream_t *stream){ struct url_t *url = stream->url; struct stream_ctrl_t *stream_ctrl = stream->stream_ctrl; struct mmst_ctrl_t *mmst_ctrl = stream_ctrl->mmst_ctrl; uint8_t *buffer = NULL; uint8_t *buffer2 = NULL; uint8_t *asf_header = NULL; int ret = 0; int asf_header_len = 0; char *path, *escaped_path; int sock; /* socket to use */ int pos; int i; stream->stream_ctrl->status = STREAMING_HANDSHAKING; buffer = (uint8_t *)xmalloc(BUFSIZE_1K); /* send buffer. used for data to send */ buffer2 = (uint8_t *)xmalloc(BUFSIZE_1K); /* working buffer */ escaped_path = strchr(url->file,'/') + 1; path = (char *)xmalloc(strlen(escaped_path) + 1); /* remove something like '%41' in url. */ url_unescape_string(path,escaped_path); if(stream->dlopts->bandwidth) { stream_ctrl->bandwidth = stream->dlopts->bandwidth; } else { stream_ctrl->bandwidth = INT_MAX_BANDWIDTH; } set_serverinfo(stream->serverinfo,url->hostname,url->port,NULL,0,MMS_PORT); sock = server_connect(stream->serverinfo->connect_host,stream->serverinfo->connect_port); if(sock < 0) { /* couldn't connect for some reason. */ free(path); goto failed; } stream->netsock->sock = sock; mmst_ctrl->seq_num = 0; /* * first thing to do: 0x01 command, do the protocol initiation. */ snprintf((char *)buffer2,BUFSIZE_1K - 1, "\034\003NSPlayer/7.0.0.1956; {33715801-BAB3-9D85-24E9-03B90328270A}; Host: %s", stream->serverinfo->host); string_utf16((char *)buffer,(char *)buffer2, strlen((char *)buffer2)); /* send !! */ send_command(stream,1, 0, 0x0004000b, strlen((char *)buffer2)*2+2, buffer); /* 1st reply */ mmst_get_command_packet(stream); /* * 0x02 command. send details of the local IP addr */ string_utf16((char *)buffer + 8, "\002\000\\\\192.168.0.1\\TCP\\1037", 24); memset(buffer,0,8); send_command(stream,2, 0, 0, 24*2+10, buffer); /* 2nd reply */ mmst_get_command_packet(stream); /* * 0x05 command, send request file path. */ string_utf16((char *)buffer + 8,path,strlen(path)); memset(buffer,0,8); send_command(stream,5, 0, 0, strlen(path) * 2 + 10, buffer); free(path); mmst_get_command_packet(stream); /* * 0x15 cmmand The ASF header chunk request, include ?session variable * for pre header. * After this command sent server should reply with 0x11 command and then * header chunk with header comes. */ memset(buffer,0,40); buffer[0x20] = 2; send_command(stream,0x15, 1, 0, 40, buffer); /* * header goes to asf_header, which is actually stream_ctrl->write_buffer. * ( write_buffer because this header is directly written to file) */ asf_header_len = mmst_get_asf_header(stream,stream_ctrl->write_buffer); if(asf_header_len <= 0) { /* failed */ display(MSDL_ERR,"cannot receive M$ asf header\n"); goto failed; } asf_header = stream_ctrl->write_buffer; stream_ctrl->write_pos = 0; /* asf header starting from stream_ctrl->write_buffer + 0. */ stream_ctrl->write_data_len = asf_header_len; mmst_ctrl->hinfo->asf_header = xmalloc(asf_header_len); memcpy(mmst_ctrl->hinfo->asf_header,asf_header,asf_header_len); ret = asf_interpret_header(mmst_ctrl->hinfo,stream_ctrl->bandwidth, asf_header,asf_header_len); { display(MSDL_DBG,"ASF_HEADER---------------------\n"); dbgdump(asf_header,asf_header_len); display(MSDL_DBG,"\n-------------------------------\n"); } if(ret < 0) { display(MSDL_ERR,"cannot receive packet length\n"); goto failed; } /* set file size to download */ stream_ctrl->file_size = mmst_ctrl->hinfo->fileh->file_size; display(MSDL_VER, "ASF header length: %d bytes\n"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -