0

I'm using:

struct in_addr ip;                                         
#define HOST_PORT atoi(argv[2])
#define HOST_IP inet_aton(argv[1], &ip)

sockaddr_in sockaddr;
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = htonl(HOST_IP);
sockaddr.sin_port = htons(HOST_PORT);

To get the ip and port numbers in cli. Then i bind, listen, accept and read.

I do compile and when i use ./server localhost 8080 everything is working as intended.

But if i use ./server 127.0.0.1 8080 or ./server 192.168.30.1 8080 seems like is bind and listening, no errors but i don't recive the request.

  • 2
    Are you sure that `inet_aton(argv[1], &ip)` returns 1 if `argv[1]` equals `localhost`? It shouldn't and it doens't on my machine (returns `0` as expected). Indeed, according to man pages, this function works only with "IPv4 numbers-and-dots notation". – Amessihel Jul 06 '20 at 19:19
  • Yes, in my case it does work using localhost but not using ipv4 addresses. – String Manolo Jul 06 '20 at 20:11
  • @StringManolo You really should be using `getaddrinfo()` instead, eg: `struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if (getaddrinfo(argv[1], argv[2], &hints, &res) == 0) { /* use res->ai_addr and res->ai_addrlen as needed ... */ freeaddrinfo(res); }` It will parse IP address strings and hostname strings into `sockaddr` structs for you, and will happily handle strings related to the local host like `"localhost"`, `"127.0.0.1"`, `"192.168.30.1"`, etc. – Remy Lebeau Jul 06 '20 at 20:29
  • @Remy Lebeau i'm asking about a problem with a bike, what's the reason why this happens. So i can learn from it and solve my problem. Solutions like: Buy a truck here is a catalog... Are not what i need. getaddrinfo do way more things. It's not even intended for this job. I'm more interested in what is the mistake i made than a working solution. There are thousands of working servers around i can copy and paste. – String Manolo Jul 06 '20 at 21:36
  • @StringManolo "*It's not even intended for this job*" - actually it is. This is exactly the type of scenario that its `AI_PASSIVE` flag is meant for - to parse input into appropriate `sockaddr_...` structs that are suitable to give to `bind()` for a `listen()`'ing server. But whatever. I have now posted an answer for why your code is not working. – Remy Lebeau Jul 06 '20 at 22:10
  • @Amessihel i only had to knew i need to use ip.s_addr instead of using ip directly. xD – String Manolo Jul 10 '20 at 03:16

1 Answers1

1

You are misusing inet_aton().

You are assigning the return value of inet_aton() to your sockaddr variable, rather than assigning the in_addr struct that inet_aton() outputs. The return value is NOT an IP address!

inet_aton() returns a non-zero value on success, and 0 on failure. In other words, its return value is basically a boolean value.

Calling bind() with an IP address of 0.0.0.0 (aka INADDR_ANY) instructs it to bind an AF_INET socket to all local network interfaces on the specified port, which is very common (and generally preferred) for a server to do.

Calling inet_aton("localhost") fails because you can't pass a hostname to inet_aton(), so it returns 0, and then you bind() the socket using a sockaddr_in whose s_addr is set to INADDR_ANY, which is OK, so your code seems to work with "localhost", but only as a fluke.

Calling inet_aton("127.0.0.1") or inet_aton("192.168.30.1") succeeds, so it returns non-zero, and then you bind() the socket using a sockaddr_in whose s_addr is set to an invalid IP, causing bind() to either fail outright, or worse to bind to an existing network interface that is different than the one you are expecting.

Also, the in_addr that inet_aton() outputs is already in network byte order, so there is no need to call htonl() on its output.

Try this instead:

struct in_addr ip;
#define HOST_PORT atoi(argv[2])
#define HOST_IP ((inet_aton(argv[1], &ip) != 0) ? ip.s_addr : 0)

struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = HOST_IP;
sockaddr.sin_port = htons(HOST_PORT);

// use sockaddr as needed ...

Or, simply get rid of your HOST_IP and HOST_PORT macros, as they are not really helping you:

struct sockaddr_in sockaddr;

memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
inet_aton(argv[1], &(sockaddr.sin_addr));
sockaddr.sin_port = htons(atoi(argv[2]));

// use sockaddr as needed ...

That being said, you really should be using getaddrinfo() instead, eg:

struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

if (getaddrinfo(argv[1], argv[2], &hints, &res) == 0)
{
    // use res->ai_addr and res->ai_addrlen with socket() and bind() as needed ...
    freeaddrinfo(res);
}

getaddrinfo() will parse both IP address strings and hostname strings into appropriate sockaddr_... structs for you, and will happily handle strings that are related to the local host, like "localhost", "127.0.0.1", "192.168.30.1", etc.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770