Fork me on GitHub

Sending and receiving File Descriptors

A very useful feature of Unix Domain Sockets is the ability to send and receive file descriptors between processes.

This, for example, enables non-privileged processes to access otherwise restricted files: A privileged process (e.g., running as root, or as a UID with special access rights) opens the restricted file, and then exposes the file handle to another process via AF_UNIX sockets.

File descriptors are sent as so-called “ancillary messages” along with regulary payload. They cannot be sent alone, so make sure that you send at least some data.

Sending file descriptors

AFUNIXSocket socket = ...

FileInputStream fin = new FileInputStream(file);
socket.setOutboundFileDescriptors(fin.getFD());
// you can also send more than one FD at the same time, just make sure they're all part of the same call to setOutboundFileDescriptors. 

// Ancillary messages are sent _along_ regular in-band messages, so we have to send something here.
os.write("Some message".getBytes("UTF-8"));

Receiving file descriptors

AFUNIXSocket socket = ...

// set ancillary receive buffer to a reasonable size (disabled by default!)
socket.setAncillaryReceiveBufferSize(1024);

InputStream in = socket.getInputStream();
// do you regular socket IO here
in.read(...)

// If there were any file descriptors sent as ancillary messages, check them right after a call to read
FileDescriptor[] descriptors = socket.getReceivedFileDescriptors();
if (descriptors != null) {
  for (FileDescriptor fd : descriptors) {
    FileInputStream fin = new FileInputStream(fd);
    // do something with the stream
  }
}

Even easier with RMI

If you’re using junixsocket-rmi for inter-process communication, you can simply wrap streams with RemoteFileInput/RemoteFileOutput (or the generic RemoteFileDescriptor) and not worry about the technicalities:

FileInputStream fin = ...;

RemoteFileInput rfi = new RemoteFileInput(socketFactory, fin);
// rfi can now be used for inter-process communication via RMI:
someRMIService.someMethod(rfi);

// on the receiving side:
public void someMethod(RemoteFileInput rfi) throws IOException {
    FileInputStream fin = rfi.asFileInputStream();
    // ...
    fin.close(); // closes the stream for this process only (different file handle).
} 

Due diligence

It is recommended to authenticate the connection, since you certainly don’t want unauthorized callers to obtain access to potentially secret information.

You may either use your own SSL/TLS authentication atop the Socket, or simply use peer credentials.

Not supported by all platforms

Not all platforms support file descriptors over AF_UNIX. Make sure they’re available using

AFUNIXSocket.supports(AFUNIXSocketCapability.CAPABILITY_FILE_DESCRIPTORS).