Why does getaddrinfo() return a value in the inputs part of the function?

991 views Asked by At

The definition of getaddrinfo() is:

int getaddrinfo(const char *node,     // e.g. "www.example.com" or IP
                const char *service,  // e.g. "http" or port number
                const struct addrinfo *hints,
                struct addrinfo **res);

Per Beej's site it says:

"You give this function three input parameters, and it gives you a pointer to a linked-list, res, of results."

In terms of usage it is:

if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
    return 1;
}

// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype,
            p->ai_protocol)) == -1) {
        perror("server: socket");
        continue;
    }

    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
            sizeof(int)) == -1) {
        perror("setsockopt");
        exit(1);
    }

    if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        close(sockfd);
        perror("server: bind");
        continue;
    }

    break;
}

The actual return value "rv" is actually never used. But the results are taken from the fourth input "res" or "servinfo" in this example. I understand that a linked list is involved but it is not clear to me why the functions return does not act in the normal way. Why isn't "rv" an array that is iterated through to get the addresses? Why is the input also returning the results?

2

There are 2 answers

0
Dietrich Epp On BEST ANSWER

The value rv is used. It contains 0 if the operation succeeds, or an error code if it fails. You can even see rv being used in the sample code you provided in the question!

                                                   // ↓ result is compared to 0
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
                                                   // ↑ error message based on rv
    return 1;
}

C does not support functions with multiple return values. In a function like getaddrinfo() with multiple outputs, at least one of the outputs has to be passed into the function as a pointer.

Alternatively, a structure could have been defined to contain the result of getaddrinfo(), but that would be a bit clumsy.

0
Dmytro Bugayev On

The way the function is coded is that the return value is just a status code - whether the functions executed successfully or not. Then the more complicated result set is populated into the provided linked list pointer.

It's not an uncommon practice to do something like this in C. The **res notation is certainly confusing, but it's equivalent to say giving the function an empty LinkedList object in java, which the function then populates.

To sum up - in C - this is not uncommon. And when inputs are passed by reference/pointer rather than by value, well the function that gets them can do what it wants with them. That's true in other languages too.