Skip site navigation (1)Skip section navigation (2)
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>