How to determine if a non-IFS LSP is installed

Enabling FILE_SKIP_COMPLETION_PORT_ON_SUCCESS on a handle associated with an I/O completion port can improve performance and reduce context switching by allowing the thread that calls the API that can complete asynchronously to handle the completion “inline” if the call can complete synchronously. This is especially useful for TCP reads when there’s already data in the network stack’s buffers, or writes when there is space in the buffers. Whilst there are design issues that must be taken into consideration before simply enabling this flag (beware recursion!) there’s a little known issue where code outside of your control can prevent the IOCP from operating correctly when this flag is enabled.

If non-IFS Winsock Base Service Providers (BSPs) or Layered Service Providers (LSPs) are installed then you may not receive completions at all for handles with the flag set.

This Microsoft Knowledge Base article has been around for quite a few years and it’s important and possibly becoming more so as more and more poorly written LSPs get installed by adware and other rubbish.

It’s all very well knowing that you can’t use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS when you have a non-IFS LSP installed but how can you tell at runtime that this is the case?

We’ve had this code in The Server Framework since 2011 or so: it iterates the Winsock catalogue and lets you know if any non-IFS LSPs are installed. You can then use the results of this to determine if it’s safe to enable FILE_SKIP_COMPLETION_PORT_ON_SUCCESS or not.

static const int s_protocols[] = { IPPROTO_TCP, IPPROTO_UDP, 0 };

bool CanEnableSkipCompletionPortOnSuccess()
{
   // At some point we MAY want to check for UDP and TCP transports separately,
   // if we do that then we need to change this.

   TExpandableBuffer<BYTE> buffer;

   LPWSAPROTOCOL_INFOW pProtocolInfo = nullptr;

   DWORD bufferLength = 0;

   int error = 0;

   int numEntries = ::WSCEnumProtocols(
      const_cast<int *>(&s_protocols[0]),
      pProtocolInfo,
      &bufferLength,
      &error);

   if (SOCKET_ERROR != numEntries)
   {
      throw CException(
         _T("CanEnableSkipCompletionPortOnSuccess()"),
         _T("Expected first call to fail and return buffer size!"));
   }

   int attempts = 0;

   bool done = false;

   while (!done)
   {
      if (error != WSAENOBUFS)
      {
         throw CWin32Exception(
            _T("CanEnableSkipCompletionPortOnSuccess()"),
            error);
      }

      if (attempts++ > 3)
      {
         // so the amount of memory required is always changing??

         throw CException(
            _T("CanEnableSkipCompletionPortOnSuccess()"),
            _T("Cannot allocate appropriate buffer: ") +
            ToString(bufferLength));
      }

      buffer.Resize(bufferLength);

      pProtocolInfo = reinterpret_cast<LPWSAPROTOCOL_INFOW>(buffer.GetBuffer());

      numEntries = ::WSCEnumProtocols(
         const_cast<int *>(&s_protocols[0]),
         pProtocolInfo,
         &bufferLength,
         &error);

      done = (SOCKET_ERROR != numEntries);
   }

   bool ok = true;

   for (int i = 0; ok && i < numEntries; ++i)
   {
      ok = ((pProtocolInfo[i].dwServiceFlags1 & XP1_IFS_HANDLES) == XP1_IFS_HANDLES);
   }

   return ok;
}