Date: Wed, 27 Sep 2000 13:13:45 -0700 (PDT) From: mikko@dynas.se To: FreeBSD-gnats-submit@freebsd.org Subject: kern/21601: kevent() does not detect UDP ECONNREFUSED Message-ID: <200009272013.e8RKDjD11153@explorer.rsa.com>
next in thread | raw e-mail | index | archive | help
>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 <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<---------------------------------------------------------------------- >Fix: >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200009272013.e8RKDjD11153>