SFML community forums

Help => Network => Topic started by: TheMagicNumber on March 07, 2011, 10:17:17 pm

Title: GetLocalAddress
Post by: TheMagicNumber on March 07, 2011, 10:17:17 pm
Whenever I call GetLocalAddress, I get the localhost IP (127.0.0.1), is this normal? :)
Title: GetLocalAddress
Post by: Laurent on March 07, 2011, 10:21:44 pm
No it shouldn't, unless you have a weird network configuration.

What is your actual local network address?
Title: GetLocalAddress
Post by: TheMagicNumber on March 07, 2011, 10:23:53 pm
It's 192.168.0.100.
Title: GetLocalAddress
Post by: Laurent on March 07, 2011, 10:42:49 pm
Can you show a minimal code that reproduces this problem, just to be sure? :)
Title: GetLocalAddress
Post by: TheMagicNumber on March 07, 2011, 10:47:47 pm
Alright, here:
Code: [Select]
#include <iostream>
#include <SFML/Network.hpp>

int main(int argc, char* argv) {
std::cout << sf::IpAddress::GetLocalAddress().ToString();
return 0;
}
Prints "127.0.0.1"
Title: GetLocalAddress
Post by: Laurent on March 07, 2011, 11:09:52 pm
What is your OS?
Title: GetLocalAddress
Post by: TheMagicNumber on March 07, 2011, 11:10:26 pm
Windows 7 x64

I see you noticed that error of yours, by the way. ;)
Title: GetLocalAddress
Post by: Laurent on March 07, 2011, 11:18:19 pm
Everytime I post bullshit, I get caught before I edit my message :lol:
Title: GetLocalAddress
Post by: TheMagicNumber on March 07, 2011, 11:41:48 pm
Any ideas? ipconfig gives me the correct information.
Title: GetLocalAddress
Post by: Laurent on March 08, 2011, 07:31:32 am
No idea. Maybe you can play with the function's code directly and see if anything's wrong.
Title: GetLocalAddress
Post by: TheMagicNumber on March 08, 2011, 02:40:14 pm
All the stuff I found online that works used getaddrinfo() or gethostbyname().
Title: GetLocalAddress
Post by: Laurent on March 08, 2011, 02:47:30 pm
Yes, there are other solutions. However getsockname on a local socket should be the best option, I'd like to understand why it fails on your machine (and not on any other Windows PC).
Title: GetLocalAddress
Post by: TheMagicNumber on March 08, 2011, 03:00:35 pm
Quote
If the socket is using a connectionless protocol, the address may not be available until I/O occurs on the socket.

From: http://msdn.microsoft.com/en-us/library/ms738543(v=vs.85).aspx

Is this relevant? I would probably assume that the function would return SOCKET_ERROR, though.
Title: GetLocalAddress
Post by: Laurent on March 08, 2011, 03:06:23 pm
Hum...
Quote from: "MSDN"
If the socket is using a connectionless protocol, the address may not be available until I/O occurs on the socket.

Can you try to add this, between connect and gethostname?
Code: [Select]
char buffer[] = {0};
send(socket, buffer, 1, 0);

You can copy the function into your code directly if you don't want to recompile SFML. If you do so, you'll have to do the following replacements:
Title: GetLocalAddress
Post by: TheMagicNumber on March 08, 2011, 03:15:03 pm
Nope. :(
Title: GetLocalAddress
Post by: Laurent on March 08, 2011, 03:19:10 pm
Doesn't work at all? Can you show me your code?
Title: GetLocalAddress
Post by: TheMagicNumber on March 08, 2011, 03:20:14 pm
It gave the same result.
Code: [Select]
sf::IpAddress GetLocalAddress()
{
// The method here is to connect a UDP socket to anyone (here to localhost),
// and get the local socket address with the getsockname function.
// UDP connection will not send anything to the network, so this function won't cause any overhead.

sf::IpAddress localAddress;

// Create the socket
SOCKET sock = socket(PF_INET, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET)
return localAddress;

// Connect the socket to localhost on any port
sockaddr_in address = CreateAddress(INADDR_LOOPBACK, 0);
if (connect(sock, reinterpret_cast<sockaddr*>(&address), sizeof(address)) == -1)
{
closesocket(sock);
return localAddress;
}

char buffer[] = {0};
send(sock, buffer, 1, 0);

// Get the local address of the socket connection
int size = sizeof(address);
if (getsockname(sock, reinterpret_cast<sockaddr*>(&address), &size) == -1)
{
closesocket(sock);
return localAddress;
}

// Close the socket
closesocket(sock);

// Finally build the IP address
localAddress = sf::IpAddress(ntohl(address.sin_addr.s_addr));

return localAddress;
}
Title: GetLocalAddress
Post by: Laurent on March 08, 2011, 03:24:13 pm
Ok... last try: check the return value of send, just to be sure (compare it against SOCKET_ERROR).
Title: GetLocalAddress
Post by: TheMagicNumber on March 08, 2011, 03:25:38 pm
Done, it didn't return SOCKET_ERROR.
Title: GetLocalAddress
Post by: Laurent on March 08, 2011, 03:27:51 pm
Can you add WSA initialization to your own code?
Code: [Select]
WSADATA init;
WSAStartup(MAKEWORD(2, 2), &init);
Title: GetLocalAddress
Post by: TheMagicNumber on March 08, 2011, 03:29:24 pm
Just put that at the beginning of main() and ran, same result. D:

I'll be back later.
Title: GetLocalAddress
Post by: Laurent on March 08, 2011, 03:42:39 pm
I've run out of ideas :D
Title: GetLocalAddress
Post by: TheMagicNumber on March 08, 2011, 09:18:13 pm
:?
Title: A suggestion...
Post by: Beernutts on May 11, 2011, 04:00:14 pm
I am having this same issue at home (using 2.0), and I've dealt with PC's with multiple IP address' in the past.  I didn't have time to debug it, but I'll look at it tonight and get back to you here.

I do think the API should be modified since often PC's are on multiple networks.  In fact, the PC I use at work has 3 IP address' to 3 different networks.  For an simple test app I wrote, I included this bit of code (Windows only) to select which IP address to use (see below).

I would love for the GetLocalIpAddress to maybe pass an index, so we can get all the possible local IP addresses, or some other method of getting all the IP addresses the PC has.

Thanks.

Code: [Select]
/* retreive our IP address */
    {
        PMIB_IPADDRTABLE pIPAddrTable;
        DWORD dwSize = 0;

        pIPAddrTable = (MIB_IPADDRTABLE*) malloc( sizeof( MIB_IPADDRTABLE) );
       
        /* Make an initial call to GetIpAddrTable to get the
         necessary size into the dwSize variable */
        if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)
        {
            free( pIPAddrTable );
            pIPAddrTable = (MIB_IPADDRTABLE *) malloc ( dwSize );
        }

        /* Make a second call to GetIpAddrTable to get the
         actual data we want */
        GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
       
        /* fill in our addrs */
        for (i = 0; i < pIPAddrTable->dwNumEntries; i++)
        {
            if ((pIPAddrTable->table[i].dwAddr != 0) &&
                (pIPAddrTable->table[i].dwAddr != LOCALHOST))
            {
                addr[NumAddrs].s_addr = pIPAddrTable->table[i].dwAddr;
                NumAddrs++;
            }
        }          
    }  
   
    /* ask users which IP address to use if more than one */
    while ((NumAddrs > 1) && bContinue)
    {
        C8 c8Char;
       
        printf("Choose Which IP address to listen on:\n");
       
        for (i = 0; i < NumAddrs; i++)
        {
            printf("%d: IP %d.%d.%d.%d\n", i+1, PRINT_IP(addr[i].s_addr));
        }
       
        c8Char = getch() - '0';
       
        if ((c8Char > 0) && (c8Char < NumAddrs+1))
        {
            bContinue = FALSE;
            gu32IpIndex = c8Char-1;
            printf("------------------------------\n");
        }
    }
Title: Re: A suggestion...
Post by: Beernutts on May 12, 2011, 03:11:23 pm
Quote from: "Beernutts"
I am having this same issue at home (using 2.0), and I've dealt with PC's with multiple IP address' in the past.  I didn't have time to debug it, but I'll look at it tonight and get back to you here.

I do think the API should be modified since often PC's are on multiple networks.  In fact, the PC I use at work has 3 IP address' to 3 different networks.  For an simple test app I wrote, I included this bit of code (Windows only) to select which IP address to use (see below).

I would love for the GetLocalIpAddress to maybe pass an index, so we can get all the possible local IP addresses, or some other method of getting all the IP addresses the PC has.

Thanks.


So, I tried to create a solution to this in my app by checking if the GetLocalAddress() was LOCALHOST, and, instead creating an sf::IpAddress with my real IP address (using code close to that above).  However, using that code doesn't seem to allow me to send any packets out the ethernet interface I'm trying to use.  Checking Wireshark, there's no data being sent on my ethernet interface (using UdpSocket here).

So, until sf:Network is modified to properly handle this situation (perhaps you need to modify Bind() to include the IP address to Bind the socket to as well as port assuming there will be multiple possible network interfaces), I'm going to implement my solution in good old sockets.