I am trying to write a UDP server with a worker thread that keeps calling GetQueuedCompletionStatus
. I can already receive data successfully with WSARecvFrom
but sending data with WSASendTo
causes the following error:
10045: The attempted operation is not supported for the type of object referenced.
I've been trying to fix this for hours now, reading documentation as well as rigorous trial and error. Switching the WSASendTo
call to a blocking call fixes the issue, but then I have to deal with blocking IO. I also have almost the exact same code for TCP (WSASend
instead of WSASendTo
, etc.), and that works with IOCP without a hitch.
I've tried calling connect
, not binding the socket, changing my OVERLAPPED
struct, verified the SOCKADDR*
parameter contains valid host/port combination, passing in a lpNumberOfBytesSent
parameter. Nothing seems to make a difference.
Basic flow of the program (code further below):
- Create a socket with
WSA_FLAG_OVERLAPPED
- Create an IO completion port and a worker thread
- Bind the socket to 127.0.0.1:2050
- Call
WSARecvFrom
(and connect with another client to set validPER_IO_DATA::SockAddrFrom
) gets_s
input from the console and send it withWSASendTo
My OVERLAPPED struct:
typedef struct PER_IO_DATA
{
OVERLAPPED Overlapped;
SOCKET Socket;
WSABUF wsaBuf;
char Buffer[1024];
DWORD Flags;
SOCKADDR_IN SockAddrFrom;
} PER_IO_DATA;
Main function:
//################################# Initialize ###############################
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
return 0;
//Create completion port
HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (!hCompletionPort)
return 0;
//Create and detach a worker thread
HANDLE hThread = CreateThread(NULL, 0, server_worker_thread, hCompletionPort, 0, NULL);
CloseHandle(hThread);
//Create UDP socket with overlapped IO
SOCKET Sock = WSASocketW(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (Sock == INVALID_SOCKET)
WSAERROR();
//################################### Bind ###################################
//Bind socket to 127.0.0.1:2050
SOCKADDR_IN serverAddr = { 0 };
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(2050);
InetPtonA(AF_INET, "127.0.0.1", &serverAddr.sin_addr.s_addr);
if (bind(Sock, (SOCKADDR*)&serverAddr, sizeof(SOCKADDR_IN)) == -1)
WSAERROR();
//Assign completion port
CreateIoCompletionPort((HANDLE)Sock, hCompletionPort, 0, 0);
//Create overlapped context
PER_IO_DATA* pPerIoData = malloc(sizeof(PER_IO_DATA));
ZeroMemory(pPerIoData, sizeof(PER_IO_DATA));
pPerIoData->Socket = Sock;
pPerIoData->Overlapped.hEvent = WSACreateEvent();
pPerIoData->wsaBuf.buf = pPerIoData->Buffer;
pPerIoData->wsaBuf.len = sizeof(pPerIoData->Buffer);
//################################## Receive #################################
int size = sizeof(SOCKADDR_IN);
if (WSARecvFrom(Sock, &pPerIoData->wsaBuf, 1, NULL,
&pPerIoData->Flags, (SOCKADDR*)&pPerIoData->SockAddrFrom,
&size, &pPerIoData->Overlapped, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
WSAERROR();
}
//################################### Send ###################################
while (TRUE)
{
gets_s(pPerIoData->Buffer, sizeof(pPerIoData->Buffer));
pPerIoData->wsaBuf.len = strlen(pPerIoData->Buffer);
//Print outgoing data
char addr[16];
DEBUG("Sending %.*s (%d bytes) to %s:%d", pPerIoData->wsaBuf.len, pPerIoData->Buffer,
pPerIoData->wsaBuf.len, InetNtopA(AF_INET, &pPerIoData->SockAddrFrom.sin_addr,
addr, sizeof(addr)), ntohs(pPerIoData->SockAddrFrom.sin_port));
//Send the data (this is where the error happens)
if (WSASendTo(Sock, &pPerIoData->wsaBuf, 1, NULL,
WSA_FLAG_OVERLAPPED, (SOCKADDR*)&pPerIoData->SockAddrFrom, sizeof(SOCKADDR_IN),
&pPerIoData->Overlapped, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
WSAERROR(); //<-- Error 10045
}
}
//################################## Clean up ################################
shutdown(Sock, SD_BOTH);
closesocket(Sock);
WSACleanup();
return 0;
Example output:
Received hello (5 bytes) from 127.0.0.1:50995
respond
Sending respond (7 bytes) to 127.0.0.1:50995
Error 10045: The attempted operation is not supported for the type of object referenced.
The error message originates from my WSAERROR
macro.
How can I call WSASendTo
with WSA_FLAG_OVERLAPPED
and have it be added to the IOCP message queue?