Exemplo n.º 1
0
void main()
{
	int nProtocols;
	int nError;
	DWORD dwSize = 0;
	LPWSAPROTOCOL_INFOW pProtoInfo = NULL;
	//  首次调用,pProtoInfo传入NULL,取得需要的缓冲区长度
	if(WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError) == SOCKET_ERROR)
	{
		if(nError != WSAENOBUFS)
		{
			return ;
		}
	}
	// 申请足够缓冲区内存。
	pProtoInfo = (LPWSAPROTOCOL_INFOW)::GlobalAlloc(GPTR, dwSize);
	if (pProtoInfo == NULL)
	{
		return ;
	}
	//再次调用WSCEnumProtocols函数
	nProtocols = ::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError);
	wchar_t szWPath[MAX_PATH] = {0};
	int iLen = MAX_PATH;
	//使控制台支持中文编码////////////////////////////////////////////////////////////////////
	setlocale(LC_ALL, "chs");
	wprintf(L"%-10s%-25s%s\n\n", L"提供者ID", L"协议类型", L"DLL路径");
	wchar_t *szWType[3] = {L"分层协议", L"基础协议", L"协议链"};
	int iIndex = 0;
	for(int i=0; i<nProtocols; i++)
	{	//打印传输服务提供者ID
		wprintf(L"%-13d", pProtoInfo[i].dwCatalogEntryId);
		//打印传输服务提供者协议类型
		iIndex = (pProtoInfo[i].ProtocolChain.ChainLen>1?2:pProtoInfo[i].ProtocolChain.ChainLen);
		wprintf(L"%-15s", szWType[iIndex]);
		//打印传输服务提供者所对应DLL的路径
		WSCGetProviderPath(&pProtoInfo[i].ProviderId, szWPath, &iLen, NULL);
		wprintf(L"%-15s\n", szWPath);
	}
	wprintf(L"共计 %d 个传输服务提供者\n", nProtocols);
	//释放内存
	GlobalFree(pProtoInfo);
	//恢复控制台编码//////////////////////////////////////////////////////////////////////////
	setlocale(LC_ALL, NULL);
}
Exemplo n.º 2
0
//
// Function: LoadProviderPath
//
// Description:
//      This function retrieves the provider's DLL path, expands any environment
//      variables, loads the DLL, and retrieves it's WSPStartup function.
//
BOOL
LoadProviderPath(
    PROVIDER    *loadProvider,
    int         *lpErrno
    )
{
    int     rc;

    *lpErrno = 0;

    // Retrieve the provider path of the lower layer
    loadProvider->ProviderPathLen = MAX_PATH - 1;
    rc = WSCGetProviderPath(
           &loadProvider->NextProvider.ProviderId,
            loadProvider->ProviderPathW,
           &loadProvider->ProviderPathLen,
            lpErrno
            );
    if ( SOCKET_ERROR == rc )
    {
        dbgprint("LoadProviderPath: WSCGetProviderPath failed: %d", *lpErrno );
        goto cleanup;
    }

    rc = ExpandEnvironmentStringsW(
            loadProvider->ProviderPathW,
            loadProvider->LibraryPathW,
            MAX_PATH - 1
            );
    if ( ( 0 != rc ) && ( MAX_PATH-1 >= rc ) )
    {
        loadProvider->Module = LoadLibraryW( loadProvider->LibraryPathW );
        if ( NULL == loadProvider->Module )
        {
            dbgprint("LoadProviderPath: LoadLibraryW failed: %d", GetLastError() );
            goto cleanup;
        }
    }
    else if ( 0 == rc )
    {
        char    ProviderPathA[ MAX_PATH ],
                LibraryPathA[ MAX_PATH ];

        // No UNICODE so we must be on Win9x
        rc = WideCharToMultiByte( CP_ACP, 0,
                loadProvider->ProviderPathW,
                loadProvider->ProviderPathLen,
                ProviderPathA,
                loadProvider->ProviderPathLen,
                NULL,
                NULL
                );
        if ( 0 == rc )
        {
            dbgprint("LoadProviderPath: WideCharToMultiByte failed: %d", GetLastError() );
            goto cleanup;
        }

        rc = ExpandEnvironmentStringsA(
                ProviderPathA,
                LibraryPathA,
                MAX_PATH - 1
                );
        if ( ( 0 == rc ) || ( MAX_PATH - 1 < rc ) )
        {
            dbgprint("LoadProviderPath: ExpandEnvironmentStringsA failed: %d", GetLastError() );
            goto cleanup;
        }

        loadProvider->Module = LoadLibraryA( LibraryPathA );
        if ( NULL == loadProvider->Module )
        {
            dbgprint("LoadProviderPath: LoadLibraryA failed: %d", GetLastError() );
            goto cleanup;
        }
    }

    // Retrieve the next provider's WSPSTartup function
    loadProvider->fnWSPStartup = (LPWSPSTARTUP) GetProcAddress(
            loadProvider->Module,
            "WSPStartup"
            );
    if ( NULL == loadProvider->fnWSPStartup )
    {
        dbgprint("LoadProviderPath: GetProcAddress failed: %d", GetLastError() );
        goto cleanup;
    }

    return TRUE;

cleanup:

    if ( *lpErrno == 0 )
        *lpErrno = GetLastError();
    return FALSE;
}
Exemplo n.º 3
0
//
// Function: InstallIfsLspProtocolChains
//
// Description:
//      This routine installs the layered protocol chains for an IFS based LSP. It
//      assumes the LSP dummy entry is already installed. This function first enumerates
//      the catalog to find the ID of the dummy entry. It then builds the protocol
//      entries for the IFS layered protocols. Note that an IFS entry must be installed
//      such that no non-IFS providers are layered beneath it. This means if the user
//      chooses to install the IFS LSP over a provider which includes non-IFS layers, it
//      must insert itself into the chain such that it is below all non-IFS providers.
//      This means that existing entries need to be modified in order to reflect this
//      ordering. Also in the event that the IFS LSP is inserted into an existing chain
//      this installer still builds a series of standalone entries (i.e. entries that
//      would have existed of the LSPs layered over the IFS LSP were installed after
//      the IFS LSP was).
//
int
InstallIfsLspProtocolChains(
    WINSOCK_CATALOG eCatalog,
    GUID           *Guid,
    WCHAR          *lpszLspName,
    WCHAR          *lpszLspFullPathAndFile,
    DWORD          *pdwCatalogIdArray,
    DWORD           dwCatalogIdArrayCount
    )
{
    WSAPROTOCOL_INFOW  *pProvider = NULL,
                       *pProviderNew = NULL,
                       *pLayeredEntries = NULL,
                       *pEntry = NULL,
                        TempEntry = {0};
    DWORD              *pProviderOrder = NULL,
                        dwDummyLspId;
    WCHAR               wszLspDll[ MAX_PATH ];
    BOOL                bLayeredOverNonIfs = FALSE,
                        bContainsNonIfs = FALSE;
    HRESULT             hr;
    int                 ProviderPathLen = MAX_PATH-1,
                        iProviderCount,
                        iProviderCountNew,
                        LayerIdx,
                        retval = SOCKET_ERROR,
                        err,
                        idx,
                        rc,
                        i, j, k;

    // Enumerate the catalog
    pProvider = EnumerateProviders( eCatalog, &iProviderCount );
    if ( NULL == pProvider )
    {
        fprintf( stderr, "InstallIfsLspProtocolChains: Unable to enumerate catalog\n" );
        goto cleanup;
    }

    // Find the dummy, hidden entry of our new LSP
    dwDummyLspId = GetCatalogIdForProviderGuid( Guid, pProvider, iProviderCount );

    ASSERT( dwDummyLspId != 0 );

    // Allocate space for the protocol chains of the new LSP
    pLayeredEntries = (WSAPROTOCOL_INFOW *) LspAlloc( sizeof(WSAPROTOCOL_INFOW) *
            dwCatalogIdArrayCount, &err );
    if ( NULL == pLayeredEntries )
    {
        fprintf( stderr, "InstallIfsLspProtocolChains: LspAlloc failed: %d\n", err );
        goto cleanup;
    }

    LayerIdx = 0;

    // Build the layered protocol entries as well as a list of those providers which
    // require modification. Whenever an LSP is installed, a number of protocol entries
    // are installed where the first entry in the chain array is the LSP's dummy entry.
    // Addtionally, if we're installing an IFS LSP over an provider whose protocol chain
    // includes non-IFS LSPs, the IFS LSP must be placed in the chain such that no
    // non-IFS LSPs are positioned after it in the chain.

    // Loop through each ID we're layering over
    for(i=0; i < (int)dwCatalogIdArrayCount ;i++)
    {
        for(j=0; j < iProviderCount ;j++)
        {
            printf("Matching selected ID %d to catalog %d\n",
                    pdwCatalogIdArray[ i ], pProvider[ j ].dwCatalogEntryId );

            if ( pdwCatalogIdArray[ i ] == pProvider[ j ].dwCatalogEntryId )
            {
                // Verify the entry has room enough to be layered over
                if ( pProvider[ j ].ProtocolChain.ChainLen >= ( MAX_PROTOCOL_CHAIN - 1 ) )
                {
                    fprintf( stderr, "InstallIfsLspProtocolChain: Too many LSPs installed!\n");
                    goto cleanup;
                }

                // Save off the entry which we're layering over
                memcpy( &pLayeredEntries[ LayerIdx ], &pProvider[ j ],
                        sizeof( pLayeredEntries[ 0  ] ) );

                memcpy( &TempEntry, &pProvider[ j ], sizeof( TempEntry ) );        

                // Fill in the new LSP entry's name
                hr = StringCchPrintfW( pLayeredEntries[ LayerIdx ].szProtocol, WSAPROTOCOL_LEN,
                        L"%s over [%s]",
                        lpszLspName,
                        pProvider[ j ].szProtocol 
                        );
                if ( FAILED( hr ) )
                {
                    fprintf( stderr, "InstallIfsLspProtocolChains: StringCchPrintfW failed: 0x%x\n", hr );
                    goto cleanup;
                }

                // Check whether the selected entry contains non IFS LSPs in its chain
                if ( pProvider[ j ].ProtocolChain.ChainLen >= 2 )
                {
                    for(k=pProvider[ j ].ProtocolChain.ChainLen-2 ; k >= 0 ;k--)
                    {
                        bContainsNonIfs = IsNonIfsProvider( pProvider, iProviderCount, 
                                pProvider[ j ].ProtocolChain.ChainEntries[ k ] );

                        if ( TRUE == bContainsNonIfs )
                        {
                            // Need to modify the pProvider entry to reference the
                            // added LSP entry within its chain

                            // In the 'modified' array make a space at location after 'k'
                            InsertIdIntoProtocolChain( &pProvider[ j ], k+1, UPDATE_LSP_ENTRY );

                            // Save the index to the layer which corresponds to this entry
                            pProvider[ j ].dwProviderReserved = LayerIdx + 1;

                            // Need to fix the 'pLayeredEntry' as well
                            BuildSubsetLspChain( &pLayeredEntries[ LayerIdx ], k+1, dwDummyLspId );

                            pLayeredEntries[ LayerIdx ].dwServiceFlags1 |= XP1_IFS_HANDLES;

                            bLayeredOverNonIfs = TRUE;

                            // Need to insert the IFS provider in all LSPs that  are layered
                            // above the location where the IFS provider was just inserted
                            InsertIfsLspIntoAllChains( &TempEntry, pProvider, iProviderCount, 
                                    LayerIdx + 1, k );

                            break;
                        }
                    }
                }

                // Need to setup the protocol chain in the pLayeredEntry if we haven't
                // already done so above
                if ( TRUE != bContainsNonIfs )
                {
                    InsertIdIntoProtocolChain( &pLayeredEntries[ LayerIdx ], 0, dwDummyLspId );

                    // The second entry is always the ID of the current pProvider[i]
                    //     In case of multiple LSPs then if we didn't do this the [1] index
                    //     would contain the ID of that LSP's dummy entry and not the entry
                    //     itself.
                    pLayeredEntries[ LayerIdx ].ProtocolChain.ChainEntries[ 1 ] = 
                            TempEntry.dwCatalogEntryId;

                    pLayeredEntries[ LayerIdx ].dwServiceFlags1 |= XP1_IFS_HANDLES;
                }

                LayerIdx++;
            }
        }
    }

    ASSERT( LayerIdx == (int)dwCatalogIdArrayCount );

    // Create a unique GUID for each provider to install and install it
    for(i=0;i < (int)dwCatalogIdArrayCount ;i++)
    {
        if ( RPC_S_OK != UuidCreate( &pLayeredEntries[ i ].ProviderId ) )
        {
            fprintf(stderr, "InstallIfsLspProtocolChains: UuidCreate failed: %d\n", GetLastError());
            goto cleanup;
        }

        rc = InstallProvider( eCatalog, &pLayeredEntries[ i ].ProviderId,
                lpszLspFullPathAndFile, &pLayeredEntries[ i ], 1 );
        if ( NO_ERROR != rc )
        {
            fprintf(stderr, "InstallIfsLspProtocolChains: Unable to install the dummy LSP entry!\n");
            goto cleanup;
        }
    }

    if ( TRUE == bLayeredOverNonIfs )
    {
        // Enumerate the catalog again so we can find the catalog IDs

        pProviderNew = EnumerateProviders( eCatalog, &iProviderCountNew );
        if ( NULL == pProvider )
        {
            fprintf( stderr, "InstallIfsLspProtocolChains: Unable to enumerate catalog\n" );
            goto cleanup;
        }

        for(i=0; i < (int)dwCatalogIdArrayCount ;i++)
        {
            pLayeredEntries[ i ].dwCatalogEntryId = GetCatalogIdForProviderGuid(
                   &pLayeredEntries[ i ].ProviderId,
                    pProviderNew,
                    iProviderCountNew
                    );

            ASSERT( pLayeredEntries[ i ].dwCatalogEntryId != 0 );
        }

        // Update the protocol chains of the modified entries to point to the just
        //    installed providers
        for(i=0; i < iProviderCount ;i++)
        {
            if ( pProvider[ i ].dwProviderReserved == 0 )
                continue;

            for(j=0; j < pProvider[ i ].ProtocolChain.ChainLen ;j++)
            {
                if ( UPDATE_LSP_ENTRY == pProvider[ i ].ProtocolChain.ChainEntries[ j ] )
                {
                    pProvider[ i ].ProtocolChain.ChainEntries[ j ] = 
                        pLayeredEntries[ pProvider[ i ].dwProviderReserved - 1 ].dwCatalogEntryId;

                    pProvider[ i ].dwProviderReserved = 0;
                }
            }

            // Get the DLL path
            ProviderPathLen = MAX_PATH-1;
            rc = WSCGetProviderPath(
                    &pProvider[ i ].ProviderId,
                     wszLspDll,
                    &ProviderPathLen,
                    &err
                     );
            if ( SOCKET_ERROR == rc )
            {
                fprintf( stderr, "InstallIfsLspProtocolChains: WSCGetProviderPath failed: %d\n", err );
                goto cleanup;
            }

            // Update the providers which were modified
            rc = UpdateProvider( eCatalog, &pProvider[ i ].ProviderId,
                    wszLspDll, &pProvider[ i ], 1, &err );
            if ( SOCKET_ERROR == rc )
            {
                fprintf( stderr, "InstallIfsLspProtocolChains: UpdateProvider failed: %d\n", err );
                goto cleanup;
            }

            printf("Updated entry ID: %d: %S (chain len = %d)\n",
                    pProvider[ i ].dwCatalogEntryId,
                    pProvider[ i ].szProtocol,
                    pProvider[ i ].ProtocolChain.ChainLen
                    );
        }

        FreeProviders( pProvider );
        pProvider = NULL;

        FreeProviders( pProviderNew );
        pProviderNew = NULL;

        /*
        {
            WSADATA wsd;

            WSACleanup();

            WSAStartup( MAKEWORD(2,2), &wsd );
        }
        */

        pProvider = EnumerateProviders( eCatalog, &iProviderCount );
        if ( NULL == pProvider )
        {
            fprintf( stderr, "InstallIfsLspProtocolChains: Unable to enumerate catalog\n" );
            goto cleanup;
        }

        // Allocate an array of DWORDs to contain the new catalog ordering
        pProviderOrder = (DWORD *)LspAlloc( iProviderCount * sizeof(DWORD), &err );
        if ( NULL == pProviderOrder )
        {
            fprintf( stderr, "InstallIfsLspProtocolChains: Unable to enumerate catalog\n" );
            goto cleanup;
        }

        // First add the entries we layered over first
        idx = 0;
        for(i=0; i < (int)dwCatalogIdArrayCount ;i++)
        {
            pEntry = FindProviderById( pdwCatalogIdArray[ i ], pProvider, iProviderCount );
            if ( NULL == pEntry )
            {
                fprintf(stderr, "InstallIfsLspProtocolChain: Unable to find entry to reorder catalog!\n");
                goto cleanup;
            }

            pEntry->dwProviderReserved = 1;

            pProviderOrder[ idx++ ] = pEntry->dwCatalogEntryId;
        }

        // Now go through the protocol chain of the entries we layered over and put those
        //    LSP entries next in the new order
        for(i=0; i < (int)dwCatalogIdArrayCount ;i++)
        {
            pEntry = FindProviderById( pdwCatalogIdArray[ i ], pProvider, iProviderCount );
            if ( NULL == pEntry )
            {
                fprintf(stderr, "InstallIfsLspProtocolChain: Unable to find entry to reorder catalog!\n");
                goto cleanup;
            }

            printf("Looping through: %d: %S (chain len = %d)\n", 
                    pEntry->dwCatalogEntryId,
                    pEntry->szProtocol,
                    pEntry->ProtocolChain.ChainLen );

            for(j=1; j < pEntry->ProtocolChain.ChainLen-1 ;j++)
            {
                dwDummyLspId = FindDummyIdFromProtocolChainId(
                        pEntry->ProtocolChain.ChainEntries[ j ],
                        pProvider,
                        iProviderCount
                        );

                printf("   Finding dummy ID for chain entry: %d is %d\n", 
                        pEntry->ProtocolChain.ChainEntries[ j ],
                        dwDummyLspId
                        );

                for(k=0; k < iProviderCount ;k++)
                {
                    if ( ( pProvider[ k ].ProtocolChain.ChainLen >= 2 ) &&
                         ( pProvider[ k ].ProtocolChain.ChainEntries[ 0 ] == dwDummyLspId ) &&
                         ( pProvider[ k ].dwProviderReserved == 0 )
                       )
                    {
                        pProviderOrder[ idx++ ] = pProvider[ k ].dwCatalogEntryId;
                        pProvider[ k ].dwProviderReserved = 1;

                        printf("      Adding: %d\n", pProvider[ k ].dwCatalogEntryId );
                    }
                }
            }
        }

        // Now any catalog entry that wasn't already copied, copy it
        for(i=0; i < iProviderCount ;i++)
        {
            if ( pProvider[ i ].dwProviderReserved == 0 )
                pProviderOrder[ idx++ ] = pProvider[ i ].dwCatalogEntryId;
        }

        ASSERT( idx == iProviderCount );

        // Write the new catalog order
        rc = WriteProviderOrder( eCatalog, pProviderOrder, iProviderCount, &err );
        if ( NO_ERROR != rc )
        {
            fprintf( stderr, "InstallIfsLspProtocolChains: WriteProviderOrder failed: %d\n",
                    err );
            goto cleanup;
        }
    }
    else
    {
        //
        // Reorder the winsock catalog so the layered chain entries appear first.
        // Since we didn't have to modify any existing entries, all we need to do is
        //    move the added entries to the head of the catalog
        // 
        rc = ReorderCatalog( eCatalog, dwDummyLspId );
        if ( NO_ERROR != rc )
        {
            fprintf(stderr, "InstallIfsLspProtocolChains: Unable to reorder Winsock catalog!\n");
            goto cleanup;
        }
    }

    retval = NO_ERROR;

cleanup:
    
    if ( NULL != pProvider )
    {
        FreeProviders( pProvider );
        pProvider = NULL;
    }

    if ( NULL != pProviderNew )
    {
        FreeProviders( pProviderNew );
        pProviderNew = NULL;
    }

    if ( NULL != pProviderOrder )
    {
        LspFree( pProviderOrder );
        pProviderOrder = NULL;
    }

    return retval;
}
Exemplo n.º 4
0
NS_IMETHODIMP
LSPAnnotationGatherer::Run()
{
  PR_SetCurrentThreadName("LSP Annotator");

  mThread = NS_GetCurrentThread();

  DWORD size = 0;
  int err;
  // Get the size of the buffer we need
  if (SOCKET_ERROR != WSCEnumProtocols(nullptr, nullptr, &size, &err) ||
      err != WSAENOBUFS) {
    // Er, what?
    NS_NOTREACHED("WSCEnumProtocols suceeded when it should have failed ...");
    return NS_ERROR_FAILURE;
  }

  auto byteArray = MakeUnique<char[]>(size);
  WSAPROTOCOL_INFOW* providers =
    reinterpret_cast<WSAPROTOCOL_INFOW*>(byteArray.get());

  int n = WSCEnumProtocols(nullptr, providers, &size, &err);
  if (n == SOCKET_ERROR) {
    // Lame. We provided the right size buffer; we'll just give up now.
    NS_WARNING("Could not get LSP list");
    return NS_ERROR_FAILURE;
  }

  nsCString str;
  for (int i = 0; i < n; i++) {
    AppendUTF16toUTF8(nsDependentString(providers[i].szProtocol), str);
    str.AppendLiteral(" : ");
    str.AppendInt(providers[i].iVersion);
    str.AppendLiteral(" : ");
    str.AppendInt(providers[i].iAddressFamily);
    str.AppendLiteral(" : ");
    str.AppendInt(providers[i].iSocketType);
    str.AppendLiteral(" : ");
    str.AppendInt(providers[i].iProtocol);
    str.AppendLiteral(" : ");
    str.AppendPrintf("0x%x", providers[i].dwServiceFlags1);
    str.AppendLiteral(" : ");
    str.AppendPrintf("0x%x", providers[i].dwProviderFlags);
    str.AppendLiteral(" : ");

    wchar_t path[MAX_PATH];
    int pathLen = MAX_PATH;
    if (!WSCGetProviderPath(&providers[i].ProviderId, path, &pathLen, &err)) {
      AppendUTF16toUTF8(nsDependentString(path), str);
    }

    str.AppendLiteral(" : ");
    // If WSCGetProviderInfo is available, we should call it to obtain the
    // category flags for this provider. When present, these flags inform
    // Windows as to which order to chain the providers.
    nsModuleHandle ws2_32(LoadLibraryW(L"ws2_32.dll"));
    if (ws2_32) {
      decltype(WSCGetProviderInfo)* pWSCGetProviderInfo =
        reinterpret_cast<decltype(WSCGetProviderInfo)*>(
            GetProcAddress(ws2_32, "WSCGetProviderInfo"));
      if (pWSCGetProviderInfo) {
        DWORD categoryInfo;
        size_t categoryInfoSize = sizeof(categoryInfo);
        if (!pWSCGetProviderInfo(&providers[i].ProviderId,
                                 ProviderInfoLspCategories,
                                 (PBYTE)&categoryInfo, &categoryInfoSize, 0,
                                 &err)) {
          str.AppendPrintf("0x%x", categoryInfo);
        }
      }
    }

    str.AppendLiteral(" : ");
    if (providers[i].ProtocolChain.ChainLen <= BASE_PROTOCOL) {
      // If we're dealing with a catalog entry that identifies an individual
      // base or layer provider, log its provider GUID.
      RPC_CSTR provIdStr = nullptr;
      if (UuidToStringA(&providers[i].ProviderId, &provIdStr) == RPC_S_OK) {
        str.Append(reinterpret_cast<char*>(provIdStr));
        RpcStringFreeA(&provIdStr);
      }
    }

    if (i + 1 != n) {
      str.AppendLiteral(" \n ");
    }
  }

  mString = str;
  NS_DispatchToMainThread(NewRunnableMethod(this, &LSPAnnotationGatherer::Annotate));
  return NS_OK;
}
Exemplo n.º 5
0
//
// Function: PrintProtocolInfo
//
// Description:
//    Decode a WSAPROTOCOL_INFO entry and print the member fields
//    in a readable format. There's no secret voodoo here, just 
//    interpret all the fields of the structure.
//
void 
PrintProtocolInfo(
    WSAPROTOCOL_INFOW *wsapi
    )
{
    WCHAR       szGuidString[MAX_PATH],
                wszProviderPath[MAX_PATH];
    INT         dwProviderPathLen=MAX_PATH-1;
    int		    rc, error, i;

    rc = WSCGetProviderPath(
           &wsapi->ProviderId,
            wszProviderPath,
           &dwProviderPathLen,
           &error
            );
    if ( 0 != rc )
    {
        fprintf(stderr, "WSCGetProviderPath failed: %d\n", error);
        lstrcpyW(wszProviderPath, L"(error)");
    }

    //
    // Display address family and protocol information
    //

    printf("\nProtocol: %S\n", wsapi->szProtocol);
    printf("\n    Path: %S\n", wszProviderPath);
    printf("           Address Family: ");
    switch ( wsapi->iAddressFamily )
    {
        case AF_INET:
        case AF_INET6:
            printf("%s\n", (wsapi->iAddressFamily == AF_INET ? "AF_INET" : "AF_INET6"));
            printf("                 Protocol: ");      
            switch (wsapi->iProtocol)
            {
                case IPPROTO_IP:
                    printf("IPROTO_IP\n");
                    break;
                case IPPROTO_ICMP:
                    printf("IPROTO_ICMP\n");
                    break;
                case IPPROTO_IGMP:
                    printf("IPROTO_IGMP\n");
                    break;
                case IPPROTO_GGP:
                    printf("IPROTO_GGP\n");
                    break;
                case IPPROTO_TCP:
                    printf("IPROTO_TCP\n");
                    break;
                case IPPROTO_PUP:
                    printf("IPROTO_PUP\n");
                    break;
                case IPPROTO_UDP:
                    printf("IPROTO_UDP\n");
                    break;
                case IPPROTO_IDP:
                    printf("IPROTO_IDP\n");
                    break;
                case IPPROTO_ND:
                    printf("IPROTO_ND\n");
                    break;
                case IPPROTO_RM:
                    printf("IPPROTO_RM\n");
                    break;
                case IPPROTO_RAW:
                    printf("IPROTO_RAW\n");
                    break;
            }
            break;

        case AF_UNSPEC:
            printf("AF_UNSPEC\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_UNIX:
            printf("AF_UNIX\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_IMPLINK:
            printf("AF_IMPLINK\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_PUP:
            printf("AF_PUP\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_CHAOS:
            printf("AF_CHAOS\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_NS:
            printf("AF_NS or AF_IPX\n");
            printf("                 Protocol: ");      

            switch ( wsapi->iProtocol )
            {
                case NSPROTO_IPX:
                    printf("NSPROTO_IPX\n");
                    break;
                case NSPROTO_SPX:
                    printf("NSPROTO_SPX\n");
                    break;
                case NSPROTO_SPXII:
                    printf("NSPROTO_SPXII\n");
                    break;
            }
            break;

        case AF_ISO:
            printf("AF_ISO or AF_OSI\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_ECMA:
            printf("AF_ECMA\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_DATAKIT:
            printf("AF_DATAKIT\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_CCITT:
            printf("AF_CCITT\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_SNA:
            printf("AF_SNA\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_DECnet:
            printf("AF_DECnet\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_DLI:
            printf("AF_DLI\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_LAT:
            printf("AF_LAT\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_HYLINK:
            printf("AF_HYLINK\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_APPLETALK:
            printf("AF_APPLETALK\n");
            printf("                 Protocol: ");      

            switch ( wsapi->iProtocol )
            {
                case DDPPROTO_RTMP:
                    printf("DDPPROTO_RTMP\n");
                    break;
                case DDPPROTO_NBP:
                    printf("DDPPROTO_NBP\n");
                    break;
                case DDPPROTO_ATP:
                    printf("DDPROTO_ATP\n");
                    break;
                case DDPPROTO_AEP:
                    printf("DDPPROTO_AEP\n");
                    break;
                case DDPPROTO_RTMPRQ:
                    printf("DDPPROTO_RTMPRQ\n");
                    break;
                case DDPPROTO_ZIP:
                    printf("DDPPROTO_ZIP\n");
                    break;
                case DDPPROTO_ADSP:
                    printf("DDPPROTO_ADSP\n");
                    break;
                case ATPROTO_ADSP:
                    printf("ATPROTO_ADSP\n");
                    break;
                case ATPROTO_ATP:
                    printf("ATPROTO_ATP\n");
                    break;
                case ATPROTO_ASP:
                    printf("ATPROTO_ASP\n");
                    break;
                case ATPROTO_PAP:
                    printf("ATPROTO_PAP\n");
                    break;
            }
            break;

        case AF_NETBIOS:
            printf("AF_NETBIOS\n");
            printf("                 Protocol: ");      
            printf("NetBIOS LANA %d\n", ((wsapi->iProtocol == 0x80000000) ? 0: abs(wsapi->iProtocol)));
            break;

        case AF_VOICEVIEW:
            printf("AF_VOICEVIEW\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_FIREFOX:
            printf("AF_FIREFOX\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_UNKNOWN1:
            printf("AF_UNKNOWN1\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_BAN:
            printf("AF_BAN\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;

        case AF_ATM:
            printf("AF_ATM\n");
            printf("                 Protocol: ");      

            switch ( wsapi->iProtocol )
            {
                case ATMPROTO_AALUSER:
                    printf("ATMPROTO_AALUSER\n");
                    break;
                case ATMPROTO_AAL1:
                    printf("ATMPROTO_AAL1\n");
                    break;
                case ATMPROTO_AAL2:
                    printf("ATMPROTO_AAL2\n");
                    break;
                case ATMPROTO_AAL34:
                    printf("ATMPROTO_AAL34\n");
                    break;
                case ATMPROTO_AAL5:
                    printf("ATMPROTO_AAL5\n");
                    break;
            }
            break;

        case AF_CLUSTER:
            printf("AF_CLUSTER\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;
        case AF_12844:
            printf("AF_12844\n");
            printf("                 Protocol: UNKNOWN: %d", wsapi->iProtocol);      
            break;
        case AF_IRDA:
            printf("AF_IRDA\n");
            printf("                 Protocol: ");      

            switch (wsapi->iProtocol)
            {
                case IRDA_PROTO_SOCK_STREAM:
                    printf("IRDA_PROTO_SOCK_STREAM\n");
                    break;
            }
            break;

        default:
            printf("Unknown: %d\n", wsapi->iAddressFamily);
    }

    //
    // Display socket type information
    //

    printf("              Socket Type: ");
    switch (wsapi->iSocketType)
    {
        case SOCK_STREAM:
            printf("SOCK_STREAM\n");
            break;
        case SOCK_DGRAM:
            printf("SOCK_DGRAM\n");
            break;
        case SOCK_RAW:
            printf("SOCK_RAW\n");
            break;
        case SOCK_RDM:
            printf("SOCK_RDM\n");
            break;
        case SOCK_SEQPACKET:
            printf("SOCK_SEQPACKET\n");
            break;
    }

    //
    // Display the various provider flags for this entry
    //

    printf("           Connectionless: ");
    if (wsapi->dwServiceFlags1 & XP1_CONNECTIONLESS)
        printf("YES\n");
    else
        printf("NO\n");
    printf("      Guaranteed Delivery: ");
    if (wsapi->dwServiceFlags1 & XP1_GUARANTEED_DELIVERY)
        printf("YES\n");
    else
        printf("NO\n");
    printf("         Guaranteed Order: ");
    if (wsapi->dwServiceFlags1 & XP1_GUARANTEED_ORDER)
        printf("YES\n");
    else
        printf("NO\n");
    printf("         Message Oriented: ");
    if (wsapi->dwServiceFlags1 & XP1_MESSAGE_ORIENTED)
        printf("YES\n");
    else
        printf("NO\n");
    printf("            Pseudo Stream: ");
    if (wsapi->dwServiceFlags1 & XP1_PSEUDO_STREAM)
        printf("YES\n");
    else
        printf("NO\n");
    printf("           Graceful Close: ");
    if (wsapi->dwServiceFlags1 & XP1_GRACEFUL_CLOSE)
        printf("YES\n");
    else
        printf("NO\n");
    printf("           Expedited Data: ");
    if (wsapi->dwServiceFlags1 & XP1_EXPEDITED_DATA)
        printf("YES\n");
    else
        printf("NO\n");
    printf("             Connect Data: ");
    if (wsapi->dwServiceFlags1 & XP1_CONNECT_DATA)
        printf("YES\n");
    else
        printf("NO\n");
    printf("          Disconnect Data: ");
    if (wsapi->dwServiceFlags1 & XP1_DISCONNECT_DATA)
        printf("YES\n");
    else
        printf("NO\n");
    printf("       Supports Broadcast: ");
    if (wsapi->dwServiceFlags1 & XP1_SUPPORT_BROADCAST)
        printf("YES\n");
    else
        printf("NO\n");
    printf("      Supports Multipoint: ");
    if (wsapi->dwServiceFlags1 & XP1_SUPPORT_MULTIPOINT)
        printf("YES\n");
    else
        printf("NO\n");
    printf(" Multipoint Control Plane: ");
    if (wsapi->dwServiceFlags1 & XP1_MULTIPOINT_CONTROL_PLANE)
        printf("ROOTED\n");
    else
        printf("NON-ROOTED\n");
    printf("    Multipoint Data Plane: ");
    if (wsapi->dwServiceFlags1 & XP1_MULTIPOINT_DATA_PLANE)
        printf("ROOTED\n");
    else
        printf("NON-ROOTED\n");
    printf("            QoS Supported: ");
    if (wsapi->dwServiceFlags1 & XP1_QOS_SUPPORTED)
        printf("YES\n");
    else
        printf("NO\n");
    printf("     Unidirectional Sends: ");
    if (wsapi->dwServiceFlags1 & XP1_UNI_SEND)
        printf("YES\n");
    else
        printf("NO\n");
    printf("    Unidirection Receives: ");
    if (wsapi->dwServiceFlags1 & XP1_UNI_RECV)
        printf("YES\n");
    else
        printf("NO\n");
    printf("              IFS Handles: ");
    if (wsapi->dwServiceFlags1 & XP1_IFS_HANDLES)
        printf("YES\n");
    else
        printf("NO\n");
    printf("         Partial Messages: ");
    if (wsapi->dwServiceFlags1 & XP1_PARTIAL_MESSAGE)
        printf("YES\n");
    else
        printf("NO\n");
    printf("           Provider Flags: ");
    if (wsapi->dwProviderFlags & PFL_MULTIPLE_PROTO_ENTRIES)
    {
        printf("PFL_MULTIPLE_PROTO_ENTRIES ");
    }
    if (wsapi->dwProviderFlags & PFL_RECOMMENDED_PROTO_ENTRY)
    {
        printf("PFL_RECOMMENDED_PROT_ENTRY ");
    }
    if (wsapi->dwProviderFlags & PFL_HIDDEN)
    {
        printf("PFL_HIDDEN ");
    }
    if (wsapi->dwProviderFlags & PFL_MATCHES_PROTOCOL_ZERO)
    {
        printf("PFL_MATCHES_PROTOCOL_ZERO ");
    }
    if (wsapi->dwProviderFlags == 0)
    {
        printf("NONE");
    }
    printf("\n");

    //
    // Display provider ID and catalog ID as well as LSP chain information
    //

    StringFromGUID2( wsapi->ProviderId, szGuidString, MAX_PATH-1 );

    printf("              Provider Id: %S\n", szGuidString);
    printf("         Catalog Entry Id: %ld\n", wsapi->dwCatalogEntryId);
    printf("  Number of Chain Entries: %d   {", 
        wsapi->ProtocolChain.ChainLen);

    for(i=0; i < wsapi->ProtocolChain.ChainLen ;i++)
        printf("%ld ", wsapi->ProtocolChain.ChainEntries[i]);

    printf("}\n");

    //
    // Display the remaining information
    //

    printf("                  Version: %d\n", wsapi->iVersion);
    printf("Max Socket Address Length: %d\n", wsapi->iMaxSockAddr);
    printf("Min Socket Address Length: %d\n", wsapi->iMinSockAddr);
    printf("      Protocol Max Offset: %d\n", wsapi->iProtocolMaxOffset);

    printf("       Network Byte Order: ");
    if (wsapi->iNetworkByteOrder == 0)
        printf("BIG-ENDIAN\n");
    else
        printf("LITLE-ENDIAN\n");

    printf("          Security Scheme: ");
    if (wsapi->iSecurityScheme == SECURITY_PROTOCOL_NONE)
        printf("NONE\n");
    else
        printf("%d\n", wsapi->iSecurityScheme);

    printf("             Message Size: ");
    if (wsapi->dwMessageSize == 0)
        printf("N/A (Stream Oriented)\n");
    else if (wsapi->dwMessageSize == 1)
        printf("Depended on underlying MTU\n");
    else if (wsapi->dwMessageSize == 0xFFFFFFFF)
        printf("No limit\n");
    else
        printf("%ld\n", wsapi->dwMessageSize);

    printf("        Provider Reserved: %d\n", wsapi->dwProviderReserved);
}
JNIEXPORT jint JNICALL Java_com_act365_net_SocketWrenchSession__1deinstallProvider( JNIEnv* env , jclass , jint protocol )
{
    int nDeinstalled = 0 ;

#ifdef WIN32

    int i = -1 ;

    // Find the installed service providers for the given protocol.

    int protocolList[1];

    protocolList[0] = (int) protocol ;

    if( ( nProtocols = WSAEnumProtocolsW( protocolList , protocolBuffer , & protocolBufferSize ) ) == SOCKET_ERROR ){

        jclass exceptionClass = env -> FindClass("java/net/SocketException");
            
        SocketUtils::throwError( env , exceptionClass , "WSAEnumProtocols()" );

        env -> DeleteLocalRef( exceptionClass );

        return nDeinstalled ;
    }

    // Find the path of the DLL in which the services are implemented. 
    // (It's assumed that they're all implemented in a single MS DLL).

    int errorCode = 0 , dllPathLength = maxDllPathLength ;

    if( nProtocols > 0 ){
        WSCGetProviderPath( & protocolBuffer[0].ProviderId , dllPath , & dllPathLength , & errorCode );
    }

    if( errorCode > 0 ){

        jclass exceptionClass = env -> FindClass("java/net/SocketException");
            
        SocketUtils::throwError( env , exceptionClass , "WSCGetProviderPath()" );

        env -> DeleteLocalRef( exceptionClass );

        return nDeinstalled ;
    }

    // Deinstall.
    

    while( ++ i < nProtocols && ! errorCode ){        
        nDeinstalled += WSCDeinstallProvider( & protocolBuffer[i].ProviderId , & errorCode );
    }

    if( errorCode > 0 ){

        jclass exceptionClass = env -> FindClass("java/net/SocketException");
            
        SocketUtils::throwError( env , exceptionClass , "WSCDeinstallProvider()" );

        env -> DeleteLocalRef( exceptionClass );
    }

#endif

    return nDeinstalled ;
}
//
// Function: BuildLspMap
//
// Description:
//    This routine builds a map of all LSPs installed according to what order
//    they are in the catalog. That is, the information returned will be ordered
//    in the way the LSPs need to be installed. For example if LSP1 is installed
//    over the base TCP and UDP providers and LSP2 is installed over LSP1, then 
//    this routine will return two LSP_ENTRY structures with LSP1 first followed
//    by LSP2. The algorithm for determining the order is to first sort by where
//    a base provider ID occurs in an LSP chain with lower numbered ones first.
//    For example, LSP1 layered directly over TCP will have a base ID (TCP) in
//    chain position 1 while LSP (layered over LSP1) will have the base ID in
//    chain index 2. This is the ChainOrder field (and it is the minimum value
//    for all layered providers). After this first sort, it is possible to have
//    several LSPs with the same ChainOrder value. Within these groupings the
//    entries are sorted by the maximum LSP chain length. Each LSP has a number
//    of layered providers each with its own chain (and the chains could be
//    different lengths). The MaxChainLength value is the longest chain length
//    of all providers belonging to a given LSP. Each grouping of LspOrder is then
//    sorted by MaxChainLengthin ascending order.
//
LSP_ENTRY *
BuildLspMap(
    WSAPROTOCOL_INFOW *pProviders,
    int                iProviderCount,
    int               *pLspCount
    )
{
    LSP_ENTRY *pLsps = NULL,
               lsptmp;
    DWORD     *pBaseList = NULL;
    int        iLspCount = 0,
               iSortLspCount = 0,
               iOrphanCount = 0,
               iBaseCount = 0,
               iProviderPathLen,
               ErrorCode,
               LspOrder,
               start,
               end,
               idx,
               rc,
               i, j, k;

    // Retrieve how many orphaned chain entries are present
    iOrphanCount = CountOrphanedChainEntries( pProviders, iProviderCount );

    // Retrieve the LSP count
    iSortLspCount = iLspCount = GetProviderCount( pProviders, iProviderCount, LAYERED_PROTOCOL );

    if ( ( 0 == iOrphanCount ) && ( 0 == iLspCount ) )
    {
        fprintf( stderr, "BuildLspMap: No LSP installed on the system!\n");
        goto cleanup;
    }

    // If orphaned entries are present, create another LSP_ENTRY and put all orphaned
    //      entries there.
    if ( iOrphanCount > 0 )
        iLspCount++;

    // Allocate space for our structure which represents the LSPs installed
    pLsps = (LSP_ENTRY *) LspAlloc(
            sizeof( LSP_ENTRY ) * iLspCount,
           &ErrorCode
            );
    if ( NULL == pLsps )
    {
        fprintf( stderr, "BuildLspMap: LspAlloc failed: %d\n", ErrorCode );
        goto cleanup;
    }

    // If orphaned entries are present, allocate space to hold them
    if ( iOrphanCount > 0 )
    {
        pLsps[ iLspCount-1 ].LayeredEntries = (WSAPROTOCOL_INFOW *)LspAlloc(
                sizeof(WSAPROTOCOL_INFOW) * iOrphanCount, &ErrorCode );
        if ( NULL == pLsps[ iLspCount-1 ].LayeredEntries )
        {
            fprintf( stderr, "BuildLspMap: LspAlloc failed: %d\n", ErrorCode );
            goto cleanup;
        }

        pLsps[ iLspCount-1 ].OrphanedEntries = TRUE;
        pLsps[ iLspCount-1 ].Count = iOrphanCount;

        //
        // Find the orphaned entries and save them off
        //
        idx = 0;
        for(i=0; i < iProviderCount ;i++)
        {
            // Only investigate protocol chain entries (i.e. chainlen > 1)
            if ( pProviders[ i ].ProtocolChain.ChainLen > 1 )
            {
                // Walk the catalog and look for the dummy entry (i.e. the ID in 
                //    chain entry 0)
                for(j=0; j < iProviderCount ;j++) 
                {
                    if ( i == j )
                        continue;

                    if ( pProviders[ i ].ProtocolChain.ChainEntries[ 0 ] ==
                         pProviders[ j ].dwCatalogEntryId )
                    {
                        break;
                    }
                }
                if ( j >= iProviderCount )
                {
                    // If j is past iProviderCount, no match was found so this is
                    //    an orphaned entry...save it off
                    memcpy( &pLsps[ iLspCount-1 ].LayeredEntries[ idx ],
                            &pProviders[ i ],
                             sizeof( WSAPROTOCOL_INFOW )
                          );
                    rc = AddGuidToLspEntry( &pLsps[ iLspCount-1 ], &pProviders[ i ].ProviderId,
                            &ErrorCode );
                    if ( SOCKET_ERROR == rc )
                    {
                        fprintf( stderr, "BuildLspMap: AddGuidToLspEntry failed: %d\n", ErrorCode );
                        goto cleanup;
                    }
                        
                    idx++;
                }
            }
        }
    }

    //
    // Build a list of the valid LSPs installed on the system
    //
    idx = 0;
    for(i=0; i < iProviderCount ;i++)
    {
        if ( LAYERED_PROTOCOL == pProviders[ i ].ProtocolChain.ChainLen )
        {
            // Copy the dummy entry
            memcpy( &pLsps[ idx ].DummyEntry, &pProviders[ i ], sizeof( WSAPROTOCOL_INFOW ) );

            // Get the DLL path
            iProviderPathLen = MAX_PATH-1;
            rc = WSCGetProviderPath(
                    &pLsps[ idx ].DummyEntry.ProviderId,
                     pLsps[ idx ].wszLspDll,
                    &iProviderPathLen,
                    &ErrorCode
                     );
            if ( SOCKET_ERROR == rc )
            {
                fprintf( stderr, "BuildLspMap: WSCGetProviderPath failed: %d\n", ErrorCode );
                goto cleanup;
            }

            //
            // Now go find all the layered entries associated with the dummy provider
            //

            // First get the count
            for(j=0; j < iProviderCount ;j++)
            {
                //
                // Compare only the first entry against the dummy ID. Otherwise, 
                //    we may pick up more than the provider's owned by this LSP 
                //    (it may pick up other providers layered over this LSP.
                //
                if ( ( pProviders[ j ].ProtocolChain.ChainLen > 1 ) &&
                     ( pProviders[ j ].ProtocolChain.ChainEntries[ 0 ] ==
                       pLsps[ idx ].DummyEntry.dwCatalogEntryId ) 
                   )
                // if ( IsIdInChain( &pProviders[ j ], pLsps[ idx ].DummyEntry.dwCatalogEntryId ) )
                {
                    pLsps[idx].Count++;
                }
            }

            // Allocate space
            pLsps[ idx ].LayeredEntries = (WSAPROTOCOL_INFOW *) LspAlloc(
                    sizeof( WSAPROTOCOL_INFOW ) * pLsps[ idx ].Count,
                   &ErrorCode
                    );
            if ( NULL == pLsps[ idx ].LayeredEntries )
            {
                fprintf( stderr, "BuildLspMap: LspAlloc failed: %d\n", ErrorCode );
                goto cleanup;
            }

            pLsps[ idx ].LayerChanged = (int *) LspAlloc(
                    sizeof( int ) * pLsps[ idx ].Count,
                   &ErrorCode
                    );
            if ( NULL == pLsps[ idx ].LayerChanged )
            {
                fprintf( stderr, "BuildLspMap: LspAlloc failed: %d\n", ErrorCode );
                goto cleanup;
            }

            // Now go find the entries
            pLsps[idx].Count = 0;
            for(j=0; j < iProviderCount ;j++)
            {
                if ( ( pProviders[ j ].ProtocolChain.ChainLen > 1 ) &&
                     ( pProviders[ j ].ProtocolChain.ChainEntries[ 0 ] ==
                       pLsps[ idx ].DummyEntry.dwCatalogEntryId ) 
                   )
                {
                    memcpy( 
                           &pLsps[ idx ].LayeredEntries[pLsps[ idx ].Count],
                           &pProviders[ j ],
                            sizeof( WSAPROTOCOL_INFOW )
                            );

                    pLsps[idx].MaxChainLength = MAX( 
                            pLsps[ idx ].MaxChainLength,
                            pLsps[ idx ].LayeredEntries[ pLsps[idx].Count ].ProtocolChain.ChainLen 
                            );

                    // Mark this entry as visited
                    pProviders[ j ].dwProviderReserved = 1;

                    // Keep track of how many GUIDs are used to install the layered entries
                    rc = AddGuidToLspEntry( &pLsps[ idx ], &pProviders[ j ].ProviderId, &ErrorCode );
                    if ( SOCKET_ERROR == rc )
                    {
                        fprintf( stderr, "BuildLspMap: AddGuidToLspEntry failed: %d\n", ErrorCode );
                        goto cleanup;
                    }

                    pLsps[ idx ].Count++;
                }
            }

            pLsps[ idx ].LspOrder = MAX_PROTOCOL_CHAIN;

            idx++;      // Increment index into the map
        }
    }

    //
    // We now have an array of "LSPs" -- now order them
    //

    // First get a list of base provider IDs
    iBaseCount = GetProviderCount( pProviders, iProviderCount, BASE_PROTOCOL );
    if ( 0 == iBaseCount )
    {
        fprintf( stderr, "BuildLspMap: GetProviderCount(BASE_PROTOCOL) returned zero!\n" );
        goto cleanup;
    }

    // Allocate space for the array of base provider ID's
    pBaseList = (DWORD *) LspAlloc(
            sizeof( DWORD ) * iBaseCount,
           &ErrorCode
            );
    if ( NULL == pBaseList )
    {
        fprintf( stderr, "BuildLspMap: HeapAlloc failed: %d\n", ErrorCode );
        goto cleanup;
    }

    //
    // Copy the base provider ID's to our array -- this array contains the catalog
    // IDs of only base providers which will be used next to determine the order
    // in which LSPs were installed.
    //
    idx = 0;
    for(i=0; i < iProviderCount ;i++)
    {
        if ( BASE_PROTOCOL == pProviders[ i ].ProtocolChain.ChainLen )
        {
            pBaseList[ idx++ ] = pProviders[ i ].dwCatalogEntryId;
        }
    }

    //
    // For each layered protocol entry of an LSP find the lowest index in the protocol
    // chain where a base provider resides. A protocol chain should always terminate
    // in a base provider.
    //
    for(LspOrder = 1; LspOrder < MAX_PROTOCOL_CHAIN ;LspOrder++)
    {
        for(i=0; i < iSortLspCount ;i++)
        {
            for(j=0; j < pLsps[ i ].Count ;j++)
            {
                for(k=0; k < iBaseCount ;k++)
                {
                    if ( pLsps[ i ].LayeredEntries[ j ].ProtocolChain.ChainEntries[ LspOrder ] ==
                         pBaseList[ k ] )
                    {
                        pLsps[ i ].LspOrder = MIN( pLsps[ i ].LspOrder, LspOrder );
                        break;
                    }
                }
            }
        }
    }

    //
    // Sort the entries according to the LspOrder field
    //
    for(i=0; i < iSortLspCount ;i++)
    {
        for(j=i; j < iSortLspCount ;j++)
        {
            if ( pLsps[ i ].LspOrder > pLsps[ j ].LspOrder )
            {
                // Exchange positions
                memcpy( &lsptmp,     &pLsps[ i ], sizeof( LSP_ENTRY ) );
                memcpy( &pLsps[ i ], &pLsps[ j ], sizeof( LSP_ENTRY ) );
                memcpy( &pLsps[ j ], &lsptmp,     sizeof( LSP_ENTRY ) );
            }
        }
    }

    //
    // Now need to sort by MaxChainLength withing the LspOrder groupings
    //
    for(LspOrder=1; LspOrder < MAX_PROTOCOL_CHAIN ;LspOrder++)
    {
        // Find the start and end positions within the array for the given
        // LspOrder value
        start = -1;
        end   = -1;

        for(i=0; i < iSortLspCount ;i++)
        {
            if ( pLsps[ i ].LspOrder == LspOrder )
            {
                start = i;
                break;
            }
        }

        //
        // Find the end position which is the LSP Map entry whose LspOrder
        // value doesn't match the current one. This will give us the range
        // of LSP entries whose LspOrder value is identical -- we need to
        // sort the LSPs of the same LspOrder according to the MaxChainLength
        //
        if ( -1 != start )
        {
            for(j=start; j < iSortLspCount ;j++)
            {
                if ( pLsps[ j ].LspOrder != LspOrder )
                {
                    end = j - 1;
                    break;
                }
            }
        }
        
        //
        // If the following is true then all entries have the same order
        // value. We still need to sort by MaxChainLength so set the end
        // to the last LSP 
        //
        if ( ( -1 != start ) && ( -1 == end ) )
        {
            end = iSortLspCount - 1;
        }

        if ( ( -1 != start ) && ( -1 != end ) )
        {
            for(i=start; i < end ;i++)
            {
                for(j=i; j < end ;j++)
                {
                    if ( pLsps[ i ].MaxChainLength > pLsps[ j ].MaxChainLength )
                    {
                        memcpy( &lsptmp,     &pLsps[ i ], sizeof( LSP_ENTRY ) );
                        memcpy( &pLsps[ i ], &pLsps[ j ], sizeof( LSP_ENTRY ) );
                        memcpy( &pLsps[ j ], &lsptmp,     sizeof( LSP_ENTRY ) );
                    }
                }
            }
        }
    }

    // Add the LSP dependency info to the map
    rc = LspDependencyCheck( pLsps, iSortLspCount );
    if ( SOCKET_ERROR == rc )
    {
        FreeLspMap( pLsps, iLspCount );
        pLsps = NULL;
        iLspCount = 0;
        goto cleanup;
    }

cleanup:
    
    if ( NULL != pLspCount )
        *pLspCount = iLspCount;

    if ( NULL != pBaseList )
        LspFree( pBaseList );

    return pLsps;
}