views:

60

answers:

2

I need to get the IP address of a system within C++. I followed the logic and advice of another comment on here and created a socket and then utilized getsockname to determine the IP address which the socket is bound to.

However, this doesn't appear to work (code below). I'm receiving an invalid IP address (58.etc) when I should be receiving a 128.etc

Any ideas?

   string Routes::systemIP(){

    // basic setup
    int sockfd;
    char str[INET_ADDRSTRLEN];
    sockaddr* sa;
    socklen_t* sl;
    struct addrinfo hints, *servinfo, *p;
    int rv;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;

    if ((rv = getaddrinfo("4.2.2.1", "80", &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return "1";
    }

    // loop through all the results and make a socket
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            perror("talker: socket");
            continue;
        }

        break;
    }

    if (p == NULL) {
        fprintf(stderr, "talker: failed to bind socket\n");
        return "2";
    }

    // get information on the local IP from the socket we created
    getsockname(sockfd, sa, sl);

    // convert the sockaddr to a sockaddr_in via casting
    struct sockaddr_in *sa_ipv4 = (struct sockaddr_in *)sa;

    // get the IP from the sockaddr_in and print it
    inet_ntop(AF_INET, &(sa_ipv4->sin_addr.s_addr), str, INET_ADDRSTRLEN);
    printf("%s\n", str);

    // return the IP
    return str;
}
+1  A: 

Your code already contains the hint: failed to bind socket. But you cut the part of the code that attempts connecting out (did you copy from Stevens UnP?). The socket is not connected to anything, so the network stack has not assigned the local address to it yet.

Once you connect the socket the kernel has to select the local address for it according to the routing table. At that point getsockname(2) will work as expected.

Nikolai N Fetissov
There is no connection required here -- this is the startup of a structure for a UDP datagram connection. I had assumed that the creation of the socket would assign a local address, apparently not?
BSchlinker
`connect(2)` works on UDP sockets too. It's actually pretty neat. If you have the UnP book - read about connected UDP sockets. To answer your question - no, creating a socket just reserves a file descriptor, it does not bind it to any address.
Nikolai N Fetissov
I was actually looking at Beej's Guide to network programming for the socket structure.
BSchlinker
That's a good source too, but get the latest edition of UnP (3rd now) anyway - it's a very good investment, you'll keep getting back to it all the time. I know I do.
Nikolai N Fetissov
+1  A: 

You do not need to allocate a socket to get the machine's available IP addresses. You can use the socket API gethostname() and gethostbyname() functions instead. Or, on Windows, you can alternatively use the Win32 API GetAdaptersInfo() or GetAdaptersAddresses() function instead.

Remy Lebeau - TeamB
This will give me all of the machines IP addresses though, correct? I need to know that the IP address which I have selected is the IP which communication occurs on with the remote system selected (in this case, 4.2.2.1). Is there some way to filter all of the IP addresses easily?
BSchlinker
Then you must connect to the target machine, and then call getsockname on the socket after it's connected
valdo
Connecting is the most accurate. However, if you do not want to waste a connection, the Win32 API has GetBestInterface/Ex() functions (but they only work with IPv4).
Remy Lebeau - TeamB
Is there a linux equivalent of GetBestInterface?
BSchlinker
I'm not a Linux developer, so I have no clue, sorry.
Remy Lebeau - TeamB