Merge commit '6e1f784b41629e88ab44'
Conflicts: INSTALL README hairtunes.c shairport.pl Manually merged all conflicts.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user