A while back a client of mine had an issue with a TLS 1.2 connection failing during the TLS handshake. We couldn't see any issues with the code and if we only enabled TLS 1.1 on the server then the connection handshake worked just fine.

Eventually we tracked the issue down to the fact that the certificate in use had been signed with MD5 and that MD5 isn't a valid hash algorithm for TLS 1.2 and so the handshake failed when SChannel attempted to validate the certificate and found that it was unacceptable. There's a Microsoft blog posting about this problem here.

Annoyingly the error message for this is: "The client and server cannot communicate, because they do not possess a common algorithm." which is bang on the money, but doesn't help much until after you've worked out what the problem is. We were already dumping out the enabled algorithms and protocols and couldn't understand why the connection either wasn't working or wasn't downgrading to TLS 1.1.

I've now added some certificate investigation code to the point where my example SChannel servers set up their contexts. This at least allows me to warn and degrade to TLS 1.1 if the certificate is not going to work with TLS 1.2. In production systems I expect we'd just fail to start up.

   CCredentials::Data data;

   data.cCreds = 1;
   data.paCred = &pCertContext;

   // Note that for TLS 1.2 you need a certificate that is signed with SHA1 and NOT MD5.
   // If you have an MD5 certificate then TLS 1.2 will not connect and will NOT downgrade
   // to TLS 1.1 or something else...

   DWORD dataSize = 0;

   if (::CertGetCertificateContextProperty(
      ByteBuffer buffer(dataSize);

      BYTE *pData = buffer.GetBuffer();

      if (::CertGetCertificateContextProperty(
         const _tstring signHashDetails(reinterpret_cast<tchar *>(pData), dataSize);

         if (signHashDetails.find(_T("MD5")) != _tstring::npos)
            if (enabledProtocols == 0 || enabledProtocols & SP_PROT_TLS1_2)
               OutputEx(_T("Certificate is signed with: ") + signHashDetails);
               OutputEx(_T("MD5 hashes do not work with TLS 1.2 and connection downgrade does NOT occur"));
               OutputEx(_T("This results in failure to connect. Disabling TLS 1.2"));

               if (enabledProtocols)
                  enabledProtocols &= ~SP_PROT_TLS1_2;

               if (!enabledProtocols)
                  // if enabledProtocols is zero then all protocols are
                  // enabled, so we need to explicitly enable everything
                  // except TLS1.2

                  enabledProtocols = SP_PROT_SSL3TLS1;

   data.grbitEnabledProtocols = enabledProtocols;

Latest release of The Server Framework: 6.6.4

Version 6.6.4 of The Server Framework was released today.

This release is mainly a bug fix release for clients using WebSockets over SSL.

As always, see the release notes here, for full details of all changes.

Bug fixes:

  • Bug fix to JetByteTools::Win32::CallbackTimerQueueBase which prevents the timeout handle from ever being incremented to zero. It's unlikely but possible.
  • Bug fix to JetByteTools::Win32::CBuffer and JetByteTools::Win32::CLockFreeBuffer to make code take notice of when m_maxBytesToRead is set. This was causing issues with WebSockets over SSL where the WebSocket code was setting a max read value and the SSL connector was ignoring it and providing more data than it should.
  • Bug fix to JetByteTools::SSPI::SChannel::CAsyncConnector::PerformWrite() so that we deal with exceptions appropriately.
  • Bug fix to JetByteTools::Socket::CFilterDataBase::WriteData() so that we deal with exceptions appropriately.
  • Bug fix for a highly unlikely possible situation in JetByteTools::WebSocket::HyBi::CProtocolHandler::HandleData() where a buffer in the read request buffers queue contains no space for more data.


  • Adjusted all includes to remove relative paths and instead be absolute in relation to the library root. So, rather than #include "..\Blah.h" it would always be #include "JetByteTools\Lib\Blah.h" this is due to a new warning in Visual Studio 2015 update 1.
  • Added JetByteTools::Socket::ListenBacklogMaxwhich is a JetByteTools::Socket::ListenBacklog value that can be used to cause the listen queue for a socket to be set to SOMAXCONN.
  • Added JetByteTools::Socket::TStreamSocketServerEx::SoMaxNumPendingAccepts which is the number of accepts that are posted if a listen backlog of JetByteTools::Socket::ListenBacklogMax is specified for the number of pending accepts. At present this is set to 200.
  • Added JetByteTools::Socket::TStreamSocketServerEx::SetListeningParameters() which can be called after construction but before starting to accept connections and can specify the listen backlog and number of receives to post separately. This allows you to set the listen backlog to SOMAXCONN using JetByteTools::Socket::ListenBacklogMax and set the number of receives to something other than JetByteTools::Socket::TStreamSocketServerEx::SoMaxNumPendingAccepts. You can also set a flag which tells the server not to close the listening socket when the server reaches a connection limit, instead it will simply stop posting accepts and so new connections will get to wait in the listen queue until they time out or until the server posts a new accept request.
  • Bug fix to to JetByteTools::Socket::TStreamSocketServerEx so that OnMaxConnections() is called correctly when the connection limit is reached. Previously it would often only be called the first time that the limit was reached.

SChannel ALPN support, documentation "bug"...


I'm looking at adding support for the TLS Application-Layer Protocol Negotiation Extension to The Server Framework as a precursor to looking into HTTP 2.0 support. This TLS extension is supported by both SChannel and OpenSSL. It's relatively new (only having been included in SChannel since June 2014 (!)) but there seems to be no documentation on MSDN for the structures and how to use them to add the appropriate entries to the TLS handshake and then to select and validate the protocol of your choice... Searching today with Google for something like "SEC_APPLICATION_PROTOCOL_NEGOTIATION_EXT" just gives just the usual selection of hits to people who think it's clever to run the Windows header files through their document generators and then publish the results on the web...

It's slightly easier with OpenSSL, but only because I can look at the source...

Anyway, long story short, I have the OpenSSL version working and am getting an HTTP 2.0 Connection Prefix from Chrome... I guess, for now, SChannel will have to wait.

I expect I'm being dense...

There should be a Developer Advocate position within Microsoft. They seriously need someone who doesn't "Drink the Kool-Aid" who can step in and tell the Program Managers or Marketing bods or whoever it is who makes all the really STUPID decisions that the decision is stupid and that they should get back in their box and leave the developers who support the Windows ecosystem by building software that runs on it to just get on with their lives...

Yes, this is going to be a rant...

So someone has decided that being able to query which version of the Operating System that your program is running on is a bad thing. If you try and call GetWindowsVersionEx() on Windows 8.1 or Windows 10 and you haven't specifically set your application's manifest to say that it's compatible with Windows 8.1 or Windows 10 then GetWindowsVersionEx() will lie to you and tell you that you're running on Windows 8.

Excuse me, but that's just brain dead. There's NO valid reason for doing this because you can't know WHY the caller needs this information.

OK, so it might be better, in some circumstances, to be checking for the presence of various function entry points in various dlls and dynamically working out that what you need is present BUT that's not the only reason that you might want to know what OS you're running on and it's not even the only GOOD reason.

My current situation is that Windows 10 spawns a conhost.exe process whenever you start a console process. The test code that I have for my Win32 Job API wrapper includes some checks to determine that the correct job accounting data is being returned from some test programs that it spawns. This accounting data is different under Windows 10 as there are more processes running within the job. Ideally I'd like to acknowledge that this is an OS difference, adjust the test to know that when it runs on this OS it needs to expect slightly different results and then move on with my life. Of course, as Microsoft has deliberately chosen to break the API that would let me cleanly work out what version I'm running on I have to spend time writing ranty blog postings and crufting up crappy work arounds.

As I said a while ago, Visual Studio 2015 appears to have lots of pretty serious bugs.

One that probably bites me more than many people is this Save As bug. If you have a project and you select a file in that project and do a "Save As" such that the target file is also in the project then the VS2015 IDE crashes.

I tweeted about this a while back, and the Visual Studio Program Manager, Cathy Sullivan, wanted me to create a new project and see if the problem happened with it... Not quite sure why she couldn't do this herself, but anyway, here's a zip of a project created with VS2015 where there's a file called SaveMeAsTargetver.h. If you save that file as targetver.h then the IDE crashes.

Latest release of The Server Framework: 6.6.3

Version 6.6.3 of The Server Framework was released today.

This release is mainly a bug fix release but it also adds support for Visual Studio 2015 and Windows 10 (though we don't explicitly use any Windows 10 APIs). There are quite a lot of small changes due to us running Gimpel Lint over the code. Most of the changes will have fixed potential issues rather than issues that have actually been reported.

However, there are two serious fixes for the SChannel Option Pack for an issue that was introduced in Release 6.6.2 and which could cause corruption of the data flow in some situations and stalling and CPU pegging in another. There is also a fix which may prevent UDP datagram corruption, See here for more details.

As always, see the release notes here, for full details of all changes.

All clients using Release 6.6.2 of the SChannel Option Pack are advised to upgrade to this release.

Bug fixes:

  • JetByteTools::IO::CBuffer::Clear() which now correctly sets m_ioSize to zero.
  • JetByteTools::IO::CBufferList::BufferData so that it cannot access pBuffer before it's initialised.
  • JetByteTools::IO::CLockableBufferProcessor::~CLockableBufferProcessor() to remove potential buffer leak.
  • JetByteTools::IO::CAsyncFileReader where we were checking the validity of data response flags incorrectly.
  • JetByteTools::SSPI::SChannel::CAsyncConnector::PerformWrite() where we could sometimes send invalid data.
  • JetByteTools::SSPI::SChannel::CAsyncConnector where we could sometimes get stuck in an infinite loop if we had decrypted data available but no application level read pending.
  • JetByteTools::Service::CService::ServiceMain() so that we set and clear the m_serviceStarting flag correctly.
  • Fix to all WSASend() and WSARecv() calls to prevent multiple threads from calling into the API on the same socket at the same time. See here for more details.
  • JetByteTools::Win32::CCallbackTimerWheel::EndTimeoutHandling() where we were leaking one shot timers.
  • JetByteTools::Win32::CThreadPool::OnThreadPoolThreadStopped() and JetByteTools::Win32::CThreadPoolEx::OnThreadPoolThreadStopped() so that the call to the monitor's OnThreadPoolStopped() function is consistent and in the right place.
  • JetByteTools::Win32::CSmartHandle to deal with closing pseudo thread or process handles.
  • Fix to JetByteTools::Socket::CFilterDataBase to ensure that each filter knows how many writes it has issued and that they pass completions to the next layer when they should.
  • JetByteTools::Win32::TReusableIdManager::InternalTryFree() so that we now correctly merge intervals. Note that this bug was purely in the way we stored the intervals (which was less efficient than it could be) and did not affect the function of the manager.
  • JetByteTools::Win32::TZeroInitialiseExpandableBuffer::Resize() so that it doesn't trash memory if you reduce the size of the buffer.
  • JetByteTools::Win32::TZeroInitialiseExpandableBuffer a fix to the assignment operator so that it actually compiles and works.


  • Ran Visual Lint using Gimpel PC Lint on all code and adjusted to remove warnings and fix bugs.
  • Added support for Visual Studio 2015.
  • Removed all use of exception specifications. We only ever used throw() but that's now gone too.
  • Protected non-virtual destructors on interfaces are now virtual even though they you can't delete the object via the interface.
  • All destructors that could throw exceptions now have optional "log and swallow" exception handlers which are enabled by default. This is better than ignoring the problem and being faced with a call to std::terminate() which can be hard to track down.
  • Changed JetByteTools::IO::CNonPooledBuffer so that it doesn't have to be immutable. You can now create a non-pooled buffer and add data to it after creation.
  • Added JetByteTools::IO::CBufferChain::AvailableSpace() and JetByteTools::IO::CBufferChain::HasAvailableSpace()
  • Added JetByteTools::IO::CBufferChain::RemoveAsSingleBuffer() which will either consolidate a chain into the first buffer (if all the data will fit) or create a JetByteTools::IO::CNonPooledBuffer of the required size and return the data inthe new buffer.
  • Added the concept of a "purge handler" for buffer chains. This comes in the form of an interface JetByteTools::IO::CBufferChain::IHandlePurgedBufferRelease and a new override for JetByteTools::IO::CBufferChain::Purge which takes a purge handler and some user data. If the new version of purge is called the purge handler is called for each buffer purged from the chain and it is responsible for disposing of the purged buffer, normally by calling Release() on it. The reason for this is that it's now possible to have a buffer chain of buffers which are 'detached' buffer chains. When purge is called in this situation a purge handler can now be supplied which recreates the buffer chains and, in turn, purges them.
  • Added new constructors for JetByteTools::IO::CAsyncFileWriter and JetByteTools::IO::CAsyncFileWriterEx that take a filename and a JetByteTools::Win32::CSmartHandle to an open file.
  • Changed constructor for JetByteTools::IO::CAsyncFileWriter that previously took a HANDLE to take a JetByteTools::Win32::CSmartHandle
  • Added JetByteTools::IO::CBufferAllocator::GetNumActive() and JetByteTools::IO::CBufferAllocator::GetNumPooled()
  • Added explicit support for building against OpenSSL libs built with VS2015 as previous versions are no longer link compatible. Note that these #pragma link lines assume our internal naming convention for OpenSSL libs.
  • Added JetByteTools::IO::CBufferChain::Detach(), JetByteTools::IO::CBufferChain::Attach() and JetByteTools::IO::CBufferChain::Splice(). These allow you to take a buffer chain and 'detach' it from the buffer chain object so that you can work in terms of a single buffer (with the additional buffers chained on in the normal way but inaccessible). You can then take such a buffer and 'attach' it back to a buffer chain object. This allows you to pass a buffer chain through an interface which only understands single buffers. Splice() allows you to take an existing buffer chain and add a 'detached' buffer chain to the end of it.
  • Changed the number of tabs used in the JetByteTools::Service::CServiceManager::GetExtraHelp() message so that the remove option lines up correctly. I think this may be a dialog font issue and it may be inconsistent on different platforms.
  • Added JetByteTools::Win32::CActivatableObject::CommandWrapper to remove duplication in the users of JetByteTools::Win32::CActivatableObject
  • Removed JetByteTools::Win32::CFileChangeMonitor as it was not used or compiled. The functionality is contained in JetByteTools::Win32::CDirectoryChangeMonitor.
  • Added JetByteTools::Win32::CNTPTime which converts SYSTEMTIME to and from NTP timestamps.
  • Changes to the various JetByteTools::Win32::ToString() implementations so that they remain consistent across Visual Studio versions. Visual Studio 2015 changes how precision is used in the printf family of functions and provides greater default precision. We limit precision to 17 in JetByteTools::Win32::ToString() so that the output is consistent with earlier versions of Visual Studio.
  • JetByteTools::Win32::TReusableIdManager::Release() now returns the id.
  • JetByteTools::Win32::CCommandLine::Parse() now takes a reference to a string that can be used to return an error message.
  • Added JetByteTools::Win32::IQueueTimers::SetTimerWithRefCountedTimer(), JetByteTools::Win32::IQueueTimers::CancelTimerWithRefCountedTimer() and JetByteTools::Win32::IQueueTimers::DestroyTimerWithRefCountedTimer() which deal with the common pattern of code required when the timer handle is a reference counted class.
  • Added JetByteTools::Win32::IQueueTimers::RefCountedTimer.
  • Added JetByteTools::Win32::IManageEnvironmentVariables::TryDeleteVariable().
  • Added locking to JetByteTools::Win32::CEnvironmentBlock so that it's now safe to use from multiple threads.
  • Added checking when we lock JetByteTools::Win32::TLockableObjectPotentialOwner<> and JetByteTools::Win32::TReentrantLockableObjectPotentialOwner<> so that an exception is thrown if it's already locked. Also changed how JetByteTools::Win32::TReentrantLockableObjectPotentialOwner<> is implemented as it was unnecessarilly complex.
  • Breaking Change VS2015's exponent doesn't include a leading 0 when calling sprintf, etc. This changes the output for some calls to JetByteTools::Win32::ToString() and makes it inconsistent with all previous releases.

As usual I have used VMs to play with the CTP releases for the new version of Visual Studio and fixed up new warnings and build failures in my source so that I'm not too surprised when the RTM comes along.

Unfortunately as soon as I put VS2015 RTM on my build server and started running it as part of my CI system I started noticing strange things...

The first is that it seems to be possible to get VS2015 into a state where it will refuse to load C++ projects. I've no idea how I've managed this, but it's now happened twice. Rebooting the machine seems to fix things. The log file that the failure indicates might help shows that it's trying to load a the "Visual Studio C++ Project System Package" and it's getting an E_POINTER result...

The second issue seems to be a race condition in shutting down the new process that's used to help various parts of VS communicate with each other, VSHub.exe. My CI system will fire up a Visual Studio instance to build a project using /build and once that completes another project is likely to get built, sometimes two VS2015 builds will follow one another, other times there are other versions of Visual Studio building in between. VS 2015 appears to start an instance of VSHub.exe but only if one isn't running (or, more likely, it always starts one but if one's already running then the new ones shut down). Then when the last instance of VS quits VSHub.exe hangs around for a moment and then shuts down... It seems to crash if it's shutting down when a new instance of VS2015 is started (and, presumably decides that the VSHub.exe that is shutting down is the one to use). A fix for this issue is simply to keep VSHub.exe alive for the entire time that all VS2015 builds need to run and I can do this by having an instance of VS2015 open on the build machine whilst the CI system is running...

Thanks to Abe10, in this thread, for the workaround for the VSHub.exe issue.

6 out of 10 for this VS release Microsoft, try harder. I hope the Windows 10 team have better QA.

I now have a real solution to the problem that I outlined on Saturday night and this solution, unlike the one developed during my "Macallan driven development" session on Saturday evening actually works.

The problem is that when using code to run build using VS2010 by running a project into devenv.com I get the following error message:

C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v12.0\CodeAnalysis\Microsoft.CodeAnalysis.targets(214,5): error MSB4175: The task factory "CodeTaskFactory" could not be loaded from the assembly "C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Build.Tasks.v12.0.dll". Could not load file or assembly 'file:///C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Build.Tasks.v12.0.dll' or one of its dependencies. The system cannot find the file specified.

The project builds correctly from the command window using the exact same command line as I use in my calls to CreateProcess().

I was on the right track on Saturday evening. It is an environment issue, just not the one that I thought it was. I also now understand why I thought I'd solved the problem on Saturday night only to discover that the fix didn't work when I checked it again on Sunday morning.

The problem is caused by the presence of "VisualStudioVersion" in the environment. This variable is set to 12.0 when my task runner program is run from within VS2013 either when debugging or running without the debugger attached but launching from within VS2013. The presence of this variable in the task runner's environment somehow causes VS2010 to use the latest version of MSBuild that ships with VS2013. When doing this MSBuild gets confused about which .Net framework directory to load assemblies from and fails to locate its dll. Removing the "VisualStudioVersion" from the inherited environment before launching VS2010 programatically fixes the problem.

Running my task running from a normal command prompt, rather than from inside of VS2013, allows it to work correctly without needing to remove the variable (as the variable is only added by VS2013 itself). I expect that I tested like this on Saturday night and that's what made me think I'd solved the problem them.

VS2013 actually adds several "VisualStudio" variables to the environment and I now remove all of them before running any task from my task runner.

Updated: 12 July 2015 - It seems that this is all incorrect... Upon running my tests again this morning I find that the x64 task runner also fails to run VS2010 correctly and so the environment differences are unlikely to be the cause...

So, having decided that my continuous integration system could be better, and having looked at JetBrains' TeamCity and decided that it doesn't quite fit I'm looking back at some code that I wrote back in 2008 when I last thought about this kind of thing...

I have some code which works with trees of dependant tasks and triggers sub tasks once the tasks they depend on complete successfully. The code uses CreateProcess() and Win32 Jobs to control the tasks and it can run builds and tests using the various flavours of Visual Studio installed on the box in question.

So far, so good as a starting point for an agent that can run multiple builds on a machine...

My problem, well, one of them, being that when using VS2010 by running a project into devenv.com I get the following error message:

C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v12.0\CodeAnalysis\Microsoft.CodeAnalysis.targets(214,5): error MSB4175: The task factory "CodeTaskFactory" could not be loaded from the assembly "C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Build.Tasks.v12.0.dll". Could not load file or assembly 'file:///C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Build.Tasks.v12.0.dll' or one of its dependencies. The system cannot find the file specified.

This is annoying, to say the least, VS2005, 2008 and 2012 and 2013 all work fine, it's just 2010 that fails. I googled the issue and the general consensus is that once you've installed VS2013 a different version of MSBuild is used. Of course that doesn't answer the question of why it 'works on my machine' except when my task runner is running the command...

Eventually I got the task runner to dump the environment and did the same from the command prompt where the command worked. The difference being that the command prompt that worked had an 'x64' environment and the task runner had a different, 'x86/win32' environment... This was because the task runner was a Win32 process. Running the task runner as x64 fixed the issue. So there's probably a bug in the VS2013 installation code that fails to set some environment variables for the Win32 command prompt that are required once it's "screwed with" the existing MSBuild installation on the box...

I'm expecting that manually adding the missing bits to the 'x86' environment will mean that the task runner will work as a Win32 build AND an x64 build...

Bug hunting


I've just spent a day tracking down a bug in a pending release of The Server Framework. It was an interesting, and actually quite enjoyable, journey but one that I shouldn't have had to make. The bug was due to a Windows API call being inserted between the previous API call and the call to GetLastError() to retrieve the error code on failure. The new API call overwrote the previous error value and this confused the error handling code for the previous API call. This was a bit of a "school boy error" and it was made worse by the fact that the code in question had a comment which clearly explained why nothing should be placed between the API call and the call to GetLastError().

About this Blog

I usually write about C++ development on Windows platforms, but I often ramble on about other less technical stuff...

This page contains recent content. Look in the archives to find all content.

I have other blogs...

Subscribe to feed The Server Framework - high performance server development
Subscribe to feed Lock Explorer - deadlock detection and multi-threaded performance tools
Subscribe to feed l'Hexapod - embedded electronics and robotics
Subscribe to feed MegèveSki - skiing