Skip to content

Commit

Permalink
Fedora(rpmlint): Migrate from deprecated gethostbyname to getaddrinfo
Browse files Browse the repository at this point in the history
POSIX.1-2008 removes the specifications of gethostbyname(), gethostbyaddr(),
and h_errno, recommending the use of getaddrinfo(3) and getnameinfo(3) instead.

While it works fine and is unlikely to be removed very soon (though you
never know for sure), it's deprecation is likely caused by the fact that
it does not support IPv6 and it's not thread-safe.

While these are not concerns for uftrace right now (but IPv6 support
could be added as a followup), rpmlint warns about it, and it's good
to modernize and fix the warning.

The Fedora review-tool runs rpmlint on the binary packages and found
that the uftrace tool was using gethostbyname, so it eases any future
review if we upgrade.

The changes are based on existing upgrades for other code and can be
cross-checked also with the reviewed code in the URL below. This is
only a first step to make the conversion in baby steps. The next step
would be to loop over the potentially multiple IPv4 adresses:
stackoverflow.com/questions/52727565/client-in-c-use-gethostbyname-or-getaddrinfo
An example for IPv4+IPv6 support is shown in answer# 8.
  • Loading branch information
Bernhard Kaindl committed Mar 27, 2023
1 parent e472b33 commit d3f0484
Showing 1 changed file with 30 additions and 8 deletions.
38 changes: 30 additions & 8 deletions cmds/recv.c
Expand Up @@ -81,23 +81,45 @@ int setup_client_socket(struct uftrace_opts *opts)
.sin_family = AF_INET,
.sin_port = htons(opts->port),
};
struct hostent *hostinfo;
struct addrinfo *results, hints;
int err;
int sock;
int one = 1;

sock = socket(AF_INET, SOCK_STREAM, 0);
// Since your original code is using sockaddr_in and AF_INET,
// use it as well. Use AF_UNSPEC above to allow getaddrinfo()
// to find both IPv4 and IPv6 addresses for the hostname:
//
// Just make sure the rest of your code is equally family-
// agnostic when dealing with the IP addresses associated
// with this connection. For instance, make sure any uses
// of sockaddr_in are changed to sockaddr_storage,
// and pay attention to its ai_ or ss_family field, etc.
//
// Next, we may loop over trying all addresses returned by getaddrinfo
// like in the example loops over the results list (accepted answer):
// IPv4 and IPv6 support is shown in answer 8 here:
// stackoverflow.com/questions/52727565/client-in-c-use-gethostbyname-or-getaddrinfo

memset(&hints, 0, sizeof hints);
hints.ai_family = addr.sin_family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

err = getaddrinfo(opts->host, NULL, &hints, &results);
if (err)
pr_err_ns("Failed to resolve host %s: %s\n", opts->host, gai_strerror(err));

addr.sin_addr = ((struct sockaddr_in *)results->ai_addr)->sin_addr;
freeaddrinfo(results);

sock = socket(hints.ai_family, hints.ai_socktype, 0);
if (sock < 0)
pr_err("socket create failed");

if (setsockopt(sock, SOL_TCP, TCP_NODELAY, &one, sizeof(one)) != 0)
pr_warn("socket setting failed\n");

hostinfo = gethostbyname(opts->host);
if (hostinfo == NULL)
pr_err("cannot find host: %s", opts->host);

addr.sin_addr = *(struct in_addr *)hostinfo->h_addr;

if (connect(sock, (const struct sockaddr *)&addr, sizeof(addr)) < 0)
pr_err("socket connect failed (host: %s, port: %d)", opts->host, opts->port);

Expand Down

0 comments on commit d3f0484

Please sign in to comment.