From 8557833d769280495ababfa71f202bf131ea5512 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 3 Mar 2016 10:33:02 +0000 Subject: daemon: support listening on Unix domain sockets Listening on Unix domain sockets can be convenient for running behind reverse proxies, avoiding port conflicts, limiting access, or avoiding the overhead (if any) of TCP over loopback. --- lib/PublicInbox/Daemon.pm | 60 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 18 deletions(-) (limited to 'lib') diff --git a/lib/PublicInbox/Daemon.pm b/lib/PublicInbox/Daemon.pm index c101ecb7..9f33c05a 100644 --- a/lib/PublicInbox/Daemon.pm +++ b/lib/PublicInbox/Daemon.pm @@ -7,6 +7,7 @@ use strict; use warnings; use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/; use IO::Handle; +use IO::Socket; STDOUT->autoflush(1); STDERR->autoflush(1); require Danga::Socket; @@ -52,17 +53,35 @@ sub daemon_prepare ($) { foreach my $l (@cfg_listen) { next if $listener_names{$l}; # already inherited - require IO::Socket::INET6; # works for IPv4, too - my %o = ( - LocalAddr => $l, - ReuseAddr => 1, - Proto => 'tcp', - ); - if (my $s = IO::Socket::INET6->new(%o)) { + my (%o, $sock_pkg); + if (index($l, '/') == 0) { + $sock_pkg = 'IO::Socket::UNIX'; + eval "use $sock_pkg"; + die $@ if $@; + %o = (Type => SOCK_STREAM, Peer => $l); + if (-S $l) { + my $c = $sock_pkg->new(%o); + if (!defined($c) && $!{ECONNREFUSED}) { + unlink $l or die +"failed to unlink stale socket=$l: $!\n"; + } # else: let the bind fail + } + $o{Local} = delete $o{Peer}; + } else { + $sock_pkg = 'IO::Socket::INET6'; # works for IPv4, too + eval "use $sock_pkg"; + die $@ if $@; + %o = (LocalAddr => $l, ReuseAddr => 1, Proto => 'tcp'); + } + $o{Listen} = 1024; + my $prev = umask 0000; + my $s = eval { $sock_pkg->new(%o) }; + warn "error binding $l: $!\n" unless $s; + umask $prev; + + if ($s) { $listener_names{sockname($s)} = $s; push @listeners, $s; - } else { - warn "error binding $l: $!\n"; } } die "No listeners bound\n" unless @listeners; @@ -165,15 +184,20 @@ sub sockname ($) { sub host_with_port ($) { my ($addr) = @_; my ($port, $host); - if (length($addr) >= 28) { - require Socket6; - ($port, $host) = Socket6::unpack_sockaddr_in6($addr); - $host = '['.Socket6::inet_ntop(Socket6::AF_INET6(), $host).']'; - } else { - ($port, $host) = Socket::sockaddr_in($addr); - $host = Socket::inet_ntoa($host); - } - ($host, $port); + + # this eval will die on Unix sockets: + eval { + if (length($addr) >= 28) { + require Socket6; + ($port, $host) = Socket6::unpack_sockaddr_in6($addr); + $host = Socket6::inet_ntop(Socket6::AF_INET6(), $host); + $host = "[$host]"; + } else { + ($port, $host) = Socket::sockaddr_in($addr); + $host = Socket::inet_ntoa($host); + } + }; + $@ ? ('127.0.0.1', 0) : ($host, $port); } sub inherit () { -- cgit v1.2.3-24-ge0c7