void ILibSSDPClient_OnData(ILibAsyncUDPSocket_SocketModule socketModule,char* buffer, int bufferLength, int remoteInterface, unsigned short remotePort, void *user, void *user2, int *PAUSE)
{
    struct packetheader *packet;
    packet = ILibParsePacketHeader(buffer,0,bufferLength);
    if(packet==NULL) {
        return;
    }

    ILibReadSSDP(packet,remoteInterface,remotePort,(struct SSDPClientModule*)user);
    ILibDestructPacket(packet);
}
int ILibWebServer_StreamHeader(struct ILibWebServer_Session *session, struct packetheader *header)
{
	struct packetheader *hdr = ILibWebClient_GetHeaderFromDataObject(session->Reserved3);
	struct packetheader_field_node *n = header->FirstField;
	char *buffer;
	int bufferLength;
	int RetVal;
	while(n!=NULL)
	{
		if(n->FieldLength==14 && strncasecmp(n->Field,"Content-Length",14)==0)
		{
			break;
		}
		n = n->NextField;
	}

	if(!(hdr->VersionLength==3 && memcmp(hdr->Version,"1.0",3)==0))
	{
		// Remove Content-Length and Chunk it!
		if(n!=NULL)
		{
			n->Field = "Transfer-Encoding";
			n->FieldLength = 17;
			n->FieldData = "chunked";
			n->FieldDataLength = 7;
		}
		else
		{
			ILibAddHeaderLine(header,"Transfer-Encoding",17,"chunked",7);
		}
	}
	else
	{
		// Check to see if they gave us a Content-Length
		if(n==NULL)
		{
			// Must Close Socket when done
			session->Reserved6=1;
		}
	}
	bufferLength = ILibGetRawPacket(header,&buffer);
	RetVal = ILibWebServer_Send_Raw(session,buffer,bufferLength,0,0);
	ILibDestructPacket(header);
	return(RetVal);
}
int ILibWebServer_Send(struct ILibWebServer_Session *session, struct packetheader *packet)
{
	char *buffer;
	int bufferSize;
	int RetVal = 0;

	session->Reserved4=1;
	bufferSize = ILibGetRawPacket(packet,&buffer);

	RetVal = ILibAsyncServerSocket_Send(session->Reserved1,session->Reserved2,buffer,bufferSize,0);
	if(RetVal==0)
	{
		// Completed Send
		RetVal = ILibWebServer_RequestAnswered(session);
	}
	ILibDestructPacket(packet);
	return(RetVal);
}
Beispiel #4
0
void ILibReadSSDP(SOCKET ReadSocket, struct SSDPClientModule *module)
{
	int bytesRead = 0;
	char* buffer = (char*)malloc(4096);
	struct sockaddr_in addr;
	int addrlen = sizeof(struct sockaddr_in);
	struct packetheader *packet;
	struct packetheader_field_node *node;
	struct parser_result* pnode;
	
	char* Location = NULL;
	char* UDN = NULL;
	int Timeout = 0;
	int Alive = 0;
	int OK;
	int rt;
	
	bytesRead = recvfrom(ReadSocket, buffer, 4096, 0, (struct sockaddr *) &addr, &addrlen);
	if(bytesRead<=0) 
	{
		FREE(buffer);
		return;
	}
	packet = ILibParsePacketHeader(buffer,0,bytesRead);
	
	if(packet->Directive==NULL)
	{
		/* M-SEARCH Response */
		if(packet->StatusCode==200)
		{
			node = packet->FirstField;
			while(node!=NULL)
			{
				if(strncasecmp(node->Field,"LOCATION",8)==0)
				{
					Location = (char*)MALLOC(node->FieldDataLength+1);
					memcpy(Location,node->FieldData,node->FieldDataLength);
					Location[node->FieldDataLength] = '\0';
				}
				if(strncasecmp(node->Field,"CACHE-CONTROL",13)==0)
				{
					pnode = ILibParseString(node->FieldData, 0, node->FieldDataLength, "=", 1);
					pnode->LastResult->data[pnode->LastResult->datalength] = '\0';
					Timeout = atoi(pnode->LastResult->data);
					ILibDestructParserResults(pnode);
				}
				if(strncasecmp(node->Field,"USN",3)==0)
				{
					pnode = ILibParseString(node->FieldData, 0, node->FieldDataLength, "::", 2);
					pnode->FirstResult->data[pnode->FirstResult->datalength] = '\0';
					UDN = pnode->FirstResult->data+5;
					ILibDestructParserResults(pnode);
				}
				node = node->NextField;
			}
			if(module->FunctionCallback!=NULL)
			{
				module->FunctionCallback(module,UDN,-1,Location,Timeout,module->Reserved);
			}
			
		}
	}
	else
	{
		/* Notify Packet */
		if(strncasecmp(packet->Directive,"NOTIFY",6)==0)
		{
			OK = 0;
			rt = 0;
			node = packet->FirstField;
			while(node!=NULL)
			{
				node->Field[node->FieldLength] = '\0';
				if(strncasecmp(node->Field,"NT",2)==0 && node->FieldLength==2)
				{
					node->FieldData[node->FieldDataLength] = '\0';
					if(strncasecmp(node->FieldData,module->DeviceURN,module->DeviceURNLength)==0)
					{
						OK = -1;
					}
					else if(strncasecmp(node->FieldData,"upnp:rootdevice",15)==0)
					{
						rt = -1;
					}
					else
					{
						break;
					}
				}
				if(strncasecmp(node->Field,"NTS",3)==0)
				{
					if(strncasecmp(node->FieldData,"ssdp:alive",10)==0)
					{
						Alive = -1;
						rt = 0;
					}
					else
					{
						Alive = 0;
						OK = 0;
					}
				}
				if(strncasecmp(node->Field,"USN",3)==0)
				{
					pnode = ILibParseString(node->FieldData, 0, node->FieldDataLength, "::", 2);
					pnode->FirstResult->data[pnode->FirstResult->datalength] = '\0';
					UDN = pnode->FirstResult->data+5;
					ILibDestructParserResults(pnode);
				}
				if(strncasecmp(node->Field,"LOCATION",8)==0)
				{
					Location = (char*)MALLOC(node->FieldDataLength+1);
					memcpy(Location,node->FieldData,node->FieldDataLength);
					Location[node->FieldDataLength] = '\0';
				}
				if(strncasecmp(node->Field,"CACHE-CONTROL",13)==0)
				{
					pnode = ILibParseString(node->FieldData, 0, node->FieldDataLength, "=", 1);
					pnode->LastResult->data[pnode->LastResult->datalength] = '\0';
					Timeout = atoi(pnode->LastResult->data);
					ILibDestructParserResults(pnode);
				}
				node = node->NextField;
			}
			if((OK!=0 && Alive!=0) || (rt!=0 && Alive==0))
			{
				if(module->FunctionCallback!=NULL)
				{
					module->FunctionCallback(module,UDN,Alive,Location,Timeout,module->Reserved);
				}
			}
		}
	}
	if(Location!=NULL) {FREE(Location);}
	ILibDestructPacket(packet);
	FREE(buffer);
}
void ILibMiniWebServerProcessSocket(struct ILibMWSHTTPReaderObject *Reader)
{
	int bytesReceived;
	int i;
	struct packetheader_field_node *node;
	char* CharStar;
	
	if(Reader->BodySize==0)
	{
		/* Still Reading Headers */
		bytesReceived = recv(Reader->ClientSocket,Reader->Header+Reader->HeaderIndex,2048-Reader->HeaderIndex,0);
		if(bytesReceived==0)
		{
			if(Reader->PacketHeader!=NULL) {ILibDestructPacket(Reader->PacketHeader);}
			if(Reader->Body_MallocSize!=0) {FREE(Reader->Body);}
			Reader->Body = NULL;
			Reader->Body_MallocSize = 0;
			Reader->PacketHeader = NULL;
			closesocket(Reader->ClientSocket);
			Reader->ClientSocket = 0xFFFFFFFF;
			return;
		}
		Reader->HeaderIndex += bytesReceived;
		if(Reader->HeaderIndex>4)
		{
			/* Must have read at least 4 bytes to perform check */
			for(i=0;i<(Reader->HeaderIndex - 3);i++)
			{
				if (Reader->Header[i] == '\r' && Reader->Header[i+1] == '\n' && Reader->Header[i+2] == '\r' && Reader->Header[i+3] == '\n')
				{
					/* Finished Header */
					Reader->PacketHeader = ILibParsePacketHeader(Reader->Header,0,i+4);
					Reader->PacketHeader->ReceivingAddress = Reader->LocalIPAddress;
					Reader->BodySize = -1;
					Reader->Body_Read = 0;
					node = Reader->PacketHeader->FirstField;
					while(node!=NULL)
					{
						if(strncasecmp(node->Field,"CONTENT-LENGTH",14)==0)
						{
							CharStar = (char*)MALLOC(1+node->FieldDataLength);
							memcpy(CharStar,node->FieldData,node->FieldDataLength);
							CharStar[node->FieldDataLength] = '\0';
							Reader->BodySize = atoi(CharStar);
							FREE(CharStar);
							break;
						}
						node = node->NextField;
					}
					if(Reader->BodySize!=-1)
					{
						if(Reader->BodySize!=0)
						{
							Reader->Body = (char*)MALLOC(Reader->BodySize);
							Reader->Body_MallocSize = Reader->BodySize;
						}
						else
						{
							Reader->Body = NULL;
							Reader->Body_MallocSize = 0;
						}
					}
					else
					{
						Reader->Body = (char*)MALLOC(4096);
						Reader->Body_MallocSize = 4096;
					}
					
					if(Reader->HeaderIndex>i+4 && Reader->BodySize!=0)
					{
						/* Part of the body is in here */
						memcpy(Reader->Body,Reader->Header+i+4,Reader->HeaderIndex-(&Reader->Header[i+4]-Reader->Header));
						Reader->Body_BeginPointer = 0;
						Reader->Body_EndPointer = Reader->HeaderIndex-(int)(&Reader->Header[i+4]-Reader->Header);
						Reader->Body_Read = Reader->Body_EndPointer;
						
						if(Reader->BodySize==-1 || Reader->Body_Read>=Reader->BodySize)
						{
							DEBUGSTATEMENT(printf("Close\r\n"));
							Reader->FunctionCallback(Reader,Reader->PacketHeader,Reader->Body,&Reader->Body_BeginPointer,Reader->Body_EndPointer - Reader->Body_BeginPointer,-1,Reader->user);
							
							while(Reader->Body_BeginPointer!=Reader->Body_EndPointer && Reader->Body_BeginPointer!=0)
							{
								memcpy(Reader->Body,Reader->Body+Reader->Body_BeginPointer,Reader->Body_EndPointer-Reader->Body_BeginPointer);
								Reader->Body_EndPointer = Reader->Body_EndPointer-Reader->Body_BeginPointer;
								Reader->Body_BeginPointer = 0;
								Reader->FunctionCallback(Reader,Reader->PacketHeader,Reader->Body,&Reader->Body_BeginPointer,Reader->Body_EndPointer,-1,Reader->user);
							}
							
							if(Reader->PacketHeader!=NULL) {ILibDestructPacket(Reader->PacketHeader);}
							if(Reader->Body_MallocSize!=0) {FREE(Reader->Body);}
							Reader->Body = NULL;
							Reader->Body_MallocSize = 0;
							Reader->PacketHeader = NULL;
							closesocket(Reader->ClientSocket);
							Reader->ClientSocket = 0xFFFFFFFF;
						}
						else
						{
							Reader->FunctionCallback(Reader,Reader->PacketHeader,Reader->Body,&Reader->Body_BeginPointer,Reader->Body_EndPointer - Reader->Body_BeginPointer,0,Reader->user);
							while(Reader->Body_BeginPointer!=Reader->Body_EndPointer && Reader->Body_BeginPointer!=0)
							{
								memcpy(Reader->Body,Reader->Body+Reader->Body_BeginPointer,Reader->Body_EndPointer-Reader->Body_BeginPointer);
								Reader->Body_EndPointer = Reader->Body_EndPointer-Reader->Body_BeginPointer;
								Reader->Body_BeginPointer = 0;
								Reader->FunctionCallback(Reader,Reader->PacketHeader,Reader->Body,&Reader->Body_BeginPointer,Reader->Body_EndPointer,0,Reader->user);
							}
						}
					}
					else
					{
						/* There is no body, but the packet is here */
						Reader->Body_BeginPointer = 0;
						Reader->Body_EndPointer = 0;
						
						if(Reader->BodySize<=0)
						{
							Reader->FunctionCallback(Reader,Reader->PacketHeader,NULL,&Reader->Body_BeginPointer,0,-1,Reader->user);
							if(Reader->PacketHeader!=NULL) {ILibDestructPacket(Reader->PacketHeader);}
							if(Reader->Body_MallocSize!=0) {FREE(Reader->Body);}
							Reader->Body = NULL;
							Reader->Body_MallocSize = 0;
							Reader->PacketHeader = NULL;
							closesocket(Reader->ClientSocket);
							Reader->ClientSocket = 0xFFFFFFFF;
						}
						else
						{
							Reader->FunctionCallback(Reader,Reader->PacketHeader,NULL,&Reader->Body_BeginPointer,0,0,Reader->user);
						}
					}
					break;
				}
			}
		}
	}
	else
	{
		/* Reading Body Only */
		if(Reader->Body_BeginPointer == Reader->Body_EndPointer)
		{
			Reader->Body_BeginPointer = 0;
			Reader->Body_EndPointer = 0;
		}
		else
		{
			if(Reader->Body_BeginPointer!=0)
			{
				Reader->Body_EndPointer = Reader->Body_BeginPointer;
			}
		}
		
		
		if(Reader->Body_EndPointer == Reader->Body_MallocSize)
		{
			Reader->Body_MallocSize += 4096;
			Reader->Body = (char*)realloc(Reader->Body,Reader->Body_MallocSize);
		}
		
		bytesReceived = recv(Reader->ClientSocket,Reader->Body+Reader->Body_EndPointer,Reader->Body_MallocSize-Reader->Body_EndPointer,0);
		Reader->Body_EndPointer += bytesReceived;
		Reader->Body_Read += bytesReceived;
		
		Reader->FunctionCallback(Reader, Reader->PacketHeader, Reader->Body+Reader->Body_BeginPointer, &Reader->Body_BeginPointer, Reader->Body_EndPointer - Reader->Body_BeginPointer, 0, Reader->user);
		while(Reader->Body_BeginPointer!=Reader->Body_EndPointer && Reader->Body_BeginPointer!=0)
		{
			memcpy(Reader->Body,Reader->Body+Reader->Body_BeginPointer,Reader->Body_EndPointer-Reader->Body_BeginPointer);
			Reader->Body_EndPointer = Reader->Body_EndPointer-Reader->Body_BeginPointer;
			Reader->Body_BeginPointer = 0;
			Reader->FunctionCallback(Reader,Reader->PacketHeader,Reader->Body,&Reader->Body_BeginPointer,Reader->Body_EndPointer,0,Reader->user);				
		}
		
		if((Reader->BodySize!=-1 && Reader->Body_Read>=Reader->BodySize)||(bytesReceived==0))
		{
			if(Reader->Body_BeginPointer == Reader->Body_EndPointer)
			{
				Reader->Body_BeginPointer = 0;
				Reader->Body_EndPointer = 0;
			}
			Reader->FunctionCallback(Reader, Reader->PacketHeader, Reader->Body, &Reader->Body_BeginPointer, Reader->Body_EndPointer, -1,Reader->user);
			if(Reader->PacketHeader!=NULL) {ILibDestructPacket(Reader->PacketHeader);}
			if(Reader->Body_MallocSize!=0) {FREE(Reader->Body);}
			Reader->Body = NULL;
			Reader->Body_MallocSize = 0;
			Reader->PacketHeader = NULL;
			closesocket(Reader->ClientSocket);
			Reader->ClientSocket = 0xFFFFFFFF;
		}
		
		if(Reader->Body_BeginPointer==Reader->Body_EndPointer)
		{
			Reader->Body_BeginPointer = 0;
			Reader->Body_EndPointer = 0;
		}
	}
}
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);
			}
		}
	}
}
DH_TransferStatus DHS_RespondWithLocalFile(struct ILibWebServer_Session *session, ILibThreadPool pool, struct packetheader *header, size_t buffer_size, const char *file_name, unsigned int supported_transfer_mode, const char *mime_type, const char *content_features, const char* ifo_uri, void *user_obj, DHS_OnResponseDone callback_response)
{
    DH_TransferStatus retval = NULL;
    FILE *f;
    struct DH_Data *data = NULL;
    struct packetheader *resp = NULL;
    char *ifo, *cf = NULL;
    long RangeStart,RangeLength,FileLength;
    char len[255];
    enum ILibWebClient_Range_Result RangeResult = 0;
    enum DH_TransferModes transferMode;

    if(session->done==0)
    {
        //
        // If the get request wasn't completely received yet, then we don't need to do anything yet
        //
        return NULL;
    }

    f = fopen(file_name,"rb");
    if(f!=NULL)
    {
        data = (struct DH_Data*)malloc(sizeof(struct DH_Data));
        memset(data,0,sizeof(struct DH_Data));

        resp = ILibCreateEmptyPacket();
        ILibSetVersion(resp,"1.1",3);
        
        fseek(f,0,SEEK_END);
        FileLength = ftell(f);
        fseek(f,0,SEEK_SET);

        cf = ILibGetHeaderLine(header,"getcontentFeatures.dlna.org",27);

        if(cf!= NULL && memcmp(cf, "1", 1)!=0)
        {
            ILibWebServer_Send_Raw(session,"HTTP/1.1 400 Bad Request\r\n\r\n",28,ILibAsyncSocket_MemoryOwnership_STATIC,1);
            fclose(f);
            free(data);
            ILibDestructPacket(resp);
            return(NULL);
        }

        transferMode = DH_GetRequestedTransferMode(header);

        if(
            ((transferMode == DH_TransferMode_Bulk) ||
             (transferMode == DH_TransferMode_Interactive))
            &&
            ((ILibGetHeaderLine(header,"TimeSeekRange.dlna.org",22)!=NULL) ||
             (ILibGetHeaderLine(header,"PlaySpeed.dlna.org",18)!=NULL) ||
             (ILibGetHeaderLine(header,"realTimeInfo.dlna.org",21)!=NULL)
            )
        )
        {
            ILibWebServer_Send_Raw(session,"HTTP/1.1 400 Bad Request\r\n\r\n",28,ILibAsyncSocket_MemoryOwnership_STATIC,1);
            fclose(f);
            free(data);
            ILibDestructPacket(resp);
            return(NULL);            
        }

        if(ILibGetHeaderLine(header,"Range",5)!=NULL)
        {
            RangeResult = ILibWebClient_Parse_Range(ILibGetHeaderLine(header,"Range",5),&RangeStart,&RangeLength,FileLength);
            switch(RangeResult)
            {
                case ILibWebClient_Range_Result_OK:
                    fseek(f,RangeStart,SEEK_SET);
                    data->BytesLeft = RangeLength;
                    ILibSetStatusCode(resp,206,"Partial Content",15);
                    DH_AddHeader_ContentRange(resp,RangeStart,(RangeStart+RangeLength)-1,FileLength);
                    break;
                case ILibWebClient_Range_Result_INVALID_RANGE:                                 
                    ILibWebServer_Send_Raw(session,"HTTP/1.1 416 Invalid Range\r\n\r\n",30,ILibAsyncSocket_MemoryOwnership_STATIC,1);
                    fclose(f);
                    free(data);
                    ILibDestructPacket(resp);
                    return(NULL);
                    break;
                case ILibWebClient_Range_Result_BAD_REQUEST:
                    ILibWebServer_Send_Raw(session,"HTTP/1.1 400 Bad Request\r\n\r\n",28,ILibAsyncSocket_MemoryOwnership_STATIC,1);
                    fclose(f);
                    free(data);
                    ILibDestructPacket(resp);
                    return(NULL);
                    break;
            }
        }
        else if(ILibGetHeaderLine(header,"TimeSeekRange.dlna.org",22)!=NULL)
        {
            ILibWebServer_Send_Raw(session,"HTTP/1.1 406 Time-based seek not supported\r\n\r\n",46,ILibAsyncSocket_MemoryOwnership_STATIC,1);
            fclose(f);
            free(data);
            ILibDestructPacket(resp);
            return(NULL);
        }
        else if(ILibGetHeaderLine(header,"PlaySpeed.dlna.org",18)!=NULL)
        {
            ILibWebServer_Send_Raw(session,"HTTP/1.1 406 PlaySpeeds not supported\r\n\r\n",41,ILibAsyncSocket_MemoryOwnership_STATIC,1);
            fclose(f);
            free(data);
            ILibDestructPacket(resp);
            return(NULL);
        }
        else
        {
            ILibSetStatusCode(resp,200,"OK",2);
            data->BytesLeft = FileLength;
            sprintf(len,"%ld",data->BytesLeft);
            ILibAddHeaderLine(resp,"Content-Length",14,len,(int)strlen(len));
            ILibAddHeaderLine(resp,"Accept-Ranges",13,"bytes",5);
        }

        if(transferMode == DH_TransferMode_Unspecified && mime_type != NULL)    
        {
            if(ILibString_StartsWith(mime_type, (int) strlen(mime_type),  "video/", 6) != 0)
            {
                DH_AddHeader_transferMode(resp, DH_TransferMode_Streaming);    
            }
            else if(ILibString_StartsWith(mime_type, (int) strlen(mime_type),  "audio/", 6) != 0)
            {
                DH_AddHeader_transferMode(resp, DH_TransferMode_Streaming);    
            }
            else if(ILibString_StartsWith(mime_type, (int) strlen(mime_type),  "image/", 6) != 0)
            {
                DH_AddHeader_transferMode(resp, DH_TransferMode_Interactive);    
            }
        }
        else if(!(transferMode & supported_transfer_mode))
        {
            //
            // Specified transfer mode is not supported
            //
            ILibWebServer_Send_Raw(session,"HTTP/1.1 406 Not Acceptable\r\n\r\n",31,ILibAsyncSocket_MemoryOwnership_STATIC,1);
            fclose(f);
            free(data);
            ILibDestructPacket(resp);
            return(NULL);
        }
        else
        {
            DH_AddHeader_transferMode(resp,transferMode);    
        }

        data->callback_response = callback_response;
        data->f = f;
        data->header = header;
        data->session = session;
        data->pool = pool;
        data->TransferStatus = retval = DH_CreateNewTransferStatus();
        data->TransferStatus->TotalBytesToBeSent = data->BytesLeft;
        data->user_object = user_obj;
        retval->ServerSession = session;
        session->OnDisconnect = &DH_Disconnect;
        
        if(content_features!=NULL)
        {
            ILibAddHeaderLine(resp,"contentFeatures.dlna.org",24,(char*) content_features,(int)strlen(content_features));
        }
        if(mime_type!=NULL)
        {
            ILibAddHeaderLine(resp,"Content-Type",12,(char*)mime_type,(int)strlen(mime_type));
        }
        else
        {
            ILibAddHeaderLine(resp,"Content-Type",12,(char*)DHS_DEFAULT_MIMETYPE,(int)strlen(DHS_DEFAULT_MIMETYPE));
        }
        if(ifo_uri!=NULL)
        {
            ifo = (char*)malloc((int)strlen(ifo_uri)+25);
            sprintf(ifo,"ifoFileURI.dlna.org=\"%s\"",ifo_uri);
            ILibAddHeaderLine(resp,"PRAGMA",6,ifo,(int)strlen(ifo));
            free(ifo);
        }

        ILibWebServer_StreamHeader(session,resp);

        if(header->DirectiveLength==4 && strncasecmp(header->Directive,"HEAD",4)==0)
        {
            ILibWebServer_StreamBody(session,NULL,0,ILibAsyncSocket_MemoryOwnership_STATIC,1);
            fclose(data->f);
            data->f = NULL;
            DH_DestroyTransferStatus(data->TransferStatus);
            free(data);
            session->OnDisconnect = NULL;
            return(NULL);
        }
        else
        {
            lock_init(&(data->SendStatusLock),0,1);
            ILibThreadPool_QueueUserWorkItem(pool,data,&DH_Pool);
        }
    }
    else
    {
        //
        // Error opening file
        //
        ILibWebServer_Send_Raw(session,"HTTP/1.1 404 File Not Found\r\n\r\n",31,ILibAsyncSocket_MemoryOwnership_STATIC,1);
    }
    return retval;
}