Here is the (pseudo) code:

long PushRequest(params ...)
{
    CURL* hEasyHandle = 0;
    Lock(); // EnterCriticalSection
    {
        // init easy handle.
        hEasyHandle = curl_easy_init();
    }
    Unlock(); // LeaveCriticalSection

    if (!hEasyHandle)
    {
        return -1;
    }

    curl_easy_setopt(...

    //----------------- !!!!!!!!
// Here I have to use dynamic memory - strange, cause I saw "strdup" in libcurl
    char* szUrlBuffer = new char[1024]; // leak, needs upgrade
StringCchPrintf(szUrlBuffer, 1024, "%s%s", szAPNSAddress, szDeviceToken);
    curl_easy_setopt(hEasyHandle, CURLOPT_URL, szUrlBuffer);
    //----------------- !!!!!!!!
curl_easy_setopt(hEasyHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
    curl_easy_setopt(hEasyHandle, CURLOPT_SSLCERT, ...);
    ...
    curl_easy_setopt(hEasyHandle, CURLOPT_USERAGENT, "curl/7.51.0-DEV");
    curl_easy_setopt(hEasyHandle, CURLOPT_TCP_KEEPALIVE, 1L);
    curl_easy_setopt(hEasyHandle, CURLOPT_PIPEWAIT, 1L);

    Lock();
    {
        curl_multi_add_handle(hMultiHandle, hEasyHandle);
    }
    Unlock();
    return 0L;
}

DWORD WINAPI ServerProc(LPVOID hParameter)
{
    ...
    long response = 0;
    char* buffer = 0;
    CURLMcode mcResult = CURLM_OK;
    while (event in non-signaled state)
    {
// here i have logic which waits if no transfers - i don't want to bother you with synchronization
        int numfds = 0;
        int iStillRunning = 0;
        CURLMcode result = CURLM_OK;
if ((result = curl_multi_perform(hMultiHandle, &iStillRunning)) == CURLM_OK)
        {
            curl_multi_wait(hMultiHandle, NULL, 0, 100, &numfds);
        }
        do
        {
            int msgq = 0;
            hMsg = curl_multi_info_read(hMultiHandle, &msgq);
            if (hMsg && (hMsg->msg == CURLMSG_DONE))
            {
curl_easy_getinfo(hMsg->easy_handle, CURLINFO_RESPONSE_CODE, &response); curl_easy_getinfo(hMsg->easy_handle, CURLINFO_EFFECTIVE_URL, &buffer);
                // enqueue message to dispatcher
                ...
                // clean-up
                Lock();
                {
curl_multi_remove_handle(hMultiHandle, hMsg->easy_handle);
                }
                Unlock();
                curl_easy_cleanup(hMsg->easy_handle);
            }
        } while(hMsg);
    }
    return 0L;
}

Clients are calling the PushRequest in parallel, while separate thread is running the ServerProc. It works fine, I was able to push 100+ concurrent requests towards the Apple APNs without any problems.
Notifications were delivered.

Complete log running 4 threads is in the attachment.
I'm suspecting I'm doing something wrong, cause I'm getting strange messages in log (sample):
* Server doesn't support multi-use yet, wait
* Curl_readwrite: forcibly told to drain data
...

Thanks!

--
Miloš Ljumović
Operating systems specialist Spec.App.
http://milos.expert.its.me

* STATE: INIT => CONNECT handle 0xf3ef20; line 1397 (connection #-5000)
* Found bundle for host api.push.apple.com: 0xf675c0 [serially]
* Server doesn't support multi-use yet, wait
* No connections available.
* STATE: CONNECT => CONNECT_PEND handle 0xf3ef20; line 1416 (connection #-5000)
* STATE: INIT => CONNECT handle 0xf52e50; line 1397 (connection #-5000)
* Found bundle for host api.push.apple.com: 0xf675c0 [serially]
* Server doesn't support multi-use yet, wait
* No connections available.
* STATE: CONNECT => CONNECT_PEND handle 0xf52e50; line 1416 (connection #-5000)
* STATE: INIT => CONNECT handle 0xf5ccb8; line 1397 (connection #-5000)
* Found bundle for host api.push.apple.com: 0xf675c0 [serially]
* Server doesn't support multi-use yet, wait
* No connections available.
* STATE: CONNECT => CONNECT_PEND handle 0xf5ccb8; line 1416 (connection #-5000)
* STATE: CONNECT_PEND => CONNECT handle 0xf3ef20; line 3080 (connection #-5000)
* STATE: CONNECT_PEND => CONNECT handle 0xf52e50; line 3080 (connection #-5000)
* STATE: CONNECT_PEND => CONNECT handle 0xf5ccb8; line 3080 (connection #-5000)
* Found bundle for host api.push.apple.com: 0xf675c0 [can multiplex]
* Conn: 0 (0xf66b20) Receive pipe weight: (-1/0), penalized: (nil)
* Multiplexed connection found!
* Found connection 0, with requests in the pipe (1)
* Re-using existing connection! (#0) with proxy **************
* STATE: CONNECT => DO handle 0xf3ef20; line 1443 (connection #0)
* http2_send len=274
* h2 header: :method:POST
* h2 header: :path:/3/device/**************
* h2 header: :scheme:https
* h2 header: :authority:api.push.apple.com
* h2 header: User-Agent:curl/7.51.0-DEV
* h2 header: Accept:*/*
* h2 header: **************
* h2 header: Content-Length:46
* h2 header: Content-Type:application/x-www-form-urlencoded
* Using Stream ID: 3 (easy handle 0xf3ef20)
* before_frame_send() was called
* on_frame_send() was called, length = 70
> POST /3/device/************** HTTP/1.1
Host: api.push.apple.com
User-Agent: curl/7.51.0-DEV
Accept: */*
apns-topic: **************
Content-Length: 46
Content-Type: application/x-www-form-urlencoded

* STATE: DO => DO_DONE handle 0xf3ef20; line 1654 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0xf3ef20; line 1781 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0xf3ef20; line 1791 (connection #0)
* http2_send len=46
* data_source_read_callback: returns 46 bytes stream 3
* on_frame_send() was called, length = 46
* http2_send returns 46 for stream 3
* Found bundle for host api.push.apple.com: 0xf675c0 [can multiplex]
* Conn: 0 (0xf66b20) Receive pipe weight: (-1/0), penalized: (nil)
* Multiplexed connection found!
* Found connection 0, with requests in the pipe (2)
* Re-using existing connection! (#0) with proxy **************
* STATE: CONNECT => DO handle 0xf52e50; line 1443 (connection #0)
* http2_send len=274
* h2 header: :method:POST
* h2 header: :path:/3/device/**************
* h2 header: :scheme:https
* h2 header: :authority:api.push.apple.com
* h2 header: User-Agent:curl/7.51.0-DEV
* h2 header: Accept:*/*
* h2 header: **************
* h2 header: Content-Length:46
* h2 header: Content-Type:application/x-www-form-urlencoded
* Using Stream ID: 5 (easy handle 0xf52e50)
* before_frame_send() was called
* on_frame_send() was called, length = 67
> POST /3/device/************** HTTP/1.1
Host: api.push.apple.com
User-Agent: curl/7.51.0-DEV
Accept: */*
apns-topic: **************
Content-Length: 46
Content-Type: application/x-www-form-urlencoded

* STATE: DO => DO_DONE handle 0xf52e50; line 1654 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0xf52e50; line 1781 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0xf52e50; line 1791 (connection #0)
* http2_send len=46
* data_source_read_callback: returns 46 bytes stream 5
* on_frame_send() was called, length = 46
* http2_send returns 46 for stream 5
* Found bundle for host api.push.apple.com: 0xf675c0 [can multiplex]
* Conn: 0 (0xf66b20) Receive pipe weight: (-1/0), penalized: (nil)
* Multiplexed connection found!
* Found connection 0, with requests in the pipe (3)
* Re-using existing connection! (#0) with proxy **************
* STATE: CONNECT => DO handle 0xf5ccb8; line 1443 (connection #0)
* http2_send len=274
* h2 header: :method:POST
* h2 header: :path:/3/device/**************
* h2 header: :scheme:https
* h2 header: :authority:api.push.apple.com
* h2 header: User-Agent:curl/7.51.0-DEV
* h2 header: Accept:*/*
* h2 header: **************
* h2 header: Content-Length:46
* h2 header: Content-Type:application/x-www-form-urlencoded
* Using Stream ID: 7 (easy handle 0xf5ccb8)
* before_frame_send() was called
* on_frame_send() was called, length = 67
> POST /3/device/************** HTTP/1.1
Host: api.push.apple.com
User-Agent: curl/7.51.0-DEV
Accept: */*
apns-topic: **************
Content-Length: 46
Content-Type: application/x-www-form-urlencoded

* STATE: DO => DO_DONE handle 0xf5ccb8; line 1654 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0xf5ccb8; line 1781 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0xf5ccb8; line 1791 (connection #0)
* http2_send len=46
* data_source_read_callback: returns 46 bytes stream 7
* on_frame_send() was called, length = 46
* http2_send returns 46 for stream 7
* h2_process_pending_input: All data in connection buffer processed
* data_source_read_callback: returns 0 bytes stream 3
* on_frame_send() was called, length = 0
* h2_process_pending_input: All data in connection buffer processed
* data_source_read_callback: returns 0 bytes stream 5
* on_frame_send() was called, length = 0
* h2_process_pending_input: All data in connection buffer processed
* data_source_read_callback: returns 0 bytes stream 7
* on_frame_send() was called, length = 0
* http2_recv: easy 0xf3ef20 (stream 3)
* nread=36
* nghttp2_session_mem_recv() returns 36
* All data in connection buffer processed
* http2_recv returns AGAIN for stream 3
* http2_recv: easy 0xf52e50 (stream 5)
* nread=9
* on_begin_headers() was called
* nghttp2_session_mem_recv() returns 9
* All data in connection buffer processed
* http2_recv returns AGAIN for stream 5
* http2_recv: easy 0xf5ccb8 (stream 7)
* nread=31
* h2 status: HTTP/2 200 (easy 0xf3ef20)
* h2 header: apns-id: B7202A01-6482-16AB-E408-2E793D433D5F
* on_frame_recv() header 1 stream 3
* Store 62 bytes headers from stream 3 at 0xf3f53c
* on_stream_close(), NO_ERROR (err 0), stream 3
* Removed stream 3 hash!
* nghttp2_session_mem_recv() returns 31
* All data in connection buffer processed
* http2_recv returns AGAIN for stream 7
* on_begin_headers() was called
* h2 status: HTTP/2 200 (easy 0xf52e50)
* h2 header: apns-id: FC6DF599-633E-6910-BE3B-0C88C8C03CD6
* on_frame_recv() header 1 stream 5
* Store 62 bytes headers from stream 5 at 0xf5346c
* on_stream_close(), NO_ERROR (err 0), stream 5
* Removed stream 5 hash!
* Curl_readwrite: forcibly told to drain data
* http2_recv: easy 0xf3ef20 (stream 3)
* http2_recv: DRAIN 62 bytes stream 3!! (0xf3f53c => 0xf3f53c)
* http2_recv: returns 62 for stream 3
* HTTP/2 found, allow multiplexing
< HTTP/2 200 
< apns-id: B7202A01-6482-16AB-E408-2E793D433D5F
< 
* http2_recv: easy 0xf3ef20 (stream 3)
* nread=9
* on_begin_headers() was called
* nghttp2_session_mem_recv() returns 9
* All data in connection buffer processed
* h2_process_pending_input: All data in connection buffer processed
* http2_recv returns 0, http2_handle_stream_close
* http2_recv: easy 0xf3ef20 (stream 3)
* nread=32
* h2 status: HTTP/2 200 (easy 0xf5ccb8)
* h2 header: apns-id: 0F2F8F8F-8D3D-6D5D-A21D-177581E68A42
* on_frame_recv() header 1 stream 7
* Store 62 bytes headers from stream 7 at 0xf5d2d4
* on_stream_close(), NO_ERROR (err 0), stream 7
* Removed stream 7 hash!
* nghttp2_session_mem_recv() returns 32
* All data in connection buffer processed
* http2_recv returns AGAIN for stream 3
* STATE: PERFORM => DONE handle 0xf3ef20; line 1955 (connection #0)
* multi_done
* Curl_http_done: called premature == 0
* free header_recvbuf!!
* Connection still in use, no more multi_done now!
* Curl_readwrite: forcibly told to drain data
* http2_recv: easy 0xf52e50 (stream 5)
* http2_recv: DRAIN 62 bytes stream 5!! (0xf5346c => 0xf5346c)
* http2_recv: returns 62 for stream 5
* HTTP/2 found, allow multiplexing
< HTTP/2 200 
< apns-id: FC6DF599-633E-6910-BE3B-0C88C8C03CD6
< 
* http2_recv: easy 0xf52e50 (stream 5)
* h2_process_pending_input: All data in connection buffer processed
* http2_recv returns 0, http2_handle_stream_close
* http2_recv: easy 0xf52e50 (stream 5)
* STATE: PERFORM => DONE handle 0xf52e50; line 1955 (connection #0)
* multi_done
* Curl_http_done: called premature == 0
* free header_recvbuf!!
* Connection still in use, no more multi_done now!
* Curl_readwrite: forcibly told to drain data
* http2_recv: easy 0xf5ccb8 (stream 7)
* http2_recv: DRAIN 62 bytes stream 7!! (0xf5d2d4 => 0xf5d2d4)
* http2_recv: returns 62 for stream 7
* HTTP/2 found, allow multiplexing
< HTTP/2 200 
< apns-id: 0F2F8F8F-8D3D-6D5D-A21D-177581E68A42
< 
* http2_recv: easy 0xf5ccb8 (stream 7)
* h2_process_pending_input: All data in connection buffer processed
* http2_recv returns 0, http2_handle_stream_close
* http2_recv: easy 0xf5ccb8 (stream 7)
* STATE: PERFORM => DONE handle 0xf5ccb8; line 1955 (connection #0)
* multi_done
* Curl_http_done: called premature == 0
* free header_recvbuf!!
* Connection #0 to host ************** left intact
* Expire cleared
* Expire cleared
-------------------------------------------------------------------
List admin: https://cool.haxx.se/list/listinfo/curl-library
Etiquette:  https://curl.haxx.se/mail/etiquette.html

Reply via email to