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 <robbat2@gentoo.org>
This commit is contained in:
Robin H. Johnson 2012-11-17 23:31:18 +00:00 committed by Arun Raghavan
parent d18c3664b5
commit 088ed8a8d6

View file

@ -64,6 +64,7 @@ PA_MODULE_USAGE(
"channels=<number of channels> " "channels=<number of channels> "
"rate=<sample rate> " "rate=<sample rate> "
"destination_ip=<destination IP address> " "destination_ip=<destination IP address> "
"source_ip=<source IP address> "
"port=<port number> " "port=<port number> "
"mtu=<maximum transfer unit> " "mtu=<maximum transfer unit> "
"loop=<loopback to local host?> " "loop=<loopback to local host?> "
@ -73,6 +74,7 @@ PA_MODULE_USAGE(
#define DEFAULT_PORT 46000 #define DEFAULT_PORT 46000
#define DEFAULT_TTL 1 #define DEFAULT_TTL 1
#define SAP_PORT 9875 #define SAP_PORT 9875
#define DEFAULT_SOURCE_IP "0.0.0.0"
#define DEFAULT_DESTINATION_IP "224.0.0.56" #define DEFAULT_DESTINATION_IP "224.0.0.56"
#define MEMBLOCKQ_MAXLENGTH (1024*170) #define MEMBLOCKQ_MAXLENGTH (1024*170)
#define DEFAULT_MTU 1280 #define DEFAULT_MTU 1280
@ -85,6 +87,7 @@ static const char* const valid_modargs[] = {
"rate", "rate",
"destination", /* Compatbility */ "destination", /* Compatbility */
"destination_ip", "destination_ip",
"source_ip",
"port", "port",
"mtu" , "mtu" ,
"loop", "loop",
@ -165,6 +168,7 @@ int pa__init(pa_module*m) {
struct userdata *u; struct userdata *u;
pa_modargs *ma = NULL; pa_modargs *ma = NULL;
const char *dst_addr; const char *dst_addr;
const char *src_addr;
uint32_t port = DEFAULT_PORT, mtu; uint32_t port = DEFAULT_PORT, mtu;
uint32_t ttl = DEFAULT_TTL; uint32_t ttl = DEFAULT_TTL;
sa_family_t af; sa_family_t af;
@ -172,9 +176,9 @@ int pa__init(pa_module*m) {
pa_source *s; pa_source *s;
pa_sample_spec ss; pa_sample_spec ss;
pa_channel_map cm; 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 #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 #endif
struct sockaddr_storage sa_dst; struct sockaddr_storage sa_dst;
pa_source_output *o = NULL; pa_source_output *o = NULL;
@ -242,6 +246,23 @@ int pa__init(pa_module*m) {
goto fail; 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); dst_addr = pa_modargs_get_value(ma, "destination", NULL);
if (dst_addr == NULL) if (dst_addr == NULL)
dst_addr = pa_modargs_get_value(ma, "destination_ip", DEFAULT_DESTINATION_IP); dst_addr = pa_modargs_get_value(ma, "destination_ip", DEFAULT_DESTINATION_IP);
@ -268,6 +289,16 @@ int pa__init(pa_module*m) {
goto fail; 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) { if (af == AF_INET && connect(fd, (struct sockaddr*) &dst_sa4, sizeof(dst_sa4)) < 0) {
pa_log("connect() failed: %s", pa_cstrerror(errno)); pa_log("connect() failed: %s", pa_cstrerror(errno));
goto fail; goto fail;
@ -283,6 +314,16 @@ int pa__init(pa_module*m) {
goto fail; 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) { 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)); pa_log("connect() failed: %s", pa_cstrerror(errno));
goto fail; goto fail;
@ -320,6 +361,7 @@ int pa__init(pa_module*m) {
pa_source_output_new_data_init(&data); pa_source_output_new_data_init(&data);
pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, "RTP Monitor Stream"); 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_sets(data.proplist, "rtp.destination", dst_addr);
pa_proplist_setf(data.proplist, "rtp.mtu", "%lu", (unsigned long) mtu); pa_proplist_setf(data.proplist, "rtp.mtu", "%lu", (unsigned long) mtu);
pa_proplist_setf(data.proplist, "rtp.port", "%lu", (unsigned long) port); 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_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_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_log_info("SDP-Data:\n%s\nEOF", p);
pa_sap_send(&u->sap_context, 0); pa_sap_send(&u->sap_context, 0);