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 this: $ 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: gaze...@xmission.com To:<bug-bash@gnu.org> Cc: Sent:Thu, 15 Jun 2017 09:36:12 -0600 Subject:Why does 'connect' take so long (sometimes) and can't be interrupted? Description: This is a little complicated and I can't give you full details on how to replicate it, since I don't fully understand it myself. But under certain circumstances, the following line takes a very long time to execute: exec 5<>/dev/tcp/localhost/12345