cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: Getting Segmentation Fault from curl_multi_perform() whenI add data

From: <heath.schaefer_at_parker.com>
Date: Thu, 17 Dec 2015 08:44:46 -0600

> ------------------------------
>
> Message: 3
> Date: Thu, 17 Dec 2015 00:01:30 +0100
> From: Dan Fandrich <dan_at_coneharvesters.com>
> To: curl-library_at_cool.haxx.se
> Subject: Re: Getting Segmentation Fault from curl_multi_perform() when
> I add data
> Message-ID: <20151216230130.GC2770_at_coneharvesters.com>
> Content-Type: text/plain; charset=iso-8859-1
>
> On Wed, Dec 16, 2015 at 02:04:59PM -0600, heath.schaefer_at_parker.com
wrote:
> > I am getting a segmentation fault from curl_multi_perform() when Itry
to add
> > data.
> >
> > My do {} while loop looks like the one on
http://curl.haxx.se/libcurl/c/
> > multi-post.html. While my program is waiting for data the
> curl_multi_perform()
> > is running and returning normally, as far as I can tell. When data
becomes
> > available I set it in the easy handle using curl_easy_setopt() with
the
> > CURLOPT_POSTFIELDS and CURLOPT_POSTFIELDSIZE enumerations. I then add
that
> > easy handle to my multi handle with curl_multi_add_handle().
>
> Are you changing and adding the first handle or a second handle? You
can't
> change a handle in mid-transfer.
 
I am adding the first handle. I have a multi and 3 easy handles created.
My plan was that I only add the easy handles to the multi handle when I
have data available for that easy handle. Once the transmission is
complete for that easy handle I'd remove it from the multi handle and wait
for more data before I add it again.

> > From what I can tell with my COUTs, it called the
> curl_multi_perform() two more
> > times and then seg faults on the third call. What could be happening?
>
> Run it under a debugger to see the exact line number of the code that's
> segfaulting. If you still can't figure it out, please post code that
> demonstrates the problem.
>
It appears that the offending line of code is the curl_multi_perform(). I
had a COUT in front and right after the call.
 

Here is a snippet of the code. It fails after the easy handle is added to
the multi-handle. Before the easy handle is added the multi-handle is
"empty". I am using libcurl.so version 5.3.0. I was using a callback
function but I took all that out trying to figure out what's happening. I
was using curl_easy_perform() to handle all 3 connections but I thought
this would be a better interface but I can't get it to work! It was
working just fine with the easy interface. I'd really like to use the
multi interface because I'd like to add more handles.

This is a worker function in a thread. My application is multi-threaded
but only this thread is using the libcurl library.

(Note: You can see some of the code where I only initialize 1 handle
instead of 3. This was just a test.)

void Class1::Worker_Function()
{
        bool Curl_initialized = false;
        CURLcode result = CURLE_OK;
        char CURL_ERROR_MESSAGES[CURL_ERROR_SIZE];
        long ResponseCode;
        struct Struct_Type Struct1;
        struct Struct_Type Struct2;
        struct Struct_Type Struct3;
        CURL *handles[3];
        CURLM *multi_handle;
        int32_t still_running;
        CURLMsg *msg;
        int32_t msgs_left;
        int32_t numfds;
 
        CURLMcode tmp;

        struct curl_slist *list = NULL;
 
        // Set the headers for this message
        list = curl_slist_append(list, "Content-Type: application/json");
        list = curl_slist_append(list, "Accept: application/json");
 
        //for (CURL *CHandle : handles)
        for (int i=0; i < 1; i++)
        {
                handles[i] = curl_easy_init();
                // Set the data that we want to send
                curl_easy_setopt(handles[i], CURLOPT_INTERFACE, "eth1");
                // Do not get the header information in the response
                curl_easy_setopt(handles[i], CURLOPT_HEADER, 0L);
                // Configure an error buffer for error messages
                curl_easy_setopt(handles[i], CURLOPT_ERRORBUFFER,
CURL_ERROR_MESSAGES);
                curl_easy_setopt(handles[i], CURLOPT_PROXY, "
http://Proxyserver");
                curl_easy_setopt(handles[i], CURLOPT_PROXYPORT, 80);
                curl_easy_setopt(handles[i], CURLOPT_PROXYUSERPWD,
"username:password");
 
                // Write the list of HTTP headers
                curl_easy_setopt(handles[i], CURLOPT_HTTPHEADER, list);
        }
        if (list != NULL)
        {
                // Free the list.
                curl_slist_free_all(list);
        }
 
        std::cout << "Start setting the URLs\n";
 
        // Set the URL
        curl_easy_setopt(handles[0], CURLOPT_URL, "
http://www.example.com/v1");

        // Set the URL
        curl_easy_setopt(handles[1], CURLOPT_URL, "
http://www.example.com/v2");

        // Set the URL
        curl_easy_setopt(handles[2], CURLOPT_URL, "
http://www.example.com/v3");

        std::cout << "Init the Multi Handle\n";
        // Initialize our multi handle
        multi_handle = curl_multi_init();
 
        curl_multi_perform(multi_handle, &still_running);

        while (1)
        {
                // Clear out the messages
                Struct1.Request.clear();
                Struct1.Response.clear();
                Struct1.JSON_Request.clear();

                Struct2.Request.clear();
                Struct2.Response.clear();
                Struct2.JSON_Request.clear();

                Struct3.Response.clear();

                // Lock access to the Queue
                std::lock_guard<std::mutex>
lock_Queue(Class1::data_Q_Mutex);
 
                // Check to see if the queue is empty
                while (Class1::Data.empty() == false)
                {
                        // There is something in the queue so peek at the
item
                        if (Class1::Data.front().Packet_Type == Type1)
                        {
                                // Develop a JSON packet to activate the
node and then serialize it
 JsonSerializer::Serialize(Struct1.JSON_Request, &(Class1::Data.front()),
Struct1.Request);
                                // Duplicate this effort to create the
control packet and then serialize it
 JsonSerializer::Serialize(Struct3.JSON_Request, &(Class1::Data.front()),
Struct3.Request);
                        }
                        // The Packet must be a data packet
                        else
                        {
                                // Develop a JSON packet to record the
data and then serialize it
 JsonSerializer::Serialize(Struct2.JSON_Request, &(Class1::Data.front()),
Struct2.Request);
                        }
                        Class1::Data.pop();
                }
                // Release access to the Cloud queue
                lock_Queue.~lock_guard();

                // Check to see if there is an Activate message ready
                if (Struct1.Request.empty() == false)
                {
                        // Set the data that we want to send
                        curl_easy_setopt(handles[0], CURLOPT_POSTFIELDS,
Struct1.Request.c_str());
                        //curl_easy_setopt(handles[0], CURLOPT_POSTFIELDS,
"Hello");
                        // Set the data size
                        curl_easy_setopt(handles[0],
CURLOPT_POSTFIELDSIZE, (ulong32_t)Struct1.Request.length());
                        //curl_easy_setopt(handles[0],
CURLOPT_POSTFIELDSIZE, 5);
                        std::cout << "Struct1\n";
                        // Add the handle in to the multihandle
                        tmp = curl_multi_add_handle(multi_handle,
handles[0]);
                        std::cout << "Handle Added: tmp = " << tmp <<
"\n";
                }
 
                if (Struct2.Request.empty() == false)
                {
                        // Set the data that we want to send
                        curl_easy_setopt(handles[1], CURLOPT_POSTFIELDS,
Struct2.Request.c_str());
                        // Set the data size
                        curl_easy_setopt(handles[1],
CURLOPT_POSTFIELDSIZE, (ulong32_t)Struct2.Request.length());
                        //std::cout << "Struct2\n";
                        // Add the handle in to the multihandle
                        curl_multi_add_handle(multi_handle, handles[1]);
                }
 
                if (Struct3.Request.empty() == false)
                {
                        // Set the data that we want to send
                        curl_easy_setopt(handles[2], CURLOPT_POSTFIELDS,
Struct3.Request.c_str());
                        // Set the data size
                        curl_easy_setopt(handles[2],
CURLOPT_POSTFIELDSIZE, (ulong32_t)Struct3.Request.length());
                        //std::cout << "Struct3\n";
                        // Add the handle in to the multihandle
                        curl_multi_add_handle(multi_handle, handles[2]);
                }

                numfds = 0;
                do
                {
                        struct timeval timeout;
                        int rc;
                        CURLMcode mc;

                        fd_set fdread;
                        fd_set fdwrite;
                        fd_set fdexcep;
                        int maxfd = -1;
                        long curl_timeo = -1;

                        FD_ZERO(&fdread);
                        FD_ZERO(&fdwrite);
                        FD_ZERO(&fdexcep);

                        timeout.tv_sec = 1;
                        timeout.tv_usec = 0;

                        curl_multi_timeout(multi_handle, &curl_timeo);
                        if (curl_timeo >= 0)
                        {
                                timeout.tv_sec = curl_timeo/1000;
                                if (timeout.tv_sec > 1)
                                {
                                        timeout.tv_sec = 1;
                                }
                                else
                                {
                                        timeout.tv_usec = (curl_timeo %
1000) * 1000;
                                }
                        }

                        mc = curl_multi_fdset(multi_handle, &fdread,
&fdwrite, &fdexcep, &maxfd);

                        if (maxfd == -1)
                        {
                                struct timeval wait = {0, 100 * 1000 };
                                rc = select(0, NULL, NULL, NULL, &wait);
                        }
                        else
                        {
                                rc = select(maxfd+1, &fdread, &fdwrite,
&fdexcep, &timeout);
                        }

                        switch (rc)
                        {
                        case -1:
                                break;
                        case 0:
                        default:
                                curl_multi_perform(multi_handle,
&still_running);
                                std::cout << "after send. still_running="
<< still_running << "\n";
                                break;
                        }

                        //std::cout << "Before Wait: numfds= " << numfds
<< "\n";
                        //tmp = curl_multi_wait(multi_handle, NULL, 0,
10000, &numfds);
                        //std::cout << "After Wait tmp=" << tmp << "\n
Before send. still running: " << still_running << "\n";
                        // Attempt to perform some action
                        //tmp = curl_multi_perform(multi_handle,
&still_running);

                } while (still_running);
 
                // Check to see how the transfers went
                while ((msg = curl_multi_info_read(multi_handle,
&msgs_left)))
                {
                        if (msg->msg == CURLMSG_DONE)
                        {
                                std::cout << "Remove a handle since we're
done\n";
                                // Remove the handle
                                curl_multi_remove_handle(multi_handle,
msg->easy_handle);
                        }
                }
                // Sleep for an amount of time.
                nanosleep(&req, NULL);
        }
}

> >>> Dan
>
>
> ------------------------------

/**************************************************
Heath Schaefer
Product Engineer
Sporlan Division, Parker Hannifin Corporation
636.392.3243
**************************************************/

-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
Received on 2015-12-17