Beispiel #1
0
void _StartPlayListProcessingFromThread(PlayListManager_S state)
{
    char* IP;
    char* Path;
    unsigned short Port;
    char *host;
    int hostLen;
    struct sockaddr_in dest;
    ILibWebClient_RequestToken token;
    char* uri = state->Parent->URI;
    struct packetheader* header = ILibCreateEmptyPacket();

    ILibParseUri(uri, &IP, &Port, &Path);
    ILibSetVersion(header, "1.1", 3);
    ILibSetDirective(header, "GET", 3, Path, (int)strlen(Path));
    host = (char*)malloc((int)strlen(IP) + 10);
    hostLen = sprintf(host, "%s:%u", IP, Port);
    ILibAddHeaderLine(header, "Host", 4, host, hostLen);
    ILibAddHeaderLine(header, "transferMode.dlna.org", 21, "Interactive", 11);

    memset(&dest, 0, sizeof(struct sockaddr_in));
    dest.sin_addr.s_addr = inet_addr(IP);
    dest.sin_port = htons(Port);

    token = ILibWebClient_PipelineRequest(state->Parent->RequestManager, &dest, header, &_RequestResponseCallback, state, NULL);

    if(IP != NULL)
    {
        free(IP);
    }
    if(Path != NULL)
    {
        free(Path);
    }
    free(host);
}
DH_TransferStatus DHC_IssueRequestAndSave(ILibWebClient_RequestManager request_manager, ILibThreadPool pool, const char *file_path, long append_flag, const char *target_uri, enum DH_TransferModes requestedTransferMode, void* user_obj, DHC_OnResponseDone callback_response)
{
	DH_TransferStatus RetVal = NULL;
	char *IP, *Path;
	unsigned short Port;
	struct sockaddr_in dest;
	char *host;
	int hostLen;

	struct packetheader *req;
	FILE *f;
	struct DHC_Data *data;
	ILibReaderWriterLock rwLock = (ILibReaderWriterLock)ILibWebClient_GetUser(request_manager);

	if(rwLock==NULL)
	{
		rwLock = ILibReaderWriterLock_CreateEx(ILibWebClient_GetChain(request_manager));
		ILibWebClient_SetUser(request_manager,rwLock);
	}
	
	memset(&dest,0,sizeof(struct sockaddr_in));

	if(append_flag==0)
	{
		f = fopen(file_path,"wb");
	}
	else 
	{
		f = fopen(file_path,"r+b");
	}
	
	if(f!=NULL)
	{
		data = (struct DHC_Data*)malloc(sizeof(struct DHC_Data));
		memset(data,0,sizeof(struct DHC_Data));

		data->TransferMode = requestedTransferMode;

		data->f = f;
		data->manager = request_manager;
		data->Callback = callback_response;
		data->pool = pool;
		data->user = user_obj;
		data->TransferStatus = DH_CreateNewTransferStatus();
		RetVal = data->TransferStatus;
		data->rwLock = rwLock;

		req = ILibCreateEmptyPacket();
		ILibSetVersion(req,"1.1",3);

		ILibParseUri((char*)target_uri,&IP,&Port,&Path);
		dest.sin_addr.s_addr = inet_addr(IP);
		dest.sin_port = htons(Port);

		host = (char*)malloc((int)strlen(IP)+10);
		hostLen = sprintf(host,"%s:%u",IP,Port);

		ILibAddHeaderLine(req,"Host",4,host,hostLen);
		ILibSetDirective(req,"GET",3,Path,(int)strlen(Path));

		//
		// Look at the append_flag
		//
		if(append_flag==-1)
		{
			//
			// Move to the end of the file
			//
			fseek(f,0,SEEK_END);
			append_flag = ftell(f);
		}
		if(append_flag>0)
		{
			if(fseek(f,append_flag,SEEK_SET)!=0)
			{
				fseek(f,0,SEEK_END);
				append_flag = ftell(f);
			}
			data->StartPosition = append_flag;
		}
		if(requestedTransferMode!=DH_TransferMode_Unspecified)
		{
			DH_AddHeader_transferMode(req,requestedTransferMode);
		}

		data->ActualPacket = req;
		req = ILibCreateEmptyPacket();
		ILibSetVersion(req,"1.1",3);
		ILibAddHeaderLine(req,"Host",4,host,hostLen);
		ILibSetDirective(req,"HEAD",4,Path,(int)strlen(Path));
			//
			// Choose a transfer mode that is supported
			// determine if Range is supported
			//
			ILibAddHeaderLine(req,"getcontentFeatures.dlna.org",27,"1",1);

		ILibReaderWriterLock_WriteLock(rwLock);
		switch(data->TransferMode)
		{
			case DH_TransferMode_Bulk:
				ILibWebClient_SetQosForNextRequest(data->manager,ILibAsyncSocket_QOS_BACKGROUND);
				break;
			case DH_TransferMode_Streaming:
				ILibWebClient_SetQosForNextRequest(data->manager,ILibAsyncSocket_QOS_AUDIO_VIDEO);
				break;
		}
		data->TransferStatus->RequestToken = data->token = ILibWebClient_PipelineRequest(request_manager,&dest,req,&DH_RequestResponse,data,NULL);
		ILibReaderWriterLock_WriteUnLock(rwLock);

		free(host);
		free(IP);
		free(Path);
	}
	return(RetVal);
}
void DH_RequestResponse(ILibWebClient_StateObject WebStateObject,int InterruptFlag,struct packetheader *header,char *bodyBuffer,int *beginPointer,int endPointer,int done,void *user1,void *user2,int *PAUSE)
{
	struct DHC_Data *data = (struct DHC_Data*)user1;
	enum DHC_Errors status;
	void *Abort = NULL;
	char *rangeResult;
	struct parser_result *pr;
	long total;
	char *contentFeatures;
	struct DLNAProtocolInfo *pi;

	ILibReaderWriterLock rwLock = NULL;
	struct packetheader *GetRequest = NULL;
	struct sockaddr_in dest;

	int needToIssueRange = 0;
	int needToIssueRealRequest = 0;
	int MustNotResume = 0;
	struct packetheader *req;
	char *temp;

	if(data==NULL)
	{
		//
		// We appeared to be in the wrong state, most likely received
		// some bad responses, so if we ignore it, we should recover.
		//
		return;
	}

	if((header==NULL && done!=0) || (header!=NULL && header->StatusCode!=200 && header->StatusCode!=206 && done!=0))
	{
		fclose(data->f);
		if(header==NULL)
		{
			status = DHC_ERRORS_CONNECTION_FAILED_OR_ABORTED;
		}
		else
		{
			status = DHC_ERRORS_HTTP;
		}

		if(data->Callback!=NULL)
		{
			if(header!=NULL)
			{
				header->StatusData[header->StatusDataLength]=0;
			}
			data->Callback(data->TransferStatus, status, header==NULL?0:header->StatusCode, header==NULL?NULL:header->StatusData,data->user);
		}
		DH_DestroyTransferStatus(data->TransferStatus);
		if(data->ActualPacket!=NULL)
		{
			ILibDestructPacket(data->ActualPacket);
		}
		free(data);
		ILibWebClient_ResetUserObjects(WebStateObject,NULL, NULL);
	}
	else if(header!=NULL && (header->StatusCode==200 || header->StatusCode==206))
	{
		if(data->ActualPacket!=NULL)
		{
			if(data->DoneProcessingContentFeatures==0)
			{
				data->DoneProcessingContentFeatures = 1;

				//
				// Determine if Range is supported, then do another Head Range Request
				//
				if(data->TransferStatus->Reserved4!=0 && data->TransferStatus->RequestToken!=NULL)
				{
					//
					// Abort... Nothing really to do, because at this point we already finished.
					// Only thing to do, is to not actually issue the request.
					//
					data->TransferStatus->RequestToken = NULL;
				}
				else
				{

					//
					// Transfer Mode wasn't specified
					//
					contentFeatures = ILibGetHeaderLine(header,"contentFeatures.dlna.org",24);
					if(contentFeatures!=NULL)
					{
						temp = ILibString_Cat("http-get:*:*:",13,contentFeatures,(int)strlen(contentFeatures));
						pi = DLNAProtocolInfo_Parse(temp,(int)strlen(temp));
						if(pi!=NULL)
						{
							if(pi->TM_B!=0)
							{
								DH_AddHeader_transferMode(data->ActualPacket,DH_TransferMode_Bulk);
								data->TransferMode = DH_TransferMode_Bulk;
							}
							else if(pi->TM_I!=0)
							{
								DH_AddHeader_transferMode(data->ActualPacket,DH_TransferMode_Interactive);
								data->TransferMode = DH_TransferMode_Interactive;
							}
							else if(pi->TM_S!=0)
							{
								DH_AddHeader_transferMode(data->ActualPacket,DH_TransferMode_Streaming);
								data->TransferMode = DH_TransferMode_Streaming;
							}
							needToIssueRange = pi->SupportsByteBasedSeek;
							DLNAProtocolInfo_Destruct(pi);
						}
						free(temp);
					}
					else
					{
						//
						// since the server didn't respond with a DLNA Content Features, then
						// most likely this is a plain Media Server, in which case, if it doesn't support range
						// it won't return an error, and it'll just ignore the header, so we can issue a range
						// request anyways.
						//
						needToIssueRange = 1;
					}
					if(needToIssueRange!=0)
					{
						//
						// Issue a Range Request
						//
						req = ILibCreateEmptyPacket();
						ILibSetVersion(req,"1.1",3);
						ILibAddHeaderLine(req,"Host",4,ILibGetHeaderLine(data->ActualPacket,"Host",4),(int)strlen(ILibGetHeaderLine(data->ActualPacket,"Host",4)));					
						ILibSetDirective(req,"HEAD",4,data->ActualPacket->DirectiveObj,data->ActualPacket->DirectiveObjLength);
						DH_AddHeader_Range(req,0,-1);

						memset(&dest,0,sizeof(struct sockaddr_in));
						dest.sin_family = AF_INET;
						dest.sin_addr.s_addr = header->Source->sin_addr.s_addr;
						dest.sin_port = header->Source->sin_port;

						ILibReaderWriterLock_WriteLock(data->rwLock);
						switch(data->TransferMode)
						{
							case DH_TransferMode_Bulk:
								ILibWebClient_SetQosForNextRequest(data->manager,ILibAsyncSocket_QOS_BACKGROUND);
								break;
							case DH_TransferMode_Streaming:
								ILibWebClient_SetQosForNextRequest(data->manager,ILibAsyncSocket_QOS_AUDIO_VIDEO);
								break;
						}
						data->TransferStatus->RequestToken = data->token = ILibWebClient_PipelineRequest(data->manager,&dest,req,&DH_RequestResponse,data,NULL);
						ILibReaderWriterLock_WriteUnLock(data->rwLock);
					}
					else
					{
						//
						// Range is not supported, so just continue with making the request.
						// However, before we do, since range isn't supported, we need to make
						// sure that we aren't trying to resume.
						MustNotResume = 1;
						needToIssueRealRequest = 1;
					}
				}
			}
			else
			{
				//
				// Process the Range Response
				//
				rangeResult = ILibGetHeaderLine(header,"content-range",13);
				if(rangeResult!=NULL)
				{
					pr = ILibParseString(rangeResult,0,(int)strlen(rangeResult),"/",1);
					total = atol(pr->LastResult->data);
					ILibDestructParserResults(pr);
					total -= data->StartPosition;
					sem_wait(&(data->TransferStatus->syncLock));
					data->TransferStatus->TotalBytesToBeReceived = total;
					sem_post(&(data->TransferStatus->syncLock));
				}
				else
				{
					//
					// We couldn't get a range result, so we need to make sure
					// we don't try to do a resume.
					//
					MustNotResume = 1;
				}

				//
				// Continue with actually making the content request
				//
				needToIssueRealRequest = 1;
			}

			if(needToIssueRealRequest!=0 && !(data->TransferStatus->Reserved4!=0 && data->TransferStatus->RequestToken!=NULL))
			{
				GetRequest = data->ActualPacket;
				data->ActualPacket = NULL;

				rwLock = (ILibReaderWriterLock)ILibWebClient_GetUser(data->manager);
				memset(&dest,0,sizeof(struct sockaddr_in));
	
				dest.sin_family = AF_INET;
				dest.sin_addr.s_addr = header->Source->sin_addr.s_addr;
				dest.sin_port = header->Source->sin_port;

				if(MustNotResume!=0)
				{
					//
					// Range isn't supported, so we must not resume
					//
					if(data->StartPosition!=0)
					{
						data->StartPosition = 0;
						fseek(data->f,0,SEEK_SET);
					}
				}
				else if(data->StartPosition!=0)
				{
					DH_AddHeader_Range(GetRequest,data->StartPosition,-1);
				}

				ILibReaderWriterLock_WriteLock(rwLock);
				switch(data->TransferMode)
				{
					case DH_TransferMode_Bulk:
						ILibWebClient_SetQosForNextRequest(data->manager,ILibAsyncSocket_QOS_BACKGROUND);
						break;
					case DH_TransferMode_Streaming:
						ILibWebClient_SetQosForNextRequest(data->manager,ILibAsyncSocket_QOS_AUDIO_VIDEO);
						break;
				}
				data->TransferStatus->RequestToken = data->token = ILibWebClient_PipelineRequest(data->manager,&dest,GetRequest,&DH_RequestResponse,data,NULL);
				ILibReaderWriterLock_WriteUnLock(rwLock);
			}

			*beginPointer = endPointer; // Don't really need to do this, because it should always be zero
			return;
		}


		data->buffer = bodyBuffer;
		data->bufferLength = endPointer;
		*beginPointer = endPointer;
		data->GotContinue = done;
		if(endPointer!=0 || done)
		{
			*PAUSE = 1;
		}
		if(data->token!=NULL)
		{
			data->webState = ILibWebClient_GetStateObjectFromRequestToken(data->token);
		}
		if(data->TransferStatus->Reserved4!=0 && data->TransferStatus->RequestToken!=NULL)
		{
			//
			// Abort
			//
			Abort = data->TransferStatus->RequestToken;
			data->TransferStatus->RequestToken = NULL;
			ILibWebClient_CancelRequest(Abort);
		}
		else if(data->TransferStatus->RequestToken!=NULL)
		{
			if(endPointer>0 || done)
			{
				ILibThreadPool_QueueUserWorkItem(data->pool,data,&DH_Pool_RequestResponse);
			}
		}
	}
}
Beispiel #4
0
char* _GetTrackMetadata(PlayListManager_S state, int trackNumber, int* offset, int* length)
{
    int trackBase;
    int rangeStart;
    int rangeLength;
    int rangeEnd;
    struct __TMData* data = (struct __TMData*)malloc(sizeof(struct __TMData));
    memset(data, 0, sizeof(struct __TMData));

    data->State = state;

    if(IndexBlocks_GetTrackRangeInfo(state->Blocks, trackNumber, &rangeStart, &rangeLength, &trackBase) == 1)
    {
        char* IP;
        char* Path;
        unsigned short Port;
        char *host;
        int hostLen;
        struct sockaddr_in dest;
        ILibWebClient_RequestToken token;
        char* uri = state->Parent->URI;
        struct packetheader* header = ILibCreateEmptyPacket();
        char rangeVal[64];
        char* metadata = NULL;

        data->LocalTrackNumber = trackNumber - trackBase;
        rangeEnd = rangeStart + rangeLength - 1;
        sprintf(rangeVal, "bytes=%d-%d", rangeStart, rangeEnd);

        ILibParseUri(uri, &IP, &Port, &Path);
        ILibSetVersion(header, "1.1", 3);
        ILibSetDirective(header, "GET", 3, Path, (int)strlen(Path));
        host = (char*)malloc((int)strlen(IP) + 10);
        hostLen = sprintf(host, "%s:%u", IP, Port);
        ILibAddHeaderLine(header, "Host", 4, host, hostLen);
        ILibAddHeaderLine(header, "Range", 5, rangeVal, (int)strlen(rangeVal));
        ILibAddHeaderLine(header, "transferMode.dlna.org", 21, "Interactive", 11);

        memset(&dest, 0, sizeof(struct sockaddr_in));
        dest.sin_addr.s_addr = inet_addr(IP);
        dest.sin_port = htons(Port);

        data->Metadata = (char*)malloc((size_t)rangeLength);
        metadata = data->Metadata;

        sem_init(&data->Sync, 0, 0);

        token = ILibWebClient_PipelineRequest(state->Parent->RequestManager, &dest, header, &_GetMetadataResponseCallback, data, NULL);

        sem_wait(&data->Sync);
        sem_destroy(&data->Sync);

        metadata = data->Metadata;

        free(host);

        free(data);

        FREE(IP);
        FREE(Path);

        if(metadata != NULL)
        {
            int i;
            int found = 0;
            int count = -1;
            int localTrack = trackNumber - trackBase;
            for(i = 0; i < (rangeLength - 5); i++)
            {
                if(memcmp(metadata + i, "<item", (size_t)5) == 0)
                {
                    count++;
                    found = i;
                    if(count == localTrack)
                    {
                        break;
                    }
                }
            }
            if(count < localTrack)
            {
                free(metadata);
                metadata = NULL;
            }
            else
            {
                int i;
                int newFound = 0;

                for(i = 0; i < (rangeLength - found - 6); i++)
                {
                    if(memcmp(metadata + found + i, "</item>", 7) == 0)
                    {
                        newFound = i;
                        break;
                    }
                }
                if(newFound > 0)
                {
                    *offset = found;
                    *length = newFound - found + 7; //found + newFound + 7;
                }
                else
                {
                    free(metadata);
                    return NULL;
                }
            }
        }

        return metadata;
    }

    free(data);

    return NULL;
}