Since the change from poll() to kqueue() in the resolver, res_send() is no longer able to "detect the absence of a name server without timing out" (quoted from res_send.c). Unless there is some (undocumented) flag combination I haven't found (and which is not used res_send), kevent() does not detect the socket error that you get when sending an UDP datagram from a connected socket to a port where nobody is listening. So, I assume this is a kernel bug. [ For me this manifests itself as all sorts of network related operations being really slow on my laptop, which is the victim of a braindead DHCP setup, listing 127.0.0.1 as the first name server, and as bin/15046 continues to be ignored, the hook provided in /sbin/dhclient-script, which would have offered a simple, documented way to filter the data is not available >:-( ] Another way to put it is "traceroute cannot be rewritten to use kqueue()" How-To-Repeat: The following little program will send an UDP datagram to a port, using either select() or kevent() to wait for error indication. Thus (on a machine with no name server, but any unused port will do): % ./a.out 127.0.0.1 53 # Uses select() socket error: Connection refused % ./a.out 127.0.0.1 53 foo # Uses kevent() timeout (1 second) ---8<---------------------------------------------------------------------- #include <sys/types.h> #include <sys/socket.h> #include <sys/event.h> #include <sys/time.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> /* * Usage: ./a.out dotted-ip port-num [ use-kqueue ] */ int main(int argc, char **argv) { struct sockaddr_in ia; struct kevent kv; int sock, n, err; ia.sin_family = AF_INET; ia.sin_addr.s_addr = inet_addr(argv[1]); ia.sin_port = htons(atoi(argv[2])); sock = socket(PF_INET, SOCK_DGRAM, 0); if (connect(sock, (struct sockaddr *)&ia, sizeof(ia)) < 0) { perror("connect"); return 1; } if (send(sock, "?", 1, 0) != 1) { perror("send"); return 1; } if (argc > 3) { struct timespec ts; int kq; kq = kqueue(); ts.tv_sec = 1; ts.tv_nsec = 0; memset(&kv, 0, sizeof(kv)); kv.ident = sock; kv.flags = EV_ADD | EV_ONESHOT; kv.filter = EVFILT_READ; n = kevent(kq, &kv, 1, &kv, 1, &ts); } else { struct timeval tv; fd_set fds; FD_ZERO(&fds); FD_SET(sock, &fds); tv.tv_sec = 1; tv.tv_usec = 0; n = select(sock+1, &fds, NULL, NULL, &tv); } switch (n) { case 0: printf("timeout (one second)\n"); break; case 1: n = sizeof(err); if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &n) < 0) { perror("getsockopt"); } else { printf("socket error: %s\n", strerror(err)); } break; default: perror("kevent/select\n"); break; } return 0; } ---8<----------------------------------------------------------------------
State Changed From-To: open->closed Bug found, fix applied to -stable and -current.