user1018513
user1018513

Reputation: 1682

Most efficient way to pass Java socket file descriptor to C binary file

I can't seem to find the answer anywhere, I'm trying to obtain a socket in Java, and hand over its file descriptor number so that I can use it in a C binary (the fd would be as argument).

I've obtained the FileDescriptor using reflection... but can't access the actual number anywhere.

I know other people have suggested JNI, but I'd like to keep it within Java if possible (and couldn't fully figure out how to do it)

Upvotes: 1

Views: 6987

Answers (2)

FThompson
FThompson

Reputation: 28687

Stephen C's answer addresses how to get a FileDescriptor, but here's a method to the file descriptor number from that object. On Windows, FileDescriptor uses long handle instead of int fd internally, so this method first checks if handle is used and returns that if so, otherwise it falls back to returning fd. I haven't tested this with sockets as OP is using, but I imagine Windows JVMs still use handle.

public static long fileno(FileDescriptor fd) throws IOException {
    try {
        if (fd.valid()) {
            // windows builds use long handle
            long fileno = getFileDescriptorField(fd, "handle", false);
            if (fileno != -1) {
                return fileno;
            }
            // unix builds use int fd
            return getFileDescriptorField(fd, "fd", true);
        }
    } catch (IllegalAccessException e) {
        throw new IOException("unable to access handle/fd fields in FileDescriptor", e);
    } catch (NoSuchFieldException e) {
        throw new IOException("FileDescriptor in this JVM lacks handle/fd fields", e);
    }
    return -1;
}

private static long getFileDescriptorField(FileDescriptor fd, String fieldName, boolean isInt) throws NoSuchFieldException, IllegalAccessException {
    Field field = FileDescriptor.class.getDeclaredField(fieldName);
    field.setAccessible(true);
    long value = isInt ? field.getInt(fd) : field.getLong(fd);
    field.setAccessible(false);
    return value;
}

Upvotes: 1

Stephen C
Stephen C

Reputation: 718826

In Java 7, you can cast a SocketInputStream to a FileInputStream, and call getFD() to get the FileDescriptor object.

Then you can use reflection to access the FileDescriptor object's private int fd field. (You use the Class.getDeclaredField(...) method to get the Field, call Field.setAccessible(true), and then get the field's value using Field.getInt(...).)


Beware that you may be making your code platform dependent by doing this. There are no guarantees that the particular private field will be present in older ... or forth-coming versions of Java, or in implementations of Java done by other vendors / suppliers.

Upvotes: 4

Related Questions