From 376b3a53c85490bc52dc7e70e7988c6d77a16681 Mon Sep 17 00:00:00 2001 From: Alfred Perlstein Date: Sun, 23 Dec 2012 12:15:44 -0800 Subject: [PATCH 1/6] allow users to force ipv4 only. add flag '-4' to commands to force ipv4. this doesn't work yet because hairtunes unconditionally uses ipv6 if available. --- shairport.pl | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/shairport.pl b/shairport.pl index a4a915a4..20f298a7 100755 --- a/shairport.pl +++ b/shairport.pl @@ -82,6 +82,9 @@ my $writepid; # show help my $help; + +my $ipv4; + unless (-x $hairtunes_cli) { say "Can't find the 'hairtunes' decoder binary, you need to build this before using ShairPort."; say "Read the INSTALL instructions!"; @@ -97,6 +100,7 @@ GetOptions("a|apname=s" => \$apname, "ao_devicename=s" => \$libao_devicename, "ao_deviceid=s" => \$libao_deviceid, "v|verbose" => \$verbose, + "4" => \$ipv4, "w|writepid=s" => \$writepid, "s|squeezebox" => \$squeeze, "c|cliport=s" => \$cliport, @@ -295,6 +299,7 @@ my $rsa = Crypt::OpenSSL::RSA->new_private_key($airport_pem) || die "RSA private my $listen; { + if (!defined($ipv4)) { eval { local $SIG{__DIE__}; $listen = new IO::Socket::INET6(Listen => 1, @@ -309,6 +314,7 @@ my $listen; "* Install this if iTunes won't play. *\n", "**************************************\n\n"; } + } $listen ||= new IO::Socket::INET(Listen => 1, LocalPort => $port, @@ -491,6 +497,7 @@ sub performSqueezeboxSetup { }; while (1) { + printf "about to select\n" if $verbose; my @waiting = $sel->can_read; foreach my $fh (@waiting) { if ($fh==$listen) { @@ -507,6 +514,7 @@ while (1) { # the 2nd connection is a player connection if (defined($play_prog) && $sel->count() == 2) { + printf "play prog: $play_prog\n" if ($verbose); system($play_prog); } } else { @@ -541,6 +549,8 @@ sub conn_handle_data { my $fh = shift; my $conn = $conns{$fh}; + printf "handle data 1\n" if ($verbose); + if ($conn->{req_need}) { if (length($conn->{data}) >= $conn->{req_need}) { $conn->{req}->content(substr($conn->{data}, 0, $conn->{req_need}, '')); @@ -675,7 +685,7 @@ sub conn_handle_request { my $dec = $hairtunes_cli . join(' ', '', map { sprintf "%s '%s'", $_, $dec_args{$_} } keys(%dec_args)); - # print "decode command: $dec\n"; + print "decode command: $dec\n" if ($verbose); my $decoder = open2(my $dec_out, my $dec_in, $dec); $conn->{decoder_pid} = $decoder; @@ -701,10 +711,15 @@ sub conn_handle_request { }; /^SET_PARAMETER$/ && do { my @lines = split /[\r\n]+/, $req->content; + printf("SET_PARAMETER req: " . $req->content . "\n") if ($verbose); my %content = map { /^(\S+): (.+)/; (lc $1, $2) } @lines; my $cfh = $conn->{decoder_fh}; if (exists $content{volume}) { + printf("sending-> vol: %f\n", $content{volume}) if ($verbose); printf $cfh "vol: %f\n", $content{volume}; + } else { + printf("unable to perform content for req: " . $req->content . "\n") if ($verbose); + } last; }; @@ -713,6 +728,7 @@ sub conn_handle_request { die("Unknown method: $_"); } + printf("%s", $resp->as_string("\r\n")) if ($verbose); print $fh $resp->as_string("\r\n"); $fh->flush; } From f42a02673123379c3a90b5c6cdfca4aa0c47e5f1 Mon Sep 17 00:00:00 2001 From: Alfred Perlstein Date: Sun, 23 Dec 2012 12:22:31 -0800 Subject: [PATCH 2/6] Handle FreeBSD having openssl in base. --- Makefile | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 0a7d912c..f3888d14 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,16 @@ -CFLAGS:=-O2 -Wall $(shell pkg-config --cflags openssl ao) -LDFLAGS:=-lm -lpthread $(shell pkg-config --libs openssl ao) + +MY_CFLAGS= $(shell pkg-config --cflags ao) +MY_LDFLAGS= $(shell pkg-config --libs ao) +ifeq ($(shell uname),FreeBSD) +MY_LDFLAGS+= -lssl +else +MY_CFLAGS+= $(shell pkg-config --cflags openssl) +MY_LDFLAGS+= $(shell pkg-config --libs openssl) +endif + +CFLAGS:=-O2 -Wall $(MY_CFLAGS) +LDFLAGS:=-lm -lpthread $(MY_LDFLAGS) + OBJS=socketlib.o shairport.o alac.o hairtunes.o all: hairtunes shairport From 220250cbe09862bc1b917df35b5b5e522888252b Mon Sep 17 00:00:00 2001 From: Alfred Perlstein Date: Sun, 23 Dec 2012 14:16:36 -0800 Subject: [PATCH 3/6] Add ipv4 only support to hairtunes.c. --- hairtunes.c | 83 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 20 deletions(-) diff --git a/hairtunes.c b/hairtunes.c index 5671c665..80265c05 100644 --- a/hairtunes.c +++ b/hairtunes.c @@ -246,6 +246,12 @@ int hairtunes_init(char *pAeskey, char *pAesiv, char *fmtpstr, int pCtrlPort, in return EXIT_SUCCESS; } +#ifdef AF_INET6 +static int ipv4_only = 0; +#else +static int ipv4_only = 1; +#endif + #ifdef HAIRTUNES_STANDALONE int main(int argc, char **argv) { char *hexaeskey = 0, *hexaesiv = 0; @@ -257,6 +263,9 @@ int main(int argc, char **argv) { hexaesiv = *++argv; argc--; } else + if (!strcasecmp(arg, "ipv4_only")) { + ipv4_only = 1; + } else if (!strcasecmp(arg, "key")) { hexaeskey = *++argv; argc--; @@ -403,13 +412,33 @@ static void buffer_put_packet(seq_t seqno, char *data, int len) { static int rtp_sockets[2]; // data, control #ifdef AF_INET6 -static struct sockaddr_in6 rtp_client; -#else -static struct sockaddr_in rtp_client; +static struct sockaddr_in6 rtp_client6; #endif +static struct sockaddr_in rtp_client4; + +struct sockaddr * get_rtp_client_sockaddr(void) { + +#ifdef AF_INET6 + if (!ipv4_only) { + return ((struct sockaddr*)&rtp_client6); + } +#endif + return ((struct sockaddr*)&rtp_client4); +} + +socklen_t get_rtp_sockaddr_len(void) { +#ifdef AF_INET6 + if (!ipv4_only) { + return (sizeof(&rtp_client6)); + } +#endif + return (sizeof(rtp_client4)); +} + + static void *rtp_thread_func(void *arg) { - socklen_t si_len = sizeof(rtp_client); + socklen_t si_len; char packet[MAX_PACKET]; char *pktp; seq_t seqno; @@ -417,6 +446,10 @@ static void *rtp_thread_func(void *arg) { int sock = rtp_sockets[0], csock = rtp_sockets[1]; int readsock; char type; + struct sockaddr *rtp_client; + + rtp_client = get_rtp_client_sockaddr(); + si_len = get_rtp_sockaddr_len(); fd_set fds; FD_ZERO(&fds); @@ -432,7 +465,7 @@ static void *rtp_thread_func(void *arg) { FD_SET(sock, &fds); FD_SET(csock, &fds); - plen = recvfrom(readsock, packet, sizeof(packet), 0, (struct sockaddr*)&rtp_client, &si_len); + plen = recvfrom(readsock, packet, sizeof(packet), 0, rtp_client, &si_len); if (plen < 0) continue; assert(plen<=MAX_PACKET); @@ -481,12 +514,17 @@ static void rtp_request_resend(seq_t first, seq_t last) { *(unsigned short *)(req+4) = htons(first); // missed seqnum *(unsigned short *)(req+6) = htons(last-first+1); // count + struct sockaddr *rtp_client = get_rtp_client_sockaddr(); + + if (ipv4_only) { + ((struct sockaddr_in *)rtp_client)->sin_port = htons(controlport); + } #ifdef AF_INET6 - rtp_client.sin6_port = htons(controlport); -#else - rtp_client.sin_port = htons(controlport); + else { + ((struct sockaddr_in6 *)rtp_client)->sin6_port = htons(controlport); + } #endif - sendto(rtp_sockets[1], req, sizeof(req), 0, (struct sockaddr *)&rtp_client, sizeof(rtp_client)); + sendto(rtp_sockets[1], req, sizeof(req), 0, rtp_client, get_rtp_sockaddr_len()); } @@ -499,11 +537,14 @@ static int init_rtp(void) { memset(&si, 0, sizeof(si)); #ifdef AF_INET6 struct sockaddr_in6 si6; - type = AF_INET6; - si_p = (struct sockaddr*)&si6; - si_len = sizeof(si6); - sin_port = &si6.sin6_port; - memset(&si6, 0, sizeof(si6)); + + if (!ipv4_only) { + type = AF_INET6; + si_p = (struct sockaddr*)&si6; + si_len = sizeof(si6); + sin_port = &si6.sin6_port; + memset(&si6, 0, sizeof(si6)); + } #endif si.sin_family = AF_INET; @@ -512,12 +553,14 @@ static int init_rtp(void) { #endif si.sin_addr.s_addr = htonl(INADDR_ANY); #ifdef AF_INET6 - si6.sin6_family = AF_INET6; - #ifdef SIN6_LEN - si6.sin6_len = sizeof(si); - #endif - si6.sin6_addr = in6addr_any; - si6.sin6_flowinfo = 0; + if (!ipv4_only) { + si6.sin6_family = AF_INET6; + #ifdef SIN6_LEN + si6.sin6_len = sizeof(si); + #endif + si6.sin6_addr = in6addr_any; + si6.sin6_flowinfo = 0; + } #endif int sock = -1, csock = -1; // data and control (we treat the streams the same here) From 2e097b670fb2d27a85ef33657a5f615b57034ece Mon Sep 17 00:00:00 2001 From: Alfred Perlstein Date: Sun, 23 Dec 2012 14:17:08 -0800 Subject: [PATCH 4/6] Pass ipv4_only to hairtunes when -4 is given as an arg. --- shairport.pl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/shairport.pl b/shairport.pl index 20f298a7..2c122d97 100755 --- a/shairport.pl +++ b/shairport.pl @@ -83,7 +83,7 @@ my $writepid; my $help; -my $ipv4; +my $ipv4_only; unless (-x $hairtunes_cli) { say "Can't find the 'hairtunes' decoder binary, you need to build this before using ShairPort."; @@ -100,7 +100,7 @@ GetOptions("a|apname=s" => \$apname, "ao_devicename=s" => \$libao_devicename, "ao_deviceid=s" => \$libao_deviceid, "v|verbose" => \$verbose, - "4" => \$ipv4, + "4" => \$ipv4_only, "w|writepid=s" => \$writepid, "s|squeezebox" => \$squeeze, "c|cliport=s" => \$cliport, @@ -299,7 +299,7 @@ my $rsa = Crypt::OpenSSL::RSA->new_private_key($airport_pem) || die "RSA private my $listen; { - if (!defined($ipv4)) { + if (!defined($ipv4_only)) { eval { local $SIG{__DIE__}; $listen = new IO::Socket::INET6(Listen => 1, @@ -685,6 +685,10 @@ sub conn_handle_request { my $dec = $hairtunes_cli . join(' ', '', map { sprintf "%s '%s'", $_, $dec_args{$_} } keys(%dec_args)); + if ($ipv4_only) { + $dec .= " ipv4_only"; + } + print "decode command: $dec\n" if ($verbose); my $decoder = open2(my $dec_out, my $dec_in, $dec); From 0621464a95abe5ba3064ccdaf704f509a27cc395 Mon Sep 17 00:00:00 2001 From: Alfred Perlstein Date: Sun, 23 Dec 2012 14:20:15 -0800 Subject: [PATCH 5/6] Add FreeBSD install instructions. --- FreeBSD.notes | 4 ++++ INSTALL.md | 6 ++++++ 2 files changed, 10 insertions(+) create mode 100644 FreeBSD.notes diff --git a/FreeBSD.notes b/FreeBSD.notes new file mode 100644 index 00000000..34cffabd --- /dev/null +++ b/FreeBSD.notes @@ -0,0 +1,4 @@ +/usr/ports/security/p5-Crypt-RSA +/usr/ports/security/p5-Crypt-OpenSSL-RSA +net/p5-Net-SDP +/usr/ports/net/p5-IO-Socket-INET6 diff --git a/INSTALL.md b/INSTALL.md index 1d154841..65a7cc64 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -50,6 +50,12 @@ Perl modules (install from CPAN if needed e.g. `perl -MCPAN -e 'install X'`): gmake perl shairport.pl +## FreeBSD + + pkg_add -r gmake libao avahi p5-libwww p5-Crypt-OpenSSL-RSA p5-Net-SDP p5-IO-Socket-INET6 + gmake + perl shairport.pl + ## Mac OS X: * install XCode From 01405e92de69b3fde205742fb20aa1f85013f159 Mon Sep 17 00:00:00 2001 From: Alfred Perlstein Date: Sun, 23 Dec 2012 14:36:57 -0800 Subject: [PATCH 6/6] tell FreeBSD people to force ipv4. --- INSTALL.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index 65a7cc64..1a8fbee9 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -54,7 +54,10 @@ Perl modules (install from CPAN if needed e.g. `perl -MCPAN -e 'install X'`): pkg_add -r gmake libao avahi p5-libwww p5-Crypt-OpenSSL-RSA p5-Net-SDP p5-IO-Socket-INET6 gmake - perl shairport.pl + # ipv6 does not work for me, but maybe works for you? might be due to not + # having local ipv6 working dns names? + # force ipv4 on FreeBSD with '-4' on the command line. + perl shairport.pl -4 ## Mac OS X: