I would like to create a TCP server application which lets the user choose the local address that is used in the bind call. The user may provide a textual representation of a host name or IP address, so I thought of using the getaddrinfo function to translate the textual representation into one or several sockaddr structs (performing name lookup if necessary).
Now here's my problem: The getaddrinfo function does not seem to suit my needs, because it requires the AI_PASSIVE flag to be set in the hints structure in order to obtain socket addresses that may be used in bind calls. But if I use AI_PASSIVE, I can not use the nodename parameter anymore, which defeats the whole purpose of letting the user choose the local address. If I do not provide AI_PASSIVE, getaddrinfo will only return those addresses which can be used in connect, sendto and sendmsg calls, but there might be addresses that can be used for binding but not for connect, sendto or sendmsg calls, which would be omitted. See the POSIX specification regarding the getaddrinfo/freeaddrinfo functions.
To clarify my needs, here is a sketch of the application I am trying to create:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
int main(int argc, char **argv)
{
if (argc != 3) {
fprintf(stderr, "Usage: %s address port\n", argv[0]);
return EXIT_FAILURE;
}
struct addrinfo hints = {0};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
struct addrinfo *result;
/* The next line won't work as intended! It will behave as if the
AI_PASSIVE flag was not set. */
if (getaddrinfo(argv[1], argv[2], &hints, &result) != 0) {
perror("getaddrinfo");
return EXIT_FAILURE;
}
/* Iterate result list */
int sfd;
struct addrinfo *rp = result;
do {
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1)
continue;
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
break; /* Success */
close(sfd);
rp = rp->ai_next;
} while (rp != NULL);
freeaddrinfo(result);
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not bind\n");
return EXIT_FAILURE;
}
/* ... use socket bound to sfd ... */
close(sfd);
return EXIT_SUCCESS;
}
I actually have several questions regarding the topic. First off, why is the nodename parameter forbidden when using the AI_PASSIVE flag? What is the intention? It does not make any sense to me. Is there any (preferably POSIX-conform) way to find local addresses that I can bind to and that correspond to a given host name or IP address in textual representation at all? Provided that the given nodename corresponds to a local address and AI_PASSIVE is not set, will there be any addresses returned by getaddrinfo, that can not be used for binding? Or worse, will there be any addresses that are only suitable for binding and that will not be returned in this case?
Related (and not answered satisfactorily): getaddrinfo: in what way is AI_PASSIVE ignored if the nodename is specified?