Annotation of embedaddon/curl/lib/easy.c, revision 1.1.1.1

1.1       misho       1: /***************************************************************************
                      2:  *                                  _   _ ____  _
                      3:  *  Project                     ___| | | |  _ \| |
                      4:  *                             / __| | | | |_) | |
                      5:  *                            | (__| |_| |  _ <| |___
                      6:  *                             \___|\___/|_| \_\_____|
                      7:  *
                      8:  * Copyright (C) 1998 - 2020, 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: /*
                     26:  * See comment in curl_memory.h for the explanation of this sanity check.
                     27:  */
                     28: 
                     29: #ifdef CURLX_NO_MEMORY_CALLBACKS
                     30: #error "libcurl shall not ever be built with CURLX_NO_MEMORY_CALLBACKS defined"
                     31: #endif
                     32: 
                     33: #ifdef HAVE_NETINET_IN_H
                     34: #include <netinet/in.h>
                     35: #endif
                     36: #ifdef HAVE_NETDB_H
                     37: #include <netdb.h>
                     38: #endif
                     39: #ifdef HAVE_ARPA_INET_H
                     40: #include <arpa/inet.h>
                     41: #endif
                     42: #ifdef HAVE_NET_IF_H
                     43: #include <net/if.h>
                     44: #endif
                     45: #ifdef HAVE_SYS_IOCTL_H
                     46: #include <sys/ioctl.h>
                     47: #endif
                     48: 
                     49: #ifdef HAVE_SYS_PARAM_H
                     50: #include <sys/param.h>
                     51: #endif
                     52: 
                     53: #include "urldata.h"
                     54: #include <curl/curl.h>
                     55: #include "transfer.h"
                     56: #include "vtls/vtls.h"
                     57: #include "url.h"
                     58: #include "getinfo.h"
                     59: #include "hostip.h"
                     60: #include "share.h"
                     61: #include "strdup.h"
                     62: #include "progress.h"
                     63: #include "easyif.h"
                     64: #include "multiif.h"
                     65: #include "select.h"
                     66: #include "sendf.h" /* for failf function prototype */
                     67: #include "connect.h" /* for Curl_getconnectinfo */
                     68: #include "slist.h"
                     69: #include "mime.h"
                     70: #include "amigaos.h"
                     71: #include "non-ascii.h"
                     72: #include "warnless.h"
                     73: #include "multiif.h"
                     74: #include "sigpipe.h"
                     75: #include "vssh/ssh.h"
                     76: #include "setopt.h"
                     77: #include "http_digest.h"
                     78: #include "system_win32.h"
                     79: #include "http2.h"
                     80: 
                     81: /* The last 3 #include files should be in this order */
                     82: #include "curl_printf.h"
                     83: #include "curl_memory.h"
                     84: #include "memdebug.h"
                     85: 
                     86: /* true globals -- for curl_global_init() and curl_global_cleanup() */
                     87: static unsigned int  initialized;
                     88: static long          init_flags;
                     89: 
                     90: /*
                     91:  * strdup (and other memory functions) is redefined in complicated
                     92:  * ways, but at this point it must be defined as the system-supplied strdup
                     93:  * so the callback pointer is initialized correctly.
                     94:  */
                     95: #if defined(_WIN32_WCE)
                     96: #define system_strdup _strdup
                     97: #elif !defined(HAVE_STRDUP)
                     98: #define system_strdup curlx_strdup
                     99: #else
                    100: #define system_strdup strdup
                    101: #endif
                    102: 
                    103: #if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
                    104: #  pragma warning(disable:4232) /* MSVC extension, dllimport identity */
                    105: #endif
                    106: 
                    107: #ifndef __SYMBIAN32__
                    108: /*
                    109:  * If a memory-using function (like curl_getenv) is used before
                    110:  * curl_global_init() is called, we need to have these pointers set already.
                    111:  */
                    112: curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
                    113: curl_free_callback Curl_cfree = (curl_free_callback)free;
                    114: curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
                    115: curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
                    116: curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
                    117: #if defined(WIN32) && defined(UNICODE)
                    118: curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
                    119: #endif
                    120: #else
                    121: /*
                    122:  * Symbian OS doesn't support initialization to code in writable static data.
                    123:  * Initialization will occur in the curl_global_init() call.
                    124:  */
                    125: curl_malloc_callback Curl_cmalloc;
                    126: curl_free_callback Curl_cfree;
                    127: curl_realloc_callback Curl_crealloc;
                    128: curl_strdup_callback Curl_cstrdup;
                    129: curl_calloc_callback Curl_ccalloc;
                    130: #endif
                    131: 
                    132: #if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
                    133: #  pragma warning(default:4232) /* MSVC extension, dllimport identity */
                    134: #endif
                    135: 
                    136: /**
                    137:  * curl_global_init() globally initializes curl given a bitwise set of the
                    138:  * different features of what to initialize.
                    139:  */
                    140: static CURLcode global_init(long flags, bool memoryfuncs)
                    141: {
                    142:   if(initialized++)
                    143:     return CURLE_OK;
                    144: 
                    145:   if(memoryfuncs) {
                    146:     /* Setup the default memory functions here (again) */
                    147:     Curl_cmalloc = (curl_malloc_callback)malloc;
                    148:     Curl_cfree = (curl_free_callback)free;
                    149:     Curl_crealloc = (curl_realloc_callback)realloc;
                    150:     Curl_cstrdup = (curl_strdup_callback)system_strdup;
                    151:     Curl_ccalloc = (curl_calloc_callback)calloc;
                    152: #if defined(WIN32) && defined(UNICODE)
                    153:     Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
                    154: #endif
                    155:   }
                    156: 
                    157:   if(!Curl_ssl_init()) {
                    158:     DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
                    159:     goto fail;
                    160:   }
                    161: 
                    162: #ifdef WIN32
                    163:   if(Curl_win32_init(flags)) {
                    164:     DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
                    165:     goto fail;
                    166:   }
                    167: #endif
                    168: 
                    169: #ifdef __AMIGA__
                    170:   if(!Curl_amiga_init()) {
                    171:     DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n"));
                    172:     goto fail;
                    173:   }
                    174: #endif
                    175: 
                    176: #ifdef NETWARE
                    177:   if(netware_init()) {
                    178:     DEBUGF(fprintf(stderr, "Warning: LONG namespace not available\n"));
                    179:   }
                    180: #endif
                    181: 
                    182:   if(Curl_resolver_global_init()) {
                    183:     DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n"));
                    184:     goto fail;
                    185:   }
                    186: 
                    187: #if defined(USE_SSH)
                    188:   if(Curl_ssh_init()) {
                    189:     goto fail;
                    190:   }
                    191: #endif
                    192: 
                    193: #ifdef USE_WOLFSSH
                    194:   if(WS_SUCCESS != wolfSSH_Init()) {
                    195:     DEBUGF(fprintf(stderr, "Error: wolfSSH_Init failed\n"));
                    196:     return CURLE_FAILED_INIT;
                    197:   }
                    198: #endif
                    199: 
                    200:   init_flags = flags;
                    201: 
                    202:   return CURLE_OK;
                    203: 
                    204:   fail:
                    205:   initialized--; /* undo the increase */
                    206:   return CURLE_FAILED_INIT;
                    207: }
                    208: 
                    209: 
                    210: /**
                    211:  * curl_global_init() globally initializes curl given a bitwise set of the
                    212:  * different features of what to initialize.
                    213:  */
                    214: CURLcode curl_global_init(long flags)
                    215: {
                    216:   return global_init(flags, TRUE);
                    217: }
                    218: 
                    219: /*
                    220:  * curl_global_init_mem() globally initializes curl and also registers the
                    221:  * user provided callback routines.
                    222:  */
                    223: CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
                    224:                               curl_free_callback f, curl_realloc_callback r,
                    225:                               curl_strdup_callback s, curl_calloc_callback c)
                    226: {
                    227:   /* Invalid input, return immediately */
                    228:   if(!m || !f || !r || !s || !c)
                    229:     return CURLE_FAILED_INIT;
                    230: 
                    231:   if(initialized) {
                    232:     /* Already initialized, don't do it again, but bump the variable anyway to
                    233:        work like curl_global_init() and require the same amount of cleanup
                    234:        calls. */
                    235:     initialized++;
                    236:     return CURLE_OK;
                    237:   }
                    238: 
                    239:   /* set memory functions before global_init() in case it wants memory
                    240:      functions */
                    241:   Curl_cmalloc = m;
                    242:   Curl_cfree = f;
                    243:   Curl_cstrdup = s;
                    244:   Curl_crealloc = r;
                    245:   Curl_ccalloc = c;
                    246: 
                    247:   /* Call the actual init function, but without setting */
                    248:   return global_init(flags, FALSE);
                    249: }
                    250: 
                    251: /**
                    252:  * curl_global_cleanup() globally cleanups curl, uses the value of
                    253:  * "init_flags" to determine what needs to be cleaned up and what doesn't.
                    254:  */
                    255: void curl_global_cleanup(void)
                    256: {
                    257:   if(!initialized)
                    258:     return;
                    259: 
                    260:   if(--initialized)
                    261:     return;
                    262: 
                    263:   Curl_ssl_cleanup();
                    264:   Curl_resolver_global_cleanup();
                    265: 
                    266: #ifdef WIN32
                    267:   Curl_win32_cleanup(init_flags);
                    268: #endif
                    269: 
                    270:   Curl_amiga_cleanup();
                    271: 
                    272:   Curl_ssh_cleanup();
                    273: 
                    274: #ifdef USE_WOLFSSH
                    275:   (void)wolfSSH_Cleanup();
                    276: #endif
                    277: 
                    278:   init_flags  = 0;
                    279: }
                    280: 
                    281: /*
                    282:  * curl_easy_init() is the external interface to alloc, setup and init an
                    283:  * easy handle that is returned. If anything goes wrong, NULL is returned.
                    284:  */
                    285: struct Curl_easy *curl_easy_init(void)
                    286: {
                    287:   CURLcode result;
                    288:   struct Curl_easy *data;
                    289: 
                    290:   /* Make sure we inited the global SSL stuff */
                    291:   if(!initialized) {
                    292:     result = curl_global_init(CURL_GLOBAL_DEFAULT);
                    293:     if(result) {
                    294:       /* something in the global init failed, return nothing */
                    295:       DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n"));
                    296:       return NULL;
                    297:     }
                    298:   }
                    299: 
                    300:   /* We use curl_open() with undefined URL so far */
                    301:   result = Curl_open(&data);
                    302:   if(result) {
                    303:     DEBUGF(fprintf(stderr, "Error: Curl_open failed\n"));
                    304:     return NULL;
                    305:   }
                    306: 
                    307:   return data;
                    308: }
                    309: 
                    310: #ifdef CURLDEBUG
                    311: 
                    312: struct socketmonitor {
                    313:   struct socketmonitor *next; /* the next node in the list or NULL */
                    314:   struct pollfd socket; /* socket info of what to monitor */
                    315: };
                    316: 
                    317: struct events {
                    318:   long ms;              /* timeout, run the timeout function when reached */
                    319:   bool msbump;          /* set TRUE when timeout is set by callback */
                    320:   int num_sockets;      /* number of nodes in the monitor list */
                    321:   struct socketmonitor *list; /* list of sockets to monitor */
                    322:   int running_handles;  /* store the returned number */
                    323: };
                    324: 
                    325: /* events_timer
                    326:  *
                    327:  * Callback that gets called with a new value when the timeout should be
                    328:  * updated.
                    329:  */
                    330: 
                    331: static int events_timer(struct Curl_multi *multi,    /* multi handle */
                    332:                         long timeout_ms, /* see above */
                    333:                         void *userp)    /* private callback pointer */
                    334: {
                    335:   struct events *ev = userp;
                    336:   (void)multi;
                    337:   if(timeout_ms == -1)
                    338:     /* timeout removed */
                    339:     timeout_ms = 0;
                    340:   else if(timeout_ms == 0)
                    341:     /* timeout is already reached! */
                    342:     timeout_ms = 1; /* trigger asap */
                    343: 
                    344:   ev->ms = timeout_ms;
                    345:   ev->msbump = TRUE;
                    346:   return 0;
                    347: }
                    348: 
                    349: 
                    350: /* poll2cselect
                    351:  *
                    352:  * convert from poll() bit definitions to libcurl's CURL_CSELECT_* ones
                    353:  */
                    354: static int poll2cselect(int pollmask)
                    355: {
                    356:   int omask = 0;
                    357:   if(pollmask & POLLIN)
                    358:     omask |= CURL_CSELECT_IN;
                    359:   if(pollmask & POLLOUT)
                    360:     omask |= CURL_CSELECT_OUT;
                    361:   if(pollmask & POLLERR)
                    362:     omask |= CURL_CSELECT_ERR;
                    363:   return omask;
                    364: }
                    365: 
                    366: 
                    367: /* socketcb2poll
                    368:  *
                    369:  * convert from libcurl' CURL_POLL_* bit definitions to poll()'s
                    370:  */
                    371: static short socketcb2poll(int pollmask)
                    372: {
                    373:   short omask = 0;
                    374:   if(pollmask & CURL_POLL_IN)
                    375:     omask |= POLLIN;
                    376:   if(pollmask & CURL_POLL_OUT)
                    377:     omask |= POLLOUT;
                    378:   return omask;
                    379: }
                    380: 
                    381: /* events_socket
                    382:  *
                    383:  * Callback that gets called with information about socket activity to
                    384:  * monitor.
                    385:  */
                    386: static int events_socket(struct Curl_easy *easy,      /* easy handle */
                    387:                          curl_socket_t s, /* socket */
                    388:                          int what,        /* see above */
                    389:                          void *userp,     /* private callback
                    390:                                              pointer */
                    391:                          void *socketp)   /* private socket
                    392:                                              pointer */
                    393: {
                    394:   struct events *ev = userp;
                    395:   struct socketmonitor *m;
                    396:   struct socketmonitor *prev = NULL;
                    397: 
                    398: #if defined(CURL_DISABLE_VERBOSE_STRINGS)
                    399:   (void) easy;
                    400: #endif
                    401:   (void)socketp;
                    402: 
                    403:   m = ev->list;
                    404:   while(m) {
                    405:     if(m->socket.fd == s) {
                    406: 
                    407:       if(what == CURL_POLL_REMOVE) {
                    408:         struct socketmonitor *nxt = m->next;
                    409:         /* remove this node from the list of monitored sockets */
                    410:         if(prev)
                    411:           prev->next = nxt;
                    412:         else
                    413:           ev->list = nxt;
                    414:         free(m);
                    415:         m = nxt;
                    416:         infof(easy, "socket cb: socket %d REMOVED\n", s);
                    417:       }
                    418:       else {
                    419:         /* The socket 's' is already being monitored, update the activity
                    420:            mask. Convert from libcurl bitmask to the poll one. */
                    421:         m->socket.events = socketcb2poll(what);
                    422:         infof(easy, "socket cb: socket %d UPDATED as %s%s\n", s,
                    423:               (what&CURL_POLL_IN)?"IN":"",
                    424:               (what&CURL_POLL_OUT)?"OUT":"");
                    425:       }
                    426:       break;
                    427:     }
                    428:     prev = m;
                    429:     m = m->next; /* move to next node */
                    430:   }
                    431:   if(!m) {
                    432:     if(what == CURL_POLL_REMOVE) {
                    433:       /* this happens a bit too often, libcurl fix perhaps? */
                    434:       /* fprintf(stderr,
                    435:          "%s: socket %d asked to be REMOVED but not present!\n",
                    436:                  __func__, s); */
                    437:     }
                    438:     else {
                    439:       m = malloc(sizeof(struct socketmonitor));
                    440:       if(m) {
                    441:         m->next = ev->list;
                    442:         m->socket.fd = s;
                    443:         m->socket.events = socketcb2poll(what);
                    444:         m->socket.revents = 0;
                    445:         ev->list = m;
                    446:         infof(easy, "socket cb: socket %d ADDED as %s%s\n", s,
                    447:               (what&CURL_POLL_IN)?"IN":"",
                    448:               (what&CURL_POLL_OUT)?"OUT":"");
                    449:       }
                    450:       else
                    451:         return CURLE_OUT_OF_MEMORY;
                    452:     }
                    453:   }
                    454: 
                    455:   return 0;
                    456: }
                    457: 
                    458: 
                    459: /*
                    460:  * events_setup()
                    461:  *
                    462:  * Do the multi handle setups that only event-based transfers need.
                    463:  */
                    464: static void events_setup(struct Curl_multi *multi, struct events *ev)
                    465: {
                    466:   /* timer callback */
                    467:   curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer);
                    468:   curl_multi_setopt(multi, CURLMOPT_TIMERDATA, ev);
                    469: 
                    470:   /* socket callback */
                    471:   curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, events_socket);
                    472:   curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, ev);
                    473: }
                    474: 
                    475: 
                    476: /* wait_or_timeout()
                    477:  *
                    478:  * waits for activity on any of the given sockets, or the timeout to trigger.
                    479:  */
                    480: 
                    481: static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
                    482: {
                    483:   bool done = FALSE;
                    484:   CURLMcode mcode = CURLM_OK;
                    485:   CURLcode result = CURLE_OK;
                    486: 
                    487:   while(!done) {
                    488:     CURLMsg *msg;
                    489:     struct socketmonitor *m;
                    490:     struct pollfd *f;
                    491:     struct pollfd fds[4];
                    492:     int numfds = 0;
                    493:     int pollrc;
                    494:     int i;
                    495:     struct curltime before;
                    496:     struct curltime after;
                    497: 
                    498:     /* populate the fds[] array */
                    499:     for(m = ev->list, f = &fds[0]; m; m = m->next) {
                    500:       f->fd = m->socket.fd;
                    501:       f->events = m->socket.events;
                    502:       f->revents = 0;
                    503:       /* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */
                    504:       f++;
                    505:       numfds++;
                    506:     }
                    507: 
                    508:     /* get the time stamp to use to figure out how long poll takes */
                    509:     before = Curl_now();
                    510: 
                    511:     /* wait for activity or timeout */
                    512:     pollrc = Curl_poll(fds, numfds, (int)ev->ms);
                    513: 
                    514:     after = Curl_now();
                    515: 
                    516:     ev->msbump = FALSE; /* reset here */
                    517: 
                    518:     if(0 == pollrc) {
                    519:       /* timeout! */
                    520:       ev->ms = 0;
                    521:       /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */
                    522:       mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0,
                    523:                                        &ev->running_handles);
                    524:     }
                    525:     else if(pollrc > 0) {
                    526:       /* loop over the monitored sockets to see which ones had activity */
                    527:       for(i = 0; i< numfds; i++) {
                    528:         if(fds[i].revents) {
                    529:           /* socket activity, tell libcurl */
                    530:           int act = poll2cselect(fds[i].revents); /* convert */
                    531:           infof(multi->easyp, "call curl_multi_socket_action(socket %d)\n",
                    532:                 fds[i].fd);
                    533:           mcode = curl_multi_socket_action(multi, fds[i].fd, act,
                    534:                                            &ev->running_handles);
                    535:         }
                    536:       }
                    537: 
                    538:       if(!ev->msbump) {
                    539:         /* If nothing updated the timeout, we decrease it by the spent time.
                    540:          * If it was updated, it has the new timeout time stored already.
                    541:          */
                    542:         timediff_t timediff = Curl_timediff(after, before);
                    543:         if(timediff > 0) {
                    544:           if(timediff > ev->ms)
                    545:             ev->ms = 0;
                    546:           else
                    547:             ev->ms -= (long)timediff;
                    548:         }
                    549:       }
                    550:     }
                    551:     else
                    552:       return CURLE_RECV_ERROR;
                    553: 
                    554:     if(mcode)
                    555:       return CURLE_URL_MALFORMAT;
                    556: 
                    557:     /* we don't really care about the "msgs_in_queue" value returned in the
                    558:        second argument */
                    559:     msg = curl_multi_info_read(multi, &pollrc);
                    560:     if(msg) {
                    561:       result = msg->data.result;
                    562:       done = TRUE;
                    563:     }
                    564:   }
                    565: 
                    566:   return result;
                    567: }
                    568: 
                    569: 
                    570: /* easy_events()
                    571:  *
                    572:  * Runs a transfer in a blocking manner using the events-based API
                    573:  */
                    574: static CURLcode easy_events(struct Curl_multi *multi)
                    575: {
                    576:   /* this struct is made static to allow it to be used after this function
                    577:      returns and curl_multi_remove_handle() is called */
                    578:   static struct events evs = {2, FALSE, 0, NULL, 0};
                    579: 
                    580:   /* if running event-based, do some further multi inits */
                    581:   events_setup(multi, &evs);
                    582: 
                    583:   return wait_or_timeout(multi, &evs);
                    584: }
                    585: #else /* CURLDEBUG */
                    586: /* when not built with debug, this function doesn't exist */
                    587: #define easy_events(x) CURLE_NOT_BUILT_IN
                    588: #endif
                    589: 
                    590: static CURLcode easy_transfer(struct Curl_multi *multi)
                    591: {
                    592:   bool done = FALSE;
                    593:   CURLMcode mcode = CURLM_OK;
                    594:   CURLcode result = CURLE_OK;
                    595: 
                    596:   while(!done && !mcode) {
                    597:     int still_running = 0;
                    598: 
                    599:     mcode = curl_multi_poll(multi, NULL, 0, 1000, NULL);
                    600: 
                    601:     if(!mcode)
                    602:       mcode = curl_multi_perform(multi, &still_running);
                    603: 
                    604:     /* only read 'still_running' if curl_multi_perform() return OK */
                    605:     if(!mcode && !still_running) {
                    606:       int rc;
                    607:       CURLMsg *msg = curl_multi_info_read(multi, &rc);
                    608:       if(msg) {
                    609:         result = msg->data.result;
                    610:         done = TRUE;
                    611:       }
                    612:     }
                    613:   }
                    614: 
                    615:   /* Make sure to return some kind of error if there was a multi problem */
                    616:   if(mcode) {
                    617:     result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
                    618:               /* The other multi errors should never happen, so return
                    619:                  something suitably generic */
                    620:               CURLE_BAD_FUNCTION_ARGUMENT;
                    621:   }
                    622: 
                    623:   return result;
                    624: }
                    625: 
                    626: 
                    627: /*
                    628:  * easy_perform() is the external interface that performs a blocking
                    629:  * transfer as previously setup.
                    630:  *
                    631:  * CONCEPT: This function creates a multi handle, adds the easy handle to it,
                    632:  * runs curl_multi_perform() until the transfer is done, then detaches the
                    633:  * easy handle, destroys the multi handle and returns the easy handle's return
                    634:  * code.
                    635:  *
                    636:  * REALITY: it can't just create and destroy the multi handle that easily. It
                    637:  * needs to keep it around since if this easy handle is used again by this
                    638:  * function, the same multi handle must be re-used so that the same pools and
                    639:  * caches can be used.
                    640:  *
                    641:  * DEBUG: if 'events' is set TRUE, this function will use a replacement engine
                    642:  * instead of curl_multi_perform() and use curl_multi_socket_action().
                    643:  */
                    644: static CURLcode easy_perform(struct Curl_easy *data, bool events)
                    645: {
                    646:   struct Curl_multi *multi;
                    647:   CURLMcode mcode;
                    648:   CURLcode result = CURLE_OK;
                    649:   SIGPIPE_VARIABLE(pipe_st);
                    650: 
                    651:   if(!data)
                    652:     return CURLE_BAD_FUNCTION_ARGUMENT;
                    653: 
                    654:   if(data->set.errorbuffer)
                    655:     /* clear this as early as possible */
                    656:     data->set.errorbuffer[0] = 0;
                    657: 
                    658:   if(data->multi) {
                    659:     failf(data, "easy handle already used in multi handle");
                    660:     return CURLE_FAILED_INIT;
                    661:   }
                    662: 
                    663:   if(data->multi_easy)
                    664:     multi = data->multi_easy;
                    665:   else {
                    666:     /* this multi handle will only ever have a single easy handled attached
                    667:        to it, so make it use minimal hashes */
                    668:     multi = Curl_multi_handle(1, 3);
                    669:     if(!multi)
                    670:       return CURLE_OUT_OF_MEMORY;
                    671:     data->multi_easy = multi;
                    672:   }
                    673: 
                    674:   if(multi->in_callback)
                    675:     return CURLE_RECURSIVE_API_CALL;
                    676: 
                    677:   /* Copy the MAXCONNECTS option to the multi handle */
                    678:   curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, data->set.maxconnects);
                    679: 
                    680:   mcode = curl_multi_add_handle(multi, data);
                    681:   if(mcode) {
                    682:     curl_multi_cleanup(multi);
                    683:     if(mcode == CURLM_OUT_OF_MEMORY)
                    684:       return CURLE_OUT_OF_MEMORY;
                    685:     return CURLE_FAILED_INIT;
                    686:   }
                    687: 
                    688:   sigpipe_ignore(data, &pipe_st);
                    689: 
                    690:   /* run the transfer */
                    691:   result = events ? easy_events(multi) : easy_transfer(multi);
                    692: 
                    693:   /* ignoring the return code isn't nice, but atm we can't really handle
                    694:      a failure here, room for future improvement! */
                    695:   (void)curl_multi_remove_handle(multi, data);
                    696: 
                    697:   sigpipe_restore(&pipe_st);
                    698: 
                    699:   /* The multi handle is kept alive, owned by the easy handle */
                    700:   return result;
                    701: }
                    702: 
                    703: 
                    704: /*
                    705:  * curl_easy_perform() is the external interface that performs a blocking
                    706:  * transfer as previously setup.
                    707:  */
                    708: CURLcode curl_easy_perform(struct Curl_easy *data)
                    709: {
                    710:   return easy_perform(data, FALSE);
                    711: }
                    712: 
                    713: #ifdef CURLDEBUG
                    714: /*
                    715:  * curl_easy_perform_ev() is the external interface that performs a blocking
                    716:  * transfer using the event-based API internally.
                    717:  */
                    718: CURLcode curl_easy_perform_ev(struct Curl_easy *data)
                    719: {
                    720:   return easy_perform(data, TRUE);
                    721: }
                    722: 
                    723: #endif
                    724: 
                    725: /*
                    726:  * curl_easy_cleanup() is the external interface to cleaning/freeing the given
                    727:  * easy handle.
                    728:  */
                    729: void curl_easy_cleanup(struct Curl_easy *data)
                    730: {
                    731:   SIGPIPE_VARIABLE(pipe_st);
                    732: 
                    733:   if(!data)
                    734:     return;
                    735: 
                    736:   sigpipe_ignore(data, &pipe_st);
                    737:   Curl_close(&data);
                    738:   sigpipe_restore(&pipe_st);
                    739: }
                    740: 
                    741: /*
                    742:  * curl_easy_getinfo() is an external interface that allows an app to retrieve
                    743:  * information from a performed transfer and similar.
                    744:  */
                    745: #undef curl_easy_getinfo
                    746: CURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...)
                    747: {
                    748:   va_list arg;
                    749:   void *paramp;
                    750:   CURLcode result;
                    751: 
                    752:   va_start(arg, info);
                    753:   paramp = va_arg(arg, void *);
                    754: 
                    755:   result = Curl_getinfo(data, info, paramp);
                    756: 
                    757:   va_end(arg);
                    758:   return result;
                    759: }
                    760: 
                    761: static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
                    762: {
                    763:   CURLcode result = CURLE_OK;
                    764:   enum dupstring i;
                    765: 
                    766:   /* Copy src->set into dst->set first, then deal with the strings
                    767:      afterwards */
                    768:   dst->set = src->set;
                    769:   Curl_mime_initpart(&dst->set.mimepost, dst);
                    770: 
                    771:   /* clear all string pointers first */
                    772:   memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
                    773: 
                    774:   /* duplicate all strings */
                    775:   for(i = (enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) {
                    776:     result = Curl_setstropt(&dst->set.str[i], src->set.str[i]);
                    777:     if(result)
                    778:       return result;
                    779:   }
                    780: 
                    781:   /* duplicate memory areas pointed to */
                    782:   i = STRING_COPYPOSTFIELDS;
                    783:   if(src->set.postfieldsize && src->set.str[i]) {
                    784:     /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */
                    785:     dst->set.str[i] = Curl_memdup(src->set.str[i],
                    786:                                   curlx_sotouz(src->set.postfieldsize));
                    787:     if(!dst->set.str[i])
                    788:       return CURLE_OUT_OF_MEMORY;
                    789:     /* point to the new copy */
                    790:     dst->set.postfields = dst->set.str[i];
                    791:   }
                    792: 
                    793:   /* Duplicate mime data. */
                    794:   result = Curl_mime_duppart(&dst->set.mimepost, &src->set.mimepost);
                    795: 
                    796:   if(src->set.resolve)
                    797:     dst->change.resolve = dst->set.resolve;
                    798: 
                    799:   return result;
                    800: }
                    801: 
                    802: /*
                    803:  * curl_easy_duphandle() is an external interface to allow duplication of a
                    804:  * given input easy handle. The returned handle will be a new working handle
                    805:  * with all options set exactly as the input source handle.
                    806:  */
                    807: struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
                    808: {
                    809:   struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy));
                    810:   if(NULL == outcurl)
                    811:     goto fail;
                    812: 
                    813:   /*
                    814:    * We setup a few buffers we need. We should probably make them
                    815:    * get setup on-demand in the code, as that would probably decrease
                    816:    * the likeliness of us forgetting to init a buffer here in the future.
                    817:    */
                    818:   outcurl->set.buffer_size = data->set.buffer_size;
                    819:   outcurl->state.buffer = malloc(outcurl->set.buffer_size + 1);
                    820:   if(!outcurl->state.buffer)
                    821:     goto fail;
                    822: 
                    823:   outcurl->state.headerbuff = malloc(HEADERSIZE);
                    824:   if(!outcurl->state.headerbuff)
                    825:     goto fail;
                    826:   outcurl->state.headersize = HEADERSIZE;
                    827: 
                    828:   /* copy all userdefined values */
                    829:   if(dupset(outcurl, data))
                    830:     goto fail;
                    831: 
                    832:   /* the connection cache is setup on demand */
                    833:   outcurl->state.conn_cache = NULL;
                    834: 
                    835:   outcurl->state.lastconnect = NULL;
                    836: 
                    837:   outcurl->progress.flags    = data->progress.flags;
                    838:   outcurl->progress.callback = data->progress.callback;
                    839: 
                    840:   if(data->cookies) {
                    841:     /* If cookies are enabled in the parent handle, we enable them
                    842:        in the clone as well! */
                    843:     outcurl->cookies = Curl_cookie_init(data,
                    844:                                         data->cookies->filename,
                    845:                                         outcurl->cookies,
                    846:                                         data->set.cookiesession);
                    847:     if(!outcurl->cookies)
                    848:       goto fail;
                    849:   }
                    850: 
                    851:   /* duplicate all values in 'change' */
                    852:   if(data->change.cookielist) {
                    853:     outcurl->change.cookielist =
                    854:       Curl_slist_duplicate(data->change.cookielist);
                    855:     if(!outcurl->change.cookielist)
                    856:       goto fail;
                    857:   }
                    858: 
                    859:   if(data->change.url) {
                    860:     outcurl->change.url = strdup(data->change.url);
                    861:     if(!outcurl->change.url)
                    862:       goto fail;
                    863:     outcurl->change.url_alloc = TRUE;
                    864:   }
                    865: 
                    866:   if(data->change.referer) {
                    867:     outcurl->change.referer = strdup(data->change.referer);
                    868:     if(!outcurl->change.referer)
                    869:       goto fail;
                    870:     outcurl->change.referer_alloc = TRUE;
                    871:   }
                    872: 
                    873:   /* Reinitialize an SSL engine for the new handle
                    874:    * note: the engine name has already been copied by dupset */
                    875:   if(outcurl->set.str[STRING_SSL_ENGINE]) {
                    876:     if(Curl_ssl_set_engine(outcurl, outcurl->set.str[STRING_SSL_ENGINE]))
                    877:       goto fail;
                    878:   }
                    879: 
                    880:   /* Clone the resolver handle, if present, for the new handle */
                    881:   if(Curl_resolver_duphandle(outcurl,
                    882:                              &outcurl->state.resolver,
                    883:                              data->state.resolver))
                    884:     goto fail;
                    885: 
                    886: #ifdef USE_ARES
                    887:   {
                    888:     CURLcode rc;
                    889: 
                    890:     rc = Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS]);
                    891:     if(rc && rc != CURLE_NOT_BUILT_IN)
                    892:       goto fail;
                    893: 
                    894:     rc = Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE]);
                    895:     if(rc && rc != CURLE_NOT_BUILT_IN)
                    896:       goto fail;
                    897: 
                    898:     rc = Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4]);
                    899:     if(rc && rc != CURLE_NOT_BUILT_IN)
                    900:       goto fail;
                    901: 
                    902:     rc = Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6]);
                    903:     if(rc && rc != CURLE_NOT_BUILT_IN)
                    904:       goto fail;
                    905:   }
                    906: #endif /* USE_ARES */
                    907: 
                    908:   Curl_convert_setup(outcurl);
                    909: 
                    910:   Curl_initinfo(outcurl);
                    911: 
                    912:   outcurl->magic = CURLEASY_MAGIC_NUMBER;
                    913: 
                    914:   /* we reach this point and thus we are OK */
                    915: 
                    916:   return outcurl;
                    917: 
                    918:   fail:
                    919: 
                    920:   if(outcurl) {
                    921:     curl_slist_free_all(outcurl->change.cookielist);
                    922:     outcurl->change.cookielist = NULL;
                    923:     Curl_safefree(outcurl->state.buffer);
                    924:     Curl_safefree(outcurl->state.headerbuff);
                    925:     Curl_safefree(outcurl->change.url);
                    926:     Curl_safefree(outcurl->change.referer);
                    927:     Curl_freeset(outcurl);
                    928:     free(outcurl);
                    929:   }
                    930: 
                    931:   return NULL;
                    932: }
                    933: 
                    934: /*
                    935:  * curl_easy_reset() is an external interface that allows an app to re-
                    936:  * initialize a session handle to the default values.
                    937:  */
                    938: void curl_easy_reset(struct Curl_easy *data)
                    939: {
                    940:   long old_buffer_size = data->set.buffer_size;
                    941: 
                    942:   Curl_free_request_state(data);
                    943: 
                    944:   /* zero out UserDefined data: */
                    945:   Curl_freeset(data);
                    946:   memset(&data->set, 0, sizeof(struct UserDefined));
                    947:   (void)Curl_init_userdefined(data);
                    948: 
                    949:   /* zero out Progress data: */
                    950:   memset(&data->progress, 0, sizeof(struct Progress));
                    951: 
                    952:   /* zero out PureInfo data: */
                    953:   Curl_initinfo(data);
                    954: 
                    955:   data->progress.flags |= PGRS_HIDE;
                    956:   data->state.current_speed = -1; /* init to negative == impossible */
                    957: 
                    958:   /* zero out authentication data: */
                    959:   memset(&data->state.authhost, 0, sizeof(struct auth));
                    960:   memset(&data->state.authproxy, 0, sizeof(struct auth));
                    961: 
                    962: #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
                    963:   Curl_http_auth_cleanup_digest(data);
                    964: #endif
                    965: 
                    966:   /* resize receive buffer */
                    967:   if(old_buffer_size != data->set.buffer_size) {
                    968:     char *newbuff = realloc(data->state.buffer, data->set.buffer_size + 1);
                    969:     if(!newbuff) {
                    970:       DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n"));
                    971:       /* nothing we can do here except use the old size */
                    972:       data->set.buffer_size = old_buffer_size;
                    973:     }
                    974:     else
                    975:       data->state.buffer = newbuff;
                    976:   }
                    977: }
                    978: 
                    979: /*
                    980:  * curl_easy_pause() allows an application to pause or unpause a specific
                    981:  * transfer and direction. This function sets the full new state for the
                    982:  * current connection this easy handle operates on.
                    983:  *
                    984:  * NOTE: if you have the receiving paused and you call this function to remove
                    985:  * the pausing, you may get your write callback called at this point.
                    986:  *
                    987:  * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
                    988:  *
                    989:  * NOTE: This is one of few API functions that are allowed to be called from
                    990:  * within a callback.
                    991:  */
                    992: CURLcode curl_easy_pause(struct Curl_easy *data, int action)
                    993: {
                    994:   struct SingleRequest *k;
                    995:   CURLcode result = CURLE_OK;
                    996:   int oldstate;
                    997:   int newstate;
                    998: 
                    999:   if(!GOOD_EASY_HANDLE(data) || !data->conn)
                   1000:     /* crazy input, don't continue */
                   1001:     return CURLE_BAD_FUNCTION_ARGUMENT;
                   1002: 
                   1003:   k = &data->req;
                   1004:   oldstate = k->keepon & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);
                   1005: 
                   1006:   /* first switch off both pause bits then set the new pause bits */
                   1007:   newstate = (k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) |
                   1008:     ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
                   1009:     ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
                   1010: 
                   1011:   if((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) == oldstate) {
                   1012:     /* Not changing any pause state, return */
                   1013:     DEBUGF(infof(data, "pause: no change, early return\n"));
                   1014:     return CURLE_OK;
                   1015:   }
                   1016: 
                   1017:   /* Unpause parts in active mime tree. */
                   1018:   if((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
                   1019:      (data->mstate == CURLM_STATE_PERFORM ||
                   1020:       data->mstate == CURLM_STATE_TOOFAST) &&
                   1021:      data->state.fread_func == (curl_read_callback) Curl_mime_read) {
                   1022:     Curl_mime_unpause(data->state.in);
                   1023:   }
                   1024: 
                   1025:   /* put it back in the keepon */
                   1026:   k->keepon = newstate;
                   1027: 
                   1028:   if(!(newstate & KEEP_RECV_PAUSE)) {
                   1029:     Curl_http2_stream_pause(data, FALSE);
                   1030: 
                   1031:     if(data->state.tempcount) {
                   1032:       /* there are buffers for sending that can be delivered as the receive
                   1033:          pausing is lifted! */
                   1034:       unsigned int i;
                   1035:       unsigned int count = data->state.tempcount;
                   1036:       struct tempbuf writebuf[3]; /* there can only be three */
                   1037:       struct connectdata *conn = data->conn;
                   1038:       struct Curl_easy *saved_data = NULL;
                   1039: 
                   1040:       /* copy the structs to allow for immediate re-pausing */
                   1041:       for(i = 0; i < data->state.tempcount; i++) {
                   1042:         writebuf[i] = data->state.tempwrite[i];
                   1043:         data->state.tempwrite[i].buf = NULL;
                   1044:       }
                   1045:       data->state.tempcount = 0;
                   1046: 
                   1047:       /* set the connection's current owner */
                   1048:       if(conn->data != data) {
                   1049:         saved_data = conn->data;
                   1050:         conn->data = data;
                   1051:       }
                   1052: 
                   1053:       for(i = 0; i < count; i++) {
                   1054:         /* even if one function returns error, this loops through and frees
                   1055:            all buffers */
                   1056:         if(!result)
                   1057:           result = Curl_client_write(conn, writebuf[i].type, writebuf[i].buf,
                   1058:                                      writebuf[i].len);
                   1059:         free(writebuf[i].buf);
                   1060:       }
                   1061: 
                   1062:       /* recover previous owner of the connection */
                   1063:       if(saved_data)
                   1064:         conn->data = saved_data;
                   1065: 
                   1066:       if(result)
                   1067:         return result;
                   1068:     }
                   1069:   }
                   1070: 
                   1071:   /* if there's no error and we're not pausing both directions, we want
                   1072:      to have this handle checked soon */
                   1073:   if((newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
                   1074:      (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) {
                   1075:     Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */
                   1076: 
                   1077:     /* force a recv/send check of this connection, as the data might've been
                   1078:        read off the socket already */
                   1079:     data->conn->cselect_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT;
                   1080:     if(data->multi)
                   1081:       Curl_update_timer(data->multi);
                   1082:   }
                   1083: 
                   1084:   if(!data->state.done)
                   1085:     /* This transfer may have been moved in or out of the bundle, update the
                   1086:        corresponding socket callback, if used */
                   1087:     Curl_updatesocket(data);
                   1088: 
                   1089:   return result;
                   1090: }
                   1091: 
                   1092: 
                   1093: static CURLcode easy_connection(struct Curl_easy *data,
                   1094:                                 curl_socket_t *sfd,
                   1095:                                 struct connectdata **connp)
                   1096: {
                   1097:   if(data == NULL)
                   1098:     return CURLE_BAD_FUNCTION_ARGUMENT;
                   1099: 
                   1100:   /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
                   1101:   if(!data->set.connect_only) {
                   1102:     failf(data, "CONNECT_ONLY is required!");
                   1103:     return CURLE_UNSUPPORTED_PROTOCOL;
                   1104:   }
                   1105: 
                   1106:   *sfd = Curl_getconnectinfo(data, connp);
                   1107: 
                   1108:   if(*sfd == CURL_SOCKET_BAD) {
                   1109:     failf(data, "Failed to get recent socket");
                   1110:     return CURLE_UNSUPPORTED_PROTOCOL;
                   1111:   }
                   1112: 
                   1113:   return CURLE_OK;
                   1114: }
                   1115: 
                   1116: /*
                   1117:  * Receives data from the connected socket. Use after successful
                   1118:  * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
                   1119:  * Returns CURLE_OK on success, error code on error.
                   1120:  */
                   1121: CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
                   1122:                         size_t *n)
                   1123: {
                   1124:   curl_socket_t sfd;
                   1125:   CURLcode result;
                   1126:   ssize_t n1;
                   1127:   struct connectdata *c;
                   1128: 
                   1129:   if(Curl_is_in_callback(data))
                   1130:     return CURLE_RECURSIVE_API_CALL;
                   1131: 
                   1132:   result = easy_connection(data, &sfd, &c);
                   1133:   if(result)
                   1134:     return result;
                   1135: 
                   1136:   *n = 0;
                   1137:   result = Curl_read(c, sfd, buffer, buflen, &n1);
                   1138: 
                   1139:   if(result)
                   1140:     return result;
                   1141: 
                   1142:   *n = (size_t)n1;
                   1143: 
                   1144:   return CURLE_OK;
                   1145: }
                   1146: 
                   1147: /*
                   1148:  * Sends data over the connected socket. Use after successful
                   1149:  * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
                   1150:  */
                   1151: CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
                   1152:                         size_t buflen, size_t *n)
                   1153: {
                   1154:   curl_socket_t sfd;
                   1155:   CURLcode result;
                   1156:   ssize_t n1;
                   1157:   struct connectdata *c = NULL;
                   1158: 
                   1159:   if(Curl_is_in_callback(data))
                   1160:     return CURLE_RECURSIVE_API_CALL;
                   1161: 
                   1162:   result = easy_connection(data, &sfd, &c);
                   1163:   if(result)
                   1164:     return result;
                   1165: 
                   1166:   *n = 0;
                   1167:   result = Curl_write(c, sfd, buffer, buflen, &n1);
                   1168: 
                   1169:   if(n1 == -1)
                   1170:     return CURLE_SEND_ERROR;
                   1171: 
                   1172:   /* detect EAGAIN */
                   1173:   if(!result && !n1)
                   1174:     return CURLE_AGAIN;
                   1175: 
                   1176:   *n = (size_t)n1;
                   1177: 
                   1178:   return result;
                   1179: }
                   1180: 
                   1181: /*
                   1182:  * Wrapper to call functions in Curl_conncache_foreach()
                   1183:  *
                   1184:  * Returns always 0.
                   1185:  */
                   1186: static int conn_upkeep(struct connectdata *conn,
                   1187:                        void *param)
                   1188: {
                   1189:   /* Param is unused. */
                   1190:   (void)param;
                   1191: 
                   1192:   if(conn->handler->connection_check) {
                   1193:     /* Do a protocol-specific keepalive check on the connection. */
                   1194:     conn->handler->connection_check(conn, CONNCHECK_KEEPALIVE);
                   1195:   }
                   1196: 
                   1197:   return 0; /* continue iteration */
                   1198: }
                   1199: 
                   1200: static CURLcode upkeep(struct conncache *conn_cache, void *data)
                   1201: {
                   1202:   /* Loop over every connection and make connection alive. */
                   1203:   Curl_conncache_foreach(data,
                   1204:                          conn_cache,
                   1205:                          data,
                   1206:                          conn_upkeep);
                   1207:   return CURLE_OK;
                   1208: }
                   1209: 
                   1210: /*
                   1211:  * Performs connection upkeep for the given session handle.
                   1212:  */
                   1213: CURLcode curl_easy_upkeep(struct Curl_easy *data)
                   1214: {
                   1215:   /* Verify that we got an easy handle we can work with. */
                   1216:   if(!GOOD_EASY_HANDLE(data))
                   1217:     return CURLE_BAD_FUNCTION_ARGUMENT;
                   1218: 
                   1219:   if(data->multi_easy) {
                   1220:     /* Use the common function to keep connections alive. */
                   1221:     return upkeep(&data->multi_easy->conn_cache, data);
                   1222:   }
                   1223:   else {
                   1224:     /* No connections, so just return success */
                   1225:     return CURLE_OK;
                   1226:   }
                   1227: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>