3

I don't know what this error means and what to do to fix it.

I've been following the Sock)et Programming Tutorials In C For Beginners | Part 2 by Eduonix on Youtube but I haven't been able to run anything from this guy, the code is from his tutorial.

If someone could help me understand what this error means and what to do to fix it?

Here is the error:

inet_aton(address, &remote_address.sin_addr.s_addr);
                   ^

[1007:1003 0:6758] 09:30:39 Wed May 29 [kristjan@Kundrum:pts/5 +1] ~/C_Programming
$ gcc http_client_tcp.c -o http_client_tcp
http_client_tcp.c: In function ‘main’:
http_client_tcp.c:24:24: warning: passing argument 2 of ‘inet_aton’ from incompatible pointer type [-Wincompatible-pointer-types]
     inet_aton(address, &remote_address.sin_addr.s_addr);
                        ^
In file included from http_client_tcp.c:8:0:
/usr/include/arpa/inet.h:73:12: note: expected ‘struct in_addr *’ but argument is of type ‘in_addr_t * {aka unsigned int *}’
 extern int inet_aton (const char *__cp, struct in_addr *__inp) __THROW;
            ^~~~~~~~~

I'm using Debian Linux 9.9 stretch and coding in Visual Studio Code but the error doesn't come in the Visual Code editor/debugger only if I compile in the shell.

Here is the code:

#include <stdio.h>
#include <stdlib.h>

#include <sys/socket.h>
#include <sys/types.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <unistd.h> // for close

int main(int argc, char *argv[])
{
    char *address;
    address = argv[1];

    int client_socket;
    client_socket = socket(AF_INET, SOCK_STREAM, 0);

    // connect to an address
    struct sockaddr_in remote_address;
    remote_address.sin_family = AF_INET;
    remote_address.sin_port = htons(80);
    inet_aton(address, &remote_address.sin_addr.s_addr);

    connect(client_socket, (struct sockaddr *) &remote_address, sizeof(remote_address));

    char request[] = "GET / HTTP/1.1\r\n\r\n";
    char response[4096];

    send(client_socket, request, sizeof(request), 0);
    recv(client_socket, &response, sizeof(response), 0);

    printf("response from server: %s\n", response);
    close(client_socket);

    return 0;
}
somethingSomething
  • 830
  • 7
  • 20
  • 43

2 Answers2

6

The tutorial is bad, the correct code is

inet_aton(address, &remote_address.sin_addr);

remote_address.sin_addr is of type in_addr, whose definition is

struct in_addr {
    unsigned long s_addr;
};

The &remote_address.sin_addr.s_addr and &remote_address.sin_addr will evaluate to the same address, but the former is of wrong type. The original will compile with warning in GCC with default settings, but it is a constraint violation!

As for the Visual Studio code, you should look harder, or perhaps compile with -Werror!


Time to look for better tutorials.

  • As a side-note, it is however fine to cast `(unsigned long*)&remote_address.sin_addr`. This is one of the few cases where such casts are ok, allowed since `sin_addr` is the first member of the struct (6.7.2.1/15). But the compiler cannot do that pointer conversion implicitly, hence the constraint violation Antti mentions. – Lundin May 29 '19 at 11:14
  • No? You can cast the address of the struct to a pointer to the type of its first member - it is well-defined. Incidentally you can also go the other way around, since the struct is an "aggregate" containing an unsigned long as (the first) member, but that leaves the rest of the struct members in an undefined state so it is very fishy practice. – Lundin May 29 '19 at 11:19
  • @Lundin yes but you've got the cast that's the opposite of what's needed here – Antti Haapala -- Слава Україні May 29 '19 at 11:26
3

Check the types. From the man page

int inet_aton(const char *cp, struct in_addr *inp);

the second argument is a pointer to struct in_addr type variable.

In your code, you defined remote_address as

 struct sockaddr_in remote_address;

where struct sockaddr_in is defined as

struct sockaddr_in {
    short            sin_family;   // e.g. AF_INET
    unsigned short   sin_port;     // e.g. htons(3490)
    struct in_addr   sin_addr;     // ***** this is the target
    char             sin_zero[8];  // zero this if you want to
};

So, your usage

 inet_aton(address, &remote_address.sin_addr.s_addr);

should be

inet_aton(address, &(remote_address.sin_addr)); // explicit parenthesis to clarify type
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261