quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

libcurl-multi.md (8140B)


      1 ---
      2 c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      3 SPDX-License-Identifier: curl
      4 Title: libcurl-multi
      5 Section: 3
      6 Source: libcurl
      7 See-also:
      8   - libcurl (3)
      9   - libcurl-easy (3)
     10   - libcurl-errors (3)
     11 Protocol:
     12   - All
     13 Added-in: 7.9.6
     14 ---
     15 
     16 # NAME
     17 
     18 libcurl-multi - how to use the multi interface
     19 
     20 # DESCRIPTION
     21 
     22 This is an overview on how to use the libcurl multi interface in your C
     23 programs. There are specific man pages for each function mentioned in
     24 here. There is also the libcurl-tutorial(3) man page for a complete
     25 tutorial to programming with libcurl and the libcurl-easy(3) man page
     26 for an overview of the libcurl easy interface.
     27 
     28 All functions in the multi interface are prefixed with curl_multi.
     29 
     30 # OBJECTIVES
     31 
     32 The multi interface offers several abilities that the easy interface does not.
     33 They are mainly:
     34 
     35 1. Enable a "pull" interface. The application that uses libcurl decides where
     36 and when to ask libcurl to get/send data.
     37 
     38 2. Enable multiple simultaneous transfers in the same thread without making it
     39 complicated for the application.
     40 
     41 3. Enable the application to wait for action on its own file descriptors and
     42 curl's file descriptors simultaneously.
     43 
     44 4. Enable event-based handling and scaling transfers up to and beyond
     45 thousands of parallel connections.
     46 
     47 # ONE MULTI HANDLE MANY EASY HANDLES
     48 
     49 To use the multi interface, you must first create a 'multi handle' with
     50 curl_multi_init(3). This handle is then used as input to all further
     51 curl_multi_* functions.
     52 
     53 With a multi handle and the multi interface you can do several simultaneous
     54 transfers in parallel. Each single transfer is built up around an easy
     55 handle. You create all the easy handles you need, and setup the appropriate
     56 options for each easy handle using curl_easy_setopt(3).
     57 
     58 There are two flavors of the multi interface, the select() oriented one and
     59 the event based one we call multi_socket. You benefit from reading through the
     60 description of both versions to fully understand how they work and
     61 differentiate. We start out with the select() oriented version.
     62 
     63 When an easy handle is setup and ready for transfer, then instead of using
     64 curl_easy_perform(3) like when using the easy interface for transfers,
     65 you should add the easy handle to the multi handle with
     66 curl_multi_add_handle(3). You can add more easy handles to a multi
     67 handle at any point, even if other transfers are already running.
     68 
     69 Should you change your mind, the easy handle is again removed from the multi
     70 stack using curl_multi_remove_handle(3). Once removed from the multi
     71 handle, you can again use other easy interface functions like
     72 curl_easy_perform(3) on the handle or whatever you think is
     73 necessary. You can remove handles at any point during transfers.
     74 
     75 Adding the easy handle to the multi handle does not start the transfer.
     76 Remember that one of the main ideas with this interface is to let your
     77 application drive. You drive the transfers by invoking
     78 curl_multi_perform(3). libcurl then transfers data if there is anything
     79 available to transfer. It uses the callbacks and everything else you have
     80 setup in the individual easy handles. It transfers data on all current
     81 transfers in the multi stack that are ready to transfer anything. It may be
     82 all, it may be none. When there is nothing more to do for now, it returns back
     83 to the calling application.
     84 
     85 Your application extracts info from libcurl about when it would like to get
     86 invoked to transfer data or do other work. The most convenient way is to use
     87 curl_multi_poll(3) that helps you wait until the application should call
     88 libcurl again. The older API to accomplish the same thing is
     89 curl_multi_fdset(3) that extracts *fd_sets* from libcurl to use in
     90 select() or poll() calls in order to get to know when the transfers in the
     91 multi stack might need attention. Both these APIs allow for your program to
     92 wait for input on your own private file descriptors at the same time.
     93 curl_multi_timeout(3) also helps you with providing a suitable timeout
     94 period for your select() calls.
     95 
     96 curl_multi_perform(3) stores the number of still running transfers in
     97 one of its input arguments, and by reading that you can figure out when all
     98 the transfers in the multi handles are done. 'done' does not mean
     99 successful. One or more of the transfers may have failed.
    100 
    101 To get information about completed transfers, to figure out success or not and
    102 similar, curl_multi_info_read(3) should be called. It can return a
    103 message about a current or previous transfer. Repeated invokes of the function
    104 get more messages until the message queue is empty. The information you
    105 receive there includes an easy handle pointer which you may use to identify
    106 which easy handle the information regards.
    107 
    108 When a single transfer is completed, the easy handle is still left added to
    109 the multi stack. You need to first remove the easy handle with
    110 curl_multi_remove_handle(3) and then close it with
    111 curl_easy_cleanup(3), or possibly set new options to it and add it again
    112 with curl_multi_add_handle(3) to start another transfer.
    113 
    114 When all transfers in the multi stack are done, close the multi handle with
    115 curl_multi_cleanup(3). Be careful and please note that you **MUST**
    116 invoke separate curl_easy_cleanup(3) calls for every single easy handle
    117 to clean them up properly.
    118 
    119 If you want to reuse an easy handle that was added to the multi handle for
    120 transfer, you must first remove it from the multi stack and then re-add it
    121 again (possibly after having altered some options at your own choice).
    122 
    123 # MULTI_SOCKET
    124 
    125 curl_multi_socket_action(3) function offers a way for applications to
    126 not only avoid being forced to use select(), but it also offers a much more
    127 high-performance API that makes a significant difference for applications
    128 using large numbers of simultaneous connections.
    129 
    130 curl_multi_socket_action(3) is then used instead of
    131 curl_multi_perform(3).
    132 
    133 When using this API, you add easy handles to the multi handle just as with the
    134 normal multi interface. Then you also set two callbacks with the
    135 CURLMOPT_SOCKETFUNCTION(3) and CURLMOPT_TIMERFUNCTION(3) options
    136 to curl_multi_setopt(3). They are two callback functions that libcurl
    137 calls with information about what sockets to wait for, and for what activity,
    138 and what the current timeout time is - if that expires libcurl should be
    139 notified.
    140 
    141 The multi_socket API is designed to inform your application about which
    142 sockets libcurl is currently using and for what activities (read and/or write)
    143 on those sockets your application is expected to wait for.
    144 
    145 Your application must make sure to receive all sockets informed about in the
    146 CURLMOPT_SOCKETFUNCTION(3) callback and make sure it reacts on the given
    147 activity on them. When a socket has the given activity, you call
    148 curl_multi_socket_action(3) specifying which socket and action there
    149 are.
    150 
    151 The CURLMOPT_TIMERFUNCTION(3) callback is called to set a timeout. When
    152 that timeout expires, your application should call the
    153 curl_multi_socket_action(3) function saying it was due to a timeout.
    154 
    155 This API is typically used with an event-driven underlying functionality (like
    156 libevent, libev, kqueue, epoll or similar) with which the application
    157 "subscribes" on socket changes. This allows applications and libcurl to much
    158 better scale upward and beyond thousands of simultaneous transfers without
    159 losing performance.
    160 
    161 When you have added your initial set of handles, you call
    162 curl_multi_socket_action(3) with CURL_SOCKET_TIMEOUT set in the
    163 *sockfd* argument, and you get callbacks invoked that set you up and you
    164 then continue to call curl_multi_socket_action(3) accordingly when you
    165 get activity on the sockets you have been asked to wait on, or if the timeout
    166 timer expires.
    167 
    168 You can poll curl_multi_info_read(3) to see if any transfer has
    169 completed, as it then has a message saying so.
    170 
    171 # BLOCKING
    172 
    173 A few areas in the code are still using blocking code, even when used from the
    174 multi interface. While we certainly want and intend for these to get fixed in
    175 the future, you should be aware of the following current restrictions:
    176 
    177 ~~~c
    178  - Name resolves unless the c-ares or threaded-resolver backends are used
    179  - file:// transfers
    180  - TELNET transfers
    181 ~~~