Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 10 Jun 2009 23:25:46 GMT
From:      Stefan Schmidt <stefan.schmidt@stadtbuch.de>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/135458: Missing errno translation in Linux getsockopt(, , SO_ERROR, , )
Message-ID:  <200906102325.n5ANPkun062552@www.freebsd.org>
Resent-Message-ID: <200906102330.n5ANU1nR019953@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         135458
>Category:       kern
>Synopsis:       Missing errno translation in Linux getsockopt(,,SO_ERROR,,)
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>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:
>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:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200906102325.n5ANPkun062552>