0

I have an application which uses Wininet on the main thread to make both sync and async calls. A single root internet handle is opened with flag - INTERNET_FLAG_ASYNC. This handle is used for all calls.To implement sync network calls, we simply wait in an infinite while loop until the request completes. Intermittently we see that we do not get any response from the Wininet.

Some code snippets/pseudo code below which show what we are trying to do.


// struct Context{
    bool resultReady;
}

// Callback function registered with Wininet to know about the progress of ongoing call 
static void CALLBACK StatusCallBack (
                     IN HINTERNET           hInternet,
                     IN DWORD_PTR           dwContext,
                     IN DWORD               dwInternetStatus,
                     IN LPVOID              lpvStatusInformation OPTIONAL,
                     IN DWORD               dwStatusInformationLength ) 
{
    Context* cxt = (Context *)dwContext;
    switch (dwInternetStatus) { 
        // other cases ... 
        case INTERNET_STATUS_REQUEST_COMPLETE : 
            cxt->resultReady = true; break;
    }
}


// Open root internet handle
HINTERNET root_hnd = InternetOpenA(agentname, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_ASYNC);

// Set status callback 
InternetSetStatusCallback(root_hnd, StatusCallBack );

// Open connect handle 
Context connect_cxt = {};
HINTERNET connect_hnd = InternetConnectA(root_hnd, hostname, NULL, NULL, INTERNET_SERVICE_HTTP, 0, &connect_cxt);

// Open HTTP request handle 
Context http_cxt= {};
DWORD flags = INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_AUTH | INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RELOAD | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS;
HINTERNET http_hnd = HttpOpenRequestA(connect_hnd, verb, objectname, HTTP_VERSIONA, NULL, NULL, flags, &http_cxt);

HttpSendRequestA(file, NULL, 0, additionalOptions, optionsLen);

while(http_cxt.resultReady == false) {
    Sleep(10);
}

This is only a snippet of what we are doing. We have error handling at each step and synchronization mechanism also in place. For making calls to same hostname, we reuse the internet connect handle as well, but open a new http request handle everytime.

Upon debugging, we found that if multiple async calls are in place to the same server, Wininet queues up the calls and doesn't actually send the request unless the previous ones are finished : http://webdebug.net/2013/01/wininet-connection-limit/

We fixed this issue by increasing allowed connection limit, and failing calls at initiation itself in case limit still exceeded. However, we are still seeing the same symptoms sometimes even in cases when only a single async call is made to a server (in parallel other calls might be in progress to other servers). Once, we do a send request, we do not get any response at all in our registered callback function.

I want to know if Wininet needs the thread on which the handles are opened to be freed up in order for it to send us something in progress callbacks ? Also, is there any other connection limit which we might be missing ?

  • If you don't process messages from the Windows event loop but just sleep in an endless loop of your own, the program will not make any progress. – Jesper Juhl Apr 30 '19 at 15:28
  • *if Wininet needs the thread on which the handles are opened* - thread can do any. callbacks will be called on working threads anyway. however sleep in loop - very bad design. you not need any loop, sleep in place (and use event for this instead sleep), etc. your error in something else. – RbMm Apr 30 '19 at 21:14
  • `InternetSetStatusCallback(root_hnd, StatusCallBack );` - this your critical error. you must set it for handle returned by `HttpOpenRequestA`. so for `http_hnd` instead `root_hnd`. – RbMm Apr 30 '19 at 21:22
  • and sure you need remove `while(http_cxt.resultReady == false) { Sleep(10); }` - this is not solution. bad logic – RbMm Apr 30 '19 at 22:04
  • @RbMm Regarding "this your critical error", I do not see how. Wininet documentation mentions that StatusCallback function is inherited by is inherited by derived handles. This is intentional and I do not see any issue here. – Shashank Gupta May 16 '19 at 10:00
  • @ShashankGupta - yes, documentation say this. but i do tests and view on practic different picture - callback is called only if i set it on handle returned by HttpOpenRequestA. simply set it for this handle for test and check different – RbMm May 16 '19 at 11:05
  • @ShashankGupta - so despite documentation in my test - if i set callback on handle returned by `InternetConnect` or `InternetOpen` - callback not called at all. if i set callback on handle returned by `HttpOpenRequestW` - all worked ok. unfortunatelly look like you not understand what i wrote for *How to safely prevent status callback function from being called in Wininet?* but if still interest - [here](https://pastebin.com/hHRzngNp) full code example (dll+exe code). this(code) is work very well, but if on 313 line i set callback on parent handle - all is breaked – RbMm May 16 '19 at 11:37

0 Answers0