14#include <zypp-core/zyppng/base/Timer> 
   15#include <zypp-core/zyppng/base/SocketNotifier> 
   16#include <zypp-core/zyppng/base/EventDispatcher> 
   22#include <zypp-core/base/DtorReset> 
   37  static const std::string _value(
 
   39      "ZYpp " LIBZYPP_VERSION_STRING 
" (curl %s)" 
   40      , curl_version_info(CURLVERSION_NOW)->version
 
 
   50    , 
_multi ( curl_multi_init() )
 
   56  curl_multi_setopt( 
_multi, CURLMOPT_TIMERDATA, 
reinterpret_cast<void *
>( 
this ) );
 
   58  curl_multi_setopt( 
_multi, CURLMOPT_SOCKETDATA, 
reinterpret_cast<void *
>( 
this ) );
 
   64  _timer->setSingleShot( 
true );
 
 
   71  curl_multi_cleanup( 
_multi );
 
 
   78  assert( that != 
nullptr );
 
   80  if ( timeout_ms >= 0 ) {
 
   81    that->
_timer->start( 
static_cast<uint64_t
>(timeout_ms) );
 
 
   97  assert( that != 
nullptr );
 
 
  103  std::shared_ptr<SocketNotifier> socketp;
 
  106    if ( what == CURL_POLL_REMOVE || what == CURL_POLL_NONE )
 
  119    if ( what == CURL_POLL_REMOVE || what == CURL_POLL_NONE )
 
  125    void *privatePtr = 
nullptr;
 
  126    if ( curl_easy_getinfo( easy, CURLINFO_PRIVATE, &privatePtr ) != CURLE_OK ) {
 
  127      privatePtr = 
nullptr; 
 
  137      WAR << 
"Cleaning up unassigned  easy handle" << std::endl;
 
  138      curl_multi_remove_handle( 
_multi, easy );
 
  139      curl_easy_cleanup( easy );
 
  145  if ( what == CURL_POLL_REMOVE ) {
 
  146    socketp->setEnabled( 
false );
 
  151  if ( what == CURL_POLL_IN ) {
 
  153  } 
else if ( what == CURL_POLL_OUT ) {
 
  155  } 
else if ( what == CURL_POLL_INOUT ) {
 
  159  socketp->setEnabled();
 
 
  167    evBitmask |= CURL_CSELECT_IN;
 
  169    evBitmask |= CURL_CSELECT_OUT;
 
  171    evBitmask |= CURL_CSELECT_ERR;
 
 
  184  CURLMcode rc = CURLM_OK;
 
  188    rc = curl_multi_socket_action( 
_multi, nativeSocket, evBitmask, &running );
 
  206  CURLMsg *msg = 
nullptr;
 
  207  while( (msg = curl_multi_info_read( 
_multi, &msgs_left )) ) {
 
  208    if(msg->msg == CURLMSG_DONE) {
 
  209      CURL *easy = msg->easy_handle;
 
  210      CURLcode res = msg->data.result;
 
  212      void *privatePtr = 
nullptr;
 
  213      if ( curl_easy_getinfo( easy, CURLINFO_PRIVATE, &privatePtr ) != CURLE_OK ) {
 
  214        WAR << 
"Unable to get CURLINFO_PRIVATE" << std::endl;
 
  220        WAR << 
"Cleaning up unassigned  easy handle" << std::endl;
 
  221        curl_multi_remove_handle( 
_multi, easy );
 
  222        curl_easy_cleanup( easy );
 
  230        std::string errBuf = 
"Broken easy handle in request";
 
  240        errBuf = 
"Failed to reinitialize the request";
 
 
  281  auto delReq = []( 
auto &list, 
NetworkRequest &req ) -> std::shared_ptr<NetworkRequest> {
 
  282    auto it = std::find_if( list.begin(), list.end(), [ &req ]( 
const std::shared_ptr<NetworkRequest> &r ) {
 
  283      return req.d_func() == r->d_func();
 
  285    if ( it != list.end() ) {
 
  296  auto rmode = std::get_if<NetworkRequestPrivate::running_t>( &req.d_func()->_runningMode );
 
  298    if ( rmode->_isInCallback ) {
 
  300      if  ( !rmode->_cachedResult )
 
  301        rmode->_cachedResult = result;
 
  303    } 
else if ( rmode->_cachedResult ) {
 
  304      result = rmode->_cachedResult.value();
 
  312  void *easyHandle = req.d_func()->_easyHandle;
 
  314    MIL_MEDIA << 
"Removing easy handle: " << easyHandle << std::endl;
 
  315    curl_multi_remove_handle( 
_multi, easyHandle );
 
  318  req.d_func()->_dispatcher = 
nullptr;
 
  322  req.d_func()->setResult( std::move(result) );
 
 
  331  CURLMcode rc = curl_multi_add_handle( 
_multi, req.d_func()->_easyHandle );
 
  337  MIL_MEDIA << 
"Added easy handle: " << req.d_func()->_easyHandle << std::endl;
 
 
  355    std::string errBuf = 
"Failed to initialize easy handle";
 
  356    if ( !req->d_func()->initialize( errBuf ) ) {
 
  365    req->d_func()->aboutToStart();
 
 
  381NetworkRequestDispatcher::NetworkRequestDispatcher( )
 
  387bool NetworkRequestDispatcher::supportsProtocol( 
const Url &url )
 
  389  curl_version_info_data *curl_info = 
nullptr;
 
  390  curl_info = curl_version_info(CURLVERSION_NOW);
 
  392  if (curl_info->protocols)
 
  394    const char * 
const *proto = 
nullptr;
 
  395    std::string        scheme( url.getScheme() );
 
  397    for(proto=curl_info->protocols; !found && *proto; ++proto) {
 
  398      if( scheme == std::string((
const char *)*proto))
 
  406void NetworkRequestDispatcher::setMaximumConcurrentConnections( 
const int maxConn )
 
  408  d_func()->_maxConnections = maxConn;
 
  411int NetworkRequestDispatcher::maximumConcurrentConnections ()
 const 
  413  return d_func()->_maxConnections;
 
  416void NetworkRequestDispatcher::enqueue(
const std::shared_ptr<NetworkRequest> &req )
 
  422  if ( std::find( d->_runningDownloads.begin(), d->_runningDownloads.end(), req ) != d->_runningDownloads.end() )  {
 
  423    WAR << 
"Ignoring request to enqueue download " << req->url().asString() << 
" request is already running " << std::endl;
 
  427  if ( std::find( d->_pendingDownloads.begin(), d->_pendingDownloads.end(), req ) != d->_pendingDownloads.end() ) {
 
  428    WAR << 
"Ignoring request to enqueue download " << req->url().asString() << 
" request is already enqueued " << std::endl;
 
  432  req->d_func()->_dispatcher = 
this;
 
  434    d->_pendingDownloads.push_back( req );
 
  436    auto it = std::find_if( d->_pendingDownloads.begin(), d->_pendingDownloads.end(), [ prio = req->priority() ]( 
const auto &pendingReq ){
 
  437      return pendingReq->priority() < prio;
 
  441    if ( it != d->_pendingDownloads.end() && it != d->_pendingDownloads.begin() )
 
  443    d->_pendingDownloads.insert( it, req );
 
  450void NetworkRequestDispatcher::setAgentString( 
const std::string &agent )
 
  456    d->_userAgent = agent;
 
  459const std::string &NetworkRequestDispatcher::agentString()
 const 
  461  return d_func()->_userAgent;
 
  464void NetworkRequestDispatcher::setHostSpecificHeader( 
const std::string &host, 
const std::string &headerName, 
const std::string &value )
 
  467  if ( value.empty() ) {
 
  468    if ( 
auto i = d->_customHeaders.find( host ); i != d->_customHeaders.end() ) {
 
  469      if ( 
auto v = i->second.find( headerName ); v != i->second.end() )  {
 
  472      if ( i->second.empty() )
 
  473        d->_customHeaders.erase(i);
 
  477  d->_customHeaders[host][headerName] = value;
 
  480const NetworkRequestDispatcher::SpecificHeaderMap &NetworkRequestDispatcher::hostSpecificHeaders()
 const 
  482  return d_func()->_customHeaders;
 
  485void NetworkRequestDispatcher::cancel( 
NetworkRequest &req, std::string reason )
 
  494  if ( req.d_func()->_dispatcher != 
this ) {
 
  499  d->setFinished( req, err );
 
  502void NetworkRequestDispatcher::cancelAll(std::string reason)
 
  509  d_func()->cancelAll ( err );
 
  512void NetworkRequestDispatcher::run()
 
  515  d->_isRunning = 
true;
 
  517  if ( d->_pendingDownloads.size() )
 
  521void NetworkRequestDispatcher::reschedule()
 
  524  if ( !d->_pendingDownloads.size() )
 
  527  std::stable_sort( d->_pendingDownloads.begin(), d->_pendingDownloads.end(), []( 
const auto &
a, 
const auto &
b ){
 
  528    return a->priority() < b->priority();
 
  534size_t NetworkRequestDispatcher::count()
 
  537  return d->_pendingDownloads.size() + d->_runningDownloads.size();
 
  540const zyppng::NetworkRequestError &NetworkRequestDispatcher::lastError()
 const 
  542  return d_func()->_lastError;
 
  547  return d_func()->_sigDownloadStarted;
 
  552  return d_func()->_sigDownloadFinished;
 
  555SignalProxy<void ( NetworkRequestDispatcher &)> NetworkRequestDispatcher::sigQueueFinished()
 
  557  return d_func()->_sigQueueFinished;
 
  560SignalProxy<void ( NetworkRequestDispatcher &)> NetworkRequestDispatcher::sigError()
 
  562  return d_func()->_sigError;
 
Assign a vaiable a certain value when going out of scope.
NetworkRequestDispatcherPrivate(NetworkRequestDispatcher &p)
static int static_socket_callback(CURL *easy, curl_socket_t s, int what, void *userp, SocketNotifier *socketp)
int socketCallback(CURL *easy, curl_socket_t s, int what, void *)
Signal< void(NetworkRequestDispatcher &)> _sigError
Signal< void(NetworkRequestDispatcher &)> _sigQueueFinished
void setFinished(NetworkRequest &req, NetworkRequestError result)
void multiTimerTimout(const Timer &t)
NetworkRequestError _lastError
void handleMultiSocketAction(curl_socket_t nativeSocket, int evBitmask)
~NetworkRequestDispatcherPrivate() override
Signal< void(NetworkRequestDispatcher &, NetworkRequest &)> _sigDownloadFinished
std::shared_ptr< Timer > _timer
std::map< curl_socket_t, std::shared_ptr< SocketNotifier > > _socketHandler
bool addRequestToMultiHandle(NetworkRequest &req)
void onSocketActivated(const SocketNotifier &listener, int events)
Signal< void(NetworkRequestDispatcher &, NetworkRequest &)> _sigDownloadStarted
std::deque< std::shared_ptr< NetworkRequest > > _pendingDownloads
static int multi_timer_cb(CURLM *multi, long timeout_ms, void *g)
void cancelAll(const NetworkRequestError &result)
std::vector< std::shared_ptr< NetworkRequest > > _runningDownloads
static zyppng::NetworkRequestError fromCurlMError(int nativeCode)
static zyppng::NetworkRequestError fromCurlError(NetworkRequest &req, int nativeCode, const std::string &nativeError)
static zyppng::NetworkRequestError customError(NetworkRequestError::Type t, std::string &&errorMsg="", std::map< std::string, boost::any > &&extraInfo={})
The NetworkRequestError class Represents a error that occured in.
std::string errorMessage() const
bool prepareToContinue(std::string &errBuf)
static Ptr create(int socket, int evTypes, bool enable=true)
SignalProxy< void(const SocketNotifier &sock, int evTypes)> sigActivated()
The Timer class provides repetitive and single-shot timers.
SignalProxy< void(Timer &t)> sigExpired()
This signal is always emitted when the timer expires.
void globalInitCurlOnce()
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
AutoDispose< void > OnScopeExit
static const std::string & defaultAgentString()
Provides API related macros.
#define L_ENV_CONSTR_DEFINE_FUNC(ENV)
#define ZYPP_IMPL_PRIVATE(Class)