Ticket #12208: curl-7.65.1-fix-dns-segfaults-1.patch

File curl-7.65.1-fix-dns-segfaults-1.patch, 106.7 KB (added by Tim Tassonis, 5 years ago)
  • lib/hash.h

    diff -ruN curl-7.65.1/lib/hash.h curl-7.65.1-fix-dns-segfaults/lib/hash.h
    old new  
    77 *                            | (__| |_| |  _ <| |___
    88 *                             \___|\___/|_| \_\_____|
    99 *
    10  * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
     10 * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
    1111 *
    1212 * This software is licensed as described in the file COPYING, which
    1313 * you should have received as part of this distribution. The terms
     
    8080void *Curl_hash_pick(struct curl_hash *, void *key, size_t key_len);
    8181void Curl_hash_apply(struct curl_hash *h, void *user,
    8282                     void (*cb)(void *user, void *ptr));
    83 int Curl_hash_count(struct curl_hash *h);
     83#define Curl_hash_count(h) ((h)->size)
    8484void Curl_hash_destroy(struct curl_hash *h);
    8585void Curl_hash_clean(struct curl_hash *h);
    8686void Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,
  • lib/multi.c

    diff -ruN curl-7.65.1/lib/multi.c curl-7.65.1-fix-dns-segfaults/lib/multi.c
    old new  
    189189 */
    190190
    191191struct Curl_sh_entry {
    192   struct curl_llist list; /* list of easy handles using this socket */
     192  struct curl_hash transfers; /* hash of transfers using this socket */
    193193  unsigned int action;  /* what combined action READ/WRITE this socket waits
    194194                           for */
    195195  void *socketp; /* settable by users with curl_multi_assign() */
     
    206206static struct Curl_sh_entry *sh_getentry(struct curl_hash *sh,
    207207                                         curl_socket_t s)
    208208{
    209   if(s != CURL_SOCKET_BAD)
     209  if(s != CURL_SOCKET_BAD) {
    210210    /* only look for proper sockets */
    211211    return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
     212  }
    212213  return NULL;
    213214}
    214215
     216#define TRHASH_SIZE 13
     217static size_t trhash(void *key, size_t key_length, size_t slots_num)
     218{
     219  size_t keyval = (size_t)*(struct Curl_easy **)key;
     220  (void) key_length;
     221
     222  return (keyval % slots_num);
     223}
     224
     225static size_t trhash_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
     226{
     227  (void)k1_len;
     228  (void)k2_len;
     229
     230  return *(struct Curl_easy **)k1 == *(struct Curl_easy **)k2;
     231}
     232
     233static void trhash_dtor(void *nada)
     234{
     235  (void)nada;
     236}
     237
     238
    215239/* make sure this socket is present in the hash for this handle */
    216240static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
    217241                                         curl_socket_t s)
     
    219243  struct Curl_sh_entry *there = sh_getentry(sh, s);
    220244  struct Curl_sh_entry *check;
    221245
    222   if(there)
     246  if(there) {
    223247    /* it is present, return fine */
    224248    return there;
     249  }
    225250
    226251  /* not present, add it */
    227252  check = calloc(1, sizeof(struct Curl_sh_entry));
    228253  if(!check)
    229254    return NULL; /* major failure */
    230255
    231   Curl_llist_init(&check->list, NULL);
     256  if(Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash,
     257                    trhash_compare, trhash_dtor)) {
     258    free(check);
     259    return NULL;
     260  }
    232261
    233262  /* make/add new hash entry */
    234263  if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
     
    244273static void sh_delentry(struct Curl_sh_entry *entry,
    245274                        struct curl_hash *sh, curl_socket_t s)
    246275{
    247   struct curl_llist *list = &entry->list;
    248   struct curl_llist_element *e;
    249   /* clear the list of transfers first */
    250   for(e = list->head; e; e = list->head) {
    251     struct Curl_easy *dta = e->ptr;
    252     Curl_llist_remove(&entry->list, e, NULL);
    253     dta->sh_entry = NULL;
    254   }
     276  Curl_hash_destroy(&entry->transfers);
     277
    255278  /* We remove the hash entry. This will end up in a call to
    256279     sh_freeentry(). */
    257280  Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
     
    320343  return CURLM_OK;
    321344}
    322345
    323 /*
    324  * multi_freeamsg()
    325  *
    326  * Callback used by the llist system when a single list entry is destroyed.
    327  */
    328 static void multi_freeamsg(void *a, void *b)
    329 {
    330   (void)a;
    331   (void)b;
    332 }
    333 
    334346struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
    335347                                     int chashsize) /* connection hash */
    336348{
     
    350362  if(Curl_conncache_init(&multi->conn_cache, chashsize))
    351363    goto error;
    352364
    353   Curl_llist_init(&multi->msglist, multi_freeamsg);
    354   Curl_llist_init(&multi->pending, multi_freeamsg);
     365  Curl_llist_init(&multi->msglist, NULL);
     366  Curl_llist_init(&multi->pending, NULL);
    355367
    356368  /* -1 means it not set by user, use the default value */
    357369  multi->maxconnects = -1;
     
    789801static void detach_connnection(struct Curl_easy *data)
    790802{
    791803  struct connectdata *conn = data->conn;
    792   if(data->sh_entry) {
    793     /* still listed as a user of a socket hash entry, remove it */
    794     Curl_llist_remove(&data->sh_entry->list, &data->sh_queue, NULL);
    795     data->sh_entry = NULL;
    796   }
    797804  if(conn)
    798805    Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
    799806  data->conn = NULL;
     
    12661273    bool stream_error = FALSE;
    12671274    rc = CURLM_OK;
    12681275
     1276    DEBUGASSERT((data->mstate <= CURLM_STATE_CONNECT) ||
     1277                (data->mstate >= CURLM_STATE_DONE) ||
     1278                data->conn);
    12691279    if(!data->conn &&
    12701280       data->mstate > CURLM_STATE_CONNECT &&
    12711281       data->mstate < CURLM_STATE_DONE) {
     
    22872297      if(action & CURL_POLL_OUT)
    22882298        entry->writers++;
    22892299
    2290       /* add 'data' to the list of handles using this socket! */
    2291       Curl_llist_insert_next(&entry->list, entry->list.tail,
    2292                              data, &data->sh_queue);
    2293       data->sh_entry = entry;
     2300      /* add 'data' to the transfer hash on this socket! */
     2301      if(!Curl_hash_add(&entry->transfers, (char *)&data, /* hash key */
     2302                        sizeof(struct Curl_easy *), data))
     2303        return CURLM_OUT_OF_MEMORY;
    22942304    }
    22952305
    22962306    comboaction = (entry->writers? CURL_POLL_OUT : 0) |
    22972307      (entry->readers ? CURL_POLL_IN : 0);
    22982308
    2299 #if 0
    2300     infof(data, "--- Comboaction: %u readers %u writers\n",
    2301           entry->readers, entry->writers);
    2302 #endif
    2303     /* check if it has the same action set */
    2304     if(entry->action == comboaction)
     2309    /* socket existed before and has the same action set as before */
     2310    if(sincebefore && (entry->action == comboaction))
    23052311      /* same, continue */
    23062312      continue;
    23072313
    2308     /* we know (entry != NULL) at this point, see the logic above */
    23092314    if(multi->socket_cb)
    2310       multi->socket_cb(data,
    2311                        s,
    2312                        comboaction,
    2313                        multi->socket_userp,
     2315      multi->socket_cb(data, s, comboaction, multi->socket_userp,
    23142316                       entry->socketp);
    23152317
    23162318    entry->action = comboaction; /* store the current action state */
     
    23522354                           entry->socketp);
    23532355        sh_delentry(entry, &multi->sockhash, s);
    23542356      }
     2357      else {
     2358        /* still users, but remove this handle as a user of this socket */
     2359        if(Curl_hash_delete(&entry->transfers, (char *)&data,
     2360                            sizeof(struct Curl_easy *))) {
     2361          DEBUGASSERT(NULL);
     2362        }
     2363      }
    23552364    }
    23562365  } /* for loop over numsocks */
    23572366
     
    24952504         and just move on. */
    24962505      ;
    24972506    else {
    2498       struct curl_llist *list = &entry->list;
    2499       struct curl_llist_element *e;
    2500       struct curl_llist_element *enext;
    2501       SIGPIPE_VARIABLE(pipe_st);
     2507      struct curl_hash_iterator iter;
     2508      struct curl_hash_element *he;
    25022509
    25032510      /* the socket can be shared by many transfers, iterate */
    2504       for(e = list->head; e; e = enext) {
    2505         data = (struct Curl_easy *)e->ptr;
    2506 
    2507         /* assign 'enext' here since the 'e' struct might be cleared
    2508            further down in the singlesocket() call */
    2509         enext = e->next;
    2510 
     2511      Curl_hash_start_iterate(&entry->transfers, &iter);
     2512      for(he = Curl_hash_next_element(&iter); he;
     2513          he = Curl_hash_next_element(&iter)) {
     2514        data = (struct Curl_easy *)he->ptr;
    25112515        DEBUGASSERT(data);
    25122516        DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER);
    25132517
     
    25152519          /* set socket event bitmask if they're not locked */
    25162520          data->conn->cselect_bits = ev_bitmask;
    25172521
    2518         sigpipe_ignore(data, &pipe_st);
    2519         result = multi_runsingle(multi, now, data);
    2520         sigpipe_restore(&pipe_st);
    2521 
    2522         if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
    2523           /* clear the bitmask only if not locked */
    2524           data->conn->cselect_bits = 0;
    2525 
    2526         if(CURLM_OK >= result) {
    2527           /* get the socket(s) and check if the state has been changed since
    2528              last */
    2529           result = singlesocket(multi, data);
    2530           if(result)
    2531             return result;
    2532         }
     2522        Curl_expire(data, 0, EXPIRE_RUN_NOW);
    25332523      }
    25342524
    25352525      /* Now we fall-through and do the timer-based stuff, since we don't want
  • lib/multi.c.orig

    diff -ruN curl-7.65.1/lib/multi.c.orig curl-7.65.1-fix-dns-segfaults/lib/multi.c.orig
    old new  
     1/***************************************************************************
     2 *                                  _   _ ____  _
     3 *  Project                     ___| | | |  _ \| |
     4 *                             / __| | | | |_) | |
     5 *                            | (__| |_| |  _ <| |___
     6 *                             \___|\___/|_| \_\_____|
     7 *
     8 * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
     9 *
     10 * This software is licensed as described in the file COPYING, which
     11 * you should have received as part of this distribution. The terms
     12 * are also available at https://curl.haxx.se/docs/copyright.html.
     13 *
     14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15 * copies of the Software, and permit persons to whom the Software is
     16 * furnished to do so, under the terms of the COPYING file.
     17 *
     18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19 * KIND, either express or implied.
     20 *
     21 ***************************************************************************/
     22
     23#include "curl_setup.h"
     24
     25#include <curl/curl.h>
     26
     27#include "urldata.h"
     28#include "transfer.h"
     29#include "url.h"
     30#include "connect.h"
     31#include "progress.h"
     32#include "easyif.h"
     33#include "share.h"
     34#include "psl.h"
     35#include "multiif.h"
     36#include "sendf.h"
     37#include "timeval.h"
     38#include "http.h"
     39#include "select.h"
     40#include "warnless.h"
     41#include "speedcheck.h"
     42#include "conncache.h"
     43#include "multihandle.h"
     44#include "sigpipe.h"
     45#include "vtls/vtls.h"
     46#include "connect.h"
     47#include "http_proxy.h"
     48#include "http2.h"
     49/* The last 3 #include files should be in this order */
     50#include "curl_printf.h"
     51#include "curl_memory.h"
     52#include "memdebug.h"
     53
     54/*
     55  CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97
     56  to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes.  Still, every
     57  CURL handle takes 45-50 K memory, therefore this 3K are not significant.
     58*/
     59#ifndef CURL_SOCKET_HASH_TABLE_SIZE
     60#define CURL_SOCKET_HASH_TABLE_SIZE 911
     61#endif
     62
     63#ifndef CURL_CONNECTION_HASH_SIZE
     64#define CURL_CONNECTION_HASH_SIZE 97
     65#endif
     66
     67#define CURL_MULTI_HANDLE 0x000bab1e
     68
     69#define GOOD_MULTI_HANDLE(x) \
     70  ((x) && (x)->type == CURL_MULTI_HANDLE)
     71
     72static CURLMcode singlesocket(struct Curl_multi *multi,
     73                              struct Curl_easy *data);
     74static int update_timer(struct Curl_multi *multi);
     75
     76static CURLMcode add_next_timeout(struct curltime now,
     77                                  struct Curl_multi *multi,
     78                                  struct Curl_easy *d);
     79static CURLMcode multi_timeout(struct Curl_multi *multi,
     80                               long *timeout_ms);
     81static void process_pending_handles(struct Curl_multi *multi);
     82static void detach_connnection(struct Curl_easy *data);
     83
     84#ifdef DEBUGBUILD
     85static const char * const statename[]={
     86  "INIT",
     87  "CONNECT_PEND",
     88  "CONNECT",
     89  "WAITRESOLVE",
     90  "WAITCONNECT",
     91  "WAITPROXYCONNECT",
     92  "SENDPROTOCONNECT",
     93  "PROTOCONNECT",
     94  "DO",
     95  "DOING",
     96  "DO_MORE",
     97  "DO_DONE",
     98  "PERFORM",
     99  "TOOFAST",
     100  "DONE",
     101  "COMPLETED",
     102  "MSGSENT",
     103};
     104#endif
     105
     106/* function pointer called once when switching TO a state */
     107typedef void (*init_multistate_func)(struct Curl_easy *data);
     108
     109static void Curl_init_completed(struct Curl_easy *data)
     110{
     111  /* this is a completed transfer */
     112
     113  /* Important: reset the conn pointer so that we don't point to memory
     114     that could be freed anytime */
     115  detach_connnection(data);
     116  Curl_expire_clear(data); /* stop all timers */
     117}
     118
     119/* always use this function to change state, to make debugging easier */
     120static void mstate(struct Curl_easy *data, CURLMstate state
     121#ifdef DEBUGBUILD
     122                   , int lineno
     123#endif
     124)
     125{
     126  CURLMstate oldstate = data->mstate;
     127  static const init_multistate_func finit[CURLM_STATE_LAST] = {
     128    NULL,              /* INIT */
     129    NULL,              /* CONNECT_PEND */
     130    Curl_init_CONNECT, /* CONNECT */
     131    NULL,              /* WAITRESOLVE */
     132    NULL,              /* WAITCONNECT */
     133    NULL,              /* WAITPROXYCONNECT */
     134    NULL,              /* SENDPROTOCONNECT */
     135    NULL,              /* PROTOCONNECT */
     136    Curl_connect_free, /* DO */
     137    NULL,              /* DOING */
     138    NULL,              /* DO_MORE */
     139    NULL,              /* DO_DONE */
     140    NULL,              /* PERFORM */
     141    NULL,              /* TOOFAST */
     142    NULL,              /* DONE */
     143    Curl_init_completed, /* COMPLETED */
     144    NULL               /* MSGSENT */
     145  };
     146
     147#if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS)
     148  (void) lineno;
     149#endif
     150
     151  if(oldstate == state)
     152    /* don't bother when the new state is the same as the old state */
     153    return;
     154
     155  data->mstate = state;
     156
     157#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
     158  if(data->mstate >= CURLM_STATE_CONNECT_PEND &&
     159     data->mstate < CURLM_STATE_COMPLETED) {
     160    long connection_id = -5000;
     161
     162    if(data->conn)
     163      connection_id = data->conn->connection_id;
     164
     165    infof(data,
     166          "STATE: %s => %s handle %p; line %d (connection #%ld)\n",
     167          statename[oldstate], statename[data->mstate],
     168          (void *)data, lineno, connection_id);
     169  }
     170#endif
     171
     172  if(state == CURLM_STATE_COMPLETED)
     173    /* changing to COMPLETED means there's one less easy handle 'alive' */
     174    data->multi->num_alive--;
     175
     176  /* if this state has an init-function, run it */
     177  if(finit[state])
     178    finit[state](data);
     179}
     180
     181#ifndef DEBUGBUILD
     182#define multistate(x,y) mstate(x,y)
     183#else
     184#define multistate(x,y) mstate(x,y, __LINE__)
     185#endif
     186
     187/*
     188 * We add one of these structs to the sockhash for each socket
     189 */
     190
     191struct Curl_sh_entry {
     192  struct curl_hash transfers; /* hash of transfers using this socket */
     193  unsigned int action;  /* what combined action READ/WRITE this socket waits
     194                           for */
     195  void *socketp; /* settable by users with curl_multi_assign() */
     196  unsigned int users; /* number of transfers using this */
     197  unsigned int readers; /* this many transfers want to read */
     198  unsigned int writers; /* this many transfers want to write */
     199};
     200/* bits for 'action' having no bits means this socket is not expecting any
     201   action */
     202#define SH_READ  1
     203#define SH_WRITE 2
     204
     205/* look up a given socket in the socket hash, skip invalid sockets */
     206static struct Curl_sh_entry *sh_getentry(struct curl_hash *sh,
     207                                         curl_socket_t s)
     208{
     209  if(s != CURL_SOCKET_BAD) {
     210    /* only look for proper sockets */
     211    return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
     212  }
     213  return NULL;
     214}
     215
     216#define TRHASH_SIZE 13
     217static size_t trhash(void *key, size_t key_length, size_t slots_num)
     218{
     219  size_t keyval = (size_t)key; /* this is a data pointer */
     220  (void) key_length;
     221
     222  return (keyval % slots_num);
     223}
     224
     225static size_t trhash_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
     226{
     227  (void)k1_len;
     228  (void)k2_len;
     229
     230  return *(struct Curl_easy **)k1 == *(struct Curl_easy **)k2;
     231}
     232
     233static void trhash_dtor(void *nada)
     234{
     235  (void)nada;
     236}
     237
     238
     239/* make sure this socket is present in the hash for this handle */
     240static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
     241                                         curl_socket_t s)
     242{
     243  struct Curl_sh_entry *there = sh_getentry(sh, s);
     244  struct Curl_sh_entry *check;
     245
     246  if(there) {
     247    /* it is present, return fine */
     248    return there;
     249  }
     250
     251  /* not present, add it */
     252  check = calloc(1, sizeof(struct Curl_sh_entry));
     253  if(!check)
     254    return NULL; /* major failure */
     255
     256  if(Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash,
     257                    trhash_compare, trhash_dtor)) {
     258    free(check);
     259    return NULL;
     260  }
     261
     262  /* make/add new hash entry */
     263  if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
     264    free(check);
     265    return NULL; /* major failure */
     266  }
     267
     268  return check; /* things are good in sockhash land */
     269}
     270
     271
     272/* delete the given socket + handle from the hash */
     273static void sh_delentry(struct Curl_sh_entry *entry,
     274                        struct curl_hash *sh, curl_socket_t s)
     275{
     276  Curl_hash_destroy(&entry->transfers);
     277
     278  /* We remove the hash entry. This will end up in a call to
     279     sh_freeentry(). */
     280  Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
     281}
     282
     283/*
     284 * free a sockhash entry
     285 */
     286static void sh_freeentry(void *freethis)
     287{
     288  struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis;
     289
     290  free(p);
     291}
     292
     293static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
     294{
     295  (void) k1_len; (void) k2_len;
     296
     297  return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2));
     298}
     299
     300static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
     301{
     302  curl_socket_t fd = *((curl_socket_t *) key);
     303  (void) key_length;
     304
     305  return (fd % slots_num);
     306}
     307
     308/*
     309 * sh_init() creates a new socket hash and returns the handle for it.
     310 *
     311 * Quote from README.multi_socket:
     312 *
     313 * "Some tests at 7000 and 9000 connections showed that the socket hash lookup
     314 * is somewhat of a bottle neck. Its current implementation may be a bit too
     315 * limiting. It simply has a fixed-size array, and on each entry in the array
     316 * it has a linked list with entries. So the hash only checks which list to
     317 * scan through. The code I had used so for used a list with merely 7 slots
     318 * (as that is what the DNS hash uses) but with 7000 connections that would
     319 * make an average of 1000 nodes in each list to run through. I upped that to
     320 * 97 slots (I believe a prime is suitable) and noticed a significant speed
     321 * increase.  I need to reconsider the hash implementation or use a rather
     322 * large default value like this. At 9000 connections I was still below 10us
     323 * per call."
     324 *
     325 */
     326static int sh_init(struct curl_hash *hash, int hashsize)
     327{
     328  return Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
     329                        sh_freeentry);
     330}
     331
     332/*
     333 * multi_addmsg()
     334 *
     335 * Called when a transfer is completed. Adds the given msg pointer to
     336 * the list kept in the multi handle.
     337 */
     338static CURLMcode multi_addmsg(struct Curl_multi *multi,
     339                              struct Curl_message *msg)
     340{
     341  Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg,
     342                         &msg->list);
     343  return CURLM_OK;
     344}
     345
     346struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
     347                                     int chashsize) /* connection hash */
     348{
     349  struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi));
     350
     351  if(!multi)
     352    return NULL;
     353
     354  multi->type = CURL_MULTI_HANDLE;
     355
     356  if(Curl_mk_dnscache(&multi->hostcache))
     357    goto error;
     358
     359  if(sh_init(&multi->sockhash, hashsize))
     360    goto error;
     361
     362  if(Curl_conncache_init(&multi->conn_cache, chashsize))
     363    goto error;
     364
     365  Curl_llist_init(&multi->msglist, NULL);
     366  Curl_llist_init(&multi->pending, NULL);
     367
     368  /* -1 means it not set by user, use the default value */
     369  multi->maxconnects = -1;
     370  return multi;
     371
     372  error:
     373
     374  Curl_hash_destroy(&multi->sockhash);
     375  Curl_hash_destroy(&multi->hostcache);
     376  Curl_conncache_destroy(&multi->conn_cache);
     377  Curl_llist_destroy(&multi->msglist, NULL);
     378  Curl_llist_destroy(&multi->pending, NULL);
     379
     380  free(multi);
     381  return NULL;
     382}
     383
     384struct Curl_multi *curl_multi_init(void)
     385{
     386  return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE,
     387                           CURL_CONNECTION_HASH_SIZE);
     388}
     389
     390CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
     391                                struct Curl_easy *data)
     392{
     393  /* First, make some basic checks that the CURLM handle is a good handle */
     394  if(!GOOD_MULTI_HANDLE(multi))
     395    return CURLM_BAD_HANDLE;
     396
     397  /* Verify that we got a somewhat good easy handle too */
     398  if(!GOOD_EASY_HANDLE(data))
     399    return CURLM_BAD_EASY_HANDLE;
     400
     401  /* Prevent users from adding same easy handle more than once and prevent
     402     adding to more than one multi stack */
     403  if(data->multi)
     404    return CURLM_ADDED_ALREADY;
     405
     406  if(multi->in_callback)
     407    return CURLM_RECURSIVE_API_CALL;
     408
     409  /* Initialize timeout list for this handle */
     410  Curl_llist_init(&data->state.timeoutlist, NULL);
     411
     412  /*
     413   * No failure allowed in this function beyond this point. And no
     414   * modification of easy nor multi handle allowed before this except for
     415   * potential multi's connection cache growing which won't be undone in this
     416   * function no matter what.
     417   */
     418  if(data->set.errorbuffer)
     419    data->set.errorbuffer[0] = 0;
     420
     421  /* set the easy handle */
     422  multistate(data, CURLM_STATE_INIT);
     423
     424  /* for multi interface connections, we share DNS cache automatically if the
     425     easy handle's one is currently not set. */
     426  if(!data->dns.hostcache ||
     427     (data->dns.hostcachetype == HCACHE_NONE)) {
     428    data->dns.hostcache = &multi->hostcache;
     429    data->dns.hostcachetype = HCACHE_MULTI;
     430  }
     431
     432  /* Point to the shared or multi handle connection cache */
     433  if(data->share && (data->share->specifier & (1<< CURL_LOCK_DATA_CONNECT)))
     434    data->state.conn_cache = &data->share->conn_cache;
     435  else
     436    data->state.conn_cache = &multi->conn_cache;
     437
     438#ifdef USE_LIBPSL
     439  /* Do the same for PSL. */
     440  if(data->share && (data->share->specifier & (1 << CURL_LOCK_DATA_PSL)))
     441    data->psl = &data->share->psl;
     442  else
     443    data->psl = &multi->psl;
     444#endif
     445
     446  /* We add the new entry last in the list. */
     447  data->next = NULL; /* end of the line */
     448  if(multi->easyp) {
     449    struct Curl_easy *last = multi->easylp;
     450    last->next = data;
     451    data->prev = last;
     452    multi->easylp = data; /* the new last node */
     453  }
     454  else {
     455    /* first node, make prev NULL! */
     456    data->prev = NULL;
     457    multi->easylp = multi->easyp = data; /* both first and last */
     458  }
     459
     460  /* make the Curl_easy refer back to this multi handle */
     461  data->multi = multi;
     462
     463  /* Set the timeout for this handle to expire really soon so that it will
     464     be taken care of even when this handle is added in the midst of operation
     465     when only the curl_multi_socket() API is used. During that flow, only
     466     sockets that time-out or have actions will be dealt with. Since this
     467     handle has no action yet, we make sure it times out to get things to
     468     happen. */
     469  Curl_expire(data, 0, EXPIRE_RUN_NOW);
     470
     471  /* increase the node-counter */
     472  multi->num_easy++;
     473
     474  /* increase the alive-counter */
     475  multi->num_alive++;
     476
     477  /* A somewhat crude work-around for a little glitch in update_timer() that
     478     happens if the lastcall time is set to the same time when the handle is
     479     removed as when the next handle is added, as then the check in
     480     update_timer() that prevents calling the application multiple times with
     481     the same timer info will not trigger and then the new handle's timeout
     482     will not be notified to the app.
     483
     484     The work-around is thus simply to clear the 'lastcall' variable to force
     485     update_timer() to always trigger a callback to the app when a new easy
     486     handle is added */
     487  memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
     488
     489  /* The closure handle only ever has default timeouts set. To improve the
     490     state somewhat we clone the timeouts from each added handle so that the
     491     closure handle always has the same timeouts as the most recently added
     492     easy handle. */
     493  data->state.conn_cache->closure_handle->set.timeout = data->set.timeout;
     494  data->state.conn_cache->closure_handle->set.server_response_timeout =
     495    data->set.server_response_timeout;
     496  data->state.conn_cache->closure_handle->set.no_signal =
     497    data->set.no_signal;
     498
     499  update_timer(multi);
     500  return CURLM_OK;
     501}
     502
     503#if 0
     504/* Debug-function, used like this:
     505 *
     506 * Curl_hash_print(multi->sockhash, debug_print_sock_hash);
     507 *
     508 * Enable the hash print function first by editing hash.c
     509 */
     510static void debug_print_sock_hash(void *p)
     511{
     512  struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p;
     513
     514  fprintf(stderr, " [easy %p/magic %x/socket %d]",
     515          (void *)sh->data, sh->data->magic, (int)sh->socket);
     516}
     517#endif
     518
     519static CURLcode multi_done(struct Curl_easy *data,
     520                           CURLcode status,  /* an error if this is called
     521                                                after an error was detected */
     522                           bool premature)
     523{
     524  CURLcode result;
     525  struct connectdata *conn = data->conn;
     526  unsigned int i;
     527
     528  DEBUGF(infof(data, "multi_done\n"));
     529
     530  if(data->state.done)
     531    /* Stop if multi_done() has already been called */
     532    return CURLE_OK;
     533
     534  /* Stop the resolver and free its own resources (but not dns_entry yet). */
     535  Curl_resolver_kill(conn);
     536
     537  /* Cleanup possible redirect junk */
     538  Curl_safefree(data->req.newurl);
     539  Curl_safefree(data->req.location);
     540
     541  switch(status) {
     542  case CURLE_ABORTED_BY_CALLBACK:
     543  case CURLE_READ_ERROR:
     544  case CURLE_WRITE_ERROR:
     545    /* When we're aborted due to a callback return code it basically have to
     546       be counted as premature as there is trouble ahead if we don't. We have
     547       many callbacks and protocols work differently, we could potentially do
     548       this more fine-grained in the future. */
     549    premature = TRUE;
     550  default:
     551    break;
     552  }
     553
     554  /* this calls the protocol-specific function pointer previously set */
     555  if(conn->handler->done)
     556    result = conn->handler->done(conn, status, premature);
     557  else
     558    result = status;
     559
     560  if(CURLE_ABORTED_BY_CALLBACK != result) {
     561    /* avoid this if we already aborted by callback to avoid this calling
     562       another callback */
     563    CURLcode rc = Curl_pgrsDone(conn);
     564    if(!result && rc)
     565      result = CURLE_ABORTED_BY_CALLBACK;
     566  }
     567
     568  process_pending_handles(data->multi); /* connection / multiplex */
     569
     570  detach_connnection(data);
     571  if(CONN_INUSE(conn)) {
     572    /* Stop if still used. */
     573    DEBUGF(infof(data, "Connection still in use %zu, "
     574                 "no more multi_done now!\n",
     575                 conn->easyq.size));
     576    return CURLE_OK;
     577  }
     578
     579  data->state.done = TRUE; /* called just now! */
     580
     581  if(conn->dns_entry) {
     582    Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
     583    conn->dns_entry = NULL;
     584  }
     585  Curl_hostcache_prune(data);
     586  Curl_safefree(data->state.ulbuf);
     587
     588  /* if the transfer was completed in a paused state there can be buffered
     589     data left to free */
     590  for(i = 0; i < data->state.tempcount; i++) {
     591    free(data->state.tempwrite[i].buf);
     592  }
     593  data->state.tempcount = 0;
     594
     595  /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
     596     forced us to close this connection. This is ignored for requests taking
     597     place in a NTLM/NEGOTIATE authentication handshake
     598
     599     if conn->bits.close is TRUE, it means that the connection should be
     600     closed in spite of all our efforts to be nice, due to protocol
     601     restrictions in our or the server's end
     602
     603     if premature is TRUE, it means this connection was said to be DONE before
     604     the entire request operation is complete and thus we can't know in what
     605     state it is for re-using, so we're forced to close it. In a perfect world
     606     we can add code that keep track of if we really must close it here or not,
     607     but currently we have no such detail knowledge.
     608  */
     609
     610  if((data->set.reuse_forbid
     611#if defined(USE_NTLM)
     612      && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 ||
     613           conn->proxy_ntlm_state == NTLMSTATE_TYPE2)
     614#endif
     615#if defined(USE_SPNEGO)
     616      && !(conn->http_negotiate_state == GSS_AUTHRECV ||
     617           conn->proxy_negotiate_state == GSS_AUTHRECV)
     618#endif
     619     ) || conn->bits.close
     620       || (premature && !(conn->handler->flags & PROTOPT_STREAM))) {
     621    CURLcode res2 = Curl_disconnect(data, conn, premature);
     622
     623    /* If we had an error already, make sure we return that one. But
     624       if we got a new error, return that. */
     625    if(!result && res2)
     626      result = res2;
     627  }
     628  else {
     629    char buffer[256];
     630    /* create string before returning the connection */
     631    msnprintf(buffer, sizeof(buffer),
     632              "Connection #%ld to host %s left intact",
     633              conn->connection_id,
     634              conn->bits.socksproxy ? conn->socks_proxy.host.dispname :
     635              conn->bits.httpproxy ? conn->http_proxy.host.dispname :
     636              conn->bits.conn_to_host ? conn->conn_to_host.dispname :
     637              conn->host.dispname);
     638
     639    /* the connection is no longer in use by this transfer */
     640    if(Curl_conncache_return_conn(conn)) {
     641      /* remember the most recently used connection */
     642      data->state.lastconnect = conn;
     643      infof(data, "%s\n", buffer);
     644    }
     645    else
     646      data->state.lastconnect = NULL;
     647  }
     648
     649  Curl_free_request_state(data);
     650  return result;
     651}
     652
     653CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
     654                                   struct Curl_easy *data)
     655{
     656  struct Curl_easy *easy = data;
     657  bool premature;
     658  bool easy_owns_conn;
     659  struct curl_llist_element *e;
     660
     661  /* First, make some basic checks that the CURLM handle is a good handle */
     662  if(!GOOD_MULTI_HANDLE(multi))
     663    return CURLM_BAD_HANDLE;
     664
     665  /* Verify that we got a somewhat good easy handle too */
     666  if(!GOOD_EASY_HANDLE(data))
     667    return CURLM_BAD_EASY_HANDLE;
     668
     669  /* Prevent users from trying to remove same easy handle more than once */
     670  if(!data->multi)
     671    return CURLM_OK; /* it is already removed so let's say it is fine! */
     672
     673  if(multi->in_callback)
     674    return CURLM_RECURSIVE_API_CALL;
     675
     676  premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE;
     677  easy_owns_conn = (data->conn && (data->conn->data == easy)) ?
     678    TRUE : FALSE;
     679
     680  /* If the 'state' is not INIT or COMPLETED, we might need to do something
     681     nice to put the easy_handle in a good known state when this returns. */
     682  if(premature) {
     683    /* this handle is "alive" so we need to count down the total number of
     684       alive connections when this is removed */
     685    multi->num_alive--;
     686  }
     687
     688  if(data->conn &&
     689     data->mstate > CURLM_STATE_DO &&
     690     data->mstate < CURLM_STATE_COMPLETED) {
     691    /* Set connection owner so that the DONE function closes it.  We can
     692       safely do this here since connection is killed. */
     693    data->conn->data = easy;
     694    streamclose(data->conn, "Removed with partial response");
     695    easy_owns_conn = TRUE;
     696  }
     697
     698  /* The timer must be shut down before data->multi is set to NULL,
     699     else the timenode will remain in the splay tree after
     700     curl_easy_cleanup is called. */
     701  Curl_expire_clear(data);
     702
     703  if(data->conn) {
     704
     705    /* we must call multi_done() here (if we still own the connection) so that
     706       we don't leave a half-baked one around */
     707    if(easy_owns_conn) {
     708
     709      /* multi_done() clears the conn->data field to lose the association
     710         between the easy handle and the connection
     711
     712         Note that this ignores the return code simply because there's
     713         nothing really useful to do with it anyway! */
     714      (void)multi_done(data, data->result, premature);
     715    }
     716  }
     717
     718  if(data->connect_queue.ptr)
     719    /* the handle was in the pending list waiting for an available connection,
     720       so go ahead and remove it */
     721    Curl_llist_remove(&multi->pending, &data->connect_queue, NULL);
     722
     723  if(data->dns.hostcachetype == HCACHE_MULTI) {
     724    /* stop using the multi handle's DNS cache, *after* the possible
     725       multi_done() call above */
     726    data->dns.hostcache = NULL;
     727    data->dns.hostcachetype = HCACHE_NONE;
     728  }
     729
     730  Curl_wildcard_dtor(&data->wildcard);
     731
     732  /* destroy the timeout list that is held in the easy handle, do this *after*
     733     multi_done() as that may actually call Curl_expire that uses this */
     734  Curl_llist_destroy(&data->state.timeoutlist, NULL);
     735
     736  /* as this was using a shared connection cache we clear the pointer to that
     737     since we're not part of that multi handle anymore */
     738  data->state.conn_cache = NULL;
     739
     740  /* change state without using multistate(), only to make singlesocket() do
     741     what we want */
     742  data->mstate = CURLM_STATE_COMPLETED;
     743  singlesocket(multi, easy); /* to let the application know what sockets that
     744                                vanish with this handle */
     745
     746  /* Remove the association between the connection and the handle */
     747  if(data->conn) {
     748    data->conn->data = NULL;
     749    detach_connnection(data);
     750  }
     751
     752#ifdef USE_LIBPSL
     753  /* Remove the PSL association. */
     754  if(data->psl == &multi->psl)
     755    data->psl = NULL;
     756#endif
     757
     758  data->multi = NULL; /* clear the association to this multi handle */
     759
     760  /* make sure there's no pending message in the queue sent from this easy
     761     handle */
     762
     763  for(e = multi->msglist.head; e; e = e->next) {
     764    struct Curl_message *msg = e->ptr;
     765
     766    if(msg->extmsg.easy_handle == easy) {
     767      Curl_llist_remove(&multi->msglist, e, NULL);
     768      /* there can only be one from this specific handle */
     769      break;
     770    }
     771  }
     772
     773  /* make the previous node point to our next */
     774  if(data->prev)
     775    data->prev->next = data->next;
     776  else
     777    multi->easyp = data->next; /* point to first node */
     778
     779  /* make our next point to our previous node */
     780  if(data->next)
     781    data->next->prev = data->prev;
     782  else
     783    multi->easylp = data->prev; /* point to last node */
     784
     785  /* NOTE NOTE NOTE
     786     We do not touch the easy handle here! */
     787  multi->num_easy--; /* one less to care about now */
     788
     789  update_timer(multi);
     790  return CURLM_OK;
     791}
     792
     793/* Return TRUE if the application asked for multiplexing */
     794bool Curl_multiplex_wanted(const struct Curl_multi *multi)
     795{
     796  return (multi && (multi->multiplexing));
     797}
     798
     799/* This is the only function that should clear data->conn. This will
     800   occasionally be called with the pointer already cleared. */
     801static void detach_connnection(struct Curl_easy *data)
     802{
     803  struct connectdata *conn = data->conn;
     804  if(conn)
     805    Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
     806  data->conn = NULL;
     807}
     808
     809/* This is the only function that should assign data->conn */
     810void Curl_attach_connnection(struct Curl_easy *data,
     811                             struct connectdata *conn)
     812{
     813  DEBUGASSERT(!data->conn);
     814  DEBUGASSERT(conn);
     815  data->conn = conn;
     816  Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
     817                         &data->conn_queue);
     818}
     819
     820static int waitconnect_getsock(struct connectdata *conn,
     821                               curl_socket_t *sock,
     822                               int numsocks)
     823{
     824  int i;
     825  int s = 0;
     826  int rc = 0;
     827
     828  if(!numsocks)
     829    return GETSOCK_BLANK;
     830
     831#ifdef USE_SSL
     832  if(CONNECT_FIRSTSOCKET_PROXY_SSL())
     833    return Curl_ssl_getsock(conn, sock, numsocks);
     834#endif
     835
     836  for(i = 0; i<2; i++) {
     837    if(conn->tempsock[i] != CURL_SOCKET_BAD) {
     838      sock[s] = conn->tempsock[i];
     839      rc |= GETSOCK_WRITESOCK(s++);
     840    }
     841  }
     842
     843  return rc;
     844}
     845
     846static int waitproxyconnect_getsock(struct connectdata *conn,
     847                                    curl_socket_t *sock,
     848                                    int numsocks)
     849{
     850  if(!numsocks)
     851    return GETSOCK_BLANK;
     852
     853  sock[0] = conn->sock[FIRSTSOCKET];
     854
     855  /* when we've sent a CONNECT to a proxy, we should rather wait for the
     856     socket to become readable to be able to get the response headers */
     857  if(conn->connect_state)
     858    return GETSOCK_READSOCK(0);
     859
     860  return GETSOCK_WRITESOCK(0);
     861}
     862
     863static int domore_getsock(struct connectdata *conn,
     864                          curl_socket_t *socks,
     865                          int numsocks)
     866{
     867  if(conn && conn->handler->domore_getsock)
     868    return conn->handler->domore_getsock(conn, socks, numsocks);
     869  return GETSOCK_BLANK;
     870}
     871
     872/* returns bitmapped flags for this handle and its sockets */
     873static int multi_getsock(struct Curl_easy *data,
     874                         curl_socket_t *socks, /* points to numsocks number
     875                                                  of sockets */
     876                         int numsocks)
     877{
     878  /* The no connection case can happen when this is called from
     879     curl_multi_remove_handle() => singlesocket() => multi_getsock().
     880  */
     881  if(!data->conn)
     882    return 0;
     883
     884  if(data->mstate > CURLM_STATE_CONNECT &&
     885     data->mstate < CURLM_STATE_COMPLETED) {
     886    /* Set up ownership correctly */
     887    data->conn->data = data;
     888  }
     889
     890  switch(data->mstate) {
     891  default:
     892#if 0 /* switch back on these cases to get the compiler to check for all enums
     893         to be present */
     894  case CURLM_STATE_TOOFAST:  /* returns 0, so will not select. */
     895  case CURLM_STATE_COMPLETED:
     896  case CURLM_STATE_MSGSENT:
     897  case CURLM_STATE_INIT:
     898  case CURLM_STATE_CONNECT:
     899  case CURLM_STATE_WAITDO:
     900  case CURLM_STATE_DONE:
     901  case CURLM_STATE_LAST:
     902    /* this will get called with CURLM_STATE_COMPLETED when a handle is
     903       removed */
     904#endif
     905    return 0;
     906
     907  case CURLM_STATE_WAITRESOLVE:
     908    return Curl_resolv_getsock(data->conn, socks, numsocks);
     909
     910  case CURLM_STATE_PROTOCONNECT:
     911  case CURLM_STATE_SENDPROTOCONNECT:
     912    return Curl_protocol_getsock(data->conn, socks, numsocks);
     913
     914  case CURLM_STATE_DO:
     915  case CURLM_STATE_DOING:
     916    return Curl_doing_getsock(data->conn, socks, numsocks);
     917
     918  case CURLM_STATE_WAITPROXYCONNECT:
     919    return waitproxyconnect_getsock(data->conn, socks, numsocks);
     920
     921  case CURLM_STATE_WAITCONNECT:
     922    return waitconnect_getsock(data->conn, socks, numsocks);
     923
     924  case CURLM_STATE_DO_MORE:
     925    return domore_getsock(data->conn, socks, numsocks);
     926
     927  case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch
     928                               to waiting for the same as the *PERFORM
     929                               states */
     930  case CURLM_STATE_PERFORM:
     931    return Curl_single_getsock(data->conn, socks, numsocks);
     932  }
     933
     934}
     935
     936CURLMcode curl_multi_fdset(struct Curl_multi *multi,
     937                           fd_set *read_fd_set, fd_set *write_fd_set,
     938                           fd_set *exc_fd_set, int *max_fd)
     939{
     940  /* Scan through all the easy handles to get the file descriptors set.
     941     Some easy handles may not have connected to the remote host yet,
     942     and then we must make sure that is done. */
     943  struct Curl_easy *data;
     944  int this_max_fd = -1;
     945  curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
     946  int i;
     947  (void)exc_fd_set; /* not used */
     948
     949  if(!GOOD_MULTI_HANDLE(multi))
     950    return CURLM_BAD_HANDLE;
     951
     952  if(multi->in_callback)
     953    return CURLM_RECURSIVE_API_CALL;
     954
     955  data = multi->easyp;
     956  while(data) {
     957    int bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
     958
     959    for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
     960      curl_socket_t s = CURL_SOCKET_BAD;
     961
     962      if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
     963        FD_SET(sockbunch[i], read_fd_set);
     964        s = sockbunch[i];
     965      }
     966      if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
     967        FD_SET(sockbunch[i], write_fd_set);
     968        s = sockbunch[i];
     969      }
     970      if(s == CURL_SOCKET_BAD)
     971        /* this socket is unused, break out of loop */
     972        break;
     973      if((int)s > this_max_fd)
     974        this_max_fd = (int)s;
     975    }
     976
     977    data = data->next; /* check next handle */
     978  }
     979
     980  *max_fd = this_max_fd;
     981
     982  return CURLM_OK;
     983}
     984
     985#define NUM_POLLS_ON_STACK 10
     986
     987CURLMcode Curl_multi_wait(struct Curl_multi *multi,
     988                          struct curl_waitfd extra_fds[],
     989                          unsigned int extra_nfds,
     990                          int timeout_ms,
     991                          int *ret,
     992                          bool *gotsocket) /* if any socket was checked */
     993{
     994  struct Curl_easy *data;
     995  curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
     996  int bitmap;
     997  unsigned int i;
     998  unsigned int nfds = 0;
     999  unsigned int curlfds;
     1000  bool ufds_malloc = FALSE;
     1001  long timeout_internal;
     1002  int retcode = 0;
     1003  struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
     1004  struct pollfd *ufds = &a_few_on_stack[0];
     1005
     1006  if(gotsocket)
     1007    *gotsocket = FALSE;
     1008
     1009  if(!GOOD_MULTI_HANDLE(multi))
     1010    return CURLM_BAD_HANDLE;
     1011
     1012  if(multi->in_callback)
     1013    return CURLM_RECURSIVE_API_CALL;
     1014
     1015  /* Count up how many fds we have from the multi handle */
     1016  data = multi->easyp;
     1017  while(data) {
     1018    bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
     1019
     1020    for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
     1021      curl_socket_t s = CURL_SOCKET_BAD;
     1022
     1023      if(bitmap & GETSOCK_READSOCK(i)) {
     1024        ++nfds;
     1025        s = sockbunch[i];
     1026      }
     1027      if(bitmap & GETSOCK_WRITESOCK(i)) {
     1028        ++nfds;
     1029        s = sockbunch[i];
     1030      }
     1031      if(s == CURL_SOCKET_BAD) {
     1032        break;
     1033      }
     1034    }
     1035
     1036    data = data->next; /* check next handle */
     1037  }
     1038
     1039  /* If the internally desired timeout is actually shorter than requested from
     1040     the outside, then use the shorter time! But only if the internal timer
     1041     is actually larger than -1! */
     1042  (void)multi_timeout(multi, &timeout_internal);
     1043  if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
     1044    timeout_ms = (int)timeout_internal;
     1045
     1046  curlfds = nfds; /* number of internal file descriptors */
     1047  nfds += extra_nfds; /* add the externally provided ones */
     1048
     1049  if(nfds > NUM_POLLS_ON_STACK) {
     1050    /* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes
     1051       big, so at 2^29 sockets this value might wrap. When a process gets
     1052       the capability to actually handle over 500 million sockets this
     1053       calculation needs a integer overflow check. */
     1054    ufds = malloc(nfds * sizeof(struct pollfd));
     1055    if(!ufds)
     1056      return CURLM_OUT_OF_MEMORY;
     1057    ufds_malloc = TRUE;
     1058  }
     1059  nfds = 0;
     1060
     1061  /* only do the second loop if we found descriptors in the first stage run
     1062     above */
     1063
     1064  if(curlfds) {
     1065    /* Add the curl handles to our pollfds first */
     1066    data = multi->easyp;
     1067    while(data) {
     1068      bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
     1069
     1070      for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
     1071        curl_socket_t s = CURL_SOCKET_BAD;
     1072
     1073        if(bitmap & GETSOCK_READSOCK(i)) {
     1074          ufds[nfds].fd = sockbunch[i];
     1075          ufds[nfds].events = POLLIN;
     1076          ++nfds;
     1077          s = sockbunch[i];
     1078        }
     1079        if(bitmap & GETSOCK_WRITESOCK(i)) {
     1080          ufds[nfds].fd = sockbunch[i];
     1081          ufds[nfds].events = POLLOUT;
     1082          ++nfds;
     1083          s = sockbunch[i];
     1084        }
     1085        if(s == CURL_SOCKET_BAD) {
     1086          break;
     1087        }
     1088      }
     1089
     1090      data = data->next; /* check next handle */
     1091    }
     1092  }
     1093
     1094  /* Add external file descriptions from poll-like struct curl_waitfd */
     1095  for(i = 0; i < extra_nfds; i++) {
     1096    ufds[nfds].fd = extra_fds[i].fd;
     1097    ufds[nfds].events = 0;
     1098    if(extra_fds[i].events & CURL_WAIT_POLLIN)
     1099      ufds[nfds].events |= POLLIN;
     1100    if(extra_fds[i].events & CURL_WAIT_POLLPRI)
     1101      ufds[nfds].events |= POLLPRI;
     1102    if(extra_fds[i].events & CURL_WAIT_POLLOUT)
     1103      ufds[nfds].events |= POLLOUT;
     1104    ++nfds;
     1105  }
     1106
     1107  if(nfds) {
     1108    int pollrc;
     1109    /* wait... */
     1110    pollrc = Curl_poll(ufds, nfds, timeout_ms);
     1111
     1112    if(pollrc > 0) {
     1113      retcode = pollrc;
     1114      /* copy revents results from the poll to the curl_multi_wait poll
     1115         struct, the bit values of the actual underlying poll() implementation
     1116         may not be the same as the ones in the public libcurl API! */
     1117      for(i = 0; i < extra_nfds; i++) {
     1118        unsigned short mask = 0;
     1119        unsigned r = ufds[curlfds + i].revents;
     1120
     1121        if(r & POLLIN)
     1122          mask |= CURL_WAIT_POLLIN;
     1123        if(r & POLLOUT)
     1124          mask |= CURL_WAIT_POLLOUT;
     1125        if(r & POLLPRI)
     1126          mask |= CURL_WAIT_POLLPRI;
     1127
     1128        extra_fds[i].revents = mask;
     1129      }
     1130    }
     1131  }
     1132
     1133  if(ufds_malloc)
     1134    free(ufds);
     1135  if(ret)
     1136    *ret = retcode;
     1137  if(gotsocket && (extra_fds || curlfds))
     1138    /* if any socket was checked */
     1139    *gotsocket = TRUE;
     1140
     1141  return CURLM_OK;
     1142}
     1143
     1144CURLMcode curl_multi_wait(struct Curl_multi *multi,
     1145                          struct curl_waitfd extra_fds[],
     1146                          unsigned int extra_nfds,
     1147                          int timeout_ms,
     1148                          int *ret)
     1149{
     1150  return Curl_multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, NULL);
     1151}
     1152
     1153/*
     1154 * multi_ischanged() is called
     1155 *
     1156 * Returns TRUE/FALSE whether the state is changed to trigger a CONNECT_PEND
     1157 * => CONNECT action.
     1158 *
     1159 * Set 'clear' to TRUE to have it also clear the state variable.
     1160 */
     1161static bool multi_ischanged(struct Curl_multi *multi, bool clear)
     1162{
     1163  bool retval = multi->recheckstate;
     1164  if(clear)
     1165    multi->recheckstate = FALSE;
     1166  return retval;
     1167}
     1168
     1169CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
     1170                                 struct Curl_easy *data,
     1171                                 struct connectdata *conn)
     1172{
     1173  CURLMcode rc;
     1174
     1175  if(multi->in_callback)
     1176    return CURLM_RECURSIVE_API_CALL;
     1177
     1178  rc = curl_multi_add_handle(multi, data);
     1179  if(!rc) {
     1180    struct SingleRequest *k = &data->req;
     1181
     1182    /* pass in NULL for 'conn' here since we don't want to init the
     1183       connection, only this transfer */
     1184    Curl_init_do(data, NULL);
     1185
     1186    /* take this handle to the perform state right away */
     1187    multistate(data, CURLM_STATE_PERFORM);
     1188    Curl_attach_connnection(data, conn);
     1189    k->keepon |= KEEP_RECV; /* setup to receive! */
     1190  }
     1191  return rc;
     1192}
     1193
     1194/*
     1195 * do_complete is called when the DO actions are complete.
     1196 *
     1197 * We init chunking and trailer bits to their default values here immediately
     1198 * before receiving any header data for the current request.
     1199 */
     1200static void do_complete(struct connectdata *conn)
     1201{
     1202  conn->data->req.chunk = FALSE;
     1203  Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
     1204}
     1205
     1206static CURLcode multi_do(struct Curl_easy *data, bool *done)
     1207{
     1208  CURLcode result = CURLE_OK;
     1209  struct connectdata *conn = data->conn;
     1210
     1211  DEBUGASSERT(conn);
     1212  DEBUGASSERT(conn->handler);
     1213
     1214  if(conn->handler->do_it) {
     1215    /* generic protocol-specific function pointer set in curl_connect() */
     1216    result = conn->handler->do_it(conn, done);
     1217
     1218    if(!result && *done)
     1219      /* do_complete must be called after the protocol-specific DO function */
     1220      do_complete(conn);
     1221  }
     1222  return result;
     1223}
     1224
     1225/*
     1226 * multi_do_more() is called during the DO_MORE multi state. It is basically a
     1227 * second stage DO state which (wrongly) was introduced to support FTP's
     1228 * second connection.
     1229 *
     1230 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to
     1231 * DOING state there's more work to do!
     1232 */
     1233
     1234static CURLcode multi_do_more(struct connectdata *conn, int *complete)
     1235{
     1236  CURLcode result = CURLE_OK;
     1237
     1238  *complete = 0;
     1239
     1240  if(conn->handler->do_more)
     1241    result = conn->handler->do_more(conn, complete);
     1242
     1243  if(!result && (*complete == 1))
     1244    /* do_complete must be called after the protocol-specific DO function */
     1245    do_complete(conn);
     1246
     1247  return result;
     1248}
     1249
     1250static CURLMcode multi_runsingle(struct Curl_multi *multi,
     1251                                 struct curltime now,
     1252                                 struct Curl_easy *data)
     1253{
     1254  struct Curl_message *msg = NULL;
     1255  bool connected;
     1256  bool async;
     1257  bool protocol_connect = FALSE;
     1258  bool dophase_done = FALSE;
     1259  bool done = FALSE;
     1260  CURLMcode rc;
     1261  CURLcode result = CURLE_OK;
     1262  timediff_t timeout_ms;
     1263  timediff_t recv_timeout_ms;
     1264  timediff_t send_timeout_ms;
     1265  int control;
     1266
     1267  if(!GOOD_EASY_HANDLE(data))
     1268    return CURLM_BAD_EASY_HANDLE;
     1269
     1270  do {
     1271    /* A "stream" here is a logical stream if the protocol can handle that
     1272       (HTTP/2), or the full connection for older protocols */
     1273    bool stream_error = FALSE;
     1274    rc = CURLM_OK;
     1275
     1276    DEBUGASSERT((data->mstate <= CURLM_STATE_CONNECT) ||
     1277                (data->mstate >= CURLM_STATE_DONE) ||
     1278                data->conn);
     1279    if(!data->conn &&
     1280       data->mstate > CURLM_STATE_CONNECT &&
     1281       data->mstate < CURLM_STATE_DONE) {
     1282      /* In all these states, the code will blindly access 'data->conn'
     1283         so this is precaution that it isn't NULL. And it silences static
     1284         analyzers. */
     1285      failf(data, "In state %d with no conn, bail out!\n", data->mstate);
     1286      return CURLM_INTERNAL_ERROR;
     1287    }
     1288
     1289    if(multi_ischanged(multi, TRUE)) {
     1290      DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n"));
     1291      process_pending_handles(multi); /* multiplexed */
     1292    }
     1293
     1294    if(data->conn && data->mstate > CURLM_STATE_CONNECT &&
     1295       data->mstate < CURLM_STATE_COMPLETED) {
     1296      /* Make sure we set the connection's current owner */
     1297      data->conn->data = data;
     1298    }
     1299
     1300    if(data->conn &&
     1301       (data->mstate >= CURLM_STATE_CONNECT) &&
     1302       (data->mstate < CURLM_STATE_COMPLETED)) {
     1303      /* we need to wait for the connect state as only then is the start time
     1304         stored, but we must not check already completed handles */
     1305      timeout_ms = Curl_timeleft(data, &now,
     1306                                 (data->mstate <= CURLM_STATE_DO)?
     1307                                 TRUE:FALSE);
     1308
     1309      if(timeout_ms < 0) {
     1310        /* Handle timed out */
     1311        if(data->mstate == CURLM_STATE_WAITRESOLVE)
     1312          failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
     1313                " milliseconds",
     1314                Curl_timediff(now, data->progress.t_startsingle));
     1315        else if(data->mstate == CURLM_STATE_WAITCONNECT)
     1316          failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
     1317                " milliseconds",
     1318                Curl_timediff(now, data->progress.t_startsingle));
     1319        else {
     1320          struct SingleRequest *k = &data->req;
     1321          if(k->size != -1) {
     1322            failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
     1323                  " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
     1324                  CURL_FORMAT_CURL_OFF_T " bytes received",
     1325                  Curl_timediff(now, data->progress.t_startsingle),
     1326                  k->bytecount, k->size);
     1327          }
     1328          else {
     1329            failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
     1330                  " milliseconds with %" CURL_FORMAT_CURL_OFF_T
     1331                  " bytes received",
     1332                  Curl_timediff(now, data->progress.t_startsingle),
     1333                  k->bytecount);
     1334          }
     1335        }
     1336
     1337        /* Force connection closed if the connection has indeed been used */
     1338        if(data->mstate > CURLM_STATE_DO) {
     1339          streamclose(data->conn, "Disconnected with pending data");
     1340          stream_error = TRUE;
     1341        }
     1342        result = CURLE_OPERATION_TIMEDOUT;
     1343        (void)multi_done(data, result, TRUE);
     1344        /* Skip the statemachine and go directly to error handling section. */
     1345        goto statemachine_end;
     1346      }
     1347    }
     1348
     1349    switch(data->mstate) {
     1350    case CURLM_STATE_INIT:
     1351      /* init this transfer. */
     1352      result = Curl_pretransfer(data);
     1353
     1354      if(!result) {
     1355        /* after init, go CONNECT */
     1356        multistate(data, CURLM_STATE_CONNECT);
     1357        Curl_pgrsTime(data, TIMER_STARTOP);
     1358        rc = CURLM_CALL_MULTI_PERFORM;
     1359      }
     1360      break;
     1361
     1362    case CURLM_STATE_CONNECT_PEND:
     1363      /* We will stay here until there is a connection available. Then
     1364         we try again in the CURLM_STATE_CONNECT state. */
     1365      break;
     1366
     1367    case CURLM_STATE_CONNECT:
     1368      /* Connect. We want to get a connection identifier filled in. */
     1369      Curl_pgrsTime(data, TIMER_STARTSINGLE);
     1370      if(data->set.timeout)
     1371        Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
     1372
     1373      if(data->set.connecttimeout)
     1374        Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
     1375
     1376      result = Curl_connect(data, &async, &protocol_connect);
     1377      if(CURLE_NO_CONNECTION_AVAILABLE == result) {
     1378        /* There was no connection available. We will go to the pending
     1379           state and wait for an available connection. */
     1380        multistate(data, CURLM_STATE_CONNECT_PEND);
     1381
     1382        /* add this handle to the list of connect-pending handles */
     1383        Curl_llist_insert_next(&multi->pending, multi->pending.tail, data,
     1384                               &data->connect_queue);
     1385        result = CURLE_OK;
     1386        break;
     1387      }
     1388      else if(data->state.previouslypending) {
     1389        /* this transfer comes from the pending queue so try move another */
     1390        infof(data, "Transfer was pending, now try another\n");
     1391        process_pending_handles(data->multi);
     1392      }
     1393
     1394      if(!result) {
     1395        if(async)
     1396          /* We're now waiting for an asynchronous name lookup */
     1397          multistate(data, CURLM_STATE_WAITRESOLVE);
     1398        else {
     1399          /* after the connect has been sent off, go WAITCONNECT unless the
     1400             protocol connect is already done and we can go directly to
     1401             WAITDO or DO! */
     1402          rc = CURLM_CALL_MULTI_PERFORM;
     1403
     1404          if(protocol_connect)
     1405            multistate(data, CURLM_STATE_DO);
     1406          else {
     1407#ifndef CURL_DISABLE_HTTP
     1408            if(Curl_connect_ongoing(data->conn))
     1409              multistate(data, CURLM_STATE_WAITPROXYCONNECT);
     1410            else
     1411#endif
     1412              multistate(data, CURLM_STATE_WAITCONNECT);
     1413          }
     1414        }
     1415      }
     1416      break;
     1417
     1418    case CURLM_STATE_WAITRESOLVE:
     1419      /* awaiting an asynch name resolve to complete */
     1420    {
     1421      struct Curl_dns_entry *dns = NULL;
     1422      struct connectdata *conn = data->conn;
     1423      const char *hostname;
     1424
     1425      DEBUGASSERT(conn);
     1426      if(conn->bits.httpproxy)
     1427        hostname = conn->http_proxy.host.name;
     1428      else if(conn->bits.conn_to_host)
     1429        hostname = conn->conn_to_host.name;
     1430      else
     1431        hostname = conn->host.name;
     1432
     1433      /* check if we have the name resolved by now */
     1434      dns = Curl_fetch_addr(conn, hostname, (int)conn->port);
     1435
     1436      if(dns) {
     1437#ifdef CURLRES_ASYNCH
     1438        conn->async.dns = dns;
     1439        conn->async.done = TRUE;
     1440#endif
     1441        result = CURLE_OK;
     1442        infof(data, "Hostname '%s' was found in DNS cache\n", hostname);
     1443      }
     1444
     1445      if(!dns)
     1446        result = Curl_resolv_check(data->conn, &dns);
     1447
     1448      /* Update sockets here, because the socket(s) may have been
     1449         closed and the application thus needs to be told, even if it
     1450         is likely that the same socket(s) will again be used further
     1451         down.  If the name has not yet been resolved, it is likely
     1452         that new sockets have been opened in an attempt to contact
     1453         another resolver. */
     1454      singlesocket(multi, data);
     1455
     1456      if(dns) {
     1457        /* Perform the next step in the connection phase, and then move on
     1458           to the WAITCONNECT state */
     1459        result = Curl_once_resolved(data->conn, &protocol_connect);
     1460
     1461        if(result)
     1462          /* if Curl_once_resolved() returns failure, the connection struct
     1463             is already freed and gone */
     1464          data->conn = NULL; /* no more connection */
     1465        else {
     1466          /* call again please so that we get the next socket setup */
     1467          rc = CURLM_CALL_MULTI_PERFORM;
     1468          if(protocol_connect)
     1469            multistate(data, CURLM_STATE_DO);
     1470          else {
     1471#ifndef CURL_DISABLE_HTTP
     1472            if(Curl_connect_ongoing(data->conn))
     1473              multistate(data, CURLM_STATE_WAITPROXYCONNECT);
     1474            else
     1475#endif
     1476              multistate(data, CURLM_STATE_WAITCONNECT);
     1477          }
     1478        }
     1479      }
     1480
     1481      if(result) {
     1482        /* failure detected */
     1483        stream_error = TRUE;
     1484        break;
     1485      }
     1486    }
     1487    break;
     1488
     1489#ifndef CURL_DISABLE_HTTP
     1490    case CURLM_STATE_WAITPROXYCONNECT:
     1491      /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
     1492      DEBUGASSERT(data->conn);
     1493      result = Curl_http_connect(data->conn, &protocol_connect);
     1494
     1495      if(data->conn->bits.proxy_connect_closed) {
     1496        rc = CURLM_CALL_MULTI_PERFORM;
     1497        /* connect back to proxy again */
     1498        result = CURLE_OK;
     1499        multi_done(data, CURLE_OK, FALSE);
     1500        multistate(data, CURLM_STATE_CONNECT);
     1501      }
     1502      else if(!result) {
     1503        if((data->conn->http_proxy.proxytype != CURLPROXY_HTTPS ||
     1504           data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) &&
     1505           Curl_connect_complete(data->conn)) {
     1506          rc = CURLM_CALL_MULTI_PERFORM;
     1507          /* initiate protocol connect phase */
     1508          multistate(data, CURLM_STATE_SENDPROTOCONNECT);
     1509        }
     1510      }
     1511      else if(result)
     1512        stream_error = TRUE;
     1513      break;
     1514#endif
     1515
     1516    case CURLM_STATE_WAITCONNECT:
     1517      /* awaiting a completion of an asynch TCP connect */
     1518      DEBUGASSERT(data->conn);
     1519      result = Curl_is_connected(data->conn, FIRSTSOCKET, &connected);
     1520      if(connected && !result) {
     1521#ifndef CURL_DISABLE_HTTP
     1522        if((data->conn->http_proxy.proxytype == CURLPROXY_HTTPS &&
     1523            !data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
     1524           Curl_connect_ongoing(data->conn)) {
     1525          multistate(data, CURLM_STATE_WAITPROXYCONNECT);
     1526          break;
     1527        }
     1528#endif
     1529        rc = CURLM_CALL_MULTI_PERFORM;
     1530        multistate(data, data->conn->bits.tunnel_proxy?
     1531                   CURLM_STATE_WAITPROXYCONNECT:
     1532                   CURLM_STATE_SENDPROTOCONNECT);
     1533      }
     1534      else if(result) {
     1535        /* failure detected */
     1536        Curl_posttransfer(data);
     1537        multi_done(data, result, TRUE);
     1538        stream_error = TRUE;
     1539        break;
     1540      }
     1541      break;
     1542
     1543    case CURLM_STATE_SENDPROTOCONNECT:
     1544      result = Curl_protocol_connect(data->conn, &protocol_connect);
     1545      if(!result && !protocol_connect)
     1546        /* switch to waiting state */
     1547        multistate(data, CURLM_STATE_PROTOCONNECT);
     1548      else if(!result) {
     1549        /* protocol connect has completed, go WAITDO or DO */
     1550        multistate(data, CURLM_STATE_DO);
     1551        rc = CURLM_CALL_MULTI_PERFORM;
     1552      }
     1553      else if(result) {
     1554        /* failure detected */
     1555        Curl_posttransfer(data);
     1556        multi_done(data, result, TRUE);
     1557        stream_error = TRUE;
     1558      }
     1559      break;
     1560
     1561    case CURLM_STATE_PROTOCONNECT:
     1562      /* protocol-specific connect phase */
     1563      result = Curl_protocol_connecting(data->conn, &protocol_connect);
     1564      if(!result && protocol_connect) {
     1565        /* after the connect has completed, go WAITDO or DO */
     1566        multistate(data, CURLM_STATE_DO);
     1567        rc = CURLM_CALL_MULTI_PERFORM;
     1568      }
     1569      else if(result) {
     1570        /* failure detected */
     1571        Curl_posttransfer(data);
     1572        multi_done(data, result, TRUE);
     1573        stream_error = TRUE;
     1574      }
     1575      break;
     1576
     1577    case CURLM_STATE_DO:
     1578      if(data->set.connect_only) {
     1579        /* keep connection open for application to use the socket */
     1580        connkeep(data->conn, "CONNECT_ONLY");
     1581        multistate(data, CURLM_STATE_DONE);
     1582        result = CURLE_OK;
     1583        rc = CURLM_CALL_MULTI_PERFORM;
     1584      }
     1585      else {
     1586        /* Perform the protocol's DO action */
     1587        result = multi_do(data, &dophase_done);
     1588
     1589        /* When multi_do() returns failure, data->conn might be NULL! */
     1590
     1591        if(!result) {
     1592          if(!dophase_done) {
     1593#ifndef CURL_DISABLE_FTP
     1594            /* some steps needed for wildcard matching */
     1595            if(data->state.wildcardmatch) {
     1596              struct WildcardData *wc = &data->wildcard;
     1597              if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
     1598                /* skip some states if it is important */
     1599                multi_done(data, CURLE_OK, FALSE);
     1600                multistate(data, CURLM_STATE_DONE);
     1601                rc = CURLM_CALL_MULTI_PERFORM;
     1602                break;
     1603              }
     1604            }
     1605#endif
     1606            /* DO was not completed in one function call, we must continue
     1607               DOING... */
     1608            multistate(data, CURLM_STATE_DOING);
     1609            rc = CURLM_OK;
     1610          }
     1611
     1612          /* after DO, go DO_DONE... or DO_MORE */
     1613          else if(data->conn->bits.do_more) {
     1614            /* we're supposed to do more, but we need to sit down, relax
     1615               and wait a little while first */
     1616            multistate(data, CURLM_STATE_DO_MORE);
     1617            rc = CURLM_OK;
     1618          }
     1619          else {
     1620            /* we're done with the DO, now DO_DONE */
     1621            multistate(data, CURLM_STATE_DO_DONE);
     1622            rc = CURLM_CALL_MULTI_PERFORM;
     1623          }
     1624        }
     1625        else if((CURLE_SEND_ERROR == result) &&
     1626                data->conn->bits.reuse) {
     1627          /*
     1628           * In this situation, a connection that we were trying to use
     1629           * may have unexpectedly died.  If possible, send the connection
     1630           * back to the CONNECT phase so we can try again.
     1631           */
     1632          char *newurl = NULL;
     1633          followtype follow = FOLLOW_NONE;
     1634          CURLcode drc;
     1635
     1636          drc = Curl_retry_request(data->conn, &newurl);
     1637          if(drc) {
     1638            /* a failure here pretty much implies an out of memory */
     1639            result = drc;
     1640            stream_error = TRUE;
     1641          }
     1642
     1643          Curl_posttransfer(data);
     1644          drc = multi_done(data, result, FALSE);
     1645
     1646          /* When set to retry the connection, we must to go back to
     1647           * the CONNECT state */
     1648          if(newurl) {
     1649            if(!drc || (drc == CURLE_SEND_ERROR)) {
     1650              follow = FOLLOW_RETRY;
     1651              drc = Curl_follow(data, newurl, follow);
     1652              if(!drc) {
     1653                multistate(data, CURLM_STATE_CONNECT);
     1654                rc = CURLM_CALL_MULTI_PERFORM;
     1655                result = CURLE_OK;
     1656              }
     1657              else {
     1658                /* Follow failed */
     1659                result = drc;
     1660              }
     1661            }
     1662            else {
     1663              /* done didn't return OK or SEND_ERROR */
     1664              result = drc;
     1665            }
     1666          }
     1667          else {
     1668            /* Have error handler disconnect conn if we can't retry */
     1669            stream_error = TRUE;
     1670          }
     1671          free(newurl);
     1672        }
     1673        else {
     1674          /* failure detected */
     1675          Curl_posttransfer(data);
     1676          if(data->conn)
     1677            multi_done(data, result, FALSE);
     1678          stream_error = TRUE;
     1679        }
     1680      }
     1681      break;
     1682
     1683    case CURLM_STATE_DOING:
     1684      /* we continue DOING until the DO phase is complete */
     1685      DEBUGASSERT(data->conn);
     1686      result = Curl_protocol_doing(data->conn,
     1687                                   &dophase_done);
     1688      if(!result) {
     1689        if(dophase_done) {
     1690          /* after DO, go DO_DONE or DO_MORE */
     1691          multistate(data, data->conn->bits.do_more?
     1692                     CURLM_STATE_DO_MORE:
     1693                     CURLM_STATE_DO_DONE);
     1694          rc = CURLM_CALL_MULTI_PERFORM;
     1695        } /* dophase_done */
     1696      }
     1697      else {
     1698        /* failure detected */
     1699        Curl_posttransfer(data);
     1700        multi_done(data, result, FALSE);
     1701        stream_error = TRUE;
     1702      }
     1703      break;
     1704
     1705    case CURLM_STATE_DO_MORE:
     1706      /*
     1707       * When we are connected, DO MORE and then go DO_DONE
     1708       */
     1709      DEBUGASSERT(data->conn);
     1710      result = multi_do_more(data->conn, &control);
     1711
     1712      if(!result) {
     1713        if(control) {
     1714          /* if positive, advance to DO_DONE
     1715             if negative, go back to DOING */
     1716          multistate(data, control == 1?
     1717                     CURLM_STATE_DO_DONE:
     1718                     CURLM_STATE_DOING);
     1719          rc = CURLM_CALL_MULTI_PERFORM;
     1720        }
     1721        else
     1722          /* stay in DO_MORE */
     1723          rc = CURLM_OK;
     1724      }
     1725      else {
     1726        /* failure detected */
     1727        Curl_posttransfer(data);
     1728        multi_done(data, result, FALSE);
     1729        stream_error = TRUE;
     1730      }
     1731      break;
     1732
     1733    case CURLM_STATE_DO_DONE:
     1734      DEBUGASSERT(data->conn);
     1735      if(data->conn->bits.multiplex)
     1736        /* Check if we can move pending requests to send pipe */
     1737        process_pending_handles(multi); /*  multiplexed */
     1738
     1739      /* Only perform the transfer if there's a good socket to work with.
     1740         Having both BAD is a signal to skip immediately to DONE */
     1741      if((data->conn->sockfd != CURL_SOCKET_BAD) ||
     1742         (data->conn->writesockfd != CURL_SOCKET_BAD))
     1743        multistate(data, CURLM_STATE_PERFORM);
     1744      else {
     1745#ifndef CURL_DISABLE_FTP
     1746        if(data->state.wildcardmatch &&
     1747           ((data->conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
     1748          data->wildcard.state = CURLWC_DONE;
     1749        }
     1750#endif
     1751        multistate(data, CURLM_STATE_DONE);
     1752      }
     1753      rc = CURLM_CALL_MULTI_PERFORM;
     1754      break;
     1755
     1756    case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */
     1757      DEBUGASSERT(data->conn);
     1758      /* if both rates are within spec, resume transfer */
     1759      if(Curl_pgrsUpdate(data->conn))
     1760        result = CURLE_ABORTED_BY_CALLBACK;
     1761      else
     1762        result = Curl_speedcheck(data, now);
     1763
     1764      if(!result) {
     1765        send_timeout_ms = 0;
     1766        if(data->set.max_send_speed > 0)
     1767          send_timeout_ms =
     1768            Curl_pgrsLimitWaitTime(data->progress.uploaded,
     1769                                   data->progress.ul_limit_size,
     1770                                   data->set.max_send_speed,
     1771                                   data->progress.ul_limit_start,
     1772                                   now);
     1773
     1774        recv_timeout_ms = 0;
     1775        if(data->set.max_recv_speed > 0)
     1776          recv_timeout_ms =
     1777            Curl_pgrsLimitWaitTime(data->progress.downloaded,
     1778                                   data->progress.dl_limit_size,
     1779                                   data->set.max_recv_speed,
     1780                                   data->progress.dl_limit_start,
     1781                                   now);
     1782
     1783        if(!send_timeout_ms && !recv_timeout_ms) {
     1784          multistate(data, CURLM_STATE_PERFORM);
     1785          Curl_ratelimit(data, now);
     1786        }
     1787        else if(send_timeout_ms >= recv_timeout_ms)
     1788          Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
     1789        else
     1790          Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST);
     1791      }
     1792      break;
     1793
     1794    case CURLM_STATE_PERFORM:
     1795    {
     1796      char *newurl = NULL;
     1797      bool retry = FALSE;
     1798      bool comeback = FALSE;
     1799
     1800      /* check if over send speed */
     1801      send_timeout_ms = 0;
     1802      if(data->set.max_send_speed > 0)
     1803        send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded,
     1804                                                 data->progress.ul_limit_size,
     1805                                                 data->set.max_send_speed,
     1806                                                 data->progress.ul_limit_start,
     1807                                                 now);
     1808
     1809      /* check if over recv speed */
     1810      recv_timeout_ms = 0;
     1811      if(data->set.max_recv_speed > 0)
     1812        recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded,
     1813                                                 data->progress.dl_limit_size,
     1814                                                 data->set.max_recv_speed,
     1815                                                 data->progress.dl_limit_start,
     1816                                                 now);
     1817
     1818      if(send_timeout_ms || recv_timeout_ms) {
     1819        Curl_ratelimit(data, now);
     1820        multistate(data, CURLM_STATE_TOOFAST);
     1821        if(send_timeout_ms >= recv_timeout_ms)
     1822          Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
     1823        else
     1824          Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST);
     1825        break;
     1826      }
     1827
     1828      /* read/write data if it is ready to do so */
     1829      result = Curl_readwrite(data->conn, data, &done, &comeback);
     1830
     1831      if(done || (result == CURLE_RECV_ERROR)) {
     1832        /* If CURLE_RECV_ERROR happens early enough, we assume it was a race
     1833         * condition and the server closed the re-used connection exactly when
     1834         * we wanted to use it, so figure out if that is indeed the case.
     1835         */
     1836        CURLcode ret = Curl_retry_request(data->conn, &newurl);
     1837        if(!ret)
     1838          retry = (newurl)?TRUE:FALSE;
     1839        else if(!result)
     1840          result = ret;
     1841
     1842        if(retry) {
     1843          /* if we are to retry, set the result to OK and consider the
     1844             request as done */
     1845          result = CURLE_OK;
     1846          done = TRUE;
     1847        }
     1848      }
     1849      else if((CURLE_HTTP2_STREAM == result) &&
     1850              Curl_h2_http_1_1_error(data->conn)) {
     1851        CURLcode ret = Curl_retry_request(data->conn, &newurl);
     1852
     1853        if(!ret) {
     1854          infof(data, "Downgrades to HTTP/1.1!\n");
     1855          data->set.httpversion = CURL_HTTP_VERSION_1_1;
     1856          /* clear the error message bit too as we ignore the one we got */
     1857          data->state.errorbuf = FALSE;
     1858          if(!newurl)
     1859            /* typically for HTTP_1_1_REQUIRED error on first flight */
     1860            newurl = strdup(data->change.url);
     1861          /* if we are to retry, set the result to OK and consider the request
     1862             as done */
     1863          retry = TRUE;
     1864          result = CURLE_OK;
     1865          done = TRUE;
     1866        }
     1867        else
     1868          result = ret;
     1869      }
     1870
     1871      if(result) {
     1872        /*
     1873         * The transfer phase returned error, we mark the connection to get
     1874         * closed to prevent being re-used. This is because we can't possibly
     1875         * know if the connection is in a good shape or not now.  Unless it is
     1876         * a protocol which uses two "channels" like FTP, as then the error
     1877         * happened in the data connection.
     1878         */
     1879
     1880        if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
     1881           result != CURLE_HTTP2_STREAM)
     1882          streamclose(data->conn, "Transfer returned error");
     1883
     1884        Curl_posttransfer(data);
     1885        multi_done(data, result, TRUE);
     1886      }
     1887      else if(done) {
     1888        followtype follow = FOLLOW_NONE;
     1889
     1890        /* call this even if the readwrite function returned error */
     1891        Curl_posttransfer(data);
     1892
     1893        /* When we follow redirects or is set to retry the connection, we must
     1894           to go back to the CONNECT state */
     1895        if(data->req.newurl || retry) {
     1896          if(!retry) {
     1897            /* if the URL is a follow-location and not just a retried request
     1898               then figure out the URL here */
     1899            free(newurl);
     1900            newurl = data->req.newurl;
     1901            data->req.newurl = NULL;
     1902            follow = FOLLOW_REDIR;
     1903          }
     1904          else
     1905            follow = FOLLOW_RETRY;
     1906          (void)multi_done(data, CURLE_OK, FALSE);
     1907          /* multi_done() might return CURLE_GOT_NOTHING */
     1908          result = Curl_follow(data, newurl, follow);
     1909          if(!result) {
     1910            multistate(data, CURLM_STATE_CONNECT);
     1911            rc = CURLM_CALL_MULTI_PERFORM;
     1912          }
     1913          free(newurl);
     1914        }
     1915        else {
     1916          /* after the transfer is done, go DONE */
     1917
     1918          /* but first check to see if we got a location info even though we're
     1919             not following redirects */
     1920          if(data->req.location) {
     1921            free(newurl);
     1922            newurl = data->req.location;
     1923            data->req.location = NULL;
     1924            result = Curl_follow(data, newurl, FOLLOW_FAKE);
     1925            free(newurl);
     1926            if(result) {
     1927              stream_error = TRUE;
     1928              result = multi_done(data, result, TRUE);
     1929            }
     1930          }
     1931
     1932          if(!result) {
     1933            multistate(data, CURLM_STATE_DONE);
     1934            rc = CURLM_CALL_MULTI_PERFORM;
     1935          }
     1936        }
     1937      }
     1938      else if(comeback)
     1939        rc = CURLM_CALL_MULTI_PERFORM;
     1940      break;
     1941    }
     1942
     1943    case CURLM_STATE_DONE:
     1944      /* this state is highly transient, so run another loop after this */
     1945      rc = CURLM_CALL_MULTI_PERFORM;
     1946
     1947      if(data->conn) {
     1948        CURLcode res;
     1949
     1950        if(data->conn->bits.multiplex)
     1951          /* Check if we can move pending requests to connection */
     1952          process_pending_handles(multi); /* multiplexing */
     1953
     1954        /* post-transfer command */
     1955        res = multi_done(data, result, FALSE);
     1956
     1957        /* allow a previously set error code take precedence */
     1958        if(!result)
     1959          result = res;
     1960
     1961        /*
     1962         * If there are other handles on the connection, multi_done won't set
     1963         * conn to NULL.  In such a case, curl_multi_remove_handle() can
     1964         * access free'd data, if the connection is free'd and the handle
     1965         * removed before we perform the processing in CURLM_STATE_COMPLETED
     1966         */
     1967        if(data->conn)
     1968          detach_connnection(data);
     1969      }
     1970
     1971#ifndef CURL_DISABLE_FTP
     1972      if(data->state.wildcardmatch) {
     1973        if(data->wildcard.state != CURLWC_DONE) {
     1974          /* if a wildcard is set and we are not ending -> lets start again
     1975             with CURLM_STATE_INIT */
     1976          multistate(data, CURLM_STATE_INIT);
     1977          break;
     1978        }
     1979      }
     1980#endif
     1981      /* after we have DONE what we're supposed to do, go COMPLETED, and
     1982         it doesn't matter what the multi_done() returned! */
     1983      multistate(data, CURLM_STATE_COMPLETED);
     1984      break;
     1985
     1986    case CURLM_STATE_COMPLETED:
     1987      break;
     1988
     1989    case CURLM_STATE_MSGSENT:
     1990      data->result = result;
     1991      return CURLM_OK; /* do nothing */
     1992
     1993    default:
     1994      return CURLM_INTERNAL_ERROR;
     1995    }
     1996    statemachine_end:
     1997
     1998    if(data->mstate < CURLM_STATE_COMPLETED) {
     1999      if(result) {
     2000        /*
     2001         * If an error was returned, and we aren't in completed state now,
     2002         * then we go to completed and consider this transfer aborted.
     2003         */
     2004
     2005        /* NOTE: no attempt to disconnect connections must be made
     2006           in the case blocks above - cleanup happens only here */
     2007
     2008        /* Check if we can move pending requests to send pipe */
     2009        process_pending_handles(multi); /* connection */
     2010
     2011        if(data->conn) {
     2012          if(stream_error) {
     2013            /* Don't attempt to send data over a connection that timed out */
     2014            bool dead_connection = result == CURLE_OPERATION_TIMEDOUT;
     2015            /* disconnect properly */
     2016            Curl_disconnect(data, data->conn, dead_connection);
     2017
     2018            /* This is where we make sure that the conn pointer is reset.
     2019               We don't have to do this in every case block above where a
     2020               failure is detected */
     2021            detach_connnection(data);
     2022          }
     2023        }
     2024        else if(data->mstate == CURLM_STATE_CONNECT) {
     2025          /* Curl_connect() failed */
     2026          (void)Curl_posttransfer(data);
     2027        }
     2028
     2029        multistate(data, CURLM_STATE_COMPLETED);
     2030        rc = CURLM_CALL_MULTI_PERFORM;
     2031      }
     2032      /* if there's still a connection to use, call the progress function */
     2033      else if(data->conn && Curl_pgrsUpdate(data->conn)) {
     2034        /* aborted due to progress callback return code must close the
     2035           connection */
     2036        result = CURLE_ABORTED_BY_CALLBACK;
     2037        streamclose(data->conn, "Aborted by callback");
     2038
     2039        /* if not yet in DONE state, go there, otherwise COMPLETED */
     2040        multistate(data, (data->mstate < CURLM_STATE_DONE)?
     2041                   CURLM_STATE_DONE: CURLM_STATE_COMPLETED);
     2042        rc = CURLM_CALL_MULTI_PERFORM;
     2043      }
     2044    }
     2045
     2046    if(CURLM_STATE_COMPLETED == data->mstate) {
     2047      if(data->set.fmultidone) {
     2048        /* signal via callback instead */
     2049        data->set.fmultidone(data, result);
     2050      }
     2051      else {
     2052        /* now fill in the Curl_message with this info */
     2053        msg = &data->msg;
     2054
     2055        msg->extmsg.msg = CURLMSG_DONE;
     2056        msg->extmsg.easy_handle = data;
     2057        msg->extmsg.data.result = result;
     2058
     2059        rc = multi_addmsg(multi, msg);
     2060        DEBUGASSERT(!data->conn);
     2061      }
     2062      multistate(data, CURLM_STATE_MSGSENT);
     2063    }
     2064  } while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE));
     2065
     2066  data->result = result;
     2067  return rc;
     2068}
     2069
     2070
     2071CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
     2072{
     2073  struct Curl_easy *data;
     2074  CURLMcode returncode = CURLM_OK;
     2075  struct Curl_tree *t;
     2076  struct curltime now = Curl_now();
     2077
     2078  if(!GOOD_MULTI_HANDLE(multi))
     2079    return CURLM_BAD_HANDLE;
     2080
     2081  if(multi->in_callback)
     2082    return CURLM_RECURSIVE_API_CALL;
     2083
     2084  data = multi->easyp;
     2085  while(data) {
     2086    CURLMcode result;
     2087    SIGPIPE_VARIABLE(pipe_st);
     2088
     2089    sigpipe_ignore(data, &pipe_st);
     2090    result = multi_runsingle(multi, now, data);
     2091    sigpipe_restore(&pipe_st);
     2092
     2093    if(result)
     2094      returncode = result;
     2095
     2096    data = data->next; /* operate on next handle */
     2097  }
     2098
     2099  /*
     2100   * Simply remove all expired timers from the splay since handles are dealt
     2101   * with unconditionally by this function and curl_multi_timeout() requires
     2102   * that already passed/handled expire times are removed from the splay.
     2103   *
     2104   * It is important that the 'now' value is set at the entry of this function
     2105   * and not for the current time as it may have ticked a little while since
     2106   * then and then we risk this loop to remove timers that actually have not
     2107   * been handled!
     2108   */
     2109  do {
     2110    multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
     2111    if(t)
     2112      /* the removed may have another timeout in queue */
     2113      (void)add_next_timeout(now, multi, t->payload);
     2114
     2115  } while(t);
     2116
     2117  *running_handles = multi->num_alive;
     2118
     2119  if(CURLM_OK >= returncode)
     2120    update_timer(multi);
     2121
     2122  return returncode;
     2123}
     2124
     2125CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
     2126{
     2127  struct Curl_easy *data;
     2128  struct Curl_easy *nextdata;
     2129
     2130  if(GOOD_MULTI_HANDLE(multi)) {
     2131    if(multi->in_callback)
     2132      return CURLM_RECURSIVE_API_CALL;
     2133
     2134    multi->type = 0; /* not good anymore */
     2135
     2136    /* Firsrt remove all remaining easy handles */
     2137    data = multi->easyp;
     2138    while(data) {
     2139      nextdata = data->next;
     2140      if(!data->state.done && data->conn)
     2141        /* if DONE was never called for this handle */
     2142        (void)multi_done(data, CURLE_OK, TRUE);
     2143      if(data->dns.hostcachetype == HCACHE_MULTI) {
     2144        /* clear out the usage of the shared DNS cache */
     2145        Curl_hostcache_clean(data, data->dns.hostcache);
     2146        data->dns.hostcache = NULL;
     2147        data->dns.hostcachetype = HCACHE_NONE;
     2148      }
     2149
     2150      /* Clear the pointer to the connection cache */
     2151      data->state.conn_cache = NULL;
     2152      data->multi = NULL; /* clear the association */
     2153
     2154#ifdef USE_LIBPSL
     2155      if(data->psl == &multi->psl)
     2156        data->psl = NULL;
     2157#endif
     2158
     2159      data = nextdata;
     2160    }
     2161
     2162    /* Close all the connections in the connection cache */
     2163    Curl_conncache_close_all_connections(&multi->conn_cache);
     2164
     2165    Curl_hash_destroy(&multi->sockhash);
     2166    Curl_conncache_destroy(&multi->conn_cache);
     2167    Curl_llist_destroy(&multi->msglist, NULL);
     2168    Curl_llist_destroy(&multi->pending, NULL);
     2169
     2170    Curl_hash_destroy(&multi->hostcache);
     2171    Curl_psl_destroy(&multi->psl);
     2172    free(multi);
     2173
     2174    return CURLM_OK;
     2175  }
     2176  return CURLM_BAD_HANDLE;
     2177}
     2178
     2179/*
     2180 * curl_multi_info_read()
     2181 *
     2182 * This function is the primary way for a multi/multi_socket application to
     2183 * figure out if a transfer has ended. We MUST make this function as fast as
     2184 * possible as it will be polled frequently and we MUST NOT scan any lists in
     2185 * here to figure out things. We must scale fine to thousands of handles and
     2186 * beyond. The current design is fully O(1).
     2187 */
     2188
     2189CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue)
     2190{
     2191  struct Curl_message *msg;
     2192
     2193  *msgs_in_queue = 0; /* default to none */
     2194
     2195  if(GOOD_MULTI_HANDLE(multi) &&
     2196     !multi->in_callback &&
     2197     Curl_llist_count(&multi->msglist)) {
     2198    /* there is one or more messages in the list */
     2199    struct curl_llist_element *e;
     2200
     2201    /* extract the head of the list to return */
     2202    e = multi->msglist.head;
     2203
     2204    msg = e->ptr;
     2205
     2206    /* remove the extracted entry */
     2207    Curl_llist_remove(&multi->msglist, e, NULL);
     2208
     2209    *msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist));
     2210
     2211    return &msg->extmsg;
     2212  }
     2213  return NULL;
     2214}
     2215
     2216/*
     2217 * singlesocket() checks what sockets we deal with and their "action state"
     2218 * and if we have a different state in any of those sockets from last time we
     2219 * call the callback accordingly.
     2220 */
     2221static CURLMcode singlesocket(struct Curl_multi *multi,
     2222                              struct Curl_easy *data)
     2223{
     2224  curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
     2225  int i;
     2226  struct Curl_sh_entry *entry;
     2227  curl_socket_t s;
     2228  int num;
     2229  unsigned int curraction;
     2230  int actions[MAX_SOCKSPEREASYHANDLE];
     2231
     2232  for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
     2233    socks[i] = CURL_SOCKET_BAD;
     2234
     2235  /* Fill in the 'current' struct with the state as it is now: what sockets to
     2236     supervise and for what actions */
     2237  curraction = multi_getsock(data, socks, MAX_SOCKSPEREASYHANDLE);
     2238
     2239  /* We have 0 .. N sockets already and we get to know about the 0 .. M
     2240     sockets we should have from now on. Detect the differences, remove no
     2241     longer supervised ones and add new ones */
     2242
     2243  /* walk over the sockets we got right now */
     2244  for(i = 0; (i< MAX_SOCKSPEREASYHANDLE) &&
     2245        (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
     2246      i++) {
     2247    unsigned int action = CURL_POLL_NONE;
     2248    unsigned int prevaction = 0;
     2249    unsigned int comboaction;
     2250    bool sincebefore = FALSE;
     2251
     2252    s = socks[i];
     2253
     2254    /* get it from the hash */
     2255    entry = sh_getentry(&multi->sockhash, s);
     2256
     2257    if(curraction & GETSOCK_READSOCK(i))
     2258      action |= CURL_POLL_IN;
     2259    if(curraction & GETSOCK_WRITESOCK(i))
     2260      action |= CURL_POLL_OUT;
     2261
     2262    actions[i] = action;
     2263    if(entry) {
     2264      /* check if new for this transfer */
     2265      int j;
     2266      for(j = 0; j< data->numsocks; j++) {
     2267        if(s == data->sockets[j]) {
     2268          prevaction = data->actions[j];
     2269          sincebefore = TRUE;
     2270          break;
     2271        }
     2272      }
     2273    }
     2274    else {
     2275      /* this is a socket we didn't have before, add it to the hash! */
     2276      entry = sh_addentry(&multi->sockhash, s);
     2277      if(!entry)
     2278        /* fatal */
     2279        return CURLM_OUT_OF_MEMORY;
     2280    }
     2281    if(sincebefore && (prevaction != action)) {
     2282      /* Socket was used already, but different action now */
     2283      if(prevaction & CURL_POLL_IN)
     2284        entry->readers--;
     2285      if(prevaction & CURL_POLL_OUT)
     2286        entry->writers--;
     2287      if(action & CURL_POLL_IN)
     2288        entry->readers++;
     2289      if(action & CURL_POLL_OUT)
     2290        entry->writers++;
     2291    }
     2292    else if(!sincebefore) {
     2293      /* a new user */
     2294      entry->users++;
     2295      if(action & CURL_POLL_IN)
     2296        entry->readers++;
     2297      if(action & CURL_POLL_OUT)
     2298        entry->writers++;
     2299
     2300      /* add 'data' to the transfer hash on this socket! */
     2301      if(!Curl_hash_add(&entry->transfers, (char *)&data, /* hash key */
     2302                        sizeof(struct Curl_easy *), data))
     2303        return CURLM_OUT_OF_MEMORY;
     2304    }
     2305
     2306    comboaction = (entry->writers? CURL_POLL_OUT : 0) |
     2307      (entry->readers ? CURL_POLL_IN : 0);
     2308
     2309    /* socket existed before and has the same action set as before */
     2310    if(sincebefore && (entry->action == comboaction))
     2311      /* same, continue */
     2312      continue;
     2313
     2314    if(multi->socket_cb)
     2315      multi->socket_cb(data, s, comboaction, multi->socket_userp,
     2316                       entry->socketp);
     2317
     2318    entry->action = comboaction; /* store the current action state */
     2319  }
     2320
     2321  num = i; /* number of sockets */
     2322
     2323  /* when we've walked over all the sockets we should have right now, we must
     2324     make sure to detect sockets that are removed */
     2325  for(i = 0; i< data->numsocks; i++) {
     2326    int j;
     2327    bool stillused = FALSE;
     2328    s = data->sockets[i];
     2329    for(j = 0; j < num; j++) {
     2330      if(s == socks[j]) {
     2331        /* this is still supervised */
     2332        stillused = TRUE;
     2333        break;
     2334      }
     2335    }
     2336    if(stillused)
     2337      continue;
     2338
     2339    entry = sh_getentry(&multi->sockhash, s);
     2340    /* if this is NULL here, the socket has been closed and notified so
     2341       already by Curl_multi_closed() */
     2342    if(entry) {
     2343      int oldactions = data->actions[i];
     2344      /* this socket has been removed. Decrease user count */
     2345      entry->users--;
     2346      if(oldactions & CURL_POLL_OUT)
     2347        entry->writers--;
     2348      if(oldactions & CURL_POLL_IN)
     2349        entry->readers--;
     2350      if(!entry->users) {
     2351        if(multi->socket_cb)
     2352          multi->socket_cb(data, s, CURL_POLL_REMOVE,
     2353                           multi->socket_userp,
     2354                           entry->socketp);
     2355        sh_delentry(entry, &multi->sockhash, s);
     2356      }
     2357      else {
     2358        /* still users, but remove this handle as a user of this socket */
     2359        if(Curl_hash_delete(&entry->transfers, (char *)&data,
     2360                            sizeof(struct Curl_easy *))) {
     2361          DEBUGASSERT(NULL);
     2362        }
     2363      }
     2364    }
     2365  } /* for loop over numsocks */
     2366
     2367  memcpy(data->sockets, socks, num*sizeof(curl_socket_t));
     2368  memcpy(data->actions, actions, num*sizeof(int));
     2369  data->numsocks = num;
     2370  return CURLM_OK;
     2371}
     2372
     2373void Curl_updatesocket(struct Curl_easy *data)
     2374{
     2375  singlesocket(data->multi, data);
     2376}
     2377
     2378
     2379/*
     2380 * Curl_multi_closed()
     2381 *
     2382 * Used by the connect code to tell the multi_socket code that one of the
     2383 * sockets we were using is about to be closed.  This function will then
     2384 * remove it from the sockethash for this handle to make the multi_socket API
     2385 * behave properly, especially for the case when libcurl will create another
     2386 * socket again and it gets the same file descriptor number.
     2387 */
     2388
     2389void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s)
     2390{
     2391  if(data) {
     2392    /* if there's still an easy handle associated with this connection */
     2393    struct Curl_multi *multi = data->multi;
     2394    if(multi) {
     2395      /* this is set if this connection is part of a handle that is added to
     2396         a multi handle, and only then this is necessary */
     2397      struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
     2398
     2399      if(entry) {
     2400        if(multi->socket_cb)
     2401          multi->socket_cb(data, s, CURL_POLL_REMOVE,
     2402                           multi->socket_userp,
     2403                           entry->socketp);
     2404
     2405        /* now remove it from the socket hash */
     2406        sh_delentry(entry, &multi->sockhash, s);
     2407      }
     2408    }
     2409  }
     2410}
     2411
     2412/*
     2413 * add_next_timeout()
     2414 *
     2415 * Each Curl_easy has a list of timeouts. The add_next_timeout() is called
     2416 * when it has just been removed from the splay tree because the timeout has
     2417 * expired. This function is then to advance in the list to pick the next
     2418 * timeout to use (skip the already expired ones) and add this node back to
     2419 * the splay tree again.
     2420 *
     2421 * The splay tree only has each sessionhandle as a single node and the nearest
     2422 * timeout is used to sort it on.
     2423 */
     2424static CURLMcode add_next_timeout(struct curltime now,
     2425                                  struct Curl_multi *multi,
     2426                                  struct Curl_easy *d)
     2427{
     2428  struct curltime *tv = &d->state.expiretime;
     2429  struct curl_llist *list = &d->state.timeoutlist;
     2430  struct curl_llist_element *e;
     2431  struct time_node *node = NULL;
     2432
     2433  /* move over the timeout list for this specific handle and remove all
     2434     timeouts that are now passed tense and store the next pending
     2435     timeout in *tv */
     2436  for(e = list->head; e;) {
     2437    struct curl_llist_element *n = e->next;
     2438    timediff_t diff;
     2439    node = (struct time_node *)e->ptr;
     2440    diff = Curl_timediff(node->time, now);
     2441    if(diff <= 0)
     2442      /* remove outdated entry */
     2443      Curl_llist_remove(list, e, NULL);
     2444    else
     2445      /* the list is sorted so get out on the first mismatch */
     2446      break;
     2447    e = n;
     2448  }
     2449  e = list->head;
     2450  if(!e) {
     2451    /* clear the expire times within the handles that we remove from the
     2452       splay tree */
     2453    tv->tv_sec = 0;
     2454    tv->tv_usec = 0;
     2455  }
     2456  else {
     2457    /* copy the first entry to 'tv' */
     2458    memcpy(tv, &node->time, sizeof(*tv));
     2459
     2460    /* Insert this node again into the splay.  Keep the timer in the list in
     2461       case we need to recompute future timers. */
     2462    multi->timetree = Curl_splayinsert(*tv, multi->timetree,
     2463                                       &d->state.timenode);
     2464  }
     2465  return CURLM_OK;
     2466}
     2467
     2468static CURLMcode multi_socket(struct Curl_multi *multi,
     2469                              bool checkall,
     2470                              curl_socket_t s,
     2471                              int ev_bitmask,
     2472                              int *running_handles)
     2473{
     2474  CURLMcode result = CURLM_OK;
     2475  struct Curl_easy *data = NULL;
     2476  struct Curl_tree *t;
     2477  struct curltime now = Curl_now();
     2478
     2479  if(checkall) {
     2480    /* *perform() deals with running_handles on its own */
     2481    result = curl_multi_perform(multi, running_handles);
     2482
     2483    /* walk through each easy handle and do the socket state change magic
     2484       and callbacks */
     2485    if(result != CURLM_BAD_HANDLE) {
     2486      data = multi->easyp;
     2487      while(data && !result) {
     2488        result = singlesocket(multi, data);
     2489        data = data->next;
     2490      }
     2491    }
     2492
     2493    /* or should we fall-through and do the timer-based stuff? */
     2494    return result;
     2495  }
     2496  if(s != CURL_SOCKET_TIMEOUT) {
     2497    struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
     2498
     2499    if(!entry)
     2500      /* Unmatched socket, we can't act on it but we ignore this fact.  In
     2501         real-world tests it has been proved that libevent can in fact give
     2502         the application actions even though the socket was just previously
     2503         asked to get removed, so thus we better survive stray socket actions
     2504         and just move on. */
     2505      ;
     2506    else {
     2507      struct curl_hash_iterator iter;
     2508      struct curl_hash_element *he;
     2509
     2510      /* the socket can be shared by many transfers, iterate */
     2511      Curl_hash_start_iterate(&entry->transfers, &iter);
     2512      for(he = Curl_hash_next_element(&iter); he;
     2513          he = Curl_hash_next_element(&iter)) {
     2514        data = (struct Curl_easy *)he->ptr;
     2515        DEBUGASSERT(data);
     2516        DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER);
     2517
     2518        if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
     2519          /* set socket event bitmask if they're not locked */
     2520          data->conn->cselect_bits = ev_bitmask;
     2521
     2522        Curl_expire(data, 0, EXPIRE_RUN_NOW);
     2523      }
     2524
     2525      /* Now we fall-through and do the timer-based stuff, since we don't want
     2526         to force the user to have to deal with timeouts as long as at least
     2527         one connection in fact has traffic. */
     2528
     2529      data = NULL; /* set data to NULL again to avoid calling
     2530                      multi_runsingle() in case there's no need to */
     2531      now = Curl_now(); /* get a newer time since the multi_runsingle() loop
     2532                           may have taken some time */
     2533    }
     2534  }
     2535  else {
     2536    /* Asked to run due to time-out. Clear the 'lastcall' variable to force
     2537       update_timer() to trigger a callback to the app again even if the same
     2538       timeout is still the one to run after this call. That handles the case
     2539       when the application asks libcurl to run the timeout prematurely. */
     2540    memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
     2541  }
     2542
     2543  /*
     2544   * The loop following here will go on as long as there are expire-times left
     2545   * to process in the splay and 'data' will be re-assigned for every expired
     2546   * handle we deal with.
     2547   */
     2548  do {
     2549    /* the first loop lap 'data' can be NULL */
     2550    if(data) {
     2551      SIGPIPE_VARIABLE(pipe_st);
     2552
     2553      sigpipe_ignore(data, &pipe_st);
     2554      result = multi_runsingle(multi, now, data);
     2555      sigpipe_restore(&pipe_st);
     2556
     2557      if(CURLM_OK >= result) {
     2558        /* get the socket(s) and check if the state has been changed since
     2559           last */
     2560        result = singlesocket(multi, data);
     2561        if(result)
     2562          return result;
     2563      }
     2564    }
     2565
     2566    /* Check if there's one (more) expired timer to deal with! This function
     2567       extracts a matching node if there is one */
     2568
     2569    multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
     2570    if(t) {
     2571      data = t->payload; /* assign this for next loop */
     2572      (void)add_next_timeout(now, multi, t->payload);
     2573    }
     2574
     2575  } while(t);
     2576
     2577  *running_handles = multi->num_alive;
     2578  return result;
     2579}
     2580
     2581#undef curl_multi_setopt
     2582CURLMcode curl_multi_setopt(struct Curl_multi *multi,
     2583                            CURLMoption option, ...)
     2584{
     2585  CURLMcode res = CURLM_OK;
     2586  va_list param;
     2587
     2588  if(!GOOD_MULTI_HANDLE(multi))
     2589    return CURLM_BAD_HANDLE;
     2590
     2591  if(multi->in_callback)
     2592    return CURLM_RECURSIVE_API_CALL;
     2593
     2594  va_start(param, option);
     2595
     2596  switch(option) {
     2597  case CURLMOPT_SOCKETFUNCTION:
     2598    multi->socket_cb = va_arg(param, curl_socket_callback);
     2599    break;
     2600  case CURLMOPT_SOCKETDATA:
     2601    multi->socket_userp = va_arg(param, void *);
     2602    break;
     2603  case CURLMOPT_PUSHFUNCTION:
     2604    multi->push_cb = va_arg(param, curl_push_callback);
     2605    break;
     2606  case CURLMOPT_PUSHDATA:
     2607    multi->push_userp = va_arg(param, void *);
     2608    break;
     2609  case CURLMOPT_PIPELINING:
     2610    multi->multiplexing = va_arg(param, long) & CURLPIPE_MULTIPLEX;
     2611    break;
     2612  case CURLMOPT_TIMERFUNCTION:
     2613    multi->timer_cb = va_arg(param, curl_multi_timer_callback);
     2614    break;
     2615  case CURLMOPT_TIMERDATA:
     2616    multi->timer_userp = va_arg(param, void *);
     2617    break;
     2618  case CURLMOPT_MAXCONNECTS:
     2619    multi->maxconnects = va_arg(param, long);
     2620    break;
     2621  case CURLMOPT_MAX_HOST_CONNECTIONS:
     2622    multi->max_host_connections = va_arg(param, long);
     2623    break;
     2624  case CURLMOPT_MAX_TOTAL_CONNECTIONS:
     2625    multi->max_total_connections = va_arg(param, long);
     2626    break;
     2627    /* options formerly used for pipelining */
     2628  case CURLMOPT_MAX_PIPELINE_LENGTH:
     2629    break;
     2630  case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
     2631    break;
     2632  case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
     2633    break;
     2634  case CURLMOPT_PIPELINING_SITE_BL:
     2635    break;
     2636  case CURLMOPT_PIPELINING_SERVER_BL:
     2637    break;
     2638  default:
     2639    res = CURLM_UNKNOWN_OPTION;
     2640    break;
     2641  }
     2642  va_end(param);
     2643  return res;
     2644}
     2645
     2646/* we define curl_multi_socket() in the public multi.h header */
     2647#undef curl_multi_socket
     2648
     2649CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s,
     2650                            int *running_handles)
     2651{
     2652  CURLMcode result;
     2653  if(multi->in_callback)
     2654    return CURLM_RECURSIVE_API_CALL;
     2655  result = multi_socket(multi, FALSE, s, 0, running_handles);
     2656  if(CURLM_OK >= result)
     2657    update_timer(multi);
     2658  return result;
     2659}
     2660
     2661CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
     2662                                   int ev_bitmask, int *running_handles)
     2663{
     2664  CURLMcode result;
     2665  if(multi->in_callback)
     2666    return CURLM_RECURSIVE_API_CALL;
     2667  result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles);
     2668  if(CURLM_OK >= result)
     2669    update_timer(multi);
     2670  return result;
     2671}
     2672
     2673CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
     2674
     2675{
     2676  CURLMcode result;
     2677  if(multi->in_callback)
     2678    return CURLM_RECURSIVE_API_CALL;
     2679  result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
     2680  if(CURLM_OK >= result)
     2681    update_timer(multi);
     2682  return result;
     2683}
     2684
     2685static CURLMcode multi_timeout(struct Curl_multi *multi,
     2686                               long *timeout_ms)
     2687{
     2688  static struct curltime tv_zero = {0, 0};
     2689
     2690  if(multi->timetree) {
     2691    /* we have a tree of expire times */
     2692    struct curltime now = Curl_now();
     2693
     2694    /* splay the lowest to the bottom */
     2695    multi->timetree = Curl_splay(tv_zero, multi->timetree);
     2696
     2697    if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
     2698      /* some time left before expiration */
     2699      timediff_t diff = Curl_timediff(multi->timetree->key, now);
     2700      if(diff <= 0)
     2701        /*
     2702         * Since we only provide millisecond resolution on the returned value
     2703         * and the diff might be less than one millisecond here, we don't
     2704         * return zero as that may cause short bursts of busyloops on fast
     2705         * processors while the diff is still present but less than one
     2706         * millisecond! instead we return 1 until the time is ripe.
     2707         */
     2708        *timeout_ms = 1;
     2709      else
     2710        /* this should be safe even on 64 bit archs, as we don't use that
     2711           overly long timeouts */
     2712        *timeout_ms = (long)diff;
     2713    }
     2714    else
     2715      /* 0 means immediately */
     2716      *timeout_ms = 0;
     2717  }
     2718  else
     2719    *timeout_ms = -1;
     2720
     2721  return CURLM_OK;
     2722}
     2723
     2724CURLMcode curl_multi_timeout(struct Curl_multi *multi,
     2725                             long *timeout_ms)
     2726{
     2727  /* First, make some basic checks that the CURLM handle is a good handle */
     2728  if(!GOOD_MULTI_HANDLE(multi))
     2729    return CURLM_BAD_HANDLE;
     2730
     2731  if(multi->in_callback)
     2732    return CURLM_RECURSIVE_API_CALL;
     2733
     2734  return multi_timeout(multi, timeout_ms);
     2735}
     2736
     2737/*
     2738 * Tell the application it should update its timers, if it subscribes to the
     2739 * update timer callback.
     2740 */
     2741static int update_timer(struct Curl_multi *multi)
     2742{
     2743  long timeout_ms;
     2744
     2745  if(!multi->timer_cb)
     2746    return 0;
     2747  if(multi_timeout(multi, &timeout_ms)) {
     2748    return -1;
     2749  }
     2750  if(timeout_ms < 0) {
     2751    static const struct curltime none = {0, 0};
     2752    if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
     2753      multi->timer_lastcall = none;
     2754      /* there's no timeout now but there was one previously, tell the app to
     2755         disable it */
     2756      return multi->timer_cb(multi, -1, multi->timer_userp);
     2757    }
     2758    return 0;
     2759  }
     2760
     2761  /* When multi_timeout() is done, multi->timetree points to the node with the
     2762   * timeout we got the (relative) time-out time for. We can thus easily check
     2763   * if this is the same (fixed) time as we got in a previous call and then
     2764   * avoid calling the callback again. */
     2765  if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
     2766    return 0;
     2767
     2768  multi->timer_lastcall = multi->timetree->key;
     2769
     2770  return multi->timer_cb(multi, timeout_ms, multi->timer_userp);
     2771}
     2772
     2773/*
     2774 * multi_deltimeout()
     2775 *
     2776 * Remove a given timestamp from the list of timeouts.
     2777 */
     2778static void
     2779multi_deltimeout(struct Curl_easy *data, expire_id eid)
     2780{
     2781  struct curl_llist_element *e;
     2782  struct curl_llist *timeoutlist = &data->state.timeoutlist;
     2783  /* find and remove the specific node from the list */
     2784  for(e = timeoutlist->head; e; e = e->next) {
     2785    struct time_node *n = (struct time_node *)e->ptr;
     2786    if(n->eid == eid) {
     2787      Curl_llist_remove(timeoutlist, e, NULL);
     2788      return;
     2789    }
     2790  }
     2791}
     2792
     2793/*
     2794 * multi_addtimeout()
     2795 *
     2796 * Add a timestamp to the list of timeouts. Keep the list sorted so that head
     2797 * of list is always the timeout nearest in time.
     2798 *
     2799 */
     2800static CURLMcode
     2801multi_addtimeout(struct Curl_easy *data,
     2802                 struct curltime *stamp,
     2803                 expire_id eid)
     2804{
     2805  struct curl_llist_element *e;
     2806  struct time_node *node;
     2807  struct curl_llist_element *prev = NULL;
     2808  size_t n;
     2809  struct curl_llist *timeoutlist = &data->state.timeoutlist;
     2810
     2811  node = &data->state.expires[eid];
     2812
     2813  /* copy the timestamp and id */
     2814  memcpy(&node->time, stamp, sizeof(*stamp));
     2815  node->eid = eid; /* also marks it as in use */
     2816
     2817  n = Curl_llist_count(timeoutlist);
     2818  if(n) {
     2819    /* find the correct spot in the list */
     2820    for(e = timeoutlist->head; e; e = e->next) {
     2821      struct time_node *check = (struct time_node *)e->ptr;
     2822      timediff_t diff = Curl_timediff(check->time, node->time);
     2823      if(diff > 0)
     2824        break;
     2825      prev = e;
     2826    }
     2827
     2828  }
     2829  /* else
     2830     this is the first timeout on the list */
     2831
     2832  Curl_llist_insert_next(timeoutlist, prev, node, &node->list);
     2833  return CURLM_OK;
     2834}
     2835
     2836/*
     2837 * Curl_expire()
     2838 *
     2839 * given a number of milliseconds from now to use to set the 'act before
     2840 * this'-time for the transfer, to be extracted by curl_multi_timeout()
     2841 *
     2842 * The timeout will be added to a queue of timeouts if it defines a moment in
     2843 * time that is later than the current head of queue.
     2844 *
     2845 * Expire replaces a former timeout using the same id if already set.
     2846 */
     2847void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id)
     2848{
     2849  struct Curl_multi *multi = data->multi;
     2850  struct curltime *nowp = &data->state.expiretime;
     2851  struct curltime set;
     2852
     2853  /* this is only interesting while there is still an associated multi struct
     2854     remaining! */
     2855  if(!multi)
     2856    return;
     2857
     2858  DEBUGASSERT(id < EXPIRE_LAST);
     2859
     2860  set = Curl_now();
     2861  set.tv_sec += milli/1000;
     2862  set.tv_usec += (unsigned int)(milli%1000)*1000;
     2863
     2864  if(set.tv_usec >= 1000000) {
     2865    set.tv_sec++;
     2866    set.tv_usec -= 1000000;
     2867  }
     2868
     2869  /* Remove any timer with the same id just in case. */
     2870  multi_deltimeout(data, id);
     2871
     2872  /* Add it to the timer list.  It must stay in the list until it has expired
     2873     in case we need to recompute the minimum timer later. */
     2874  multi_addtimeout(data, &set, id);
     2875
     2876  if(nowp->tv_sec || nowp->tv_usec) {
     2877    /* This means that the struct is added as a node in the splay tree.
     2878       Compare if the new time is earlier, and only remove-old/add-new if it
     2879       is. */
     2880    timediff_t diff = Curl_timediff(set, *nowp);
     2881    int rc;
     2882
     2883    if(diff > 0) {
     2884      /* The current splay tree entry is sooner than this new expiry time.
     2885         We don't need to update our splay tree entry. */
     2886      return;
     2887    }
     2888
     2889    /* Since this is an updated time, we must remove the previous entry from
     2890       the splay tree first and then re-add the new value */
     2891    rc = Curl_splayremovebyaddr(multi->timetree,
     2892                                &data->state.timenode,
     2893                                &multi->timetree);
     2894    if(rc)
     2895      infof(data, "Internal error removing splay node = %d\n", rc);
     2896  }
     2897
     2898  /* Indicate that we are in the splay tree and insert the new timer expiry
     2899     value since it is our local minimum. */
     2900  *nowp = set;
     2901  data->state.timenode.payload = data;
     2902  multi->timetree = Curl_splayinsert(*nowp, multi->timetree,
     2903                                     &data->state.timenode);
     2904}
     2905
     2906/*
     2907 * Curl_expire_done()
     2908 *
     2909 * Removes the expire timer. Marks it as done.
     2910 *
     2911 */
     2912void Curl_expire_done(struct Curl_easy *data, expire_id id)
     2913{
     2914  /* remove the timer, if there */
     2915  multi_deltimeout(data, id);
     2916}
     2917
     2918/*
     2919 * Curl_expire_clear()
     2920 *
     2921 * Clear ALL timeout values for this handle.
     2922 */
     2923void Curl_expire_clear(struct Curl_easy *data)
     2924{
     2925  struct Curl_multi *multi = data->multi;
     2926  struct curltime *nowp = &data->state.expiretime;
     2927
     2928  /* this is only interesting while there is still an associated multi struct
     2929     remaining! */
     2930  if(!multi)
     2931    return;
     2932
     2933  if(nowp->tv_sec || nowp->tv_usec) {
     2934    /* Since this is an cleared time, we must remove the previous entry from
     2935       the splay tree */
     2936    struct curl_llist *list = &data->state.timeoutlist;
     2937    int rc;
     2938
     2939    rc = Curl_splayremovebyaddr(multi->timetree,
     2940                                &data->state.timenode,
     2941                                &multi->timetree);
     2942    if(rc)
     2943      infof(data, "Internal error clearing splay node = %d\n", rc);
     2944
     2945    /* flush the timeout list too */
     2946    while(list->size > 0) {
     2947      Curl_llist_remove(list, list->tail, NULL);
     2948    }
     2949
     2950#ifdef DEBUGBUILD
     2951    infof(data, "Expire cleared (transfer %p)\n", data);
     2952#endif
     2953    nowp->tv_sec = 0;
     2954    nowp->tv_usec = 0;
     2955  }
     2956}
     2957
     2958
     2959
     2960
     2961CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s,
     2962                            void *hashp)
     2963{
     2964  struct Curl_sh_entry *there = NULL;
     2965
     2966  if(multi->in_callback)
     2967    return CURLM_RECURSIVE_API_CALL;
     2968
     2969  there = sh_getentry(&multi->sockhash, s);
     2970
     2971  if(!there)
     2972    return CURLM_BAD_SOCKET;
     2973
     2974  there->socketp = hashp;
     2975
     2976  return CURLM_OK;
     2977}
     2978
     2979size_t Curl_multi_max_host_connections(struct Curl_multi *multi)
     2980{
     2981  return multi ? multi->max_host_connections : 0;
     2982}
     2983
     2984size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
     2985{
     2986  return multi ? multi->max_total_connections : 0;
     2987}
     2988
     2989/*
     2990 * When information about a connection has appeared, call this!
     2991 */
     2992
     2993void Curl_multiuse_state(struct connectdata *conn,
     2994                         int bundlestate) /* use BUNDLE_* defines */
     2995{
     2996  DEBUGASSERT(conn);
     2997  DEBUGASSERT(conn->bundle);
     2998  DEBUGASSERT(conn->data);
     2999  DEBUGASSERT(conn->data->multi);
     3000
     3001  conn->bundle->multiuse = bundlestate;
     3002  process_pending_handles(conn->data->multi);
     3003}
     3004
     3005static void process_pending_handles(struct Curl_multi *multi)
     3006{
     3007  struct curl_llist_element *e = multi->pending.head;
     3008  if(e) {
     3009    struct Curl_easy *data = e->ptr;
     3010
     3011    DEBUGASSERT(data->mstate == CURLM_STATE_CONNECT_PEND);
     3012
     3013    multistate(data, CURLM_STATE_CONNECT);
     3014
     3015    /* Remove this node from the list */
     3016    Curl_llist_remove(&multi->pending, e, NULL);
     3017
     3018    /* Make sure that the handle will be processed soonish. */
     3019    Curl_expire(data, 0, EXPIRE_RUN_NOW);
     3020
     3021    /* mark this as having been in the pending queue */
     3022    data->state.previouslypending = TRUE;
     3023  }
     3024}
     3025
     3026void Curl_set_in_callback(struct Curl_easy *data, bool value)
     3027{
     3028  /* might get called when there is no data pointer! */
     3029  if(data) {
     3030    if(data->multi_easy)
     3031      data->multi_easy->in_callback = value;
     3032    else if(data->multi)
     3033      data->multi->in_callback = value;
     3034  }
     3035}
     3036
     3037bool Curl_is_in_callback(struct Curl_easy *easy)
     3038{
     3039  return ((easy->multi && easy->multi->in_callback) ||
     3040          (easy->multi_easy && easy->multi_easy->in_callback));
     3041}
     3042
     3043#ifdef DEBUGBUILD
     3044void Curl_multi_dump(struct Curl_multi *multi)
     3045{
     3046  struct Curl_easy *data;
     3047  int i;
     3048  fprintf(stderr, "* Multi status: %d handles, %d alive\n",
     3049          multi->num_easy, multi->num_alive);
     3050  for(data = multi->easyp; data; data = data->next) {
     3051    if(data->mstate < CURLM_STATE_COMPLETED) {
     3052      /* only display handles that are not completed */
     3053      fprintf(stderr, "handle %p, state %s, %d sockets\n",
     3054              (void *)data,
     3055              statename[data->mstate], data->numsocks);
     3056      for(i = 0; i < data->numsocks; i++) {
     3057        curl_socket_t s = data->sockets[i];
     3058        struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
     3059
     3060        fprintf(stderr, "%d ", (int)s);
     3061        if(!entry) {
     3062          fprintf(stderr, "INTERNAL CONFUSION\n");
     3063          continue;
     3064        }
     3065        fprintf(stderr, "[%s %s] ",
     3066                (entry->action&CURL_POLL_IN)?"RECVING":"",
     3067                (entry->action&CURL_POLL_OUT)?"SENDING":"");
     3068      }
     3069      if(data->numsocks)
     3070        fprintf(stderr, "\n");
     3071    }
     3072  }
     3073}
     3074#endif
  • lib/url.c

    diff -ruN curl-7.65.1/lib/url.c curl-7.65.1-fix-dns-segfaults/lib/url.c
    old new  
    16731673#endif
    16741674}
    16751675
    1676 static void llist_dtor(void *user, void *element)
    1677 {
    1678   (void)user;
    1679   (void)element;
    1680   /* Do nothing */
    1681 }
    1682 
    16831676/*
    16841677 * Allocate and initialize a new connectdata object.
    16851678 */
     
    17911784#endif
    17921785
    17931786  /* Initialize the easy handle list */
    1794   Curl_llist_init(&conn->easyq, (curl_llist_dtor) llist_dtor);
     1787  Curl_llist_init(&conn->easyq, NULL);
    17951788
    17961789#ifdef HAVE_GSSAPI
    17971790  conn->data_prot = PROT_CLEAR;
  • lib/urldata.h

    diff -ruN curl-7.65.1/lib/urldata.h curl-7.65.1-fix-dns-segfaults/lib/urldata.h
    old new  
    17781778
    17791779  struct connectdata *conn;
    17801780  struct curl_llist_element connect_queue;
    1781   struct curl_llist_element sh_queue; /* list per Curl_sh_entry */
    1782   struct Curl_sh_entry *sh_entry; /* the socket hash this was added to */
    17831781  struct curl_llist_element conn_queue; /* list per connectdata */
    17841782
    17851783  CURLMstate mstate;  /* the handle's state */