Microsoft KB Archive/246689

From BetaArchive Wiki
Knowledge Base


How To Use WSAIoctl with SIO_GET_QOS

Article ID: 246689

Article Last Modified on 2/22/2007



APPLIES TO

  • Microsoft Windows 2000 Server
  • Microsoft Windows 2000 Advanced Server
  • Microsoft Windows 2000 Professional Edition
  • Microsoft Windows 98 Standard Edition



This article was previously published under Q246689

SUMMARY

The version of the GQoS on Windows 2000 is version 4 (GQoSv4). The version of the GQoS on Windows 98 and Microsoft Windows 98 Second Edition is version 1 (GQoSv1). The WSAEnumProtocols function can be used to determine the version of the GQoS.

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

  • GQoSv4 allows you to query the system to determine how large an output buffer you need in order to retrieve the QOS structure(s) whereas with GQoSv1 you must pass in a large enough buffer.
  • GQoSv4 requires the output buffer to be contiguous whereas GQoSv1 does not.
  • GQoSv4 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 GQoSv1 returns the portion of the provider-specific data (complete provider-specific QOS objects only) that can fit in the supplied provider-specific buffer.
  • GQoSv1 requires that the output buffer be initialized so that the provider-specific pointer in the QOS structure points to valid memory, whereas GQoSv4 treats the buffer strictly as an output-only parameter (as it should).

As background, the WSAIoctl function 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 the WSAAsyncSelect or WSAEventSelect function. 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 by using 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 GQoSv1 or GQoSv4, and takes into account the differences outlined earlier:

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

    if (GQOSv1)
        // For GQOSv1 we must pick a buffer size
        dwBufferLen = 2048;
    else
        {
        // For GQOSv4 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);
        }

    // GQOSv1 workaround - not needed for GQOSv4, but doesn't
    // hurt.  GQOSv1 needs the provider specific buffer to point 
    // to valid memory, whereas GQOSv4 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.  GQOSv1 needs this whereas GQOSv4 ignores this. 
    // GQOSv1 should not care, because this is strictly an output
    // buffer, GQOSv4 corrects this problem. 
    pTempQos = (QOS *)pBuf;
    pTempQos->ProviderSpecific.buf = pBuf + sizeof(QOS);
    pTempQos->ProviderSpecific.len = dwBufferLen - sizeof(QOS);
    // end GQOSv1 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;
                

Keywords: kbdswnet2003swept kbapi kbgqos kbhowto kbnetwork KB246689