The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.


Net::Curl::Multi - Perl interface for curl_multi_* functions


 use Net::Curl::Multi qw(:constants);

 my $multi = Net::Curl::Multi->new();
 $multi->add_handle( $easy );

 my $running = 0;
 do {
     my ($r, $w, $e) = $multi->fdset();
     my $timeout = $multi->timeout();
     select $r, $w, $e, $timeout / 1000
         if $timeout > 0;

     $running = $multi->perform();
     while ( my ( $msg, $easy, $result ) = $multi->info_read() ) {
         $multi->remove_handle( $easy );

         # process $easy
 } while ( $running );


This module wraps multi handle from libcurl and all related functions and constants. It does not export by default anything, but constants can be exported upon request.

 use Net::Curl::Multi qw(:constants);


new( [BASE] )

Creates new Net::Curl::Multi object. If BASE is specified it will be used as object base, otherwise an empty hash will be used. BASE must be a valid reference which has not been blessed already. It will not be used by the object.

 my $multi = Net::Curl::Multi->new( [qw(my very private data)] );

Calls curl_multi_init(3) and presets some defaults.


add_handle( EASY )

Add Net::Curl::Easy to this Net::Curl::Multi object.

 $multi->add_handle( $easy );

Calls curl_multi_add_handle(3). Throws "Net::Curl::Multi::Code" on error.

remove_handle( EASY )

Remove Net::Curl::Easy from this Net::Curl::Multi object.

 $multi->remove_handle( $easy );

Calls curl_multi_remove_handle(3). Rethrows exceptions from callbacks. Throws "Net::Curl::Multi::Code" on error.

info_read( )

Read last message from this Multi.

 my ( $msg, $easy, $result ) = $multi->info_read();

$msg contains one of CURLMSG_* values, currently only CURLMSG_DONE is returned. $easy is the Net::Curl::Easy object. Result is a Net::Curl::Easy::Code dualvar object.

Calls curl_multi_info_read(3).

fdset( )

Returns read, write and exception vectors suitable for select() and vec() perl builtins.

 my ( $rvec, $wvec, $evec ) = $multi->fdset();

Calls curl_multi_fdset(3). Throws "Net::Curl::Multi::Code" on error.

timeout( )

Returns timeout value in miliseconds.

 my $timeout_ms = $multi->timeout();

Calls curl_multi_timeout(3). Throws "Net::Curl::Multi::Code" on error.

setopt( OPTION, VALUE )

Set an option. OPTION is a numeric value, use one of CURLMOPT_* constants. VALUE depends on whatever that option expects.

 $multi->setopt( CURLMOPT_MAXCONNECTS, 10 );

Calls curl_multi_setopt(3). Throws "Net::Curl::Multi::Code" on error.

perform( )

Perform. Call it if there is some activity on any fd used by multi interface or timeout has just reached zero.

 my $active = $multi->perform();

Calls curl_multi_perform(3). Rethrows exceptions from callbacks. Throws "Net::Curl::Multi::Code" on error.


This method polls on all file descriptors used by the curl easy handles contained in the given multi handle set. It will block until activity is detected on at least one of the handles or TIMEOUT_MS has passed.

 my $active = $multi->wait(1000);

It will also poll on all filehandles requested. Each event descriptor is a hash and requires keys: fd - file number of the handle and events - a bitmask of the events to wait for. On detected event it will return the data in revents key.

 my $ev_read_stdin = {
   fd => fileno STDIN,
   events => CURL_WAIT_POLLIN,

 my $active = $multi->wait( [ $ev_read_stdin ], 1000 );
 if ( $active and $ev_read_stdin->{revents} == CURL_WAIT_POLLIN )
   # STDIN is ready to read

Calls curl_multi_wait(3) (available since libcurl/7.28.0). Rethrows exceptions from callbacks. Throws "Net::Curl::Multi::Code" on error.

socket_action( [SOCKET], [BITMASK] )

Signalize action on a socket.

 my $active = $multi->socket_action();

 # there is data to read on socket:
 my $active = $multi->socket_action( $socket, CURL_CSELECT_IN );

Calls curl_multi_socket_action(3). Rethrows exceptions from callbacks. Throws "Net::Curl::Multi::Code" on error.

assign( SOCKET, [VALUE] )

Assigns some value to a socket file descriptor. Removes it if value is not specified. The value is used only in socket callback.

 my $socket = some_socket_open(...);

 # store socket object for socket callback
 $multi->assign( $socket->fileno(), $socket );

Calls curl_multi_assign(3). Throws "Net::Curl::Multi::Code" on error.

handles( )

In list context returns easy handles attached to this multi. In scalar context returns number of easy handles attached.

There is no libcurl equivalent.


None of those functions are exported, you must use fully qualified names.

strerror( [WHATEVER], CODE )

Return a string for error code CODE.

 my $message = $multi->strerror( CURLM_BAD_EASY_HANDLE );

See curl_multi_strerror(3) for more info.



If any method fails, it will return one of those values.


Message type from info_read().


Option values for setopt().


Poll action information for socket callback.


Select bits for socket_action() method.


Special socket value for socket_action() method.



Socket callback will be called only if socket_action() method is being used. It receives 6 arguments: multi handle, easy handle, socket file number, poll action, socket data (see assign), and CURLMOPT_SOCKETDATA value. It must return 0. For more information refer to curl_multi_socket_action(3).

 sub cb_socket {
     my ( $multi, $easy, $socketfn, $action, $socketdata, $uservar ) = @_;
     # ... register or deregister socket actions ...
     return 0;

Timer callback receives 3 arguments: multi object, timeout in ms, and CURLMOPT_TIMERDATA value. Should return 0.

 sub cb_timer {
     my ( $multi, $timeout_ms, $uservar ) = @_;
     # ... update timeout ...
     return 0;


Most Net::Curl::Multi methods on failure throw a Net::Curl::Multi::Code error object. It has both numeric value and, when used as string, it calls strerror() function to display a nice message.

 eval {
 if ( ref $@ eq "Net::Curl::Easy::Code" ) {
     if ( $@ == CURLM_SOME_ERROR_WE_EXPECTED ) {
         warn "Expected multi error, continuing\n";
     } else {
         die "Unexpected curl multi error: $@\n";
 } else {
     # rethrow everyting else
     die $@;


Net::Curl Net::Curl::Easy Net::Curl::examples libcurl-multi(3) libcurl-errors(3)


Copyright (c) 2011-2015 Przemyslaw Iskra <sparky at>.

You may opt to use, copy, modify, merge, publish, distribute and/or sell copies of the Software, and permit persons to whom the Software is furnished to do so, under the terms of the MPL or the MIT/X-derivate licenses. You may pick one of these licenses.