From owner-freebsd-bugs Wed Sep 27 13:20:22 2000 Delivered-To: freebsd-bugs@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id 57B8937B423 for ; Wed, 27 Sep 2000 13:20:01 -0700 (PDT) Received: (from gnats@localhost) by freefall.freebsd.org (8.9.3/8.9.2) id NAA94656; Wed, 27 Sep 2000 13:20:01 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: from karon.dynas.se (karon.dynas.se [192.71.43.4]) by hub.freebsd.org (Postfix) with SMTP id DB0C837B422 for ; Wed, 27 Sep 2000 13:13:53 -0700 (PDT) Received: (qmail 89815 invoked from network); 27 Sep 2000 20:13:51 -0000 Received: from spirit.sto.dynas.se (HELO spirit.dynas.se) (172.16.1.10) by karon.sto.dynas.se with SMTP; 27 Sep 2000 20:13:51 -0000 Received: (qmail 10194 invoked from network); 27 Sep 2000 20:14:00 -0000 Received: from explorer.rsa.com (10.81.217.59) by spirit.dynas.se with SMTP; 27 Sep 2000 20:14:00 -0000 Received: (from mikko@localhost) by explorer.rsa.com (8.11.0/8.11.0) id e8RKDjD11153; Wed, 27 Sep 2000 13:13:45 -0700 (PDT) (envelope-from mikko) Message-Id: <200009272013.e8RKDjD11153@explorer.rsa.com> Date: Wed, 27 Sep 2000 13:13:45 -0700 (PDT) From: mikko@dynas.se Reply-To: mikko@dynas.se To: FreeBSD-gnats-submit@freebsd.org X-Send-Pr-Version: 3.2 Subject: kern/21601: kevent() does not detect UDP ECONNREFUSED Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org >Number: 21601 >Category: kern >Synopsis: kevent() does not detect UDP ECONNREFUSED >Confidential: no >Severity: serious >Priority: high >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Wed Sep 27 13:20:00 PDT 2000 >Closed-Date: >Last-Modified: >Originator: Mikko Tyolajarvi >Release: FreeBSD 4.1-STABLE i386 >Organization: >Environment: This is on -STABLE as of a few days ago (Sep 24, 2000). It is probably in 4.1.1R >Description: 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 #include #include #include #include #include #include /* * 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<---------------------------------------------------------------------- >Fix: >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message