Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Add UDP support to Net::EmptyPort #8

Merged
merged 1 commit into from

2 participants

@SineSwiper

See RT#83751.

I also added in the compatibility for check_port and wait_port, since it's still useful for quick UDP port checks. Added a new test file, which passes on both Windows 7 and Debian Linux. (The rest of the test platform isn't working on Windows, but that's another issue.)

@tokuhirom tokuhirom merged commit 8972845 into tokuhirom:master
@SineSwiper SineSwiper deleted the SineSwiper:topic/udp_support branch
@SineSwiper

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 18, 2013
  1. @SineSwiper
This page is out of date. Refresh to see the latest.
Showing with 88 additions and 18 deletions.
  1. +46 −18 lib/Net/EmptyPort.pm
  2. +42 −0 t/11_net_emptyport.t
View
64 lib/Net/EmptyPort.pm
@@ -11,7 +11,7 @@ our @EXPORT = qw/ empty_port check_port /;
# http://www.iana.org/assignments/port-numbers
sub empty_port {
my $port = do {
- if (@_) {
+ if (defined $_[0]) {
my $p = $_[0];
$p = 49152 unless $p =~ /^[0-9]+$/ && $p < 49152;
$p;
@@ -19,14 +19,17 @@ sub empty_port {
50000 + int(rand()*1000);
}
};
+ my $proto = $_[1] ? lc($_[1]) : 'tcp';
while ( $port++ < 60000 ) {
- next if check_port($port);
+ # Remote checks don't work on UDP, and Local checks would be redundant here...
+ next if ($proto eq 'tcp' && check_port($port));
+
my $sock = IO::Socket::INET->new(
- Listen => 5,
+ (($proto eq 'udp') ? () : (Listen => 5)),
LocalAddr => '127.0.0.1',
LocalPort => $port,
- Proto => 'tcp',
+ Proto => $proto,
(($^O eq 'MSWin32') ? () : (ReuseAddr => 1)),
);
return $port if $sock;
@@ -35,29 +38,43 @@ sub empty_port {
}
sub check_port {
- my ($port) = @_;
-
- my $remote = IO::Socket::INET->new(
- Proto => 'tcp',
- PeerAddr => '127.0.0.1',
- PeerPort => $port,
- );
- if ($remote) {
- close $remote;
+ my $port = $_[0];
+ my $proto = $_[1] ? lc($_[1]) : 'tcp';
+
+ # for TCP, we do a remote port check
+ # for UDP, we do a local port check, like empty_port does
+ my $sock = ($proto eq 'tcp') ?
+ IO::Socket::INET->new(
+ Proto => 'tcp',
+ PeerAddr => '127.0.0.1',
+ PeerPort => $port,
+ ) :
+ IO::Socket::INET->new(
+ Proto => $proto,
+ LocalAddr => '127.0.0.1',
+ LocalPort => $port,
+ (($^O eq 'MSWin32') ? () : (ReuseAddr => 1)),
+ )
+ ;
+
+ if ($sock) {
+ close $sock;
return 1;
}
else {
return 0;
}
+
}
sub wait_port {
- my ($port, $sleep, $retry) = @_;
+ my ($port, $sleep, $retry, $proto) = @_;
$retry ||= 100;
$sleep ||= 0.1;
+ $proto = $proto ? lc($proto) : 'tcp';
while ( $retry-- ) {
- if ($^O eq 'MSWin32' ? `$^X -MNet::EmptyPort -echeck_port $port` : check_port( $port )) {
+ if ($^O eq 'MSWin32' ? `$^X -MNet::EmptyPort -e"check_port $port,'$proto'"` : check_port( $port, $proto )) {
return 1;
}
Time::HiRes::sleep($sleep);
@@ -73,7 +90,7 @@ __END__
=head1 NAME
-Net::EmptyPort - find a free TCP port
+Net::EmptyPort - find a free TCP/UDP port
=head1 SYNOPSIS
@@ -89,7 +106,7 @@ Net::EmptyPort - find a free TCP port
=head1 DESCRIPTION
-Net::EmptyPort helps finding an empty TCP port.
+Net::EmptyPort helps finding an empty TCP/UDP port.
=head1 METHODS
@@ -109,13 +126,24 @@ But you want to use another range, use a following form:
# 5963..65535
my $port = empty_port(5963);
+You can also find an empty UDP port by specifying the protocol as
+the second parameter:
+
+ my $port = empty_port(1024, 'udp');
+ # use 49152..65535 range
+ my $port = empty_port(undef, 'udp');
+
=item check_port
my $true_or_false = check_port(5000);
Checks if the given port is already in use. Returns true if it is in use (i.e. if the port is NOT free). Returns false if the port is free.
-=item wait_port($port:Int[, $sleep:Number, $retry:Int])
+Also works for UDP:
+
+ my $true_or_false = check_port(5000, 'udp');
+
+=item wait_port($port:Int[, $sleep:Number, $retry:Int, $proto:String])
Waits for a particular port is available for connect.
View
42 t/11_net_emptyport.t
@@ -0,0 +1,42 @@
+use warnings;
+use strict;
+use Test::More tests => 11;
+use Net::EmptyPort qw(empty_port check_port);
+use IO::Socket::INET;
+
+my ($port, $new_port, $sock);
+
+foreach my $proto_uc ('TCP', 'UDP') {
+ my $proto = lc $proto_uc;
+ $port = empty_port(5000, $proto);
+ ok( $port, $proto_uc.': port found via empty_port' );
+
+ $sock = new_ok( 'IO::Socket::INET' => [
+ (($proto eq 'udp') ? () : (Listen => 5)),
+ LocalAddr => '127.0.0.1',
+ LocalPort => $port,
+ Proto => $proto,
+ (($^O eq 'MSWin32') ? () : (ReuseAddr => 1)),
+ ] );
+
+ $new_port = empty_port($port, $proto);
+ isnt( $new_port, $port, $proto_uc.': different port found via empty_port' );
+
+ $sock->close;
+ $sock = new_ok( 'IO::Socket::INET' => [
+ (($proto eq 'udp') ? () : (Listen => 5)),
+ LocalAddr => '127.0.0.1',
+ LocalPort => $port,
+ PeerAddr => '127.0.0.1',
+ PeerPort => $new_port,
+ Proto => $proto,
+ (($^O eq 'MSWin32') ? () : (ReuseAddr => 1)),
+ ] );
+
+ is( check_port($port) , 0, $proto_uc.': check_port($port) == 0') if ($proto eq 'udp');
+ is( check_port($new_port), 0, $proto_uc.': check_port($new_port) == 0');
+
+ $sock->close;
+}
+
+1;
Something went wrong with that request. Please try again.