// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
#include <Windows.h>
#include <WinHttp.h>
#include <stdio.h>
int wmain()
{
DWORD dwError = ERROR_SUCCESS;
BOOL fStatus = FALSE;
HINTERNET hSessionHandle = NULL;
HINTERNET hConnectionHandle = NULL;
HINTERNET hRequestHandle = NULL;
HINTERNET hWebSocketHandle = NULL;
BYTE rgbCloseReasonBuffer[123];
BYTE rgbBuffer[1024];
BYTE *pbCurrentBufferPointer = rgbBuffer;
DWORD dwBufferLength = ARRAYSIZE(rgbBuffer);
DWORD dwBytesTransferred = 0;
DWORD dwCloseReasonLength = 0;
USHORT usStatus = 0;
WINHTTP_WEB_SOCKET_BUFFER_TYPE eBufferType;
INTERNET_PORT Port = INTERNET_DEFAULT_HTTP_PORT;
const WCHAR *pcwszServerName = L"localhost";
const WCHAR *pcwszPath = L"/WinHttpWebSocketSample/EchoWebSocket.ashx";
const WCHAR *pcwszMessage = L"Hello world";
const DWORD cdwMessageLength = ARRAYSIZE(L"Hello world") * sizeof(WCHAR);
//
// Create session, connection and request handles.
//
hSessionHandle = WinHttpOpen(L"WebSocket sample",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
NULL,
NULL,
0);
if (hSessionHandle == NULL)
{
dwError = GetLastError();
goto quit;
}
hConnectionHandle = WinHttpConnect(hSessionHandle,
pcwszServerName,
Port,
0);
if (hConnectionHandle == NULL)
{
dwError = GetLastError();
goto quit;
}
hRequestHandle = WinHttpOpenRequest(hConnectionHandle,
L"GET",
pcwszPath,
NULL,
NULL,
NULL,
0);
if (hRequestHandle == NULL)
{
dwError = GetLastError();
goto quit;
}
//
// Request protocol upgrade from http to websocket.
//
#pragma prefast(suppress:6387, "WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET does not take any arguments.")
fStatus = WinHttpSetOption(hRequestHandle,
WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET,
NULL,
0);
if (!fStatus)
{
dwError = GetLastError();
goto quit;
}
//
// Perform websocket handshake by sending a request and receiving server's response.
// Application may specify additional headers if needed.
//
fStatus = WinHttpSendRequest(hRequestHandle,
WINHTTP_NO_ADDITIONAL_HEADERS,
0,
NULL,
0,
0,
0);
if (!fStatus)
{
dwError = GetLastError();
goto quit;
}
fStatus = WinHttpReceiveResponse(hRequestHandle, 0);
if (!fStatus)
{
dwError = GetLastError();
goto quit;
}
//
// 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.
//
hWebSocketHandle = WinHttpWebSocketCompleteUpgrade(hRequestHandle, NULL);
if (hWebSocketHandle == NULL)
{
dwError = GetLastError();
goto quit;
}
//
// The request handle is not needed anymore. From now on we will use the websocket handle.
//
WinHttpCloseHandle(hRequestHandle);
hRequestHandle = NULL;
wprintf(L"Succesfully upgraded to websocket protocol\n");
//
// Send and receive data on the websocket protocol.
//
dwError = WinHttpWebSocketSend(hWebSocketHandle,
WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE,
(PVOID)pcwszMessage,
cdwMessageLength);
if (dwError != ERROR_SUCCESS)
{
goto quit;
}
wprintf(L"Sent message to the server: '%s'\n", pcwszMessage);
do
{
if (dwBufferLength == 0)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto quit;
}
dwError = WinHttpWebSocketReceive(hWebSocketHandle,
pbCurrentBufferPointer,
dwBufferLength,
&dwBytesTransferred,
&eBufferType);
if (dwError != ERROR_SUCCESS)
{
goto quit;
}
//
// If we receive just part of the message restart the receive operation.
//
pbCurrentBufferPointer += dwBytesTransferred;
dwBufferLength -= dwBytesTransferred;
}
while (eBufferType == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE);
//
// We expected server just to echo single binary message.
//
if (eBufferType != WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE)
{
wprintf(L"Unexpected buffer type\n");
dwError = ERROR_INVALID_PARAMETER;
goto quit;
}
wprintf(L"Received message from the server: '%.*s'\n", dwBufferLength, (WCHAR*)rgbBuffer);
//
// Gracefully close the connection.
//
dwError = WinHttpWebSocketClose(hWebSocketHandle,
WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS,
NULL,
0);
if (dwError != ERROR_SUCCESS)
{
goto quit;
}
//
// Check close status returned by the server.
//
dwError = WinHttpWebSocketQueryCloseStatus(hWebSocketHandle,
&usStatus,
rgbCloseReasonBuffer,
ARRAYSIZE(rgbCloseReasonBuffer),
&dwCloseReasonLength);
if (dwError != ERROR_SUCCESS)
{
goto quit;
}
wprintf(L"The server closed the connection with status code: '%d' and reason: '%.*S'\n",
(int)usStatus,
dwCloseReasonLength,
rgbCloseReasonBuffer);
quit:
if (hRequestHandle != NULL)
{
WinHttpCloseHandle(hRequestHandle);
hRequestHandle = NULL;
}
if (hWebSocketHandle != NULL)
{
WinHttpCloseHandle(hWebSocketHandle);
hWebSocketHandle = NULL;
}
if (hConnectionHandle != NULL)
{
WinHttpCloseHandle(hConnectionHandle);
hConnectionHandle = NULL;
}
if (hSessionHandle != NULL)
{
WinHttpCloseHandle(hSessionHandle);
hSessionHandle = NULL;
}
if (dwError != ERROR_SUCCESS)
{
wprintf(L"Application failed with error: %u\n", dwError);
return -1;
}
return 0;
}