Krzysztof Tarnawski
Krzysztof Tarnawski

Reputation: 5

C socket programming, getting IP of server on raspberrypi

I am writing a server application on Raspberry Pi with communication on TCP/IP sockets and I have trouble with showing an IP of socket I am listening on. I have found two solutions and none of them are working.

1st solution:

char hostName[255];
struct hostent *host_entry;
char * szLocalIP;
gethostname(hostName, 255);
host_entry = gethostbyname(hostName);
szLocalIP = inet_ntoa (*(struct in_addr *)host_entry->h_addr);
printf("Server runs on IP: %s, port: %d\n\n", szLocalIP, ntohs(server_address.sin_port));

output: Server runs on IP: 0.0.0.0, port: 5000

2nd solution:

struct sockaddr_in server_address;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
if (getnameinfo((struct sockaddr *)&server_address, server_len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0)
         printf("Server runs on IP: %s, port: %s\n\n", hbuf, sbuf);

output: Server runs on IP: 127.0.1.1, port: 5000

full code:

#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <netdb.h>

#define PORT 5000
#define MAX_QUEUE 3
#define NAME "Server"

int main()
{
    int server_file_descriptor, new_connection;
    long valread;
    unsigned long counter = 1;
    struct sockaddr_in server_address, client_address;
    socklen_t server_len, client_len;
    int opt = 1;
    char buffer[1024] = {0};

    char hostName[255];
    struct hostent *host_entry;
    char * szLocalIP;

    char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];

    char *hello = "Temperature send";

    if ((server_file_descriptor = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    if (setsockopt(server_file_descriptor, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)))
    {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = INADDR_ANY;
    server_address.sin_port = htons(PORT);

    server_len = sizeof(server_address);

    if (bind(server_file_descriptor, (struct sockaddr *)&server_address, server_len))
    {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    if (listen(server_file_descriptor, MAX_QUEUE))
    {
        perror("listen failed");
        exit(EXIT_FAILURE);
    }

    gethostname(hostName, 255);
    host_entry = gethostbyname(hostName);
    szLocalIP = inet_ntoa (*(struct in_addr *)host_entry->h_addr);

    if (getnameinfo((struct sockaddr *)&server_address, server_len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0)
         printf("1 - Server runs on IP: %s, port: %s\n\n", hbuf, sbuf);

    printf("2 - Server runs on IP: %s, port: %d\n\n", szLocalIP, ntohs(server_address.sin_port));
    printf("3 - Server runs on IP: %s, port: %d\n\n", inet_ntoa(server_address.sin_addr), ntohs(server_address.sin_port));

    client_len = sizeof(client_address);

    for (;;counter++)
    {
        if ((new_connection = accept(server_file_descriptor, (struct sockaddr *)&client_address, &client_len)) == -1)
        {
            perror("accept failed");
            exit(EXIT_FAILURE);
        }

        printf("%s: got connection from %s on port: %d.\n", NAME, inet_ntoa(client_address.sin_addr), ntohs(client_address.sin_port));

        valread = read( new_connection , buffer, 1024);

        printf("%s sends request: %s\n", inet_ntoa(client_address.sin_addr), buffer);

        if (strcmp(buffer, "get_temp") == 0)
        {
            send(new_connection , hello , strlen(hello) , 0 );
            printf("%s: message \"%s\" send to %s.\n", NAME, hello, inet_ntoa(client_address.sin_addr));
        }
        else
        {
            send(new_connection , "Unknown command\n" , 15 , 0 );
            printf("%s: message \"Unknown command\" send to %s.\n", NAME, inet_ntoa(client_address.sin_addr));
        }
        printf("%s: closing connection with: %s.\n", NAME, inet_ntoa(client_address.sin_addr));
        printf("Handled calls: %ld\n\n", counter);
        close(new_connection);
        memset(buffer, 0, sizeof(buffer));
    }
}

output of 3rd printf is the same as 1st.

Upvotes: 0

Views: 1821

Answers (1)

kfx
kfx

Reputation: 8537

The answer 0.0.0.0 is the correct one.

More precisely, when you open a server socket, it does not have a specific, well-defined address. Therefore if you ask any system calls to "find the local address this socket is listening to" they will return the wildcard address 0.0.0.0. Furthermore, you can connect to the server using many different destination addresses: for example "127.0.0.1", "127.1.2.3", "192.168.40.21" (the address of your network interface), etc.

If you want to listen to a specific address, you need to pass that address to bind(). For example, this code listens to a specific local address 127.1.2.3:

server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("127.1.2.3");
server_address.sin_port = htons(PORT);
if (bind(server_file_descriptor, (struct sockaddr *)&server_address, sizeof(server_address)))
   ...

Output:

3 - Server runs on IP: 127.1.2.3, port: 5000

The problem is that connections to "127.0.0.1", "192.168.40.21" and all of the other addresses are now going to fail, since you have restricted the server to be reachable only on a specific address.

However, there is a thing that does have a well-defined address in your initial example. It is the client socket created after the connection is accepted. If you add this code after the accept() call, you will see the address the client has connected to:

    struct sockaddr_in addr;
    socklen_t len;
    len = sizeof(addr);
    getsockname(new_connection, (struct sockaddr *)&addr, &len);
    printf("Client connected to: %s, port: %d\n\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));

This address may be different for different clients: i.e. one client may connect to "127.0.0.1", another to "192.168.40.21".

Upvotes: 1

Related Questions