1212#include < CCDB/CCDBDownloader.h>
1313
1414#include < curl/curl.h>
15- #include < uv.h>
16-
1715#include < unordered_map>
1816#include < cstdio>
1917#include < cstdlib>
2624#include < unistd.h>
2725#include < sys/types.h>
2826#include < sys/socket.h>
27+ #include < fairlogger/Logger.h>
2928
3029namespace o2 ::ccdb
3130{
3231
32+ void uvErrorCheck (int code)
33+ {
34+ if (code != 0 ) {
35+ char buf[1000 ];
36+ uv_strerror_r (code, buf, 1000 );
37+ LOG (error) << " CCDBDownloader: UV error - " << buf;
38+ }
39+ }
40+
41+ void curlEasyErrorCheck (CURLcode code)
42+ {
43+ if (code != CURLE_OK ) {
44+ LOG (error) << " CCDBDownloader: CURL error - " << curl_easy_strerror (code);
45+ }
46+ }
47+
48+ void curlMultiErrorCheck (CURLMcode code)
49+ {
50+ if (code != CURLM_OK ) {
51+ LOG (error) << " CCDBDownloader: CURL error - " << curl_multi_strerror (code);
52+ }
53+ }
54+
3355CCDBDownloader::CCDBDownloader (uv_loop_t * uv_loop)
3456{
3557 if (uv_loop) {
@@ -43,8 +65,8 @@ CCDBDownloader::CCDBDownloader(uv_loop_t* uv_loop)
4365 // Preparing timer to be used by curl
4466 mTimeoutTimer = new uv_timer_t ();
4567 mTimeoutTimer ->data = this ;
46- uv_loop_init (mUVLoop );
47- uv_timer_init (mUVLoop , mTimeoutTimer );
68+ uvErrorCheck ( uv_loop_init (mUVLoop ) );
69+ uvErrorCheck ( uv_timer_init (mUVLoop , mTimeoutTimer ) );
4870 mHandleMap [(uv_handle_t *)mTimeoutTimer ] = true ;
4971
5072 // Preparing curl handle
@@ -54,35 +76,36 @@ CCDBDownloader::CCDBDownloader(uv_loop_t* uv_loop)
5476 // uv_loop runs only when there are active handles, this handle guarantees the loop won't close immedietly after starting
5577 auto timerCheckQueueHandle = new uv_timer_t ();
5678 timerCheckQueueHandle->data = this ;
57- uv_timer_init (mUVLoop , timerCheckQueueHandle);
79+ uvErrorCheck ( uv_timer_init (mUVLoop , timerCheckQueueHandle) );
5880 mHandleMap [(uv_handle_t *)timerCheckQueueHandle] = true ;
59- uv_timer_start (timerCheckQueueHandle, checkStopSignal, 100 , 100 );
81+ uvErrorCheck ( uv_timer_start (timerCheckQueueHandle, checkStopSignal, 100 , 100 ) );
6082
6183 mLoopThread = new std::thread (&CCDBDownloader::runLoop, this );
6284}
6385
6486void CCDBDownloader::initializeMultiHandle ()
6587{
6688 mCurlMultiHandle = curl_multi_init ();
67- curl_multi_setopt (mCurlMultiHandle , CURLMOPT_SOCKETFUNCTION , handleSocket);
89+ curlMultiErrorCheck ( curl_multi_setopt (mCurlMultiHandle , CURLMOPT_SOCKETFUNCTION , handleSocket) );
6890 auto socketData = &mSocketData ;
6991 socketData->curlm = mCurlMultiHandle ;
7092 socketData->CD = this ;
71- curl_multi_setopt (mCurlMultiHandle , CURLMOPT_SOCKETDATA , socketData);
72- curl_multi_setopt (mCurlMultiHandle , CURLMOPT_TIMERFUNCTION , startTimeout);
73- curl_multi_setopt (mCurlMultiHandle , CURLMOPT_TIMERDATA , mTimeoutTimer );
74- curl_multi_setopt (mCurlMultiHandle , CURLMOPT_MAX_TOTAL_CONNECTIONS , mMaxHandlesInUse );
93+ curlMultiErrorCheck ( curl_multi_setopt (mCurlMultiHandle , CURLMOPT_SOCKETDATA , socketData) );
94+ curlMultiErrorCheck ( curl_multi_setopt (mCurlMultiHandle , CURLMOPT_TIMERFUNCTION , startTimeout) );
95+ curlMultiErrorCheck ( curl_multi_setopt (mCurlMultiHandle , CURLMOPT_TIMERDATA , mTimeoutTimer ) );
96+ curlMultiErrorCheck ( curl_multi_setopt (mCurlMultiHandle , CURLMOPT_MAX_TOTAL_CONNECTIONS , mMaxHandlesInUse ) );
7597}
7698
7799CCDBDownloader::~CCDBDownloader ()
78100{
101+ mIsClosing = true ;
79102 // Cleanup and close all socket timers (curl_multi_cleanup will take care of the sockets)
80103 for (auto socketTimerPair : mSocketTimerMap ) {
81104 auto timer = socketTimerPair.second ;
82105 if (timer->data ) {
83106 delete (DataForClosingSocket*)timer->data ;
84107 }
85- uv_timer_stop (socketTimerPair.second );
108+ uvErrorCheck ( uv_timer_stop (socketTimerPair.second ) );
86109 uv_close ((uv_handle_t *)socketTimerPair.second , onUVClose);
87110 }
88111 // all timers have been closed --> so clear this map (otherwise it may get accessed in different callbacks again
@@ -102,15 +125,15 @@ CCDBDownloader::~CCDBDownloader()
102125 while (UV_EBUSY == uv_loop_close (mUVLoop )) {
103126 mCloseLoop = false ;
104127 uv_walk (mUVLoop , closeHandles, this );
105- uv_run (mUVLoop , UV_RUN_ONCE );
128+ uvErrorCheck ( uv_run (mUVLoop , UV_RUN_ONCE ) );
106129 }
107130 delete mUVLoop ;
108131 }
109132
110133 // delete timer
111134 // delete mTimeoutTimer; ---> not necessay (done elsewhere??)
112135
113- curl_multi_cleanup (mCurlMultiHandle );
136+ curlMultiErrorCheck ( curl_multi_cleanup (mCurlMultiHandle ) );
114137}
115138
116139void closeHandles (uv_handle_t * handle, void * arg)
@@ -134,7 +157,7 @@ void CCDBDownloader::checkStopSignal(uv_timer_t* handle)
134157 // Check for closing signal
135158 auto CD = (CCDBDownloader*)handle->data ;
136159 if (CD ->mCloseLoop ) {
137- uv_timer_stop (handle);
160+ uvErrorCheck ( uv_timer_stop (handle) );
138161 uv_stop (CD ->mUVLoop );
139162 }
140163 CD ->checkForThreadsToJoin ();
@@ -145,24 +168,29 @@ void CCDBDownloader::closesocketCallback(void* clientp, curl_socket_t item)
145168 auto CD = (CCDBDownloader*)clientp;
146169 if (CD ->mSocketTimerMap .find (item) != CD ->mSocketTimerMap .end ()) {
147170 auto timer = CD ->mSocketTimerMap [item];
148- uv_timer_stop (timer);
171+ uvErrorCheck ( uv_timer_stop (timer) );
149172 // we are getting rid of the uv_timer_t pointer ... so we need
150173 // to free possibly attached user data pointers as well. Counteracts action of opensocketCallback
151174 if (timer->data ) {
152175 delete (DataForClosingSocket*)timer->data ;
153176 }
154177 CD ->mSocketTimerMap .erase (item);
155- close (item);
178+ if (close (item) == -1 ) {
179+ LOG (error) << " CCDBDownloader: Socket failed to close" ;
180+ }
156181 }
157182}
158183
159184curl_socket_t opensocketCallback (void * clientp, curlsocktype purpose, struct curl_sockaddr * address)
160185{
161186 auto CD = (CCDBDownloader*)clientp;
162187 auto sock = socket (address->family , address->socktype , address->protocol );
188+ if (sock == -1 ) {
189+ LOG (error) << " CCDBDownloader: Socket failed to open" ;
190+ }
163191
164192 CD ->mSocketTimerMap [sock] = new uv_timer_t ();
165- uv_timer_init (CD ->mUVLoop , CD ->mSocketTimerMap [sock]);
193+ uvErrorCheck ( uv_timer_init (CD ->mUVLoop , CD ->mSocketTimerMap [sock]) );
166194 CD ->mHandleMap [(uv_handle_t *)CD ->mSocketTimerMap [sock]] = true ;
167195
168196 auto data = new DataForClosingSocket ();
@@ -187,9 +215,11 @@ void CCDBDownloader::closeSocketByTimer(uv_timer_t* handle)
187215 auto sock = data->socket ;
188216
189217 if (CD ->mSocketTimerMap .find (sock) != CD ->mSocketTimerMap .end ()) {
190- uv_timer_stop (CD ->mSocketTimerMap [sock]);
218+ uvErrorCheck ( uv_timer_stop (CD ->mSocketTimerMap [sock]) );
191219 CD ->mSocketTimerMap .erase (sock);
192- close (sock);
220+ if (close (sock) == -1 ) {
221+ LOG (error) << " CCDBDownloader: Socket failed to close" ;
222+ }
193223
194224 delete data;
195225 }
@@ -216,7 +246,7 @@ void CCDBDownloader::curlPerform(uv_poll_t* handle, int status, int events)
216246
217247 auto context = (CCDBDownloader::curl_context_t *)handle->data ;
218248
219- curl_multi_socket_action (context->CD ->mCurlMultiHandle , context->sockfd , flags, &running_handles);
249+ curlMultiErrorCheck ( curl_multi_socket_action (context->CD ->mCurlMultiHandle , context->sockfd , flags, &running_handles) );
220250 context->CD ->checkMultiInfo ();
221251}
222252
@@ -233,7 +263,7 @@ int CCDBDownloader::handleSocket(CURL* easy, curl_socket_t s, int action, void*
233263 case CURL_POLL_INOUT :
234264
235265 curl_context = socketp ? (CCDBDownloader::curl_context_t *)socketp : CD ->createCurlContext (s);
236- curl_multi_assign (socketData->curlm , s, (void *)curl_context);
266+ curlMultiErrorCheck ( curl_multi_assign (socketData->curlm , s, (void *)curl_context) );
237267
238268 if (action != CURL_POLL_IN ) {
239269 events |= UV_WRITABLE ;
@@ -243,19 +273,19 @@ int CCDBDownloader::handleSocket(CURL* easy, curl_socket_t s, int action, void*
243273 }
244274
245275 if (CD ->mSocketTimerMap .find (s) != CD ->mSocketTimerMap .end ()) {
246- uv_timer_stop (CD ->mSocketTimerMap [s]);
276+ uvErrorCheck ( uv_timer_stop (CD ->mSocketTimerMap [s]) );
247277 }
248278
249- uv_poll_start (curl_context->poll_handle , events, curlPerform);
279+ uvErrorCheck ( uv_poll_start (curl_context->poll_handle , events, curlPerform) );
250280 break ;
251281 case CURL_POLL_REMOVE :
252282 if (socketp) {
253283 if (CD ->mSocketTimerMap .find (s) != CD ->mSocketTimerMap .end ()) {
254- uv_timer_start (CD ->mSocketTimerMap [s], closeSocketByTimer, CD ->mKeepaliveTimeoutMS , 0 );
284+ uvErrorCheck ( uv_timer_start (CD ->mSocketTimerMap [s], closeSocketByTimer, CD ->mKeepaliveTimeoutMS , 0 ) );
255285 }
256- uv_poll_stop (((CCDBDownloader::curl_context_t *)socketp)->poll_handle );
286+ uvErrorCheck ( uv_poll_stop (((CCDBDownloader::curl_context_t *)socketp)->poll_handle ) );
257287 CD ->destroyCurlContext ((CCDBDownloader::curl_context_t *)socketp);
258- curl_multi_assign (socketData->curlm , s, nullptr );
288+ curlMultiErrorCheck ( curl_multi_assign (socketData->curlm , s, nullptr ) );
259289 }
260290 break ;
261291 default :
@@ -325,7 +355,7 @@ CCDBDownloader::curl_context_t* CCDBDownloader::createCurlContext(curl_socket_t
325355 context->sockfd = sockfd;
326356 context->poll_handle = new uv_poll_t ();
327357
328- uv_poll_init_socket (mUVLoop , context->poll_handle , sockfd);
358+ uvErrorCheck ( uv_poll_init_socket (mUVLoop , context->poll_handle , sockfd) );
329359 mHandleMap [(uv_handle_t *)(context->poll_handle )] = true ;
330360 context->poll_handle ->data = context;
331361
@@ -354,9 +384,9 @@ void CCDBDownloader::transferFinished(CURL* easy_handle, CURLcode curlCode)
354384{
355385 mHandlesInUse --;
356386 PerformData* data;
357- curl_easy_getinfo (easy_handle, CURLINFO_PRIVATE , &data);
387+ curlEasyErrorCheck ( curl_easy_getinfo (easy_handle, CURLINFO_PRIVATE , &data) );
358388
359- curl_multi_remove_handle (mCurlMultiHandle , easy_handle);
389+ curlMultiErrorCheck ( curl_multi_remove_handle (mCurlMultiHandle , easy_handle) );
360390 *data->codeDestination = curlCode;
361391
362392 // If no requests left then signal finished based on type of operation
@@ -383,7 +413,7 @@ void CCDBDownloader::transferFinished(CURL* easy_handle, CURLcode curlCode)
383413
384414 // Calling timeout starts a new download if a new easy_handle was added.
385415 int running_handles;
386- curl_multi_socket_action (mCurlMultiHandle , CURL_SOCKET_TIMEOUT , 0 , &running_handles);
416+ curlMultiErrorCheck ( curl_multi_socket_action (mCurlMultiHandle , CURL_SOCKET_TIMEOUT , 0 , &running_handles) );
387417 checkMultiInfo ();
388418}
389419
@@ -411,27 +441,27 @@ int CCDBDownloader::startTimeout(CURLM* multi, long timeout_ms, void* userp)
411441 auto timeout = (uv_timer_t *)userp;
412442
413443 if (timeout_ms < 0 ) {
414- uv_timer_stop (timeout);
444+ uvErrorCheck ( uv_timer_stop (timeout) );
415445 } else {
416446 if (timeout_ms == 0 ) {
417447 timeout_ms = 1 ; // Calling curlTimeout when timeout = 0 could create an infinite loop
418448 }
419- uv_timer_start (timeout, curlTimeout, timeout_ms, 0 );
449+ uvErrorCheck ( uv_timer_start (timeout, curlTimeout, timeout_ms, 0 ) );
420450 }
421451 return 0 ;
422452}
423453
424454void CCDBDownloader::setHandleOptions (CURL * handle, PerformData* data)
425455{
426- curl_easy_setopt (handle, CURLOPT_PRIVATE , data);
427- curl_easy_setopt (handle, CURLOPT_CLOSESOCKETFUNCTION , closesocketCallback);
428- curl_easy_setopt (handle, CURLOPT_CLOSESOCKETDATA , this );
429- curl_easy_setopt (handle, CURLOPT_OPENSOCKETFUNCTION , opensocketCallback);
430- curl_easy_setopt (handle, CURLOPT_OPENSOCKETDATA , this );
456+ curlEasyErrorCheck ( curl_easy_setopt (handle, CURLOPT_PRIVATE , data) );
457+ curlEasyErrorCheck ( curl_easy_setopt (handle, CURLOPT_CLOSESOCKETFUNCTION , closesocketCallback) );
458+ curlEasyErrorCheck ( curl_easy_setopt (handle, CURLOPT_CLOSESOCKETDATA , this ) );
459+ curlEasyErrorCheck ( curl_easy_setopt (handle, CURLOPT_OPENSOCKETFUNCTION , opensocketCallback) );
460+ curlEasyErrorCheck ( curl_easy_setopt (handle, CURLOPT_OPENSOCKETDATA , this ) );
431461
432- curl_easy_setopt (handle, CURLOPT_TIMEOUT_MS , mRequestTimeoutMS );
433- curl_easy_setopt (handle, CURLOPT_CONNECTTIMEOUT_MS , mConnectionTimeoutMS );
434- curl_easy_setopt (handle, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS , mHappyEyeballsHeadstartMS );
462+ curlEasyErrorCheck ( curl_easy_setopt (handle, CURLOPT_TIMEOUT_MS , mRequestTimeoutMS ) );
463+ curlEasyErrorCheck ( curl_easy_setopt (handle, CURLOPT_CONNECTTIMEOUT_MS , mConnectionTimeoutMS ) );
464+ curlEasyErrorCheck ( curl_easy_setopt (handle, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS , mHappyEyeballsHeadstartMS ) );
435465}
436466
437467void CCDBDownloader::checkHandleQueue ()
@@ -441,7 +471,7 @@ void CCDBDownloader::checkHandleQueue()
441471 if (mHandlesToBeAdded .size () > 0 ) {
442472 // Add handles without going over the limit
443473 while (mHandlesToBeAdded .size () > 0 && mHandlesInUse < mMaxHandlesInUse ) {
444- curl_multi_add_handle (mCurlMultiHandle , mHandlesToBeAdded .front ());
474+ curlMultiErrorCheck ( curl_multi_add_handle (mCurlMultiHandle , mHandlesToBeAdded .front () ));
445475 mHandlesInUse ++;
446476 mHandlesToBeAdded .erase (mHandlesToBeAdded .begin ());
447477 }
@@ -451,7 +481,10 @@ void CCDBDownloader::checkHandleQueue()
451481
452482void CCDBDownloader::runLoop ()
453483{
454- uv_run (mUVLoop , UV_RUN_DEFAULT );
484+ uvErrorCheck (uv_run (mUVLoop , UV_RUN_DEFAULT ));
485+ if (!mIsClosing ) {
486+ LOG (error) << " CCDBDownloader: uvloop closed prematurely" ;
487+ }
455488}
456489
457490CURLcode CCDBDownloader::perform (CURL * handle)
@@ -545,8 +578,8 @@ void CCDBDownloader::makeLoopCheckQueueAsync()
545578{
546579 auto asyncHandle = new uv_async_t ();
547580 asyncHandle->data = this ;
548- uv_async_init (mUVLoop , asyncHandle, asyncUVHandleCheckQueue);
549- uv_async_send (asyncHandle);
581+ uvErrorCheck ( uv_async_init (mUVLoop , asyncHandle, asyncUVHandleCheckQueue) );
582+ uvErrorCheck ( uv_async_send (asyncHandle) );
550583}
551584
552585} // namespace o2
0 commit comments