From: Juho Vähä-Herttua Date: Sat, 17 Mar 2012 11:59:00 +0000 (+0200) Subject: Parse the remote address from SDP instead of a hack. X-Git-Tag: upstream/0.9.0~4^2~103 X-Git-Url: https://git.piment-noir.org/?p=deb_shairplay.git;a=commitdiff_plain;h=ba0970e1c7736ca136e7bf070f6ee1270af891a0 Parse the remote address from SDP instead of a hack. --- diff --git a/src/lib/netutils.c b/src/lib/netutils.c index 13ebce9..5399fb0 100644 --- a/src/lib/netutils.c +++ b/src/lib/netutils.c @@ -151,3 +151,39 @@ netutils_get_address(void *sockaddr, int *length) return NULL; } +int +netutils_parse_address(int family, const char *src, void *dst, int dstlen) +{ + struct addrinfo *result; + struct addrinfo *ptr; + struct addrinfo hints; + int length; + int ret; + + if (family != AF_INET && family != AF_INET6) { + return -1; + } + if (!src || !dst) { + return -1; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + + ret = getaddrinfo(src, NULL, &hints, &result); + if (ret != 0) { + return -1; + } + + length = -1; + for (ptr=result; ptr!=NULL; ptr=ptr->ai_next) { + if (family == ptr->ai_family && dstlen >= ptr->ai_addrlen) { + memcpy(dst, ptr->ai_addr, ptr->ai_addrlen); + length = ptr->ai_addrlen; + break; + } + } + freeaddrinfo(result); + return length; +} diff --git a/src/lib/netutils.h b/src/lib/netutils.h index eaef366..63854ad 100644 --- a/src/lib/netutils.h +++ b/src/lib/netutils.h @@ -20,5 +20,6 @@ void netutils_cleanup(); int netutils_init_socket(unsigned short *port, int use_ipv6, int use_udp); unsigned char *netutils_get_address(void *sockaddr, int *length); +int netutils_parse_address(int family, const char *src, void *dst, int dstlen); #endif diff --git a/src/lib/raop.c b/src/lib/raop.c index 1ce99de..b40ee2d 100644 --- a/src/lib/raop.c +++ b/src/lib/raop.c @@ -150,14 +150,22 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) data = http_request_get_data(request, &datalen); if (data) { - sdp_t *sdp = sdp_init(data, datalen); - logger_log(&conn->raop->logger, LOGGER_DEBUG, "rsaaeskey: %s\n", sdp_get_rsaaeskey(sdp)); - logger_log(&conn->raop->logger, LOGGER_DEBUG, "aesiv: %s\n", sdp_get_aesiv(sdp)); - - aeskeylen = rsakey_decrypt(raop->rsakey, aeskey, sizeof(aeskey), - sdp_get_rsaaeskey(sdp)); - aesivlen = rsakey_parseiv(raop->rsakey, aesiv, sizeof(aesiv), - sdp_get_aesiv(sdp)); + sdp_t *sdp; + const char *remotestr, *fmtpstr, *aeskeystr, *aesivstr; + + sdp = sdp_init(data, datalen); + remotestr = sdp_get_connection(sdp); + fmtpstr = sdp_get_fmtp(sdp); + aeskeystr = sdp_get_rsaaeskey(sdp); + aesivstr = sdp_get_aesiv(sdp); + + logger_log(&conn->raop->logger, LOGGER_DEBUG, "connection: %s\n", remotestr); + logger_log(&conn->raop->logger, LOGGER_DEBUG, "fmtp: %s\n", fmtpstr); + logger_log(&conn->raop->logger, LOGGER_DEBUG, "rsaaeskey: %s\n", aeskeystr); + logger_log(&conn->raop->logger, LOGGER_DEBUG, "aesiv: %s\n", aesivstr); + + aeskeylen = rsakey_decrypt(raop->rsakey, aeskey, sizeof(aeskey), aeskeystr); + aesivlen = rsakey_parseiv(raop->rsakey, aesiv, sizeof(aesiv), aesivstr); logger_log(&conn->raop->logger, LOGGER_DEBUG, "aeskeylen: %d\n", aeskeylen); logger_log(&conn->raop->logger, LOGGER_DEBUG, "aesivlen: %d\n", aesivlen); @@ -166,10 +174,11 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) raop_rtp_destroy(conn->raop_rtp); conn->raop_rtp = NULL; } - conn->raop_rtp = raop_rtp_init(&raop->logger, &raop->callbacks, sdp_get_fmtp(sdp), aeskey, aesiv); + conn->raop_rtp = raop_rtp_init(&raop->logger, &raop->callbacks, remotestr, fmtpstr, aeskey, aesiv); sdp_destroy(sdp); } } else if (!strcmp(method, "SETUP")) { + unsigned short remote_cport=0, remote_tport=0; unsigned short cport=0, tport=0, dport=0; const char *transport; char buffer[1024]; @@ -180,14 +189,35 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) logger_log(&conn->raop->logger, LOGGER_INFO, "Transport: %s\n", transport); use_udp = strncmp(transport, "RTP/AVP/TCP", 11); - - /* FIXME: Should use the parsed ports for resend */ - raop_rtp_start(conn->raop_rtp, use_udp, 1234, 1234, &cport, &tport, &dport); + if (use_udp) { + char *original, *current, *tmpstr; + + current = original = strdup(transport); + if (original) { + while ((tmpstr = utils_strsep(¤t, ";")) != NULL) { + unsigned short value; + int ret; + + ret = sscanf(tmpstr, "control_port=%hu", &value); + if (ret == 1) { + logger_log(&conn->raop->logger, LOGGER_DEBUG, "Found remote control port: %hu\n", value); + remote_cport = value; + } + ret = sscanf(tmpstr, "timing_port=%hu", &value); + if (ret == 1) { + logger_log(&conn->raop->logger, LOGGER_DEBUG, "Found remote timing port: %hu\n", value); + remote_tport = value; + } + } + } + free(original); + } + raop_rtp_start(conn->raop_rtp, use_udp, remote_cport, remote_tport, &cport, &tport, &dport); memset(buffer, 0, sizeof(buffer)); if (use_udp) { snprintf(buffer, sizeof(buffer)-1, - "RTP/AVP/UDP;unicast;mode=record;timing_port=%u;events;control_port=%u;server_port=%u", + "RTP/AVP/UDP;unicast;mode=record;timing_port=%hu;events;control_port=%hu;server_port=%hu", tport, cport, dport); } else { snprintf(buffer, sizeof(buffer)-1, diff --git a/src/lib/raop_rtp.c b/src/lib/raop_rtp.c index 88f65c6..607e760 100644 --- a/src/lib/raop_rtp.c +++ b/src/lib/raop_rtp.c @@ -22,6 +22,7 @@ #include "raop.h" #include "raop_buffer.h" #include "netutils.h" +#include "utils.h" #include "compat.h" #include "logger.h" @@ -31,8 +32,13 @@ struct raop_rtp_s { logger_t *logger; raop_callbacks_t callbacks; + /* Buffer to handle all resends */ raop_buffer_t *buffer; + /* Remote address as sockaddr */ + struct sockaddr_storage remote_saddr; + socklen_t remote_saddr_len; + /* These variables only edited mutex locked */ int running; int joined; @@ -53,18 +59,63 @@ struct raop_rtp_s { unsigned short timing_lport; unsigned short data_lport; + /* Initialized after the first control packet */ struct sockaddr_storage control_saddr; socklen_t control_saddr_len; unsigned short control_seqnum; }; +static int +raop_rtp_parse_remote(raop_rtp_t *raop_rtp, const char *remote) +{ + char *original; + char *current; + char *tmpstr; + int family; + int ret; + + assert(raop_rtp); + + current = original = strdup(remote); + if (!original) { + return -1; + } + tmpstr = utils_strsep(¤t, " "); + if (strcmp(tmpstr, "IN")) { + free(original); + return -1; + } + tmpstr = utils_strsep(¤t, " "); + if (!strcmp(tmpstr, "IP4") && current) { + family = AF_INET; + } else if (!strcmp(tmpstr, "IP6") && current) { + family = AF_INET6; + } else { + free(original); + return -1; + } + ret = netutils_parse_address(family, current, + &raop_rtp->remote_saddr, + sizeof(raop_rtp->remote_saddr)); + if (ret < 0) { + free(original); + return -1; + } + raop_rtp->remote_saddr_len = ret; + free(original); + return 0; +} + raop_rtp_t * -raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *fmtp, - const unsigned char *aeskey, const unsigned char *aesiv) +raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *remote, + const char *fmtp, const unsigned char *aeskey, const unsigned char *aesiv) { raop_rtp_t *raop_rtp; assert(logger); + assert(callbacks); + assert(remote); + assert(fmtp); raop_rtp = calloc(1, sizeof(raop_rtp_t)); if (!raop_rtp) { @@ -77,6 +128,10 @@ raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *fmtp, free(raop_rtp); return NULL; } + if (raop_rtp_parse_remote(raop_rtp, remote) < 0) { + free(raop_rtp); + return NULL; + } raop_rtp->running = 0; raop_rtp->joined = 1; @@ -150,6 +205,7 @@ raop_rtp_resend_callback(void *opaque, unsigned short seqnum, unsigned short cou unsigned short ourseqnum; struct sockaddr *addr; socklen_t addrlen; + int ret; addr = (struct sockaddr *)&raop_rtp->control_saddr; addrlen = raop_rtp->control_saddr_len; @@ -167,7 +223,11 @@ raop_rtp_resend_callback(void *opaque, unsigned short seqnum, unsigned short cou packet[6] = (count >> 8); packet[7] = count; - sendto(raop_rtp->csock, (const char *)packet, sizeof(packet), 0, addr, addrlen); + ret = sendto(raop_rtp->csock, (const char *)packet, sizeof(packet), 0, addr, addrlen); + if (ret == -1) { + logger_log(raop_rtp->logger, LOGGER_WARNING, "Resend failed: %d\n", SOCKET_GET_ERROR()); + } + return 0; } @@ -253,7 +313,7 @@ raop_rtp_thread_udp(void *arg) packetlen = recvfrom(raop_rtp->csock, (char *)packet, sizeof(packet), 0, (struct sockaddr *)&saddr, &saddrlen); - /* FIXME: Get destination address here */ + /* Get the destination address here, because we need the sin6_scope_id */ memcpy(&raop_rtp->control_saddr, &saddr, saddrlen); raop_rtp->control_saddr_len = saddrlen; @@ -443,6 +503,8 @@ void raop_rtp_start(raop_rtp_t *raop_rtp, int use_udp, unsigned short control_rport, unsigned short timing_rport, unsigned short *control_lport, unsigned short *timing_lport, unsigned short *data_lport) { + int use_ipv6 = 0; + assert(raop_rtp); MUTEX_LOCK(raop_rtp->run_mutex); @@ -454,7 +516,10 @@ raop_rtp_start(raop_rtp_t *raop_rtp, int use_udp, unsigned short control_rport, /* Initialize ports and sockets */ raop_rtp->control_rport = control_rport; raop_rtp->timing_rport = timing_rport; - if (raop_rtp_init_sockets(raop_rtp, 1, use_udp) < 0) { + if (raop_rtp->remote_saddr.ss_family == AF_INET6) { + use_ipv6 = 1; + } + if (raop_rtp_init_sockets(raop_rtp, use_ipv6, use_udp) < 0) { logger_log(raop_rtp->logger, LOGGER_INFO, "Initializing sockets failed\n"); MUTEX_UNLOCK(raop_rtp->run_mutex); return; diff --git a/src/lib/raop_rtp.h b/src/lib/raop_rtp.h index c62d87b..1e947d6 100644 --- a/src/lib/raop_rtp.h +++ b/src/lib/raop_rtp.h @@ -25,8 +25,8 @@ typedef struct raop_rtp_s raop_rtp_t; -raop_rtp_t *raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *fmtp, - const unsigned char *aeskey, const unsigned char *aesiv); +raop_rtp_t *raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *remote, + const char *fmtp, const unsigned char *aeskey, const unsigned char *aesiv); void raop_rtp_start(raop_rtp_t *raop_rtp, int use_udp, unsigned short control_rport, unsigned short timing_rport, unsigned short *control_lport, unsigned short *timing_lport, unsigned short *data_lport); void raop_rtp_set_volume(raop_rtp_t *raop_rtp, float volume);