4 #include <zypp/zyppng/base/Timer> 5 #include <zypp/zyppng/base/SocketNotifier> 6 #include <zypp/zyppng/base/EventDispatcher> 14 using namespace boost;
18 NetworkRequestDispatcherPrivate::NetworkRequestDispatcherPrivate( )
19 : _timer(
Timer::create() )
20 , _multi ( curl_multi_init() )
25 curl_multi_setopt(
_multi, CURLMOPT_TIMERDATA, reinterpret_cast<void *>(
this ) );
27 curl_multi_setopt(
_multi, CURLMOPT_SOCKETDATA, reinterpret_cast<void *>(
this ) );
35 curl_multi_cleanup(
_multi );
42 assert( that !=
nullptr );
44 if ( timeout_ms >= 0 ) {
45 that->
_timer->start( static_cast<uint64_t>(timeout_ms) );
61 assert( that !=
nullptr );
67 std::shared_ptr<SocketNotifier> socketp;
70 if ( what == CURL_POLL_REMOVE || what == CURL_POLL_NONE )
83 if ( what == CURL_POLL_REMOVE || what == CURL_POLL_NONE )
89 void *privatePtr =
nullptr;
90 if ( curl_easy_getinfo( easy, CURLINFO_PRIVATE, &privatePtr ) != CURLE_OK ) {
101 DBG <<
"Cleaning up unassigned easy handle" << std::endl;
102 curl_multi_remove_handle(
_multi, easy );
103 curl_easy_cleanup( easy );
109 if ( what == CURL_POLL_REMOVE ) {
110 socketp->setEnabled(
false );
118 if ( what == CURL_POLL_IN ) {
120 }
else if ( what == CURL_POLL_OUT ) {
122 }
else if ( what == CURL_POLL_INOUT ) {
126 socketp->setEnabled();
134 evBitmask |= CURL_CSELECT_IN;
136 evBitmask |= CURL_CSELECT_OUT;
138 evBitmask |= CURL_CSELECT_ERR;
146 CURLMcode rc = curl_multi_socket_action(
_multi, nativeSocket, evBitmask, &running );
158 CURLMsg *msg =
nullptr;
159 while( (msg = curl_multi_info_read(
_multi, &msgs_left )) ) {
160 if(msg->msg == CURLMSG_DONE) {
161 CURL *easy = msg->easy_handle;
162 CURLcode res = msg->data.result;
164 void *privatePtr =
nullptr;
165 if ( curl_easy_getinfo( easy, CURLINFO_PRIVATE, &privatePtr ) != CURLE_OK )
170 DBG <<
"Cleaning up unassigned easy handle" << std::endl;
171 curl_multi_remove_handle(
_multi, easy );
172 curl_easy_cleanup( easy );
207 auto it = std::find_if( list.begin(), list.end(), [ &req ](
const std::shared_ptr<NetworkRequest> &r ) {
208 return req.d_func() == r->d_func();
210 if ( it != list.end() ) {
219 void *easyHandle = req.d_func()->_easyHandle;
221 curl_multi_remove_handle(
_multi, easyHandle );
224 req.d_func()->_dispatcher =
nullptr;
228 req.d_func()->setResult( std::move(result) );
247 std::string errBuf =
"Failed to initialize easy handle";
248 if ( !req->d_func()->initialize( errBuf ) ) {
255 CURLMcode rc = curl_multi_add_handle(
_multi, req->d_func()->_easyHandle );
262 req->d_func()->aboutToStart();
276 NetworkRequestDispatcher::NetworkRequestDispatcher( )
282 bool NetworkRequestDispatcher::supportsProtocol(
const Url &
url )
284 curl_version_info_data *curl_info =
nullptr;
285 curl_info = curl_version_info(CURLVERSION_NOW);
287 if (curl_info->protocols)
289 const char *
const *proto;
292 for(proto=curl_info->protocols; !found && *proto; ++proto) {
293 if( scheme == std::string((
const char *)*proto))
301 void NetworkRequestDispatcher::setMaximumConcurrentConnections(
size_t maxConn )
303 d_func()->_maxConnections = maxConn;
306 void NetworkRequestDispatcher::enqueue(
const std::shared_ptr<NetworkRequest> &req )
312 if ( std::find( d->_runningDownloads.begin(), d->_runningDownloads.end(), req ) != d->_runningDownloads.end() ) {
313 WAR <<
"Ignoring request to enqueue download " << req->url().asString() <<
" request is already running " << std::endl;
317 if ( std::find( d->_pendingDownloads.begin(), d->_pendingDownloads.end(), req ) != d->_pendingDownloads.end() ) {
318 WAR <<
"Ignoring request to enqueue download " << req->url().asString() <<
" request is already enqueued " << std::endl;
322 req->d_func()->_dispatcher =
this;
324 d->_pendingDownloads.push_back( req );
326 auto it = std::find_if( d->_pendingDownloads.begin(), d->_pendingDownloads.end(), [](
const auto &req ){
331 if ( it != d->_pendingDownloads.end() && it != d->_pendingDownloads.begin() )
333 d->_pendingDownloads.insert( it, req );
340 void NetworkRequestDispatcher::cancel( NetworkRequest &req, std::string reason )
345 void NetworkRequestDispatcher::cancel(NetworkRequest &req,
const NetworkRequestError &err)
349 if ( req.d_func()->_dispatcher != this ) {
354 d->setFinished( req, err );
357 void NetworkRequestDispatcher::run()
360 d->_isRunning =
true;
362 if ( d->_pendingDownloads.size() )
368 return d_func()->_lastError;
371 SignalProxy<void (NetworkRequestDispatcher &, NetworkRequest &)> NetworkRequestDispatcher::sigDownloadStarted()
373 return d_func()->_sigDownloadStarted;
376 SignalProxy<void (NetworkRequestDispatcher &, NetworkRequest &)> NetworkRequestDispatcher::sigDownloadFinished()
378 return d_func()->_sigDownloadFinished;
381 SignalProxy<void ( NetworkRequestDispatcher &)> NetworkRequestDispatcher::sigQueueFinished()
383 return d_func()->_sigQueueFinished;
386 SignalProxy<void ( NetworkRequestDispatcher &)> NetworkRequestDispatcher::sigError()
388 return d_func()->_sigError;
std::string getScheme() const
Returns the scheme name of the URL.
void globalInitCurlOnce()
NetworkRequestError _lastError
static void unrefLater(T &&ptr)
static int multi_timer_cb(CURLM *multi, long timeout_ms, void *g)
std::array< char, CURL_ERROR_SIZE+1 > _errorBuf
void cancelAll(NetworkRequestError result)
int socketCallback(CURL *easy, curl_socket_t s, int what, void *)
static zyppng::NetworkRequestError fromCurlMError(int nativeCode)
static Ptr create(int socket, int evTypes, bool enable=true)
signal< void(NetworkRequestDispatcher &, NetworkRequest &)> _sigDownloadFinished
signal< void(NetworkRequestDispatcher &)> _sigQueueFinished
std::shared_ptr< Timer > _timer
std::map< curl_socket_t, std::shared_ptr< SocketNotifier > > _socketHandler
static int static_socket_callback(CURL *easy, curl_socket_t s, int what, void *userp, SocketNotifier *socketp)
std::deque< std::shared_ptr< NetworkRequest > > _pendingDownloads
void multiTimerTimout(const Timer &t)
virtual ~NetworkRequestDispatcherPrivate()
void handleMultiSocketAction(curl_socket_t nativeSocket, int evBitmask)
The NetworkRequestError class Represents a error that occured in.
The Timer class provides repetitive and single-shot timers.
signal< void(NetworkRequestDispatcher &)> _sigError
signal< void(NetworkRequestDispatcher &, NetworkRequest &)> _sigDownloadStarted
static zyppng::NetworkRequestError fromCurlError(NetworkRequest &req, int nativeCode, const char *errBuf)
void setFinished(NetworkRequest &req, NetworkRequestError result)
std::vector< std::shared_ptr< NetworkRequest > > _runningDownloads
void onSocketActivated(const SocketNotifier &listener, int events)
static zyppng::NetworkRequestError customError(NetworkRequestError::Type t, std::string &&errorMsg="", std::map< std::string, boost::any > &&extraInfo={})