Parse the remote address from SDP instead of a hack.
authorJuho Vähä-Herttua <juhovh@iki.fi>
Sat, 17 Mar 2012 11:59:00 +0000 (13:59 +0200)
committerJuho Vähä-Herttua <juhovh@iki.fi>
Wed, 16 May 2012 21:33:31 +0000 (00:33 +0300)
src/lib/netutils.c
src/lib/netutils.h
src/lib/raop.c
src/lib/raop_rtp.c
src/lib/raop_rtp.h

index 13ebce926da9b55a34a0202a076f62b82495e49f..5399fb07f56520e7b3001176770666b60526ca36 100644 (file)
@@ -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;
+}
index eaef366f232c9210557feb29f0a119547b50ba40..63854adc4525c67719e524438752ae82145902c5 100644 (file)
@@ -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
index 1ce99de1a5619c28f1de639f77fd6ffa8b643bba..b40ee2d367c079e990f42386fdaa7bd7516cadc7 100644 (file)
@@ -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(&current, ";")) != 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,
index 88f65c602af9820481d9b510d0b29c1a9bdd2dd9..607e760c31457eea80600793e7adb8343d1e7377 100644 (file)
@@ -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(&current, " ");
+       if (strcmp(tmpstr, "IN")) {
+               free(original);
+               return -1;
+       }
+       tmpstr = utils_strsep(&current, " ");
+       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;
index c62d87b6d630b0033113a75333a02117048b6f46..1e947d6bf07840caa708b2dbedf70c5331cc14d8 100644 (file)
@@ -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);