⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 core_mmsh.cpp

📁 ASFR+是在ASFRecorder的基础上的改进版本,它可以: ◇支持中文文件名. ◇多线程下载ASF文件. ◇断点续传,自动重试. ◇支持MMS(TCP)协议和HTTP协议(自动探测). ◇在下载
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
  ModuleL: core_mmsh.cxx
  ASF donwload and extraction
*/

/* The core routine for ASF download/extraction. */
#include "core_mmsh.h"

#include "../../asfr.h"

#include "../asf_commonh.h"
#include "../asf_helper.h"
#include "../asf_redirection.h"
#include "../asf_net.h"

void core_mmsh(struct JOB_PARM *My_Job)
{
	int				MyID = My_Job->ThreadID;
	struct THREAD_INFO 		*My_ti = My_Job->ti[MyID];
	struct HEADER_INFO 		*My_hi = My_Job->hi;
	struct CUSTOM_INFO_ASF 	*My_ci = (struct CUSTOM_INFO_ASF*)My_Job->ci;

	unsigned int i;
	unsigned char Buffer[MAX_CHUNK_SIZE];

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	switch(My_ti->RequestType)
	{
	case REQUEST_INIT:
		My_Job->ciSize = sizeof(struct CUSTOM_INFO_ASF);
		break;

	case REQUEST_RESET:
		memset(My_ci, 0, sizeof(struct CUSTOM_INFO_ASF));
		My_ci->ASFContentType = unknown_content;
		My_ci->PortNum = MMSH_DEFAULT_PORT;
		randomize_guid(My_ci->RandomizedGUID);
		break;

	case REQUEST_INFORMATION:
		{

			char *URLPtr;
			char *DashPtr;
			char *ColonPtr;
			char EscapedURL[512];

			My_ti->Reply = REPLY_FAIL;

			/* Firset treat this as a on-disk redirection file */
			parse_redirection(My_Job, NULL, 0);

			gui_showstatus(STATUS_INFORMATION, "Parsing URL: '%s'\n", My_Job->URL);

			/* replace unescaped characters (e.g. spaces) by escape sequences */
			escape_url_string(EscapedURL, My_Job->URL);

			URLPtr = EscapedURL;
			if (!strnicmp("http://", URLPtr, 7)) URLPtr += 7;
			if (!strnicmp("mms://",  URLPtr, 6)) URLPtr += 6;
			DashPtr = strchr(URLPtr, '/');
			if (DashPtr == NULL)
			{
				DashPtr = URLPtr+strlen(URLPtr);
				gui_showstatus(STATUS_CRITICALERROR, "Invalid URL format!\n");
				break;
			}
			else
			    {
				strncpy(My_ci->ServerName, URLPtr, DashPtr-URLPtr);
				My_ci->ServerName[DashPtr-URLPtr] = 0;
				strcpy(My_ci->File, DashPtr);

				ColonPtr = strchr(My_ci->ServerName, ':');
				if (ColonPtr != NULL)
				{
					My_ci->PortNum = (unsigned short)atol(ColonPtr+1);
					*ColonPtr = '\0';
					if (My_ci->PortNum == 0)
					{
						gui_showstatus(STATUS_CRITICALERROR, "Invalid URL format!\n");
						strcpy(My_ci->ServerName, "");
						strcpy(My_ci->File, "");
						break;
					}
				}
			} /* url parse finished */

			/* parse proxy URL */
			if ( strcmp( My_Job->Proxy, "") )
			{
				char FullPath[512];
				if (My_ci->PortNum == MMSH_DEFAULT_PORT)
					sprintf(FullPath, "http://%s%s", My_ci->ServerName, My_ci->File);
				else
				    sprintf(FullPath, "http://%s:%d%s", My_ci->ServerName, My_ci->PortNum, My_ci->File);
				strcpy(My_ci->File, FullPath);

				escape_url_string(EscapedURL, My_Job->Proxy);
				URLPtr = EscapedURL;
				if (!strnicmp("http://", URLPtr, 7)) URLPtr+=7;

				DashPtr = strchr(URLPtr, '/'); /* There should be no '/' in proxy string */
				if (DashPtr != NULL)
					gui_showstatus(STATUS_CRITICALERROR, "Invalid proxy URL format!\n");
				else
				    {
					ColonPtr = strchr(URLPtr, ':');
					if (ColonPtr != NULL)
					{
						unsigned short ProxyPortNum;
						ProxyPortNum = (unsigned short)atol(ColonPtr+1);
						if (ProxyPortNum == 0)
						{
							gui_showstatus(STATUS_CRITICALERROR, "Invalid proxy URL format!\n");
							strcpy(My_ci->ServerName, "");
							strcpy(My_ci->File, "");
						}
						else
						    My_ci->PortNum = ProxyPortNum;
					}
					else
					    ColonPtr = URLPtr+strlen(URLPtr);

					strncpy(My_ci->ServerName, URLPtr, ColonPtr-URLPtr);
					My_ci->ServerName[ColonPtr-URLPtr] = 0;
				}
			} /* proxy parse finished */

			if ( strcmp(My_Job->Username, "") || strcmp(My_Job->Password, "") )
			{
				char PasswordCombo[128];
				sprintf(PasswordCombo, "%s:%s", My_Job->Username, My_Job->Password);
				base64enc(PasswordCombo,My_ci->Base64Buf);
			}

			if(Debug) gui_showstatus(STATUS_INFORMATION, "ServerName: '%s'\nPortNum: %d\nFile: '%s'\n",
			My_ci->ServerName, My_ci->PortNum, My_ci->File);

			/* Attempt to detect if we should call gethostbyname() or gethostbyaddr() */
			if(Debug) gui_showstatus(STATUS_INFORMATION, "Resolving host: '%s'\n", My_ci->ServerName);

			unsigned int Addr = 0;
			struct hostent *hp = NULL;

			if (isalpha(My_ci->ServerName[0]))
			{
				/* Server address is a host name */
				hp = gethostbyname(My_ci->ServerName);
				if (hp == NULL)
				{
					gui_showstatus(STATUS_CRITICALERROR, "Unable to resolve host '%s'!\n", My_ci->ServerName);
					break;
				}
			}
			else
			    {
				/* Server is a ip address. convert nnn.nnn address to a usable one */
				Addr = inet_addr(My_ci->ServerName);
				if ((hp = gethostbyaddr((char *)&Addr,4,AF_INET))!=NULL)
					strcpy(My_ci->ServerName, hp->h_name);
			}	/* Gethost finished */

			/* Copy the resolved information into the sockaddr_in structure */
			if (hp != NULL)
			{
				memcpy(&(My_ci->Server.sin_addr),hp->h_addr,hp->h_length);
				My_ci->Server.sin_family = hp->h_addrtype;
				strcpy(My_ci->ServerName, hp->h_name);
			}
			else
			    {
				memcpy(&(My_ci->Server.sin_addr), &Addr, 4);
				My_ci->Server.sin_family = AF_INET;
			}
			My_ci->Server.sin_port = htons(My_ci->PortNum);
		} /* Fall through */

	case REQUEST_GETDATA:
		{
			My_ti->Message = 0;
			My_ti->Reply = REPLY_FAIL;

			/* Open a socket */
			SOCKET ConnSocket;
			if ((ConnSocket=my_socket(AF_INET, SOCK_STREAM, 0)) <= 0)
			{
				gui_showstatus(STATUS_CRITICALERROR, "Socket() failed: %d\n", errno);
				break;
			}

			gui_showstatus(STATUS_INFORMATION, "Connecting to: %s:%d\n", My_ci->ServerName, My_ci->PortNum);

			if( my_connect(ConnSocket, (struct sockaddr*)&(My_ci->Server), sizeof(My_ci->Server)) == SOCKET_ERROR )
			{
				if(My_ci->PortNum == MMSH_DEFAULT_PORT) /* maybe this is a dedicated mmst server, mmsh port(80) is not opened */
					My_ti->Reply = REPLY_MMST;	/* Try mmst next time */
				gui_showstatus(STATUS_CRITICALERROR, "connect() failed: %d\n", errno);
				break;
			}

			/* Prepare a stream to read incoming datas */
			struct STREAM_PARM Stream_Parm;
			Stream_Parm.RequestType = REQUEST_INIT;
			Stream_Parm.conn_socket = ConnSocket;
			if( (Stream_Parm.si = (char*)malloc( readfromstream(&Stream_Parm, 0, 0))) == NULL) break;

			Stream_Parm.RequestType = REQUEST_RESET;
			readfromstream(&Stream_Parm, 0, 0);

			Stream_Parm.RequestType = REQUEST_GETDATA;

			/* Generate a HTTP request */
			unsigned long OffsetHi = 0;
			unsigned long OffsetLo = My_ti->SourOffset;
			char *BufPtr = (char*)Buffer;
			if(OffsetLo == 0) OffsetHi=0xffffffff,OffsetLo=0xffffffff;

			if (My_ti->RequestType == REQUEST_GETDATA)
			{	/* Generate information for server */
				BufPtr+=sprintf(BufPtr,"GET %s HTTP/1.0\r\n", My_ci->File);
				if ( ustrcmp(My_ci->Base64Buf, "") ) BufPtr += sprintf(BufPtr,"Authorization: Basic %s\r\n", My_ci->Base64Buf);
				BufPtr+=sprintf(BufPtr,"Accept: */*\r\n");
				BufPtr+=sprintf(BufPtr,"User-Agent: NSPlayer/4.1.0.3856\r\n");
				if ( strcmp(My_Job->Proxy, "") ) BufPtr+=sprintf(BufPtr,"Host: %s\r\n", My_ci->ServerName);
				if (My_ci->ASFContentType == prerecorded_content)
					BufPtr+=sprintf(BufPtr,"Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=%u:%u,request-context=2,max-duration=0\r\n",(unsigned)OffsetHi,(unsigned)OffsetLo);
				if (My_ci->ASFContentType == live_content)
					BufPtr+=sprintf(BufPtr,"Pragma: no-cache,rate=1.000000,request-context=2\r\n");
				BufPtr+=sprintf(BufPtr,"Pragma: xPlayStrm=1\r\n");
				BufPtr+=sprintf(BufPtr,"Pragma: xClientGUID=%s\r\n", My_ci->RandomizedGUID);
				BufPtr+=sprintf(BufPtr,"Pragma: stream-switch-count=1\r\n");
				BufPtr+=sprintf(BufPtr,"Pragma: stream-switch-entry=ffff:1:0\r\n");
				BufPtr+=sprintf(BufPtr,"Connection: Close\r\n\r\n");
			}
			if (My_ti->RequestType == REQUEST_INFORMATION)
			{
				BufPtr+=sprintf(BufPtr,"GET %s HTTP/1.0\r\n", My_ci->File);
				if ( ustrcmp(My_ci->Base64Buf, "") ) BufPtr += sprintf(BufPtr,"Authorization: Basic %s\r\n", My_ci->Base64Buf);
				BufPtr+=sprintf(BufPtr,"Accept: */*\r\n");
				BufPtr+=sprintf(BufPtr,"User-Agent: NSPlayer/4.1.0.3856\r\n");
				if ( strcmp(My_Job->Proxy, "") ) BufPtr+=sprintf(BufPtr,"Host: %s\r\n", My_ci->ServerName);
				BufPtr+=sprintf(BufPtr,"Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=0:0,request-context=1,max-duration=0\r\n");
				BufPtr+=sprintf(BufPtr,"Pragma: xClientGUID=%s\r\n", My_ci->RandomizedGUID);
				BufPtr+=sprintf(BufPtr,"Connection: Close\r\n\r\n");
			}

			if (DUMP_HEADERS) 			/* Dump the outgoing HTTP request */
				gui_showstatus(STATUS_INFORMATION, "\nHTTP-Request to send:\n%s", Buffer);

			gui_showstatus(STATUS_INFORMATION, "sending request [%d bytes]\n",(int)BufPtr-(int)Buffer);

			if ((my_send(ConnSocket,Buffer,((int)BufPtr-(int)Buffer),0)) == SOCKET_ERROR)
			{
				gui_showstatus(STATUS_CRITICALERROR, "send() failed: %d\n", errno);
				my_closesocket(ConnSocket);
				free(Stream_Parm.si);
				break;
			}

			gui_showstatus(STATUS_INFORMATION, "Waiting for reply...\n");

			char HTTPLine[512];
			char HTTPMessage[128] = "<none>";
			char Features[256] = "";
			char ContentType[256] = "";
			char ServerType[256] = "";

			char *HDRPtr;
			unsigned int ErrorCode = 0;
			unsigned int EOL = 0;
			unsigned int HDRPos = 0;
			unsigned int LinePos = 0;
			unsigned int LineNum = 0;
			unsigned char ToBreak = 0;

			for (;;)
			{
				unsigned char c;

				if (readfromstream(&Stream_Parm, &c, 1) == 1)
				{
					/* Server is OK, so retry if connect reset */
					My_ti->Reply = REPLY_RETRY;

					if ((c != '\r') && (c != '\n'))
					{
						EOL = 0;
						HTTPLine[LinePos++] = c;
					}
					else
						HTTPLine[LinePos++] = 0;

					if (c == '\n')	/* finish of a line */
					{
						if (EOL == 0) /* if this is first '/n'? 2 '/n' will make this FALSE ,which mean end of HTTP header */
						{
							LinePos = 0;
							EOL = 1;
							LineNum++;
							HDRPtr = HTTPLine;

							if (LineNum == 1) /* Parse first line of HTTP reply */
							{
								if ((!strnicmp(HDRPtr, "HTTP/1.0 ", 9)) || (!strnicmp(HDRPtr, "HTTP/1.1 ", 9)))
								{
									HDRPtr += 9;
									sscanf(HDRPtr, "%d", &ErrorCode);
									HDRPtr += 4;
									strcpy(HTTPMessage, HDRPtr);
								}
								else
								    gui_showstatus(STATUS_CRITICALERROR, "Illegal server reply! Expected HTTP/1.0 or HTTP/1.1\n");
							}
							else
							    {
								/* Parse all other lines of HTTP reply , find "Content-Type:" */
								if (!strnicmp(HDRPtr, "Content-Type: ", 14))
								{
									HDRPtr += 14;
									strncpy(ContentType, HDRPtr, sizeof(ContentType));
								}
								if (!strnicmp(HDRPtr, "Pragma: ", 8))
								{
									HDRPtr += 8;
									if (!strnicmp(HDRPtr, "features=", 9))
									{
										HDRPtr += 9;
										strncpy(Features, HDRPtr, sizeof(Features));
									}
								}
								if (!strnicmp(HDRPtr, "Server: ", 8))
								{
									HDRPtr += 8;
									strncpy(ServerType, HDRPtr, sizeof(ServerType));
								}
							}
						}
						else
						    {
							Buffer[HDRPos++] = 0;
							break;
						}
					}
					Buffer[HDRPos++] = c;
				}
				else
				{
					if( !HDRPos ) /* Nothing Received, this is probably a mmst stream */
						My_ti->Reply = REPLY_MMST;
				    gui_showstatus(STATUS_CRITICALERROR, "readfromstream() returned other than 1!\n");
					ToBreak = 1;
					break;
				}
			}

			if(ToBreak) break;
			ToBreak = 0;

			gui_showstatus(STATUS_INFORMATION, "reply: %d - %s\n", ErrorCode, HTTPMessage);

			/* Dump the incoming HTTP reply */
			if (DUMP_HEADERS)
				gui_showstatus(STATUS_INFORMATION, "\nHTTP-Reply:\n%s\n", Buffer);

			/* Detect reply's content, apply only once */
			if(My_ti->RequestType == REQUEST_INFORMATION)
			{
				if ( !stricmp(ContentType, "application/octet-stream") )
				{
					if (strstr(Features, "broadcast"))
					{
						My_ci->ASFContentType = live_content;
						My_hi->Resumeable = FALSE;
					}
					else
					    {
						My_ci->ASFContentType = prerecorded_content;
						My_hi->Resumeable = TRUE;
					}
				}
				else /* Then what's it */
				    {
					if (!eos(&Stream_Parm))				/* try to read as much data as fits into the buffer */
					{
						unsigned char c = 0x00;
						unsigned int RedirSize = 0;
						unsigned int PrintableCount = 0;

						RedirSize = readfromstream(&Stream_Parm, Buffer, MAX_CHUNK_SIZE);
						for(i=0 ; i<RedirSize ; c=Buffer[i++]) /* Count all printable chars */
						{
							if( (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n')) continue;
							if(isprint(c)) PrintableCount++;
						}
						if(PrintableCount >= RedirSize*3/4) /* If printable chars > 3/4, assume it as redirector */
						{
							gui_showstatus(0, "\n%s", Buffer);
							parse_redirection(My_Job, Buffer, RedirSize);
							My_ti->Reply = REPLY_RETRY;
						}
						else
						{
							gui_showstatus(STATUS_CRITICALERROR, "This is a HTTP content\n");
							My_ti->Reply = REPLY_HTTP;
						}
					}
					else
					    {
						gui_showstatus(STATUS_CRITICALERROR, "Unknown content-type: %s\n", ContentType);
					}
				}

				switch(ErrorCode)
				{
				case 200: /* ok */
					break;

				case 401:
					My_hi->RequirePassword = TRUE;
					ToBreak = 1;
					break;

				case 400: /* Bad Request */
				case 404: /* The famous 404 error */
					My_ti->Reply = REPLY_MMST;
					ToBreak = 1;
					break;

				case 453: /* "Not enough bandwidth" */
					My_ti->Reply = REPLY_RETRY;
					ToBreak = 1;
					break;

				default:  /* We dont know what it is */
					My_ci->ASFContentType = server_error;
					ToBreak = 1;
					break;
				}
			}

			if(ToBreak)
			{
				my_closesocket(ConnSocket);
				free(Stream_Parm.si);
				break;
			}

			/* Return if contenttype unknown */
			if ( eos(&Stream_Parm) || ((My_ci->ASFContentType != live_content) && (My_ci->ASFContentType != prerecorded_content)) )
			{
				my_closesocket(ConnSocket);
				free(Stream_Parm.si);
				break;
			}

			/* Handle live or prerecorded content */
			unsigned long MyFilePointer = 0;
			unsigned char TimeCodeString[64]={""};
			//unsigned int StartTimeHi = 0xffffffff;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -