about summary refs log tree commit homepage
path: root/lib
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2016-03-03 10:33:02 +0000
committerEric Wong <e@80x24.org>2016-03-04 00:25:43 +0000
commit8557833d769280495ababfa71f202bf131ea5512 (patch)
tree9f988d17af1e75a95badfe6d1eb083ee9ad7fdd9 /lib
parentb38de6f02fa04e36b881d2aad9c7f792beb0b6a1 (diff)
downloadpublic-inbox-8557833d769280495ababfa71f202bf131ea5512.tar.gz
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.
Diffstat (limited to 'lib')
-rw-r--r--lib/PublicInbox/Daemon.pm60
1 files changed, 42 insertions, 18 deletions
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 () {