Skip to content

Commit d9a5853

Browse files
authored
Allow SIP plugin to bind media to a specific address (see #3248) (#3263)
1 parent aed755a commit d9a5853

File tree

1 file changed

+92
-50
lines changed

1 file changed

+92
-50
lines changed

src/plugins/janus_sip.c

+92-50
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,7 @@ static gboolean ipv6_disabled = FALSE;
854854
static janus_callbacks *gateway = NULL;
855855

856856
static char *local_ip = NULL, *sdp_ip = NULL, *local_media_ip = NULL;
857+
static janus_network_address janus_network_local_media_ip = { 0 };
857858
static int keepalive_interval = 120;
858859
static gboolean behind_nat = FALSE;
859860
static char *user_agent;
@@ -1882,11 +1883,11 @@ int janus_sip_init(janus_callbacks *callback, const char *config_path) {
18821883
}
18831884

18841885
item = janus_config_get(config, config_general, janus_config_type_item, "local_media_ip");
1885-
if(item && item->value)
1886+
if(item && item->value && strlen(item->value) > 0)
18861887
local_media_ip = g_strdup(item->value);
18871888

18881889
item = janus_config_get(config, config_general, janus_config_type_item, "sdp_ip");
1889-
if(item && item->value) {
1890+
if(item && item->value && strlen(item->value) > 0) {
18901891
sdp_ip = g_strdup(item->value);
18911892
JANUS_LOG(LOG_VERB, "IP to advertise in SDP: %s\n", sdp_ip);
18921893
}
@@ -2003,6 +2004,25 @@ int janus_sip_init(janus_callbacks *callback, const char *config_path) {
20032004
}
20042005
JANUS_LOG(LOG_VERB, "Local IP set to %s\n", local_ip);
20052006

2007+
/* Since we might have to derive SDP connection address from local_media_ip make sure it has a meaningful value
2008+
* for the purpose of using it in the SDP c= header */
2009+
janus_network_address_nullify(&janus_network_local_media_ip);
2010+
if(local_media_ip) {
2011+
if(janus_network_string_to_address(janus_network_query_options_any_ip, local_media_ip, &janus_network_local_media_ip) != 0) {
2012+
JANUS_LOG(LOG_ERR, "Invalid local media IP address [%s]...\n", local_media_ip);
2013+
return -1;
2014+
}
2015+
if((janus_network_local_media_ip.family == AF_INET && janus_network_local_media_ip.ipv4.s_addr == INADDR_ANY) ||
2016+
(janus_network_local_media_ip.family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&janus_network_local_media_ip.ipv6))) {
2017+
janus_network_address_nullify(&janus_network_local_media_ip);
2018+
}
2019+
}
2020+
JANUS_LOG(LOG_VERB, "Binding media address set to [%s]...\n", janus_network_address_is_null(&janus_network_local_media_ip) ? "any" : local_media_ip);
2021+
if(!sdp_ip) {
2022+
sdp_ip = janus_network_address_is_null(&janus_network_local_media_ip) ? local_ip : local_media_ip;
2023+
JANUS_LOG(LOG_VERB, "IP to advertise in SDP: %s\n", sdp_ip);
2024+
}
2025+
20062026
/* Setup sofia */
20072027
su_init();
20082028
if(notify_events && callback->events_is_enabled()) {
@@ -2022,19 +2042,29 @@ int janus_sip_init(janus_callbacks *callback, const char *config_path) {
20222042
/* This is the callback we'll need to invoke to contact the Janus core */
20232043
gateway = callback;
20242044

2025-
/* Finally, let's check if IPv6 is disabled, as we may need to know for RTP/RTCP sockets */
2026-
int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
2027-
if(fd <= 0) {
2028-
ipv6_disabled = TRUE;
2029-
} else {
2030-
int v6only = 0;
2031-
if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0)
2045+
if(janus_network_address_is_null(&janus_network_local_media_ip) ||
2046+
janus_network_local_media_ip.family == AF_INET6) {
2047+
/* Finally, let's check if IPv6 is disabled, as we may need to know for RTP/RTCP sockets */
2048+
int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
2049+
if(fd <= 0) {
20322050
ipv6_disabled = TRUE;
2033-
}
2034-
if(fd > 0)
2035-
close(fd);
2036-
if(ipv6_disabled) {
2037-
JANUS_LOG(LOG_WARN, "IPv6 disabled, will only use IPv4 for RTP/RTCP sockets (SIP)\n");
2051+
} else {
2052+
int v6only = 0;
2053+
if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0)
2054+
ipv6_disabled = TRUE;
2055+
}
2056+
if(fd > 0)
2057+
close(fd);
2058+
if(ipv6_disabled) {
2059+
if(!janus_network_address_is_null(&janus_network_local_media_ip)) {
2060+
JANUS_LOG(LOG_ERR, "IPv6 disabled and local media address is IPv6...\n");
2061+
return -1;
2062+
}
2063+
JANUS_LOG(LOG_WARN, "IPv6 disabled, will only use IPv4 for RTP/RTCP sockets (SIP)\n");
2064+
}
2065+
} else if(janus_network_local_media_ip.family == AF_INET) {
2066+
/* Disable if we have a specified IPv4 address for RTP/RTCP sockets */
2067+
ipv6_disabled = TRUE;
20382068
}
20392069

20402070
g_atomic_int_set(&initialized, 1);
@@ -6489,7 +6519,7 @@ char *janus_sip_sdp_manipulate(janus_sip_session *session, janus_sdp *sdp, gbool
64896519
JANUS_LOG(LOG_VERB, "Setting protocol to %s\n", session->media.require_srtp ? "RTP/SAVP" : "RTP/AVP");
64906520
if(sdp->c_addr) {
64916521
g_free(sdp->c_addr);
6492-
sdp->c_addr = g_strdup(sdp_ip ? sdp_ip : (local_media_ip ? local_media_ip : local_ip));
6522+
sdp->c_addr = g_strdup(sdp_ip);
64936523
}
64946524
int opusred_pt = answer ? janus_sdp_get_opusred_pt(sdp, -1) : -1;
64956525
GList *temp = sdp->m_lines;
@@ -6523,7 +6553,7 @@ char *janus_sip_sdp_manipulate(janus_sip_session *session, janus_sdp *sdp, gbool
65236553
}
65246554
}
65256555
g_free(m->c_addr);
6526-
m->c_addr = g_strdup(sdp_ip ? sdp_ip : (local_media_ip ? local_media_ip : local_ip));
6556+
m->c_addr = g_strdup(sdp_ip);
65276557
if(answer && (m->type == JANUS_SDP_AUDIO || m->type == JANUS_SDP_VIDEO)) {
65286558
/* Check which codec was negotiated eventually */
65296559
int pt = -1;
@@ -6625,18 +6655,24 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u
66256655
session->media.pipefd[1] = -1;
66266656
}
66276657
}
6658+
gboolean use_ipv6_address_family = !ipv6_disabled &&
6659+
(janus_network_address_is_null(&janus_network_local_media_ip) || janus_network_local_media_ip.family == AF_INET6);
6660+
socklen_t addrlen = use_ipv6_address_family? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
66286661
/* Start */
66296662
int attempts = 100; /* FIXME Don't retry forever */
66306663
if(session->media.has_audio) {
6631-
JANUS_LOG(LOG_VERB, "Allocating audio ports:\n");
6664+
JANUS_LOG(LOG_VERB, "Allocating audio ports using address [%s]\n",
6665+
janus_network_address_is_null(&janus_network_local_media_ip) ? "any" : local_media_ip);
66326666
struct sockaddr_storage audio_rtp_address, audio_rtcp_address;
66336667
while(session->media.local_audio_rtp_port == 0 || session->media.local_audio_rtcp_port == 0) {
66346668
if(attempts == 0) /* Too many failures */
66356669
return -1;
6670+
memset(&audio_rtp_address, 0, sizeof(audio_rtp_address));
6671+
memset(&audio_rtcp_address, 0, sizeof(audio_rtcp_address));
66366672
if(session->media.audio_rtp_fd == -1) {
6637-
session->media.audio_rtp_fd = socket(!ipv6_disabled ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
6673+
session->media.audio_rtp_fd = socket(use_ipv6_address_family ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
66386674
int v6only = 0;
6639-
if(!ipv6_disabled && session->media.audio_rtp_fd != -1 &&
6675+
if(use_ipv6_address_family && session->media.audio_rtp_fd != -1 &&
66406676
setsockopt(session->media.audio_rtp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) {
66416677
JANUS_LOG(LOG_WARN, "Error setting v6only to false on audio RTP socket (error=%s)\n",
66426678
g_strerror(errno));
@@ -6652,9 +6688,9 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u
66526688
}
66536689
}
66546690
if(session->media.audio_rtcp_fd == -1) {
6655-
session->media.audio_rtcp_fd = socket(!ipv6_disabled ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
6691+
session->media.audio_rtcp_fd = socket(use_ipv6_address_family ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
66566692
int v6only = 0;
6657-
if(!ipv6_disabled && session->media.audio_rtcp_fd != -1 &&
6693+
if(use_ipv6_address_family && session->media.audio_rtcp_fd != -1 &&
66586694
setsockopt(session->media.audio_rtcp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) {
66596695
JANUS_LOG(LOG_WARN, "Error setting v6only to false on audio RTCP socket (error=%s)\n",
66606696
g_strerror(errno));
@@ -6667,39 +6703,40 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u
66676703
int rtp_port = g_random_int_range(rtp_range_min, rtp_range_max);
66686704
if(rtp_port % 2)
66696705
rtp_port++; /* Pick an even port for RTP */
6670-
if(!ipv6_disabled) {
6706+
if(use_ipv6_address_family) {
66716707
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&audio_rtp_address;
66726708
addr->sin6_family = AF_INET6;
66736709
addr->sin6_port = htons(rtp_port);
6674-
addr->sin6_addr = in6addr_any;
6710+
addr->sin6_addr = janus_network_address_is_null(&janus_network_local_media_ip) ? in6addr_any : janus_network_local_media_ip.ipv6;
66756711
} else {
66766712
struct sockaddr_in *addr = (struct sockaddr_in *)&audio_rtp_address;
66776713
addr->sin_family = AF_INET;
66786714
addr->sin_port = htons(rtp_port);
6679-
addr->sin_addr.s_addr = INADDR_ANY;
6715+
addr->sin_addr.s_addr = janus_network_address_is_null(&janus_network_local_media_ip) ? INADDR_ANY : janus_network_local_media_ip.ipv4.s_addr;
66806716
}
6681-
if(bind(session->media.audio_rtp_fd, (struct sockaddr *)(&audio_rtp_address), sizeof(audio_rtp_address)) < 0) {
6682-
JANUS_LOG(LOG_ERR, "Bind failed for audio RTP (port %d), trying a different one...\n", rtp_port);
6717+
if(bind(session->media.audio_rtp_fd, (struct sockaddr *)(&audio_rtp_address), addrlen) < 0) {
6718+
JANUS_LOG(LOG_ERR, "Bind failed for audio RTP (port %d), error (%s), trying a different one...\n", rtp_port, g_strerror(errno));
66836719
close(session->media.audio_rtp_fd);
66846720
session->media.audio_rtp_fd = -1;
66856721
attempts--;
66866722
continue;
66876723
}
6688-
JANUS_LOG(LOG_VERB, "Audio RTP listener bound to %s:%d(%d)\n", (local_media_ip ? local_media_ip : local_ip), rtp_port, session->media.audio_rtp_fd);
6724+
JANUS_LOG(LOG_VERB, "Audio RTP listener bound to [%s]:%d(%d)\n",
6725+
janus_network_address_is_null(&janus_network_local_media_ip) ? "any" : local_media_ip, rtp_port, session->media.audio_rtp_fd);
66896726
int rtcp_port = rtp_port+1;
6690-
if(!ipv6_disabled) {
6727+
if(use_ipv6_address_family) {
66916728
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&audio_rtcp_address;
66926729
addr->sin6_family = AF_INET6;
66936730
addr->sin6_port = htons(rtcp_port);
6694-
addr->sin6_addr = in6addr_any;
6731+
addr->sin6_addr = janus_network_address_is_null(&janus_network_local_media_ip) ? in6addr_any : janus_network_local_media_ip.ipv6;
66956732
} else {
66966733
struct sockaddr_in *addr = (struct sockaddr_in *)&audio_rtcp_address;
66976734
addr->sin_family = AF_INET;
66986735
addr->sin_port = htons(rtcp_port);
6699-
addr->sin_addr.s_addr = INADDR_ANY;
6736+
addr->sin_addr.s_addr = janus_network_address_is_null(&janus_network_local_media_ip) ? INADDR_ANY : janus_network_local_media_ip.ipv4.s_addr;
67006737
}
6701-
if(bind(session->media.audio_rtcp_fd, (struct sockaddr *)(&audio_rtcp_address), sizeof(audio_rtcp_address)) < 0) {
6702-
JANUS_LOG(LOG_ERR, "Bind failed for audio RTCP (port %d), trying a different one...\n", rtcp_port);
6738+
if(bind(session->media.audio_rtcp_fd, (struct sockaddr *)(&audio_rtcp_address), addrlen) < 0) {
6739+
JANUS_LOG(LOG_ERR, "Bind failed for audio RTCP (port %d), error (%s), trying a different one...\n", rtcp_port, g_strerror(errno));
67036740
/* RTP socket is not valid anymore, reset it */
67046741
close(session->media.audio_rtp_fd);
67056742
session->media.audio_rtp_fd = -1;
@@ -6708,21 +6745,24 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u
67086745
attempts--;
67096746
continue;
67106747
}
6711-
JANUS_LOG(LOG_VERB, "Audio RTCP listener bound to %s:%d(%d)\n", (local_media_ip ? local_media_ip : local_ip), rtcp_port, session->media.audio_rtcp_fd);
6748+
JANUS_LOG(LOG_VERB, "Audio RTCP listener bound to [%s]:%d(%d)\n", janus_network_address_is_null(&janus_network_local_media_ip) ?"any":local_media_ip, rtcp_port, session->media.audio_rtcp_fd);
67126749
session->media.local_audio_rtp_port = rtp_port;
67136750
session->media.local_audio_rtcp_port = rtcp_port;
67146751
}
67156752
}
67166753
if(session->media.has_video) {
6717-
JANUS_LOG(LOG_VERB, "Allocating video ports:\n");
6754+
JANUS_LOG(LOG_VERB, "Allocating video ports using address [%s]\n",
6755+
janus_network_address_is_null(&janus_network_local_media_ip ) ?"any" : local_media_ip);
67186756
struct sockaddr_storage video_rtp_address, video_rtcp_address;
67196757
while(session->media.local_video_rtp_port == 0 || session->media.local_video_rtcp_port == 0) {
67206758
if(attempts == 0) /* Too many failures */
67216759
return -1;
6760+
memset(&video_rtp_address, 0, sizeof(video_rtp_address));
6761+
memset(&video_rtcp_address, 0, sizeof(video_rtcp_address));
67226762
if(session->media.video_rtp_fd == -1) {
6723-
session->media.video_rtp_fd = socket(!ipv6_disabled ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
6763+
session->media.video_rtp_fd = socket(use_ipv6_address_family ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
67246764
int v6only = 0;
6725-
if(!ipv6_disabled && session->media.video_rtp_fd != -1 &&
6765+
if(use_ipv6_address_family && session->media.video_rtp_fd != -1 &&
67266766
setsockopt(session->media.video_rtp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) {
67276767
JANUS_LOG(LOG_WARN, "Error setting v6only to false on video RTP socket (error=%s)\n",
67286768
g_strerror(errno));
@@ -6738,9 +6778,9 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u
67386778
}
67396779
}
67406780
if(session->media.video_rtcp_fd == -1) {
6741-
session->media.video_rtcp_fd = socket(!ipv6_disabled ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
6781+
session->media.video_rtcp_fd = socket(use_ipv6_address_family ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
67426782
int v6only = 0;
6743-
if(!ipv6_disabled && session->media.video_rtcp_fd != -1 &&
6783+
if(use_ipv6_address_family && session->media.video_rtcp_fd != -1 &&
67446784
setsockopt(session->media.video_rtcp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) {
67456785
JANUS_LOG(LOG_WARN, "Error setting v6only to false on video RTCP socket (error=%s)\n",
67466786
g_strerror(errno));
@@ -6753,39 +6793,40 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u
67536793
int rtp_port = g_random_int_range(rtp_range_min, rtp_range_max);
67546794
if(rtp_port % 2)
67556795
rtp_port++; /* Pick an even port for RTP */
6756-
if(!ipv6_disabled) {
6796+
if(use_ipv6_address_family) {
67576797
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&video_rtp_address;
67586798
addr->sin6_family = AF_INET6;
67596799
addr->sin6_port = htons(rtp_port);
6760-
addr->sin6_addr = in6addr_any;
6800+
addr->sin6_addr = janus_network_address_is_null(&janus_network_local_media_ip) ? in6addr_any : janus_network_local_media_ip.ipv6;
67616801
} else {
67626802
struct sockaddr_in *addr = (struct sockaddr_in *)&video_rtp_address;
67636803
addr->sin_family = AF_INET;
67646804
addr->sin_port = htons(rtp_port);
6765-
addr->sin_addr.s_addr = INADDR_ANY;
6805+
addr->sin_addr.s_addr = janus_network_address_is_null(&janus_network_local_media_ip) ? INADDR_ANY : janus_network_local_media_ip.ipv4.s_addr;
67666806
}
6767-
if(bind(session->media.video_rtp_fd, (struct sockaddr *)(&video_rtp_address), sizeof(video_rtp_address)) < 0) {
6768-
JANUS_LOG(LOG_ERR, "Bind failed for video RTP (port %d), trying a different one...\n", rtp_port);
6807+
if(bind(session->media.video_rtp_fd, (struct sockaddr *)(&video_rtp_address), addrlen) < 0) {
6808+
JANUS_LOG(LOG_ERR, "Bind failed for video RTP (port %d), error (%s), trying a different one...\n", rtp_port, g_strerror(errno));
67696809
close(session->media.video_rtp_fd);
67706810
session->media.video_rtp_fd = -1;
67716811
attempts--;
67726812
continue;
67736813
}
6774-
JANUS_LOG(LOG_VERB, "Video RTP listener bound to %s:%d(%d)\n", (local_media_ip ? local_media_ip : local_ip), rtp_port, session->media.video_rtp_fd);
6814+
JANUS_LOG(LOG_VERB, "Video RTP listener bound to [%s]:%d(%d)\n",
6815+
janus_network_address_is_null(&janus_network_local_media_ip) ? "any" : local_media_ip, rtp_port, session->media.video_rtp_fd);
67756816
int rtcp_port = rtp_port+1;
6776-
if(!ipv6_disabled) {
6817+
if(use_ipv6_address_family) {
67776818
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&video_rtcp_address;
67786819
addr->sin6_family = AF_INET6;
67796820
addr->sin6_port = htons(rtcp_port);
6780-
addr->sin6_addr = in6addr_any;
6821+
addr->sin6_addr = janus_network_address_is_null(&janus_network_local_media_ip) ? in6addr_any : janus_network_local_media_ip.ipv6;
67816822
} else {
67826823
struct sockaddr_in *addr = (struct sockaddr_in *)&video_rtcp_address;
67836824
addr->sin_family = AF_INET;
67846825
addr->sin_port = htons(rtcp_port);
6785-
addr->sin_addr.s_addr = INADDR_ANY;
6826+
addr->sin_addr.s_addr = janus_network_address_is_null(&janus_network_local_media_ip) ? INADDR_ANY : janus_network_local_media_ip.ipv4.s_addr;
67866827
}
6787-
if(bind(session->media.video_rtcp_fd, (struct sockaddr *)(&video_rtcp_address), sizeof(video_rtcp_address)) < 0) {
6788-
JANUS_LOG(LOG_ERR, "Bind failed for video RTCP (port %d), trying a different one...\n", rtcp_port);
6828+
if(bind(session->media.video_rtcp_fd, (struct sockaddr *)(&video_rtcp_address), addrlen) < 0) {
6829+
JANUS_LOG(LOG_ERR, "Bind failed for video RTCP (port %d), error (%s), trying a different one...\n", rtcp_port, g_strerror(errno));
67896830
/* RTP socket is not valid anymore, reset it */
67906831
close(session->media.video_rtp_fd);
67916832
session->media.video_rtp_fd = -1;
@@ -6794,7 +6835,8 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u
67946835
attempts--;
67956836
continue;
67966837
}
6797-
JANUS_LOG(LOG_VERB, "Video RTCP listener bound to %s:%d(%d)\n", (local_media_ip ? local_media_ip : local_ip), rtcp_port, session->media.video_rtcp_fd);
6838+
JANUS_LOG(LOG_VERB, "Video RTCP listener bound to [%s]:%d(%d)\n",
6839+
janus_network_address_is_null(&janus_network_local_media_ip) ? "any" : local_media_ip, rtcp_port, session->media.video_rtcp_fd);
67986840
session->media.local_video_rtp_port = rtp_port;
67996841
session->media.local_video_rtcp_port = rtcp_port;
68006842
}

0 commit comments

Comments
 (0)