13

I'm trying to compile this program, as referenced in Beej's Guide to Network Programming on page 19.

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

int main() {
    int status;
    struct addrinfo hints;
    struct addrinfo *servinfo;          /* Will point to the results */
    memset(&hints, 0, sizeof hints);    /* Make sure the struct is empty */
    hints.ai_family = AF_UNSPEC;        /* Don't care IPv4 or IPv6 */
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;

    if ((status = getaddrinfo(NULL, "3490", &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
        exit(1);
    }

    /* Servinfo now points to a linked list of 1 or more struct addrinfos
        ... do everything until you don't need servinfo anymore .... */

    freeaddrinfo(servinfo); /* Free the linked-list */

    return 0;
}    

Among other errors, I see

../main.c:8:18: error: storage size of ‘hints’ isn’t known
../main.c:13:19: error: ‘AI_PASSIVE’ undeclared (first use in this function)
../main.c:16:3: warning: implicit declaration of function ‘gai_strerror’

It appears that gcc isn't linking with netdb.h. Eclipse, the IDE that I'm using to build this, has no trouble finding the file. Here's the compiler command:

gcc -O0 -g3 -pedantic -Wall -c -fmessage-length=0 -ansi -MMD -MP -MF"main.d" -MT"main.d" -o"main.o" "../main.c"

Adding -lnetdb doesn't resolve the issue. Also...

~> find /usr/include/ -name netdb.h
/usr/include/bits/netdb.h
/usr/include/gssrpc/netdb.h
/usr/include/netdb.h
/usr/include/rpc/netdb.h

I think these files came preinstalled on my openSUSE host. Why doesn't gcc detect netdb.h? Or am I drawing the wrong conclusion?

Pieter
  • 31,619
  • 76
  • 167
  • 242
  • I am running into a similar issue on Linux Mint 20. My IDE (VS Code) doesn't recognize the addrinfo struct and when compiling I get the following errors: gethost.c: In function ‘main’: gethost.c:52:5: warning: implicit declaration of function ‘freehostent’; did you mean /usr/bin/ld: /tmp/ccNUFQ8z.o: in function `main': gethost.c:(.text+0x2ad): undefined reference to `freehostent' collect2: error: ld returned 1 exit status This exact same source file compiles fine on MacOS 10.14. – Josh Benson Oct 12 '20 at 14:15

4 Answers4

17
../main.c:8:18: error: storage size of ‘hints’ isn’t known
../main.c:13:19: error: ‘AI_PASSIVE’ undeclared (first use in this function)
../main.c:16:3: warning: implicit declaration of function ‘gai_strerror’

It appears that gcc isn't linking with netdb.h....

These are not linking errors, and you don't need a netdb shared object file (there is no such beast; netdb.h simply defines data structures and macros for use in your code).

These are compiler errors: gcc complaining because you're using names that it doesn't recognize (AI_PASSIVE) and data types for which the structure is unknown (struct addrinfo).

The code as you've presented it appears to be correct, and addrinfo is defined in /usr/include/netdb.h. What happens if you compile it like this:

gcc -c main.c

Do you still get the same behavior? If so, take a look at the output of:

gcc -E main.c

This generates a preprocessed version of the code, with all of the #include statements replaced by their actual content. You should be able to grep through this and see if the compiler is actually getting /usr/include/netdb.h if if it's finding something else:

$ gcc -E foo.c | grep netdb.h | awk '{print $3}' | sort -u

Which on my system yields:

"/usr/include/bits/netdb.h"
"/usr/include/netdb.h"
"/usr/include/rpc/netdb.h"

When you add -ansi to the command line, your are changing the way gcc behaves in ways that will break the Linux kernel and many system header files. The addrinfo definition in netdb.h is protected like this:

#ifdef  __USE_POSIX
/* Structure to contain information about address of a service provider.  */
struct addrinfo
{
  int ai_flags;                 /* Input flags.  */
  int ai_family;                /* Protocol family for socket.  */
  int ai_socktype;              /* Socket type.  */
  int ai_protocol;              /* Protocol for socket.  */
  socklen_t ai_addrlen;         /* Length of socket address.  */
  struct sockaddr *ai_addr;     /* Socket address for socket.  */
  char *ai_canonname;           /* Canonical name for service location.  */
  struct addrinfo *ai_next;     /* Pointer to next in list.  */
};

// ...other stuff...
#endif

When you run gcc with the -ansi flag, this undefines the __USE_POSIX macro, because things protected by this may not be strictly ANSI compliant. You can see the difference if you compare this:

gcc -E /usr/include/netdb.h

With this:

gcc -E -ansi /usr/include/netdb.h

Only the former contains the addrinfo structure.

larsks
  • 277,717
  • 41
  • 399
  • 399
  • I get the same three header files as output. I see these compile errors: http://pastebin.com/jVVMqftA – Pieter Sep 28 '11 at 10:35
  • 1
    So...it's working? That is, you're not seeing any errors related to `netdb.h`, and you're just getting a warning about `memset()`? That sounds like progress. The `memset()` warning means you need to `#include ` (this comes from the `memset(3)` man page). – larsks Sep 28 '11 at 13:13
  • I don't see any warnings or errors if I include `string.h` as well. However, I want my code to be ANSI C-compliant so I'm still getting these errors... http://pastebin.com/B21NyGQ9 – Pieter Sep 28 '11 at 16:19
  • I've updated my answer to explain what's happening. If you've found this discussion helpful, indicating so by accepting the answer would be very kind. – larsks Sep 28 '11 at 16:40
3

add at the top of your file

#define _XOPEN_SOURCE 600
Jesse
  • 8,605
  • 7
  • 47
  • 57
mf_
  • 605
  • 8
  • 17
  • Thanks! This worked. The problem was the presence of this line: `#define _POSIX_C_SOURCE 199309` and adding `#define _XOPEN_SOURCE 600` immediately underneath it fixed it, without having to remove it entirely or change it to `_GNU_SOURCE` which would have changed the meaning of the program too much. – Krellan Jun 11 '19 at 01:48
0

Use #include <netinet/in.h> ....along with that.....and in compilation (ubuntu)....

gcc server/client -o server/client.c -lpthread

(here lpthread is a linki processing thread)...which solves your problem. :-D

jstedfast
  • 35,744
  • 5
  • 97
  • 110
aho
  • 1
0

Linking doesn't attach a header file to the program, pre-processing handles header files.

Linking attaches shared object libraries (look in /usr/lib) to compiled objects. Sometimes it is not sufficent to just add "-lnetdb" as the library might not be in the linker path. In that case, you need to use a -L(path) to add a path entry so the directive "-lnetdb" can find the correct netdb.so file.

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • It looks like I don't have a shared object named `*netdb*` in that folder... http://pastebin.com/9GPmFehC How can I obtain the SO files that I'm missing? – Pieter Sep 27 '11 at 17:05