bitcoinwinsock2recv

Winsock2, BitCoin Select() returns data to read, Recv() returns 0 bytes


I made a connection to BitCoin node via WinSock2. I sent the proper "getaddr" message and then the server responds, the replied data are ready to read, because Select() notifies this, but when I call Recv() there are 0 bytes read.

My code is working OK on localhost test server. The incomplete "getaddr" message (less than 24 bytes) is NOT replied by BitCoin node, only proper message, but I can't read the reply with Recv(). After returning 0 bytes, the Select() still returns there are data to read.

My code is divided into DLL which uses Winsock2 and the main() function.

Here are key fragments:

struct CMessageHeader
{
    uint32_t magic;
    char command[12];
    uint32_t payload;
    uint32_t checksum;
};

CSocket *sock = new CSocket();
int actual; /* Actually read/written bytes */

sock->connect("109.173.41.43", 8333);

CMessageHeader msg = { 0xf9beb4d9, "getaddr\0\0\0\0", 0, 0x5df6e0e2 }, rcv = { 0 };

actual = sock->send((const char *)&msg, sizeof(msg));

actual = sock->select(2, 0); /* Select read with 2 seconds waiting time */

actual = sock->receive((char *)&rcv, sizeof(rcv));

The key fragment of DLL code:

int CSocket::receive(char *buf, int len)
{
    int actual;

    if ((actual = ::recv(sock, buf, len, 0)) == SOCKET_ERROR) {
        std::ostringstream s;

        s << "Nie mozna odebrac " << len << " bajtow.";
        throw(CError(s));
   }
   return(actual);
}

Solution

  • If select() reports the socket is readable, and then recv() returns 0 afterwards, that means the peer gracefully closed the connection on their end (ie, sent a FIN packet to you), so you need to close your socket.

    On a side note, recv() can return fewer bytes than requested, so your receive() function should call recv() in a loop until all of the expected bytes have actually been received, or an error occurs (same with send(), too).