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;
+}
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
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);
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];
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,
#include "raop.h"
#include "raop_buffer.h"
#include "netutils.h"
+#include "utils.h"
#include "compat.h"
#include "logger.h"
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;
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) {
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;
unsigned short ourseqnum;
struct sockaddr *addr;
socklen_t addrlen;
+ int ret;
addr = (struct sockaddr *)&raop_rtp->control_saddr;
addrlen = raop_rtp->control_saddr_len;
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;
}
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;
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);
/* 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;
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);