NetBSD Problem Report #58874

From www@netbsd.org  Thu Dec  5 00:25:25 2024
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange X25519 server-signature RSA-PSS (2048 bits)
	 client-signature RSA-PSS (2048 bits))
	(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id 9DB161A9238
	for <gnats-bugs@gnats.NetBSD.org>; Thu,  5 Dec 2024 00:25:25 +0000 (UTC)
Message-Id: <20241205002524.762C61A923B@mollari.NetBSD.org>
Date: Thu,  5 Dec 2024 00:25:24 +0000 (UTC)
From: campbell+netbsd@mumble.net
Reply-To: campbell+netbsd@mumble.net
To: gnats-bugs@NetBSD.org
Subject: nonblocking connect() and getsockname() error conditions
X-Send-Pr-Version: www-1.0

>Number:         58874
>Notify-List:    kim
>Category:       kern
>Synopsis:       nonblocking connect() and getsockname() error conditions
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Dec 05 00:30:01 +0000 2024
>Last-Modified:  Sun Mar 16 07:16:55 +0000 2025
>Originator:     Taylor R Campbell
>Release:        10
>Organization:
The NetBSD EINPROGRESS
>Environment:
>Description:
NetBSD and Linux disagree on some error conditions of nonblocking
connect() and getsockname() when the connection is refused,
illustrated by the following program.

Maybe both are sensible and compatible with POSIX -- I don't know, I
haven't assessed; I just stumbled upon the difference while running
git-cinnabar tests:

  https://github.com/glandium/git-cinnabar/issues/340

So I'm filing this PR to make a record of the difference and any
determination about it.

#include <sys/socket.h>

#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
	struct addrinfo *ai0, *ai, hints;
	int error;

	if (argc != 3)
		errx(1, "Usage: %s <host> <service>", argv[0]);

	memset(&hints, 0, sizeof(hints));
	hints.ai_socktype = SOCK_STREAM;
	error = getaddrinfo(argv[1], argv[2], &hints, &ai0);
	if (error)
		errx(1, "getaddrinfo: %s", gai_strerror(error));

	for (ai = ai0; ai != NULL; ai = ai->ai_next) {
		int fd;
		struct sockaddr_storage ss;
		socklen_t namelen;
		socklen_t optlen;
		socklen_t i;

		fd = socket(ai->ai_family, ai->ai_socktype|SOCK_NONBLOCK,
		    ai->ai_protocol);
		if (fd == -1) {
			warn("socket");
			continue;
		}
		if (connect(fd, ai->ai_addr, ai->ai_addrlen) != -1) {
			warnx("connect succeeded");
			(void)close(fd);
			continue;
		}
		if (errno != EINPROGRESS)
			err(1, "connect failed unexpectedly");
		warn("first connect");

		if (connect(fd, ai->ai_addr, ai->ai_addrlen) == -1)
			warn("second connect");
		else
			warnx("second connect succeeded!");

		if (getsockname(fd, (struct sockaddr *)&ss, &namelen) == -1) {
			warn("getsockname");
		} else {
			for (i = 0; i < namelen; i++) {
				fprintf(stderr, "%02hhx",
				    ((const char *)&ss)[i]);
			}
			fprintf(stderr, "\n");
		}
		optlen = sizeof(error);
		if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &optlen) ==
		    -1)
			err(1, "getsockopt(SO_ERROR)");
		errno = error;
		warn("connect SO_ERROR");
		if (connect(fd, ai->ai_addr, ai->ai_addrlen) == -1)
			warn("third connect");
		else
			warnx("third connect succeeded!");
		return 0;
	}
	errx(1, "no addresses");
}

>How-To-Repeat:
linux$ ./sn localhost 12345
sn: first connect: Operation now in progress
sn: second connect: Connection refused
00000000000000000000000000000000000000000000000000000000
sn: connect SO_ERROR: Success
sn: third connect: Operation now in progress

netbsd$ ./sn localhost 12345
sn: first connect: Operation now in progress
sn: second connect: Invalid argument
sn: getsockname: Invalid argument
sn: connect SO_ERROR: Connection refused
sn: third connect: Invalid argument
>Fix:
1. determine whether there is a problem here
2. maybe make a change

>Release-Note:

>Audit-Trail:

From: Simon Burge <simonb@NetBSD.org>
To: gnats-bugs@netbsd.org
Cc: kern-bug-people@netbsd.org, gnats-admin@netbsd.org,
    netbsd-bugs@netbsd.org
Subject: Re: kern/58874: nonblocking connect() and getsockname() error conditions
Date: Sun, 15 Dec 2024 16:27:26 +1100

 campbell+netbsd@mumble.net wrote:

 > Maybe both are sensible and compatible with POSIX -- I don't know, I
 > haven't assessed; I just stumbled upon the difference while running
 > git-cinnabar tests:
 >
 >   https://github.com/glandium/git-cinnabar/issues/340
 >
 > So I'm filing this PR to make a record of the difference and any
 > determination about it.
 >
 > [ test program deleted ]

 On FreeBSD 13.3:

 freebsd$ ./sn localhost 12345
 sn: first connect: Operation now in progress
 sn: second connect: Connection refused

 sn: connect SO_ERROR: No error: 0
 sn: third connect: Connection refused

 Cheers,
 Simon.

From: Christoph Badura <bad@bsd.de>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: Re: kern/58874: nonblocking connect() and getsockname() error
 conditions
Date: Sun, 15 Dec 2024 12:10:59 +0100

 macOS doesn't have SOCK_NONBLOCK, so:

 --- sn.c,0	2024-12-15 11:39:56
 +++ sn.c	2024-12-15 11:59:50
 @@ -2,6 +2,7 @@

  #include <err.h>
  #include <errno.h>
 +#include <fcntl.h>
  #include <netdb.h>
  #include <stdio.h>
  #include <stdlib.h>
 @@ -30,12 +31,14 @@
  		socklen_t optlen;
  		socklen_t i;

 -		fd = socket(ai->ai_family, ai->ai_socktype|SOCK_NONBLOCK,
 +		fd = socket(ai->ai_family, ai->ai_socktype,
  		    ai->ai_protocol);
  		if (fd == -1) {
  			warn("socket");
  			continue;
  		}
 +		if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) 
 +			err(1, "fcntl can't F_SETFL O_NONBLOCK");
  		if (connect(fd, ai->ai_addr, ai->ai_addrlen) != -1) {
  			warnx("connect succeeded");
  			(void)close(fd);

 output (macOS 14.7.1, amd64):

 Script started on Sun Dec 15 12:03:09 2024
 Command: ./sn localhost 12345
 sn: first connect: Operation now in progress
 sn: second connect: Connection refused
 1c1ef713000000000000000000000000000000000000000100000000
 sn: connect SO_ERROR: Undefined error: 0
 sn: third connect: Invalid argument

 Command exit status: 0
 Script done on Sun Dec 15 12:03:09 2024

 --chris

From: Valery Ushakov <uwe@stderr.spb.ru>
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: kern/58874: nonblocking connect() and getsockname() error
 conditions
Date: Sun, 15 Dec 2024 19:04:31 +0300

 Solaris 11.3 (with the fnctl patch)

 $ ./sn localhost 12345
 sn: first connect: Operation now in progress
 sn: second connect: Connection refused
 1a00000000000000000000000000000000000000000000000000000000000000
 sn: connect SO_ERROR: Error 0
 sn: third connect: Operation now in progress

 -uwe

>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.49 2026/05/14 01:52:41 riastradh Exp $
$NetBSD: gnats_config.sh,v 1.10 2026/05/13 22:00:09 riastradh Exp $
Copyright © 1994-2026 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.