0

I'm having problems with the following piece of code:

#include <errno.h>
#include <stdlib.h>

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


[...]
    struct protoent *tcp;
    struct addrinfo hint = {0};
    struct addrinfo *addrs;
    int             status;

    tcp = getprotobyname("tcp");
    if (!tcp)
        return  -EINVAL;
    hint.ai_family      = AF_UNSPEC;
    hint.ai_socktype    = SOCK_STREAM;
    hint.ai_protocol    = tcp->p_proto;
// errno is 0
    status  = getaddrinfo("localhost", "30002", &hint, &addrs);
// errno is 22
    if (status)
        return  -labs(status);
[...]

The problem is that although it works (I'm using this for a TCP communication which indeed is working), it's inconsistent:

man getaddrinfo says nothing about errno; instead it returns an error code. Why may it be setting errno to EINVAL (22, Invalid argument) internally?

1 Answers1

8

It doesn't matter why it happens. errno only has meaning to you when a function call fails in your own code, and that function is designed to use errno to report errors to you. But that is not the case with getaddrinfo() in most situations.

getaddrinfo() may be (and likely is) using other functions internally to do its work, and if those functions fail then getaddrinfo() will silently handle them internally as needed. If those errors are fatal to getaddrinfo()'s work then it will exit with its own error code returned to you as needed.

So, as long as getaddrinfo() itself is not reporting an error code to you than you simply can't rely on errno having any kind of meaningful value. errno changing value is simply a side effect of getaddrinfo()'s internal implementation on your system.

The ONLY time you should be looking at errno after getaddrinfo() exits is when getaddrinfo() returns EAI_SYSTEM, ONLY THEN will errno have a meaningful value to you.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    @AndrewHenle read that documentation again more carefully, it DOES document the use of `errno`: "*The getaddrinfo() function shall fail and return the corresponding error value if: ... [EAI_SYSTEM] A system error occurred; **the error code can be found in errno**.*" – Remy Lebeau Feb 18 '20 at 21:03
  • Ahh, yes I needed to read more. Hmm, then I'd say it shouldn't be setting `errno` to non-zero values, per https://port70.net/~nsz/c/c11/n1570.html#7.5p3 – Andrew Henle Feb 18 '20 at 21:04
  • 1
    @AndrewHenle read that spec again more carefully: "***The value of errno may be set to nonzero by a library function call whether or not there is an error**, provided the use of errno is not documented in the description of the function in this International Standard.*" The value of `errno` is *indeterminate* upon `getaddrinfo()`'s exit, unless it returns `EAI_SYSTEM`, that is the only documented case where `errno`'s value is meaningful when `getaddrinfo()` exits. – Remy Lebeau Feb 18 '20 at 21:28
  • You can display any error with `getaddrinfo()` through `gai_strerror()`. – David C. Rankin Feb 18 '20 at 22:04
  • @DavidC.Rankin that only applies to `getaddrinfo()` own error codes. That is not the issue here. – Remy Lebeau Feb 18 '20 at 22:08
  • Yes, sorry that is what was intended, the question specifies a `0` return -- which from what I can tell means `getaddrinfo()` didn't set `errno` to begin with (it was set somewhere else). The intent of the comment was that if `getaddrinfo()` had failed and returned a non-zero exit, then further information can be obtained through `gai_strerror()`. (given that `getaddrinfo()` doesn't specify that it sets `EINVAL` at all) – David C. Rankin Feb 18 '20 at 22:13
  • @DavidC.Rankin while that is true, it is completely irrelevant to the question at hand. The question is about why `getaddrinfo()` sets `errno` to non-zero when `getaddrinfo()` succeeds and returns 0. It has nothing to do with gleaming info about why `getaddrinfo()` returns non-zero if it fails. – Remy Lebeau Feb 18 '20 at 22:16