Forum Discussion
JVD66
Mar 09, 2021Copper Contributor
winsock2 's recvfrom and recv both return extended error 10045 for bound UDP socket - why?
I have some C code using winsock2 : int fd = socket ( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); struct sockaddr_in sin = { ... }; if (fd == -1) _ERR_( ... ) ... if (...
JVD66
Copper Contributor
Aha! I have verified this is definitely a bug with 'ioctlsocket' .
I modified the example here :
https://www.binarytides.com/udp-socket-programming-in-winsock/
to simply call 'ioctlsocket(s, FIONREAD, &bytes_available) before calling recvfrom with
the positive 'bytes_available' result, and that call also then generates extended error 10045, whereas without the call to 'ioctlsocket' , and receiving BUFLEN, with a call to recvfrom, it works fine.
There is no documentation on either the 'recvfrom' page or on the 'ioctlsocket' pages stating that a call to ioctlsocket with FIONREAD with a bound UDP socket will make the socket parameter into an invalid socket - this is a BUG.
It is a BUG that ioctlsocket() cannot be used before a call to 'recv' or 'recvfrom'().
I will raise these as microsoft bugs (somehow), but is there any better (preferably open-source) alternative to using WinSock2 for BSD sockets programming on WIndows ? The WinSock2 library does not seem to be coded very reliably .
I modified the example here :
https://www.binarytides.com/udp-socket-programming-in-winsock/
to simply call 'ioctlsocket(s, FIONREAD, &bytes_available) before calling recvfrom with
the positive 'bytes_available' result, and that call also then generates extended error 10045, whereas without the call to 'ioctlsocket' , and receiving BUFLEN, with a call to recvfrom, it works fine.
There is no documentation on either the 'recvfrom' page or on the 'ioctlsocket' pages stating that a call to ioctlsocket with FIONREAD with a bound UDP socket will make the socket parameter into an invalid socket - this is a BUG.
It is a BUG that ioctlsocket() cannot be used before a call to 'recv' or 'recvfrom'().
I will raise these as microsoft bugs (somehow), but is there any better (preferably open-source) alternative to using WinSock2 for BSD sockets programming on WIndows ? The WinSock2 library does not seem to be coded very reliably .
JVD66
Mar 09, 2021Copper Contributor
/*
Simple UDP Server
*/
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
#define BUFLEN 512 //Max length of buffer
#define PORT 8888 //The port on which to listen for incoming data
int main()
{
SOCKET s;
struct sockaddr_in server, si_other;
int slen , recv_len;
char buf[BUFLEN];
WSADATA wsa;
slen = sizeof(si_other) ;
//Initialise winsock
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("Initialised.\n");
//Create a socket
if((s = socket(AF_INET , SOCK_DGRAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
printf("Socket created.\n");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_port = htons( 60514 );
server.sin_addr.s_addr =htonl((127<<24)|1);
//Bind
if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
puts("Bind done");
//keep listening for data
unsigned int bytes_available = 0;
while(1)
{
printf("Waiting for data...");
fflush(stdout);
//clear the buffer by filling null, it might have previously received data
memset(buf,'\0', BUFLEN);
bytes_available = 0;
if ( ioctlsocket(s, FIONREAD, &bytes_available) != 0 )
{
printf("ioctlsocket() failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
if ( bytes_available > 0 )
{
//try to receive some data, this is a blocking call
if ((recv_len = recvfrom(s, buf, bytes_available, MSG_WAITALL, (struct sockaddr *) &si_other, &slen)) == SOCKET_ERROR)
{
printf("recvfrom() failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
//print details of the client/peer and the data received
printf("Received packet from %s:%d\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port));
printf("Data: %s\n" , buf);
}else
Sleep(1000);
}
closesocket(s);
WSACleanup();
return 0;
}
- JVD66Mar 09, 2021Copper ContributorThis program prints:
Compiled with normal $INCLUDE and $LIB set from vcvarsall.bat :
$ cl winsock_ex.c /link /NODEFAULTLIB:MSVCRT shell32.lib Ws2_32.lib kernel32.lib
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29337 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
winsock_ex.c
Microsoft (R) Incremental Linker Version 14.28.29337.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:winsock_ex.exe
/debug
/NODEFAULTLIB:MSVCRT
Synchronization.lib
shell32.lib
Ws2_32.lib
kernel32.lib
winsock_ex.obj
$ ./winsock_ex.exe
Initialising Winsock...Initialised.
Socket created.
Bind done
Waiting for data...Waiting for data...Waiting for data...Waiting for data...Waiting for data...Waiting for data...Waiting for data...Waiting for data...Waiting for data...Waiting for data...Waiting for data...Waiting for data...Waiting for data...recvfrom() failed with error code : 10045
Commenting out the bit where it calls ioctlsocket() allows it to recvfrom() OK.
Looks like a bug to me.