From 088ed8a8d6ffb55ab904f447b743c061167ceb3f Mon Sep 17 00:00:00 2001 From: "Robin H. Johnson" Date: Sat, 17 Nov 2012 23:31:18 +0000 Subject: [PATCH] rtp: Introduce source IP configuration On a multi-homed system, the user may wish RTP to be used only on specific interfaces. The default binding of 0.0.0.0 for the source address causes SAP multicast on all interfaces, which is not ideal. Introduce a new module argument, that allows selection of the source IP, and thus interface. (changes in v2: s/srcip/source_ip) Signed-off-by: Robin H. Johnson --- src/modules/rtp/module-rtp-send.c | 48 +++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 00cc6c919..acabcf5bf 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -64,6 +64,7 @@ PA_MODULE_USAGE( "channels= " "rate= " "destination_ip= " + "source_ip= " "port= " "mtu= " "loop= " @@ -73,6 +74,7 @@ PA_MODULE_USAGE( #define DEFAULT_PORT 46000 #define DEFAULT_TTL 1 #define SAP_PORT 9875 +#define DEFAULT_SOURCE_IP "0.0.0.0" #define DEFAULT_DESTINATION_IP "224.0.0.56" #define MEMBLOCKQ_MAXLENGTH (1024*170) #define DEFAULT_MTU 1280 @@ -85,6 +87,7 @@ static const char* const valid_modargs[] = { "rate", "destination", /* Compatbility */ "destination_ip", + "source_ip", "port", "mtu" , "loop", @@ -165,6 +168,7 @@ int pa__init(pa_module*m) { struct userdata *u; pa_modargs *ma = NULL; const char *dst_addr; + const char *src_addr; uint32_t port = DEFAULT_PORT, mtu; uint32_t ttl = DEFAULT_TTL; sa_family_t af; @@ -172,9 +176,9 @@ int pa__init(pa_module*m) { pa_source *s; pa_sample_spec ss; pa_channel_map cm; - struct sockaddr_in dst_sa4, dst_sap_sa4; + struct sockaddr_in dst_sa4, dst_sap_sa4, src_sa4, src_sap_sa4; #ifdef HAVE_IPV6 - struct sockaddr_in6 dst_sa6, dst_sap_sa6; + struct sockaddr_in6 dst_sa6, dst_sap_sa6, src_sa6, src_sap_sa6; #endif struct sockaddr_storage sa_dst; pa_source_output *o = NULL; @@ -242,6 +246,23 @@ int pa__init(pa_module*m) { goto fail; } + src_addr = pa_modargs_get_value(ma, "source_ip", DEFAULT_SOURCE_IP); + + if (inet_pton(AF_INET, src_addr, &src_sa4.sin_addr) > 0) { + src_sa4.sin_family = af = AF_INET; + src_sa4.sin_port = htons(0); + src_sap_sa4 = src_sa4; +#ifdef HAVE_IPV6 + } else if (inet_pton(AF_INET6, src_addr, &src_sa6.sin6_addr) > 0) { + src_sa6.sin6_family = af = AF_INET6; + src_sa6.sin6_port = htons(0); + src_sap_sa6 = src_sa6; +#endif + } else { + pa_log("Invalid source address '%s'", src_addr); + goto fail; + } + dst_addr = pa_modargs_get_value(ma, "destination", NULL); if (dst_addr == NULL) dst_addr = pa_modargs_get_value(ma, "destination_ip", DEFAULT_DESTINATION_IP); @@ -268,6 +289,16 @@ int pa__init(pa_module*m) { goto fail; } + if (af == AF_INET && bind(fd, (struct sockaddr*) &src_sa4, sizeof(src_sa4)) < 0) { + pa_log("bind() failed: %s", pa_cstrerror(errno)); + goto fail; +#ifdef HAVE_IPV6 + } else if (af == AF_INET6 && bind(fd, (struct sockaddr*) &src_sa6, sizeof(src_sa6)) < 0) { + pa_log("bind() failed: %s", pa_cstrerror(errno)); + goto fail; +#endif + } + if (af == AF_INET && connect(fd, (struct sockaddr*) &dst_sa4, sizeof(dst_sa4)) < 0) { pa_log("connect() failed: %s", pa_cstrerror(errno)); goto fail; @@ -283,6 +314,16 @@ int pa__init(pa_module*m) { goto fail; } + if (af == AF_INET && bind(sap_fd, (struct sockaddr*) &src_sap_sa4, sizeof(src_sap_sa4)) < 0) { + pa_log("bind() failed: %s", pa_cstrerror(errno)); + goto fail; +#ifdef HAVE_IPV6 + } else if (af == AF_INET6 && bind(sap_fd, (struct sockaddr*) &src_sap_sa6, sizeof(src_sap_sa6)) < 0) { + pa_log("bind() failed: %s", pa_cstrerror(errno)); + goto fail; +#endif + } + if (af == AF_INET && connect(sap_fd, (struct sockaddr*) &dst_sap_sa4, sizeof(dst_sap_sa4)) < 0) { pa_log("connect() failed: %s", pa_cstrerror(errno)); goto fail; @@ -320,6 +361,7 @@ int pa__init(pa_module*m) { pa_source_output_new_data_init(&data); pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, "RTP Monitor Stream"); + pa_proplist_sets(data.proplist, "rtp.source", src_addr); pa_proplist_sets(data.proplist, "rtp.destination", dst_addr); pa_proplist_setf(data.proplist, "rtp.mtu", "%lu", (unsigned long) mtu); pa_proplist_setf(data.proplist, "rtp.port", "%lu", (unsigned long) port); @@ -387,7 +429,7 @@ int pa__init(pa_module*m) { pa_rtp_context_init_send(&u->rtp_context, fd, m->core->cookie, payload, pa_frame_size(&ss)); pa_sap_context_init_send(&u->sap_context, sap_fd, p); - pa_log_info("RTP stream initialized with mtu %u on %s:%u ttl=%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dst_addr, port, ttl, u->rtp_context.ssrc, payload, u->rtp_context.sequence); + pa_log_info("RTP stream initialized with mtu %u on %s:%u from %s ttl=%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dst_addr, port, src_addr, ttl, u->rtp_context.ssrc, payload, u->rtp_context.sequence); pa_log_info("SDP-Data:\n%s\nEOF", p); pa_sap_send(&u->sap_context, 0);