diff --git a/core/AmRtpStream.cpp b/core/AmRtpStream.cpp index 4acd4427..138fa1ab 100644 --- a/core/AmRtpStream.cpp +++ b/core/AmRtpStream.cpp @@ -368,8 +368,12 @@ void AmRtpStream::setRAddr(const string& addr, unsigned short port) sa.sin_family = AF_INET; sa.sin_port = htons(port); - if(!inet_aton(addr.c_str(),&sa.sin_addr)){ - ERROR("address not valid (host: %s)\n",addr.c_str()); + /* inet_aton only supports dot-notation IP address strings... but an RFC + * 4566 unicast-address, as found in c=, can be an FQDN (or other!). + * We need to do more sophisticated parsing -- hence p_s_i_f_n(). + */ + if (!populate_sockaddr_in_from_name(addr, &sa)) { + ERROR("Address not valid (host: %s).\n", addr.c_str()); throw string("invalid address"); } diff --git a/core/AmUtils.cpp b/core/AmUtils.cpp index 2e46e00a..8bd93d45 100644 --- a/core/AmUtils.cpp +++ b/core/AmUtils.cpp @@ -398,6 +398,51 @@ string get_ip_from_name(const string& name) return get_addr_str(a); } +/* Takes a string representation of an IP address, or an FQDN, + * and populates the provided struct sockaddr_in (similar to + * inet_aton). + * Returns the hostent for the input, or NULL on failure. + * Almost certainly won't work with IPv6 addresses. + */ +int populate_sockaddr_in_from_name(const string& name, struct sockaddr_in *sa) { + + if (NULL == sa) { + return 0; + } + + int res = 0; + struct addrinfo hints; + struct addrinfo *result, *rp; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; // AF_UNSPEC for IPv4 or IPv6 + hints.ai_socktype = SOCK_DGRAM; // Datagram socket. + hints.ai_flags = AI_ADDRCONFIG; + hints.ai_protocol = 0; // Any protocol. + + int s = getaddrinfo(name.c_str(), NULL, &hints, &result); + if (s != 0) { + WARN("getaddrinfo failed on %s: %s.\n", + name.c_str(), + gai_strerror(s)); + return res; + } + + for (rp = result; rp != NULL; rp = rp->ai_next) { + if ((rp->ai_addrlen != sizeof(struct sockaddr_in)) || // Should not happen. + (rp->ai_socktype != SOCK_DGRAM) || + (rp->ai_family != AF_INET)) // TODO: Won't behave with IPv6. + continue; + memcpy(&(sa->sin_addr), + &((struct sockaddr_in *)rp->ai_addr)->sin_addr, + sizeof(sa->sin_addr)); + res = 1; + break; + } + + freeaddrinfo(result); + return res; +} + string uri_from_name_addr(const string& name_addr) { string uri = name_addr; diff --git a/core/AmUtils.h b/core/AmUtils.h index ebca5312..e6cd0931 100644 --- a/core/AmUtils.h +++ b/core/AmUtils.h @@ -221,6 +221,14 @@ string get_addr_str(struct in_addr in); string uri_from_name_addr(const string& name_addr); string get_ip_from_name(const string& name); +/* Generalized hostname/IP address handling -- wherever you would use + * inet_aton(addr.c_str(), &sa.sin_addr) + * instead use + * populate_sockaddr_in_from_name(addr, &sa) + */ +int populate_sockaddr_in_from_name(const string& name, + struct sockaddr_in *sa); + #ifdef SUPPORT_IPV6 int inet_aton_v6(const char* name, struct sockaddr_storage* ss); void set_port_v6(struct sockaddr_storage* ss, short port);