0

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 valid PER_IO_DATA::SockAddrFrom)
  • gets_s input from the console and send it with WSASendTo

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?

user3670011
  • 194
  • 11
  • 2
    `WSA_FLAG_OVERLAPPED== MSG_OOB` in call `WSASendTo` is error. here must be absolute another flags. almost always 0. exactly this and produce your error – RbMm Apr 05 '19 at 18:58
  • 2
    [Read the documentation](https://learn.microsoft.com/en-us/windows/desktop/api/winsock2/nf-winsock2-wsasendto). `WSA_FLAG_OVERLAPPED` is not a valid flag to pass to `WSASendTo()`. Also, you must allocate a new `PER_IO_DATA` for each individual call to `WSARecvFrom()` and `WSASendTo()`. Do not reuse a single `PER_IO_DATA` like you are currently doing – Remy Lebeau Apr 05 '19 at 19:02
  • 1
    also for what you create event - `Overlapped.hEvent = WSACreateEvent();` - this is not need, when you use iocp. you not need save `WSABUF wsaBuf` – RbMm Apr 05 '19 at 19:03
  • @RbMm Thank you so much! I was agonizing over this for longer than I'm willing to admit. That fixed it right up. – user3670011 Apr 05 '19 at 19:04

0 Answers0