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>
