Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add support for connecting via UNIX socket #63

Merged
merged 2 commits into from
Jan 10, 2018

Conversation

jordemort
Copy link

This adds support for connecting via a UNIX socket. I am not aware of any editors that actually implement listening on a UNIX socket, but recent versions of OpenSSH are capable of forwarding a remote socket to a local TCP port, which is how I'm using it. It's nice to have the option for a bit more privacy if you're SSHing into a shared machine, and a bit easier to script around contention between multiple sessions all wanting to forward the same socket.

The socket path can be specified via unix in the config file, -u or --unix on the command-line, or in the RMATE_UNIX environment variable.

This implementation requires that a version of nc that understands the -U option is installed; unfortunately, bash doesn't seem to have a facility for connecting to UNIX sockets like it does for TCP sockets. It could also be implemented in terms of socat or possibly other tools. I'm not sure if it's worth implementing a fallback or some way to customize the command used to connect to the socket; I'd be willing to look into that if there's interest.


fifodir=$(mktemp -d) && \
mkfifo "$fifodir/in" "$fifodir/out" && \
( (nc -U "$unix" < "$fifodir/in" > "$fifodir/out" &) &) && \
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if I should be doing something smarter than nothing with the stderr of nc; maybe direct it to a file in the fifodir and cat it out if there's a connection error?

exit 1
connect_status=$?

[ -d "$fifodir" ] && rm -rf "$fifodir"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After everything is connected we can just trash the fifodir immediately, as everything has its file descriptors open and nothing else will need to refer to anything there by name again.

exit 1
fi
else
exec 3<> "/dev/tcp/$host/$port" && exec 4>&3
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately I wasn't able to figure out how to get read and write to the socket happening on the same file descriptor, so I had to split them, and that meant splitting them even in the TCP case :(

@aurora
Copy link
Owner

aurora commented Jul 26, 2017

Nice! Thank you! I have to play around with this a little before merging :-)

@jordemort
Copy link
Author

Cool, I might iterate a bit more on this later tonight to tighten up the error checking and add socat and custom command support.

@aurora
Copy link
Owner

aurora commented Jul 26, 2017

Btw.: what i am always wondering when writing a shell script -- is there a "best-practice" to check command compatibility? Eg. to verify that nc supports -U in this case? Or is it best to just let it crash, if there's a nc without unix domain socket support?

@jordemort
Copy link
Author

@aurora I'm not sure what the best way to detect a nc that supports -U vs an nc that doesn't, which is why I think maybe I should add a way to customize what command is used. I also had the idea that perhaps I could embed a minimal UNIX socket client in perl into rmate as a heredoc, and then write it out and use it. This is the shortest I could get it while still being confident in its correctness:

#!/usr/bin/env perl
use strict; use IO::Socket::UNIX; use IO::Select;

our $U = IO::Socket::UNIX->new($ARGV[0]) or die "$!";
our $S = IO::Select->new(\*STDIN, $U);
map { $_->blocking(0) or die "$!" } $S->handles;
our ($TIMEOUT, $BUFFER);

while (my @in = $S->can_read($TIMEOUT)) {
  HANDLE: for my $in (@in) {
    my $out = $in eq $U ? \*STDOUT : $U;
    unless (read $in, $BUFFER, 1024) {
      shutdown($U, $in eq $U ? 1 : 0); close($out) unless $out eq $U;
      $S->remove($in); $TIMEOUT = 0; next HANDLE;
    }
    print $out $BUFFER; $out->flush();
  }
}

If you don't think that's too big of a chunk of Perl to embed, I think a lot more systems are going to have perl installed by default over socat or an appropriately-enabed nc

@aurora
Copy link
Owner

aurora commented Jul 27, 2017

Cool. I am undecided whether to include it, though: someone could come up with the question, why rmate wasn't implemented as perl script, instead ;) ... i have to think about this ... too bad, that this can't be done in 100% bash :( ...

@jordemort
Copy link
Author

Yeah I was really surprised that bash can connect to TCP sockets on its own but not UNIX ones. If you'd like, I could rework this as a sort of "generic proxy command" support, and leave out any opinions on what that proxy command should be. I could then document examples of how to use nc or socat to connect to a UNIX socket, but actually specifying what command to use would be left as an exercise to the end-user. That would maintain the bash purity of rmate and also absolves us of having to write a lot of fancy error-checking code to see if they have the right version of nc.

@aurora
Copy link
Owner

aurora commented Jul 28, 2017

@jordemort thought a little more on this, yes i think if you could rework this as "generic proxy command" support and would write an example in the README, that would be awesome. I think in this case we could also include your perl-client as example as standalone script in this repository. Would this be ok for you?

@jordemort
Copy link
Author

Sounds good!

@aurora
Copy link
Owner

aurora commented Jul 31, 2017

@jordemort cool! looking forward to it ...

@jordemort
Copy link
Author

@aurora Hey I do intend to come back to this, just have a lot of different things I'm hacking on right now. Hopefully by the end of August :D

@aurora
Copy link
Owner

aurora commented Aug 6, 2017

@jordemort no problem, i fully understand -- so i am looking forward to end of august or early september ;)

@randy3k
Copy link
Contributor

randy3k commented Aug 12, 2017

@jordemort Textmate does support unix socket, see textmate/rmate#38

Is this compatible with it?

@jordemort
Copy link
Author

@randy3k Should be; same protocol, different transport

@aurora
Copy link
Owner

aurora commented Jan 9, 2018

@jordemort Hey, ... i am still interested in having this feature in rmate :). I think i could also help with this, if you do not have time for further development regarding this. Am i right, that it would be "just" a matter of replacing the nc command in line 401 of your pull request https://github.com/aurora/rmate/pull/63/files#diff-047298641ecfdd3128084b5759e836beR401 with a configurable command? The only other question would be, how to specify the proxy-command -- as comandline-argument or make it just configurable in the config-file?

@jordemort
Copy link
Author

@aurora Sorry, I have really still been intending to get back to this, but there are a great many things going on for me right now. You're correct, all that would be needed is to replace nc -u "$unix" there with something like $proxy_command, and then replace the --unix switch with a mechanism for the user to specify $proxy_command. If you'd like to go ahead and finish this up yourself instead of waiting for my "someday" to come, I would not be offended :D

@aurora
Copy link
Owner

aurora commented Jan 9, 2018

@jordemort no worries, i totally understand. No need to hurry, I am currently just between two projects, so i have some spare time to work on rmate. Thanks!

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants