1

I know that WSARecvFrom has a parameter which is meant to return the sender's ip address. However, when I use it with overlapped io, the variable that I pass it doesn't get filled.

WSARecvFrom(udpSocket, &receiveBuffer, 1, 0, &flags, (sockaddr*)&incomingAddress, &SocketAddressSize, &receiveOverlapped, 0)

...

WSAWaitForMultipleEvents(2, networkEvents, false, WSA_INFINITE, false)

...

WSAGetOverlappedResult(udpSocket, &receiveOverlapped, &transferCount, true, &flags);

...

char* incomingAddressString = inet_ntoa(incomingAddress.sin_addr);

incomingAddressString now equals "204.204.204.204"

Am I missing something?

Thanks

XZodia
  • 33
  • 1
  • 6

1 Answers1

1

According to the documentation:

Also, the values indicated by lpFrom and lpFromlen are not updated until completion is itself indicated. Applications must not use or disturb these values until they have been updated, therefore the application must not use automatic (that is, stack-based) variables for these parameters.

Typically, when using overlapped I/O, you should define a custom struct that contains an OVERLAPPED or WSAOVERLAPPED (depending on which API you use - WSAOVERLAPPED in this situation) and whatever other data you need in (like your sockaddr_in buffer in this situation). Then allocate a dynamic instance of the struct and pass its data members to WSARecvFrom() and wait for the operation to complete before then freeing the memory for the struct. That way, the memory remains valid while the operlapped operation is doing its own. For example:

struct MyOverlappedInfo
{
    WSAOVERLAPPED Overlapped;
    DWORD Flags;
    sockaddr_in IncomingAddress;
    int IncomingAddressSize; 
    BYTE Data[1024];
    DWORD DataSize;
    WSABUF Buffer;

    MyOverlappedInfo()
    {
        memset(this, 0, sizeof(this));
        Overlapped.hEvent = WSACreateEvent();
        Buffer.len = sizeof(Data);
        Buffer.buf = (char*) Data;
    }

    ~MyOverlappedInfo()
    {
        WSACloseEvent(Overlapped.hEvent);
    }
};

MyOverlappedInfo info = new MyOverlappedInfo;

WSARecvFrom(udpSocket, &info->Buffer, 1, NULL, &info->Flags, (sockaddr*)&info->IncomingAddress, &info->IncomingAddressSize, &info->Overlapped, NULL);
... 
WSAWaitForMultipleEvents(2, networkEvents, false, WSA_INFINITE, false) 
... 
WSAGetOverlappedResult(udpSocket, &info->Overlapped, &info->DataSize, TRUE, &info->Flags); 
... 
char* incomingAddressString = inet_ntoa(info->IncomingAddress.sin_addr); 
delete info;

This approach is much more useful if you use an I/O Completion Port for your socket I/O via CreateIOCompletionPort() and GetQueuedCompletionStatus(), instead of usin WSAWaitForMultipleEvents() and WSAGetOverlappedResult(). Read this article for more details:

Windows Sockets 2.0: Write Scalable Winsock Apps Using Completion Ports

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • All my networking is in a class and I'm not passing any stack variables. I tested passing a new variable to lpFromLen but it errored unless it was set to the size of the address structure, which makes me doubt the accuracy of the documentation there. – XZodia Dec 20 '11 at 22:50
  • That is what you are supposed to do. The documentation I linked to in my answer states as much: "The value pointed to by `lpFromlen` is initialized to the size of this buffer, and is modified on completion to indicate the actual size of the address stored there." – Remy Lebeau Dec 20 '11 at 23:21
  • Yeah, I was refering to "lpFromlen are not updated until completion" which doesn't make any sense (why would it change?). But we're getting off topic here... – XZodia Dec 21 '11 at 00:37
  • You can pass a larger buffer to `WSARecvFrom()` and it will truncate the size if a smaller address is received. For instance, when passing a buffer that is large enough to hold an IPv6 address an IPv4 address is received. Some OS versions support dual-stack sockets for handling both IPv4 and IPv6 traffic on a single socket. To support both addresses, your `lpFrom` buffer should be large enough to hold a `SOCKADDR_STORAGE` structure. – Remy Lebeau Dec 21 '11 at 01:28
  • An IPv4 address of `204.204.204.204` mean you have a 4-byte address that is filled with `0xCC` bytes. Some memory managers use `0xCC` to fill freed memory as a means of detecting later accesses to freed memory. I would start looking there. Make sure your class object is not being freed while `WSARecvFrom()` is busy. Also, you are waiting for multiple network events, so are you sure the `WSARecvFrom()` event is the one actually being signaled when you call `WSAGetOverlappedResult()`? Are you doing error handling to make sure `WSAGetOverlappedResult()` is not failing? – Remy Lebeau Dec 21 '11 at 03:25
  • I tried zeroing the incomingAddress memory and the 0xCC's are now 0x0's. Nothing getting freed. Yes, I have a switch statement for the result of WSAWaitForMultipleEvents(). I wasn't error checking WSAGetOverlappedResult(), but I am now and its not erroring. – XZodia Dec 21 '11 at 03:57
  • The fact that the memory was initially all `0xCC` means something in your app intentionally filled that memory. Windows doesn't do that by itself. I still think you are accessing freed memory, or have a bad pointer to your object, or something along those lines. Can you please show a more complete code snippet showing exactly what you are really doing? – Remy Lebeau Dec 21 '11 at 16:54
  • Sorry, for the delay, here's the source code: http://www.mediafire.com/?b0d1xr9r6hovait The main class is NetworkDevice, it has a method called Process which runs on its own thread. Thanks for taking the time to help me. =) – XZodia Dec 23 '11 at 21:04
  • Doh...Found the problem, I had re-declared incomingAddress in the Process method... – XZodia Dec 23 '11 at 22:17