diff --git a/AUTHORS.txt b/AUTHORS.txt index d036b8d20..0c3e2eb2b 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -26,4 +26,4 @@ CONTRIBUTORS ordered by first contribution. * lovecat "Bug fixed" * panda1986<542638787@qq.com> "Bug fixed" * YueHonghui "Bug fixed" - +* ThomasDreibholz "IPv6 support" diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 199903694..6884c0789 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3607,7 +3607,7 @@ srs_error_t SrsConfig::check_normal_config() return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "invalid stats.network=%d", get_stats_network()); } if (true) { - vector ips = srs_get_local_ipv4_ips(); + vector ips = srs_get_local_ips(); int index = get_stats_network(); if (index >= (int)ips.size()) { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "invalid stats.network=%d of %d", diff --git a/trunk/src/app/srs_app_heartbeat.cpp b/trunk/src/app/srs_app_heartbeat.cpp index 4cc125850..9a0f28edc 100644 --- a/trunk/src/app/srs_app_heartbeat.cpp +++ b/trunk/src/app/srs_app_heartbeat.cpp @@ -68,7 +68,7 @@ srs_error_t SrsHttpHeartbeat::do_heartbeat() std::string ip = ""; std::string device_id = _srs_config->get_heartbeat_device_id(); - vector& ips = srs_get_local_ipv4_ips(); + vector& ips = srs_get_local_ips(); if (!ips.empty()) { ip = ips[_srs_config->get_stats_network() % (int)ips.size()]; } diff --git a/trunk/src/app/srs_app_listener.cpp b/trunk/src/app/srs_app_listener.cpp index 72c13c21d..23ffe5c12 100755 --- a/trunk/src/app/srs_app_listener.cpp +++ b/trunk/src/app/srs_app_listener.cpp @@ -31,6 +31,7 @@ #include #include #include +#include using namespace std; #include @@ -111,20 +112,31 @@ srs_error_t SrsUdpListener::listen() { srs_error_t err = srs_success; - if ((_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - return srs_error_new(ERROR_SOCKET_CREATE, "create socket"); + char port_string[8]; + snprintf(port_string, sizeof(port_string), "%d", port); + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICHOST; + addrinfo* result = NULL; + if(getaddrinfo(ip.c_str(), port_string, (const addrinfo*)&hints, &result) != 0) { + return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address"); } + if ((_fd = socket(result->ai_family, result->ai_socktype, result->ai_protocol)) == -1) { + freeaddrinfo(result); + return srs_error_new(ERROR_SOCKET_CREATE, "create linux socket error. ip=%s, port=%d", ip.c_str(), port); + } + srs_fd_close_exec(_fd); srs_socket_reuse_addr(_fd); - sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = inet_addr(ip.c_str()); - if (bind(_fd, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { - return srs_error_new(ERROR_SOCKET_BIND, "bind socket"); + if (bind(_fd, result->ai_addr, result->ai_addrlen) == -1) { + freeaddrinfo(result); + return srs_error_new(ERROR_SOCKET_BIND, "bind socket error. ep=%s:%d", ip.c_str(), port);; } + freeaddrinfo(result); if ((_stfd = srs_netfd_open_socket(_fd)) == NULL){ return srs_error_new(ERROR_ST_OPEN_SOCKET, "st open socket"); @@ -148,16 +160,15 @@ srs_error_t SrsUdpListener::cycle() return srs_error_wrap(err, "udp listener"); } - // TODO: FIXME: support ipv6, @see man 7 ipv6 - sockaddr_in from; - int nb_from = sizeof(sockaddr_in); + sockaddr_storage from; + int nb_from = sizeof(from); int nread = 0; if ((nread = srs_recvfrom(_stfd, buf, nb_buf, (sockaddr*)&from, &nb_from, SRS_UTIME_NO_TIMEOUT)) <= 0) { return srs_error_new(ERROR_SOCKET_READ, "udp read, nread=%d", nread); } - if ((err = handler->on_udp_packet(&from, buf, nread)) != srs_success) { + if ((err = handler->on_udp_packet((const sockaddr*)&from, nb_from, buf, nread)) != srs_success) { return srs_error_wrap(err, "handle packet %d bytes", nread); } @@ -197,21 +208,32 @@ srs_error_t SrsTcpListener::listen() { srs_error_t err = srs_success; - if ((_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - return srs_error_new(ERROR_SOCKET_CREATE, "create socket"); + char port_string[8]; + snprintf(port_string, sizeof(port_string), "%d", port); + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + addrinfo* result = NULL; + if(getaddrinfo(ip.c_str(), port_string, (const addrinfo*)&hints, &result) != 0) { + return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address"); } + if ((_fd = socket(result->ai_family, result->ai_socktype, result->ai_protocol)) == -1) { + freeaddrinfo(result); + return srs_error_new(ERROR_SOCKET_CREATE, "create linux socket error. ip=%s, port=%d", ip.c_str(), port); + } + srs_fd_close_exec(_fd); srs_socket_reuse_addr(_fd); - sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = inet_addr(ip.c_str()); - if (bind(_fd, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { - return srs_error_new(ERROR_SOCKET_BIND, "bind socket"); + if (bind(_fd, result->ai_addr, result->ai_addrlen) == -1) { + freeaddrinfo(result); + return srs_error_new(ERROR_SOCKET_BIND, "bind socket error. ep=%s:%d", ip.c_str(), port);; } - + freeaddrinfo(result); + if (::listen(_fd, SERVER_LISTEN_BACKLOG) == -1) { return srs_error_new(ERROR_SOCKET_LISTEN, "listen socket"); } diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp index 7d0c75389..d2c6aa5cd 100644 --- a/trunk/src/app/srs_app_listener.hpp +++ b/trunk/src/app/srs_app_listener.hpp @@ -31,7 +31,7 @@ #include #include -struct sockaddr_in; +struct sockaddr; /** * the udp packet handler. @@ -57,7 +57,7 @@ public: * @param nb_buf, the size of udp packet bytes. * @remark user should never use the buf, for it's a shared memory bytes. */ - virtual srs_error_t on_udp_packet(sockaddr_in* from, char* buf, int nb_buf) = 0; + virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) = 0; }; /** diff --git a/trunk/src/app/srs_app_mpegts_udp.cpp b/trunk/src/app/srs_app_mpegts_udp.cpp index 532271f4c..a938a4cf2 100644 --- a/trunk/src/app/srs_app_mpegts_udp.cpp +++ b/trunk/src/app/srs_app_mpegts_udp.cpp @@ -29,6 +29,7 @@ #include #include #include +#include using namespace std; #include @@ -155,10 +156,18 @@ SrsMpegtsOverUdp::~SrsMpegtsOverUdp() srs_freep(pprint); } -srs_error_t SrsMpegtsOverUdp::on_udp_packet(sockaddr_in* from, char* buf, int nb_buf) +srs_error_t SrsMpegtsOverUdp::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) { - std::string peer_ip = inet_ntoa(from->sin_addr); - int peer_port = ntohs(from->sin_port); + char address_string[64]; + char port_string[16]; + if(getnameinfo(from, fromlen, + (char*)&address_string, sizeof(address_string), + (char*)&port_string, sizeof(port_string), + NI_NUMERICHOST|NI_NUMERICSERV) != 0) { + return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address"); + } + std::string peer_ip = std::string(address_string); + int peer_port = atoi(port_string); // append to buffer. buffer->append(buf, nb_buf); diff --git a/trunk/src/app/srs_app_mpegts_udp.hpp b/trunk/src/app/srs_app_mpegts_udp.hpp index 819e50631..d00a711da 100644 --- a/trunk/src/app/srs_app_mpegts_udp.hpp +++ b/trunk/src/app/srs_app_mpegts_udp.hpp @@ -28,7 +28,7 @@ #ifdef SRS_AUTO_STREAM_CASTER -struct sockaddr_in; +struct sockaddr; #include #include @@ -100,7 +100,7 @@ public: virtual ~SrsMpegtsOverUdp(); // interface ISrsUdpHandler public: - virtual srs_error_t on_udp_packet(sockaddr_in* from, char* buf, int nb_buf); + virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); private: virtual srs_error_t on_udp_bytes(std::string host, int port, char* buf, int nb_buf); // interface ISrsTsHandler diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index 98b1ecda6..cf7603b65 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -87,7 +87,7 @@ SrsSimpleRtmpClient::~SrsSimpleRtmpClient() srs_error_t SrsSimpleRtmpClient::connect_app() { - std::vector ips = srs_get_local_ipv4_ips(); + std::vector ips = srs_get_local_ips(); assert(_srs_config->get_stats_network() < (int)ips.size()); std::string local_ip = ips[_srs_config->get_stats_network()]; diff --git a/trunk/src/app/srs_app_rtsp.cpp b/trunk/src/app/srs_app_rtsp.cpp index e7376e53b..874821b64 100644 --- a/trunk/src/app/srs_app_rtsp.cpp +++ b/trunk/src/app/srs_app_rtsp.cpp @@ -54,7 +54,7 @@ SrsRtpConn::SrsRtpConn(SrsRtspConn* r, int p, int sid) _port = p; stream_id = sid; // TODO: support listen at <[ip:]port> - listener = new SrsUdpListener(this, "0.0.0.0", p); + listener = new SrsUdpListener(this, (srs_check_ipv6() ? "::" : "0.0.0.0"), p); cache = new SrsRtpPacket(); pprint = SrsPithyPrint::create_caster(); } @@ -76,7 +76,7 @@ srs_error_t SrsRtpConn::listen() return listener->listen(); } -srs_error_t SrsRtpConn::on_udp_packet(sockaddr_in* from, char* buf, int nb_buf) +srs_error_t SrsRtpConn::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_rtsp.hpp b/trunk/src/app/srs_app_rtsp.hpp index aca5a2a56..616f371de 100644 --- a/trunk/src/app/srs_app_rtsp.hpp +++ b/trunk/src/app/srs_app_rtsp.hpp @@ -74,7 +74,7 @@ public: virtual srs_error_t listen(); // interface ISrsUdpHandler public: - virtual srs_error_t on_udp_packet(sockaddr_in* from, char* buf, int nb_buf); + virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); }; /** diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 6416dd751..6b206e0ce 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -1137,7 +1137,7 @@ srs_error_t SrsServer::listen_stream_caster() } // TODO: support listen at <[ip:]port> - if ((err = listener->listen("0.0.0.0", port)) != srs_success) { + if ((err = listener->listen( (srs_check_ipv6() ? "::" : "0.0.0.0"), port)) != srs_success) { return srs_error_wrap(err, "listen at %d", port); } } diff --git a/trunk/src/app/srs_app_utility.cpp b/trunk/src/app/srs_app_utility.cpp index cc23cff02..15d29c759 100644 --- a/trunk/src/app/srs_app_utility.cpp +++ b/trunk/src/app/srs_app_utility.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #ifdef SRS_OSX #include @@ -1103,76 +1104,84 @@ void srs_update_rtmp_server(int nb_conn, SrsKbps* kbps) } } +int srs_check_ipv6() +{ + int sd = socket(AF_INET6, SOCK_DGRAM, 0); + if(sd >= 0) { + close(sd); + return 1; + } + return 0; +} + string srs_get_local_ip(int fd) { - std::string ip; - // discovery client information - sockaddr_in addr; + sockaddr_storage addr; socklen_t addrlen = sizeof(addr); if (getsockname(fd, (sockaddr*)&addr, &addrlen) == -1) { - return ip; + return ""; } srs_verbose("get local ip success."); - - // ip v4 or v6 - char buf[INET6_ADDRSTRLEN]; - memset(buf, 0, sizeof(buf)); - - if ((inet_ntop(addr.sin_family, &addr.sin_addr, buf, sizeof(buf))) == NULL) { - return ip; + + char address_string[64]; + const int success = getnameinfo((const sockaddr*)&addr, addrlen, + (char*)&address_string, sizeof(address_string), + NULL, 0, + NI_NUMERICHOST); + if(success != 0) { + return ""; } - - ip = buf; - - srs_verbose("get local ip of client ip=%s, fd=%d", buf, fd); - - return ip; + + srs_verbose("get local ip of client ip=%s, fd=%d", address_string, fd); + return std::string(address_string); } int srs_get_local_port(int fd) { // discovery client information - sockaddr_in addr; + sockaddr_storage addr; socklen_t addrlen = sizeof(addr); if (getsockname(fd, (sockaddr*)&addr, &addrlen) == -1) { return 0; } srs_verbose("get local ip success."); - - int port = ntohs(addr.sin_port); - - srs_verbose("get local ip of client port=%s, fd=%d", port, fd); - + + int port = 0; + switch(addr.ss_family) { + case AF_INET: + port = ntohs(((sockaddr_in*)&addr)->sin_port); + break; + case AF_INET6: + port = ntohs(((sockaddr_in6*)&addr)->sin6_port); + break; + } + + srs_verbose("get local port of client port=%s, fd=%d", port, fd); return port; } string srs_get_peer_ip(int fd) { - std::string ip; - // discovery client information - sockaddr_in addr; + sockaddr_storage addr; socklen_t addrlen = sizeof(addr); - if (getpeername(fd, (sockaddr*)&addr, &addrlen) == -1) { - return ip; + if (getsockname(fd, (sockaddr*)&addr, &addrlen) == -1) { + return ""; } - srs_verbose("get peer name success."); - - // ip v4 or v6 - char buf[INET6_ADDRSTRLEN]; - memset(buf, 0, sizeof(buf)); - - if ((inet_ntop(addr.sin_family, &addr.sin_addr, buf, sizeof(buf))) == NULL) { - return ip; + srs_verbose("get peer ip success."); + + char address_string[64]; + const int success = getnameinfo((const sockaddr*)&addr, addrlen, + (char*)&address_string, sizeof(address_string), + NULL, 0, + NI_NUMERICHOST); + if(success != 0) { + return ""; } - srs_verbose("get peer ip of client ip=%s, fd=%d", buf, fd); - - ip = buf; - - srs_verbose("get peer ip success. ip=%s, fd=%d", ip.c_str(), fd); - - return ip; + + srs_verbose("get peer ip of client ip=%s, fd=%d", address_string, fd); + return std::string(address_string); } bool srs_is_digit_number(const string& str) diff --git a/trunk/src/app/srs_app_utility.hpp b/trunk/src/app/srs_app_utility.hpp index 611be7a8c..71cd46603 100644 --- a/trunk/src/app/srs_app_utility.hpp +++ b/trunk/src/app/srs_app_utility.hpp @@ -643,6 +643,9 @@ extern SrsNetworkRtmpServer* srs_get_network_rtmp_server(); // the deamon st-thread will update it. extern void srs_update_rtmp_server(int nb_conn, SrsKbps* kbps); +// check for IPv6 support +extern int srs_check_ipv6(); + // get local or peer ip. // where local ip is the server ip which client connected. extern std::string srs_get_local_ip(int fd); diff --git a/trunk/src/kernel/srs_kernel_utility.cpp b/trunk/src/kernel/srs_kernel_utility.cpp index 3d5bb364b..199176b92 100644 --- a/trunk/src/kernel/srs_kernel_utility.cpp +++ b/trunk/src/kernel/srs_kernel_utility.cpp @@ -154,50 +154,79 @@ int64_t srs_update_system_time_ms() return _srs_system_time_us_cache / 1000; } -string srs_dns_resolve(string host) +string srs_dns_resolve(string host, int& family) { - if (inet_addr(host.c_str()) != INADDR_NONE) { - return host; - } - - hostent* answer = gethostbyname(host.c_str()); - if (answer == NULL) { + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + addrinfo* result = NULL; + if(getaddrinfo(host.c_str(), NULL, NULL, &result) != 0) { return ""; } - char ipv4[16]; - memset(ipv4, 0, sizeof(ipv4)); - - // covert the first entry to ip. - if (answer->h_length > 0) { - inet_ntop(AF_INET, answer->h_addr_list[0], ipv4, sizeof(ipv4)); + char address_string[64]; + const int success = getnameinfo(result->ai_addr, result->ai_addrlen, + (char*)&address_string, sizeof(address_string), + NULL, 0, + NI_NUMERICHOST); + freeaddrinfo(result); + + if(success) { + family = result->ai_family; + return string(address_string); } - - return ipv4; + return ""; } void srs_parse_hostport(const string& hostport, string& host, int& port) { - size_t pos = hostport.find(":"); + const size_t pos = hostport.rfind(":"); // Look for ":" from the end, to work with IPv6. if (pos != std::string::npos) { - string p = hostport.substr(pos + 1); - host = hostport.substr(0, pos); + const string p = hostport.substr(pos + 1); + if ((pos >= 1) && + (hostport[0] == '[') && + (hostport[pos - 1] == ']')) { + // Handle IPv6 in RFC 2732 format, e.g. [3ffe:dead:beef::1]:1935 + host = hostport.substr(1, pos - 2); + } + else { + // Handle IP address + host = hostport.substr(0, pos); + } port = ::atoi(p.c_str()); } else { host = hostport; } } +static int check_ipv6() +{ + int sd = socket(AF_INET6, SOCK_DGRAM, 0); + if(sd >= 0) { + close(sd); + return 1; + } + return 0; +} + void srs_parse_endpoint(string hostport, string& ip, int& port) { - ip = "0.0.0.0"; - - size_t pos = string::npos; - if ((pos = hostport.find(":")) != string::npos) { - ip = hostport.substr(0, pos); - string sport = hostport.substr(pos + 1); + const size_t pos = hostport.rfind(":"); // Look for ":" from the end, to work with IPv6. + if (pos != std::string::npos) { + if ((pos >= 1) && + (hostport[0] == '[') && + (hostport[pos - 1] == ']')) { + // Handle IPv6 in RFC 2732 format, e.g. [3ffe:dead:beef::1]:1935 + ip = hostport.substr(1, pos - 2); + } + else { + // Handle IP address + ip = hostport.substr(0, pos); + } + const string sport = hostport.substr(pos + 1); port = ::atoi(sport.c_str()); } else { + ip = check_ipv6() ? "::" : "0.0.0.0"; port = ::atoi(hostport.c_str()); } } @@ -317,7 +346,7 @@ string srs_string_remove(string str, string remove_chars) bool srs_string_ends_with(string str, string flag) { - ssize_t pos = str.rfind(flag); + const size_t pos = str.rfind(flag); return (pos != string::npos) && (pos == str.length() - flag.length()); } diff --git a/trunk/src/kernel/srs_kernel_utility.hpp b/trunk/src/kernel/srs_kernel_utility.hpp index b021517c4..c5e936837 100644 --- a/trunk/src/kernel/srs_kernel_utility.hpp +++ b/trunk/src/kernel/srs_kernel_utility.hpp @@ -47,7 +47,7 @@ extern int64_t srs_get_system_startup_time_ms(); extern int64_t srs_update_system_time_ms(); // dns resolve utility, return the resolved ip address. -extern std::string srs_dns_resolve(std::string host); +extern std::string srs_dns_resolve(std::string host, int& family); // split the host:port to host and port. // @remark the hostport format in , where port is optional. diff --git a/trunk/src/libs/srs_lib_simple_socket.cpp b/trunk/src/libs/srs_lib_simple_socket.cpp index 6ad58b27c..bfd1566e5 100644 --- a/trunk/src/libs/srs_lib_simple_socket.cpp +++ b/trunk/src/libs/srs_lib_simple_socket.cpp @@ -64,6 +64,8 @@ #include #include +#include +#include #include #include @@ -73,6 +75,7 @@ struct SrsBlockSyncSocket { SOCKET fd; + int family; int64_t rbytes; int64_t sbytes; // The send/recv timeout in ms. @@ -105,27 +108,40 @@ void srs_hijack_io_destroy(srs_hijack_io_t ctx) int srs_hijack_io_create_socket(srs_hijack_io_t ctx, srs_rtmp_t owner) { SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; - - skt->fd = ::socket(AF_INET, SOCK_STREAM, 0); + + skt->family = AF_INET6; + skt->fd = ::socket(skt->family, SOCK_STREAM, 0); // Try IPv6 first. + if (!SOCKET_VALID(skt->fd)) { + skt->family = AF_INET; + skt->fd = ::socket(skt->family, SOCK_STREAM, 0); // Try IPv4 instead, if IPv6 fails. + } if (!SOCKET_VALID(skt->fd)) { return ERROR_SOCKET_CREATE; } - + return ERROR_SUCCESS; } int srs_hijack_io_connect(srs_hijack_io_t ctx, const char* server_ip, int port) { SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; - - sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = inet_addr(server_ip); - - if(::connect(skt->fd, (const struct sockaddr*)&addr, sizeof(sockaddr_in)) < 0){ - return ERROR_SOCKET_CONNECT; + + char port_string[8]; + snprintf(port_string, sizeof(port_string), "%d", port); + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = skt->family; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + addrinfo* result = NULL; + + if(getaddrinfo(server_ip, port_string, (const addrinfo*)&hints, &result) == 0) { + if(::connect(skt->fd, result->ai_addr, result->ai_addrlen) < 0){ + freeaddrinfo(result); + return ERROR_SOCKET_CONNECT; + } } - + + freeaddrinfo(result); return ERROR_SUCCESS; } int srs_hijack_io_read(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nread) diff --git a/trunk/src/libs/srs_librtmp.cpp b/trunk/src/libs/srs_librtmp.cpp index fc747579d..baaac2b56 100644 --- a/trunk/src/libs/srs_librtmp.cpp +++ b/trunk/src/libs/srs_librtmp.cpp @@ -24,6 +24,7 @@ #include #include +#include // for srs-librtmp, @see https://github.com/ossrs/srs/issues/213 #ifndef _WIN32 @@ -340,16 +341,12 @@ static char *inet_ntop6(const u_char *src, char *dst, socklen_t size); const char* inet_ntop(int af, const void *src, char *dst, socklen_t size) { switch (af) { - case AF_INET: - return (inet_ntop4( (unsigned char*)src, (char*)dst, size)); // **** -#ifdef AF_INET6 -#error "IPv6 not supported" - //case AF_INET6: - // return (char*)(inet_ntop6( (unsigned char*)src, (char*)dst, size)); // **** -#endif - default: - // return (NULL); // **** - return 0 ; // **** + case AF_INET: + return (inet_ntop4( (unsigned char*)src, (char*)dst, size)); + case AF_INET6: + return (char*)(inet_ntop6( (unsigned char*)src, (char*)dst, size)); + default: + return (NULL); } /* NOTREACHED */ } @@ -498,7 +495,8 @@ int srs_librtmp_context_resolve_host(Context* context) int ret = ERROR_SUCCESS; // connect to server:port - context->ip = srs_dns_resolve(context->host); + int family = AF_UNSPEC; + context->ip = srs_dns_resolve(context->host, family); if (context->ip.empty()) { return ERROR_SYSTEM_DNS_RESOLVE; } diff --git a/trunk/src/service/srs_service_st.cpp b/trunk/src/service/srs_service_st.cpp index 06fc77313..9999ca2c6 100644 --- a/trunk/src/service/srs_service_st.cpp +++ b/trunk/src/service/srs_service_st.cpp @@ -26,6 +26,7 @@ #include #include #include +#include using namespace std; #include @@ -104,8 +105,6 @@ srs_thread_t srs_thread_self() srs_error_t srs_socket_connect(string server, int port, int64_t tm, srs_netfd_t* pstfd) { - srs_error_t err = srs_success; - st_utime_t timeout = ST_UTIME_NO_TIMEOUT; if (tm != SRS_CONSTS_NO_TMMS) { timeout = (st_utime_t)(tm * 1000); @@ -113,45 +112,43 @@ srs_error_t srs_socket_connect(string server, int port, int64_t tm, srs_netfd_t* *pstfd = NULL; srs_netfd_t stfd = NULL; - sockaddr_in addr; - - int sock = socket(AF_INET, SOCK_STREAM, 0); - if(sock == -1){ - return srs_error_new(ERROR_SOCKET_CREATE, "create socket"); + + char port_string[8]; + snprintf(port_string, sizeof(port_string), "%d", port); + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + addrinfo* result = NULL; + if(getaddrinfo(server.c_str(), port_string, (const addrinfo*)&hints, &result) != 0) { + return srs_error_new(ERROR_SYSTEM_IP_INVALID, "dns resolve server error"); } - srs_fd_close_exec(sock); + int sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol); + if(sock == -1){ + freeaddrinfo(result); + return srs_error_new(ERROR_SOCKET_CREATE, "create socket"); + } srs_assert(!stfd); stfd = st_netfd_open_socket(sock); if(stfd == NULL){ + srs_close_stfd(stfd); + freeaddrinfo(result); return srs_error_new(ERROR_ST_OPEN_SOCKET, "open socket"); } - // connect to server. - std::string ip = srs_dns_resolve(server); - if (ip.empty()) { - return srs_error_new(ERROR_SYSTEM_IP_INVALID, "resolve server %s", server.c_str()); - } - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = inet_addr(ip.c_str()); - - if (st_connect((st_netfd_t)stfd, (const struct sockaddr*)&addr, sizeof(sockaddr_in), timeout) == -1){ - err = srs_error_new(ERROR_ST_CONNECT, "connect to %s:%d", ip.c_str(), port); - goto failed; - } - srs_info("connect ok. server=%s, ip=%s, port=%d", server.c_str(), ip.c_str(), port); - - *pstfd = stfd; - return err; - -failed: - if (stfd) { + if (st_connect((st_netfd_t)stfd, result->ai_addr, result->ai_addrlen, timeout) == -1){ srs_close_stfd(stfd); + freeaddrinfo(result); + return srs_error_new(ERROR_ST_CONNECT, "connect to %s:%d", server.c_str(), port); } - return err; + + srs_info("connect ok. server=%s, port=%d", server.c_str(), port); + + freeaddrinfo(result); + *pstfd = stfd; + return srs_success; } srs_cond_t srs_cond_new() diff --git a/trunk/src/service/srs_service_utility.cpp b/trunk/src/service/srs_service_utility.cpp index 5b255c967..dc3ae444e 100644 --- a/trunk/src/service/srs_service_utility.cpp +++ b/trunk/src/service/srs_service_utility.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include using namespace std; @@ -61,44 +62,54 @@ bool srs_net_device_is_internet(string ifname) return _srs_device_ifs[ifname]; } -bool srs_net_device_is_internet(in_addr_t addr) +bool srs_net_device_is_internet(const sockaddr* addr) { - uint32_t addr_h = ntohl(addr); - - // lo, 127.0.0.0-127.0.0.1 - if (addr_h >= 0x7f000000 && addr_h <= 0x7f000001) { - return false; + if(addr->sa_family == AF_INET) { + const in_addr inaddr = ((sockaddr_in*)addr)->sin_addr; + const uint32_t addr_h = ntohl(inaddr.s_addr); + + // lo, 127.0.0.0-127.0.0.1 + if (addr_h >= 0x7f000000 && addr_h <= 0x7f000001) { + return false; + } + + // Class A 10.0.0.0-10.255.255.255 + if (addr_h >= 0x0a000000 && addr_h <= 0x0affffff) { + return false; + } + + // Class B 172.16.0.0-172.31.255.255 + if (addr_h >= 0xac100000 && addr_h <= 0xac1fffff) { + return false; + } + + // Class C 192.168.0.0-192.168.255.255 + if (addr_h >= 0xc0a80000 && addr_h <= 0xc0a8ffff) { + return false; + } } - - // Class A 10.0.0.0-10.255.255.255 - if (addr_h >= 0x0a000000 && addr_h <= 0x0affffff) { - return false; - } - - // Class B 172.16.0.0-172.31.255.255 - if (addr_h >= 0xac100000 && addr_h <= 0xac1fffff) { - return false; - } - - // Class C 192.168.0.0-192.168.255.255 - if (addr_h >= 0xc0a80000 && addr_h <= 0xc0a8ffff) { - return false; + else if(addr->sa_family == AF_INET6) { + const sockaddr_in6* a6 = (const sockaddr_in6*)addr; + if ((IN6_IS_ADDR_LINKLOCAL(&a6->sin6_addr)) || + (IN6_IS_ADDR_SITELOCAL(&a6->sin6_addr))) { + return false; + } } return true; } -vector _srs_system_ipv4_ips; +vector _srs_system_ips; -void retrieve_local_ipv4_ips() +void retrieve_local_ips() { - vector& ips = _srs_system_ipv4_ips; + vector& ips = _srs_system_ips; ips.clear(); ifaddrs* ifap; if (getifaddrs(&ifap) == -1) { - srs_warn("retrieve local ips, ini ifaddrs failed."); + srs_warn("retrieve local ips, getifaddrs failed."); return; } @@ -111,32 +122,33 @@ void retrieve_local_ipv4_ips() ifaddrs* p = ifap; while (p != NULL) { ifaddrs* cur = p; - sockaddr* addr = cur->ifa_addr; p = p->ifa_next; - // retrieve ipv4 addr + // retrieve IP address // ignore the tun0 network device, // which addr is NULL. // @see: https://github.com/ossrs/srs/issues/141 - if (addr && addr->sa_family == AF_INET) { - in_addr* inaddr = &((sockaddr_in*)addr)->sin_addr; - - char buf[16]; - memset(buf, 0, sizeof(buf)); - - if ((inet_ntop(addr->sa_family, inaddr, buf, sizeof(buf))) == NULL) { - srs_warn("convert local ip failed"); + if ( (cur->ifa_addr) && + ( (cur->ifa_addr->sa_family == AF_INET) || + (cur->ifa_addr->sa_family == AF_INET6) ) ) { + char address_string[64]; + const int success = getnameinfo(cur->ifa_addr, sizeof(sockaddr_storage), + (char*)&address_string, sizeof(address_string), + NULL, 0, + NI_NUMERICHOST); + if(success != 0) { + srs_warn("convert local ip failed: %s", gai_strerror(success)); break; } - std::string ip = buf; + std::string ip = address_string; if (ip != SRS_CONSTS_LOCALHOST) { ss0 << ", local[" << (int)ips.size() << "] ipv4 " << ip; ips.push_back(ip); } // set the device internet status. - if (!srs_net_device_is_internet(inaddr->s_addr)) { + if (!srs_net_device_is_internet(cur->ifa_addr)) { ss1 << ", intranet "; _srs_device_ifs[cur->ifa_name] = false; } else { @@ -152,13 +164,13 @@ void retrieve_local_ipv4_ips() freeifaddrs(ifap); } -vector& srs_get_local_ipv4_ips() +vector& srs_get_local_ips() { - if (_srs_system_ipv4_ips.empty()) { - retrieve_local_ipv4_ips(); + if (_srs_system_ips.empty()) { + retrieve_local_ips(); } - return _srs_system_ipv4_ips; + return _srs_system_ips; } std::string _public_internet_address; @@ -169,7 +181,7 @@ string srs_get_public_internet_address() return _public_internet_address; } - std::vector& ips = srs_get_local_ipv4_ips(); + std::vector& ips = srs_get_local_ips(); // find the best match public address. for (int i = 0; i < (int)ips.size(); i++) { diff --git a/trunk/src/service/srs_service_utility.hpp b/trunk/src/service/srs_service_utility.hpp index d9b613b9c..30b06f18a 100644 --- a/trunk/src/service/srs_service_utility.hpp +++ b/trunk/src/service/srs_service_utility.hpp @@ -37,14 +37,14 @@ extern bool srs_string_is_http(std::string url); extern bool srs_string_is_rtmp(std::string url); // get local ip, fill to @param ips -extern std::vector& srs_get_local_ipv4_ips(); +extern std::vector& srs_get_local_ips(); // get local public ip, empty string if no public internet address found. extern std::string srs_get_public_internet_address(); // detect whether specified device is internet public address. extern bool srs_net_device_is_internet(std::string ifname); -extern bool srs_net_device_is_internet(in_addr_t addr); +extern bool srs_net_device_is_internet(const sockaddr* addr); #endif