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>