Merge pull request #60 from Andywebs/master.

C Only implementation
This commit is contained in:
Albert Zeyer
2011-04-30 08:12:24 -07:00
8 changed files with 1605 additions and 51 deletions
+6 -2
View File
@@ -2,18 +2,22 @@ PKGFLAGS:=$(shell pkg-config --cflags --libs openssl ao)
CFLAGS:=-O2 -Wall
LDFLAGS:=-lm -lpthread
all: hairtunes
all: hairtunes shairport
hairtunes: hairtunes.c alac.c
$(CC) $(CFLAGS) hairtunes.c alac.c -o $@ $(PKGFLAGS) $(LDFLAGS)
shairport: socketlib.c shairport.c alac.c
$(CC) $(CFLAGS) alac.c socketlib.c shairport.c -o $@ $(PKGFLAGS) $(LDFLAGS)
clean:
-@rm -rf hairtunes
-@rm -rf hairtunes shairport
prefix=/usr/local
install: hairtunes
install -m 0755 hairtunes $(prefix)/bin
install -m 0755 shairport.pl $(prefix)/bin
install -m 0755 shairport $(prefix)/bin
.PTHONY: all clean install
+24
View File
@@ -0,0 +1,24 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA59dE8qLieItsH1WgjrcFRKj6eUWqi+bGLOX1HL3U3GhC/j0Qg90u3sG/1CUt
wC5vOYvfDmFI6oSFXi5ELabWJmT2dKHzBJKa3k9ok+8t9ucRqMd6DZHJ2YCCLlDRKSKv6kDqnw4U
wPdpOMXziC/AMj3Z/lUVX1G7WSHCAWKf1zNS1eLvqr+boEjXuBOitnZ/bDzPHrTOZz0Dew0uowxf
/+sG+NCK3eQJVxqcaJ/vEHKIVd2M+5qL71yJQ+87X6oV3eaYvt3zWZYD6z5vYTcrtij2VZ9Zmni/
UAaHqn9JdsBWLUEpVviYnhimNVvYFZeCXg/IdTQ+x4IRdiXNv5hEewIDAQABAoIBAQDl8Axy9XfW
BLmkzkEiqoSwF0PsmVrPzH9KsnwLGH+QZlvjWd8SWYGN7u1507HvhF5N3drJoVU3O14nDY4TFQAa
LlJ9VM35AApXaLyY1ERrN7u9ALKd2LUwYhM7Km539O4yUFYikE2nIPscEsA5ltpxOgUGCY7b7ez5
NtD6nL1ZKauw7aNXmVAvmJTcuPxWmoktF3gDJKK2wxZuNGcJE0uFQEG4Z3BrWP7yoNuSK3dii2jm
lpPHr0O/KnPQtzI3eguhe0TwUem/eYSdyzMyVx/YpwkzwtYL3sR5k0o9rKQLtvLzfAqdBxBurciz
aaA/L0HIgAmOit1GJA2saMxTVPNhAoGBAPfgv1oeZxgxmotiCcMXFEQEWflzhWYTsXrhUIuz5jFu
a39GLS99ZEErhLdrwj8rDDViRVJ5skOp9zFvlYAHs0xh92ji1E7V/ysnKBfsMrPkk5KSKPrnjndM
oPdevWnVkgJ5jxFuNgxkOLMuG9i53B4yMvDTCRiIPMQ++N2iLDaRAoGBAO9v//mU8eVkQaoANf0Z
oMjW8CN4xwWA2cSEIHkd9AfFkftuv8oyLDCG3ZAf0vrhrrtkrfa7ef+AUb69DNggq4mHQAYBp7L+
k5DKzJrKuO0r+R0YbY9pZD1+/g9dVt91d6LQNepUE/yY2PP5CNoFmjedpLHMOPFdVgqDzDFxU8hL
AoGBANDrr7xAJbqBjHVwIzQ4To9pb4BNeqDndk5Qe7fT3+/H1njGaC0/rXE0Qb7q5ySgnsCb3DvA
cJyRM9SJ7OKlGt0FMSdJD5KG0XPIpAVNwgpXXH5MDJg09KHeh0kXo+QA6viFBi21y340NonnEfdf
54PX4ZGS/Xac1UK+pLkBB+zRAoGAf0AY3H3qKS2lMEI4bzEFoHeK3G895pDaK3TFBVmD7fV0Zhov
17fegFPMwOII8MisYm9ZfT2Z0s5Ro3s5rkt+nvLAdfC/PYPKzTLalpGSwomSNYJcB9HNMlmhkGzc
1JnLYT4iyUyx6pcZBmCd8bD0iwY/FzcgNDaUmbX9+XDvRA0CgYEAkE7pIPlE71qvfJQgoA9em0gI
LAuE4Pu13aKiJnfft7hIjbK+5kyb3TysZvoyDnb3HOKvInK7vXbKuU4ISgxB2bB3HcYzQMGsz1qJ
2gG0N5hvJpzwwhbhXqFKA4zaaSrw622wDniAK5MlIE0tIAKKP4yxNGjoD2QYjhBGuhvkWKaXTyY=
-----END RSA PRIVATE KEY-----
+79 -49
View File
@@ -36,6 +36,8 @@
#include <openssl/aes.h>
#include <math.h>
#include <sys/stat.h>
#include "hairtunes.h"
#include <sys/signal.h>
#include <fcntl.h>
#include <ao/ao.h>
@@ -161,11 +163,84 @@ int init_decoder(void) {
return 0;
}
int hairtunes_init(char *pAeskey, char *pAesiv, char *fmtpstr, int pCtrlPort, int pTimingPort,
int pDataPort, char *pRtpHost, char*pPipeName, char *pLibaoDriver, char *pLibaoDeviceName, char *pLibaoDeviceId)
{
if(pAeskey != NULL)
memcpy(aeskey, pAeskey, sizeof(aeskey));
if(pAesiv != NULL)
memcpy(aesiv, pAesiv, sizeof(aesiv));
if(pRtpHost != NULL)
rtphost = pRtpHost;
if(pPipeName != NULL)
pipename = pPipeName;
if(pLibaoDriver != NULL)
libao_driver = pLibaoDriver;
if(pLibaoDeviceName != NULL)
libao_devicename = pLibaoDeviceName;
if(pLibaoDeviceId != NULL)
libao_deviceid = pLibaoDeviceId;
controlport = pCtrlPort;
timingport = pTimingPort;
dataport = pDataPort;
AES_set_decrypt_key(aeskey, 128, &aes);
memset(fmtp, 0, sizeof(fmtp));
int i = 0;
char *arg;
while ( (arg = strsep(&fmtpstr, " \t")) )
fmtp[i++] = atoi(arg);
init_decoder();
init_buffer();
init_rtp(); // open a UDP listen port and start a listener; decode into ring buffer
fflush(stdout);
init_output(); // resample and output from ring buffer
char line[128];
int in_line = 0;
int n;
double f;
while (fgets(line + in_line, sizeof(line) - in_line, stdin)) {
n = strlen(line);
if (line[n-1] != '\n') {
in_line = strlen(line) - 1;
if (n == sizeof(line)-1)
in_line = 0;
continue;
}
if (sscanf(line, "vol: %lf\n", &f)) {
assert(f<=0);
if (debug)
fprintf(stderr, "VOL: %lf\n", f);
volume = pow(10.0,0.05*f);
fix_volume = 65536.0 * volume;
continue;
}
if (!strcmp(line, "exit\n")) {
exit(0);
}
if (!strcmp(line, "flush\n")) {
pthread_mutex_lock(&ab_mutex);
ab_resync();
pthread_mutex_unlock(&ab_mutex);
if (debug)
fprintf(stderr, "FLUSH\n");
}
}
fprintf(stderr, "bye!\n");
fflush(stderr);
return EXIT_SUCCESS;
}
#ifndef DONT_USE_HAIRTUNES_MAIN
int main(int argc, char **argv) {
char *hexaeskey = 0, *hexaesiv = 0;
char *fmtpstr = 0;
char *arg;
int i;
assert(RAND_MAX >= 0x10000); // XXX move this to compile time
while ( (arg = *++argv) ) {
if (!strcasecmp(arg, "iv")) {
@@ -234,55 +309,10 @@ int main(int argc, char **argv) {
die("can't understand IV");
if (hex2bin(aeskey, hexaeskey))
die("can't understand key");
AES_set_decrypt_key(aeskey, 128, &aes);
memset(fmtp, 0, sizeof(fmtp));
i = 0;
while ( (arg = strsep(&fmtpstr, " \t")) )
fmtp[i++] = atoi(arg);
init_decoder();
init_buffer();
init_rtp(); // open a UDP listen port and start a listener; decode into ring buffer
fflush(stdout);
init_output(); // resample and output from ring buffer
char line[128];
int in_line = 0;
int n;
double f;
while (fgets(line + in_line, sizeof(line) - in_line, stdin)) {
n = strlen(line);
if (line[n-1] != '\n') {
in_line = strlen(line) - 1;
if (n == sizeof(line)-1)
in_line = 0;
continue;
}
if (sscanf(line, "vol: %lf\n", &f)) {
assert(f<=0);
if (debug)
fprintf(stderr, "VOL: %lf\n", f);
volume = pow(10.0,0.05*f);
fix_volume = 65536.0 * volume;
continue;
}
if (!strcmp(line, "exit\n")) {
exit(0);
}
if (!strcmp(line, "flush\n")) {
pthread_mutex_lock(&ab_mutex);
ab_resync();
pthread_mutex_unlock(&ab_mutex);
if (debug)
fprintf(stderr, "FLUSH\n");
}
}
fprintf(stderr, "bye!\n");
fflush(stderr);
return EXIT_SUCCESS;
return hairtunes_init(NULL, NULL, fmtpstr, controlport, timingport, dataport,
NULL, NULL, NULL, NULL, NULL);
}
#endif
void init_buffer(void) {
int i;
+5
View File
@@ -0,0 +1,5 @@
#ifndef _HAIRTUNES_H_
#define _HAIRTUNES_H_
int hairtunes_init(char *pAeskey, char *pAesiv, char *pFmtpstr, int pCtrlPort, int pTimingPort,
int pDataPort, char *pRtpHost, char*pPipeName, char *pLibaoDriver, char *pLibaoDeviceName, char *pLibaoDeviceId);
#endif
+1141
View File
File diff suppressed because it is too large Load Diff
+79
View File
@@ -0,0 +1,79 @@
#include "stdio.h"
#include "string.h"
#include "unistd.h"
#include "openssl/bio.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "socketlib.h"
#include "regex.h"
#include <sys/types.h>
#include <regex.h>
#define DONT_USE_HAIRTUNES_MAIN
#define HWID_SIZE 6
#define SHAIRPORT_LOG 1
#define LOG_INFO 1
#define LOG_DEBUG 5
#define LOG_DEBUG_V 6
#define LOG_DEBUG_VV 7
struct shairbuffer
{
char *data;
int current;
int maxsize;
int marker;
};
struct keyring
{
char *aeskey;
char *aesiv;
char *fmt;
};
struct comms
{
int in[2];
int out[2];
};
struct connection
{
struct shairbuffer recv;
struct shairbuffer resp;
struct keyring *keys; // Does not point to malloc'd memory.
struct comms *hairtunes;
int clientSocket;
char *password;
};
RSA *loadKey();
int startAvahi(const char *pHwAddr, const char *pServerName, int pPort);
void cleanupBuffers(struct connection *pConnection);
void cleanup(struct connection *pConnection);
void handleClient(int pSock, char *pPassword, char *pHWADDR);
int getAvailChars(struct shairbuffer *pBuf);
char *getTrimmedMalloc(char *pChar, int pSize, int pEndStr, int pAddNL);
char *getTrimmed(char *pChar, int pSize, int pEndStr, int pAddNL, char *pTrimDest);
void initBuffer(struct shairbuffer *pBuf, int pNumChars);
void printBufferInfo(struct shairbuffer *pBuf, int pLevel);
void addToShairBuffer(struct shairbuffer *pBuf, char *pNewBuf);
void addNToShairBuffer(struct shairbuffer *pBuf, char *pNewBuf, int pNofNewBuf);
int readDataFromClient(int pSock, struct shairbuffer *pClientBuffer);
int parseMessage(struct connection *pConn, char *pIpStr, char *pHWADDR);
void closePipe(int *pPipe);
void setKeys(struct keyring *pKeys, char *pIV, char* pAESKey, char *pFmtp);
void initConnection(struct connection *pConn, struct keyring *pKeys,
struct comms *pComms, int pSocket, char *pPassword);
void writeDataToClient(int pSock, struct shairbuffer *pResponse);
void propogateCSeq(struct connection *pConn);
void convertIpToBinary(char *pIpAddress, int pIsIPv6, char *pBinaryOutput);
int buildAppleResponse(struct connection *pConn, char *pIpStr, char *pHwAddr);
void sim(int pLevel, char *pValue1, char *pValue2);
void slog(int pLevel, char *pFormat, ...);
int isLogEnabledFor(int pLevel);
+233
View File
@@ -0,0 +1,233 @@
/*
* Socket Library - Common socket functions, based on stevens networking book.
* Copyright (c) M. Andrew Webster 2011
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include "socketlib.h"
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
int common_setup(struct addrinfo *pAddrInfo)
{
int tSock;
//printAddrs(pAddrInfo);
tSock = socket(pAddrInfo->ai_family, pAddrInfo->ai_socktype, 0);
return tSock;
}
int setup_client(struct addrinfo *server_host)
{
int tSockDesc = -1;
int tIdx = 0;
while(tIdx++ < RETRY_COUNT)
{
tSockDesc = common_setup(server_host);
if (tSockDesc < 0 && tIdx >= RETRY_COUNT)
{
perror("Error: Could not create socket");
return ERROR;
}
if (connect(tSockDesc, server_host->ai_addr, server_host->ai_addrlen) >= 0)
{
return tSockDesc;
}
else
{
close(tSockDesc);
perror("Error: Could not connect to server");
struct timeval tRes;
delay(RETRY_DELAY, &tRes);
}
}
printf("%d Retry attempts exceeded\n", RETRY_COUNT);
return ERROR;
}
int getAddr(char *pHostname, char *pService, int pFamily, int pSockType, struct addrinfo **pAddrInfo)
{
struct addrinfo hints;
int tError = 0;
memset(&hints, 0 , sizeof(hints));
hints.ai_family = pFamily;
hints.ai_socktype = pSockType;
if(pHostname == NULL)
{
hints.ai_flags = AI_PASSIVE;
}
tError = getaddrinfo(pHostname, pService, &hints, pAddrInfo);
if(tError != 0)
{
printf("Error getting address info\n");
}
return tError;
}
int setup_server(struct addrinfo *server_addr)
{
int tSock = common_setup(server_addr);
if (tSock < 0)
{
perror("Error: Could not create server socket");
return ERROR;
}
int tEnable = 1;
setsockopt(tSock, SOL_SOCKET, SO_REUSEADDR, &tEnable, sizeof (tEnable));
if (bind(tSock, server_addr->ai_addr, server_addr->ai_addrlen) < 0)
{
close(tSock);
perror("Error: Could not bind socket");
return ERROR;
}
if (listen(tSock, 5) < 0)
{
close(tSock);
perror("Error: Unable to listen on server socket");
return ERROR;
}
return tSock;
}
int acceptClient(int pSock, struct addrinfo *server_addr)
{
int tAccept = accept(pSock, server_addr->ai_addr, &server_addr->ai_addrlen);
// close the listen socket. Not expecting any more clients.
if (tAccept < 0)
{
perror("Error: Unable to accept connection to server socket");
return ERROR;
}
else
{
//printf("..Accepted on socket: %d\n", tAccept);
}
return tAccept;
}
int setupListenServer(struct addrinfo **pAddrInfo, int pPort)
{
char tService[SERVLEN];
sprintf(tService, "%d", pPort); // copies port to string
int tFamily = AF_INET;
#ifdef AF_INET6
//printf("Listening on IPv6 Socket\n");
tFamily = AF_INET6;
#else
//printf("Listening on IPv4 Socket");
#endif
if(getAddr(NULL, tService, tFamily, SOCK_STREAM, pAddrInfo))
{
return ERROR; // getAddr prints out error message
}
int tSocketDescriptor = setup_server(*pAddrInfo);
char tAddr[INET6_ADDRSTRLEN];
socklen_t tSize = INET6_ADDRSTRLEN;
inet_ntop((*pAddrInfo)->ai_family, (*pAddrInfo)->ai_addr, tAddr, tSize);
//printf("Size is: %d\n", tSize);
return tSocketDescriptor;
}
void delay(long pMillisecs, struct timeval *pRes)
{
pRes->tv_sec = pMillisecs / 1000;
pRes->tv_usec = (pMillisecs - (pRes->tv_sec * 1000)) * 1000;
select(0,NULL,NULL,NULL,pRes);
}
// From http://www.ioncannon.net/programming/34/howto-base64-encode-with-cc-and-openssl/
//int main(int argc, char **argv)
//{
// char *output = decode_base64("WU9ZTyEA\n\0", strlen("WU9ZTyEA\n\0"));
// printf("Unbase64: *%s*\n", output);
// free(output);/
//}
char *decode_base64(unsigned char *input, int length, int *pActualLength)
{
// Needs All no_no flags for proper RSA AES KEY Descrypt
BIO *b64, *bmem;
char *buffer = (char *)malloc(length);
memset(buffer, 0, length);
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_new_mem_buf(input, length);
BIO_set_flags(bmem, BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_push(b64, bmem);
BIO_set_flags(bmem, BIO_FLAGS_BASE64_NO_NL);
*pActualLength = BIO_read(bmem, buffer, length);
BIO_free_all(bmem);
return buffer;
}
char *encode_base64(unsigned char *input, int length)
{
BIO *bmem, *b64;
BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64());
// This enables/disables nls
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem);
BIO_write(b64, input, length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
char *buff = (char *)malloc(bptr->length);
memcpy(buff, bptr->data, bptr->length-1);
buff[bptr->length-1] = 0;
BIO_free_all(b64);
return buff;
}
+38
View File
@@ -0,0 +1,38 @@
/* Name: M. Andrew Webster
* Based on stevens networking book
* Description: function prototypes for socket library
*/
#ifndef _SOCKETLIB_H
#define _SOCKETLIB_H
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAX_SIZE 8192
#define PORT 5000
#define RETRY_COUNT 7
#define SERVLEN 80
#define RETRY_DELAY 1000
#define ERROR -1
#define DEFAULT_IP "127.0.0.1"
#define DEFAULT_UNIX "/unix"
int setup_client(struct addrinfo *server_info);
int setup_server(struct addrinfo *server_address);
int setupListenServer(struct addrinfo **pAddrInfo, int pPort);
int acceptClient(int pSock, struct addrinfo *server_addr);
void delay(long pMillisecs, struct timeval *pRes);
int getAddr(char *pHostname, char *pService, int pFamily, int pSockType, struct addrinfo **pAddrInfo);
// All calls to decode and encode need to be freed
char *decode_base64(unsigned char *input, int length, int *tActualLength);
// All calls to decode and encode need to be freed
char *encode_base64(unsigned char *input, int length);
#endif