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_IssuePostRequestFromFile(ILibWebClient_RequestManager request_manager, ILibThreadPool pool, const char* target_uri, const char *file_path, int resume_pos, enum DH_TransferModes requestedTransferMode, const char *mime_type, const char *content_features, void* user_obj, DHC_OnResponseDone callback_response) { DH_TransferStatus RetVal; struct packetheader *h; struct sockaddr_in addr; char host[22]; struct DHC_Data *data = NULL; FILE *f; long fileLength; char *Ip; char *Path; unsigned short Port; ILibReaderWriterLock rwLock = (ILibReaderWriterLock)ILibWebClient_GetUser(request_manager); if(rwLock==NULL) { rwLock = ILibReaderWriterLock_CreateEx(ILibWebClient_GetChain(request_manager)); ILibWebClient_SetUser(request_manager,rwLock); } f = fopen(file_path,"rb"); if(f==NULL) { // // Couldn't open file // return(NULL); } data = (struct DHC_Data*)malloc(sizeof(struct DHC_Data)); memset(data,0,sizeof(struct DHC_Data)); data->TransferMode = requestedTransferMode; data->f = f; data->user = user_obj; data->Callback = callback_response; data->pool = pool; data->buffer = (char*)malloc(DHC_READ_BLOCK_SIZE); data->bufferLength = DHC_READ_BLOCK_SIZE; RetVal = data->TransferStatus = DH_CreateNewTransferStatus(); data->rwLock = rwLock; ILibParseUri((char*)target_uri,&Ip,&Port,&Path); memset(&addr,0,sizeof(struct sockaddr_in)); addr.sin_addr.s_addr = inet_addr(Ip); addr.sin_port = htons(Port); sprintf(host,"%s:%u",Ip,Port); h = ILibCreateEmptyPacket(); ILibSetVersion(h,"1.1",3); ILibSetDirective(h,"POST",4,Path,(int)strlen(Path)); ILibAddHeaderLine(h,"Host",4,host,(int)strlen(host)); ILibAddHeaderLine(h,"Expect",6,"100-Continue",12); if(resume_pos>0) { fseek(f,0,SEEK_END); fileLength = ftell(f); fseek(f,(long)resume_pos,SEEK_SET); DH_AddHeader_ContentRange(h,resume_pos,fileLength-1,fileLength); } if(requestedTransferMode!=DH_TransferMode_Unspecified) { DH_AddHeader_transferMode(h, DH_TransferMode_Bulk); } if(content_features!=NULL) { ILibAddHeaderLine(h,"contentFeatures.dlna.org",24,(char*) content_features,(int)strlen(content_features)); } if(mime_type!=NULL) { ILibAddHeaderLine(h,"Content-Type",12,(char*)mime_type,(int)strlen(mime_type)); } ILibReaderWriterLock_WriteLock(rwLock); switch(data->TransferMode) { case DH_TransferMode_Bulk: ILibWebClient_SetQosForNextRequest(request_manager,ILibAsyncSocket_QOS_BACKGROUND); break; case DH_TransferMode_Streaming: ILibWebClient_SetQosForNextRequest(request_manager,ILibAsyncSocket_QOS_AUDIO_VIDEO); break; } data->token = data->TransferStatus->RequestToken = ILibWebClient_PipelineStreamedRequest(request_manager,&addr,h,&DHC_OnResponse,&DHC_OnSendOK,NULL,data); ILibReaderWriterLock_WriteUnLock(rwLock); free(Ip); free(Path); return(RetVal); }
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); } } } }
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; }