> > 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