0

I am trying to develop a WebSockets client in C++ using WinHttp. I am making very slow progress (I am .NET developer). I have my WS server developed in .NET 6 and now I am working on a C++ console app that connects to the server and listens for messages.

So far I successfully connect to the server and upgrade the connection to WS but struggle setting up the callback that triggers when a new message was sent from the server. I spent hours finding an example with no success.

Can someone please help me how to set the callback for the below code or provide me with a working example?

static void CALLBACK Callback(HINTERNET handle,
    DWORD_PTR context,
    DWORD code,
    void* info,
    DWORD length)
{
    switch (code) {

        case WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE:
        {
            int i = 0;
            break;
        }

        case WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED:
        {
            int i = 0;
            break;
        }

        case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
        {
            int i = 0;
            break;
        }
        
    default:
        {
        }
    }


    if (0 != context)
    {

    }
}



int main()
{

    DWORD dwError = ERROR_SUCCESS;
    BOOL fStatus = FALSE;
    DWORD dwSize = 0;
    DWORD dwDownloaded = 0;
    LPSTR pszOutBuffer;
    BOOL  bResults = FALSE;
    HINTERNET  hSession = NULL, hConnect = NULL, hRequest = NULL, hWebSocket = NULL;

    // Use WinHttpOpen to obtain a session handle.
    hSession = WinHttpOpen(L"WinHTTP Example/1.0",
        WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
        WINHTTP_NO_PROXY_NAME,
        WINHTTP_NO_PROXY_BYPASS,
        0);
    //WINHTTP_FLAG_ASYNC);

    if (hSession == NULL)
    {
        dwError = GetLastError();
    }

    // Setup the status callback function.
    WINHTTP_STATUS_CALLBACK isCallback = WinHttpSetStatusCallback(hSession,
        (WINHTTP_STATUS_CALLBACK)Callback,
        WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS,
        NULL);


    hConnect = WinHttpConnect(hSession, L"localhost", 5004, 0);

    if (hConnect == NULL)
    {
        dwError = GetLastError();
    }


    // Create an HTTP request handle.
    if (hConnect)
        hRequest = WinHttpOpenRequest(hConnect,
            L"GET",
            L"/ws",
            NULL,
            WINHTTP_NO_REFERER,
            WINHTTP_DEFAULT_ACCEPT_TYPES,
            0);//WINHTTP_FLAG_SECURE); // flags

    if (hRequest == NULL)
    {
        dwError = GetLastError();
    }


    //
    // Request protocol upgrade from http to websocket.
    //
#pragma prefast(suppress:6387, "WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET does not take any arguments.")
    fStatus = WinHttpSetOption(hRequest,
        WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET,
        NULL,
        0);

    if (!fStatus)
    {
        dwError = GetLastError();
    }



    // Send a request.
    if (hRequest)
        fStatus = WinHttpSendRequest(hRequest,
            WINHTTP_NO_ADDITIONAL_HEADERS,
            0,
            WINHTTP_NO_REQUEST_DATA,
            0,  // request data length
            0,  // total length
            0); // context

    if (!fStatus)
    {
        dwError = GetLastError();
    }

    fStatus = WinHttpReceiveResponse(hRequest, 0);

    if (!fStatus)
    {
        dwError = GetLastError();
    }


    //
    // Application should check what is the HTTP status code returned by the server and behave accordingly.
    // WinHttpWebSocketCompleteUpgrade will fail if the HTTP status code is different than 101.
    //
    hWebSocket = WinHttpWebSocketCompleteUpgrade(hRequest, NULL);

    if (hWebSocket == NULL)
    {
        dwError = GetLastError();
    }


    //
    // The request handle is not needed anymore. From now on we will use the websocket handle.
    //
    WinHttpCloseHandle(hRequest);
    hRequest = NULL;

    std::cout << "Connected to WS!\n";

}
JHBonarius
  • 10,824
  • 3
  • 22
  • 41
Dimt
  • 2,278
  • 2
  • 20
  • 26
  • I don't understand what exactly are you trying to achieve or what is your current problem. I tested out this example you provided here, (which is from MSDN) by changing the url to some random webpage and changing the port the the `INTERNET_DEFAULT_HTTP_PORT`. The callback function does get called. – Milan Š. Dec 26 '22 at 14:14
  • @MilanŠ. It gets called on the HTTP response but not, for any future message sent from the WS server. This is the problem. The purpose of this project is to periodically send updates from the server via established WS connections to the client app (for now is going to be this console app). – Dimt Dec 26 '22 at 16:35
  • Well if that's the case you will have to create a `minimal reproducible example`. Because the code you presented works as intended and if I cycle through it - it still initiates the callback. Please update your question with appropriate code. Ideal would be both a small server application (you can make it in `C#` if you feel it's easier) and a minimal `C++` application. – Milan Š. Dec 26 '22 at 17:47
  • Thanks, @MilanŠ. I will try to put other moving parts here that will reproduce the problem. FYI I found [CWebSocket](https://github.com/mstniy/CWebSocket) which fulfils all my needs for now. But, I still need to understand how to implement this correctly from the scratch. – Dimt Dec 26 '22 at 18:48

0 Answers0