Skip Menu |

This queue is for tickets about the Net-UPnP CPAN distribution.

Report information
The Basics
Id: 39979
Status: open
Priority: 0/
Queue: Net-UPnP

People
Owner: skonno [...] cybergarage.org
Requestors: AGRUNDMA [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 1.2.4
Fixed in: (no value)



Subject: Searching needs to receive unicast UDP, not multicast
Currently, Net::UPnP sends out the multicast M-SEARCH packet OK, but continues to listen only for multicast NOTIFY responses. It should also be listening for unicast UDP responses to the M-SEARCH packet. These are sent directly by servers to the source host and port of the request. So Net::UPnP needs to fix 2 things: Always set source port to 1900 with a bind() call. Listen for unicast UDP packets on port 1900. You can see the broken behavior by sniffing the network with ngrep or tcpdump, you'll see the unicast packets that are being missed.
The package has no background threads because I would like to implement as simply. The other my implementation such as C, C++, Java and Objective-C has the background threads to receive all SSDP packets. However I think the Perl version doesn't need the background thread now. Please tell me why you want to add the function :-)
On Tue Oct 14 22:25:12 2008, SKONNO wrote: Show quoted text
> The package has no background threads because I would like to implement > as simply. > > The other my implementation such as C, C++, Java and Objective-C has the > background threads to receive all SSDP packets. However I think the Perl > version doesn't need the background thread now. > > Please tell me why you want to add the function :-)
This shouldn't need any background or asynchronous handling, since it's not designed to be run in a loop listening for events. I'll get you a patch later this week to fix search(). I work on SqueezeCenter (www.slimdevices.com) and am about to rewrite our UPnP client implementation. After more carefully reading the UPnP spec I realized Net::UPnP wasn't working properly.
Show quoted text
> This shouldn't need any background or asynchronous handling, since it's > not designed to be run in a loop listening for events. I'll get you a > patch later this week to fix search().
Could you join the project on SourceForge.net as a developer ? I have the latest source codes using the following SVN repository. http://sourceforge.net/svn/?group_id=153283 Show quoted text
> I work on SqueezeCenter (www.slimdevices.com) and am about to rewrite > our UPnP client implementation. After more carefully reading the UPnP > spec I realized Net::UPnP wasn't working properly.
Wow. I have been interested in your devices always, I would like to buy your devices in Japan if I can :-)
On Wed Oct 15 05:52:29 2008, SKONNO wrote: Show quoted text
> > This shouldn't need any background or asynchronous handling, since it's > > not designed to be run in a loop listening for events. I'll get you a > > patch later this week to fix search().
> > Could you join the project on SourceForge.net as a developer ? > I have the latest source codes using the following SVN repository. > > http://sourceforge.net/svn/?group_id=153283
Sure, my SF username is agrundma. Show quoted text
> > I work on SqueezeCenter (www.slimdevices.com) and am about to rewrite > > our UPnP client implementation. After more carefully reading the UPnP > > spec I realized Net::UPnP wasn't working properly.
> > Wow. I have been interested in your devices always, I would like to buy > your devices in Japan if I can :-)
Awesome, yeah Logitech has a bit of a naming issue in Japan (have to be renamed Logicool) so not many products are sold I think... surely you can buy from overseas though? :)
Here, try this patch. It properly joins the IGMP multicast group, sets the TTL to 4 when sending the search packet, and receives both unicast and multicast messages. Try with the examples, you will notice you'll get faster responses in the form of HTTP/1.1 200 OK within the 0-$mx time limit, instead of just the NOTIFY packets.
=== lib/Net/UPnP/ControlPoint.pm ================================================================== --- lib/Net/UPnP/ControlPoint.pm (revision 44776) +++ lib/Net/UPnP/ControlPoint.pm (local) @@ -7,7 +7,8 @@ use strict; use warnings; -use Socket; +use IO::Select; +use IO::Socket::INET; use Net::UPnP; use Net::UPnP::HTTP; @@ -52,10 +53,12 @@ $key, $dev, ); + + my $mcast_addr = $Net::UPnP::SSDP_ADDR . ':' . $Net::UPnP::SSDP_PORT; $ssdp_header = <<"SSDP_SEARCH_MSG"; M-SEARCH * HTTP/1.1 -Host: $Net::UPnP::SSDP_ADDR:$Net::UPnP::SSDP_PORT +Host: $mcast_addr Man: "ssdp:discover" ST: $args{st} MX: $args{mx} @@ -64,22 +67,28 @@ $ssdp_header =~ s/\r//g; $ssdp_header =~ s/\n/\r\n/g; + + my $sock = IO::Socket::INET->new( + LocalPort => $Net::UPnP::SSDP_PORT, + Proto => 'udp', + ); + + # add the socket to the correct IGMP multicast group + _mcast_add( $sock, $mcast_addr ); + + # send the search query + _mcast_send( $sock, $ssdp_header, $mcast_addr ); - socket(SSDP_SOCK, AF_INET, SOCK_DGRAM, getprotobyname('udp')); - $ssdp_mcast = sockaddr_in($Net::UPnP::SSDP_PORT, inet_aton($Net::UPnP::SSDP_ADDR)); - - send(SSDP_SOCK, $ssdp_header, 0, $ssdp_mcast); - if ($Net::UPnP::DEBUG) { print "$ssdp_header\n"; - } + } + + my $sel = IO::Select->new($sock); @dev_list = (); - $rin = ''; - vec($rin, fileno(SSDP_SOCK), 1) = 1; - while( select($rout = $rin, undef, undef, ($args{mx} * 2)) ) { - recv(SSDP_SOCK, $ssdp_res_msg, 4096, 0); + while ( $sel->can_read( $args{mx} ) ) { + recv $sock, $ssdp_res_msg, 4096, 0; print "$ssdp_res_msg" if ($Net::UPnP::DEBUG); @@ -119,11 +128,68 @@ } - close(SSDP_SOCK); + close $sock; @dev_list; } +sub _mcast_add { + my ( $sock, $host ) = @_; + + my ( $addr, $port ) = split /:/, $host; + + my $ip_mreq = inet_aton( $addr ) . INADDR_ANY; + + setsockopt( + $sock, + getprotobyname('ip') || 0, + _constant('IP_ADD_MEMBERSHIP'), + $ip_mreq + ) || warn "Unable to add IGMP membership: $!\n"; +} + +sub _mcast_send { + my ( $sock, $msg, $host ) = @_; + + my ( $addr, $port ) = split /:/, $host; + + # Set a TTL of 4 as per UPnP spec + setsockopt( + $sock, + getprotobyname('ip') || 0, + _constant('IP_MULTICAST_TTL'), + pack 'I', 4, + ) || do { + warn "Error setting multicast TTL to 4: $!\n"; + return; + }; + + my $dest_addr = sockaddr_in( $port, inet_aton( $addr ) ); + send( $sock, $msg, 0, $dest_addr ); +} + +sub _constant { + my $name = shift; + + my %names = ( + IP_MULTICAST_TTL => 0, + IP_ADD_MEMBERSHIP => 1, + ); + + my %constants = ( + MSWin32 => [10,12], + cygwin => [3,5], + darwin => [10,12], + default => [33,35], + ); + + my $index = $names{$name}; + + my $ref = $constants{ $^O } || $constants{default}; + + return $ref->[ $index ]; +} + 1; __END__
Show quoted text
> Sure, my SF username is agrundma.
I added you into the project as a developer. Recently I added a new class to coltrol UPnP renderer device easily. Show quoted text
> Awesome, yeah Logitech has a bit of a naming issue in Japan (have to be > renamed Logicool) so not many products are sold I think... surely you > can buy from overseas though? :)
I see. I will check your product at Logicool's site. Thanks.