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:
- Why does WSAPoll() always returns an updated socket, even if there wasn't any interaction with it ?
- 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.
sendto()
beforerecvfrom()
, so the problem's not there" doesn't make sense. You calledsendto()
, an ICMP UNREACH was return, and you detected it in the followingrecvfrom()
. – user207421sendto()
. You said so. And even if you hadn't, callingrecvfrom()
would also have done an implicit bind. Unclear what on earth you're talking about here. – user207421sendto()
beforerecvfrom()
or it would not work. I did not knowrecvfrom()
did an implicit bind too. My bad. – Heowyn