📄 wmserver.c
字号:
/*********************************************************************** * wmserver.c : for downloading from WMServer using rtsp *********************************************************************** * Copyright (C) 2007 metro <me_t_ro@yahoo.com> * * This file is part of msdl, media stream downloader * * This file is based on information shown on wireshark, * analyzing transaction of Windows media player. * * * 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. * ***********************************************************************/ #include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include "msdl.h"#include "msdllib.h"#include "display.h"#include "network.h"#include "rtsp.h"#include "asf.h"#include "sdpcommon.h"#include "sdpwms.h"#include "wmserver.h"/* * Windows Media Player provided RTSP strings */static const char wms_useragent[] = "User-Agent: WMPlayer/11.0.5721.5145 guid/3300AD50-2C39-46C0-AE0A-E1D79F0FD2D8";static const char wms_supported[] = "Supported: com.microsoft.wm.srvppair, com.microsoft.wm.sswitch, com.microsoft.wm.eosmsg, com.microsoft.wm.fastcache, com.microsoft.wm.packetpairssrc, com.microsoft.wm.startupprofile";static const char wms_authentication[]= "X-Accept-Authentication: Negotiate, NTLM, Digest, Basic";static const char wms_transport[] = "Transport: RTP/AVP/TCP;unicast;interleaved=0-1;ssrc=75afe1e1;mode=PLAY";static int wmserver_process_header(struct stream_t *stream);static int wmserver_process_media_packet(struct stream_t *stream,uint8_t *header, uint8_t *buffer,size_t max_size);int wmserver_prepare_resuming(struct stream_t *stream);/* * send DESCRIBE * return value: -1: failed 1: success 0: retry with other protocol */static int wmserver_rtsp_describe(struct stream_t *stream,char **description_ret){ struct rtsp_ctrl_t *rtsp_ctrl = stream->stream_ctrl->rtsp_ctrl; struct rtsp_header_t *rtsp_hdr = NULL; char *description = NULL; int ret = 0; char *field = 0; int len = 0; /* send DESCRIBE request */ rtsp_hdr = new_rtsp_header_with_standard_fields(rtsp_ctrl); rtsp_set_field(rtsp_hdr, wms_useragent); rtsp_set_field(rtsp_hdr, wms_supported); rtsp_request_describe(rtsp_hdr,rtsp_ctrl->mrl); rtsp_send_request_and_free(stream,rtsp_hdr); /* receive reply for DESCRIBE */ rtsp_hdr = new_rtsp_header(); ret = rtsp_recv_header(stream,rtsp_hdr); if(ret < 0) { free_rtsp_header(rtsp_hdr); goto failed_retry; } /* NOT OK */ if(!is_rtsp_response_ok(rtsp_hdr->status_code)) { display(MSDL_ERR,"DESCRIBE request returned: %d (%s)\n", rtsp_hdr->status_code,rtsp_hdr->reason_phrase); field = rtsp_get_field(rtsp_hdr,"Alert"); if(field) { while(*field == ' ') field++; display(MSDL_ERR,"message from server --> %s\n",field); } free_rtsp_header(rtsp_hdr); goto failed; } len = 0; /* Content-length must be present */ if((field = rtsp_get_field(rtsp_hdr,"Content-Length")) != NULL) { while(*field == ' ') field++; len = atoi(field); } else { /* no Content-length */ display(MSDL_ERR,"warning: No Content-Length in fields!!\n"); } if((field = rtsp_get_field(rtsp_hdr,"ETag")) == NULL) { display(MSDL_VER,"warning: No ETag!!\n"); /* in MS-RTSP Etag is not necessary */ } free_rtsp_header(rtsp_hdr); /* copy description (sdp) */ description = (char *)xmalloc(len + 1); len = read_data(stream,(uint8_t *)description,len); description[len] = '\0'; display(MSDL_DBG,"=desc=================\n%s\n=(%d bytes)========desc=\n", description,(int)strlen(description)); *description_ret = description; return 1; failed: if(description) free(description); *description_ret = NULL; return -1; failed_retry: if(description) free(description); *description_ret = NULL; return 0;}/* * send SETUP request * return value: -1: failed last status code: SETUP request sent */static int wmserver_rtsp_setup(struct stream_t *stream, struct asf_headerinfo_t *asf_headerinfo,struct sdpwms_t *sdpwms){ struct rtsp_ctrl_t *rtsp_ctrl = stream->stream_ctrl->rtsp_ctrl; char *buffer = NULL; int ret = 0; int i = 0; if(!stream || !asf_headerinfo || !sdpwms) { /* NULL check */ return -1; } if(!(asf_headerinfo->streams->n_audio + asf_headerinfo->streams->n_video)) { return -1; } buffer = xmalloc(BUFSIZE_1K); for(i = 0; i < 2; i++) { /* 0 --> audio, 1 --> video */ int n = 0; int id = 0; char *default_control = NULL; if(i == 0) { n = asf_headerinfo->streams->n_audio; id = asf_headerinfo->streams->audio_id; default_control = "audio"; } else { n = asf_headerinfo->streams->n_video; id = asf_headerinfo->streams->video_id; default_control = "video"; } if(n) { struct list_h *p = NULL; char *controlstr = NULL; struct rtsp_header_t *rtsp_hdr = new_rtsp_header_with_standard_fields(rtsp_ctrl); rtsp_set_field(rtsp_hdr,wms_supported); rtsp_set_field(rtsp_hdr,wms_transport); /* find control for audio_id */ for(p = sdpwms->streams ; p ; p = p->next) { struct sdpwms_stream_t *sdpwmsstream = p->p; if(sdpwmsstream->streamnum == id) { controlstr = sdpwmsstream->control; break; } } if(!controlstr) { controlstr = default_control; /* default */ } if(strstr(controlstr,"://")) { /* --> absolute URL */ snprintf(buffer,BUFSIZE_1K - 1,"%s",controlstr); } else { snprintf(buffer,BUFSIZE_1K - 1,"%s/%s",rtsp_ctrl->mrl,controlstr); } rtsp_request_setup(rtsp_hdr,buffer); rtsp_send_request_and_free(stream,rtsp_hdr); /* receive message for SETUP */ ret = rtsp_recv_header_ignore_message(stream); } } free(buffer); return ret;}/* * send SET_PARAMETER request * return value: -1:failure status code: success */static int wmserver_rtsp_set_parameter(struct stream_t *stream){ struct rtsp_ctrl_t *rtsp_ctrl = stream->stream_ctrl->rtsp_ctrl; struct rtsp_header_t *rtsp_hdr = NULL; char *buffer = xmalloc(BUFSIZE_1K); int ret = 0; rtsp_hdr = new_rtsp_header_with_standard_fields(rtsp_ctrl); rtsp_set_field(rtsp_hdr,wms_useragent); rtsp_request_set_parameter(rtsp_hdr,rtsp_ctrl->mrl); rtsp_send_request_and_free(stream,rtsp_hdr); /* receive message for SET_PARAMETER if something needs to be done to message, use rtsp_recv_header */ ret = rtsp_recv_header_ignore_message(stream); free(buffer); return ret;}/* * send PLAY request * return value: -1:failure status code: success */static int wmserver_rtsp_play(struct stream_t *stream){ struct rtsp_ctrl_t *rtsp_ctrl = stream->stream_ctrl->rtsp_ctrl; struct rtsp_header_t *rtsp_hdr = NULL; char *buffer = xmalloc(BUFSIZE_1K); int ret = 0; int bandwidth_to_send = 0; char *field = NULL; /* * Sending part */ rtsp_hdr = new_rtsp_header_with_standard_fields(rtsp_ctrl); rtsp_set_field(rtsp_hdr,wms_useragent); if(stream->dlopts->resume_download) { wmserver_prepare_resuming(stream); } rtsp_set_range_field(rtsp_hdr,stream->dlopts->range); rtsp_set_speed_field(rtsp_hdr,stream->dlopts->speed); /* bandwidth specified */ bandwidth_to_send = (stream->dlopts->bandwidth) ? (stream->dlopts->bandwidth) : INT_MAX_BANDWIDTH; snprintf(buffer,BUFSIZE_1K - 1,"Bandwidth: %d",bandwidth_to_send); rtsp_set_field(rtsp_hdr,buffer); snprintf(buffer,BUFSIZE_1K - 1, "X-Accelerate-Streaming: AccelDuration = 18000;AccelBandwidth=%d",bandwidth_to_send); rtsp_set_field(rtsp_hdr,buffer); rtsp_request_play(rtsp_hdr,rtsp_ctrl->mrl); rtsp_send_request_and_free(stream,rtsp_hdr); rtsp_hdr = NULL; /* * Receiving part */ /* receive message for PLAY request */ rtsp_hdr = new_rtsp_header(); ret = rtsp_recv_header(stream,rtsp_hdr); if(!is_rtsp_response_ok(ret)) { display(MSDL_ERR,"PLAY request returned: %d (%s)\n", rtsp_hdr->status_code,rtsp_hdr->reason_phrase); field = rtsp_get_field(rtsp_hdr,"Alert"); if(field) { while(*field == ' ') field++; display(MSDL_ERR,"message from server --> %s\n",field); } free_rtsp_header(rtsp_hdr); goto failed; } /* display real speed (might differ from user requested) */ if((field = rtsp_get_field(rtsp_hdr,"Speed")) != NULL) { if(stream->dlopts->speed) { while(*field == ' ') field++; display(MSDL_NOR,"Speed: %s\n",field); } } if((field = rtsp_get_field(rtsp_hdr,"Range")) != NULL) { if(stream->dlopts->range) { while(*field == ' ') field++; display(MSDL_NOR,"Range: %s\n",field); } } /* skip content-length bytes from network */ rtsp_ignore_data_after_header(stream,rtsp_hdr); free_rtsp_header(rtsp_hdr); free(buffer); return ret; failed: free(buffer); return -1;}/* * get asf_headerinfo and sdpwms by sdpstr, and stream->stream_ctrl->bandwidth * return value: 0 : failed 1: success */static int wmserver_get_info_from_sdp_string(struct stream_t *stream,char *sdpstr, struct asf_headerinfo_t **asf_headerinfo_ret, struct sdpwms_t **sdpwms_ret){ struct asf_headerinfo_t *asf_headerinfo = NULL; struct sdpwms_t *sdpwms = NULL; if(!stream || !sdpstr) { /* stream could not be NULL */ goto failed; } /* parse sdp and get information about file to download */ sdpwms = wmserver_parse_sdp(sdpstr); if(sdpwms->asf_header_len <= sizeof(struct asf_header_t)) { display(MSDL_ERR,"asf header smaller than asf_header_t\n"); goto failed; } asf_headerinfo = new_asf_headerinfo_t(); asf_interpret_header(asf_headerinfo,stream->stream_ctrl->bandwidth, sdpwms->asf_header,sdpwms->asf_header_len); /* set asf header len */ asf_headerinfo->asf_header_len = sdpwms->asf_header_len; /* copy raw header */ asf_headerinfo->asf_header = xmalloc(sdpwms->asf_header_len); memcpy(asf_headerinfo->asf_header,sdpwms->asf_header,sdpwms->asf_header_len); /* return structures */ *asf_headerinfo_ret = asf_headerinfo; *sdpwms_ret = sdpwms; return 1; failed: if(asf_headerinfo) free_asf_headerinfo_t(asf_headerinfo); if(sdpwms) free_sdpwms_t(sdpwms); *asf_headerinfo_ret = NULL; *sdpwms_ret = NULL; return 0;}/* * send SETUP,SEND_REQUEST,PLAY requests. * * return value 1 : success * 0 : error, retry via mms * -1 : error. */int wmserver_setup_and_get_header(struct stream_t *stream, struct asf_headerinfo_t **asf_headerinfo_ret){ struct stream_ctrl_t *stream_ctrl = stream->stream_ctrl; struct rtsp_ctrl_t *rtsp_ctrl = stream_ctrl->rtsp_ctrl; struct asf_headerinfo_t *asf_headerinfo = NULL; struct sdpwms_t *sdpwms = NULL; char *description = NULL; int ret = 0; /* use "-b" option 4 low bandwidth.. */ if(stream->dlopts->bandwidth) { stream_ctrl->bandwidth = stream->dlopts->bandwidth; } else { stream_ctrl->bandwidth = INT_MAX_BANDWIDTH; } rtsp_ctrl->cseq = 1; ret = wmserver_rtsp_describe(stream,&description); if(ret == 0) { /* retry */ goto failed_retry; } else if(ret < 0) { goto failed; } if(!wmserver_get_info_from_sdp_string(stream,description,&asf_headerinfo,&sdpwms)) { goto failed; } /* SETUP requests (for audio and video) */ if(wmserver_rtsp_setup(stream,asf_headerinfo,sdpwms) < 0) { goto failed; } /* send SET_PARAMETER request to download stream */ if(wmserver_rtsp_set_parameter(stream) < 0) { goto failed; } /* send PLAY request to download stream */ if(wmserver_rtsp_play(stream) < 0) { goto failed; } /* copy to write buffer */ stream_ctrl->write_pos = 0; memcpy(stream_ctrl->write_buffer, sdpwms->asf_header, sdpwms->asf_header_len); stream_ctrl->write_data_len = sdpwms->asf_header_len; free_sdpwms_t(sdpwms); free(description); *asf_headerinfo_ret = asf_headerinfo; return 1; failed: if(asf_headerinfo) free_asf_headerinfo_t(asf_headerinfo); if(sdpwms) free_sdpwms_t(sdpwms); if(description) free(description); *asf_headerinfo_ret = NULL; return -1; failed_retry: /* retry with other protocol */ if(asf_headerinfo) free_asf_headerinfo_t(asf_headerinfo); if(sdpwms) free_sdpwms_t(sdpwms); if(description) free(description); *asf_headerinfo_ret = NULL; return 0;}/* * After reveiving EOF packet, ANNOUNCE may come when * streaming still continues. (this is most likely to be a download protection) * * * */struct asf_headerinfo_t *wmserver_announce_continue(struct stream_t *stream){ struct stream_ctrl_t *stream_ctrl = stream->stream_ctrl; struct rtsp_ctrl_t *rtsp_ctrl = stream_ctrl->rtsp_ctrl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -