2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "DllLibCurl.h"
11 #include "threads/SystemClock.h"
12 #include "utils/log.h"
19 CURLcode
DllLibCurl::global_init(long flags
)
21 return curl_global_init(flags
);
24 void DllLibCurl::global_cleanup()
26 curl_global_cleanup();
29 CURL_HANDLE
* DllLibCurl::easy_init()
31 return curl_easy_init();
34 CURLcode
DllLibCurl::easy_perform(CURL_HANDLE
* handle
)
36 return curl_easy_perform(handle
);
39 CURLcode
DllLibCurl::easy_pause(CURL_HANDLE
* handle
, int bitmask
)
41 return curl_easy_pause(handle
, bitmask
);
44 void DllLibCurl::easy_reset(CURL_HANDLE
* handle
)
46 curl_easy_reset(handle
);
49 void DllLibCurl::easy_cleanup(CURL_HANDLE
* handle
)
51 curl_easy_cleanup(handle
);
54 CURL_HANDLE
* DllLibCurl::easy_duphandle(CURL_HANDLE
* handle
)
56 return curl_easy_duphandle(handle
);
59 CURLM
* DllLibCurl::multi_init()
61 return curl_multi_init();
64 CURLMcode
DllLibCurl::multi_add_handle(CURLM
* multi_handle
, CURL_HANDLE
* easy_handle
)
66 return curl_multi_add_handle(multi_handle
, easy_handle
);
69 CURLMcode
DllLibCurl::multi_perform(CURLM
* multi_handle
, int* running_handles
)
71 return curl_multi_perform(multi_handle
, running_handles
);
74 CURLMcode
DllLibCurl::multi_remove_handle(CURLM
* multi_handle
, CURL_HANDLE
* easy_handle
)
76 return curl_multi_remove_handle(multi_handle
, easy_handle
);
79 CURLMcode
DllLibCurl::multi_fdset(
80 CURLM
* multi_handle
, fd_set
* read_fd_set
, fd_set
* write_fd_set
, fd_set
* exc_fd_set
, int* max_fd
)
82 return curl_multi_fdset(multi_handle
, read_fd_set
, write_fd_set
, exc_fd_set
, max_fd
);
85 CURLMcode
DllLibCurl::multi_timeout(CURLM
* multi_handle
, long* timeout
)
87 return curl_multi_timeout(multi_handle
, timeout
);
90 CURLMsg
* DllLibCurl::multi_info_read(CURLM
* multi_handle
, int* msgs_in_queue
)
92 return curl_multi_info_read(multi_handle
, msgs_in_queue
);
95 CURLMcode
DllLibCurl::multi_cleanup(CURLM
* handle
)
97 return curl_multi_cleanup(handle
);
100 curl_slist
* DllLibCurl::slist_append(curl_slist
* list
, const char* to_append
)
102 return curl_slist_append(list
, to_append
);
105 void DllLibCurl::slist_free_all(curl_slist
* list
)
107 curl_slist_free_all(list
);
110 const char* DllLibCurl::easy_strerror(CURLcode code
)
112 return curl_easy_strerror(code
);
115 DllLibCurlGlobal::DllLibCurlGlobal()
117 /* we handle this ourself */
118 if (curl_global_init(CURL_GLOBAL_ALL
))
120 CLog::Log(LOGERROR
, "Error initializing libcurl");
124 DllLibCurlGlobal::~DllLibCurlGlobal()
127 curl_global_cleanup();
130 void DllLibCurlGlobal::CheckIdle()
132 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
133 /* 20 seconds idle time before closing handle */
134 const unsigned int idletime
= 30000;
136 VEC_CURLSESSIONS::iterator it
= m_sessions
.begin();
137 while (it
!= m_sessions
.end())
139 auto now
= std::chrono::steady_clock::now();
141 std::chrono::duration_cast
<std::chrono::milliseconds
>(now
- it
->m_idletimestamp
);
143 if (!it
->m_busy
&& duration
.count() > idletime
)
145 CLog::Log(LOGDEBUG
, "{} - Closing session to {}://{} (easy={}, multi={})", __FUNCTION__
,
146 it
->m_protocol
, it
->m_hostname
, fmt::ptr(it
->m_easy
), fmt::ptr(it
->m_multi
));
148 if (it
->m_multi
&& it
->m_easy
)
149 multi_remove_handle(it
->m_multi
, it
->m_easy
);
151 easy_cleanup(it
->m_easy
);
153 multi_cleanup(it
->m_multi
);
155 it
= m_sessions
.erase(it
);
162 void DllLibCurlGlobal::easy_acquire(const char* protocol
,
163 const char* hostname
,
164 CURL_HANDLE
** easy_handle
,
165 CURLM
** multi_handle
)
167 assert(easy_handle
!= NULL
);
169 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
171 for (auto& it
: m_sessions
)
175 /* allow reuse of requester is trying to connect to same host */
176 /* curl will take care of any differences in username/password */
177 if (it
.m_protocol
.compare(protocol
) == 0 && it
.m_hostname
.compare(hostname
) == 0)
183 it
.m_easy
= easy_init();
185 *easy_handle
= it
.m_easy
;
191 it
.m_multi
= multi_init();
193 *multi_handle
= it
.m_multi
;
201 SSession session
= {};
202 session
.m_busy
= true;
203 session
.m_protocol
= protocol
;
204 session
.m_hostname
= hostname
;
208 session
.m_easy
= easy_init();
209 *easy_handle
= session
.m_easy
;
214 session
.m_multi
= multi_init();
215 *multi_handle
= session
.m_multi
;
218 m_sessions
.push_back(session
);
220 CLog::Log(LOGDEBUG
, "{} - Created session to {}://{}", __FUNCTION__
, protocol
, hostname
);
223 void DllLibCurlGlobal::easy_release(CURL_HANDLE
** easy_handle
, CURLM
** multi_handle
)
225 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
227 CURL_HANDLE
* easy
= NULL
;
238 multi
= *multi_handle
;
239 *multi_handle
= NULL
;
242 for (auto& it
: m_sessions
)
244 if (it
.m_easy
== easy
&& (multi
== nullptr || it
.m_multi
== multi
))
246 /* reset session so next caller doesn't reuse options, only connections */
247 /* will reset verbose too so it won't print that it closed connections on cleanup*/
250 it
.m_idletimestamp
= std::chrono::steady_clock::now();
256 CURL_HANDLE
* DllLibCurlGlobal::easy_duphandle(CURL_HANDLE
* easy_handle
)
258 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
260 for (const auto& it
: m_sessions
)
262 if (it
.m_easy
== easy_handle
)
264 SSession session
= it
;
265 session
.m_easy
= DllLibCurl::easy_duphandle(easy_handle
);
266 m_sessions
.push_back(session
);
267 return session
.m_easy
;
270 return DllLibCurl::easy_duphandle(easy_handle
);
273 void DllLibCurlGlobal::easy_duplicate(CURL_HANDLE
* easy
,
275 CURL_HANDLE
** easy_out
,
278 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
280 if (easy_out
&& easy
)
281 *easy_out
= DllLibCurl::easy_duphandle(easy
);
283 if (multi_out
&& multi
)
284 *multi_out
= DllLibCurl::multi_init();
286 for (const auto& it
: m_sessions
)
288 if (it
.m_easy
== easy
)
290 SSession session
= it
;
291 if (easy_out
&& easy
)
292 session
.m_easy
= *easy_out
;
294 session
.m_easy
= NULL
;
296 if (multi_out
&& multi
)
297 session
.m_multi
= *multi_out
;
299 session
.m_multi
= NULL
;
301 m_sessions
.push_back(session
);