-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow SIP plugin to bind media to a specific address (see #3248) #3263
Changes from 1 commit
18ea060
67af7b4
f3fc5d8
c3ce78c
fa705e1
2705df7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -854,6 +854,7 @@ static gboolean ipv6_disabled = FALSE; | |
static janus_callbacks *gateway = NULL; | ||
|
||
static char *local_ip = NULL, *sdp_ip = NULL, *local_media_ip = NULL; | ||
static janus_network_address janus_network_local_media_ip = { 0 }; | ||
static int keepalive_interval = 120; | ||
static gboolean behind_nat = FALSE; | ||
static char *user_agent; | ||
|
@@ -1882,11 +1883,11 @@ int janus_sip_init(janus_callbacks *callback, const char *config_path) { | |
} | ||
|
||
item = janus_config_get(config, config_general, janus_config_type_item, "local_media_ip"); | ||
if(item && item->value) | ||
if(item && item->value && strlen(item->value) > 0) | ||
local_media_ip = g_strdup(item->value); | ||
|
||
item = janus_config_get(config, config_general, janus_config_type_item, "sdp_ip"); | ||
if(item && item->value) { | ||
if(item && item->value && strlen(item->value) > 0) { | ||
sdp_ip = g_strdup(item->value); | ||
JANUS_LOG(LOG_VERB, "IP to advertise in SDP: %s\n", sdp_ip); | ||
} | ||
|
@@ -2003,6 +2004,27 @@ int janus_sip_init(janus_callbacks *callback, const char *config_path) { | |
} | ||
JANUS_LOG(LOG_VERB, "Local IP set to %s\n", local_ip); | ||
|
||
/* | ||
Since we might have to derive SDP connection address from local_media_ip make sure it has a meaningful value | ||
for the prupose of using it in the SDP c= header. | ||
*/ | ||
janus_network_address_nullify(&janus_network_local_media_ip); | ||
if(local_media_ip) { | ||
if(janus_network_string_to_address(janus_network_query_options_any_ip, local_media_ip, &janus_network_local_media_ip) != 0) { | ||
JANUS_LOG(LOG_ERR, "Invalid local media IP address [%s]...\n", local_media_ip); | ||
return -1; | ||
} | ||
if((janus_network_local_media_ip.family == AF_INET && janus_network_local_media_ip.ipv4.s_addr == INADDR_ANY) || | ||
(janus_network_local_media_ip.family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&janus_network_local_media_ip.ipv6))) { | ||
janus_network_address_nullify(&janus_network_local_media_ip); | ||
} | ||
} | ||
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); | ||
if(!sdp_ip) { | ||
sdp_ip = janus_network_address_is_null(&janus_network_local_media_ip) ? local_ip : local_media_ip; | ||
pawnnail marked this conversation as resolved.
Show resolved
Hide resolved
|
||
JANUS_LOG(LOG_VERB, "IP to advertise in SDP: %s\n", sdp_ip); | ||
} | ||
|
||
/* Setup sofia */ | ||
su_init(); | ||
if(notify_events && callback->events_is_enabled()) { | ||
|
@@ -2022,19 +2044,24 @@ int janus_sip_init(janus_callbacks *callback, const char *config_path) { | |
/* This is the callback we'll need to invoke to contact the Janus core */ | ||
gateway = callback; | ||
|
||
/* Finally, let's check if IPv6 is disabled, as we may need to know for RTP/RTCP sockets */ | ||
int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); | ||
if(fd <= 0) { | ||
ipv6_disabled = TRUE; | ||
} else { | ||
int v6only = 0; | ||
if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) | ||
if(janus_network_address_is_null(&janus_network_local_media_ip)) { | ||
/* Finally, let's check if IPv6 is disabled, as we may need to know for RTP/RTCP sockets */ | ||
int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); | ||
if(fd <= 0) { | ||
ipv6_disabled = TRUE; | ||
} | ||
if(fd > 0) | ||
close(fd); | ||
if(ipv6_disabled) { | ||
JANUS_LOG(LOG_WARN, "IPv6 disabled, will only use IPv4 for RTP/RTCP sockets (SIP)\n"); | ||
} else { | ||
int v6only = 0; | ||
if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) | ||
ipv6_disabled = TRUE; | ||
} | ||
if(fd > 0) | ||
close(fd); | ||
if(ipv6_disabled) { | ||
JANUS_LOG(LOG_WARN, "IPv6 disabled, will only use IPv4 for RTP/RTCP sockets (SIP)\n"); | ||
} | ||
} else if(janus_network_local_media_ip.family == AF_INET) { | ||
/* Disable if we have a specified IPv4 address for RTP/RTCP sockets */ | ||
ipv6_disabled = TRUE; | ||
} | ||
|
||
g_atomic_int_set(&initialized, 1); | ||
|
@@ -6489,7 +6516,7 @@ char *janus_sip_sdp_manipulate(janus_sip_session *session, janus_sdp *sdp, gbool | |
JANUS_LOG(LOG_VERB, "Setting protocol to %s\n", session->media.require_srtp ? "RTP/SAVP" : "RTP/AVP"); | ||
if(sdp->c_addr) { | ||
g_free(sdp->c_addr); | ||
sdp->c_addr = g_strdup(sdp_ip ? sdp_ip : (local_media_ip ? local_media_ip : local_ip)); | ||
sdp->c_addr = g_strdup(sdp_ip); | ||
} | ||
int opusred_pt = answer ? janus_sdp_get_opusred_pt(sdp, -1) : -1; | ||
GList *temp = sdp->m_lines; | ||
|
@@ -6523,7 +6550,7 @@ char *janus_sip_sdp_manipulate(janus_sip_session *session, janus_sdp *sdp, gbool | |
} | ||
} | ||
g_free(m->c_addr); | ||
m->c_addr = g_strdup(sdp_ip ? sdp_ip : (local_media_ip ? local_media_ip : local_ip)); | ||
m->c_addr = g_strdup(sdp_ip); | ||
if(answer && (m->type == JANUS_SDP_AUDIO || m->type == JANUS_SDP_VIDEO)) { | ||
/* Check which codec was negotiated eventually */ | ||
int pt = -1; | ||
|
@@ -6625,14 +6652,27 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u | |
session->media.pipefd[1] = -1; | ||
} | ||
} | ||
/* Determine the address family to use */ | ||
if(ipv6_disabled && | ||
!janus_network_address_is_null(&janus_network_local_media_ip) && | ||
janus_network_local_media_ip.family == AF_INET6) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Code style: you need another tab of indent for the two additional checks above, otherwise it ends up lined with the action below. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Point taken. The condition is removed as redundant. |
||
JANUS_LOG(LOG_ERR, "Error setting address for media sockets, IPv6 is disabled and local media address is IPv6...\n"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't like this action failing at runtime. It looks like a check that can be done when thew plugin is loaded, that is after the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense. Moved the failure to the config loading time. |
||
return -1; | ||
} | ||
gboolean use_ipv6_address_family = !ipv6_disabled && | ||
(janus_network_address_is_null(&janus_network_local_media_ip) || janus_network_local_media_ip.family == AF_INET6); | ||
socklen_t addrlen = use_ipv6_address_family? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); | ||
/* Start */ | ||
int attempts = 100; /* FIXME Don't retry forever */ | ||
if(session->media.has_audio) { | ||
JANUS_LOG(LOG_VERB, "Allocating audio ports:\n"); | ||
JANUS_LOG(LOG_VERB, "Allocating audio ports using address [%s]\n", | ||
janus_network_address_is_null(&janus_network_local_media_ip) ? "any" : local_media_ip); | ||
struct sockaddr_storage audio_rtp_address, audio_rtcp_address; | ||
while(session->media.local_audio_rtp_port == 0 || session->media.local_audio_rtcp_port == 0) { | ||
if(attempts == 0) /* Too many failures */ | ||
return -1; | ||
memset(&audio_rtp_address, 0, sizeof(audio_rtp_address)); | ||
memset(&audio_rtcp_address, 0, sizeof(audio_rtcp_address)); | ||
if(session->media.audio_rtp_fd == -1) { | ||
session->media.audio_rtp_fd = socket(!ipv6_disabled ? AF_INET6 : AF_INET, SOCK_DGRAM, 0); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you forget to switch to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Essentially |
||
int v6only = 0; | ||
|
@@ -6667,39 +6707,40 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u | |
int rtp_port = g_random_int_range(rtp_range_min, rtp_range_max); | ||
if(rtp_port % 2) | ||
rtp_port++; /* Pick an even port for RTP */ | ||
if(!ipv6_disabled) { | ||
if(use_ipv6_address_family) { | ||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&audio_rtp_address; | ||
addr->sin6_family = AF_INET6; | ||
addr->sin6_port = htons(rtp_port); | ||
addr->sin6_addr = in6addr_any; | ||
addr->sin6_addr = janus_network_address_is_null(&janus_network_local_media_ip) ? in6addr_any : janus_network_local_media_ip.ipv6; | ||
} else { | ||
struct sockaddr_in *addr = (struct sockaddr_in *)&audio_rtp_address; | ||
addr->sin_family = AF_INET; | ||
addr->sin_port = htons(rtp_port); | ||
addr->sin_addr.s_addr = INADDR_ANY; | ||
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; | ||
} | ||
if(bind(session->media.audio_rtp_fd, (struct sockaddr *)(&audio_rtp_address), sizeof(audio_rtp_address)) < 0) { | ||
JANUS_LOG(LOG_ERR, "Bind failed for audio RTP (port %d), trying a different one...\n", rtp_port); | ||
if(bind(session->media.audio_rtp_fd, (struct sockaddr *)(&audio_rtp_address), addrlen) < 0) { | ||
JANUS_LOG(LOG_ERR, "Bind failed for audio RTP (port %d), error (%s), trying a different one...\n", rtp_port, g_strerror(errno)); | ||
close(session->media.audio_rtp_fd); | ||
session->media.audio_rtp_fd = -1; | ||
attempts--; | ||
continue; | ||
} | ||
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); | ||
JANUS_LOG(LOG_VERB, "Audio RTP listener bound to [%s]:%d(%d)\n", | ||
janus_network_address_is_null(&janus_network_local_media_ip) ? "any" : local_media_ip, rtp_port, session->media.audio_rtp_fd); | ||
int rtcp_port = rtp_port+1; | ||
if(!ipv6_disabled) { | ||
if(use_ipv6_address_family) { | ||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&audio_rtcp_address; | ||
addr->sin6_family = AF_INET6; | ||
addr->sin6_port = htons(rtcp_port); | ||
addr->sin6_addr = in6addr_any; | ||
addr->sin6_addr = janus_network_address_is_null(&janus_network_local_media_ip) ? in6addr_any : janus_network_local_media_ip.ipv6; | ||
} else { | ||
struct sockaddr_in *addr = (struct sockaddr_in *)&audio_rtcp_address; | ||
addr->sin_family = AF_INET; | ||
addr->sin_port = htons(rtcp_port); | ||
addr->sin_addr.s_addr = INADDR_ANY; | ||
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; | ||
} | ||
if(bind(session->media.audio_rtcp_fd, (struct sockaddr *)(&audio_rtcp_address), sizeof(audio_rtcp_address)) < 0) { | ||
JANUS_LOG(LOG_ERR, "Bind failed for audio RTCP (port %d), trying a different one...\n", rtcp_port); | ||
if(bind(session->media.audio_rtcp_fd, (struct sockaddr *)(&audio_rtcp_address), addrlen) < 0) { | ||
JANUS_LOG(LOG_ERR, "Bind failed for audio RTCP (port %d), error (%s), trying a different one...\n", rtcp_port, g_strerror(errno)); | ||
/* RTP socket is not valid anymore, reset it */ | ||
close(session->media.audio_rtp_fd); | ||
session->media.audio_rtp_fd = -1; | ||
|
@@ -6708,17 +6749,20 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u | |
attempts--; | ||
continue; | ||
} | ||
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); | ||
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); | ||
session->media.local_audio_rtp_port = rtp_port; | ||
session->media.local_audio_rtcp_port = rtcp_port; | ||
} | ||
} | ||
if(session->media.has_video) { | ||
JANUS_LOG(LOG_VERB, "Allocating video ports:\n"); | ||
JANUS_LOG(LOG_VERB, "Allocating video ports using address [%s]\n", | ||
janus_network_address_is_null(&janus_network_local_media_ip ) ?"any" : local_media_ip); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are some weird spaces in here. Per the code style, it should be
|
||
struct sockaddr_storage video_rtp_address, video_rtcp_address; | ||
while(session->media.local_video_rtp_port == 0 || session->media.local_video_rtcp_port == 0) { | ||
if(attempts == 0) /* Too many failures */ | ||
return -1; | ||
memset(&video_rtp_address, 0, sizeof(video_rtp_address)); | ||
memset(&video_rtcp_address, 0, sizeof(video_rtcp_address)); | ||
if(session->media.video_rtp_fd == -1) { | ||
session->media.video_rtp_fd = socket(!ipv6_disabled ? AF_INET6 : AF_INET, SOCK_DGRAM, 0); | ||
pawnnail marked this conversation as resolved.
Show resolved
Hide resolved
|
||
int v6only = 0; | ||
|
@@ -6753,39 +6797,40 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u | |
int rtp_port = g_random_int_range(rtp_range_min, rtp_range_max); | ||
if(rtp_port % 2) | ||
rtp_port++; /* Pick an even port for RTP */ | ||
if(!ipv6_disabled) { | ||
if(use_ipv6_address_family) { | ||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&video_rtp_address; | ||
addr->sin6_family = AF_INET6; | ||
addr->sin6_port = htons(rtp_port); | ||
addr->sin6_addr = in6addr_any; | ||
addr->sin6_addr = janus_network_address_is_null(&janus_network_local_media_ip) ? in6addr_any : janus_network_local_media_ip.ipv6; | ||
} else { | ||
struct sockaddr_in *addr = (struct sockaddr_in *)&video_rtp_address; | ||
addr->sin_family = AF_INET; | ||
addr->sin_port = htons(rtp_port); | ||
addr->sin_addr.s_addr = INADDR_ANY; | ||
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; | ||
} | ||
if(bind(session->media.video_rtp_fd, (struct sockaddr *)(&video_rtp_address), sizeof(video_rtp_address)) < 0) { | ||
JANUS_LOG(LOG_ERR, "Bind failed for video RTP (port %d), trying a different one...\n", rtp_port); | ||
if(bind(session->media.video_rtp_fd, (struct sockaddr *)(&video_rtp_address), addrlen) < 0) { | ||
JANUS_LOG(LOG_ERR, "Bind failed for video RTP (port %d), error (%s), trying a different one...\n", rtp_port, g_strerror(errno)); | ||
close(session->media.video_rtp_fd); | ||
session->media.video_rtp_fd = -1; | ||
attempts--; | ||
continue; | ||
} | ||
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); | ||
JANUS_LOG(LOG_VERB, "Video RTP listener bound to [%s]:%d(%d)\n", | ||
janus_network_address_is_null(&janus_network_local_media_ip) ? "any" : local_media_ip, rtp_port, session->media.video_rtp_fd); | ||
int rtcp_port = rtp_port+1; | ||
if(!ipv6_disabled) { | ||
if(use_ipv6_address_family) { | ||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&video_rtcp_address; | ||
addr->sin6_family = AF_INET6; | ||
addr->sin6_port = htons(rtcp_port); | ||
addr->sin6_addr = in6addr_any; | ||
addr->sin6_addr = janus_network_address_is_null(&janus_network_local_media_ip) ? in6addr_any : janus_network_local_media_ip.ipv6; | ||
} else { | ||
struct sockaddr_in *addr = (struct sockaddr_in *)&video_rtcp_address; | ||
addr->sin_family = AF_INET; | ||
addr->sin_port = htons(rtcp_port); | ||
addr->sin_addr.s_addr = INADDR_ANY; | ||
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; | ||
} | ||
if(bind(session->media.video_rtcp_fd, (struct sockaddr *)(&video_rtcp_address), sizeof(video_rtcp_address)) < 0) { | ||
JANUS_LOG(LOG_ERR, "Bind failed for video RTCP (port %d), trying a different one...\n", rtcp_port); | ||
if(bind(session->media.video_rtcp_fd, (struct sockaddr *)(&video_rtcp_address), addrlen) < 0) { | ||
JANUS_LOG(LOG_ERR, "Bind failed for video RTCP (port %d), error (%s), trying a different one...\n", rtcp_port, g_strerror(errno)); | ||
/* RTP socket is not valid anymore, reset it */ | ||
close(session->media.video_rtp_fd); | ||
session->media.video_rtp_fd = -1; | ||
|
@@ -6794,7 +6839,8 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u | |
attempts--; | ||
continue; | ||
} | ||
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); | ||
JANUS_LOG(LOG_VERB, "Video 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.video_rtcp_fd); | ||
session->media.local_video_rtp_port = rtp_port; | ||
session->media.local_video_rtcp_port = rtcp_port; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't use this format for comments. Align to what we use in other parts of the code, so something the lines of
As a side notem there's a typo in "purpose".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point taken.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The format of the comment is still incorrect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry about that. Fixed.