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