Steve Valliere
Steve Valliere

Reputation: 1207

Unable to recv data that recv(PEEK) returned

I was debugging some 64 bit, native C code using WinSock2 for TCP and after eliminating all of the errors I expected, I found out that WinSock2 was doing something I did not expect. Simplified for clarity, the code was doing this:

statOne = recv(sock,bufOne,1380,MSG_PEEK);
if( statOne == 1380 )
{
   statTwo = recv(sock,bufTwo,1380,0);
   if( statTwo == SOCKET_ERROR )
   {
      lastError = WSAGetLastError();
      MessageBox(hwnd,"How did this happen?",
                 "WinSock Error?",MB_OK);
   }
}

EXCEPT... the existing code was assuming that the second recv() call would always return the expected number of bytes and data that the previous PEEK call had returned. Instead, every once in a while the second recv() would return SOCKET_ERROR instead of any data! When I added the second if and message box, the message box would appear, but, like the original coder, I don't believe that should be possible if WinSock2 is working correctly.

This is a single-threaded Windows Desktop app that had only a single TCP connection.

I cannot find anything that indicates this might be expected behavior and I'm hoping someone can explain to me why WinSock2 does not have a serious bug if it is doing this.

I've been working with WinSock2 ever since it was introduced and I've never encountered this before. I have tried to create a minimal project that demonstrates this issue, but I've been unable to get it to trigger, except with the non-trivial example I was debugging. However, the recv(peek)/if/recv() sequence shown above is presented exactly as it is in the code, nothing except the if test is between the two recv() calls so there should be no possibility of some other code in the single-threaded program draining the TCP buffer.

Oh, please keep comments about never using MSG_PEEK to yourself, I already know the arguments against. Perhaps this bug is yet another argument to add to the list.

EDIT: I call the program "single threaded" because none of the program's source code calls any form of beginthread() function. That said, the Process Explorer shows that there are actually at least seven threads created by DLLs it uses: ucrtbased.dll, mswsock.dll, ntdll.dll, and winmm.dll. They not created (directly?) by the program code (i.e. beginthread or the like), not running our code, and IMHO, shouldn't be reading from our TCP sockets, but hey, its Microsoft, so who knows.

I have re-written the code and the issue no longer occurs. Unfortunately, that means I have no way to confirm the WSAGetLastError() value. I was under pressure to get it working and was so surprised that the second recv() could fail that I did not check everything I should've checked. Thanks for the reminders, though, if I see anything like this again, I'll come back and update this with more info.

Upvotes: 2

Views: 118

Answers (0)

Related Questions