[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RFE: File Descriptor passing and socket pair creation

From: tetsujin
Subject: RFE: File Descriptor passing and socket pair creation
Date: Thu, 15 Jun 2017 15:33:33 -0400

Since the subject's come up - difficulties with /dev/tcp, no timeout
feature, somehow a failure to interrupt it, etc.  I want to suggest
an alternative.  I don't propose removing /dev/tcp from Bash (since
it's been there quite a long time, people use it and I'm sure many
people like it), but I propose an alternative approach for providing
similar functionality in the future:

In Unix, there are what's known as "local" and "Unix Domain" sockets.
A nice feature of these is the ability to pass open files between
processes. Integrating that functionality into the shell opens up a
lot of possibilities for integrating other things into the shell
without having to write them as shell "builtin" libraries.
Specifically, if you provide "socketpair" and "recvmsg" as
shell-built-ins, then processes for opening files and file-like
devices can be implemented as external executables.

I wrote an interface to socketpair(), sendmsg(), and recvmsg() as
shell builtins (for Bash and ksh) as part of a library I'm working on
called "shell-pepper". The library is like a platform for delivering
functionality I want to see in the shell, but don't expect to be
accepted by the upstream maintainers. :) With it you could write an
external program to handle the task of opening that TCP connection,
and send the file table entry for the connection over a local socket -
then the connection process COULD run in the background, kind of like

$ enable -f ./socketpair socketpair
$ enable -f ./recvmsg recvmsg
$ socketpair s   # Create a socketpair, store the FDs in $s
$ tcp_connect localhost 12345 >&${s[1]}  &    # Run a program to
create a TCP connection
$ exec {s[1]}<&-    # Close the socket we sent to tcp_connect, so
we can tell when tcp_connect is done with it
$ recvmsg msg tcp_fd <&${s[0]}   # Get a response message, including
file descriptors, from tcp_connect
$ exec {s[0]}<&-    # Alas, attempting to use this syntax on Bash
4.2 will kill your shell!

Of course all the above is way more code than simply

$ exec {fd}<>/dev/tcp/localhost/12345

And most notably, it doesn't allow you to localize the open file
descriptor the way a redirect does:

$ { cmd1; cmd2; etc; } <>/dev/tcp/localhost/49152
$ # TCP connection was closed automatically when the commands above
were finished.

The upshot is that it gives you flexibility: If you want different
types of connections (named socket, etc.), or different connection
options (datagram, timeout, etc.), or authentication as part of
creating the connection, it can be implemented as part of the
executable. Then the whole ugly process of creating the socketpair,
running the command, receiving the message, etc. could be wrapped in a
shell function. 

Better yet, look how this plays out in ksh:

$ tcp_connect localhost 12345 | recvmsg msg tcp_fd

...Because "pipes" in Korn Shell are actually socket pairs, (and
because it has the equivalent of shopt "lastpipe" on by default) you
can receive file descriptors from external commands without having to
explicitly create and destroy a socketpair. (Though the use of sockets
in ksh has negative side-effects as well - for instance opening files
in /dev/fd on Linux works for pipes, but not for sockets. Maybe some
alternative could be considered that lends comparable convenience?)

I realize "socketpair()" and FD passing are not universally supported
over all the platforms supported by Bash...  The feature goes back
POSIX-2001, so it should be pretty broadly supported at least.

----- Original Message -----
From: address@hidden
Sent:Thu, 15 Jun 2017 09:36:12 -0600
Subject:Why does 'connect' take so long (sometimes) and can't be

 This is a little complicated and I can't give you full details on how
 replicate it, since I don't fully understand it myself. But under
 circumstances, the following line takes a very long time to execute:

 exec 5<>/dev/tcp/localhost/12345

reply via email to

[Prev in Thread] Current Thread [Next in Thread]