From acb137827a454f52b11a78fa7f3c16691aeecca0 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 6 Mar 2023 17:02:27 +0100 Subject: [PATCH] Use getaddrinfo instead of gethostbyname (fixes #3156) (#3159) --- src/ip-utils.c | 46 ++++++++++ src/ip-utils.h | 22 ++++- src/plugins/janus_audiobridge.c | 54 ++++++----- src/plugins/janus_nosip.c | 125 +++++++++++++++---------- src/plugins/janus_sip.c | 157 ++++++++++++++++++++------------ src/sdp-utils.c | 2 + 6 files changed, 271 insertions(+), 135 deletions(-) diff --git a/src/ip-utils.c b/src/ip-utils.c index d4f918ae15..9098095126 100644 --- a/src/ip-utils.c +++ b/src/ip-utils.c @@ -321,3 +321,49 @@ char *janus_network_detect_local_ip_as_string(janus_network_query_options addr_t return NULL; return g_strdup(janus_network_address_string_from_buffer(&buf)); } + +int janus_network_resolve_address(const char *host, struct sockaddr_storage *address) { + if(!host || !address) + return -EINVAL; + /* Check whether we need to resolve the address*/ + gboolean resolved = FALSE; + if(strstr(host, ":")) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)address; + addr6->sin6_family = AF_INET6; + if(inet_pton(AF_INET6, host, &addr6->sin6_addr) == 1) { + /* Numeric IPv6 address */ + resolved = TRUE; + } + } else { + struct sockaddr_in *addr = (struct sockaddr_in *)address; + addr->sin_family = AF_INET; + if(inet_pton(AF_INET, host, &addr->sin_addr) == 1) { + /* Numeric IPv4 address */ + resolved = TRUE; + } + } + if(!resolved) { + /* Perform a getaddrinfo on the address */ + struct addrinfo *result = NULL; + int res = getaddrinfo(host, NULL, NULL, &result); + if(res == 0) { + /* Address resolved */ + struct addrinfo *temp = result; + while(temp && !resolved) { + if(result->ai_family == AF_INET6) { + resolved = TRUE; + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)address; + memcpy(&addr6->sin6_addr, result->ai_addr, sizeof(*addr6)); + } else if(result->ai_family == AF_INET) { + resolved = TRUE; + struct sockaddr_in *addr = (struct sockaddr_in *)address; + memcpy(&addr->sin_addr, result->ai_addr, sizeof(*addr)); + } + temp = temp->ai_next; + } + freeaddrinfo(result); + } + } + /* Done */ + return resolved ? 0 : -1; +} diff --git a/src/ip-utils.h b/src/ip-utils.h index e0664711ff..49bd8d6b0b 100644 --- a/src/ip-utils.h +++ b/src/ip-utils.h @@ -215,7 +215,7 @@ int janus_network_string_is_valid_address(janus_network_query_options addr_type, * janus_network_query_options_ipv6 or janus_network_query_options_any_ip) * \param user_value The IP address string to check * \param result Pointer to a valid janus_network_address instance that will contain the result - * \return 0 in case of success, -EINVAL otherwise otherwise + * \return 0 in case of success, -EINVAL otherwise */ int janus_network_string_to_address(janus_network_query_options addr_type, const char *user_value, janus_network_address *result); @@ -224,7 +224,7 @@ int janus_network_string_to_address(janus_network_query_options addr_type, const * \param ifas The list of interfaces to look into (e.g., as returned from getifaddrs) * \param iface The interface name or IP address to look for * \param result Pointer to a valid janus_network_address instance that will contain the result - * \return 0 in case of success, -EINVAL otherwise otherwise + * \return 0 in case of success, -EINVAL otherwise */ int janus_network_lookup_interface(const struct ifaddrs *ifas, const char *iface, janus_network_address *result); @@ -233,7 +233,7 @@ int janus_network_lookup_interface(const struct ifaddrs *ifas, const char *iface * \param addr_type The type of address you're interested in (janus_network_query_options_ipv4, * janus_network_query_options_ipv6 or janus_network_query_options_any_ip) * \param result Pointer to a valid janus_network_address instance that will contain the result - * \return 0 in case of success, -EINVAL otherwise otherwise + * \return 0 in case of success, -EINVAL otherwise */ int janus_network_detect_local_ip(janus_network_query_options addr_type, janus_network_address *result); @@ -242,9 +242,23 @@ int janus_network_detect_local_ip(janus_network_query_options addr_type, janus_n * \note The string is allocated with g_strdup and so needs to be freed by the caller * \param addr_type The type of address you're interested in (janus_network_query_options_ipv4, * janus_network_query_options_ipv6 or janus_network_query_options_any_ip) - * \return 0 in case of success, -EINVAL otherwise otherwise + * \return 0 in case of success, -EINVAL otherwise */ char *janus_network_detect_local_ip_as_string(janus_network_query_options addr_type); ///@} +/** @name Janus helper methods to resolve external addresses + */ +/*! + * \brief Wrapper inet_pton or getaddrinfo to fill a struct sockaddr_storage structure from an address + * \note The method will only do inet_pton if it detects a numeric address, and will perform + * a getaddrinfo otherwise. Notice that, since the request is synchronous, it may have to wait + * for a DNS response to that request. + * \param host The address to resolve + * \param address A pointer to the struct sockaddr_storage to write the result to + * \return 0 in case of success, a negative integer otherwise + */ +int janus_network_resolve_address(const char *host, struct sockaddr_storage *address); +///@} + #endif diff --git a/src/plugins/janus_audiobridge.c b/src/plugins/janus_audiobridge.c index 60a2fa739e..9ae6030d9b 100644 --- a/src/plugins/janus_audiobridge.c +++ b/src/plugins/janus_audiobridge.c @@ -6560,23 +6560,25 @@ static void *janus_audiobridge_handler(void *data) { g_free(participant->plainrtp_media.remote_audio_ip); participant->plainrtp_media.remote_audio_ip = g_strdup(ip); participant->plainrtp_media.remote_audio_rtp_port = port; - struct sockaddr_in audio_server_addr = { 0 }; - memset(&audio_server_addr, 0, sizeof(struct sockaddr_in)); - audio_server_addr.sin_family = AF_INET; - gboolean have_audio_server_ip = TRUE; - if(participant->plainrtp_media.remote_audio_ip && inet_aton(participant->plainrtp_media.remote_audio_ip, &audio_server_addr.sin_addr) == 0) { /* Not a numeric IP... */ - /* Note that gethostbyname() may block waiting for response if it triggers on the wire request.*/ - struct hostent *host = gethostbyname(participant->plainrtp_media.remote_audio_ip); /* ...resolve name */ - if(!host) { - JANUS_LOG(LOG_ERR, "[AudioBridge-%p] Couldn't get host (%s)\n", session, participant->plainrtp_media.remote_audio_ip); - have_audio_server_ip = FALSE; - } else { - audio_server_addr.sin_addr = *(struct in_addr *)host->h_addr_list; + /* Resolve the address */ + gboolean have_audio_server_ip = FALSE; + struct sockaddr_storage audio_server_addr = { 0 }; + if(janus_network_resolve_address(participant->plainrtp_media.remote_audio_ip, &audio_server_addr) < 0) { + JANUS_LOG(LOG_ERR, "[AudioBridge-%p] Couldn't get host '%s'\n", session, + participant->plainrtp_media.remote_audio_ip); + } else { + /* Address resolved */ + have_audio_server_ip = TRUE; + if(audio_server_addr.ss_family == AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&audio_server_addr; + addr6->sin6_port = htons(port); + } else if(audio_server_addr.ss_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)&audio_server_addr; + addr->sin_port = htons(port); } } - audio_server_addr.sin_port = htons(participant->plainrtp_media.remote_audio_rtp_port); if(have_audio_server_ip) { - if(connect(participant->plainrtp_media.audio_rtp_fd, (struct sockaddr *)&audio_server_addr, sizeof(struct sockaddr)) == -1) { + if(connect(participant->plainrtp_media.audio_rtp_fd, (struct sockaddr *)&audio_server_addr, sizeof(audio_server_addr)) == -1) { JANUS_LOG(LOG_ERR, "[AudioBridge-%p] Couldn't connect audio RTP? (%s:%d)\n", session, participant->plainrtp_media.remote_audio_ip, participant->plainrtp_media.remote_audio_rtp_port); JANUS_LOG(LOG_ERR, "[AudioBridge-%p] -- %d (%s)\n", session, errno, g_strerror(errno)); @@ -8712,11 +8714,15 @@ static int janus_audiobridge_plainrtp_allocate_port(janus_audiobridge_plainrtp_m JANUS_LOG(LOG_ERR, "No ports available in range: %u -- %u\n", rtp_range_min, rtp_range_max); break; } + if(rtp_fd == -1) + rtp_fd = socket(AF_INET6, SOCK_DGRAM, 0); if(rtp_fd == -1) { - rtp_fd = socket(AF_INET, SOCK_DGRAM, 0); + JANUS_LOG(LOG_ERR, "Error creating socket... %d (%s)\n", errno, g_strerror(errno)); + break; } - if(rtp_fd == -1) { - JANUS_LOG(LOG_ERR, "Error creating socket...\n"); + int v6only = 0; + if(setsockopt(rtp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) { + JANUS_LOG(LOG_ERR, "setsockopt on socket failed... %d (%s)\n", errno, g_strerror(errno)); break; } int rtp_port = rtp_port_next; @@ -8727,11 +8733,11 @@ static int janus_audiobridge_plainrtp_allocate_port(janus_audiobridge_plainrtp_m rtp_port_next = rtp_range_min; rtp_port_wrap = TRUE; } - struct sockaddr_in rtp_address = { 0 }; - rtp_address.sin_family = AF_INET; - rtp_address.sin_port = htons(rtp_port); - inet_pton(AF_INET, local_ip, &rtp_address.sin_addr.s_addr); - if(bind(rtp_fd, (struct sockaddr *)(&rtp_address), sizeof(struct sockaddr)) < 0) { + struct sockaddr_in6 rtp_address = { 0 }; + rtp_address.sin6_family = AF_INET6; + rtp_address.sin6_port = htons(rtp_port); + rtp_address.sin6_addr = in6addr_any; + if(bind(rtp_fd, (struct sockaddr *)(&rtp_address), sizeof(rtp_address)) < 0) { /* rtp_fd still unbound, reuse it in the next iteration */ } else { media->audio_rtp_fd = rtp_fd; @@ -8758,7 +8764,7 @@ static void *janus_audiobridge_plainrtp_relay_thread(void *data) { /* File descriptors */ socklen_t addrlen; - struct sockaddr_in remote = { 0 }; + struct sockaddr_storage remote = { 0 }; int resfd = 0, bytes = 0, pollerrs = 0; struct pollfd fds[2]; int pipe_fd = participant->plainrtp_media.pipefd[0]; @@ -8835,7 +8841,7 @@ static void *janus_audiobridge_plainrtp_relay_thread(void *data) { } /* Got an RTP packet */ addrlen = sizeof(remote); - bytes = recvfrom(fds[i].fd, buffer, 1500, 0, (struct sockaddr*)&remote, &addrlen); + bytes = recvfrom(fds[i].fd, buffer, 1500, 0, (struct sockaddr *)&remote, &addrlen); if(bytes < 0) { /* Failed to read? */ continue; diff --git a/src/plugins/janus_nosip.c b/src/plugins/janus_nosip.c index 4c18736b40..1f032c3d10 100644 --- a/src/plugins/janus_nosip.c +++ b/src/plugins/janus_nosip.c @@ -1982,11 +1982,11 @@ char *janus_nosip_sdp_manipulate(janus_nosip_session *session, janus_sdp *sdp, g } static int janus_nosip_bind_socket(int fd, int port) { - struct sockaddr_in rtp_address = { 0 }; - rtp_address.sin_family = AF_INET; - rtp_address.sin_port = htons(port); - inet_pton(AF_INET, local_ip, &rtp_address.sin_addr.s_addr); - if(bind(fd, (struct sockaddr *)(&rtp_address), sizeof(struct sockaddr)) < 0) { + struct sockaddr_in6 rtp_address = { 0 }; + rtp_address.sin6_family = AF_INET6; + rtp_address.sin6_port = htons(port); + rtp_address.sin6_addr = in6addr_any; + if(bind(fd, (struct sockaddr *)(&rtp_address), sizeof(rtp_address)) < 0) { JANUS_LOG(LOG_ERR, "Bind failed (port %d)\n", port); return -1; } @@ -2007,7 +2007,12 @@ static int janus_nosip_allocate_port_pair(gboolean video, int fds[2], int ports[ break; } if(rtp_fd == -1) { - rtp_fd = socket(AF_INET, SOCK_DGRAM, 0); + rtp_fd = socket(AF_INET6, SOCK_DGRAM, 0); + int v6only = 0; + if(rtp_fd != -1 && setsockopt(rtp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) { + JANUS_LOG(LOG_WARN, "Error setting v6only to false on RTP socket (error=%s)\n", + g_strerror(errno)); + } /* Set the DSCP value if set in the config file */ if(rtp_fd != -1 && !video && dscp_audio_rtp > 0) { int optval = dscp_audio_rtp << 2; @@ -2026,7 +2031,12 @@ static int janus_nosip_allocate_port_pair(gboolean video, int fds[2], int ports[ } } if(rtcp_fd == -1) { - rtcp_fd = socket(AF_INET, SOCK_DGRAM, 0); + int v6only = 0; + rtcp_fd = socket(AF_INET6, SOCK_DGRAM, 0); + if(rtcp_fd != -1 && setsockopt(rtcp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) { + JANUS_LOG(LOG_WARN, "Error setting v6only to false on RTP socket (error=%s)\n", + g_strerror(errno)); + } } if(rtp_fd == -1 || rtcp_fd == -1) { JANUS_LOG(LOG_ERR, "Error creating %s sockets...\n", video ? "video" : "audio"); @@ -2170,7 +2180,7 @@ static int janus_nosip_allocate_local_ports(janus_nosip_session *session, gboole } /* Helper method to (re)connect RTP/RTCP sockets */ -static void janus_nosip_connect_sockets(janus_nosip_session *session, struct sockaddr_in *audio_server_addr, struct sockaddr_in *video_server_addr) { +static void janus_nosip_connect_sockets(janus_nosip_session *session, struct sockaddr_storage *audio_server_addr, struct sockaddr_storage *video_server_addr) { if(!session || (!audio_server_addr && !video_server_addr)) return; @@ -2180,30 +2190,58 @@ static void janus_nosip_connect_sockets(janus_nosip_session *session, struct soc /* Connect peers (FIXME This pretty much sucks right now) */ if(session->media.remote_audio_rtp_port && audio_server_addr && session->media.audio_rtp_fd != -1) { - audio_server_addr->sin_port = htons(session->media.remote_audio_rtp_port); - if(connect(session->media.audio_rtp_fd, (struct sockaddr *)audio_server_addr, sizeof(struct sockaddr)) == -1) { - JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't connect audio RTP? (%s:%d)\n", session, session->media.remote_audio_ip, session->media.remote_audio_rtp_port); + if(audio_server_addr->ss_family == AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)audio_server_addr; + addr6->sin6_port = htons(session->media.remote_audio_rtp_port); + } else if(audio_server_addr->ss_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)audio_server_addr; + addr->sin_port = htons(session->media.remote_audio_rtp_port); + } + if(connect(session->media.audio_rtp_fd, (struct sockaddr *)audio_server_addr, sizeof(struct sockaddr_storage)) == -1) { + JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't connect audio RTP? (%s:%d)\n", session, + session->media.remote_audio_ip, session->media.remote_audio_rtp_port); JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, errno, g_strerror(errno)); } } if(session->media.remote_audio_rtcp_port && audio_server_addr && session->media.audio_rtcp_fd != -1) { - audio_server_addr->sin_port = htons(session->media.remote_audio_rtcp_port); - if(connect(session->media.audio_rtcp_fd, (struct sockaddr *)audio_server_addr, sizeof(struct sockaddr)) == -1) { - JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't connect audio RTCP? (%s:%d)\n", session, session->media.remote_audio_ip, session->media.remote_audio_rtcp_port); + if(audio_server_addr->ss_family == AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)audio_server_addr; + addr6->sin6_port = htons(session->media.remote_audio_rtcp_port); + } else if(audio_server_addr->ss_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)audio_server_addr; + addr->sin_port = htons(session->media.remote_audio_rtcp_port); + } + if(connect(session->media.audio_rtcp_fd, (struct sockaddr *)audio_server_addr, sizeof(struct sockaddr_storage)) == -1) { + JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't connect audio RTCP? (%s:%d)\n", session, + session->media.remote_audio_ip, session->media.remote_audio_rtcp_port); JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, errno, g_strerror(errno)); } } if(session->media.remote_video_rtp_port && video_server_addr && session->media.video_rtp_fd != -1) { - video_server_addr->sin_port = htons(session->media.remote_video_rtp_port); - if(connect(session->media.video_rtp_fd, (struct sockaddr *)video_server_addr, sizeof(struct sockaddr)) == -1) { - JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't connect video RTP? (%s:%d)\n", session, session->media.remote_video_ip, session->media.remote_video_rtp_port); + if(video_server_addr->ss_family == AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)video_server_addr; + addr6->sin6_port = htons(session->media.remote_video_rtp_port); + } else if(video_server_addr->ss_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)video_server_addr; + addr->sin_port = htons(session->media.remote_video_rtp_port); + } + if(connect(session->media.video_rtp_fd, (struct sockaddr *)video_server_addr, sizeof(struct sockaddr_storage)) == -1) { + JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't connect video RTP? (%s:%d)\n", session, + session->media.remote_video_ip, session->media.remote_video_rtp_port); JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, errno, g_strerror(errno)); } } if(session->media.remote_video_rtcp_port && video_server_addr && session->media.video_rtcp_fd != -1) { - video_server_addr->sin_port = htons(session->media.remote_video_rtcp_port); - if(connect(session->media.video_rtcp_fd, (struct sockaddr *)video_server_addr, sizeof(struct sockaddr)) == -1) { - JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't connect video RTCP? (%s:%d)\n", session, session->media.remote_video_ip, session->media.remote_video_rtcp_port); + if(video_server_addr->ss_family == AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)video_server_addr; + addr6->sin6_port = htons(session->media.remote_video_rtcp_port); + } else if(video_server_addr->ss_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)video_server_addr; + addr->sin_port = htons(session->media.remote_video_rtcp_port); + } + if(connect(session->media.video_rtcp_fd, (struct sockaddr *)video_server_addr, sizeof(struct sockaddr_storage)) == -1) { + JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't connect video RTCP? (%s:%d)\n", session, + session->media.remote_video_ip, session->media.remote_video_rtcp_port); JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, errno, g_strerror(errno)); } } @@ -2295,48 +2333,39 @@ static void *janus_nosip_relay_thread(void *data) { /* Apparently there was a session update, or the loop has just been entered */ session->media.updated = FALSE; - have_audio_server_ip = session->media.remote_audio_ip != NULL; - struct sockaddr_in audio_server_addr = { 0 }; - memset(&audio_server_addr, 0, sizeof(struct sockaddr_in)); - audio_server_addr.sin_family = AF_INET; - - have_video_server_ip = session->media.remote_video_ip != NULL; - struct sockaddr_in video_server_addr = { 0 }; - memset(&video_server_addr, 0, sizeof(struct sockaddr_in)); - video_server_addr.sin_family = AF_INET; - - if(session->media.remote_audio_ip && inet_aton(session->media.remote_audio_ip, &audio_server_addr.sin_addr) == 0) { /* Not a numeric IP... */ - /* Note that gethostbyname() may block waiting for response if it triggers on the wire request.*/ - struct hostent *host = gethostbyname(session->media.remote_audio_ip); /* ...resolve name */ - if(!host) { - JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't get host (%s)\n", session, session->media.remote_audio_ip); - have_audio_server_ip = FALSE; + /* Resolve the addresses, if needed */ + have_audio_server_ip = FALSE; + have_video_server_ip = FALSE; + struct sockaddr_storage audio_server_addr = { 0 }, video_server_addr = { 0 }; + if(session->media.remote_audio_ip && strcmp(session->media.remote_audio_ip, "0.0.0.0")) { + if(janus_network_resolve_address(session->media.remote_audio_ip, &audio_server_addr) < 0) { + JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't resolve audio address '%s'\n", + session, session->media.remote_audio_ip); } else { - audio_server_addr.sin_addr = *(struct in_addr *)host->h_addr_list; + /* Address resolved */ + have_audio_server_ip = TRUE; } } - - if(session->media.remote_video_ip && inet_aton(session->media.remote_video_ip, &video_server_addr.sin_addr) == 0) { /* Not a numeric IP... */ - /* Note that gethostbyname() may block waiting for response if it triggers on the wire request.*/ - struct hostent *host = gethostbyname(session->media.remote_audio_ip); /* ...resolve name */ - if(!host) { - JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't get host (%s)\n", session, session->media.remote_video_ip); - have_video_server_ip = FALSE; + if(session->media.remote_video_ip && strcmp(session->media.remote_video_ip, "0.0.0.0")) { + if(janus_network_resolve_address(session->media.remote_video_ip, &video_server_addr) < 0) { + JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't resolve video address '%s'\n", + session, session->media.remote_video_ip); } else { - video_server_addr.sin_addr = *(struct in_addr *)host->h_addr_list; + /* Address resolved */ + have_video_server_ip = TRUE; } } if(have_audio_server_ip || have_video_server_ip) { janus_nosip_connect_sockets(session, have_audio_server_ip ? &audio_server_addr : NULL, have_video_server_ip ? &video_server_addr : NULL); - } else if (session->media.remote_audio_ip == NULL && session->media.remote_video_ip == NULL) { + } else if (session->media.remote_audio_ip == NULL && session->media.remote_video_ip == NULL) { JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't update session details: both audio and video remote IP addresses are NULL\n", session); } else { - if (session->media.remote_audio_ip) + if(session->media.remote_audio_ip) JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't update session details: audio remote IP address (%s) is invalid\n", session, session->media.remote_audio_ip); - if (session->media.remote_video_ip) + if(session->media.remote_video_ip) JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't update session details: video remote IP address (%s) is invalid\n", session, session->media.remote_video_ip); } diff --git a/src/plugins/janus_sip.c b/src/plugins/janus_sip.c index 0aa1e297b4..047647f0f9 100644 --- a/src/plugins/janus_sip.c +++ b/src/plugins/janus_sip.c @@ -6608,12 +6608,17 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u int attempts = 100; /* FIXME Don't retry forever */ if(session->media.has_audio) { JANUS_LOG(LOG_VERB, "Allocating audio ports:\n"); - struct sockaddr_in audio_rtp_address, audio_rtcp_address; + struct sockaddr_in6 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; if(session->media.audio_rtp_fd == -1) { - session->media.audio_rtp_fd = socket(AF_INET, SOCK_DGRAM, 0); + session->media.audio_rtp_fd = socket(AF_INET6, SOCK_DGRAM, 0); + int v6only = 0; + if(session->media.audio_rtp_fd != -1 && setsockopt(session->media.audio_rtp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) { + JANUS_LOG(LOG_WARN, "Error setting v6only to false on audio RTP socket (error=%s)\n", + g_strerror(errno)); + } /* Set the DSCP value if set in the config file */ if(session->media.audio_rtp_fd != -1 && dscp_audio_rtp > 0) { int optval = dscp_audio_rtp << 2; @@ -6625,7 +6630,12 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u } } if(session->media.audio_rtcp_fd == -1) { - session->media.audio_rtcp_fd = socket(AF_INET, SOCK_DGRAM, 0); + session->media.audio_rtcp_fd = socket(AF_INET6, SOCK_DGRAM, 0); + int v6only = 0; + if(session->media.audio_rtcp_fd != -1 && setsockopt(session->media.audio_rtcp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) { + JANUS_LOG(LOG_WARN, "Error setting v6only to false on audio RTCP socket (error=%s)\n", + g_strerror(errno)); + } } if(session->media.audio_rtp_fd == -1 || session->media.audio_rtcp_fd == -1) { JANUS_LOG(LOG_ERR, "Error creating audio sockets...\n"); @@ -6634,10 +6644,10 @@ 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 */ - audio_rtp_address.sin_family = AF_INET; - audio_rtp_address.sin_port = htons(rtp_port); - inet_pton(AF_INET, (local_media_ip ? local_media_ip : local_ip), &audio_rtp_address.sin_addr.s_addr); - if(bind(session->media.audio_rtp_fd, (struct sockaddr *)(&audio_rtp_address), sizeof(struct sockaddr)) < 0) { + audio_rtp_address.sin6_family = AF_INET6; + audio_rtp_address.sin6_port = htons(rtp_port); + audio_rtp_address.sin6_addr = in6addr_any; + 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); close(session->media.audio_rtp_fd); session->media.audio_rtp_fd = -1; @@ -6646,10 +6656,10 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u } 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); int rtcp_port = rtp_port+1; - audio_rtcp_address.sin_family = AF_INET; - audio_rtcp_address.sin_port = htons(rtcp_port); - inet_pton(AF_INET, (local_media_ip ? local_media_ip : local_ip), &audio_rtcp_address.sin_addr.s_addr); - if(bind(session->media.audio_rtcp_fd, (struct sockaddr *)(&audio_rtcp_address), sizeof(struct sockaddr)) < 0) { + audio_rtcp_address.sin6_family = AF_INET6; + audio_rtcp_address.sin6_port = htons(rtcp_port); + audio_rtcp_address.sin6_addr = in6addr_any; + 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); /* RTP socket is not valid anymore, reset it */ close(session->media.audio_rtp_fd); @@ -6666,12 +6676,17 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u } if(session->media.has_video) { JANUS_LOG(LOG_VERB, "Allocating video ports:\n"); - struct sockaddr_in video_rtp_address, video_rtcp_address; + struct sockaddr_in6 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; if(session->media.video_rtp_fd == -1) { session->media.video_rtp_fd = socket(AF_INET, SOCK_DGRAM, 0); + int v6only = 0; + if(session->media.video_rtp_fd != -1 && setsockopt(session->media.video_rtp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) { + JANUS_LOG(LOG_WARN, "Error setting v6only to false on video RTP socket (error=%s)\n", + g_strerror(errno)); + } /* Set the DSCP value if set in the config file */ if(session->media.video_rtp_fd != -1 && dscp_video_rtp > 0) { int optval = dscp_video_rtp << 2; @@ -6684,6 +6699,11 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u } if(session->media.video_rtcp_fd == -1) { session->media.video_rtcp_fd = socket(AF_INET, SOCK_DGRAM, 0); + int v6only = 0; + if(session->media.video_rtcp_fd != -1 && setsockopt(session->media.video_rtcp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) { + JANUS_LOG(LOG_WARN, "Error setting v6only to false on video RTCP socket (error=%s)\n", + g_strerror(errno)); + } } if(session->media.video_rtp_fd == -1 || session->media.video_rtcp_fd == -1) { JANUS_LOG(LOG_ERR, "Error creating video sockets...\n"); @@ -6692,10 +6712,10 @@ 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 */ - video_rtp_address.sin_family = AF_INET; - video_rtp_address.sin_port = htons(rtp_port); - inet_pton(AF_INET, (local_media_ip ? local_media_ip : local_ip), &video_rtp_address.sin_addr.s_addr); - if(bind(session->media.video_rtp_fd, (struct sockaddr *)(&video_rtp_address), sizeof(struct sockaddr)) < 0) { + video_rtp_address.sin6_family = AF_INET6; + video_rtp_address.sin6_port = htons(rtp_port); + video_rtp_address.sin6_addr = in6addr_any; + 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); close(session->media.video_rtp_fd); session->media.video_rtp_fd = -1; @@ -6704,10 +6724,10 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u } 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); int rtcp_port = rtp_port+1; - video_rtcp_address.sin_family = AF_INET; - video_rtcp_address.sin_port = htons(rtcp_port); - inet_pton(AF_INET, (local_media_ip ? local_media_ip : local_ip), &video_rtcp_address.sin_addr.s_addr); - if(bind(session->media.video_rtcp_fd, (struct sockaddr *)(&video_rtcp_address), sizeof(struct sockaddr)) < 0) { + video_rtcp_address.sin6_family = AF_INET; + video_rtcp_address.sin6_port = htons(rtcp_port); + video_rtcp_address.sin6_addr = in6addr_any; + 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); /* RTP socket is not valid anymore, reset it */ close(session->media.video_rtp_fd); @@ -6730,36 +6750,64 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u } /* Helper method to (re)connect RTP/RTCP sockets */ -static void janus_sip_connect_sockets(janus_sip_session *session, struct sockaddr_in *audio_server_addr, struct sockaddr_in *video_server_addr) { +static void janus_sip_connect_sockets(janus_sip_session *session, struct sockaddr_storage *audio_server_addr, struct sockaddr_storage *video_server_addr) { if(!session || (!audio_server_addr && !video_server_addr)) return; /* Connect peers (FIXME This pretty much sucks right now) */ if(session->media.remote_audio_rtp_port && audio_server_addr && session->media.audio_rtp_fd != -1) { - audio_server_addr->sin_port = htons(session->media.remote_audio_rtp_port); - if(connect(session->media.audio_rtp_fd, (struct sockaddr *)audio_server_addr, sizeof(struct sockaddr)) == -1) { - JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect audio RTP? (%s:%d)\n", session->account.username, session->media.remote_audio_ip, session->media.remote_audio_rtp_port); + if(audio_server_addr->ss_family == AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)audio_server_addr; + addr6->sin6_port = htons(session->media.remote_audio_rtp_port); + } else if(audio_server_addr->ss_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)audio_server_addr; + addr->sin_port = htons(session->media.remote_audio_rtp_port); + } + if(connect(session->media.audio_rtp_fd, (struct sockaddr *)audio_server_addr, sizeof(struct sockaddr_storage)) == -1) { + JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect audio RTP? (%s:%d)\n", session->account.username, + session->media.remote_audio_ip, session->media.remote_audio_rtp_port); JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, errno, g_strerror(errno)); } } if(session->media.remote_audio_rtcp_port && audio_server_addr && session->media.audio_rtcp_fd != -1) { - audio_server_addr->sin_port = htons(session->media.remote_audio_rtcp_port); - if(connect(session->media.audio_rtcp_fd, (struct sockaddr *)audio_server_addr, sizeof(struct sockaddr)) == -1) { - JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect audio RTCP? (%s:%d)\n", session->account.username, session->media.remote_audio_ip, session->media.remote_audio_rtcp_port); + if(audio_server_addr->ss_family == AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)audio_server_addr; + addr6->sin6_port = htons(session->media.remote_audio_rtcp_port); + } else if(audio_server_addr->ss_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)audio_server_addr; + addr->sin_port = htons(session->media.remote_audio_rtcp_port); + } + if(connect(session->media.audio_rtcp_fd, (struct sockaddr *)audio_server_addr, sizeof(struct sockaddr_storage)) == -1) { + JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect audio RTCP? (%s:%d)\n", session->account.username, + session->media.remote_audio_ip, session->media.remote_audio_rtcp_port); JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, errno, g_strerror(errno)); } } if(session->media.remote_video_rtp_port && video_server_addr && session->media.video_rtp_fd != -1) { - video_server_addr->sin_port = htons(session->media.remote_video_rtp_port); - if(connect(session->media.video_rtp_fd, (struct sockaddr *)video_server_addr, sizeof(struct sockaddr)) == -1) { - JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect video RTP? (%s:%d)\n", session->account.username, session->media.remote_video_ip, session->media.remote_video_rtp_port); + if(video_server_addr->ss_family == AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)video_server_addr; + addr6->sin6_port = htons(session->media.remote_video_rtp_port); + } else if(video_server_addr->ss_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)video_server_addr; + addr->sin_port = htons(session->media.remote_video_rtp_port); + } + if(connect(session->media.video_rtp_fd, (struct sockaddr *)video_server_addr, sizeof(struct sockaddr_storage)) == -1) { + JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect video RTP? (%s:%d)\n", session->account.username, + session->media.remote_video_ip, session->media.remote_video_rtp_port); JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, errno, g_strerror(errno)); } } if(session->media.remote_video_rtcp_port && video_server_addr && session->media.video_rtcp_fd != -1) { - video_server_addr->sin_port = htons(session->media.remote_video_rtcp_port); - if(connect(session->media.video_rtcp_fd, (struct sockaddr *)video_server_addr, sizeof(struct sockaddr)) == -1) { - JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect video RTCP? (%s:%d)\n", session->account.username, session->media.remote_video_ip, session->media.remote_video_rtcp_port); + if(video_server_addr->ss_family == AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)video_server_addr; + addr6->sin6_port = htons(session->media.remote_video_rtcp_port); + } else if(video_server_addr->ss_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)video_server_addr; + addr->sin_port = htons(session->media.remote_video_rtcp_port); + } + if(connect(session->media.video_rtcp_fd, (struct sockaddr *)video_server_addr, sizeof(struct sockaddr_storage)) == -1) { + JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect video RTCP? (%s:%d)\n", session->account.username, + session->media.remote_video_ip, session->media.remote_video_rtcp_port); JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, errno, g_strerror(errno)); } } @@ -6862,42 +6910,33 @@ static void *janus_sip_relay_thread(void *data) { /* Apparently there was a session update, or the loop has just been entered */ session->media.updated = FALSE; - have_audio_server_ip = session->media.remote_audio_ip != NULL; - struct sockaddr_in audio_server_addr; - memset(&audio_server_addr, 0, sizeof(struct sockaddr_in)); - audio_server_addr.sin_family = AF_INET; - - have_video_server_ip = session->media.remote_video_ip != NULL; - struct sockaddr_in video_server_addr; - memset(&video_server_addr, 0, sizeof(struct sockaddr_in)); - video_server_addr.sin_family = AF_INET; - - if(session->media.remote_audio_ip && inet_aton(session->media.remote_audio_ip, &audio_server_addr.sin_addr) == 0) { /* Not a numeric IP... */ - /* Note that gethostbyname() may block waiting for response if it triggers on the wire request.*/ - struct hostent *host = gethostbyname(session->media.remote_audio_ip); /* ...resolve name */ - if(!host) { - JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't get host (%s)\n", session->account.username, session->media.remote_audio_ip); - have_audio_server_ip = FALSE; + /* Resolve the addresses, if needed */ + have_audio_server_ip = FALSE; + have_video_server_ip = FALSE; + struct sockaddr_storage audio_server_addr = { 0 }, video_server_addr = { 0 }; + if(session->media.remote_audio_ip && strcmp(session->media.remote_audio_ip, "0.0.0.0")) { + if(janus_network_resolve_address(session->media.remote_audio_ip, &audio_server_addr) < 0) { + JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't resolve audio address '%s'\n", + session->account.username, session->media.remote_audio_ip); } else { - audio_server_addr.sin_addr = *(struct in_addr *)host->h_addr_list; + /* Address resolved */ + have_audio_server_ip = TRUE; } } - - if(session->media.remote_video_ip && inet_aton(session->media.remote_video_ip, &video_server_addr.sin_addr) == 0) { /* Not a numeric IP... */ - /* Note that gethostbyname() may block waiting for response if it triggers on the wire request.*/ - struct hostent *host = gethostbyname(session->media.remote_video_ip); /* ...resolve name */ - if(!host) { - JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't get host (%s)\n", session->account.username, session->media.remote_video_ip); - have_video_server_ip = FALSE; + if(session->media.remote_video_ip && strcmp(session->media.remote_video_ip, "0.0.0.0")) { + if(janus_network_resolve_address(session->media.remote_video_ip, &video_server_addr) < 0) { + JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't resolve video address '%s'\n", + session->account.username, session->media.remote_video_ip); } else { - video_server_addr.sin_addr = *(struct in_addr *)host->h_addr_list; + /* Address resolved */ + have_video_server_ip = TRUE; } } if(have_audio_server_ip || have_video_server_ip) { janus_sip_connect_sockets(session, have_audio_server_ip ? &audio_server_addr : NULL, have_video_server_ip ? &video_server_addr : NULL); - } else if(session->media.remote_audio_ip == NULL && session->media.remote_video_ip == NULL) { + } else if(session->media.remote_audio_ip == NULL && session->media.remote_video_ip == NULL) { JANUS_LOG(LOG_ERR, "[SIP-%p] Couldn't update session details: both audio and video remote IP addresses are NULL\n", session->account.username); } else { diff --git a/src/sdp-utils.c b/src/sdp-utils.c index ba09b01196..d546d40661 100644 --- a/src/sdp-utils.c +++ b/src/sdp-utils.c @@ -1138,6 +1138,8 @@ char *janus_sdp_write(janus_sdp *imported) { janus_strlcat_fast(sdp, buffer, sdplen, &offset); /* c= */ if(imported->c_addr != NULL) { + if(imported->c_ipv4 && imported->c_addr && strstr(imported->c_addr, ":")) + imported->c_ipv4 = FALSE; g_snprintf(buffer, sizeof(buffer), "c=IN %s %s\r\n", imported->c_ipv4 ? "IP4" : "IP6", imported->c_addr); janus_strlcat_fast(sdp, buffer, sdplen, &offset);