nanog mailing list archives

Re: dns and software, was Re: Reliable Cloud host ?


From: Owen DeLong <owen () delong com>
Date: Thu, 1 Mar 2012 13:07:31 -0800


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


Current thread: