Merge commit '6e1f784b41629e88ab44'

Conflicts:
	INSTALL
	README
	hairtunes.c
	shairport.pl

Manually merged all conflicts.
This commit is contained in:
Albert Zeyer
2011-04-11 19:38:21 +02:00
4 changed files with 97 additions and 19 deletions
+3 -2
View File
@@ -10,8 +10,9 @@ You need the following installed:
Perl
Debian/Ubuntu users need:
libssl-dev libcrypt-openssl-rsa-perl libao2 libao-dev2
libssl-dev libcrypt-openssl-rsa-perl libao2 libao-dev2 libio-socket-inet6-perl
Perl modules (install from CPAN if needed):
HTTP::Message
Crypt::OpenSSL::RSA (cpan, then install)
Crypt::OpenSSL::RSA
IO::Socket::INET6
+13 -2
View File
@@ -1,7 +1,7 @@
Shairport v0.01
Shairport v0.03
==============
James Laird <jhl@mafipulation.org>
April 5, 2011
April 11, 2011
What it is
----------
@@ -37,6 +37,7 @@ Thanks to everyone who has worked to reverse engineer the RAOP protocol - after
finding the keys, everything else was pretty much trivial.
Thanks also to Apple for obfuscating the private key in the ROM image, using a
scheme that made the deobfuscation code itself stand out like a flare.
Thanks to Ten Thousand Free Men and their Families for having a computer and stuff.
Thanks to wtbw.
How to compile and install on Mac OSX 10.6
@@ -51,3 +52,13 @@ How to compile and install on Mac OSX 10.6
OSX 10.5 only bundles perl 5.8, which won't work with shairport. After getting a update
here (http://www.perl.org/get.html), it worked.
Changelog
---------
0.01 April 5, 2011
initial release
0.02 April 11, 2011
bugfix: libao compatibility
0.03 April 11, 2011
bugfix: ipv6 didn't work -
IO::Socket::INET6 is required too
+34 -6
View File
@@ -328,7 +328,12 @@ void buffer_put_packet(seq_t seqno, char *data, int len) {
}
static int rtp_sockets[2]; // data, control
struct sockaddr_in rtp_client;
#ifdef AF_INET6
struct sockaddr_in6 rtp_client;
#else
struct sockaddr_in rtp_client;
#endif
void *rtp_thread_func(void *arg) {
socklen_t si_len = sizeof(rtp_client);
char packet[MAX_PACKET];
@@ -384,33 +389,55 @@ 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
#ifdef AF_INET6
rtp_client.sin6_port = htons(controlport);
#else
rtp_client.sin_port = htons(controlport);
#endif
sendto(rtp_sockets[1], req, sizeof(req), 0, (struct sockaddr *)&rtp_client, sizeof(struct sockaddr_in));
}
int init_rtp(void) {
#ifdef AF_INET6
struct sockaddr_in6 si;
int type = AF_INET6;
short *sin_port = &si.sin6_port;
#else
struct sockaddr_in si;
int type = AF_INET;
short *sin_port = &si.sin_port;
#endif
int sock, csock; // data and control (we treat the streams the same here)
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sock = socket(type, SOCK_DGRAM, IPPROTO_UDP);
if (sock==-1)
die("Can't create socket!");
memset(&si, 0, sizeof(si));
#ifdef AF_INET6
si.sin6_family = AF_INET6;
#ifdef SIN6_LEN
si.sin6_len = sizeof(si);
#endif
si.sin6_addr = in6addr_any;
si.sin6_flowinfo = 0;
#else
si.sin_family = AF_INET;
si.sin_len = sizeof(si);
si.sin_addr.s_addr = htonl(INADDR_ANY);
#endif
unsigned short port = 6000 - 3;
do {
port += 3;
si.sin_port = htons(port);
*sin_port = htons(port);
} while (bind(sock, (struct sockaddr*)&si, sizeof(si))==-1);
csock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
csock = socket(type, SOCK_DGRAM, IPPROTO_UDP);
if (csock==-1)
die("Can't create socket!");
si.sin_port = htons(port + 1);
*sin_port = htons(port + 1);
if (bind(csock, (struct sockaddr*)&si, sizeof(si))==-1)
die("can't bind control socket");
@@ -661,11 +688,12 @@ int init_output(void) {
int driver = ao_default_driver_id();
ao_sample_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.bits = 16;
fmt.rate = sampling_rate;
fmt.channels = NUM_CHANNELS;
fmt.byte_format = AO_FMT_LITTLE;
// fmt.matrix = 0;
ao_device *dev = ao_open_live(driver, &fmt, 0);
void* arg = dev;
+47 -9
View File
@@ -4,7 +4,7 @@
# AP name - as will be shown in iTunes' menu
# example:
# my $apname = "SteePort";
my $apname = "HairPort $$ on " . `hostname`;
my $apname = "ShairPort $$ on " . `hostname`;
# password - required to connect
# for no password, set:
@@ -45,7 +45,7 @@ use IPC::Open2;
use Crypt::OpenSSL::RSA;
use Digest::MD5 qw/md5_hex/;
use POSIX ":sys_wait_h";
eval "use IO::Socket::INET6;";
chomp $apname;
@@ -85,7 +85,7 @@ $SIG{CHLD} = \&REAP;
my %conns;
$SIG{TERM} = $SIG{INT} = $SIG{__DIE__} = sub {
$SIG{TERM} = $SIG{INT} = sub {
print "killed\n";
map { eval { kill $_->{decoder_pid} } } keys %conns;
kill 9, $avahi_publish;
@@ -95,12 +95,43 @@ $SIG{TERM} = $SIG{INT} = $SIG{__DIE__} = sub {
my $airport_pem = join '', <DATA>;
my $rsa = Crypt::OpenSSL::RSA->new_private_key($airport_pem) || die "RSA private key import failed";
my $listen = new IO::Socket::INET(Listen => 1,
LocalPort => 5000,
ReuseAddr => 1,
Proto => 'tcp');
my $listen;
{
eval {
$listen = new IO::Socket::INET6(Listen => 1,
Domain => AF_INET6,
LocalPort => 5000,
ReuseAddr => 1,
Proto => 'tcp');
};
if ($@) {
print "**************************************\n\n",
"* IO::Socket::INET6 not present! *\n",
"* Install this if iTunes won't play. *\n",
"**************************************\n\n";
$listen = new IO::Socket::INET(Listen => 1,
LocalPort => 5000,
ReuseAddr => 1,
Proto => 'tcp');
}
}
die "Can't listen on port 5000: $!" unless $listen;
sub ip6bin {
my $ip = shift;
$ip =~ /((.*)::)?(.+)/;
my @left = split /:/, $2;
my @right = split /:/, $3;
my @mid;
my $pad = 8 - ($#left + $#right + 2);
if ($pad > 0) {
@mid = (0) x $pad;
}
pack('S>*', map { hex } (@left, @mid, @right));
}
my $sel = new IO::Select($listen);
print "listening...\n";
@@ -110,7 +141,8 @@ while (1) {
foreach $fh (@waiting) {
if ($fh==$listen) {
my $new = $listen->accept;
print "new connection\n";
printf "new connection from %s\n", $new->sockhost;
$sel->add($new);
$new->blocking(0);
$conns{$new} = {fh => $fh};
@@ -192,7 +224,13 @@ sub conn_handle_request {
if (my $chall = $req->header('Apple-Challenge')) {
my $data = decode_base64($chall);
$data .= join '', map { chr } split(/\./, $fh->sockhost);
my $ip = $fh->sockhost;
if ($ip =~ /((\d+\.){3}\d+)$/) { # IPv4
$data .= join '', map { chr } split(/\./, $1);
} else {
$data .= ip6bin($ip);
}
$data .= join '', map { chr } @hw_addr;
$data .= chr(0) x (0x20-length($data));