Search code examples
cmemset

Memset function in programm that resolves host adresses


First of all, i understand what the code (see at the end of the post) does in general and i dont want an overall explanation.

What i don't understand is this particular line of code: memset(&hints, 0, sizeof(struct addrinfo));

What i get so far is that a memset() is a function to fill the string which it is pointed to up.

It has three parameters, first the pointer to the string, second the value to be set and third the number of bytes set to the value.

In this case the the value to be filled up is &hints which would be the adress of the variable hints. The value which should be set is 0 so it is filled with zeroes. And last it is filled to the size of the struct addrinfo.

So in this case memset() generates for the variable hints zeroes to the size of the struct. Did i get this right?

If yes, why is this needed in my example?

#include <stdlib.h>/* EXIT_SUCCESS */
#include <stdio.h>/* printf */
#include <string.h>/* memset() */
#include <errno.h>/* int errno */
#include <sys/types.h>/* socket defines */
#include <sys/socket.h>/* socket() */
#include <netdb.h>/* getaddrinfo() */
#define ECHO_PORT "7"

int main (int argc, char* argv[]){
if (argc != 2) {
printf ("Usage: %s HOSTNAME\n", argv[0]);
exit(EXIT_FAILURE);
}

/* Resolve host addresses: */

struct addrinfo hints;
struct addrinfo* result, *rp;

memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;/* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM;/* Stream socket */
hints.ai_flags = 0;
hints.ai_protocol = 0;/* Any protocol */

int err = getaddrinfo(argv[1], ECHO_PORT, &hints, &result);

/* Handle potential error: */

if (err) {
printf("Error: getaddrinfo: %s\n", gai_strerror(err));
exit(EXIT_FAILURE);
}

/* Print names found: */

printf("Addresses for %s:\n", argv[1]);
for (rp = result; rp != NULL; rp = rp->ai_next) {
int af = rp->ai_family;
char* address = NULL;
int ok;

if (AF_INET == rp->ai_family) {
uint8_t in_addr =((struct sockaddr_in*)rp->ai_addr)->sin_addr.s_addr;
address = malloc(INET_ADDRSTRLEN);
ok = inet_ntop(af, &in_addr, address, INET_ADDRSTRLEN);
}

if (AF_INET6 == rp->ai_family) {
char* in6_addr =((struct sockaddr_in6*)rp->ai_addr)->sin6_addr.s6_addr;
address = malloc(INET6_ADDRSTRLEN);
ok = inet_ntop(af, in6_addr, address, INET6_ADDRSTRLEN);
}

if (ok) {
printf("%s\n", address);
}
else {
perror("inet_ntop");
}

free(address);
}

freeaddrinfo(result);

return EXIT_SUCCESS;

}

Solution

  • Yes, your understanding is basically correct. The code is simply filling the entire hints variable with 0x00 bytes before passing it to getaddrinfo(). This is needed to initialize the hints to a default state, which is important because addrinfo contains flags and memory pointers to control getaddrinfo()'s behavior. So you can't just leave the hints in an uninitialized state, it will contain random garbage that will cause undefined behavior, confusing getaddrinfo() and/or even leading to corrupted memory, crashes, etc.

    Using the memset() is a quick way to initialize all of the fields of the hints to zeros in one quick operation, instead of initializing each field individually. This way, you can focus on assigning values to just the fields you are actually interested in.

    An easier way to initialize the hints is like this instead:

    struct addrinfo hints = {0};
    

    This will value-initialize the first field (ai_flags) to 0, and default-initialize the remaining fields to their default values, which in this case is also zeros.