Windows UDP sockets: recvfrom() fails with error 10054

10,606

In Windows, if host A use UDP socket and call sendto() to send something to host B, but B doesn't bind any port so that B doesn't receive the message, and then host A call recvfrom() to receive some message, recvfrom() will failed, and WSAGetLastError() will return 10054.

It's a bug of Windows. If UDP socket recv a ICMP(port unreachable) message after send a message, this error will be stored, and next time call recvfrom() will return this error.

There are 2 ways to solve this problem:

  1. Make sure host B has already bound the port you want to send to.
  2. Disable this error by using following code:
#include <Winsock2.h>
#include <Mstcpip.h>
#include <stdio.h>

#pragma comment(lib, "ws2_32.lib")
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12)

BOOL bNewBehavior = FALSE;
DWORD dwBytesReturned = 0;
WSAIoctl(iSock, SIO_UDP_CONNRESET, &bNewBehavior, sizeof bNewBehavior, NULL, 0, &dwBytesReturned, NULL, NULL);

Reference: http://www.cnblogs.com/cnpirate/p/4059137.html

Share:
10,606

Related videos on Youtube

Heowyn
Author by

Heowyn

Updated on September 15, 2022

Comments

  • Heowyn
    Heowyn over 1 year


    Hello everyone.
    I'm trying to use Windows sockets to send and receive UDP packets (in C++).
    It worked well until three days ago, when the program stopped behaving properly.
    To summarize the situation:

    • When calling WSAPoll() on my socket, it always returns my socket updated with EVERY revents possible (corresponding to every events I gave the pollfd), even if there is no server launched.
    • When calling recvfrom() and no server is launched, it returns SOCKET_ERROR with error code 10054(*).
    • When calling recvfrom() and a server is launched, it works properly - blocks until it receives something.
    • The behavior is the same whether I try to connect to localhost or to a distant host.

    (*) I investigated this error. In UDP, it means that there is an ICMP problem. ("On a UDP-datagram socket this error indicates a previous send operation resulted in an ICMP Port Unreachable message.").
    I indeed call sendto() before recvfrom(), so the problem's not here.
    I tried to put down my firewall to see if it changed anything, but it didn't. I also tried to put down every network flowing through my PC. In this state I managed to get the program to work for a few minutes, but when I enabled the networks it stopped working again. I tried to repeat the process but it would not work anymore.
    I tried compiling with both visual studio (2015) and MinGW.
    I tried on another computer too (under Windows 7, mine has Windows 8.1), to no avail.

    Here is a simple test file which does not work on my computer.

    #undef _WIN32_WINNT
    #define _WIN32_WINNT 0x501
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <stdio.h>
    #include <vector>
    #include <iostream>
    
    int main() {
      int clientSock;
      char buf[100];
      int serverPort;
    
      /* Initializing WSA */
      WSADATA wsaData;
      WSAStartup(MAKEWORD(2, 2), &wsaData);
    
      /* I create my socket */
      struct addrinfo specs;
      struct addrinfo *addr = new addrinfo;
      ZeroMemory(&specs, sizeof(specs));
      specs.ai_family = AF_INET;
      specs.ai_socktype = SOCK_DGRAM;
      specs.ai_flags = 0;
      getaddrinfo("127.0.0.1", "2324", &specs, &addr);
    
      clientSock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
    
      /* I get the server's address */
      struct sockaddr_in serverAddr;
      serverAddr.sin_family = AF_INET;
      serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
      serverAddr.sin_port = htons(2324);
      int len = sizeof(struct sockaddr);
    
      /* I'll poll & recvfrom on my socket */
      std::vector<pollfd> fds;
      pollfd fd;
      fd.fd = clientSock;
      fd.events = POLLRDNORM;
      fd.revents = -1;
      fds.push_back(fd);
    
      while(1) {
        memset(buf,0,sizeof(buf));
        printf("\nClient--->: ");
        gets(buf);
        /* It's UDP, so it doesn't matter if there is someone to receive the packet */
        sendto(clientSock, buf, strlen(buf), 0, (sockaddr*)&serverAddr ,len);
    
        memset(buf,0,sizeof(buf));
        int ret;
        /* Always returns "1" */
        if ((ret = WSAPoll(fds.data(), 1, 0)) > 0) {
          std::cout << ret;
          /* Always returns "-1" */
          std::cout << recvfrom(clientSock,buf,sizeof(buf),0, (sockaddr*)&serverAddr,&len) << std::endl;
          printf("\n--->From the server: ");
          printf("%s",buf);
        }
      }
    
      closesocket(clientSock);
      WSACleanup();
    
      return 0;
    }
    

    Two questions:

    1. Why does WSAPoll() always returns an updated socket, even if there wasn't any interaction with it ?
    2. Why does recvfrom() return this error and how can I fix it ? I suppose it comes from my computer. I tried allowing ICMP through my firewall but it didn't change anything, maybe I did something wrong ?

    Edit: I fixed my main program (not shown here because it is way too large) by just ignoring any "error 10054" I received. Now it works the same way it does on Unix.
    Still, it is not really a solution (ignoring an error code... meh) and if anyone knows why I get the "ICMP Port Unreachable" error when calling sendto(), I'd be glad to hear about it.

  • Njål Arne Gjermundshaug
    Njål Arne Gjermundshaug over 6 years
    Thanks for providing the answer. Here's how to do it with a boost socket in case someone else needs to: WSAIoctl(boostSocket.get()->native(), SIO_UDP_CONNRESET, &bNewBehavior, sizeof bNewBehavior, NULL, 0, &dwBytesReturned, NULL, NULL);