[windows] Fix MAC Address Discovery
[xbmc.git] / xbmc / filesystem / DllLibCurl.cpp
blobc2c215a08e76c2a782f3cba0594e048fb7220e5c
1 /*
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.
7 */
9 #include "DllLibCurl.h"
11 #include "threads/SystemClock.h"
12 #include "utils/log.h"
14 #include <assert.h>
15 #include <mutex>
17 namespace XCURL
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()
126 for (auto& session : m_sessions)
128 if (session.m_multi && session.m_easy)
129 multi_remove_handle(session.m_multi, session.m_easy);
130 if (session.m_easy)
131 easy_cleanup(session.m_easy);
132 if (session.m_multi)
133 multi_cleanup(session.m_multi);
135 // close libcurl
136 curl_global_cleanup();
139 void DllLibCurlGlobal::CheckIdle()
141 std::unique_lock<CCriticalSection> lock(m_critSection);
142 /* 20 seconds idle time before closing handle */
143 const unsigned int idletime = 30000;
145 VEC_CURLSESSIONS::iterator it = m_sessions.begin();
146 while (it != m_sessions.end())
148 auto now = std::chrono::steady_clock::now();
149 auto duration =
150 std::chrono::duration_cast<std::chrono::milliseconds>(now - it->m_idletimestamp);
152 if (!it->m_busy && duration.count() > idletime)
154 CLog::Log(LOGDEBUG, "{} - Closing session to {}://{} (easy={}, multi={})", __FUNCTION__,
155 it->m_protocol, it->m_hostname, fmt::ptr(it->m_easy), fmt::ptr(it->m_multi));
157 if (it->m_multi && it->m_easy)
158 multi_remove_handle(it->m_multi, it->m_easy);
159 if (it->m_easy)
160 easy_cleanup(it->m_easy);
161 if (it->m_multi)
162 multi_cleanup(it->m_multi);
164 it = m_sessions.erase(it);
165 continue;
167 ++it;
171 void DllLibCurlGlobal::easy_acquire(const char* protocol,
172 const char* hostname,
173 CURL_HANDLE** easy_handle,
174 CURLM** multi_handle)
176 assert(easy_handle != NULL);
178 std::unique_lock<CCriticalSection> lock(m_critSection);
180 for (auto& it : m_sessions)
182 if (!it.m_busy)
184 /* allow reuse of requester is trying to connect to same host */
185 /* curl will take care of any differences in username/password */
186 if (it.m_protocol.compare(protocol) == 0 && it.m_hostname.compare(hostname) == 0)
188 it.m_busy = true;
189 if (easy_handle)
191 if (!it.m_easy)
192 it.m_easy = easy_init();
194 *easy_handle = it.m_easy;
197 if (multi_handle)
199 if (!it.m_multi)
200 it.m_multi = multi_init();
202 *multi_handle = it.m_multi;
205 return;
210 SSession session = {};
211 session.m_busy = true;
212 session.m_protocol = protocol;
213 session.m_hostname = hostname;
215 if (easy_handle)
217 session.m_easy = easy_init();
218 *easy_handle = session.m_easy;
221 if (multi_handle)
223 session.m_multi = multi_init();
224 *multi_handle = session.m_multi;
227 m_sessions.push_back(session);
229 CLog::Log(LOGDEBUG, "{} - Created session to {}://{}", __FUNCTION__, protocol, hostname);
232 void DllLibCurlGlobal::easy_release(CURL_HANDLE** easy_handle, CURLM** multi_handle)
234 std::unique_lock<CCriticalSection> lock(m_critSection);
236 CURL_HANDLE* easy = NULL;
237 CURLM* multi = NULL;
239 if (easy_handle)
241 easy = *easy_handle;
242 *easy_handle = NULL;
245 if (multi_handle)
247 multi = *multi_handle;
248 *multi_handle = NULL;
251 for (auto& it : m_sessions)
253 if (it.m_easy == easy && (multi == nullptr || it.m_multi == multi))
255 /* reset session so next caller doesn't reuse options, only connections */
256 /* will reset verbose too so it won't print that it closed connections on cleanup*/
257 easy_reset(easy);
258 it.m_busy = false;
259 it.m_idletimestamp = std::chrono::steady_clock::now();
260 return;
265 CURL_HANDLE* DllLibCurlGlobal::easy_duphandle(CURL_HANDLE* easy_handle)
267 std::unique_lock<CCriticalSection> lock(m_critSection);
269 for (const auto& it : m_sessions)
271 if (it.m_easy == easy_handle)
273 SSession session = it;
274 session.m_easy = DllLibCurl::easy_duphandle(easy_handle);
275 m_sessions.push_back(session);
276 return session.m_easy;
279 return DllLibCurl::easy_duphandle(easy_handle);
282 void DllLibCurlGlobal::easy_duplicate(CURL_HANDLE* easy,
283 const CURLM* multi,
284 CURL_HANDLE** easy_out,
285 CURLM** multi_out)
287 std::unique_lock<CCriticalSection> lock(m_critSection);
289 if (easy_out && easy)
290 *easy_out = DllLibCurl::easy_duphandle(easy);
292 if (multi_out && multi)
293 *multi_out = DllLibCurl::multi_init();
295 for (const auto& it : m_sessions)
297 if (it.m_easy == easy)
299 SSession session = it;
300 if (easy_out && easy)
301 session.m_easy = *easy_out;
302 else
303 session.m_easy = NULL;
305 if (multi_out && multi)
306 session.m_multi = *multi_out;
307 else
308 session.m_multi = NULL;
310 m_sessions.push_back(session);
311 return;
315 } // namespace XCURL