Microsoft KB Archive/246689

From BetaArchive Wiki
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
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