Annotation of embedaddon/curl/lib/easy.c, revision 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>