Beispiel #1
0
//------------------------------------------------------------------------
//  LSPAlreadyInstalled()
//
//  Check to see if the restricted network LSP is alreay installed.
//------------------------------------------------------------------------
DWORD LSPAlreadyInstalled( BOOL *pfIsInstalled )
    {
    int                  i;
    int                  iEnumResult;
    int                  iError;
    DWORD                dwStatus = NO_ERROR;
    int                  aiProtocols[2];
    WSAPROTOCOL_INFOW   *pProtocolInfoBuff = NULL;
    DWORD                dwProtocolInfoBuffSize = 0;


    // Enumerate TCP/IP providers and chains

    *pfIsInstalled = FALSE;

    aiProtocols[0] = IPPROTO_TCP;
    aiProtocols[1] = 0;

    // Call WSCEnumProtocols with a zero length buffer so we know what
    // size to send in to get all the installed PROTOCOL_INFO structs. 
    iEnumResult = WSCEnumProtocols( aiProtocols,
                                    pProtocolInfoBuff,
                                    &dwProtocolInfoBuffSize,
                                    &iError );

    if ((iEnumResult == SOCKET_ERROR) && (iError == WSAENOBUFS))
        {
        pProtocolInfoBuff = (WSAPROTOCOL_INFOW*)new char [dwProtocolInfoBuffSize];
        if (!pProtocolInfoBuff)
            {
            // Out of memory...
            return ERROR_NOT_ENOUGH_MEMORY;
            }

        iEnumResult = WSCEnumProtocols( aiProtocols,
                                        pProtocolInfoBuff,
                                        &dwProtocolInfoBuffSize,
                                        &iError );
            
        if (iEnumResult != SOCKET_ERROR)
            {
            // Look through the list and see if the Restricted Network LSP
            // is already there.
            for (i=0; i<iEnumResult; i++)
                {
                if (!memcmp(&pProtocolInfoBuff[i].ProviderId,
                            &LayeredProviderGuid,
                            sizeof(GUID)))
                    {
                    *pfIsInstalled = TRUE;
                    break;
                    }
                }
            }
        }

    delete pProtocolInfoBuff;

    return dwStatus;
    }
Beispiel #2
0
SOCKET
open_ifs_socket(int af, int type, int protocol)
{
    dTHX;
    char *s;
    unsigned long proto_buffers_len = 0;
    int error_code;
    SOCKET out = INVALID_SOCKET;

    if ((s = PerlEnv_getenv("PERL_ALLOW_NON_IFS_LSP")) && atoi(s))
        return WSASocket(af, type, protocol, NULL, 0, 0);

    if (WSCEnumProtocols(NULL, NULL, &proto_buffers_len, &error_code) == SOCKET_ERROR
        && error_code == WSAENOBUFS)
    {
	WSAPROTOCOL_INFOW *proto_buffers;
        int protocols_available = 0;       
 
        Newx(proto_buffers, proto_buffers_len / sizeof(WSAPROTOCOL_INFOW),
            WSAPROTOCOL_INFOW);

        if ((protocols_available = WSCEnumProtocols(NULL, proto_buffers, 
            &proto_buffers_len, &error_code)) != SOCKET_ERROR)
        {
            int i;
            for (i = 0; i < protocols_available; i++)
            {
                WSAPROTOCOL_INFOA proto_info;

                if ((af != AF_UNSPEC && af != proto_buffers[i].iAddressFamily)
                    || (type != proto_buffers[i].iSocketType)
                    || (protocol != 0 && proto_buffers[i].iProtocol != 0 &&
                        protocol != proto_buffers[i].iProtocol))
                    continue;

                if ((proto_buffers[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0)
                    continue;

                convert_proto_info_w2a(&(proto_buffers[i]), &proto_info);

                out = WSASocket(af, type, protocol, &proto_info, 0, 0);
                break;
            }
        }

        Safefree(proto_buffers);
    }

    return out;
}
Beispiel #3
0
//
// Function: EnumerateProvidersExisting
//
// Description:
//      This function enumerates the catalog into a preallocated buffer.
//
int
EnumerateProvidersExisting(
    WINSOCK_CATALOG     Catalog, 
    WSAPROTOCOL_INFOW  *ProtocolInfo,
    LPDWORD             ProtocolInfoSize
    )
{
	INT                 ErrorCode = NO_ERROR,
                        rc = NO_ERROR;
    
#ifdef _WIN64
    if ( LspCatalog64Only == Catalog )
    {
        rc = WSCEnumProtocols( NULL, ProtocolInfo, ProtocolInfoSize, &ErrorCode );
    }
    else if ( LspCatalog32Only == Catalog )
    {
        rc = WSCEnumProtocols32( NULL, ProtocolInfo, ProtocolInfoSize, &ErrorCode );
    }
#else
    if ( LspCatalog32Only == Catalog )
    {
        rc = WSCEnumProtocols( NULL, ProtocolInfo, ProtocolInfoSize, &ErrorCode );
    }
    else if ( LspCatalog64Only == Catalog )
    {
        dbgprint( "Unable to enumerate 64-bit Winsock catalog from 32-bit process!" );
    }
#endif
    if ( SOCKET_ERROR == rc )
    {
        dbgprint( "EnumerateProvidersExisting: WSCEnumProviders failed: %d",
                GetLastError() );
    }

	return rc;
}
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);
}
bool HasIPv6Enabled() {
#ifndef WIN32
  // We only need to check this for Windows XP (so far).
  return true;
#else
  if (IsWindowsVistaOrLater()) {
    return true;
  }
  if (!IsWindowsXpOrLater()) {
    return false;
  }
  DWORD protbuff_size = 4096;
  scoped_array<char> protocols;
  LPWSAPROTOCOL_INFOW protocol_infos = NULL;
  int requested_protocols[2] = {AF_INET6, 0};

  int err = 0;
  int ret = 0;
  // Check for protocols in a do-while loop until we provide a buffer large
  // enough. (WSCEnumProtocols sets protbuff_size to its desired value).
  // It is extremely unlikely that this will loop more than once.
  do {
    protocols.reset(new char[protbuff_size]);
    protocol_infos = reinterpret_cast<LPWSAPROTOCOL_INFOW>(protocols.get());
    ret = WSCEnumProtocols(requested_protocols, protocol_infos,
                           &protbuff_size, &err);
  } while (ret == SOCKET_ERROR && err == WSAENOBUFS);

  if (ret == SOCKET_ERROR) {
    return false;
  }

  // Even if ret is positive, check specifically for IPv6.
  // Non-IPv6 enabled WinXP will still return a RAW protocol.
  for (int i = 0; i < ret; ++i) {
    if (protocol_infos[i].iAddressFamily == AF_INET6) {
      return true;
    }
  }
  return false;
#endif
}
Beispiel #6
0
void zmq::pgm_socket_t::open_transport ()
{
    SOCKADDR_IN salocal;
    SOCKADDR_IN sasession;

    zmq_log (1, "Opening PGM: network  %s, port %i, %s(%i)\n",
        network, port_number, __FILE__, __LINE__);
    
    //  Check if the machine supports PGM.
    int	protocol_list[] = { IPPROTO_RM, 0 };
    WSAPROTOCOL_INFOW*	lpProtocolBuf = NULL;
    DWORD dwBufLen = 0;
    int err;
    int protocols = WSCEnumProtocols (protocol_list, lpProtocolBuf, 
        &dwBufLen, &err);
    if (protocols != SOCKET_ERROR)
        assert (false);
    else if (err != WSAENOBUFS)
        assert (false);

    //  Allocate needed space for lpProtocolBuf.
    lpProtocolBuf = (WSAPROTOCOL_INFOW*)malloc (dwBufLen);
    if (lpProtocolBuf == NULL)
        assert (false);

    //  Get information about available protocols, the information will be
    //  placed to lpProtocolBuf.
	protocols = WSCEnumProtocols (protocol_list, lpProtocolBuf, 
        &dwBufLen, &err);
    if (SOCKET_ERROR == protocols) {
        free (lpProtocolBuf);
        assert (false);
    }

    bool found = FALSE;
    for (int i = 0; i < protocols; i++) {
        if (AF_INET == lpProtocolBuf[i].iAddressFamily &&
              IPPROTO_RM == lpProtocolBuf[i].iProtocol &&
              SOCK_RDM == lpProtocolBuf[i].iSocketType) {
            found = TRUE;
            break;
        }
    }

    if (!found) {
        fprintf (stderr, "PGM support is not installed on this machine.");
        free (lpProtocolBuf);
        assert (false);
    }

	free (lpProtocolBuf);
        
    //  Receiver transport.
    if (receiver) {

        receiver_listener_socket = socket (AF_INET, SOCK_RDM, IPPROTO_RM);
        wsa_assert (receiver_listener_socket != INVALID_SOCKET);

        // The bind port (port_number) specified should match that
        // which the sender specified in the connect call.
        salocal.sin_family = AF_INET;
        salocal.sin_port   = htons (port_number);
        salocal.sin_addr.s_addr = inet_addr (multicast);

        int rc = bind (receiver_listener_socket, (SOCKADDR *) &salocal, 
            sizeof(salocal));
        wsa_assert (rc != SOCKET_ERROR);

        rc = listen (receiver_listener_socket, 10);
        wsa_assert (rc != SOCKET_ERROR);

        //  Set the socket to non-blocking mode.
        u_long flag = 1;
        rc = ioctlsocket (receiver_listener_socket, FIONBIO, &flag);
        wsa_assert (rc != SOCKET_ERROR);
 
    //  Sender transport.
    } else {

        sender_socket = socket (AF_INET, SOCK_RDM, IPPROTO_RM);
        wsa_assert (sender_socket != INVALID_SOCKET);
        salocal.sin_family = AF_INET;
        salocal.sin_port   = htons (0);        // Port is ignored here
        salocal.sin_addr.s_addr = htonl (INADDR_ANY);

        int rc = bind (sender_socket, (SOCKADDR *)&salocal, sizeof(salocal));
        wsa_assert (rc != SOCKET_ERROR);
        int to_preallocate = 0;

        // Set socket options.
        ULONG val = 1;
        setsockopt (sender_socket, IPPROTO_RM, RM_HIGH_SPEED_INTRANET_OPT, 
            (char*)&val, sizeof(val));

        //  Set the socket to non-blocking mode.
        u_long flag = 1;
        rc = ioctlsocket (sender_socket, FIONBIO, &flag);
        wsa_assert (rc != SOCKET_ERROR);

        // Set the outgoing interface.
        ULONG send_iface;
        send_iface = inet_addr (network);
        rc = setsockopt (sender_socket, IPPROTO_RM, RM_SET_SEND_IF,
            (char *)&send_iface, sizeof(send_iface));
        wsa_assert (rc != SOCKET_ERROR);

        //  Set window size.
        //  Parameter WindowSizeInBytes is calculated automaticaly as
        //  send_window.WindowSizeInBytes = 
        //  send_window.RateKbitsPerSec * send_window.WindowSizeInMSecs / 8.
        assert (pgm_max_rte >= 1000);
        assert (pgm_secs != 0);
        RM_SEND_WINDOW send_window;
        send_window.RateKbitsPerSec = (pgm_max_rte / 1024) * 8;
        send_window.WindowSizeInMSecs = pgm_secs * 1000;

        //  Parameter WindowSizeInBytes is calculated automaticaly as:
        send_window.WindowSizeInBytes =
            send_window.RateKbitsPerSec * send_window.WindowSizeInMSecs / 8;
        
        //  Set multicast address and port number.
        sasession.sin_family = AF_INET;
        sasession.sin_port = htons (port_number);
        sasession.sin_addr.s_addr = inet_addr (multicast);
        
        rc = setsockopt (sender_socket, IPPROTO_RM, RM_RATE_WINDOW_SIZE, 
            (char *) &send_window, sizeof (send_window));
        wsa_assert (rc != SOCKET_ERROR);

        rc = connect (sender_socket, (SOCKADDR *)&sasession, 
            sizeof(sasession));
        wsa_assert (rc != SOCKET_ERROR);
    }
}
Beispiel #7
0
//
// Function: GetProviders
//
// Description:
//    This enumerates the Winsock catalog via the global variable ProtocolInfo.
//
LPWSAPROTOCOL_INFOW 
EnumerateProviders(
    WINSOCK_CATALOG Catalog, 
    LPINT           TotalProtocols
    )
{
	LPWSAPROTOCOL_INFOW ProtocolInfo = NULL;
	DWORD               ProtocolInfoSize = 0;
	INT                 ErrorCode = NO_ERROR,
                        rc;
    
    if ( NULL == TotalProtocols )
        goto cleanup;

	*TotalProtocols = 0;

#ifdef _WIN64
	// Find out how many entries we need to enumerate
    if ( LspCatalog64Only == Catalog )
    {
        // Find the size of the buffer
        rc = WSCEnumProtocols( NULL, ProtocolInfo, &ProtocolInfoSize, &ErrorCode );
        if ( SOCKET_ERROR == rc )
        {
            if ( WSAENOBUFS != ErrorCode )
                goto cleanup;
            ErrorCode = NO_ERROR;
        }

        // Allocate the buffer
        ProtocolInfo = (LPWSAPROTOCOL_INFOW) LspAlloc(
                ProtocolInfoSize,
               &ErrorCode
                );
        if (ProtocolInfo == NULL)
            goto cleanup;

        // Enumerate the catalog for real
        rc = WSCEnumProtocols( NULL, ProtocolInfo, &ProtocolInfoSize, &ErrorCode );
        if ( SOCKET_ERROR == rc )
            goto cleanup;

        // Update the count
        *TotalProtocols = rc;
    }
    else if ( LspCatalog32Only == Catalog )
    {
        HMODULE            hModule;
        LPWSCENUMPROTOCOLS fnWscEnumProtocols32 = NULL;

        // Load ws2_32.dll
        hModule = LoadLibrary( TEXT( "ws2_32.dll" ) );
        if ( NULL == hModule )
            goto cleanup;

        // Find the 32-bit catalog enumerator
        fnWscEnumProtocols32 = (LPWSCENUMPROTOCOLS) GetProcAddress(
                hModule, 
                TEXT( "WSCEnumProtocols32" )
                );
        if ( NULL == fnWscEnumProtocols32 )
            goto cleanup;
        
        // Find the required buffer size
        rc = fnWscEnumProtocols32(NULL, ProtocolInfo, &ProtocolInfoSize, &ErrorCode);
        if ( SOCKET_ERROR == rc )
        {
            if ( WSAENOBUFS != ErrorCode )
                goto cleanup;
            ErrorCode = NO_ERROR;
        }

        // Allocate the buffer
        ProtocolInfo = (LPWSAPROTOCOL_INFOW) LspAlloc(
                ProtocolInfoSize,
               &ErrorCode
                );
        if ( NULL == ProtocolInfo )
            goto cleanup;

        // Enumrate the catalog for real this time
        rc = fnWscEnumProtocols32( NULL, ProtocolInfo, &ProtocolInfoSize, &ErrorCode );
        if ( SOCKET_ERROR == rc )
            goto cleanup;

        // Update the count 
        *TotalProtocols = rc;

        FreeLibrary( hModule );
    }
#else
    if ( LspCatalog32Only == Catalog )
    {
        // Find the size of the buffer
        rc = WSCEnumProtocols( NULL, ProtocolInfo, &ProtocolInfoSize, &ErrorCode );
        if ( SOCKET_ERROR == rc )
        {
            if ( WSAENOBUFS != ErrorCode )
                goto cleanup;
            ErrorCode = NO_ERROR;
        }

        // Allocate the buffer
        ProtocolInfo = (LPWSAPROTOCOL_INFOW) LspAlloc(
                ProtocolInfoSize,
               &ErrorCode
                );
        if ( NULL == ProtocolInfo )
            goto cleanup;

        // Enumerate the catalog for real
        rc = WSCEnumProtocols( NULL, ProtocolInfo, &ProtocolInfoSize, &ErrorCode );
        if ( SOCKET_ERROR == rc )
            goto cleanup;

        // Update the count
        *TotalProtocols = rc;
    }
    else if ( LspCatalog64Only == Catalog )
    {
        dbgprint( "Unable to enumerate 64-bit Winsock catalog from 32-bit process!");
    }
#endif
    else
    {
        // Find the size of the buffer
        rc = WSCEnumProtocols( NULL, ProtocolInfo, &ProtocolInfoSize, &ErrorCode );
        if ( SOCKET_ERROR == rc )
        {
            if ( WSAENOBUFS != ErrorCode )
                goto cleanup;
            ErrorCode = NO_ERROR;
        }

        // Allocate the buffer
        ProtocolInfo = (LPWSAPROTOCOL_INFOW) LspAlloc(
                ProtocolInfoSize,
               &ErrorCode
                );
        if ( NULL == ProtocolInfo )
            goto cleanup;

        // Enumerate the catalog for real
        rc = WSCEnumProtocols( NULL, ProtocolInfo, &ProtocolInfoSize, &ErrorCode );
        if ( SOCKET_ERROR == rc )
            goto cleanup;

        // Update the count
        *TotalProtocols = rc;
    }

cleanup:

    if ( ( NO_ERROR != ErrorCode ) && ( NULL != ProtocolInfo ) )
    {
        LspFree( ProtocolInfo );
        ProtocolInfo = NULL;
    }

	return ProtocolInfo;
}
Beispiel #8
0
//------------------------------------------------------------------------
//  InstallLSP()
//
//  Install the msrlsp into the Winsock2 WSP chains.
//
//------------------------------------------------------------------------
void InstallLSP()
    {
    int                  i;
    int                  EnumResult;
    int                  iError;
    LONG                 lStatus;
    DWORD                CatalogEntryId;
    LPWSAPROTOCOL_INFOW  ProtocolInfoBuff = NULL;
    DWORD                ProtocolInfoBuffSize = 0;
    BOOL                 EntryIdFound;


    // Install the WSAPROTOCOL_INFOW for the layered provider.
    lStatus = InstallRestrictedLSP( &CatalogEntryId );

    if (NO_ERROR == lStatus)
        {
        //
        // Enumerate the installed providers and chains
        //

        // Call WSCEnumProtocols with a zero length buffer so we know what
        // size to  send in to get all the installed PROTOCOL_INFO
        // structs. 
        WSCEnumProtocols( NULL,
                          ProtocolInfoBuff,
                          & ProtocolInfoBuffSize,
                          &iError);

        ProtocolInfoBuff = (LPWSAPROTOCOL_INFOW)new char [ProtocolInfoBuffSize];

        if (ProtocolInfoBuff)
            {
            EnumResult = WSCEnumProtocols(
                NULL,                     // lpiProtocols
                ProtocolInfoBuff,         // lpProtocolBuffer
                & ProtocolInfoBuffSize,   // lpdwBufferLength
                &iError );
            
            if (SOCKET_ERROR != EnumResult)
                {
                // Find our provider entry to get our catalog entry ID
                EntryIdFound = FALSE;
                for (i=0; i<EnumResult; i++)
                    {
                    if (!memcmp(&ProtocolInfoBuff[i].ProviderId,
                                &LayeredProviderGuid,
                                sizeof(GUID)))
                        {
                        
                        CatalogEntryId =
                            ProtocolInfoBuff[i].dwCatalogEntryId;
                        EntryIdFound = TRUE;
                        break;
                        }
                    }

                if (EntryIdFound)
                    {
                    for (i=0; i<EnumResult; i++)
                        {
                        if (  (ProtocolInfoBuff[i].iAddressFamily == AF_INET)
                           && (ProtocolInfoBuff[i].iProtocol == IPPROTO_TCP) )
                            {
                            InstallNewChain( &ProtocolInfoBuff[i],
                                             CatalogEntryId );
                            break;
                            }
                        }
                    }
                }
            }
        }
    }
Beispiel #9
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;
}