--- SlimServer_v6.0b2/Slim/Networking/Protocol.pm Sat Mar 19 02:43:38 2005 +++ SlimS-changes-used-v6.0b2/Slim/Networking/Protocol.pm Thu Mar 17 08:17:46 2005 @@ -26,6 +26,7 @@ #-------- You probably don't want to change this -----------------# my $SERVERPORT = 3483; # IANA-assigned port for the Slim protocol, used in firmware 1.3+ +my $SLIMECHO_PORT = 7; # Echo port on the Slim devices #-----------------------------------------------------------------# use vars qw( $udpsock ); @@ -77,7 +78,8 @@ $udpsock = IO::Socket::INET->new( Proto => 'udp', LocalPort => $SERVERPORT, - LocalAddr => $main::localClientNetAddr + LocalAddr => $main::localClientNetAddr, + Timeout => Slim::Utils::Prefs::get('remotestreamtimeout') ) or do { msg("Problem: There is already another copy of the SlimServer running on this machine. ($!)\n"); @@ -122,52 +124,113 @@ $clientpaddr = recv($sock,$msg,1500,0); if ($clientpaddr) { - - # check that it's a message type we know: starts with i r 2 d a or h (but not h followed by 0x00 0x00) - if ($msg =~ /^(?:[ir2a]|h(?!\x00\x00))/) { - my $client = getUdpClient($clientpaddr, $sock, $msg); - - if (!defined($client)) { - return; - } - - if ($SIMULATE_RX_DELAY) { - # simulate rx delay - Slim::Utils::Timers::setTimer($client, Time::HiRes::time() + $SIMULATE_RX_DELAY/1000, - \&Slim::Networking::Protocols::processMessage, $msg); - } else { - processMessage($client, $msg); - } - - } elsif ($msg =~/^d/) { - # Discovery request: note that slimp3 sends deviceid and revision in the discovery - # request, but the revision is wrong (v 2.2 sends revision 1.1). Oops. - # also, it does not send the MAC address until the [h]ello packet. - # Squeezebox sends all fields correctly. - - my ($msgtype, $deviceid, $revision, @mac) = unpack 'axCCxxxxxxxxH2H2H2H2H2H2', $msg; - my $mac = join(':', @mac); - Slim::Network::Discovery::gotDiscoveryRequest($sock, $clientpaddr, $deviceid, $revision, $mac); - - # Playlist::executecommand can be accessed over the UDP port - } elsif ($msg=~/^executecommand\((.*)\)$/) { - my $ecArgs=$1; - my @ecArgs=split(/, ?/, $ecArgs); - $::d_protocol && msg("UDP: executecommand($ecArgs)\n"); - my $clientipport = shift(@ecArgs); - my $client = Slim::Player::Client::getClient($clientipport); - Slim::Control::Command::execute($client, \@ecArgs); - + my ($clientport, $clientip) = sockaddr_in($clientpaddr); + + if ($clientport eq Slim::Networking::Slimproto::getSlimProtoPort()) { + # handle the udp packets that came from client the SLIMPROTO_PORT(3483) + processReplyFromSlimPort($sock, $clientpaddr, $clientip, $msg); + + } elsif ($clientport eq $SLIMECHO_PORT) { + # handle the udp packets that came from client the echo port(7) + processReplyFromEchoPort($sock, $clientpaddr, $msg); + } else { if ($::d_protocol) { - my ($clientport, $clientip) = sockaddr_in($clientpaddr); msg("ignoring Client: ".inet_ntoa($clientip).":$clientport that sent bogus message $msg\n"); } } } } while $clientpaddr; +} + +sub processReplyFromSlimPort { + my ($sock, $clientpaddr, $clientip, $msg) = @_; + + # check that it's a message type we know: starts with i r 2 d a or h (but not h followed by 0x00 0x00) + if ($msg =~ /^(?:[ir2a]|h(?!\x00\x00))/) { + my $client = getUdpClient($clientpaddr, $sock, $msg); + + if (!defined($client)) { + return; + } + + if ($SIMULATE_RX_DELAY) { + # simulate rx delay + Slim::Utils::Timers::setTimer($client, Time::HiRes::time() + $SIMULATE_RX_DELAY/1000, + \&Slim::Networking::Protocols::processMessage, $msg); + } else { + processMessage($client, $msg); + } + $client->lastReplyTime(Time::HiRes::time()); + + } elsif ($msg =~/^d/) { + # Discovery request: note that slimp3 sends deviceid and revision in the discovery + # request, but the revision is wrong (v 2.2 sends revision 1.1). Oops. + # also, it does not send the MAC address until the [h]ello packet. + # Squeezebox sends all fields correctly. + + my ($msgtype, $deviceid, $revision, @mac) = unpack 'axCCxxxxxxxxH2H2H2H2H2H2', $msg; + my $mac = join(':', @mac); + Slim::Network::Discovery::gotDiscoveryRequest($sock, $clientpaddr, $deviceid, $revision, $mac); + + # Playlist::executecommand can be accessed over the UDP port + } elsif ($msg=~/^executecommand\((.*)\)$/) { + my $ecArgs=$1; + my @ecArgs=split(/, ?/, $ecArgs); + $::d_protocol && msg("UDP: executecommand($ecArgs)\n"); + my $clientipport = shift(@ecArgs); + my $client = Slim::Player::Client::getClient($clientipport); + Slim::Control::Command::execute($client, \@ecArgs); + $client->lastReplyTime(Time::HiRes::time()); + + } else { + if ($::d_protocol) { + msg("ignoring Client: ".inet_ntoa($clientip).":slimport that sent bogus message $msg\n"); + } + } +} + +sub processReplyFromEchoPort { + my ($sock, $clientpaddr, $msg) = @_; + my $client; + my @mac; + my $txt; + my $macaddr; + + ( $txt, $mac[0], $mac[1], $mac[2], $mac[3], $mac[4], $mac[5] ) + = unpack ('a4H2H2H2H2H2H2', $msg); + $macaddr = join(':', @mac); + + $client = Slim::Player::Client::getClient($macaddr); + if (defined($client)) { + $client->lastReplyTime(Time::HiRes::time()); + if ($::d_protocol) { + my ($clientport, $clientip) = sockaddr_in($client->paddr); + msg("processReplyFromEchoPort: recv text of '$txt'\n from Client: " + .inet_ntoa($clientip)." lastReplyTime was set\n"); + } + } else { + $::d_protocol && msg("processReplyFromEchoPort: recv text of '$txt'\n"); + } + +} + +sub sendEchoToClient { + my $client = shift; + + my @mac = split(':', $client->macaddress()); + my $paddr = ipaddress2paddr($client->ip.":".$SLIMECHO_PORT); + my $frame = pack 'a4H2H2H2H2H2H2', (' Yo!', + $mac[0], $mac[1], $mac[2], $mac[3], $mac[4], $mac[5] ); + + $udpsock->send( $frame, 0, $paddr); + + if ($::d_protocol) { + my ($clientport, $clientip) = sockaddr_in($client->paddr); + msg("sendEchoToClient sent to Client: ".inet_ntoa($clientip)."\n"); + } } sub paddr2ipaddress {