0

I am trying to read from a UDP port, from a local (loopback) application, using IOCP. IOCP works fine for TCP/IP, but I am unable to open the socket properly for UDP.

This is what I am doing:

// same as for tcp/ip
struct sockaddr_in remoteAddr = { 0 };
remoteAddr.sin_addr.s_addr = LOOPBACK_ADDRESS;
remoteAddr.sin_family = AF_INET;
remoteAddr.sin_port = htons(portNumber);

// using SOCK_DGRAM here
SOCKET sock = INVALID_SOCKET;
sock = WSASocketW(AF_INET, SOCK_DGRAM, IPPROTO_IP, 
    NULL, 0, WSA_FLAG_OVERLAPPED);

if( sock == INVALID_SOCKET ) {
    LOG("WSASocketW failed: %d", WSAGetLastError());
    return;
}

nRet = WSAConnect(*sock, (const struct sockaddr*)&remoteAddr, sizeof(remoteAddr),
    NULL, NULL, NULL, NULL);

if (nRet == SOCKET_ERROR)
{
    LOG("WSAConnect failed: %d", WSAGetLastError());
    return;
}

nRet = WSARecv(sock, &wsabuf, 1, NULL, &flags, &overlapped, NULL);
if (nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError()))
{
    LOG("WSARecv failed: %d", WSAGetLastError());
    return;
}

// no errors of any kind
LOG("seems good so far");

Everything passes without errors, but GetQueuedCompletionStatus inside the worker loop thread never returns. If I do the same thing to connect to a TCP socket (just replace SOCK_DGRAM with SOCK_STREAM basically), I get data inside the loop.

Am I doing something obviously wrong?

(Btw) I know I could use WSARecvFrom, but I would like to reuse as much code as possible from the TCP socket. I.e. hopefully, set everything up and then post WSARecv calls inside the worker thread regardless of the type of the socket (WSARecv is supposed to work with UDP properly, AFAIK).

Lou
  • 4,244
  • 3
  • 33
  • 72
  • Do you want to reuse your code or do you want to make it work? UDP is connection-less, so calling `WSAConnect` doesn't make much sense (unless your joining a uni/multicast group). UDP sockets must be bound to a port/interface using `bind`. – huysentruitw Apr 10 '17 at 19:05
  • @Wouter: if possible, reuse and make it work, of course, that's why I wrote this question. :) Does this mean I cannot use `WSARecv` with `bind`, only `WSARecvFrom`? Can you post an answer describing this? – Lou Apr 10 '17 at 19:10
  • 1
    Never used `WSARecv` myself (only `recv()`), but I think you should be able to replace `WSARecvFrom` with `bind()` + `WSARecv`. – huysentruitw Apr 10 '17 at 19:12
  • It's even in the docs: [*The WSARecv function receives data from a connected socket or a bound connectionless socket.*](https://msdn.microsoft.com/en-us/library/windows/desktop/ms741688(v=vs.85).aspx), the word *bound* refers to the `bind()` function. – huysentruitw Apr 10 '17 at 19:15
  • and where you bind to *IOCP* ?? also for UDP *WSAConnect* senseless and need use *WSARecvFrom* instead *WSARecv* – RbMm Apr 10 '17 at 19:16
  • @RbMm: I don't understand the question, I don't "bind to IOCP", I just wanted to see if I can reuse the same code I used for overlapped IO with TCP. As stated on [MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/ms741688(v=vs.85).aspx), `WSARecv` works for both TCP and UDP sockets, why do you find it "senseless"? – Lou Apr 10 '17 at 21:12
  • @Lou - for got packets from IOCP when operation complete you need bind file handle (socket) to IOCP - I not view how/where you do this. and WSAConnect senseless I say – RbMm Apr 10 '17 at 21:22

1 Answers1

0

Managed to get it to work, thanks to the comment by @WouterHuysentruit.

Basically, if I want to receive UDP packets using WSARecv, I need to bind. If I want to send UDP packets using WSASend, I need to connect. So the following works:

if (port_type == incoming_packets)
{
    // bind to port
    ret = bind(*sock, (const struct sockaddr*)&remoteAddr, sizeof(remoteAddr));
    ...
    WSARecv(...);
}
else
{
    // this can send to a loopback udp port which is bound in 
    // a different application
    ret = WSAConnect(*sock, (const struct sockaddr*)&remoteAddr, sizeof(remoteAddr), ...);
    ...
    WSASend(...);
}

As others have pointed out, WSAReceiveFrom/WSASendTo are usually a better choice for UDP, but in this case I can support multiple port types using IOCP transparently.

Lou
  • 4,244
  • 3
  • 33
  • 72