dns and software, was Re: Reliable Cloud host ?
Owen DeLong
owen at delong.com
Thu Mar 1 21:07:31 UTC 2012
>
> It's deeper than just that, though. The whole paradigm is messy, from
> the point of view of someone who just wants to get stuff done. The
> examples are (almost?) all fatally flawed. The code that actually gets
> at least some of it right ends up being too complex and too hard for
> people to understand why things are done the way they are.
>
> Even in the "old days", before IPv6, geez, look at this:
>
> bcopy(host->h_addr_list[n], (char *)&addr->sin_addr.s_addr, sizeof(addr->sin_addr.s_addr));
>
> That's real comprehensible - and it's essentially the data interface
> between the resolver library and the system's addressing structures
> for syscalls.
>
> On one hand, it's "great" that they wanted to abstract the dirty details
> of DNS away from users, but I'd say they failed pretty much even at that.
>
> ... JG
> --
> Joe Greco - sol.net Network Services - Milwaukee, WI - http://www.sol.net
> "We call it the 'one bite at the apple' rule. Give me one chance [and] then I
> won't contact you again." - Direct Marketing Ass'n position on e-mail spam(CNN)
> With 24 million small businesses in the US alone, that's way too many apples.
I think that the modern set of getaddrinfo and connect is actually not that complicated:
/* Hints for getaddrinfo() (tell it what we want) */
memset(&addrinfo, 0, sizeof(addrinfo)); /* Zero out the buffer */
addrinfo.ai_family=PF_UNSPEC; /* Any and all address families */
addrinfo.ai_socktype=SOCK_STREAM; /* Stream Socket */
addrinfo.ai_protocol=IPPROTO_TCP; /* TCP */
/* Ask the resolver library for the information. Exit on failure. */
/* argv[1] is the hostname passed in by the user. "demo" is the service name */
if (rval = getaddrinfo(argv[1], "demo", &addrinfo, &res) != 0) {
fprintf(stderr, "%s: Failed to resolve address information.\n", argv[0]);
exit(2);
}
/* Iterate through the results */
for (r=res; r; r = r->ai_next) {
/* Create a socket configured for the next candidate */
sockfd6 = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
/* Try to connect */
if (connect(sockfd6, r->ai_addr, r->ai_addrlen) < 0)
{
/* Failed to connect */
e_save = errno;
/* Destroy socket */
(void) close(sockfd6);
/* Recover the error information */
errno = e_save;
/* Tell the user that this attempt failed */
fprintf(stderr, "%s: Failed attempt to %s.\n", argv[0],
get_ip_str((struct sockaddr *)r->ai_addr, buf, BUFLEN));
/* Give error details */
perror("Socket error");
} else { /* Success! */
/* Inform the user */
snprintf(s, BUFLEN, "%s: Succeeded to %s.", argv[0],
get_ip_str((struct sockaddr *)r->ai_addr, buf, BUFLEN));
debug(5, argv[0], s);
/* Flag our success */
success++;
/* Stop iterating */
break;
}
}
/* Out of the loop. Either we succeeded or ran out of possibilities */
if (success == 0) /* If we ran out of possibilities... */
{
/* Inform the user, free up the resources, and exit */
fprintf(stderr, "%s: Failed to connect to %s.\n", argv[0], argv[1]);
freeaddrinfo(res);
exit(5);
}
/* Succeeded. Inform the user and continue with the application */
printf("%s: Successfully connected to %s at %s on FD %d.\n", argv[0], argv[1],
get_ip_str((struct sockaddr *)r->ai_addr, buf, BUFLEN),
sockfd6);
/* Free up the memory held by the resolver results */
freeaddrinfo(res);
It's really hard to make a case that this is all that complex.
I put a lot of extra comments in there to make it clear what's happening for people who may not be used to coding in C. It also contains a whole lot of extra user notification and debugging instrumentation because it is designed as an example people can use to learn with.
Yes, this was a lot messier and a lot stranger and harder to get right with get*by{name,addr}, but, those days are long gone and anyone still coding with those needs to move forward.
Owen
More information about the NANOG
mailing list