HOWTO: Use WSAIoctl with SIO_GET_QOS

ID: Q246689


The information in this article applies to:
  • Microsoft Windows 98
  • Microsoft Windows 2000


SUMMARY

Using WSAIoctl with the SIO_GET_QOS control code can be different because Windows 2000 and Windows 98 differ in how the API can and must be called. The differences are as follows:

  • Windows 2000 allows you to query the system to determine how large an output buffer you need in order to retrieve the QOS structure(s) whereas Windows 98 you must pass in a large enough buffer.


  • Windows 2000 requires the output buffer to be contiguous whereas Windows 98 does not.


  • Windows 2000 requires that the supplied output buffer be large enough to contain all the Quality of Service (QOS) data (specifically the variable length provider-specific data in addition to the fixed size flowspec data) otherwise none of the information will be returned whereas Windows 98 returns the portion of the provider-specific data (complete provider-specific QOS objects only) that can fit in the supplied provider-specific buffer.


  • Windows 98 requires the output buffer to be initialized so that the provider specific pointer in the QOS structure points to valid memory whereas Windows 2000 treats the buffer strictly as an output-only parameter (as it should).


As background the WSAIoctl API is called with the SIO_GET_QOS control code to retrieve one or more QOS structures from the system. Typically this is done in response to the receipt of an FD_QOS as a result of using either WSAAsyncSelect or WSAEventSelect. A high performance server application that utilizes Quality of Service most likely would not call either WSAAsyncSelect or WSAEventSelect but would instead call WSAIoctl(SIO_GET_QOS) in an overlapped manner, perhaps even utilizing I/O Completion Ports (IOCP).


MORE INFORMATION

The following code snippet demonstrates a technique that can be used to call WSAIoctl with the SIO_GET_QOS control code on either Windows 98 or Windows 2000 that takes into account the differences outlined earlier.


    DWORD   dwBytesReturned=0;
    DWORD   status;
    DWORD   dwBufferLen;
    CHAR    *pBuf = NULL;
    QOS     *pTempQos = NULL;
    QOS     *pQos = NULL;

    if (bWin98)
        // For Windows 98 we must pick a buffer size
        dwBufferLen = 2048;
    else
        {
        // For Windows 2000 we can query the system to determine
        // how large a buffer we need to pass in.
        dwBufferLen = 0;
        status = WSAIoctl(sd, SIO_GET_QOS, NULL, 0,
                    &dwBufferLen, sizeof(dwBufferLen),
                    &dwBytesReturned, NULL, NULL);
        if (SOCKET_ERROR == status)
            {
            DWORD dwErr = WSAGetLastError();
            if (WSAEWOULDBLOCK == dwErr)
                {
                // nothing to do
                return(FALSE);
                }
            else if (WSAENOBUFS != dwErr)
                {
                // some sort of error not related to passing a
                // large enough buffer
                printf("WSAIoctl(SIO_GET_QOS)-query: %d\n",dwErr);
		return(FALSE);
                }
            }
        }

    // for Windows 98 dwBufferLen has been set above, for
    // Windows 2000 we queried the OS for the proper buffer size
    printf("dwBufferlen for pQos = %d\n", dwBufferLen);
    if (!(pBuf = (CHAR *)malloc(dwBufferLen)))
        {
        printf("malloc: %d\n", GetLastError());
        return(FALSE);
        }

    // Windows 98 workaround - not needed for Win2000, but doesn't
    // hurt.  Windows 98 needs the provider specific buffer to point 
    // to valid memory, whereas Windows 2000 simply needs a contiguous   
    // block of memory.  Therefore we allocate a contiguous block of
    // memory cast it to a QOS structure and then set the provider
    // specific buffer pointer to just beyond the QOS structure
    // proper.  Windows 98 needs this whereas Windows 2000 ignores this. 
    // Windows 98 should not care, because this is strictly an output
    // buffer, Windows 2000 corrects this problem. 
    pTempQos = (QOS *)pBuf;
    pTempQos->ProviderSpecific.buf = pBuf + sizeof(QOS);
    pTempQos->ProviderSpecific.len = dwBufferLen - sizeof(QOS);
    // end Windows 98 workaround

    status = WSAIoctl(sd, SIO_GET_QOS, NULL, 0,
                   pBuf, dwBufferLen, &dwBytesReturned,
                   NULL, NULL);
    if (SOCKET_ERROR == status)
        {
        DWORD dwErr = WSAGetLastError();
        free((char *)pBuf);
        if (WSAEWOULDBLOCK != dwErr)
            {
            printf("WSAIoctl(SIO_GET_QOS) %d\n", dwErr);
            }
        return(FALSE);
        }
    pQos = (QOS *)pBuf; 

Additional query words:

Keywords : kbnetwork kbAPI kbGQos kbWinOS2000 kbSDKPlatform kbSDKWin32 kbWinOS98 kbDSupport kbGrpNet
Version : WINDOWS:
Platform : WINDOWS
Issue type : kbhowto


Last Reviewed: December 2, 1999
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.