//Worker thread static void *requestThread(void *data) { data; CCThread thread; thread.createAutoreleasePool(); HttpRequestPacket *req = NULL; while (true) { //Wait for http request tasks from main thread int semWaitRet = sem_wait(s_pSem); if (semWaitRet < 0) { CCLog("HttpRequest async thread semaphore error: %s\n", strerror(errno)); break; } std::queue<HttpRequestPacket *> *pQueue = s_requestQueue; pthread_mutex_lock(&s_requestQueueMutex); //Get request task from queue if (pQueue->empty()) { pthread_mutex_unlock(&s_requestQueueMutex); if (need_quit) { break; } else { continue; } } else { if (need_quit) { pthread_mutex_unlock(&s_requestQueueMutex); break; } req = pQueue->front(); pQueue->pop(); pthread_mutex_unlock(&s_requestQueueMutex); } //Create a response packet and assume it will successed HttpResponsePacket *responsePacket = new HttpResponsePacket(); responsePacket->request = req; responsePacket->succeed = true; //Process the request if (req->reqType == kHttpRequestGet) { //Get Request int32_t ret = processGetTask(req, writeData, &responsePacket->responseData, &responsePacket->responseCode); if (ret != 0) { responsePacket->succeed = false; responsePacket->responseData = errorBuffer; } } else if (req->reqType == kHttpRequestPost) { //Post Request int32_t ret = processPostTask(req, writeData, &responsePacket->responseData, &responsePacket->responseCode); if (ret != 0) { responsePacket->succeed = false; responsePacket->responseData = errorBuffer; } } else if (req->reqType == kHttpRequestDownloadFile) { //Download File Request bool fullyDownloaded = true; std::vector<std::string>::iterator iter; std::string saveFileName; std::string needDownload; for (iter = req->files.begin(); iter != req->files.end(); ++iter) { needDownload = *iter; std::string::size_type pos = needDownload.rfind("/"); if (pos != std::string::npos) { saveFileName = needDownload.substr(pos + 1); } else { saveFileName = needDownload; } //If the download url is http://www.xxx.com/yyy.html //The saved file name must be yyy.html saveFileName = CCFileUtils::sharedFileUtils()->getWriteablePath() + saveFileName; CCLog(CCFileUtils::sharedFileUtils()->getWriteablePath().c_str()); FILE *handle = fopen(saveFileName.c_str(), "w+b"); CCLog("open file for download"); CCLog(saveFileName.c_str()); if (!handle) { fullyDownloaded = false; break; } CCLog("success"); req->url = needDownload; int32_t ret = processDownloadTask(req, writeFile, handle, &responsePacket->responseCode); if (handle) { fclose(handle); } if (ret != 0) { fullyDownloaded = false; break; } } //Only consider download task successfully when all the files downloaded if (!fullyDownloaded) { responsePacket->succeed = false; responsePacket->responseData = errorBuffer; } } pthread_mutex_lock(&s_responseQueueMutex); s_responseQueue->push(responsePacket); pthread_mutex_unlock(&s_responseQueueMutex); } //If worker thread received quit signal, clean up un-completed request queue releaseRequestQueue(); if (s_pSem != NULL) { #if CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE sem_unlink(CC_ASYNC_HTTPREQUEST_SEMAPHORE); sem_close(s_pSem); #else sem_destroy(s_pSem); #endif s_pSem = NULL; pthread_mutex_destroy(&s_requestQueueMutex); pthread_mutex_destroy(&s_responseQueueMutex); delete s_requestQueue; delete s_responseQueue; } pthread_exit(NULL); return 0; }
// Worker thread static void* networkThread(void *data) { CCHttpRequest *request = NULL; while (true) { if (need_quit) { break; } // step 1: send http request if the requestQueue isn't empty request = NULL; pthread_mutex_lock(&s_requestQueueMutex); //Get request task from queue if (0 != s_requestQueue->count()) { request = dynamic_cast<CCHttpRequest*>(s_requestQueue->objectAtIndex(0)); s_requestQueue->removeObjectAtIndex(0); // request's refcount = 1 here } pthread_mutex_unlock(&s_requestQueueMutex); if (NULL == request) { // Wait for http request tasks from main thread pthread_cond_wait(&s_SleepCondition, &s_SleepMutex); continue; } // step 2: libcurl sync access // Create a HttpResponse object, the default setting is http access failed CCHttpResponse *response = new CCHttpResponse(request); // request's refcount = 2 here, it's retained by HttpRespose constructor request->release(); // ok, refcount = 1 now, only HttpResponse hold it. int32_t responseCode = -1; int retValue = 0; // Process the request -> get response packet switch (request->getRequestType()) { case CCHttpRequest::kHttpGet: // HTTP GET retValue = processGetTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader()); break; case CCHttpRequest::kHttpPost: // HTTP POST retValue = processPostTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader()); break; case CCHttpRequest::kHttpPut: retValue = processPutTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader()); break; case CCHttpRequest::kHttpDelete: retValue = processDeleteTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader()); break; default: CCAssert(true, "CCHttpClient: unkown request type, only GET and POSt are supported"); break; } // write data to HttpResponse response->setResponseCode(responseCode); if (retValue != 0) { response->setSucceed(false); response->setErrorBuffer(s_errorBuffer); } else { response->setSucceed(true); } // add response packet into queue pthread_mutex_lock(&s_responseQueueMutex); s_responseQueue->addObject(response); pthread_mutex_unlock(&s_responseQueueMutex); // resume dispatcher selector CAScheduler::getScheduler()->resumeTarget(CCHttpClient::getInstance()); } // cleanup: if worker thread received quit signal, clean up un-completed request queue pthread_mutex_lock(&s_requestQueueMutex); s_requestQueue->removeAllObjects(); pthread_mutex_unlock(&s_requestQueueMutex); s_asyncRequestCount -= s_requestQueue->count(); if (s_requestQueue != NULL) { pthread_mutex_destroy(&s_requestQueueMutex); pthread_mutex_destroy(&s_responseQueueMutex); pthread_mutex_destroy(&s_SleepMutex); pthread_cond_destroy(&s_SleepCondition); s_requestQueue->release(); s_requestQueue = NULL; s_responseQueue->release(); s_responseQueue = NULL; } pthread_exit(NULL); return 0; }
// Worker thread static void* networkThread(void *data) { CCHttpRequest *request = NULL; while (true) { // Wait for http request tasks from main thread int semWaitRet = sem_wait(s_pSem); if (semWaitRet < 0) { CCLog("HttpRequest async thread semaphore error: %s\n", strerror(errno)); break; } if (need_quit) { break; } // step 1: send http request if the requestQueue isn't empty request = NULL; pthread_mutex_lock(&s_requestQueueMutex); //Get request task from queue if (0 != s_requestQueue->count()) { request = dynamic_cast<CCHttpRequest*>(s_requestQueue->objectAtIndex(0)); s_requestQueue->removeObjectAtIndex(0); // request's refcount = 1 here } pthread_mutex_unlock(&s_requestQueueMutex); if (NULL == request) { continue; } // step 2: libcurl sync access // Create a HttpResponse object, the default setting is http access failed CCHttpResponse *response = new CCHttpResponse(request); // request's refcount = 2 here, it's retained by HttpRespose constructor request->release(); // ok, refcount = 1 now, only HttpResponse hold it. int responseCode = -1; int retValue = 0; // Process the request -> get response packet switch (request->getRequestType()) { case CCHttpRequest::kHttpGet: // HTTP GET retValue = processGetTask(request, writeData, response->getResponseData(), &responseCode); break; case CCHttpRequest::kHttpPost: // HTTP POST retValue = processPostTask(request, writeData, response->getResponseData(), &responseCode); break; default: CCAssert(true, "CCHttpClient: unkown request type, only GET and POSt are supported"); break; } // write data to HttpResponse response->setResponseCode(responseCode); if (retValue != 0) { response->setSucceed(false); response->setErrorBuffer(s_errorBuffer); } else { response->setSucceed(true); } // add response packet into queue pthread_mutex_lock(&s_responseQueueMutex); s_responseQueue->addObject(response); pthread_mutex_unlock(&s_responseQueueMutex); // resume dispatcher selector CCDirector::sharedDirector()->getScheduler()->resumeTarget(CCHttpClient::getInstance()); } // cleanup: if worker thread received quit signal, clean up un-completed request queue pthread_mutex_lock(&s_requestQueueMutex); s_requestQueue->removeAllObjects(); pthread_mutex_unlock(&s_requestQueueMutex); s_asyncRequestCount -= s_requestQueue->count(); if (s_pSem != NULL) { #if CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE sem_unlink(CC_ASYNC_HTTPREQUEST_SEMAPHORE); sem_close(s_pSem); #else sem_destroy(s_pSem); #endif s_pSem = NULL; pthread_mutex_destroy(&s_requestQueueMutex); pthread_mutex_destroy(&s_responseQueueMutex); s_requestQueue->release(); s_responseQueue->release(); } pthread_exit(NULL); return 0; }
// Process Response static void processResponse(HttpResponse* response, char* errorBuffer) { auto request = response->getHttpRequest(); long responseCode = -1; int retValue = 0; // Process the request -> get response packet switch (request->getRequestType()) { case HttpRequest::Type::GET: // HTTP GET retValue = processGetTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader(), errorBuffer); break; case HttpRequest::Type::POST: // HTTP POST retValue = processPostTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader(), errorBuffer); break; case HttpRequest::Type::PUT: retValue = processPutTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader(), errorBuffer); break; case HttpRequest::Type::DELETE: retValue = processDeleteTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader(), errorBuffer); break; case HttpRequest::Type::POSTFILE: // HTTP POST retValue = processPostFileTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader(), errorBuffer); break; default: CCASSERT(true, "CCHttpClient: unkown request type, only GET and POSt are supported"); break; } // write data to HttpResponse response->setResponseCode(responseCode); if (retValue != 0) { response->setSucceed(false); response->setErrorBuffer(errorBuffer); } else { response->setSucceed(true); } }
// Worker thread void HttpClient::networkThread() { HttpRequest *request = nullptr; auto scheduler = Director::getInstance()->getScheduler(); while (true) { if (s_need_quit) { break; } // step 1: send http request if the requestQueue isn't empty request = nullptr; s_requestQueueMutex.lock(); //Get request task from queue if (!s_requestQueue->empty()) { request = s_requestQueue->at(0); s_requestQueue->erase(0); } s_requestQueueMutex.unlock(); if (nullptr == request) { // Wait for http request tasks from main thread std::unique_lock<std::mutex> lk(s_SleepMutex); s_SleepCondition.wait(lk); continue; } // step 2: libcurl sync access // Create a HttpResponse object, the default setting is http access failed HttpResponse *response = new HttpResponse(request); // request's refcount = 2 here, it's retained by HttpRespose constructor request->release(); // ok, refcount = 1 now, only HttpResponse hold it. long responseCode = -1; int retValue = 0; // Process the request -> get response packet switch (request->getRequestType()) { case HttpRequest::Type::GET: // HTTP GET retValue = processGetTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader()); break; case HttpRequest::Type::POST: // HTTP POST retValue = processPostTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader()); break; case HttpRequest::Type::PUT: retValue = processPutTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader()); break; case HttpRequest::Type::DELETE: retValue = processDeleteTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader()); break; default: CCASSERT(true, "CCHttpClient: unkown request type, only GET and POSt are supported"); break; } // write data to HttpResponse response->setResponseCode(responseCode); if (retValue != 0) { response->setSucceed(false); response->setErrorBuffer(s_errorBuffer); } else { response->setSucceed(true); } // add response packet into queue s_responseQueueMutex.lock(); s_responseQueue->pushBack(response); s_responseQueueMutex.unlock(); if (nullptr != s_pHttpClient) { scheduler->performFunctionInCocosThread(CC_CALLBACK_0(HttpClient::dispatchResponseCallbacks, this)); } } // cleanup: if worker thread received quit signal, clean up un-completed request queue s_requestQueueMutex.lock(); s_requestQueue->clear(); s_requestQueueMutex.unlock(); if (s_requestQueue != nullptr) { delete s_requestQueue; s_requestQueue = nullptr; delete s_responseQueue; s_responseQueue = nullptr; } }
//Worker thread static void *requestThread(void *data) { CCThread thread; thread.createAutoreleasePool(); HttpRequestPacket *req = NULL; while (true) { int semWaitRet = sem_wait(s_pSem); if (semWaitRet < 0) { CCLog("HttpRequest async thread semaphore error: %s\n", strerror(errno)); break; } std::queue<HttpRequestPacket *> *pQueue = s_requestQueue; pthread_mutex_lock(&s_requestQueueMutex); if (pQueue->empty()) { pthread_mutex_unlock(&s_requestQueueMutex); if (need_quit) { break; } else { continue; } } else { if (need_quit) { pthread_mutex_unlock(&s_requestQueueMutex); break; } req = pQueue->front(); pQueue->pop(); pthread_mutex_unlock(&s_requestQueueMutex); } HttpResponsePacket *responsePacket = new HttpResponsePacket(); responsePacket->request = req; responsePacket->succeed = true; //Process the request if (req->reqType == kHttpRequestGet) { int32_t ret = processGetTask(req, writeData, &responsePacket->responseData, &responsePacket->responseCode); if (ret != 0) { responsePacket->succeed = false; responsePacket->responseData = errorBuffer; } } else if (req->reqType == kHttpRequestPost) { int32_t ret = processPostTask(req, writeData, &responsePacket->responseData, &responsePacket->responseCode); if (ret != 0) { responsePacket->succeed = false; responsePacket->responseData = errorBuffer; } } else if (req->reqType == kHttpRequestDownloadFile) { bool fullyDownloaded = true; std::vector<std::string>::iterator iter; std::string saveFileName; std::string needDownload; for (iter = req->files.begin(); iter != req->files.end(); ++iter) { needDownload = *iter; std::string::size_type pos = needDownload.rfind("/"); if (pos != std::string::npos) { saveFileName = needDownload.substr(pos + 1); } else { saveFileName = needDownload; } saveFileName = CCFileUtils::sharedFileUtils()->getWriteablePath() + saveFileName; FILE *handle = fopen(saveFileName.c_str(), "w+"); if (!handle) { fullyDownloaded = false; break; } req->url = needDownload; int32_t ret = processDownloadTask(req, writeFile, handle, &responsePacket->responseCode); if (handle) { fclose(handle); } if (ret != 0) { fullyDownloaded = false; break; } } if (!fullyDownloaded) { responsePacket->succeed = false; responsePacket->responseData = errorBuffer; } } pthread_mutex_lock(&s_responseQueueMutex); s_responseQueue->push(responsePacket); pthread_mutex_unlock(&s_responseQueueMutex); } releaseRequestQueue(); if (s_pSem != NULL) { #if CC_ASYNC_HTTPREQUEST_USE_NAMED_SEMAPHORE sem_unlink(CC_ASYNC_HTTPREQUEST_SEMAPHORE); sem_close(s_pSem); #else sem_destroy(s_pSem); #endif s_pSem = NULL; pthread_mutex_destroy(&s_requestQueueMutex); pthread_mutex_destroy(&s_responseQueueMutex); delete s_requestQueue; delete s_responseQueue; } pthread_exit(NULL); return 0; }
// Worker thread static KDvoid* networkThread ( KDvoid* pData ) { CCHttpRequest* pRequest = KD_NULL; while ( 1 ) { if ( l_bNeedQuit ) { break; } // step 1: send http request if the requestQueue isn't empty pRequest = KD_NULL; kdThreadMutexLock ( l_pRequestQueueMutex ); // Get request task from queue if ( 0 != l_pRequestQueue->count ( ) ) { pRequest = dynamic_cast<CCHttpRequest*> ( l_pRequestQueue->objectAtIndex ( 0 ) ); l_pRequestQueue->removeObjectAtIndex ( 0 ); // request's refcount = 1 here } kdThreadMutexUnlock ( l_pRequestQueueMutex ); if ( KD_NULL == pRequest ) { // Wait for http request tasks from main thread kdThreadCondWait ( l_pSleepCondition, l_pSleepMutex ); continue; } // step 2: libcurl sync access // Create a HttpResponse object, the default setting is http access failed CCHttpResponse* pResponse = new CCHttpResponse ( pRequest ); // request's refcount = 2 here, it's retained by HttpRespose constructor pRequest->release ( ); // ok, refcount = 1 now, only HttpResponse hold it. KDint nResponseCode = -1; KDint nRetValue = 0; // Process the request -> get response packet switch ( pRequest->getRequestType ( ) ) { case CCHttpRequest::kCCHttpGet : // HTTP GET nRetValue = processGetTask ( pRequest, writeData, pResponse->getResponseData ( ), &nResponseCode ); break; case CCHttpRequest::kCCHttpPost : // HTTP POST nRetValue = processPostTask ( pRequest, writeData, pResponse->getResponseData ( ), &nResponseCode ); break; default : CCAssert ( KD_TRUE, "CCHttpClient: unkown request type, only GET and POSt are supported" ); break; } // write data to HttpResponse pResponse->setResponseCode ( nResponseCode ); if ( nRetValue != 0 ) { pResponse->setSucceed ( KD_FALSE ); pResponse->setErrorBuffer ( l_szErrorBuffer ); } else { pResponse->setSucceed ( KD_TRUE ); } // add response packet into queue kdThreadMutexLock ( l_pResponseQueueMutex ); l_pResponseQueue->addObject ( pResponse ); kdThreadMutexUnlock ( l_pResponseQueueMutex ); // resume dispatcher selector CCDirector::sharedDirector ( )->getScheduler ( )->resumeTarget ( CCHttpClient::getInstance ( ) ); } // cleanup: if worker thread received quit signal, clean up un-completed request queue kdThreadMutexLock ( l_pRequestQueueMutex ); l_pRequestQueue->removeAllObjects ( ); kdThreadMutexUnlock ( l_pRequestQueueMutex ); l_uAsyncRequestCount -= l_pRequestQueue->count ( ); if ( l_pRequestQueue != KD_NULL ) { kdThreadMutexFree ( l_pRequestQueueMutex ); kdThreadMutexFree ( l_pResponseQueueMutex ); kdThreadMutexFree ( l_pSleepMutex ); kdThreadCondFree ( l_pSleepCondition ); l_pRequestQueue->release ( ); l_pRequestQueue = KD_NULL; l_pResponseQueue->release ( ); l_pResponseQueue = KD_NULL; } kdThreadExit ( KD_NULL ); return 0; }
// Worker thread static void networkThread(void) { HttpRequest *request = NULL; while (true) { if (s_need_quit) { break; } // step 1: send http request if the requestQueue isn't empty request = NULL; s_requestQueueMutex.lock(); //Get request task from queue if (0 != s_requestQueue->count()) { request = dynamic_cast<HttpRequest*>(s_requestQueue->getObjectAtIndex(0)); s_requestQueue->removeObjectAtIndex(0); } s_requestQueueMutex.unlock(); if (NULL == request) { // Wait for http request tasks from main thread std::unique_lock<std::mutex> lk(s_SleepMutex); s_SleepCondition.wait(lk); continue; } // step 2: libcurl sync access // Create a HttpResponse object, the default setting is http access failed HttpResponse *response = new HttpResponse(request); // request's refcount = 2 here, it's retained by HttpRespose constructor request->release(); // ok, refcount = 1 now, only HttpResponse hold it. long responseCode = -1; int retValue = 0; // Process the request -> get response packet switch (request->getRequestType()) { case HttpRequest::Type::GET: // HTTP GET retValue = processGetTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader()); break; case HttpRequest::Type::POST: // HTTP POST retValue = processPostTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader()); break; case HttpRequest::Type::PUT: retValue = processPutTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader()); break; case HttpRequest::Type::DELETE: retValue = processDeleteTask(request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader()); break; default: CCASSERT(true, "CCHttpClient: unkown request type, only GET and POSt are supported"); break; } // write data to HttpResponse response->setResponseCode(responseCode); if (retValue != 0) { response->setSucceed(false); response->setErrorBuffer(s_errorBuffer); } else { response->setSucceed(true); } // add response packet into queue s_responseQueueMutex.lock(); s_responseQueue->addObject(response); s_responseQueueMutex.unlock(); // resume dispatcher selector Director::getInstance()->getScheduler()->resumeTarget(HttpClient::getInstance()); } // cleanup: if worker thread received quit signal, clean up un-completed request queue s_requestQueueMutex.lock(); s_requestQueue->removeAllObjects(); s_requestQueueMutex.unlock(); s_asyncRequestCount -= s_requestQueue->count(); if (s_requestQueue != NULL) { s_requestQueue->release(); s_requestQueue = NULL; s_responseQueue->release(); s_responseQueue = NULL; } }
// Process Response void HttpClient::processRequest(HttpResponse* response, char* responseMessage) { HttpRequest* request = response->getHttpRequest(); long responseCode = -1; int retValue = 0; if(request == NULL) { printf("request is zero,please fix\n"); return; } // Process the request -> get response packet switch (request->getRequestType()) { case HttpRequest::GET: // HTTP GET retValue = processGetTask(this, request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader(), responseMessage); break; case HttpRequest::POST: // HTTP POST retValue = processPostTask(this, request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader(), responseMessage); break; case HttpRequest::PUT: retValue = processPutTask(this, request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader(), responseMessage); break; case HttpRequest::_DELETE: retValue = processDeleteTask(this, request, writeData, response->getResponseData(), &responseCode, writeHeaderData, response->getResponseHeader(), responseMessage); break; default: printf("CCHttpClient: unknown request type, only GET and POSt are supported"); break; } // write data to HttpResponse response->setResponseCode(responseCode); if (retValue != 0) { response->setSucceed(false); response->setErrorBuffer(responseMessage); } else { response->setSucceed(true); } }