RDK Documentation (Open Sourced RDK Components)
AampCurlStore.cpp
Go to the documentation of this file.
1 /*
2  * If not stated otherwise in this file or this component's license file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2022 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 
20 /**
21  * @file AampCurlStore.cpp
22  * @brief Advanced Adaptive Media Player (AAMP) Curl store
23  */
24 
25 #include "AampCurlStore.h"
26 #include "AampDefine.h"
27 
28 #define CURL_EASY_SETOPT(curl, CURLoption, option)\
29  if (curl_easy_setopt(curl, CURLoption, option) != 0) {\
30  logprintf("Failed at curl_easy_setopt ");\
31  } //CID:132698,135078 - checked return
32 
33 // Curl callback functions
34 static pthread_mutex_t gCurlShMutex = PTHREAD_MUTEX_INITIALIZER;
35 /**
36  * @brief
37  * @param curl ptr to CURL instance
38  * @param data curl data lock
39  * @param acess curl access lock
40  * @param user_ptr CurlCallbackContext pointer
41  * @retval void
42  */
43 static void curl_lock_callback(CURL *curl, curl_lock_data data, curl_lock_access access, void *user_ptr)
44 {
45  pthread_mutex_t *pCurlShareLock = NULL;
46  CurlDataShareLock *locks =(CurlDataShareLock *)user_ptr;
47 
48  (void)access; /* unused */
49  (void)curl; /* unused */
50 
51  if(locks)
52  {
53  switch ( data )
54  {
55  case CURL_LOCK_DATA_DNS:
56  pCurlShareLock = &(locks->mDnsCurlShareMutex);
57  break;
58  case CURL_LOCK_DATA_SSL_SESSION:
59  pCurlShareLock = &(locks->mSslCurlShareMutex);
60  break;
61 
62  default:
63  pCurlShareLock = &(locks->mCurlSharedlock);
64  break;
65  }
66 
67  pthread_mutex_lock(pCurlShareLock);
68  }
69  else
70  {
71  pthread_mutex_lock(&gCurlShMutex);
72  }
73 }
74 
75 /**
76  * @brief
77  * @param curl ptr to CURL instance
78  * @param data curl data lock
79  * @param acess curl access lock
80  * @param user_ptr CurlCallbackContext pointer
81  * @retval void
82  */
83 static void curl_unlock_callback(CURL *curl, curl_lock_data data, void *user_ptr)
84 {
85  pthread_mutex_t *pCurlShareLock = NULL;
86  CurlDataShareLock *locks =(CurlDataShareLock *)user_ptr;
87 
88  (void)curl; /* unused */
89 
90  if(locks)
91  {
92  switch ( data )
93  {
94  case CURL_LOCK_DATA_DNS:
95  pCurlShareLock = &(locks->mDnsCurlShareMutex);
96  break;
97  case CURL_LOCK_DATA_SSL_SESSION:
98  pCurlShareLock = &(locks->mSslCurlShareMutex);
99  break;
100 
101  default:
102  pCurlShareLock = &(locks->mCurlSharedlock);
103  break;
104  }
105 
106  pthread_mutex_unlock(pCurlShareLock);
107  }
108  else
109  {
110  pthread_mutex_unlock(&gCurlShMutex);
111  }
112 }
113 
114 /**
115  * @brief write callback to be used by CURL
116  * @param ptr pointer to buffer containing the data
117  * @param size size of the buffer
118  * @param nmemb number of bytes
119  * @param userdata CurlCallbackContext pointer
120  * @retval size consumed or 0 if interrupted
121  */
122 static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
123 {
124  size_t ret = 0;
125  CurlCallbackContext *context = (CurlCallbackContext *)userdata;
126  if(context)
127  {
128  ret = context->aamp->HandleSSLWriteCallback( ptr, size, nmemb, userdata);
129  }
130  return ret;
131 }
132 
133 /**
134  * @brief callback invoked on http header by curl
135  * @param ptr pointer to buffer containing the data
136  * @param size size of the buffer
137  * @param nmemb number of bytes
138  * @param user_data CurlCallbackContext pointer
139  * @retval
140  */
141 static size_t header_callback(const char *ptr, size_t size, size_t nmemb, void *user_data)
142 {
143  size_t ret = 0;
144  CurlCallbackContext *context = static_cast<CurlCallbackContext *>(user_data);
145  if(context)
146  {
147  ret = context->aamp->HandleSSLHeaderCallback(ptr, size, nmemb, user_data);
148  }
149  return ret;
150 }
151 
152 /**
153  * @brief
154  * @param clientp app-specific as optionally set with CURLOPT_PROGRESSDATA
155  * @param dltotal total bytes expected to download
156  * @param dlnow downloaded bytes so far
157  * @param ultotal total bytes expected to upload
158  * @param ulnow uploaded bytes so far
159  * @retval
160  */
161 static int progress_callback(
162  void *clientp, // app-specific as optionally set with CURLOPT_PROGRESSDATA
163  double dltotal, // total bytes expected to download
164  double dlnow, // downloaded bytes so far
165  double ultotal, // total bytes expected to upload
166  double ulnow // uploaded bytes so far
167  )
168 {
169  int ret = 0;
170  CurlProgressCbContext *context = (CurlProgressCbContext *)clientp;
171 
172  if(context)
173  {
174  ret = context->aamp->HandleSSLProgressCallback ( clientp, dltotal, dlnow, ultotal, ulnow );
175  }
176  return ret;
177 }
178 
179 /**
180  * @brief
181  * @param curl ptr to CURL instance
182  * @param ssl_ctx SSL context used by CURL
183  * @param user_ptr data pointer set as param to CURLOPT_SSL_CTX_DATA
184  * @retval CURLcode CURLE_OK if no errors, otherwise corresponding CURL code
185  */
186 CURLcode ssl_callback(CURL *curl, void *ssl_ctx, void *user_ptr)
187 {
188  PrivateInstanceAAMP *context = (PrivateInstanceAAMP *)user_ptr;
189  AAMPLOG_TRACE("priv aamp :%p", context);
190  CURLcode rc = CURLE_OK;
191  pthread_mutex_lock(&context->mLock);
192  if (!context->mDownloadsEnabled)
193  {
194  rc = CURLE_ABORTED_BY_CALLBACK ; // CURLE_ABORTED_BY_CALLBACK
195  }
196  pthread_mutex_unlock(&context->mLock);
197  return rc;
198 }
199 
200 /**
201  * @brief
202  * @param handle ptr to CURL instance
203  * @param type type of data passed in the callback
204  * @param data data pointer, NOT null terminated
205  * @param size size of the data
206  * @param userp user pointer set with CURLOPT_DEBUGDATA
207  * @retval return 0
208  */
209 static int eas_curl_debug_callback(CURL *handle, curl_infotype type, char *data, size_t size, void *userp)
210 {
211  (void)handle;
212  (void)userp;
213  if(type == CURLINFO_TEXT || type == CURLINFO_HEADER_IN)
214  {
215  //limit log spam to only TEXT and HEADER_IN
216  size_t len = size;
217  while( len>0 && data[len-1]<' ' ) len--;
218  std::string printable(data,len);
219  switch (type)
220  {
221  case CURLINFO_TEXT:
222  AAMPLOG_WARN("curl: %s", printable.c_str() );
223  break;
224  case CURLINFO_HEADER_IN:
225  AAMPLOG_WARN("curl header: %s", printable.c_str() );
226  break;
227  default:
228  break; //CID:94999 - Resolve deadcode
229  }
230  }
231  return 0;
232 }
233 
234 /**
235  * @fn CreateCurlStore
236  * @brief CreateCurlStore - Create a new curl store for given host
237  */
238 CurlSocketStoreStruct *CurlStore::CreateCurlStore ( const std::string &hostname )
239 {
240  CurlSocketStoreStruct *CurlSock = new curlstorestruct();
241  CurlDataShareLock *locks = new curldatasharelock();
242  if ( NULL == CurlSock || NULL == locks )
243  {
244  AAMPLOG_WARN("Failed to alloc memory for curl store");
245  return NULL;
246  }
247 
248  CurlSock->timestamp = aamp_GetCurrentTimeMS();
249  CurlSock->pstShareLocks = locks;
250  CurlSock->mCurlStoreUserCount += 1;
251 
252  CURLSHcode sh;
253  CurlSock->mCurlShared = curl_share_init();
254  sh = curl_share_setopt(CurlSock->mCurlShared, CURLSHOPT_USERDATA, (void*)locks);
255  sh = curl_share_setopt(CurlSock->mCurlShared, CURLSHOPT_LOCKFUNC, curl_lock_callback);
256  sh = curl_share_setopt(CurlSock->mCurlShared, CURLSHOPT_UNLOCKFUNC, curl_unlock_callback);
257  sh = curl_share_setopt(CurlSock->mCurlShared, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
258  sh = curl_share_setopt(CurlSock->mCurlShared, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
259 
260  if ( umCurlSockDataStore.size() >= MaxCurlSockStore )
261  {
262  // Remove not recently used handle.
263  RemoveCurlSock();
264  }
265 
266  umCurlSockDataStore[hostname]=CurlSock;
267  AAMPLOG_INFO("Curl store for %s created, Added shared ctx %p in curlstore %p, size:%lu maxsize:%d", hostname.c_str(),
268  CurlSock->mCurlShared, CurlSock, umCurlSockDataStore.size(), MaxCurlSockStore);
269  return CurlSock;
270 }
271 
272 /**
273  * @fn GetCurlHandle
274  * @brief GetCurlHandle - Get a free curl easy handle for given url & curl index
275  */
276 CURL* CurlStore::GetCurlHandle(void *pAamp,std::string url, AampCurlInstance startIdx )
277 {
278  CURL * curl = NULL;
279  assert (startIdx <= eCURLINSTANCE_MAX);
280 
281  PrivateInstanceAAMP *aamp = (PrivateInstanceAAMP *)pAamp;
282  std::string HostName;
283  HostName = aamp_getHostFromURL ( url );
284 
286  {
287  GetFromCurlStore ( HostName, startIdx, &curl );
288  }
289  else
290  {
291  curl = curl_easy_init();
292  }
293 
294  return curl;
295 }
296 
297 /**
298  * @fn SaveCurlHandle
299  * @brief SaveCurlHandle - Save a curl easy handle for given host & curl index
300  */
301 void CurlStore::SaveCurlHandle (void *pAamp, std::string url, AampCurlInstance startIdx, CURL *curl )
302 {
303  assert (startIdx <= eCURLINSTANCE_MAX);
304 
305  PrivateInstanceAAMP *aamp = (PrivateInstanceAAMP *)pAamp;
306  std::string HostName;
307  HostName = aamp_getHostFromURL ( url );
308 
310  {
311  KeepInCurlStore ( HostName, startIdx, curl );
312  }
313  else
314  {
315  curl_easy_cleanup(curl);
316  }
317 }
318 
319 /**
320  * @fn CurlEasyInitWithOpt
321  * @brief CurlEasyInitWithOpt - Create a curl easy handle with set of aamp opts
322  */
323 CURL* CurlStore::CurlEasyInitWithOpt ( void *privContext, const std::string &proxyName, int instId )
324 {
325  PrivateInstanceAAMP *aamp = (PrivateInstanceAAMP *)privContext;
326  std::string UserAgentString;
327  UserAgentString=aamp->mConfig->GetUserAgentString();
328 
329  CURL *curlEasyhdl = curl_easy_init();
331  {
332  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_VERBOSE, 1L);
333  }
334  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_NOSIGNAL, 1L);
335  //curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); // unused
336  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_PROGRESSFUNCTION, progress_callback);
337  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_HEADERFUNCTION, header_callback);
338  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_WRITEFUNCTION, write_callback);
339  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_TIMEOUT, DEFAULT_CURL_TIMEOUT);
340  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_CONNECTTIMEOUT, DEFAULT_CURL_CONNECTTIMEOUT);
341  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
342  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_FOLLOWLOCATION, 1L);
343  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_NOPROGRESS, 0L); // enable progress meter (off by default)
344 
345  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_USERAGENT, UserAgentString.c_str());
346  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_ACCEPT_ENCODING, "");//Enable all the encoding formats supported by client
347  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_SSL_CTX_FUNCTION, ssl_callback); //Check for downloads disabled in btw ssl handshake
348  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_SSL_CTX_DATA, aamp);
349  long dns_cache_timeout = 3*60;
350  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_DNS_CACHE_TIMEOUT, dns_cache_timeout);
351  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_SHARE, aamp->mCurlShared);
352  //CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_TCP_KEEPALIVE, 1 );
353 
354  aamp->curlDLTimeout[instId] = DEFAULT_CURL_TIMEOUT * 1000;
355 
356  if (!proxyName.empty())
357  {
358  /* use this proxy */
359  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_PROXY, proxyName.c_str());
360  /* allow whatever auth the proxy speaks */
361  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
362  }
363 
364  if(aamp->IsEASContent())
365  {
366  //enable verbose logs so we can debug field issues
367  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_VERBOSE, 1);
368  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_DEBUGFUNCTION, eas_curl_debug_callback);
369  //set eas specific timeouts to handle faster cycling through bad hosts and faster total timeout
370  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_TIMEOUT, EAS_CURL_TIMEOUT);
371  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_CONNECTTIMEOUT, EAS_CURL_CONNECTTIMEOUT);
372 
373  aamp->curlDLTimeout[instId] = EAS_CURL_TIMEOUT * 1000;
374 
375  //on ipv6 box force curl to use ipv6 mode only (DELIA-20209)
376  struct stat tmpStat;
377  bool isv6(::stat( "/tmp/estb_ipv6", &tmpStat) == 0);
378  if(isv6)
379  {
380  CURL_EASY_SETOPT(curlEasyhdl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
381  }
382  AAMPLOG_WARN("aamp eas curl config: timeout=%ld, connecttimeout%ld, ipv6=%d", EAS_CURL_TIMEOUT, EAS_CURL_CONNECTTIMEOUT, isv6);
383  }
384  //log_current_time("curl initialized");
385 
386  return curlEasyhdl;
387 }
388 
389 /**
390  * @fn CurlInit
391  * @brief CurlInit - Initialize or get easy handles for given host & curl index from curl store
392  */
393 void CurlStore::CurlInit(void *privContext, AampCurlInstance startIdx, unsigned int instanceCount, std::string proxyName, const std::string &RemoteHost)
394 {
395  PrivateInstanceAAMP *aamp = (PrivateInstanceAAMP *)privContext;
396 
397  int instanceEnd = startIdx + instanceCount;
398  assert (instanceEnd <= eCURLINSTANCE_MAX);
399 
400  std::string HostName;
401  bool IsRemotehost = true, CurlFdHost=false;
402  AampCurlStoreErrorCode CurlStoreErrCode=eCURL_STORE_HOST_NOT_AVAILABLE;
403 
404  if(RemoteHost.size())
405  {
406  HostName = RemoteHost;
407  CurlFdHost = true;
408  }
409  else
410  {
411  HostName = aamp->mOrigManifestUrl.hostname;
412  IsRemotehost = aamp->mOrigManifestUrl.isRemotehost;
413  }
414 
415  if ( IsRemotehost )
416  {
418  {
419  AAMPLOG_INFO("Check curl store for host:%s inst:%d-%d Fds[%p:%p]\n", HostName.c_str(), startIdx, instanceEnd, aamp->curl[startIdx], aamp->curlhost[startIdx]->curl );
420  CurlStoreErrCode = GetFromCurlStoreBulk(HostName, startIdx, instanceEnd, aamp, CurlFdHost );
421  AAMPLOG_TRACE("From curl store for inst:%d-%d Fds[%p:%p] ShHdl:%p\n", startIdx, instanceEnd, aamp->curl[startIdx], aamp->curlhost[startIdx]->curl, aamp->mCurlShared );
422  }
423  else
424  {
425  if(NULL==aamp->mCurlShared)
426  {
427  aamp->mCurlShared = curl_share_init();
428  curl_share_setopt(aamp->mCurlShared, CURLSHOPT_USERDATA, (void*)NULL);
429  curl_share_setopt(aamp->mCurlShared, CURLSHOPT_LOCKFUNC, curl_lock_callback);
430  curl_share_setopt(aamp->mCurlShared, CURLSHOPT_UNLOCKFUNC, curl_unlock_callback);
431  curl_share_setopt(aamp->mCurlShared, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
432 
434  {
435  curl_share_setopt(aamp->mCurlShared, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
436  }
437  }
438  }
439  }
440 
441  if(eCURL_STORE_HOST_SOCK_AVAILABLE != CurlStoreErrCode)
442  {
443  CURL **CurlFd = NULL;
444  for (unsigned int i = startIdx; i < instanceEnd; i++)
445  {
446  if(CurlFdHost)
447  {
448  CurlFd = &aamp->curlhost[i]->curl;
449  }
450  else
451  {
452  CurlFd = &aamp->curl[i];
453  }
454 
455  if (NULL == *CurlFd )
456  {
457  *CurlFd = CurlEasyInitWithOpt(aamp, proxyName, i);
458  AAMPLOG_INFO("Created new curl handle:%p for inst:%d", *CurlFd, i );
459  }
460  }
461  }
462 }
463 
464 /**
465  * @fn CurlTerm
466  * @brief CurlTerm - Terminate or store easy handles in curlstore
467  */
468 void CurlStore::CurlTerm(void *privContext, AampCurlInstance startIdx, unsigned int instanceCount, const std::string &RemoteHost )
469 {
470  PrivateInstanceAAMP *aamp = (PrivateInstanceAAMP *)privContext;
471  int instanceEnd = startIdx + instanceCount;
472  std::string HostName;
473  bool IsRemotehost = true, CurlFdHost=false;
474 
475  if(RemoteHost.size())
476  {
477  HostName = RemoteHost;
478  CurlFdHost = true;
479  }
480  else
481  {
482  HostName = aamp->mOrigManifestUrl.hostname;
483  IsRemotehost = aamp->mOrigManifestUrl.isRemotehost;
484  }
485 
486  if( ISCONFIGSET(eAAMPConfig_EnableCurlStore) && ( IsRemotehost ))
487  {
488  AAMPLOG_INFO("Store unused curl handle:%p in Curlstore for inst:%d-%d", aamp->curl[startIdx], startIdx, instanceEnd );
489  KeepInCurlStoreBulk ( HostName, startIdx, instanceEnd, aamp, CurlFdHost);
491  }
492  else
493  {
494  for (unsigned int i = startIdx; i < instanceEnd; i++)
495  {
496  if (aamp->curl[i])
497  {
498  curl_easy_cleanup(aamp->curl[i]);
499  aamp->curl[i] = NULL;
500  aamp->curlDLTimeout[i] = 0;
501  }
502  }
503  }
504 }
505 
506 CurlStore* CurlStore::CurlInstance = NULL;
507 pthread_mutex_t CurlStore::mCurlInstLock = PTHREAD_MUTEX_INITIALIZER;
509 
510 /**
511  * @fn GetCurlStoreInstance
512  * @brief GetCurlStoreInstance - Get static curlstore singleton object
513  */
515 {
516  PrivateInstanceAAMP *aamp = (PrivateInstanceAAMP *)pContext;
517 
518  pthread_mutex_lock(&mCurlInstLock);
519  if ( NULL == CurlInstance )
520  {
521  int MaxSockStoreSize=0;
522  CurlInstance = new CurlStore();
523 
524  if ( NULL == CurlInstance )
525  {
526  AAMPLOG_WARN("Failed to alloc mem for Curl instance");
527  return NULL;
528  }
529 
530  GETCONFIGVALUE(eAAMPConfig_MaxCurlSockStore,MaxSockStoreSize);
531  if( MAX_CURL_SOCK_STORE != MaxSockStoreSize)
532  {
533  MaxCurlSockStore = MaxSockStoreSize;
534  }
535  AAMPLOG_INFO("Max sock store size:%d", MaxCurlSockStore);
536  }
537  pthread_mutex_unlock(&mCurlInstLock);
538  return CurlInstance;
539 }
540 
541 /**
542  * @fn GetCurlHandleFromFreeQ
543  * @brief GetCurlHandleFromFreeQ - Get curl handle from free queue
544  */
546 {
547  CURL *curlhdl = NULL;
548  long long MaxAge = CurlSock->timestamp-eCURL_MAX_AGE_TIME;
549 
550  for (int i = instId; i < instId+1 && !CurlSock->mFreeQ.empty(); )
551  {
552  CurlHandleStruct mObj = CurlSock->mFreeQ.front();
553 
554  if( MaxAge > mObj.eHdlTimestamp )
555  {
556  CurlSock->mFreeQ.pop_front();
557  AAMPLOG_TRACE("Remove old curl hdl:%p", mObj.curl);
558  curl_easy_cleanup(mObj.curl);
559  mObj.curl = NULL;
560  continue;
561  }
562 
563  if ( mObj.curlId == i )
564  {
565  CurlSock->mFreeQ.pop_front();
566  curlhdl = mObj.curl;
567  break;
568  }
569 
570  for(auto it=CurlSock->mFreeQ.begin()+1; it!=CurlSock->mFreeQ.end(); ++it)
571  {
572  if (( MaxAge < it->eHdlTimestamp ) && ( it->curlId == i ))
573  {
574  curlhdl=it->curl;
575  CurlSock->mFreeQ.erase(it);
576  break;
577  }
578  }
579 
580  ++i;
581  }
582 
583  return curlhdl;
584 }
585 
586 /**
587  * @fn GetFromCurlStoreBulk
588  * @brief GetFromCurlStoreBulk - Get free curl easy handle in bulk for given host & curl indices
589  */
590 AampCurlStoreErrorCode CurlStore::GetFromCurlStoreBulk ( const std::string &hostname, AampCurlInstance CurlIndex, int count, void *priv, bool CurlFdHost )
591 {
593  AampCurlStoreErrorCode ret = eCURL_STORE_HOST_SOCK_AVAILABLE;
594 
595  pthread_mutex_lock(&mCurlInstLock);
596  CurlSockDataIter it = umCurlSockDataStore.find(hostname);
597 
598  if (it != umCurlSockDataStore.end())
599  {
600  int CurlFdCount=0,loop=0;
601  CURL **CurlFd=NULL;
602  CurlSocketStoreStruct *CurlSock = it->second;
603  CurlSock->mCurlStoreUserCount += 1;
604  CurlSock->timestamp = aamp_GetCurrentTimeMS();
605  aamp->mCurlShared = CurlSock->mCurlShared;
606 
607  for( loop = (int)CurlIndex; loop < count; )
608  {
609  if(CurlFdHost)
610  {
611  CurlFd=&aamp->curlhost[loop]->curl;
612  }
613  else
614  {
615  CurlFd=&aamp->curl[loop];
616  }
617 
618  if (!CurlSock->mFreeQ.empty())
619  {
620  *CurlFd= GetCurlHandleFromFreeQ ( CurlSock, loop );
621  if(NULL!=*CurlFd)
622  {
623  CURL_EASY_SETOPT(*CurlFd, CURLOPT_SSL_CTX_DATA, aamp);
624  ++CurlFdCount;
625  }
626  else
627  {
628  ret = eCURL_STORE_SOCK_NOT_AVAILABLE;
629  }
630  ++loop;
631  }
632  else
633  {
634  AAMPLOG_TRACE("Queue is empty");
635  ret = eCURL_STORE_SOCK_NOT_AVAILABLE;
636  break;
637  }
638  }
639 
640  AAMPLOG_INFO ("%d fd(s) got from CurlStore User count:%d", CurlFdCount, CurlSock->mCurlStoreUserCount);
641 
642  if ( umCurlSockDataStore.size() > MaxCurlSockStore )
643  {
644  // Remove not recently used handle.
645  RemoveCurlSock();
646  }
647  }
648  else
649  {
650  AAMPLOG_TRACE("Curl Inst %d for %s not in store", CurlIndex, hostname.c_str());
651  ret = eCURL_STORE_HOST_NOT_AVAILABLE;
652 
653  CurlSocketStoreStruct *CurlSock = CreateCurlStore(hostname);
654 
655  if(NULL != CurlSock)
656  {
657  aamp->mCurlShared = CurlSock->mCurlShared;
658  }
659  }
660 
661  pthread_mutex_unlock(&mCurlInstLock);
662  return ret;
663 }
664 
665 /**
666  * @fn GetFromCurlStore
667  * @brief GetFromCurlStore - Get a free curl easy handle for given host & curl index
668  */
669 AampCurlStoreErrorCode CurlStore::GetFromCurlStore ( const std::string &hostname, AampCurlInstance CurlIndex, CURL **curl )
670 {
671  AampCurlStoreErrorCode ret = eCURL_STORE_HOST_SOCK_AVAILABLE;
672  CurlSocketStoreStruct *CurlSock = NULL;
673  *curl = NULL;
674 
675  pthread_mutex_lock(&mCurlInstLock);
676  CurlSockDataIter it = umCurlSockDataStore.find(hostname);
677 
678  if (it != umCurlSockDataStore.end())
679  {
680  CurlSock = it->second;
681  CurlSock->mCurlStoreUserCount += 1;
682  CurlSock->timestamp = aamp_GetCurrentTimeMS();
683  long long MaxAge = CurlSock->timestamp-eCURL_MAX_AGE_TIME;
684 
685  for( int loop = (int)CurlIndex; loop < CurlIndex+1; )
686  {
687  if (!CurlSock->mFreeQ.empty())
688  {
689  *curl = GetCurlHandleFromFreeQ ( CurlSock, loop);
690 
691  if(NULL==*curl)
692  {
693  ret = eCURL_STORE_SOCK_NOT_AVAILABLE;
694  }
695  ++loop;
696  }
697  else
698  {
699  AAMPLOG_TRACE("Queue is empty");
700  ret = eCURL_STORE_SOCK_NOT_AVAILABLE;
701  break;
702  }
703  }
704  }
705 
706  if ( NULL == *curl )
707  {
708  AAMPLOG_TRACE("Curl Inst %d for %s not available", CurlIndex, hostname.c_str());
709 
710  if(NULL == CurlSock)
711  {
712  ret = eCURL_STORE_HOST_NOT_AVAILABLE;
713 
714  CurlSock = CreateCurlStore(hostname);
715  }
716 
717  *curl = curl_easy_init();
718  CURL_EASY_SETOPT(*curl, CURLOPT_SHARE, CurlSock->mCurlShared);
719  }
720 
721  pthread_mutex_unlock(&mCurlInstLock);
722  return ret;
723 }
724 
725 /**
726  * @fn KeepInCurlStoreBulk
727  * @brief KeepInCurlStoreBulk - Store curl easy handle in bulk for given host & curl index
728  */
729 void CurlStore::KeepInCurlStoreBulk ( const std::string &hostname, AampCurlInstance CurlIndex, int count, void *priv, bool CurlFdHost )
730 {
732  CurlSocketStoreStruct *CurlSock = NULL;
733 
734  pthread_mutex_lock(&mCurlInstLock);
735  CurlSockDataIter it = umCurlSockDataStore.find(hostname);
736 
737  if(it != umCurlSockDataStore.end())
738  {
739  CurlSock = it->second;
740  CurlSock->timestamp = aamp_GetCurrentTimeMS();
741  CurlSock->mCurlStoreUserCount -= 1;
742 
743  for( int loop = (int)CurlIndex; loop < count; ++loop)
744  {
745  CurlHandleStruct mObj;
746  if(CurlFdHost)
747  {
748  mObj.curl = aamp->curlhost[loop]->curl;
749  aamp->curlhost[loop]->curl = NULL;
750  }
751  else
752  {
753  mObj.curl = aamp->curl[loop];
754  aamp->curl[loop] = NULL;
755  }
756 
757  mObj.eHdlTimestamp = CurlSock->timestamp;
758  mObj.curlId = loop;
759  CurlSock->mFreeQ.push_back(mObj);
760  AAMPLOG_TRACE("Curl Inst %d CurlCtx:%p stored at %lu", loop, mObj.curl, CurlSock->mFreeQ.size());
761  }
762 
763  AAMPLOG_TRACE ("CurlStore User count:%d for:%s", CurlSock->mCurlStoreUserCount, hostname.c_str());
764  if ( umCurlSockDataStore.size() > MaxCurlSockStore )
765  {
766  // Remove not recently used handle.
767  RemoveCurlSock();
768  }
769  }
770  else
771  {
772  AAMPLOG_INFO("Host %s not in store, Curl Inst %d-%d", hostname.c_str(), CurlIndex,count);
773  }
774 
775  pthread_mutex_unlock(&mCurlInstLock);
776 }
777 
778 /**
779  * @fn KeepInCurlStore
780  * @brief KeepInCurlStore - Store a curl easy handle for given host & curl index
781  */
782 void CurlStore::KeepInCurlStore ( const std::string &hostname, AampCurlInstance CurlIndex, CURL *curl )
783 {
784  CurlSocketStoreStruct *CurlSock = NULL;
785  pthread_mutex_lock(&mCurlInstLock);
786  CurlSockDataIter it = umCurlSockDataStore.find(hostname);
787  if(it != umCurlSockDataStore.end())
788  {
789  CurlSock = it->second;
790  CurlSock->timestamp = aamp_GetCurrentTimeMS();
791  CurlSock->mCurlStoreUserCount -= 1;
792 
793  CurlHandleStruct mObj;
794  mObj.curl = curl;
795  mObj.eHdlTimestamp = CurlSock->timestamp;
796  mObj.curlId = (int)CurlIndex;
797  CurlSock->mFreeQ.push_back(mObj);
798  AAMPLOG_TRACE("Curl Inst %d for %s CurlCtx:%p stored at %lu, User:%d", CurlIndex, hostname.c_str(),
799  curl,CurlSock->mFreeQ.size(), CurlSock->mCurlStoreUserCount);
800  }
801  else
802  {
803  AAMPLOG_INFO("Host %s not in store, Curlfd:%p", hostname.c_str(), curl);
804  }
805  pthread_mutex_unlock(&mCurlInstLock);
806 }
807 
808 /**
809  * @fn RemoveCurlSock
810  * @brief RemoveCurlSock - Remove not recently used entry from curl store
811  */
813 {
814  unsigned long long time=aamp_GetCurrentTimeMS() + 1;
815 
816  CurlSockDataIter it=umCurlSockDataStore.begin();
817  CurlSockDataIter RemIt=umCurlSockDataStore.end();
818 
819  for(; it != umCurlSockDataStore.end(); ++it )
820  {
821  CurlSocketStoreStruct *CurlSock = it->second;
822  if( !CurlSock->mCurlStoreUserCount && ( time > CurlSock->timestamp ) )
823  {
824  time = CurlSock->timestamp;
825  RemIt = it;
826  }
827  }
828 
829  if( umCurlSockDataStore.end() != RemIt )
830  {
831  CurlSocketStoreStruct *RmCurlSock = RemIt->second;
832  AAMPLOG_INFO("Removing host:%s lastused:%lld UserCount:%d", (RemIt->first).c_str(), RmCurlSock->timestamp, RmCurlSock->mCurlStoreUserCount);
833 
834  for(auto it = RmCurlSock->mFreeQ.begin(); it != RmCurlSock->mFreeQ.end(); )
835  {
836  if(it->curl)
837  {
838  curl_easy_cleanup(it->curl);
839  }
840  it=RmCurlSock->mFreeQ.erase(it);
841  }
842  std::deque<CurlHandleStruct>().swap(RmCurlSock->mFreeQ);
843 
844  if(RmCurlSock->mCurlShared)
845  {
846  CurlDataShareLock *locks = RmCurlSock->pstShareLocks;
847  curl_share_cleanup(RmCurlSock->mCurlShared);
848 
849  pthread_mutex_destroy(&locks->mCurlSharedlock);
850  pthread_mutex_destroy(&locks->mDnsCurlShareMutex);
851  pthread_mutex_destroy(&locks->mSslCurlShareMutex);
852  SAFE_DELETE(RmCurlSock->pstShareLocks);
853  }
854 
855  SAFE_DELETE(RmCurlSock);
856  umCurlSockDataStore.erase(RemIt);
857 
859  }
860  else
861  {
862  /**
863  * Lets extend the size of curlstore, since all entries are busy..
864  * Later it will get shrunk to user configured size.
865  */
866  }
867 }
868 
869 /**
870  * @fn ShowCurlStoreData
871  * @brief ShowCurlStoreData - Print curl store details
872  */
873 void CurlStore::ShowCurlStoreData ( bool trace )
874 {
875  if(trace)
876  {
877  AAMPLOG_INFO("Curl Store Size:%lu, MaxSize:%d", umCurlSockDataStore.size(), MaxCurlSockStore);
878 
879  CurlSockDataIter it=umCurlSockDataStore.begin();
880  for(int loop=1; it != umCurlSockDataStore.end(); ++it,++loop )
881  {
882  CurlSocketStoreStruct *CurlSock = it->second;
883  AAMPLOG_INFO("%d.Host:%s ShHdl:%p LastUsed:%lld UserCount:%d", loop, (it->first).c_str(), CurlSock->mCurlShared, CurlSock->timestamp, CurlSock->mCurlStoreUserCount);
884  AAMPLOG_INFO("%d.Total Curl fds:%lu,", loop, CurlSock->mFreeQ.size());
885 
886  for(auto it = CurlSock->mFreeQ.begin(); it != CurlSock->mFreeQ.end(); ++it)
887  {
888  AAMPLOG_TRACE("CurlFd:%p Time:%lld Inst:%d", it->curl, it->eHdlTimestamp, it->curlId);
889  }
890  }
891  }
892 }
PrivateInstanceAAMP::IsEASContent
bool IsEASContent()
Checking whether EAS content or not.
Definition: priv_aamp.h:1712
AampDefine.h
Macros for Aamp.
CurlProgressCbContext
context during curl progress callbacks
Definition: AampCurlStore.h:263
curlstruct
Definition: AampCurlStore.h:65
EAS_CURL_TIMEOUT
#define EAS_CURL_TIMEOUT
Definition: priv_aamp.h:74
CurlStore::CurlTerm
void CurlTerm(void *privContext, AampCurlInstance startIdx, unsigned int instanceCount, const std::string &remotehost=std::string(""))
Definition: AampCurlStore.cpp:468
eAAMPConfig_EnableCurlStore
@ eAAMPConfig_EnableCurlStore
Definition: AampConfig.h:200
ISCONFIGSET
#define ISCONFIGSET(x)
Definition: AampConfig.h:84
CurlStore::CurlInit
void CurlInit(void *privContext, AampCurlInstance startIdx, unsigned int instanceCount, std::string proxyName, const std::string &remotehost=std::string(""))
Definition: AampCurlStore.cpp:393
eAAMPConfig_EnableSharedSSLSession
@ eAAMPConfig_EnableSharedSSLSession
Definition: AampConfig.h:182
PrivateInstanceAAMP::curlDLTimeout
long curlDLTimeout[eCURLINSTANCE_MAX]
Definition: priv_aamp.h:1022
CurlStore::GetFromCurlStore
AampCurlStoreErrorCode GetFromCurlStore(const std::string &hostname, AampCurlInstance CurlIndex, CURL **curl)
Definition: AampCurlStore.cpp:669
curldatasharelock
locks used when lock/unlock callback occurs for different shared data
Definition: AampCurlStore.h:51
CurlStore::MaxCurlSockStore
static int MaxCurlSockStore
Definition: AampCurlStore.h:105
CurlStore::CurlEasyInitWithOpt
CURL * CurlEasyInitWithOpt(void *privContext, const std::string &proxyName, int instId)
Definition: AampCurlStore.cpp:323
DEFAULT_CURL_CONNECTTIMEOUT
#define DEFAULT_CURL_CONNECTTIMEOUT
Definition: priv_aamp.h:73
CurlStore::GetCurlHandleFromFreeQ
CURL * GetCurlHandleFromFreeQ(CurlSocketStoreStruct *CurlSock, int instId)
Definition: AampCurlStore.cpp:545
CurlStore::RemoveCurlSock
void RemoveCurlSock(void)
Definition: AampCurlStore.cpp:812
DEFAULT_CURL_TIMEOUT
#define DEFAULT_CURL_TIMEOUT
Definition: priv_aamp.h:72
eas_curl_debug_callback
static int eas_curl_debug_callback(CURL *handle, curl_infotype type, char *data, size_t size, void *userp)
Definition: AampCurlStore.cpp:209
curl_unlock_callback
static void curl_unlock_callback(CURL *curl, curl_lock_data data, void *user_ptr)
Definition: AampCurlStore.cpp:83
PrivateInstanceAAMP::mOrigManifestUrl
AampURLInfoStruct mOrigManifestUrl
Definition: priv_aamp.h:836
write_callback
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
write callback to be used by CURL
Definition: AampCurlStore.cpp:122
CurlCallbackContext
context during curl callbacks
Definition: AampCurlStore.h:232
aamp_IsLocalHost
bool aamp_IsLocalHost(std::string Hostname)
check is local or not from given hostname
Definition: AampUtils.cpp:267
eCURL_MAX_AGE_TIME
#define eCURL_MAX_AGE_TIME
Definition: AampCurlStore.h:34
eAAMPConfig_CurlLogging
@ eAAMPConfig_CurlLogging
Definition: AampConfig.h:143
curl_lock_callback
static void curl_lock_callback(CURL *curl, curl_lock_data data, curl_lock_access access, void *user_ptr)
Definition: AampCurlStore.cpp:43
CurlStore::CreateCurlStore
CurlSocketStoreStruct * CreateCurlStore(const std::string &hostname)
Definition: AampCurlStore.cpp:238
aamp_getHostFromURL
std::string aamp_getHostFromURL(std::string url)
Extract host string from url.
Definition: AampUtils.cpp:232
CurlStore::KeepInCurlStoreBulk
void KeepInCurlStoreBulk(const std::string &hostname, AampCurlInstance CurlIndex, int count, void *priv, bool HostCurlFd)
Definition: AampCurlStore.cpp:729
eAAMPConfig_MaxCurlSockStore
@ eAAMPConfig_MaxCurlSockStore
Definition: AampConfig.h:264
CurlStore::GetCurlHandle
CURL * GetCurlHandle(void *pAamp, std::string url, AampCurlInstance startIdx)
Definition: AampCurlStore.cpp:276
AAMPLOG_TRACE
#define AAMPLOG_TRACE(FORMAT,...)
AAMP logging defines, this can be enabled through setLogLevel() as per the need.
Definition: AampLogManager.h:83
AampCurlInstance
AampCurlInstance
Enumeration for Curl Instances.
Definition: priv_aamp.h:156
eCURLINSTANCE_MAX
@ eCURLINSTANCE_MAX
Definition: priv_aamp.h:166
PrivateInstanceAAMP
Class representing the AAMP player's private instance, which is not exposed to outside world.
Definition: priv_aamp.h:640
header_callback
static size_t header_callback(const char *ptr, size_t size, size_t nmemb, void *user_data)
callback invoked on http header by curl
Definition: AampCurlStore.cpp:141
eAAMPConfig_TraceLogging
@ eAAMPConfig_TraceLogging
Definition: AampConfig.h:138
ssl_callback
CURLcode ssl_callback(CURL *curl, void *ssl_ctx, void *user_ptr)
Definition: AampCurlStore.cpp:186
CurlStore::GetCurlStoreInstance
static CurlStore * GetCurlStoreInstance(void *pContext)
Definition: AampCurlStore.cpp:514
progress_callback
static int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
Definition: AampCurlStore.cpp:161
AampCurlStore.h
Advanced Adaptive Media Player (AAMP) Curl store.
aamp_GetCurrentTimeMS
long long aamp_GetCurrentTimeMS(void)
Get current time from epoch is milliseconds.
Definition: AampUtils.cpp:92
CurlStore::KeepInCurlStore
void KeepInCurlStore(const std::string &hostname, AampCurlInstance CurlIndex, CURL *curl)
Definition: AampCurlStore.cpp:782
CurlStore::GetFromCurlStoreBulk
AampCurlStoreErrorCode GetFromCurlStoreBulk(const std::string &hostname, AampCurlInstance CurlIndex, int count, void *priv, bool HostCurlFd)
Definition: AampCurlStore.cpp:590
EAS_CURL_CONNECTTIMEOUT
#define EAS_CURL_CONNECTTIMEOUT
Definition: priv_aamp.h:75
AampCurlStoreErrorCode
AampCurlStoreErrorCode
Error codes returned by curlstore.
Definition: AampCurlStore.h:40
MAX_CURL_SOCK_STORE
#define MAX_CURL_SOCK_STORE
Definition: AampDefine.h:119
CurlStore::ShowCurlStoreData
void ShowCurlStoreData(bool trace=true)
Definition: AampCurlStore.cpp:873
CurlStore
Singleton curlstore to save/reuse curl handles.
Definition: AampCurlStore.h:100
CurlStore::SaveCurlHandle
void SaveCurlHandle(void *pAamp, std::string url, AampCurlInstance startIdx, CURL *curl)
Definition: AampCurlStore.cpp:301
curlstorestruct
structure to store curl easy, shared handle & locks for a host
Definition: AampCurlStore.h:78