From nobody@FreeBSD.org  Wed Jun 10 23:25:47 2009
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 88A59106566C
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 10 Jun 2009 23:25:47 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 766C38FC13
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 10 Jun 2009 23:25:47 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id n5ANPki4062553
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 10 Jun 2009 23:25:46 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id n5ANPkun062552;
	Wed, 10 Jun 2009 23:25:46 GMT
	(envelope-from nobody)
Message-Id: <200906102325.n5ANPkun062552@www.freebsd.org>
Date: Wed, 10 Jun 2009 23:25:46 GMT
From: Stefan Schmidt <stefan.schmidt@stadtbuch.de>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Missing errno translation in Linux getsockopt(,,SO_ERROR,,)
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         135458
>Category:       kern
>Synopsis:       Missing errno translation in Linux getsockopt(,,SO_ERROR,,)
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    dchagin
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Jun 10 23:30:01 UTC 2009
>Closed-Date:    
>Last-Modified:  Mon Jul 12 21:40:02 UTC 2010
>Originator:     Stefan Schmidt
>Release:        FreeBSD 8.0-CURRENT as of 2009-06-10
>Organization:
>Environment:
FreeBSD shuttle.stadtbuch.de 8.0-CURRENT FreeBSD 8.0-CURRENT #0: Tue Jun  9 21:16:43 CEST 2009     root@shuttle.stadtbuch.de:/usr/obj/usr/src/sys/SHUTTLE  amd64

>Description:
FreeBSD's Linux emulation layer uses a translation table to convert Linux errnos to FreeBSD errnos.

However, while working on some non-blocking networking code (Java NIO, running on Sun's Linux JDK 1.6.0_14), I found that some errnos are not translated. For example, I get "No data available" (= Linux errno 61) instead of the expected "Connection refused" (= FreeBSD errno 61).

Some digging revealed that Sun's implementation of Java NIO uses getsockopt under the hood to retrieve the failure reason of a non-blocking connect request. And the emulated Linux getsockopt does not translate FreeBSD's errno to Linux'...
>How-To-Repeat:
The following (stripped down) test program (sorry for using Java) initiates a non-blocking connect and waits for the result.
Using a Linux JDK (e.g. 1.6.0_14), the output is "java.net.ConnectException: No data available" instead of the expected "java.net.ConnectException: Connection refused".

package javaapplication1;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

public class Main {

    public static void main(String[] args) {
        try {
            Selector selector = Selector.open();
            SocketChannel socketChannel = SocketChannel.open();

            socketChannel.configureBlocking(false);
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
            socketChannel.connect(new InetSocketAddress("127.0.0.1", 12345));

            selector.select();
            socketChannel.finishConnect();
        } catch (IOException e) {
            System.out.println(e);
        }
    }
}

>Fix:
I've attached a patch which adds errno translation to the emulated getsockopt syscall. Works fine for me. Maybe someone can review the patch and commit it?

Patch attached with submission follows:

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	getsockopt.patch
#
echo x - getsockopt.patch
sed 's/^X//' >getsockopt.patch << '375616829dae7c22aabec4029ce3ff39'
XIndex: sys/compat/linux/linux_socket.c
X===================================================================
XRCS file: /home/ncvs/src/sys/compat/linux/linux_socket.c,v
Xretrieving revision 1.99
Xdiff -u -r1.99 linux_socket.c
X--- sys/compat/linux/linux_socket.c	1 Jun 2009 20:54:41 -0000	1.99
X+++ sys/compat/linux/linux_socket.c	10 Jun 2009 22:22:41 -0000
X@@ -396,6 +396,23 @@
X 	return (error);
X }
X 
X+static int
X+bsd_to_linux_errno(int *arg)
X+{
X+	int errno;
X+	size_t errno_len = sizeof(int);
X+	int error;
X+
X+	if ((error = copyin(arg, &errno, errno_len)))
X+		return (error);
X+
X+	if (errno < elf_linux_sysvec.sv_errsize)
X+		errno = -elf_linux_sysvec.sv_errtbl[errno];
X+
X+	error = copyout(&errno, arg, errno_len);
X+
X+	return (error);
X+}
X 
X static int
X linux_sa_put(struct osockaddr *osa)
X@@ -1521,11 +1538,12 @@
X 	bsd_args.val = PTRIN(args->optval);
X 	bsd_args.avalsize = PTRIN(args->optlen);
X 
X-	if (name == IPV6_NEXTHOP) {
X-		error = getsockopt(td, &bsd_args);
X+	error = getsockopt(td, &bsd_args);
X+
X+	if (name == IPV6_NEXTHOP)
X 		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
X-	} else
X-		error = getsockopt(td, &bsd_args);
X+	else if (name == SO_ERROR)
X+		bsd_to_linux_errno((int *)bsd_args.val);
X 
X 	return (error);
X }
375616829dae7c22aabec4029ce3ff39
exit



>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->dchagin 
Responsible-Changed-By: dchagin 
Responsible-Changed-When: Thu Jun 11 04:41:20 UTC 2009 
Responsible-Changed-Why:  
take it. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=135458 

From: Stefan Schmidt <stefan.schmidt@stadtbuch.de>
To: bug-followup@FreeBSD.org, stefan.schmidt@stadtbuch.de
Cc:  
Subject: Re: kern/135458: Missing errno translation in Linux getsockopt(,,SO_ERROR,,)
Date: Wed, 09 Dec 2009 00:21:10 +0100

 This is a multi-part message in MIME format.
 --------------030107000206070805050905
 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
 Content-Transfer-Encoding: 7bit
 
 Updated patch to apply cleanly, tested against RELENG_8 as of 2009-12-08.
 
 --------------030107000206070805050905
 Content-Type: text/plain;
  name="getsockopt.patch"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline;
  filename="getsockopt.patch"
 
 Index: sys/compat/linux/linux_socket.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/compat/linux/linux_socket.c,v
 retrieving revision 1.101.2.2
 diff -u -w -d -r1.101.2.2 linux_socket.c
 --- sys/compat/linux/linux_socket.c	6 Dec 2009 09:36:11 -0000	1.101.2.2
 +++ sys/compat/linux/linux_socket.c	8 Dec 2009 23:11:53 -0000
 @@ -394,6 +394,23 @@
  	return (error);
  }
  
 +static int
 +bsd_to_linux_errno(int *arg)
 +{
 +	int errno;
 +	size_t errno_len = sizeof(int);
 +	int error;
 +
 +	if ((error = copyin(arg, &errno, errno_len)))
 +		return (error);
 +
 +	if (errno < elf_linux_sysvec.sv_errsize)
 +		errno = -elf_linux_sysvec.sv_errtbl[errno];
 +
 +	error = copyout(&errno, arg, errno_len);
 +
 +	return (error);
 +}
  
  static int
  linux_sa_put(struct osockaddr *osa)
 @@ -1507,11 +1524,12 @@
  	bsd_args.val = PTRIN(args->optval);
  	bsd_args.avalsize = PTRIN(args->optlen);
  
 -	if (name == IPV6_NEXTHOP) {
  		error = getsockopt(td, &bsd_args);
 +
 +	if (name == IPV6_NEXTHOP)
  		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
 -	} else
 -		error = getsockopt(td, &bsd_args);
 +	else if (name == SO_ERROR)
 +		bsd_to_linux_errno((int *)bsd_args.val);
  
  	return (error);
  }
 
 --------------030107000206070805050905--

From: Chagin Dmitry <dchagin@FreeBSD.org>
To: bug-followup@FreeBSD.org, stefan.schmidt@stadtbuch.de
Cc:  
Subject: Re: kern/135458: Missing errno translation in Linux
	getsockopt(,,SO_ERROR,,)
Date: Tue, 13 Jul 2010 01:37:35 +0400

 --1UWUbFP1cBYEclgG
 Content-Type: multipart/mixed; boundary="/04w6evG8XlLl3ft"
 Content-Disposition: inline
 
 
 --/04w6evG8XlLl3ft
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 Content-Transfer-Encoding: quoted-printable
 
 
 Please, test attached patch.
 
 --=20
 Have fun!
 chd
 
 --/04w6evG8XlLl3ft
 Content-Type: text/x-diff; charset=us-ascii
 Content-Disposition: attachment; filename="so_error.patch"
 Content-Transfer-Encoding: quoted-printable
 
 diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socke=
 t.c
 index d94d926..2f3601d 100644
 --- a/sys/compat/linux/linux_socket.c
 +++ b/sys/compat/linux/linux_socket.c
 @@ -1448,10 +1448,12 @@ linux_getsockopt(struct thread *td, struct linux_ge=
 tsockopt_args *args)
  	} */ bsd_args;
  	l_timeval linux_tv;
  	struct timeval tv;
 -	socklen_t tv_len, xulen;
 +	socklen_t tv_len, xulen, len;
  	struct xucred xu;
  	struct l_ucred lxu;
  	int error, name;
 +	struct proc *p =3D td->td_proc;
 +	int newval;
 =20
  	bsd_args.s =3D args->s;
  	bsd_args.level =3D linux_to_bsd_sockopt_level(args->level);
 @@ -1490,6 +1492,21 @@ linux_getsockopt(struct thread *td, struct linux_get=
 sockopt_args *args)
  			return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu)));
  			/* NOTREACHED */
  			break;
 +		case SO_ERROR:
 +			len =3D sizeof(newval);
 +			error =3D kern_getsockopt(td, args->s, bsd_args.level,
 +			    name, &newval, UIO_SYSSPACE, &len);
 +			if (error)
 +				return (error);
 +			if (p->p_sysent->sv_errsize) {
 +				if (newval < p->p_sysent->sv_errsize ||
 +				    (newval =3D EINVAL) < p->p_sysent->sv_errsize)
 +					newval =3D p->p_sysent->sv_errtbl[newval];
 +				else
 +					newval =3D 0;     /* XXX */
 +			}
 +			return (copyout(&newval, PTRIN(args->optval), sizeof(newval)));
 +			/* NOTREACHED */
  		default:
  			break;
  		}
 
 --/04w6evG8XlLl3ft--
 
 --1UWUbFP1cBYEclgG
 Content-Type: application/pgp-signature
 Content-Disposition: inline
 
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.10 (FreeBSD)
 
 iEYEARECAAYFAkw7ix8ACgkQ0t2Tb3OO/O2a3gCeM0PF+kCE+GsiWCb1MIkeIQpZ
 x1wAnRgwg228CBpUie6UitsovZI5rb0F
 =/DT1
 -----END PGP SIGNATURE-----
 
 --1UWUbFP1cBYEclgG--
>Unformatted:
