2

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.

6
  • 5
    What does recv(sock,bufTwo,1380,0) actually return? If it fails (it returns SOCKET_ERROR) then what is the error you get (what does WSAGetLastError() give you)? Commented Jul 2, 2024 at 12:36
  • The only way I know for a non-peek recv to fall immediately after a successful peek is if another thread recv's the data before the failing recv. But that doesn't seem to be the case here. Commented Jul 2, 2024 at 14:54
  • Could you please show a minimal, reproducible sample without private information? Commented Jul 3, 2024 at 6:03
  • Maybe errno is set to EAGAIN because the resource was temoprarily unavailable? Please check (and post!) the errno value after the second recv() call returns error! Commented Jul 3, 2024 at 7:44
  • 1
    Why do you think you received exactly 1372 bytes? Reminder, just because you sent 1372 in one chunk does not mean you will receive it in one chunk. Tcp is a streaming protocol, nota message protocol Commented Jul 3, 2024 at 14:20

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.