dns and software, was Re: Reliable Cloud host ?

Owen DeLong owen at delong.com
Thu Mar 1 15:07:31 CST 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]);

  /* 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 */
      /* Stop iterating */
  /* 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]);
  /* 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),
  /* Free up the memory held by the resolver results */

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.


More information about the NANOG mailing list