1 //! Multi - initiating multiple requests simultaneously
2 
3 use std::fmt;
4 use std::marker;
5 use std::ptr;
6 use std::time::Duration;
7 
8 use curl_sys;
9 use libc::{c_char, c_int, c_long, c_short, c_void};
10 
11 #[cfg(unix)]
12 use libc::{pollfd, POLLIN, POLLOUT, POLLPRI};
13 
14 use easy::{Easy, Easy2, List};
15 use panic;
16 use {Error, MultiError};
17 
18 /// A multi handle for initiating multiple connections simultaneously.
19 ///
20 /// This structure corresponds to `CURLM` in libcurl and provides the ability to
21 /// have multiple transfers in flight simultaneously. This handle is then used
22 /// to manage each transfer. The main purpose of a `CURLM` is for the
23 /// *application* to drive the I/O rather than libcurl itself doing all the
24 /// blocking. Methods like `action` allow the application to inform libcurl of
25 /// when events have happened.
26 ///
27 /// Lots more documentation can be found on the libcurl [multi tutorial] where
28 /// the APIs correspond pretty closely with this crate.
29 ///
30 /// [multi tutorial]: https://curl.haxx.se/libcurl/c/libcurl-multi.html
31 pub struct Multi {
32     raw: *mut curl_sys::CURLM,
33     data: Box<MultiData>,
34 }
35 
36 struct MultiData {
37     socket: Box<dyn FnMut(Socket, SocketEvents, usize) + Send>,
38     timer: Box<dyn FnMut(Option<Duration>) -> bool + Send>,
39 }
40 
41 /// Message from the `messages` function of a multi handle.
42 ///
43 /// Currently only indicates whether a transfer is done.
44 pub struct Message<'multi> {
45     ptr: *mut curl_sys::CURLMsg,
46     _multi: &'multi Multi,
47 }
48 
49 /// Wrapper around an easy handle while it's owned by a multi handle.
50 ///
51 /// Once an easy handle has been added to a multi handle then it can no longer
52 /// be used via `perform`. This handle is also used to remove the easy handle
53 /// from the multi handle when desired.
54 pub struct EasyHandle {
55     easy: Easy,
56     // This is now effectively bound to a `Multi`, so it is no longer sendable.
57     _marker: marker::PhantomData<&'static Multi>,
58 }
59 
60 /// Wrapper around an easy handle while it's owned by a multi handle.
61 ///
62 /// Once an easy handle has been added to a multi handle then it can no longer
63 /// be used via `perform`. This handle is also used to remove the easy handle
64 /// from the multi handle when desired.
65 pub struct Easy2Handle<H> {
66     easy: Easy2<H>,
67     // This is now effectively bound to a `Multi`, so it is no longer sendable.
68     _marker: marker::PhantomData<&'static Multi>,
69 }
70 
71 /// Notification of the events that have happened on a socket.
72 ///
73 /// This type is passed as an argument to the `action` method on a multi handle
74 /// to indicate what events have occurred on a socket.
75 pub struct Events {
76     bits: c_int,
77 }
78 
79 /// Notification of events that are requested on a socket.
80 ///
81 /// This type is yielded to the `socket_function` callback to indicate what
82 /// events are requested on a socket.
83 pub struct SocketEvents {
84     bits: c_int,
85 }
86 
87 /// Raw underlying socket type that the multi handles use
88 pub type Socket = curl_sys::curl_socket_t;
89 
90 /// File descriptor to wait on for use with the `wait` method on a multi handle.
91 pub struct WaitFd {
92     inner: curl_sys::curl_waitfd,
93 }
94 
95 impl Multi {
96     /// Creates a new multi session through which multiple HTTP transfers can be
97     /// initiated.
new() -> Multi98     pub fn new() -> Multi {
99         unsafe {
100             ::init();
101             let ptr = curl_sys::curl_multi_init();
102             assert!(!ptr.is_null());
103             Multi {
104                 raw: ptr,
105                 data: Box::new(MultiData {
106                     socket: Box::new(|_, _, _| ()),
107                     timer: Box::new(|_| true),
108                 }),
109             }
110         }
111     }
112 
113     /// Set the callback informed about what to wait for
114     ///
115     /// When the `action` function runs, it informs the application about
116     /// updates in the socket (file descriptor) status by doing none, one, or
117     /// multiple calls to the socket callback. The callback gets status updates
118     /// with changes since the previous time the callback was called. See
119     /// `action` for more details on how the callback is used and should work.
120     ///
121     /// The `SocketEvents` parameter informs the callback on the status of the
122     /// given socket, and the methods on that type can be used to learn about
123     /// what's going on with the socket.
124     ///
125     /// The third `usize` parameter is a custom value set by the `assign` method
126     /// below.
socket_function<F>(&mut self, f: F) -> Result<(), MultiError> where F: FnMut(Socket, SocketEvents, usize) + Send + 'static,127     pub fn socket_function<F>(&mut self, f: F) -> Result<(), MultiError>
128     where
129         F: FnMut(Socket, SocketEvents, usize) + Send + 'static,
130     {
131         self._socket_function(Box::new(f))
132     }
133 
_socket_function( &mut self, f: Box<dyn FnMut(Socket, SocketEvents, usize) + Send>, ) -> Result<(), MultiError>134     fn _socket_function(
135         &mut self,
136         f: Box<dyn FnMut(Socket, SocketEvents, usize) + Send>,
137     ) -> Result<(), MultiError> {
138         self.data.socket = f;
139         let cb: curl_sys::curl_socket_callback = cb;
140         self.setopt_ptr(
141             curl_sys::CURLMOPT_SOCKETFUNCTION,
142             cb as usize as *const c_char,
143         )?;
144         let ptr = &*self.data as *const _;
145         self.setopt_ptr(curl_sys::CURLMOPT_SOCKETDATA, ptr as *const c_char)?;
146         return Ok(());
147 
148         // TODO: figure out how to expose `_easy`
149         extern "C" fn cb(
150             _easy: *mut curl_sys::CURL,
151             socket: curl_sys::curl_socket_t,
152             what: c_int,
153             userptr: *mut c_void,
154             socketp: *mut c_void,
155         ) -> c_int {
156             panic::catch(|| unsafe {
157                 let f = &mut (*(userptr as *mut MultiData)).socket;
158                 f(socket, SocketEvents { bits: what }, socketp as usize)
159             });
160             0
161         }
162     }
163 
164     /// Set data to associate with an internal socket
165     ///
166     /// This function creates an association in the multi handle between the
167     /// given socket and a private token of the application. This is designed
168     /// for `action` uses.
169     ///
170     /// When set, the token will be passed to all future socket callbacks for
171     /// the specified socket.
172     ///
173     /// If the given socket isn't already in use by libcurl, this function will
174     /// return an error.
175     ///
176     /// libcurl only keeps one single token associated with a socket, so
177     /// calling this function several times for the same socket will make the
178     /// last set token get used.
179     ///
180     /// The idea here being that this association (socket to token) is something
181     /// that just about every application that uses this API will need and then
182     /// libcurl can just as well do it since it already has an internal hash
183     /// table lookup for this.
184     ///
185     /// # Typical Usage
186     ///
187     /// In a typical application you allocate a struct or at least use some kind
188     /// of semi-dynamic data for each socket that we must wait for action on
189     /// when using the `action` approach.
190     ///
191     /// When our socket-callback gets called by libcurl and we get to know about
192     /// yet another socket to wait for, we can use `assign` to point out the
193     /// particular data so that when we get updates about this same socket
194     /// again, we don't have to find the struct associated with this socket by
195     /// ourselves.
assign(&self, socket: Socket, token: usize) -> Result<(), MultiError>196     pub fn assign(&self, socket: Socket, token: usize) -> Result<(), MultiError> {
197         unsafe {
198             cvt(curl_sys::curl_multi_assign(
199                 self.raw,
200                 socket,
201                 token as *mut _,
202             ))?;
203             Ok(())
204         }
205     }
206 
207     /// Set callback to receive timeout values
208     ///
209     /// Certain features, such as timeouts and retries, require you to call
210     /// libcurl even when there is no activity on the file descriptors.
211     ///
212     /// Your callback function should install a non-repeating timer with the
213     /// interval specified. Each time that timer fires, call either `action` or
214     /// `perform`, depending on which interface you use.
215     ///
216     /// A timeout value of `None` means you should delete your timer.
217     ///
218     /// A timeout value of 0 means you should call `action` or `perform` (once)
219     /// as soon as possible.
220     ///
221     /// This callback will only be called when the timeout changes.
222     ///
223     /// The timer callback should return `true` on success, and `false` on
224     /// error. This callback can be used instead of, or in addition to,
225     /// `get_timeout`.
timer_function<F>(&mut self, f: F) -> Result<(), MultiError> where F: FnMut(Option<Duration>) -> bool + Send + 'static,226     pub fn timer_function<F>(&mut self, f: F) -> Result<(), MultiError>
227     where
228         F: FnMut(Option<Duration>) -> bool + Send + 'static,
229     {
230         self._timer_function(Box::new(f))
231     }
232 
_timer_function( &mut self, f: Box<dyn FnMut(Option<Duration>) -> bool + Send>, ) -> Result<(), MultiError>233     fn _timer_function(
234         &mut self,
235         f: Box<dyn FnMut(Option<Duration>) -> bool + Send>,
236     ) -> Result<(), MultiError> {
237         self.data.timer = f;
238         let cb: curl_sys::curl_multi_timer_callback = cb;
239         self.setopt_ptr(
240             curl_sys::CURLMOPT_TIMERFUNCTION,
241             cb as usize as *const c_char,
242         )?;
243         let ptr = &*self.data as *const _;
244         self.setopt_ptr(curl_sys::CURLMOPT_TIMERDATA, ptr as *const c_char)?;
245         return Ok(());
246 
247         // TODO: figure out how to expose `_multi`
248         extern "C" fn cb(
249             _multi: *mut curl_sys::CURLM,
250             timeout_ms: c_long,
251             user: *mut c_void,
252         ) -> c_int {
253             let keep_going = panic::catch(|| unsafe {
254                 let f = &mut (*(user as *mut MultiData)).timer;
255                 if timeout_ms == -1 {
256                     f(None)
257                 } else {
258                     f(Some(Duration::from_millis(timeout_ms as u64)))
259                 }
260             })
261             .unwrap_or(false);
262             if keep_going {
263                 0
264             } else {
265                 -1
266             }
267         }
268     }
269 
270     /// Enable or disable HTTP pipelining and multiplexing.
271     ///
272     /// When http_1 is true, enable HTTP/1.1 pipelining, which means that if
273     /// you add a second request that can use an already existing connection,
274     /// the second request will be "piped" on the same connection rather than
275     /// being executed in parallel.
276     ///
277     /// When multiplex is true, enable HTTP/2 multiplexing, which means that
278     /// follow-up requests can re-use an existing connection and send the new
279     /// request multiplexed over that at the same time as other transfers are
280     /// already using that single connection.
pipelining(&mut self, http_1: bool, multiplex: bool) -> Result<(), MultiError>281     pub fn pipelining(&mut self, http_1: bool, multiplex: bool) -> Result<(), MultiError> {
282         let bitmask = if http_1 { curl_sys::CURLPIPE_HTTP1 } else { 0 }
283             | if multiplex {
284                 curl_sys::CURLPIPE_MULTIPLEX
285             } else {
286                 0
287             };
288         self.setopt_long(curl_sys::CURLMOPT_PIPELINING, bitmask)
289     }
290 
291     /// Sets the max number of connections to a single host.
292     ///
293     /// Pass a long to indicate the max number of simultaneously open connections
294     /// to a single host (a host being the same as a host name + port number pair).
295     /// For each new session to a host, libcurl will open up a new connection up to the
296     /// limit set by the provided value. When the limit is reached, the sessions will
297     /// be pending until a connection becomes available. If pipelining is enabled,
298     /// libcurl will try to pipeline if the host is capable of it.
set_max_host_connections(&mut self, val: usize) -> Result<(), MultiError>299     pub fn set_max_host_connections(&mut self, val: usize) -> Result<(), MultiError> {
300         self.setopt_long(curl_sys::CURLMOPT_MAX_HOST_CONNECTIONS, val as c_long)
301     }
302 
303     /// Sets the max simultaneously open connections.
304     ///
305     /// The set number will be used as the maximum number of simultaneously open
306     /// connections in total using this multi handle. For each new session,
307     /// libcurl will open a new connection up to the limit set by the provided
308     /// value. When the limit is reached, the sessions will be pending until
309     /// there are available connections. If pipelining is enabled, libcurl will
310     /// try to pipeline or use multiplexing if the host is capable of it.
set_max_total_connections(&mut self, val: usize) -> Result<(), MultiError>311     pub fn set_max_total_connections(&mut self, val: usize) -> Result<(), MultiError> {
312         self.setopt_long(curl_sys::CURLMOPT_MAX_TOTAL_CONNECTIONS, val as c_long)
313     }
314 
315     /// Set size of connection cache.
316     ///
317     /// The set number will be used as the maximum amount of simultaneously open
318     /// connections that libcurl may keep in its connection cache after
319     /// completed use. By default libcurl will enlarge the size for each added
320     /// easy handle to make it fit 4 times the number of added easy handles.
321     ///
322     /// By setting this option, you can prevent the cache size from growing
323     /// beyond the limit set by you.
324     ///
325     /// When the cache is full, curl closes the oldest one in the cache to
326     /// prevent the number of open connections from increasing.
327     ///
328     /// See [`set_max_total_connections`](#method.set_max_total_connections) for
329     /// limiting the number of active connections.
set_max_connects(&mut self, val: usize) -> Result<(), MultiError>330     pub fn set_max_connects(&mut self, val: usize) -> Result<(), MultiError> {
331         self.setopt_long(curl_sys::CURLMOPT_MAXCONNECTS, val as c_long)
332     }
333 
334     /// Sets the pipeline length.
335     ///
336     /// This sets the max number that will be used as the maximum amount of
337     /// outstanding requests in an HTTP/1.1 pipelined connection. This option
338     /// is only used for HTTP/1.1 pipelining, and not HTTP/2 multiplexing.
set_pipeline_length(&mut self, val: usize) -> Result<(), MultiError>339     pub fn set_pipeline_length(&mut self, val: usize) -> Result<(), MultiError> {
340         self.setopt_long(curl_sys::CURLMOPT_MAX_PIPELINE_LENGTH, val as c_long)
341     }
342 
setopt_long(&mut self, opt: curl_sys::CURLMoption, val: c_long) -> Result<(), MultiError>343     fn setopt_long(&mut self, opt: curl_sys::CURLMoption, val: c_long) -> Result<(), MultiError> {
344         unsafe { cvt(curl_sys::curl_multi_setopt(self.raw, opt, val)) }
345     }
346 
setopt_ptr( &mut self, opt: curl_sys::CURLMoption, val: *const c_char, ) -> Result<(), MultiError>347     fn setopt_ptr(
348         &mut self,
349         opt: curl_sys::CURLMoption,
350         val: *const c_char,
351     ) -> Result<(), MultiError> {
352         unsafe { cvt(curl_sys::curl_multi_setopt(self.raw, opt, val)) }
353     }
354 
355     /// Add an easy handle to a multi session
356     ///
357     /// Adds a standard easy handle to the multi stack. This function call will
358     /// make this multi handle control the specified easy handle.
359     ///
360     /// When an easy interface is added to a multi handle, it will use a shared
361     /// connection cache owned by the multi handle. Removing and adding new easy
362     /// handles will not affect the pool of connections or the ability to do
363     /// connection re-use.
364     ///
365     /// If you have `timer_function` set in the multi handle (and you really
366     /// should if you're working event-based with `action` and friends), that
367     /// callback will be called from within this function to ask for an updated
368     /// timer so that your main event loop will get the activity on this handle
369     /// to get started.
370     ///
371     /// The easy handle will remain added to the multi handle until you remove
372     /// it again with `remove` on the returned handle - even when a transfer
373     /// with that specific easy handle is completed.
add(&self, mut easy: Easy) -> Result<EasyHandle, MultiError>374     pub fn add(&self, mut easy: Easy) -> Result<EasyHandle, MultiError> {
375         // Clear any configuration set by previous transfers because we're
376         // moving this into a `Send+'static` situation now basically.
377         easy.transfer();
378 
379         unsafe {
380             cvt(curl_sys::curl_multi_add_handle(self.raw, easy.raw()))?;
381         }
382         Ok(EasyHandle {
383             easy,
384             _marker: marker::PhantomData,
385         })
386     }
387 
388     /// Same as `add`, but works with the `Easy2` type.
add2<H>(&self, easy: Easy2<H>) -> Result<Easy2Handle<H>, MultiError>389     pub fn add2<H>(&self, easy: Easy2<H>) -> Result<Easy2Handle<H>, MultiError> {
390         unsafe {
391             cvt(curl_sys::curl_multi_add_handle(self.raw, easy.raw()))?;
392         }
393         Ok(Easy2Handle {
394             easy,
395             _marker: marker::PhantomData,
396         })
397     }
398 
399     /// Remove an easy handle from this multi session
400     ///
401     /// Removes the easy handle from this multi handle. This will make the
402     /// returned easy handle be removed from this multi handle's control.
403     ///
404     /// When the easy handle has been removed from a multi stack, it is again
405     /// perfectly legal to invoke `perform` on it.
406     ///
407     /// Removing an easy handle while being used is perfectly legal and will
408     /// effectively halt the transfer in progress involving that easy handle.
409     /// All other easy handles and transfers will remain unaffected.
remove(&self, easy: EasyHandle) -> Result<Easy, MultiError>410     pub fn remove(&self, easy: EasyHandle) -> Result<Easy, MultiError> {
411         unsafe {
412             cvt(curl_sys::curl_multi_remove_handle(
413                 self.raw,
414                 easy.easy.raw(),
415             ))?;
416         }
417         Ok(easy.easy)
418     }
419 
420     /// Same as `remove`, but for `Easy2Handle`.
remove2<H>(&self, easy: Easy2Handle<H>) -> Result<Easy2<H>, MultiError>421     pub fn remove2<H>(&self, easy: Easy2Handle<H>) -> Result<Easy2<H>, MultiError> {
422         unsafe {
423             cvt(curl_sys::curl_multi_remove_handle(
424                 self.raw,
425                 easy.easy.raw(),
426             ))?;
427         }
428         Ok(easy.easy)
429     }
430 
431     /// Read multi stack informationals
432     ///
433     /// Ask the multi handle if there are any messages/informationals from the
434     /// individual transfers. Messages may include informationals such as an
435     /// error code from the transfer or just the fact that a transfer is
436     /// completed. More details on these should be written down as well.
messages<F>(&self, mut f: F) where F: FnMut(Message),437     pub fn messages<F>(&self, mut f: F)
438     where
439         F: FnMut(Message),
440     {
441         self._messages(&mut f)
442     }
443 
_messages(&self, f: &mut dyn FnMut(Message))444     fn _messages(&self, f: &mut dyn FnMut(Message)) {
445         let mut queue = 0;
446         unsafe {
447             loop {
448                 let ptr = curl_sys::curl_multi_info_read(self.raw, &mut queue);
449                 if ptr.is_null() {
450                     break;
451                 }
452                 f(Message { ptr, _multi: self })
453             }
454         }
455     }
456 
457     /// Inform of reads/writes available data given an action
458     ///
459     /// When the application has detected action on a socket handled by libcurl,
460     /// it should call this function with the sockfd argument set to
461     /// the socket with the action. When the events on a socket are known, they
462     /// can be passed `events`. When the events on a socket are unknown, pass
463     /// `Events::new()` instead, and libcurl will test the descriptor
464     /// internally.
465     ///
466     /// The returned integer will contain the number of running easy handles
467     /// within the multi handle. When this number reaches zero, all transfers
468     /// are complete/done. When you call `action` on a specific socket and the
469     /// counter decreases by one, it DOES NOT necessarily mean that this exact
470     /// socket/transfer is the one that completed. Use `messages` to figure out
471     /// which easy handle that completed.
472     ///
473     /// The `action` function informs the application about updates in the
474     /// socket (file descriptor) status by doing none, one, or multiple calls to
475     /// the socket callback function set with the `socket_function` method. They
476     /// update the status with changes since the previous time the callback was
477     /// called.
action(&self, socket: Socket, events: &Events) -> Result<u32, MultiError>478     pub fn action(&self, socket: Socket, events: &Events) -> Result<u32, MultiError> {
479         let mut remaining = 0;
480         unsafe {
481             cvt(curl_sys::curl_multi_socket_action(
482                 self.raw,
483                 socket,
484                 events.bits,
485                 &mut remaining,
486             ))?;
487             Ok(remaining as u32)
488         }
489     }
490 
491     /// Inform libcurl that a timeout has expired and sockets should be tested.
492     ///
493     /// The returned integer will contain the number of running easy handles
494     /// within the multi handle. When this number reaches zero, all transfers
495     /// are complete/done. When you call `action` on a specific socket and the
496     /// counter decreases by one, it DOES NOT necessarily mean that this exact
497     /// socket/transfer is the one that completed. Use `messages` to figure out
498     /// which easy handle that completed.
499     ///
500     /// Get the timeout time by calling the `timer_function` method. Your
501     /// application will then get called with information on how long to wait
502     /// for socket actions at most before doing the timeout action: call the
503     /// `timeout` method. You can also use the `get_timeout` function to
504     /// poll the value at any given time, but for an event-based system using
505     /// the callback is far better than relying on polling the timeout value.
timeout(&self) -> Result<u32, MultiError>506     pub fn timeout(&self) -> Result<u32, MultiError> {
507         let mut remaining = 0;
508         unsafe {
509             cvt(curl_sys::curl_multi_socket_action(
510                 self.raw,
511                 curl_sys::CURL_SOCKET_BAD,
512                 0,
513                 &mut remaining,
514             ))?;
515             Ok(remaining as u32)
516         }
517     }
518 
519     /// Get how long to wait for action before proceeding
520     ///
521     /// An application using the libcurl multi interface should call
522     /// `get_timeout` to figure out how long it should wait for socket actions -
523     /// at most - before proceeding.
524     ///
525     /// Proceeding means either doing the socket-style timeout action: call the
526     /// `timeout` function, or call `perform` if you're using the simpler and
527     /// older multi interface approach.
528     ///
529     /// The timeout value returned is the duration at this very moment. If 0, it
530     /// means you should proceed immediately without waiting for anything. If it
531     /// returns `None`, there's no timeout at all set.
532     ///
533     /// Note: if libcurl returns a `None` timeout here, it just means that
534     /// libcurl currently has no stored timeout value. You must not wait too
535     /// long (more than a few seconds perhaps) before you call `perform` again.
get_timeout(&self) -> Result<Option<Duration>, MultiError>536     pub fn get_timeout(&self) -> Result<Option<Duration>, MultiError> {
537         let mut ms = 0;
538         unsafe {
539             cvt(curl_sys::curl_multi_timeout(self.raw, &mut ms))?;
540             if ms == -1 {
541                 Ok(None)
542             } else {
543                 Ok(Some(Duration::from_millis(ms as u64)))
544             }
545         }
546     }
547 
548     /// Block until activity is detected or a timeout passes.
549     ///
550     /// The timeout is used in millisecond-precision. Large durations are
551     /// clamped at the maximum value curl accepts.
552     ///
553     /// The returned integer will contain the number of internal file
554     /// descriptors on which interesting events occured.
555     ///
556     /// This function is a simpler alternative to using `fdset()` and `select()`
557     /// and does not suffer from file descriptor limits.
558     ///
559     /// # Example
560     ///
561     /// ```
562     /// use curl::multi::Multi;
563     /// use std::time::Duration;
564     ///
565     /// let m = Multi::new();
566     ///
567     /// // Add some Easy handles...
568     ///
569     /// while m.perform().unwrap() > 0 {
570     ///     m.wait(&mut [], Duration::from_secs(1)).unwrap();
571     /// }
572     /// ```
wait(&self, waitfds: &mut [WaitFd], timeout: Duration) -> Result<u32, MultiError>573     pub fn wait(&self, waitfds: &mut [WaitFd], timeout: Duration) -> Result<u32, MultiError> {
574         let timeout_ms = {
575             let secs = timeout.as_secs();
576             if secs > (i32::max_value() / 1000) as u64 {
577                 // Duration too large, clamp at maximum value.
578                 i32::max_value()
579             } else {
580                 secs as i32 * 1000 + timeout.subsec_nanos() as i32 / 1_000_000
581             }
582         };
583         unsafe {
584             let mut ret = 0;
585             cvt(curl_sys::curl_multi_wait(
586                 self.raw,
587                 waitfds.as_mut_ptr() as *mut _,
588                 waitfds.len() as u32,
589                 timeout_ms,
590                 &mut ret,
591             ))?;
592             Ok(ret as u32)
593         }
594     }
595 
596     /// Reads/writes available data from each easy handle.
597     ///
598     /// This function handles transfers on all the added handles that need
599     /// attention in an non-blocking fashion.
600     ///
601     /// When an application has found out there's data available for this handle
602     /// or a timeout has elapsed, the application should call this function to
603     /// read/write whatever there is to read or write right now etc.  This
604     /// method returns as soon as the reads/writes are done. This function does
605     /// not require that there actually is any data available for reading or
606     /// that data can be written, it can be called just in case. It will return
607     /// the number of handles that still transfer data.
608     ///
609     /// If the amount of running handles is changed from the previous call (or
610     /// is less than the amount of easy handles you've added to the multi
611     /// handle), you know that there is one or more transfers less "running".
612     /// You can then call `info` to get information about each individual
613     /// completed transfer, and that returned info includes `Error` and more.
614     /// If an added handle fails very quickly, it may never be counted as a
615     /// running handle.
616     ///
617     /// When running_handles is set to zero (0) on the return of this function,
618     /// there is no longer any transfers in progress.
619     ///
620     /// # Return
621     ///
622     /// Before libcurl version 7.20.0: If you receive `is_call_perform`, this
623     /// basically means that you should call `perform` again, before you select
624     /// on more actions. You don't have to do it immediately, but the return
625     /// code means that libcurl may have more data available to return or that
626     /// there may be more data to send off before it is "satisfied". Do note
627     /// that `perform` will return `is_call_perform` only when it wants to be
628     /// called again immediately. When things are fine and there is nothing
629     /// immediate it wants done, it'll return `Ok` and you need to wait for
630     /// "action" and then call this function again.
631     ///
632     /// This function only returns errors etc regarding the whole multi stack.
633     /// Problems still might have occurred on individual transfers even when
634     /// this function returns `Ok`. Use `info` to figure out how individual
635     /// transfers did.
perform(&self) -> Result<u32, MultiError>636     pub fn perform(&self) -> Result<u32, MultiError> {
637         unsafe {
638             let mut ret = 0;
639             cvt(curl_sys::curl_multi_perform(self.raw, &mut ret))?;
640             Ok(ret as u32)
641         }
642     }
643 
644     /// Extracts file descriptor information from a multi handle
645     ///
646     /// This function extracts file descriptor information from a given
647     /// handle, and libcurl returns its `fd_set` sets. The application can use
648     /// these to `select()` on, but be sure to `FD_ZERO` them before calling
649     /// this function as curl_multi_fdset only adds its own descriptors, it
650     /// doesn't zero or otherwise remove any others. The curl_multi_perform
651     /// function should be called as soon as one of them is ready to be read
652     /// from or written to.
653     ///
654     /// If no file descriptors are set by libcurl, this function will return
655     /// `Ok(None)`. Otherwise `Ok(Some(n))` will be returned where `n` the
656     /// highest descriptor number libcurl set. When `Ok(None)` is returned it
657     /// is because libcurl currently does something that isn't possible for
658     /// your application to monitor with a socket and unfortunately you can
659     /// then not know exactly when the current action is completed using
660     /// `select()`. You then need to wait a while before you proceed and call
661     /// `perform` anyway.
662     ///
663     /// When doing `select()`, you should use `get_timeout` to figure out
664     /// how long to wait for action. Call `perform` even if no activity has
665     /// been seen on the `fd_set`s after the timeout expires as otherwise
666     /// internal retries and timeouts may not work as you'd think and want.
667     ///
668     /// If one of the sockets used by libcurl happens to be larger than what
669     /// can be set in an `fd_set`, which on POSIX systems means that the file
670     /// descriptor is larger than `FD_SETSIZE`, then libcurl will try to not
671     /// set it. Setting a too large file descriptor in an `fd_set` implies an out
672     /// of bounds write which can cause crashes, or worse. The effect of NOT
673     /// storing it will possibly save you from the crash, but will make your
674     /// program NOT wait for sockets it should wait for...
fdset2( &self, read: Option<&mut curl_sys::fd_set>, write: Option<&mut curl_sys::fd_set>, except: Option<&mut curl_sys::fd_set>, ) -> Result<Option<i32>, MultiError>675     pub fn fdset2(
676         &self,
677         read: Option<&mut curl_sys::fd_set>,
678         write: Option<&mut curl_sys::fd_set>,
679         except: Option<&mut curl_sys::fd_set>,
680     ) -> Result<Option<i32>, MultiError> {
681         unsafe {
682             let mut ret = 0;
683             let read = read.map(|r| r as *mut _).unwrap_or(ptr::null_mut());
684             let write = write.map(|r| r as *mut _).unwrap_or(ptr::null_mut());
685             let except = except.map(|r| r as *mut _).unwrap_or(ptr::null_mut());
686             cvt(curl_sys::curl_multi_fdset(
687                 self.raw, read, write, except, &mut ret,
688             ))?;
689             if ret == -1 {
690                 Ok(None)
691             } else {
692                 Ok(Some(ret))
693             }
694         }
695     }
696 
697     /// Does nothing and returns `Ok(())`. This method remains for backwards
698     /// compatibility.
699     ///
700     /// This method will be changed to take `self` in a future release.
701     #[doc(hidden)]
702     #[deprecated(
703         since = "0.4.30",
704         note = "cannot close safely without consuming self; \
705                 will be changed or removed in a future release"
706     )]
close(&self) -> Result<(), MultiError>707     pub fn close(&self) -> Result<(), MultiError> {
708         Ok(())
709     }
710 
711     /// Get a pointer to the raw underlying CURLM handle.
raw(&self) -> *mut curl_sys::CURLM712     pub fn raw(&self) -> *mut curl_sys::CURLM {
713         self.raw
714     }
715 
close_impl(&self) -> Result<(), MultiError>716     unsafe fn close_impl(&self) -> Result<(), MultiError> {
717         cvt(curl_sys::curl_multi_cleanup(self.raw))
718     }
719 }
720 
cvt(code: curl_sys::CURLMcode) -> Result<(), MultiError>721 fn cvt(code: curl_sys::CURLMcode) -> Result<(), MultiError> {
722     if code == curl_sys::CURLM_OK {
723         Ok(())
724     } else {
725         Err(MultiError::new(code))
726     }
727 }
728 
729 impl fmt::Debug for Multi {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result730     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
731         f.debug_struct("Multi").field("raw", &self.raw).finish()
732     }
733 }
734 
735 impl Drop for Multi {
drop(&mut self)736     fn drop(&mut self) {
737         let _ = unsafe { self.close_impl() };
738     }
739 }
740 
741 macro_rules! impl_easy_getters {
742     () => {
743         impl_easy_getters! {
744             time_condition_unmet -> bool,
745             effective_url -> Option<&str>,
746             effective_url_bytes -> Option<&[u8]>,
747             response_code -> u32,
748             http_connectcode -> u32,
749             filetime -> Option<i64>,
750             download_size -> f64,
751             content_length_download -> f64,
752             total_time -> Duration,
753             namelookup_time -> Duration,
754             connect_time -> Duration,
755             appconnect_time -> Duration,
756             pretransfer_time -> Duration,
757             starttransfer_time -> Duration,
758             redirect_time -> Duration,
759             redirect_count -> u32,
760             redirect_url -> Option<&str>,
761             redirect_url_bytes -> Option<&[u8]>,
762             header_size -> u64,
763             request_size -> u64,
764             content_type -> Option<&str>,
765             content_type_bytes -> Option<&[u8]>,
766             os_errno -> i32,
767             primary_ip -> Option<&str>,
768             primary_port -> u16,
769             local_ip -> Option<&str>,
770             local_port -> u16,
771             cookies -> List,
772         }
773     };
774 
775     ($($name:ident -> $ret:ty,)*) => {
776         $(
777             impl_easy_getters!($name, $ret, concat!(
778                 "Same as [`Easy2::",
779                 stringify!($name),
780                 "`](../easy/struct.Easy2.html#method.",
781                 stringify!($name),
782                 ")."
783             ));
784         )*
785     };
786 
787     ($name:ident, $ret:ty, $doc:expr) => {
788         #[doc = $doc]
789         pub fn $name(&mut self) -> Result<$ret, Error> {
790             self.easy.$name()
791         }
792     };
793 }
794 
795 impl EasyHandle {
796     /// Sets an internal private token for this `EasyHandle`.
797     ///
798     /// This function will set the `CURLOPT_PRIVATE` field on the underlying
799     /// easy handle.
set_token(&mut self, token: usize) -> Result<(), Error>800     pub fn set_token(&mut self, token: usize) -> Result<(), Error> {
801         unsafe {
802             ::cvt(curl_sys::curl_easy_setopt(
803                 self.easy.raw(),
804                 curl_sys::CURLOPT_PRIVATE,
805                 token,
806             ))
807         }
808     }
809 
810     impl_easy_getters!();
811 
812     /// Unpause reading on a connection.
813     ///
814     /// Using this function, you can explicitly unpause a connection that was
815     /// previously paused.
816     ///
817     /// A connection can be paused by letting the read or the write callbacks
818     /// return `ReadError::Pause` or `WriteError::Pause`.
819     ///
820     /// The chance is high that you will get your write callback called before
821     /// this function returns.
unpause_read(&self) -> Result<(), Error>822     pub fn unpause_read(&self) -> Result<(), Error> {
823         self.easy.unpause_read()
824     }
825 
826     /// Unpause writing on a connection.
827     ///
828     /// Using this function, you can explicitly unpause a connection that was
829     /// previously paused.
830     ///
831     /// A connection can be paused by letting the read or the write callbacks
832     /// return `ReadError::Pause` or `WriteError::Pause`. A write callback that
833     /// returns pause signals to the library that it couldn't take care of any
834     /// data at all, and that data will then be delivered again to the callback
835     /// when the writing is later unpaused.
unpause_write(&self) -> Result<(), Error>836     pub fn unpause_write(&self) -> Result<(), Error> {
837         self.easy.unpause_write()
838     }
839 
840     /// Get a pointer to the raw underlying CURL handle.
raw(&self) -> *mut curl_sys::CURL841     pub fn raw(&self) -> *mut curl_sys::CURL {
842         self.easy.raw()
843     }
844 }
845 
846 impl fmt::Debug for EasyHandle {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result847     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
848         self.easy.fmt(f)
849     }
850 }
851 
852 impl<H> Easy2Handle<H> {
853     /// Acquires a reference to the underlying handler for events.
get_ref(&self) -> &H854     pub fn get_ref(&self) -> &H {
855         self.easy.get_ref()
856     }
857 
858     /// Acquires a reference to the underlying handler for events.
get_mut(&mut self) -> &mut H859     pub fn get_mut(&mut self) -> &mut H {
860         self.easy.get_mut()
861     }
862 
863     /// Same as `EasyHandle::set_token`
set_token(&mut self, token: usize) -> Result<(), Error>864     pub fn set_token(&mut self, token: usize) -> Result<(), Error> {
865         unsafe {
866             ::cvt(curl_sys::curl_easy_setopt(
867                 self.easy.raw(),
868                 curl_sys::CURLOPT_PRIVATE,
869                 token,
870             ))
871         }
872     }
873 
874     impl_easy_getters!();
875 
876     /// Unpause reading on a connection.
877     ///
878     /// Using this function, you can explicitly unpause a connection that was
879     /// previously paused.
880     ///
881     /// A connection can be paused by letting the read or the write callbacks
882     /// return `ReadError::Pause` or `WriteError::Pause`.
883     ///
884     /// The chance is high that you will get your write callback called before
885     /// this function returns.
unpause_read(&self) -> Result<(), Error>886     pub fn unpause_read(&self) -> Result<(), Error> {
887         self.easy.unpause_read()
888     }
889 
890     /// Unpause writing on a connection.
891     ///
892     /// Using this function, you can explicitly unpause a connection that was
893     /// previously paused.
894     ///
895     /// A connection can be paused by letting the read or the write callbacks
896     /// return `ReadError::Pause` or `WriteError::Pause`. A write callback that
897     /// returns pause signals to the library that it couldn't take care of any
898     /// data at all, and that data will then be delivered again to the callback
899     /// when the writing is later unpaused.
unpause_write(&self) -> Result<(), Error>900     pub fn unpause_write(&self) -> Result<(), Error> {
901         self.easy.unpause_write()
902     }
903 
904     /// Get a pointer to the raw underlying CURL handle.
raw(&self) -> *mut curl_sys::CURL905     pub fn raw(&self) -> *mut curl_sys::CURL {
906         self.easy.raw()
907     }
908 }
909 
910 impl<H: fmt::Debug> fmt::Debug for Easy2Handle<H> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result911     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
912         self.easy.fmt(f)
913     }
914 }
915 
916 impl<'multi> Message<'multi> {
917     /// If this message indicates that a transfer has finished, returns the
918     /// result of the transfer in `Some`.
919     ///
920     /// If the message doesn't indicate that a transfer has finished, then
921     /// `None` is returned.
922     ///
923     /// Note that the `result*_for` methods below should be preferred as they
924     /// provide better error messages as the associated error data on the
925     /// handle can be associated with the error type.
result(&self) -> Option<Result<(), Error>>926     pub fn result(&self) -> Option<Result<(), Error>> {
927         unsafe {
928             if (*self.ptr).msg == curl_sys::CURLMSG_DONE {
929                 Some(::cvt((*self.ptr).data as curl_sys::CURLcode))
930             } else {
931                 None
932             }
933         }
934     }
935 
936     /// Same as `result`, except only returns `Some` for the specified handle.
937     ///
938     /// Note that this function produces better error messages than `result` as
939     /// it uses `take_error_buf` to associate error information with the
940     /// returned error.
result_for(&self, handle: &EasyHandle) -> Option<Result<(), Error>>941     pub fn result_for(&self, handle: &EasyHandle) -> Option<Result<(), Error>> {
942         if !self.is_for(handle) {
943             return None;
944         }
945         let mut err = self.result();
946         if let Some(Err(e)) = &mut err {
947             if let Some(s) = handle.easy.take_error_buf() {
948                 e.set_extra(s);
949             }
950         }
951         err
952     }
953 
954     /// Same as `result`, except only returns `Some` for the specified handle.
955     ///
956     /// Note that this function produces better error messages than `result` as
957     /// it uses `take_error_buf` to associate error information with the
958     /// returned error.
result_for2<H>(&self, handle: &Easy2Handle<H>) -> Option<Result<(), Error>>959     pub fn result_for2<H>(&self, handle: &Easy2Handle<H>) -> Option<Result<(), Error>> {
960         if !self.is_for2(handle) {
961             return None;
962         }
963         let mut err = self.result();
964         if let Some(Err(e)) = &mut err {
965             if let Some(s) = handle.easy.take_error_buf() {
966                 e.set_extra(s);
967             }
968         }
969         err
970     }
971 
972     /// Returns whether this easy message was for the specified easy handle or
973     /// not.
is_for(&self, handle: &EasyHandle) -> bool974     pub fn is_for(&self, handle: &EasyHandle) -> bool {
975         unsafe { (*self.ptr).easy_handle == handle.easy.raw() }
976     }
977 
978     /// Same as `is_for`, but for `Easy2Handle`.
is_for2<H>(&self, handle: &Easy2Handle<H>) -> bool979     pub fn is_for2<H>(&self, handle: &Easy2Handle<H>) -> bool {
980         unsafe { (*self.ptr).easy_handle == handle.easy.raw() }
981     }
982 
983     /// Returns the token associated with the easy handle that this message
984     /// represents a completion for.
985     ///
986     /// This function will return the token assigned with
987     /// `EasyHandle::set_token`. This reads the `CURLINFO_PRIVATE` field of the
988     /// underlying `*mut CURL`.
token(&self) -> Result<usize, Error>989     pub fn token(&self) -> Result<usize, Error> {
990         unsafe {
991             let mut p = 0usize;
992             ::cvt(curl_sys::curl_easy_getinfo(
993                 (*self.ptr).easy_handle,
994                 curl_sys::CURLINFO_PRIVATE,
995                 &mut p,
996             ))?;
997             Ok(p)
998         }
999     }
1000 }
1001 
1002 impl<'a> fmt::Debug for Message<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1003     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1004         f.debug_struct("Message").field("ptr", &self.ptr).finish()
1005     }
1006 }
1007 
1008 impl Events {
1009     /// Creates a new blank event bit mask.
new() -> Events1010     pub fn new() -> Events {
1011         Events { bits: 0 }
1012     }
1013 
1014     /// Set or unset the whether these events indicate that input is ready.
input(&mut self, val: bool) -> &mut Events1015     pub fn input(&mut self, val: bool) -> &mut Events {
1016         self.flag(curl_sys::CURL_CSELECT_IN, val)
1017     }
1018 
1019     /// Set or unset the whether these events indicate that output is ready.
output(&mut self, val: bool) -> &mut Events1020     pub fn output(&mut self, val: bool) -> &mut Events {
1021         self.flag(curl_sys::CURL_CSELECT_OUT, val)
1022     }
1023 
1024     /// Set or unset the whether these events indicate that an error has
1025     /// happened.
error(&mut self, val: bool) -> &mut Events1026     pub fn error(&mut self, val: bool) -> &mut Events {
1027         self.flag(curl_sys::CURL_CSELECT_ERR, val)
1028     }
1029 
flag(&mut self, flag: c_int, val: bool) -> &mut Events1030     fn flag(&mut self, flag: c_int, val: bool) -> &mut Events {
1031         if val {
1032             self.bits |= flag;
1033         } else {
1034             self.bits &= !flag;
1035         }
1036         self
1037     }
1038 }
1039 
1040 impl fmt::Debug for Events {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1041     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1042         f.debug_struct("Events")
1043             .field("input", &(self.bits & curl_sys::CURL_CSELECT_IN != 0))
1044             .field("output", &(self.bits & curl_sys::CURL_CSELECT_OUT != 0))
1045             .field("error", &(self.bits & curl_sys::CURL_CSELECT_ERR != 0))
1046             .finish()
1047     }
1048 }
1049 
1050 impl SocketEvents {
1051     /// Wait for incoming data. For the socket to become readable.
input(&self) -> bool1052     pub fn input(&self) -> bool {
1053         self.bits & curl_sys::CURL_POLL_IN == curl_sys::CURL_POLL_IN
1054     }
1055 
1056     /// Wait for outgoing data. For the socket to become writable.
output(&self) -> bool1057     pub fn output(&self) -> bool {
1058         self.bits & curl_sys::CURL_POLL_OUT == curl_sys::CURL_POLL_OUT
1059     }
1060 
1061     /// Wait for incoming and outgoing data. For the socket to become readable
1062     /// or writable.
input_and_output(&self) -> bool1063     pub fn input_and_output(&self) -> bool {
1064         self.bits & curl_sys::CURL_POLL_INOUT == curl_sys::CURL_POLL_INOUT
1065     }
1066 
1067     /// The specified socket/file descriptor is no longer used by libcurl.
remove(&self) -> bool1068     pub fn remove(&self) -> bool {
1069         self.bits & curl_sys::CURL_POLL_REMOVE == curl_sys::CURL_POLL_REMOVE
1070     }
1071 }
1072 
1073 impl fmt::Debug for SocketEvents {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1074     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1075         f.debug_struct("Events")
1076             .field("input", &self.input())
1077             .field("output", &self.output())
1078             .field("remove", &self.remove())
1079             .finish()
1080     }
1081 }
1082 
1083 impl WaitFd {
1084     /// Constructs an empty (invalid) WaitFd.
new() -> WaitFd1085     pub fn new() -> WaitFd {
1086         WaitFd {
1087             inner: curl_sys::curl_waitfd {
1088                 fd: 0,
1089                 events: 0,
1090                 revents: 0,
1091             },
1092         }
1093     }
1094 
1095     /// Set the file descriptor to wait for.
set_fd(&mut self, fd: Socket)1096     pub fn set_fd(&mut self, fd: Socket) {
1097         self.inner.fd = fd;
1098     }
1099 
1100     /// Indicate that the socket should poll on read events such as new data
1101     /// received.
1102     ///
1103     /// Corresponds to `CURL_WAIT_POLLIN`.
poll_on_read(&mut self, val: bool) -> &mut WaitFd1104     pub fn poll_on_read(&mut self, val: bool) -> &mut WaitFd {
1105         self.flag(curl_sys::CURL_WAIT_POLLIN, val)
1106     }
1107 
1108     /// Indicate that the socket should poll on high priority read events such
1109     /// as out of band data.
1110     ///
1111     /// Corresponds to `CURL_WAIT_POLLPRI`.
poll_on_priority_read(&mut self, val: bool) -> &mut WaitFd1112     pub fn poll_on_priority_read(&mut self, val: bool) -> &mut WaitFd {
1113         self.flag(curl_sys::CURL_WAIT_POLLPRI, val)
1114     }
1115 
1116     /// Indicate that the socket should poll on write events such as the socket
1117     /// being clear to write without blocking.
1118     ///
1119     /// Corresponds to `CURL_WAIT_POLLOUT`.
poll_on_write(&mut self, val: bool) -> &mut WaitFd1120     pub fn poll_on_write(&mut self, val: bool) -> &mut WaitFd {
1121         self.flag(curl_sys::CURL_WAIT_POLLOUT, val)
1122     }
1123 
flag(&mut self, flag: c_short, val: bool) -> &mut WaitFd1124     fn flag(&mut self, flag: c_short, val: bool) -> &mut WaitFd {
1125         if val {
1126             self.inner.events |= flag;
1127         } else {
1128             self.inner.events &= !flag;
1129         }
1130         self
1131     }
1132 
1133     /// After a call to `wait`, returns `true` if `poll_on_read` was set and a
1134     /// read event occured.
received_read(&self) -> bool1135     pub fn received_read(&self) -> bool {
1136         self.inner.revents & curl_sys::CURL_WAIT_POLLIN == curl_sys::CURL_WAIT_POLLIN
1137     }
1138 
1139     /// After a call to `wait`, returns `true` if `poll_on_priority_read` was set and a
1140     /// priority read event occured.
received_priority_read(&self) -> bool1141     pub fn received_priority_read(&self) -> bool {
1142         self.inner.revents & curl_sys::CURL_WAIT_POLLPRI == curl_sys::CURL_WAIT_POLLPRI
1143     }
1144 
1145     /// After a call to `wait`, returns `true` if `poll_on_write` was set and a
1146     /// write event occured.
received_write(&self) -> bool1147     pub fn received_write(&self) -> bool {
1148         self.inner.revents & curl_sys::CURL_WAIT_POLLOUT == curl_sys::CURL_WAIT_POLLOUT
1149     }
1150 }
1151 
1152 #[cfg(unix)]
1153 impl From<pollfd> for WaitFd {
from(pfd: pollfd) -> WaitFd1154     fn from(pfd: pollfd) -> WaitFd {
1155         let mut events = 0;
1156         if pfd.events & POLLIN == POLLIN {
1157             events |= curl_sys::CURL_WAIT_POLLIN;
1158         }
1159         if pfd.events & POLLPRI == POLLPRI {
1160             events |= curl_sys::CURL_WAIT_POLLPRI;
1161         }
1162         if pfd.events & POLLOUT == POLLOUT {
1163             events |= curl_sys::CURL_WAIT_POLLOUT;
1164         }
1165         WaitFd {
1166             inner: curl_sys::curl_waitfd {
1167                 fd: pfd.fd,
1168                 events,
1169                 revents: 0,
1170             },
1171         }
1172     }
1173 }
1174 
1175 impl fmt::Debug for WaitFd {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1176     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1177         f.debug_struct("WaitFd")
1178             .field("fd", &self.inner.fd)
1179             .field("events", &self.inner.fd)
1180             .field("revents", &self.inner.fd)
1181             .finish()
1182     }
1183 }
1184