Can I get the IP address from which my DatagramSocket has received a packet?

Hi!

A question for those of you that may understand networking better than I do:

Is it possible to get the IP address from which my DatagramSocket has received a packet?

In my program I wan to be able to tell which sender a packet is from, and the IP address seems ideal to be, but I see nothing in the DatagramSocket documentation on how to get hold of that information.

 

Any tips?

Surely it should be possible, no?

 

Thank you!

I am looking to do a similar thing.

 

From what I have seen about the Juce library, the Datagram class does not seem to have anything that allows someone to get the senders IP from a datagram.

 

If you are only using Windows, then the WinSock2 has 'recvfrom' which will let you grab the IP address of the system that sent the datagram.

 

A way that would seem an easy and quick fix would be for each sender to attach their own IP address to the datagram being sent. So when an application receives a datagram the application can pull out the IP address of the sender.

 

Juce doesn't have a method for determining the localhost’s IP address on a network. It does not seem simple to come up with a method that will cater for all scenarios (dual network interfaces, etc.).

 

I have tried to determine my machines IP address and have had some luck, but I have not tested it in all scenarios, only ones where my application is used. I made a small method that returns the IP address I need and works something like this:

ip = new IPAddress();
ip->findAllAddresses(ipList);
ipList.remove(0);
return ipList.getFirst();

On my machines the first IP address found seems to always be 127.0.0.1, with the second being the IP address on the network. I have not tested this extensively and cannot say that this will definitely work. For me this works fine, but I would certainly go for something better if anyone has any ideas.

Mac and Linux have recvfrom too, and probably everything else supported. The implementation of DatagramSocket would need to be changed to use that instead. Juce uses it in 'waitForNextConnection'

If you can subclass DatagramSocket (I haven't tried) you can add a new Read method with this function, and ask Jules to add it.

 

Bruce

 

 

Shaw, this is what i use to get the probably current ipaddress. Testing for local instead of removing the first entry in the list.

IPAddress NetworkUtils::getCurrentIPAddress()

{

    Array<IPAddress> ipAdresses;

    IPAddress::findAllAddresses (ipAdresses);

//return first non local ipaddress

    for (int i=0; i<ipAdresses.size(); ++i)

    {

        if (ipAdresses[i] != IPAddress::local())

            return ipAdresses[i];

    }

return IPAddress();

}

Following Bruce's suggestion, I got something working. Subclassing DatagramSocket didn't work, but copying it into a new class and renaming it did :)

It is full of apocryphal code that I need to read up about to properly understand, for the moment I got a solution working that is not very pretty, but does the job for me...

As it is a hack it its current state I would not suggest to anyone that it be included in Juce, for example I've only edited the code for Windows (I don't have a mac).

But I paste it here regardless in case someone else wants to use it.

The below is in place of readSocket in SocketHelpers:


#include <winsock2.h>   // this must come first to prevent errors with MSVC7
#include <WS2tcpip.h>

(...)

static int readFromSocket (    const SocketHandle handle,
                                void* const destBuffer, const int maxBytesToRead,
                                bool volatile& connected,
                                String& ipAddress,
                                const bool blockUntilSpecifiedAmountHasArrived) noexcept
    {
        int bytesRead = 0;
        while (bytesRead < maxBytesToRead)
        {
            int bytesThisTime;
           #if JUCE_WINDOWS
            struct sockaddr_storage address;
            juce_socklen_t len = sizeof (address);
            bytesThisTime = recvfrom (    handle, 
                                        static_cast<char*> (destBuffer) + bytesRead, 
                                        maxBytesToRead - bytesRead, 
                                        0,
                                        (struct sockaddr*) &address, 
                                        &len);
            ipAddress = String(inet_ntoa (((struct sockaddr_in*) &address)->sin_addr));
            //bytesThisTime = recv (handle, static_cast<char*> (destBuffer) + bytesRead, maxBytesToRead - bytesRead, 0);

           #else
            while ((bytesThisTime = (int) ::read (handle, addBytesToPointer (destBuffer, bytesRead), (size_t) (maxBytesToRead - bytesRead))) < 0
                     && errno == EINTR
                     && connected)
            {
            }
           #endif
            if (bytesThisTime <= 0 || ! connected)
            {
                if (bytesRead == 0)
                    bytesRead = -1;
                break;
            }
            bytesRead += bytesThisTime;
            if (! blockUntilSpecifiedAmountHasArrived)
                break;
        }
        return bytesRead;
    }

And then in the XXXDatagramSocket class:


int XXXDatagramSocket::readFrom (void* destBuffer, const int maxBytesToRead, String& ipAddress, const bool blockUntilSpecifiedAmountHasArrived)
{
    return connected ? IliasSocketHelpers::readFromSocket (handle, destBuffer, maxBytesToRead, connected, ipAddress, blockUntilSpecifiedAmountHasArrived)
                     : -1;
}