Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Why IO::Socket::INET prohibit to bind dynamic port on INADDR_ANY? [rt.cpan.org #91231] #17438

Open
toddr opened this issue Apr 19, 2018 · 1 comment
Labels
dist-IO issues in the dual-life blead-first IO distribution

Comments

@toddr
Copy link
Member

toddr commented Apr 19, 2018

Migrated from rt.cpan.org#91231 (status was 'new')

Requestors:

From [email protected] on 2013-12-07 02:19:52:

Hi all,

I want to listen on dynamically  selected port using IO::Socket::INET.
When I specify LocalAddr to '127.0.0.1' or so, it works.
However it doesn't work for  '0.0.0.0'.

The code in IO/Socket/INET.pm seems intentionally prohibit this.
I'm just curious to know the reason.

N.A.





--- works well --
use IO::Socket;
my $sock = IO::Socket::INET->new( Proto => 'udp', LocalPort => 0,
LocalAddr => '127.0.0.1' );
say $sock->sockport();
------



--- doesn't work --
use IO::Socket;
my $sock = IO::Socket::INET->new( Proto => 'udp', LocalPort => 0,
LocalAddr => '0.0.0.0' );
say $sock->sockport();
------


--- IO/Socket/INET.pm  line 202  --
	if($lport || ($laddr ne INADDR_ANY) || exists $arg->{Listen}) {
	    $sock->bind($lport || 0, $laddr) or
		    return _error($sock, $!, "$!");
	}
-------
@toddr toddr transferred this issue from Dual-Life/IO Jan 20, 2020
@toddr toddr added Needs Triage dist-IO issues in the dual-life blead-first IO distribution labels Jan 20, 2020
@richardleach
Copy link
Contributor

This does seem like a bug to me.

  1. The ($laddr ne INADDR_ANY) might exist because of the logic flow in sub configure. It first does this:
    $laddr = defined $laddr ? inet_aton($laddr)
                            : INADDR_ANY;
  1. It uses $laddr in a check:
    return _error($sock, $EINVAL, "Bad hostname '",$arg->{LocalAddr},"'")
        unless(defined $laddr);
  1. Then does the check to see if it should bind():
	if($lport || ($laddr ne INADDR_ANY) || exists $arg->{Listen}) {
	    $sock->bind($lport || 0, $laddr) or
		    return _error($sock, $!, "$!");
	}
  1. Then if exists($arg->{PeerAddr}) is true, it will try to make an outgoing connect() to a remote socket.

The ($laddr ne INADDR_ANY) check seems to be there to stop the module from doing both a bind() and a connect() call, when only a connect() is appropriate.

Changes along these lines might work:

  • Combine 1 & 2 into:
    if (defined $laddr) {
        $laddr = inet_aton($laddr);
        return _error($sock, $EINVAL, "Bad hostname '",$arg->{LocalAddr},"'")
            unless(defined $laddr);
    }
  • Change 3. to:
	if($lport || $laddr || exists $arg->{Listen}) {
            $laddr = INADDR_ANY unless ($laddr);
	    $sock->bind($lport || 0, $laddr) or
		    return _error($sock, $!, "$!");
	}

All that said:

  • IO::Socket::INET will do what the OP wants if the Listen argument is also passed to the constructor.
  • IO::Socket::IP is preferred nowadays and seems to do what the OP wants out of the box:
use v5.40;
use IO::Socket::IP;
my $sock = IO::Socket::IP->new( Proto => 'udp', LocalPort => 0, LocalAddr => '0.0.0.0' );
say $sock->sockhost();
say $sock->sockport();

outputs:

0.0.0.0
52246

So is this a wontfix?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dist-IO issues in the dual-life blead-first IO distribution
Projects
None yet
Development

No branches or pull requests

3 participants