kern/135458: Missing errno translation in Linux getsockopt(, ,
SO_ERROR, , )
Stefan Schmidt
stefan.schmidt at stadtbuch.de
Wed Jun 10 23:30:02 UTC 2009
>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 at 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:
More information about the freebsd-bugs
mailing list