1 #include "multirat_conf.h"
2 #include "multirat_process.h"
3 #include "multirat_libapi.h"
4 #include "multirat_range_request_thread.h"
5 #include "multirat_connection.h"
6 #include "multirat_block_manager.h"
7 #include "multirat_data_buffer.h"
8 #include "multirat_decode_http.h"
12 void range_request_thread_init(RangeRequestThread *rrthread, SmartBondingData *SBData)
14 MultiSocket *mSocket = SBData->msocket;
15 int8 *default_iname = DEFAULT_INTERFACE;
16 uint32 ifaceidx = rrthread->threadId;
18 rrthread->pThreadId = 0;
19 rrthread->socketId = 0;
20 rrthread->minBlockSize = MIN_BLOCK_SIZE;
21 rrthread->maxBlockSize = MAX_BLOCK_SIZE;
22 rrthread->speedTimeOut = SPEED_TIMEOUT;
23 rrthread->blockForSpeed = BLOCK_SIZE_SPEED;
24 rrthread->minDataForSpeed = MIN_DATA_FOR_SPEED;
25 rrthread->compRspLen = mSocket->compRspLen;
26 rrthread->contRngLen = SBData->resp.instanceSize;
27 rrthread->commBuffer = mSocket->commBuffer;
28 rrthread->conn = mSocket->conn;
29 rrthread->blockMgr = mSocket->blockMgr;
30 rrthread->compRspRcvdFlag = &mSocket->compRspRcvdFlag;
31 rrthread->firstRngStatus = FIRST_RSP_STATUS_PENDING;
33 if (0 == strncasecmp(default_iname, LTE, strlen(LTE)))
36 * thread 0 should get interface LTE (1)
37 * and thread 1 should get interface WIFI(0)
39 ifaceidx = (ifaceidx + 1) % 2;
42 rrthread->reqHeaders = SBData->req.request[ifaceidx] ;
43 rrthread->headerLen = strlen(SBData->req.request[ifaceidx]);
46 if(SBData->req.req_buff_wo_range != NULL)
48 rrthread->reqHeaders = SBData->req.req_buff_wo_range;
49 rrthread->headerLen = SBData->req.req_wo_len;
53 rrthread->reqHeaders = SBData->req.req_buff;
54 rrthread->headerLen = SBData->req.reqLen;
57 rrthread->SBData = SBData;
59 }/* End of RangeRequestThread() */
61 uint32 range_request_thread_start(RangeRequestThread *rrthread)
63 if(0 != pthread_create(&rrthread->pThreadId, NULL,
64 range_request_thread_rngreq_thread_callback, (void *)rrthread))
66 TIZEN_LOGD("Error !!! while creating range thread");
67 range_request_thread_exit(rrthread);
71 TIZEN_LOGD("thread ID %d Rangethread started", rrthread->threadId);
75 void *range_request_thread_rngreq_thread_callback(void *pArg)
77 RangeRequestThread *rngReq = ((RangeRequestThread*)pArg);
78 range_request_thread_run(rngReq);
83 int range_request_thread_handleIOExp(RangeRequestThread *rrthread, uint32 *ifCount , int iptype)
85 /* Check if interface is available */
86 if (!connection_is_ifaceup(rrthread->threadId, rrthread->conn->ifaceInfo,iptype))
88 if((rrthread->firstRngStatus == FIRST_RSP_STATUS_PENDING) && (*ifCount++ > 2))
90 rrthread->firstRngStatus = FIRST_RSP_STATUS_FAILED;
91 *(rrthread->compRspRcvdFlag) = 0;
92 TIZEN_LOGD("First Response Failed for ThreadId %d\n",rrthread->threadId);
95 uint32 otherId = GET_OTHER_THREAD_ID(rrthread->threadId);
96 if((rrthread->blockMgr->threadState[otherId] == STATE_THREAD_STOPPED) &&
97 (connection_is_ifaceup(otherId, rrthread->conn->ifaceInfo,iptype)))
99 TIZEN_LOGD("Swapping thread as other thread is stopped \n");
100 rrthread->blockMgr->threadState[rrthread->threadId] = STATE_THREAD_STOPPED;
101 rrthread->threadId = otherId;
102 rrthread->blockMgr->threadState[otherId] = STATE_THREAD_RUNNING;
103 rrthread->blockMgr->noOfIOExp[otherId] = 0;
107 return THREAD_CONTINUE;
110 /* IOException case */
111 connect_server(rrthread);
112 TIZEN_LOGD("thread ID %d rrthread->socketId %d\n",rrthread->threadId,rrthread->socketId);
113 if ((0 == rrthread->socketId) || (!(*(rrthread->compRspRcvdFlag))))
115 if (rrthread->firstRngStatus == FIRST_RSP_STATUS_PENDING)
117 rrthread->firstRngStatus = FIRST_RSP_STATUS_FAILED;
118 TIZEN_LOGD("First Response failed\n");;
119 /* server doest support Range Request */
120 /* Exit all threads */
121 *(rrthread->compRspRcvdFlag) = 0;
122 TIZEN_LOGD("First Response Failed for ThreadId %d\n",rrthread->threadId);
127 return THREAD_CONTINUE;
133 void range_request_thread_handleSendFailCase(RangeRequestThread *rrthread, int32 chunkId)
135 TIZEN_LOGD("Thread with %d got Exception during send",rrthread->threadId);
137 if (rrthread->firstRngStatus == FIRST_RSP_STATUS_PENDING)
139 rrthread->firstRngStatus = FIRST_RSP_STATUS_FAILED;
140 TIZEN_LOGD("First Response failed\n");;
141 /* server doest support Range Request */
142 /* Exit all threads */
143 *(rrthread->compRspRcvdFlag) = 0;
146 if (rrthread->socketId != 0)
148 close(rrthread->socketId);
149 rrthread->socketId = 0;
151 if ((chunkId != -1) && (DATA_BUFFER_GET_THREAD_ID(rrthread->commBuffer + chunkId) == rrthread->threadId))
153 /* IO Exception inform Block manager */
154 block_manager_io_exception(rrthread->threadId, chunkId, rrthread->blockMgr);
155 DATA_BUFFER_SET_STATE(STATE_BLOCKED, (rrthread->commBuffer + chunkId));
159 void range_request_thread_run(RangeRequestThread *rrthread)
163 int32 blockOffset = 0;
164 int32 headerRcvd = B_FALSE;
165 int32 IOException = B_TRUE;
169 uint32 rngRspLen = 0;
170 uint32 connClose = 0;
171 uint32 waitThread = B_FALSE;
172 uint32 iface_check_count = 0;
173 uint32 minBlockLen = rrthread->minBlockSize;
175 uint64 startTime = 0;
176 uint64 currChunkLen = 0;
177 uint64 chunkStrTime = 0;
178 uint64 temp_startTime = 0;
179 int64 chunkInfo[CHUNK_INFO_SIZE] = {0};
180 int8 *newRequest = NULL;
181 //int8 *chunkBuff = NULL;
182 int8 tempBuff[MAX_BLOCK_SIZE] = {0};
183 DataBuffer *currChunk = NULL;
185 newRequest = (char*)malloc(rrthread->headerLen + MAX_RANGE_FIELD_LEN);
186 if(NULL == newRequest)
190 while (*(rrthread->compRspRcvdFlag))
192 /* Check the current state of thread */
193 if(rrthread->blockMgr->threadState[rrthread->threadId] == STATE_THREAD_STOPPED)
195 TIZEN_LOGD("Thread %d stopped state exiting\n",rrthread->threadId);
199 /* Get the status of commonBuffer (memory availability) */
200 if (1 == block_manager_check_buffer_status(rrthread->blockMgr))
206 if(waitThread == B_TRUE)
208 retval = block_manager_checkAllBufferStatus(rrthread->blockMgr,rrthread->threadId);
209 if(THREAD_WAIT == retval)
211 /* Other thread is downloading this thread has to wait */
215 else if (THREAD_EXIT == retval)
217 /* Wait thread should exit as other thread has completed */
218 TIZEN_LOGD("Download Complete by other thread Exiting Thread Id %d",rrthread->threadId);
221 else if(THREAD_CONTINUE == retval)
223 /* Other thread has chunk is blocked */
224 TIZEN_LOGD("waiting thread need to download chunk", rrthread->threadId);
225 waitThread = B_FALSE;
229 if (IOException == B_TRUE)
232 if(iface_check_count > rrthread->SBData->timeout)
234 rrthread->blockMgr->threadState[rrthread->threadId] = STATE_THREAD_STOPPED;
235 TIZEN_LOGD("Stopping Thread %d as Interaface is Down For Long Time");
238 retval = range_request_thread_handleIOExp(rrthread,&ifCount,rrthread->SBData->conn.ip_family);
239 if(THREAD_EXIT == retval)
243 else if (THREAD_CONTINUE == retval)
249 iface_check_count = 0;
250 IOException = B_FALSE;
252 memset(chunkInfo,0,CHUNK_INFO_SIZE*sizeof(int64));
254 /* Block Manager for next block */
255 block_manager_get_next_chunk(chunkInfo, rrthread->threadId,
256 rrthread->socketId, rrthread->blockMgr);
258 currChunkLen = chunkInfo[1] - chunkInfo[0] + 1;
259 chunkId = chunkInfo[2];
260 TIZEN_LOGD("Chunk Id %d Thread Id %d RANGE START %dRANGE END %d\n",
261 chunkId, rrthread->threadId, chunkInfo[0] ,chunkInfo[1]);
265 /* This condition is for keep-alive case */
270 currChunk = rrthread->commBuffer + chunkId;
271 memset(newRequest,0,(rrthread->headerLen + MAX_RANGE_FIELD_LEN));
272 reqLen = range_request_thread_rebuild_req(newRequest, chunkInfo, rrthread);
274 startTime = get_time_in_microsec();
276 if (-1 == send(rrthread->socketId, newRequest, reqLen, 0))
278 range_request_thread_handleSendFailCase(rrthread,chunkId);
279 IOException = B_TRUE;
284 headerRcvd = B_FALSE;
286 //chunkBuff = DATA_BUFFER_GET_BUFFER(currChunk);
288 while (rngRspLen != currChunkLen)
290 blockLen = MIN(minBlockLen, (currChunkLen-rngRspLen));
291 minBlockLen = MIN(rrthread->maxBlockSize, (minBlockLen<<1));
293 memset(tempBuff,0,MAX_BLOCK_SIZE);
296 retval = range_request_recv_rng_rsp_headers(rrthread->socketId, blockLen, TIME_OUT_MILLISEC,
297 rrthread->contRngLen, currChunkLen, &blockOffset, tempBuff, rrthread->compRspLen, &connClose);
298 if (HTTP_RSP_DECODING_SUCCESS != retval)
300 if (rrthread->firstRngStatus == FIRST_RSP_STATUS_PENDING)
302 TIZEN_LOGD("First Response failed\n");;
303 /* server doest support Range Request */
304 /* Exit all threads */
305 *(rrthread->compRspRcvdFlag) = 0;
306 rrthread->firstRngStatus = FIRST_RSP_STATUS_FAILED;
311 IOException = B_TRUE;
312 TIZEN_LOGD("Thread %d got Exception during recv headers",rrthread->threadId);
318 endTime = get_time_in_microsec();
319 temp_startTime = endTime;
320 chunkStrTime = endTime;
321 uint64 headSpeed = (endTime-startTime)/1000;
323 TIZEN_D_LOGD("Thread %d Header speed %d\n",rrthread->threadId,headSpeed);
324 SET_HEAD_SPEED(rrthread->threadId,headSpeed,rrthread->blockMgr);
327 /* Success response received from server */
328 if (rrthread->firstRngStatus == FIRST_RSP_STATUS_PENDING)
330 rrthread->firstRngStatus = FIRST_RSP_STATUS_SUCCESS;
331 TIZEN_LOGD("First Response Success\n");
335 data_buffer_add(blockOffset, rrthread->threadId, tempBuff, currChunk);
336 rngRspLen = rngRspLen + blockOffset;
343 uint32 currOffset = 0;
344 uint32 prevOffset = 0;
345 uint32 diffOffset = 0;
346 uint32 temp_check = 0;
352 uint64 blockStrtTime = 0;
353 uint64 blockEndTime = 0;
354 int8 *block = tempBuff;
356 prevTime = get_time_in_microsec();
357 blockStrtTime = prevTime;
358 while (blockOffset != blockLen)
360 if (conn_poll(rrthread->socketId, TIME_OUT_MILLISEC) <= 0)
362 TIZEN_LOGD("Thread %d pollfd <=0\n",rrthread->threadId);
366 lenRcvd = recv(rrthread->socketId,block + blockOffset,blockLen-blockOffset, 0);
367 if ((lenRcvd == -1) || (lenRcvd == 0))
369 TIZEN_LOGD("Thread %d pollfd recv faill \n",rrthread->threadId);
372 else if (lenRcvd > 0)
374 currOffset = currOffset + lenRcvd;
375 blockOffset = blockOffset + lenRcvd;
376 currTime = get_time_in_microsec();
377 blockEndTime = currTime;
378 diffTime = (currTime-prevTime) /1000;
379 diffOffset = currOffset-prevOffset;
380 if((rngRspLen > rrthread->minDataForSpeed) &&
381 ((diffOffset >= rrthread->blockForSpeed) || (diffTime >= rrthread->speedTimeOut)))
384 prevOffset = currOffset;
385 avgTime = (currTime - chunkStrTime)/1000;
388 speed = ((rngRspLen + blockOffset) * 8)/avgTime;
390 SET_SPEED(rrthread->threadId,speed, rrthread->blockMgr);
392 if((blockEndTime-blockStrtTime) >= BLOCK_TIME_OUT)
394 blockLen = blockOffset;
398 if (blockOffset != blockLen)
401 TIZEN_LOGD("Thread %d IOException during read\n",rrthread->threadId);
402 IOException = B_TRUE;
408 data_buffer_add(blockOffset, rrthread->threadId, tempBuff, currChunk);
409 rngRspLen = rngRspLen + blockOffset;
411 TIZEN_D_LOGD("Thread %d completed block of len\n",blockLen);
412 /* check the other thread status */
413 if((currTime - temp_startTime) > TEMP_TIME_OUT)
415 TIZEN_D_LOGD("Go For Temperature Checking");
416 temp_startTime = currTime;
419 if(block_manager_checkOtherThread(rrthread->threadId,chunkId,rrthread->blockMgr,temp_check))
421 TIZEN_LOGD("Thread %d IOException as other thread is blocked read\n",rrthread->threadId);
422 IOException = B_TRUE;
428 if (IOException == B_TRUE)
430 if ((chunkId != -1) && (DATA_BUFFER_GET_THREAD_ID(rrthread->commBuffer + chunkId) ==
433 /* close the current fd */
434 if (rrthread->socketId != 0)
436 close(rrthread->socketId);
437 rrthread->socketId = 0;
439 /* IO Exception inform Block manager */
440 block_manager_io_exception(rrthread->threadId,chunkId, rrthread->blockMgr);
441 DATA_BUFFER_SET_STATE(STATE_BLOCKED, (rrthread->commBuffer + chunkId));
442 if(blockOffset != blockLen)
444 /* Consider only IO Expection due to socket */
445 rrthread->blockMgr->noOfIOExp[rrthread->threadId]++;
450 /* Current thread is slow Need to check buffer status */
451 if (block_manager_chunk_present(rrthread->blockMgr) <= 0)
454 TIZEN_LOGD("Slow Thread %d is in wait state \n",rrthread->threadId);
456 rrthread->socketId = 0;
461 TIZEN_LOGD("Thread %d Completed chunk %d \n",rrthread->threadId, chunkId);
463 if ((IOException == B_FALSE) && (1 == connClose))
465 IOException = B_TRUE;
466 if (block_manager_chunk_present(rrthread->blockMgr) <= 0)
469 TIZEN_LOGD("Thread %d is in wait state \n",rrthread->threadId);
471 if (rrthread->socketId != 0)
473 close(rrthread->socketId);
474 rrthread->socketId = 0;
479 rrthread->blockMgr->threadState[rrthread->threadId] = STATE_THREAD_STOPPED;
481 if (rrthread->socketId != 0)
483 close(rrthread->socketId);
484 rrthread->socketId = 0;
487 if(NULL != newRequest)
495 uint32 range_request_thread_rebuild_req(int8 *newRequest, int64 *chunkInfo,RangeRequestThread *rrthread)
497 int8 rangeField[50] = {0};
500 rangeLen = sprintf(rangeField,"%s%lld%s%lld%s","Range: bytes=", chunkInfo[0], "-",
501 chunkInfo[1], "\r\n\r\n");
503 memcpy(newRequest, rrthread->reqHeaders, rrthread->headerLen);
504 newRequest[rrthread->headerLen] = '\0';
507 memcpy(newRequest + (rrthread->headerLen - 2), rangeField, rangeLen);
508 newRequest[rangeLen + rrthread->headerLen-2] = '\0';
509 TIZEN_LOGD("thread ID %d range_request_thread_rebuild_req new req with range =%s\n",
510 rrthread->threadId, newRequest);
511 return (rangeLen + rrthread->headerLen -2);
514 void range_request_thread_exit(RangeRequestThread *rrthread)
516 TIZEN_LOGD("range_request_thread_exit %p", rrthread);
518 if (0 != rrthread->socketId)
520 close(rrthread->socketId);
521 rrthread->socketId = 0;
524 if (0 != rrthread->pThreadId)
526 pthread_join(rrthread->pThreadId,NULL);
527 rrthread->pThreadId = 0;
532 TIZEN_LOGD("range_request_thread_exit Sucess %p", rrthread);
535 int range_request_recv_rng_rsp_headers(int32 socket_fd, uint32 size, uint32 timeout, uint64 instanceSize,
536 uint64 currChunkLen, int32 *bodyLen, int8 *blockSize, uint64 respLen, uint32 *connClose)
543 int8 rspSize[MAX_HEADERS_SIZE + 1] = {0};
544 int8 rspPrint[MAX_HEADERS_SIZE] = {0};
547 memset(rspSize, 0, MAX_HEADERS_SIZE + 1);
548 memset(rspPrint, 0, MAX_HEADERS_SIZE);
552 if(conn_poll(socket_fd, timeout) <= 0)
554 TIZEN_LOGD("Poll Error in recv headers");
555 return HTTP_RSP_SOCKET_ERROR;
557 uint32 min_size = MIN(size, (MAX_HEADERS_SIZE - offset));
558 rcvdLen = recv(socket_fd, rspSize + offset, min_size, 0);
559 TIZEN_D_LOGD("thread ID recvd lenght %d\n", rcvdLen);
562 rspSize[offset + rcvdLen +1] = '\0';
563 len = decode_http_find_str(rspSize, END_OF_HEADERS);
567 offset = offset + rcvdLen;
568 *bodyLen = offset - headerLen;
570 memcpy(rspPrint, rspSize, headerLen);
571 TIZEN_LOGD("Response %s\n", rspPrint);
572 /* Decode Response headers */
573 memset(&httprsp, 0, sizeof(httpResp));
574 decode_http_rsp_init(rspSize, headerLen, &httprsp);
576 retval = process_http_rsp(&httprsp);
577 if (HTTP_RSP_DECODING_SUCCESS == retval)
579 retval = range_request_validate_rsp(instanceSize,
580 &httprsp, currChunkLen, respLen, connClose);
582 if((retval == HTTP_RSP_DECODING_SUCCESS) && (*bodyLen > 0))
584 /* Copy initial Response to block */
585 memcpy(blockSize,rspSize + headerLen,*bodyLen);
588 delete_http_rsp(&httprsp);
593 offset = offset + rcvdLen;
594 if (offset == MAX_HEADERS_SIZE)
596 /* Rsp header too large */
597 retval = HTTP_RSP_DECODING_ERROR;
604 TIZEN_LOGD("recv Error in recv headers");
605 retval = HTTP_RSP_SOCKET_ERROR;
610 }/* End of recvRngRspHeaders() */
612 int range_request_validate_rsp(uint64 instanceSize, httpResp *httpRsp,
613 uint64 currChunkLen, uint64 respLen, uint32 *connClose)
615 int32 retval = HTTP_RSP_DECODING_ERROR;
616 int8 *rspCode = DECODE_HTTP_RSP_GET_RSP_CODE(httpRsp);
617 int8 *contLen = DECODE_HTTP_RSP_GET_CONT_LEN(httpRsp);
618 int8 *conn = DECODE_HTTP_RSP_GET_CONNECTION(httpRsp);
622 if(0 == strncasecmp(conn,"close",strlen("close")))
628 if ((rspCode != NULL) && (contLen != NULL))
630 if ((0 == strncasecmp(rspCode, "200 OK", strlen("200 OK")))
631 || (0 == strncasecmp(rspCode, "206 Partial Content",strlen("206 Partial Content"))))
633 uint64 rcvdContLen = atol(contLen);
634 TIZEN_LOGD("rcvdContLen %llu Expected %llu",rcvdContLen,currChunkLen);
635 if (rcvdContLen == currChunkLen)
637 uint64 rcvdContRngLen = decode_http_rsp_get_cont_rnglen(httpRsp->contRange);
638 TIZEN_LOGD("rcvdContRngLen %llu contRngLen %llu compRspLen %s",
639 rcvdContRngLen, instanceSize, contLen);
640 if ((instanceSize != 0) && (instanceSize == rcvdContRngLen))
642 retval = HTTP_RSP_DECODING_SUCCESS;
644 else if (rcvdContRngLen == respLen)
646 retval = HTTP_RSP_DECODING_SUCCESS;