1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-12 11:21:52 +00:00

IPv6 support (for 3.0 release) (#988)

* IPv6 support, part 1.

* IPv6 support, part 2.

* Some more IPv6 work.

* Made functions for address:port paŕsing IPv6-capable.

* Fixed type (compile warning).

* Fixed formatting.

* Reverted option change.

* Replaced abort() by proper error handling.

* Also retrieving local IPv6 addresses now.
This commit is contained in:
Thomas Dreibholz 2017-10-14 05:29:33 +02:00 committed by winlin
parent db08f1586c
commit feaae341b9
20 changed files with 296 additions and 201 deletions

View file

@ -26,4 +26,4 @@ CONTRIBUTORS ordered by first contribution.
* lovecat<littlefawn@163.com> "Bug fixed" * lovecat<littlefawn@163.com> "Bug fixed"
* panda1986<542638787@qq.com> "Bug fixed" * panda1986<542638787@qq.com> "Bug fixed"
* YueHonghui<hongf.yue@hotmail.com> "Bug fixed" * YueHonghui<hongf.yue@hotmail.com> "Bug fixed"
* ThomasDreibholz<dreibh@simula.no> "IPv6 support"

View file

@ -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()); return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "invalid stats.network=%d", get_stats_network());
} }
if (true) { if (true) {
vector<std::string> ips = srs_get_local_ipv4_ips(); vector<std::string> ips = srs_get_local_ips();
int index = get_stats_network(); int index = get_stats_network();
if (index >= (int)ips.size()) { if (index >= (int)ips.size()) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "invalid stats.network=%d of %d", return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "invalid stats.network=%d of %d",

View file

@ -68,7 +68,7 @@ srs_error_t SrsHttpHeartbeat::do_heartbeat()
std::string ip = ""; std::string ip = "";
std::string device_id = _srs_config->get_heartbeat_device_id(); std::string device_id = _srs_config->get_heartbeat_device_id();
vector<string>& ips = srs_get_local_ipv4_ips(); vector<string>& ips = srs_get_local_ips();
if (!ips.empty()) { if (!ips.empty()) {
ip = ips[_srs_config->get_stats_network() % (int)ips.size()]; ip = ips[_srs_config->get_stats_network() % (int)ips.size()];
} }

View file

@ -31,6 +31,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <netdb.h>
using namespace std; using namespace std;
#include <srs_kernel_log.hpp> #include <srs_kernel_log.hpp>
@ -111,20 +112,31 @@ srs_error_t SrsUdpListener::listen()
{ {
srs_error_t err = srs_success; srs_error_t err = srs_success;
if ((_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { char port_string[8];
return srs_error_new(ERROR_SOCKET_CREATE, "create socket"); 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_fd_close_exec(_fd);
srs_socket_reuse_addr(_fd); srs_socket_reuse_addr(_fd);
sockaddr_in addr; if (bind(_fd, result->ai_addr, result->ai_addrlen) == -1) {
addr.sin_family = AF_INET; freeaddrinfo(result);
addr.sin_port = htons(port); return srs_error_new(ERROR_SOCKET_BIND, "bind socket error. ep=%s:%d", ip.c_str(), 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");
} }
freeaddrinfo(result);
if ((_stfd = srs_netfd_open_socket(_fd)) == NULL){ if ((_stfd = srs_netfd_open_socket(_fd)) == NULL){
return srs_error_new(ERROR_ST_OPEN_SOCKET, "st open socket"); 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"); return srs_error_wrap(err, "udp listener");
} }
// TODO: FIXME: support ipv6, @see man 7 ipv6 sockaddr_storage from;
sockaddr_in from; int nb_from = sizeof(from);
int nb_from = sizeof(sockaddr_in);
int nread = 0; int nread = 0;
if ((nread = srs_recvfrom(_stfd, buf, nb_buf, (sockaddr*)&from, &nb_from, SRS_UTIME_NO_TIMEOUT)) <= 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); 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); 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; srs_error_t err = srs_success;
if ((_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { char port_string[8];
return srs_error_new(ERROR_SOCKET_CREATE, "create socket"); 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_fd_close_exec(_fd);
srs_socket_reuse_addr(_fd); srs_socket_reuse_addr(_fd);
sockaddr_in addr; if (bind(_fd, result->ai_addr, result->ai_addrlen) == -1) {
addr.sin_family = AF_INET; freeaddrinfo(result);
addr.sin_port = htons(port); return srs_error_new(ERROR_SOCKET_BIND, "bind socket error. ep=%s:%d", ip.c_str(), 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");
} }
freeaddrinfo(result);
if (::listen(_fd, SERVER_LISTEN_BACKLOG) == -1) { if (::listen(_fd, SERVER_LISTEN_BACKLOG) == -1) {
return srs_error_new(ERROR_SOCKET_LISTEN, "listen socket"); return srs_error_new(ERROR_SOCKET_LISTEN, "listen socket");
} }

View file

@ -31,7 +31,7 @@
#include <srs_app_st.hpp> #include <srs_app_st.hpp>
#include <srs_app_thread.hpp> #include <srs_app_thread.hpp>
struct sockaddr_in; struct sockaddr;
/** /**
* the udp packet handler. * the udp packet handler.
@ -57,7 +57,7 @@ public:
* @param nb_buf, the size of udp packet bytes. * @param nb_buf, the size of udp packet bytes.
* @remark user should never use the buf, for it's a shared memory 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;
}; };
/** /**

View file

@ -29,6 +29,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netdb.h>
using namespace std; using namespace std;
#include <srs_app_config.hpp> #include <srs_app_config.hpp>
@ -155,10 +156,18 @@ SrsMpegtsOverUdp::~SrsMpegtsOverUdp()
srs_freep(pprint); 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); char address_string[64];
int peer_port = ntohs(from->sin_port); 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. // append to buffer.
buffer->append(buf, nb_buf); buffer->append(buf, nb_buf);

View file

@ -28,7 +28,7 @@
#ifdef SRS_AUTO_STREAM_CASTER #ifdef SRS_AUTO_STREAM_CASTER
struct sockaddr_in; struct sockaddr;
#include <string> #include <string>
#include <map> #include <map>
@ -100,7 +100,7 @@ public:
virtual ~SrsMpegtsOverUdp(); virtual ~SrsMpegtsOverUdp();
// interface ISrsUdpHandler // interface ISrsUdpHandler
public: 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: private:
virtual srs_error_t on_udp_bytes(std::string host, int port, char* buf, int nb_buf); virtual srs_error_t on_udp_bytes(std::string host, int port, char* buf, int nb_buf);
// interface ISrsTsHandler // interface ISrsTsHandler

View file

@ -87,7 +87,7 @@ SrsSimpleRtmpClient::~SrsSimpleRtmpClient()
srs_error_t SrsSimpleRtmpClient::connect_app() srs_error_t SrsSimpleRtmpClient::connect_app()
{ {
std::vector<std::string> ips = srs_get_local_ipv4_ips(); std::vector<std::string> ips = srs_get_local_ips();
assert(_srs_config->get_stats_network() < (int)ips.size()); assert(_srs_config->get_stats_network() < (int)ips.size());
std::string local_ip = ips[_srs_config->get_stats_network()]; std::string local_ip = ips[_srs_config->get_stats_network()];

View file

@ -54,7 +54,7 @@ SrsRtpConn::SrsRtpConn(SrsRtspConn* r, int p, int sid)
_port = p; _port = p;
stream_id = sid; stream_id = sid;
// TODO: support listen at <[ip:]port> // 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(); cache = new SrsRtpPacket();
pprint = SrsPithyPrint::create_caster(); pprint = SrsPithyPrint::create_caster();
} }
@ -76,7 +76,7 @@ srs_error_t SrsRtpConn::listen()
return listener->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; srs_error_t err = srs_success;

View file

@ -74,7 +74,7 @@ public:
virtual srs_error_t listen(); virtual srs_error_t listen();
// interface ISrsUdpHandler // interface ISrsUdpHandler
public: 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);
}; };
/** /**

View file

@ -1137,7 +1137,7 @@ srs_error_t SrsServer::listen_stream_caster()
} }
// TODO: support listen at <[ip:]port> // 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); return srs_error_wrap(err, "listen at %d", port);
} }
} }

View file

@ -30,6 +30,7 @@
#include <signal.h> #include <signal.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <math.h> #include <math.h>
#include <netdb.h>
#ifdef SRS_OSX #ifdef SRS_OSX
#include <sys/sysctl.h> #include <sys/sysctl.h>
@ -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) string srs_get_local_ip(int fd)
{ {
std::string ip;
// discovery client information // discovery client information
sockaddr_in addr; sockaddr_storage addr;
socklen_t addrlen = sizeof(addr); socklen_t addrlen = sizeof(addr);
if (getsockname(fd, (sockaddr*)&addr, &addrlen) == -1) { if (getsockname(fd, (sockaddr*)&addr, &addrlen) == -1) {
return ip; return "";
} }
srs_verbose("get local ip success."); srs_verbose("get local ip success.");
// ip v4 or v6 char address_string[64];
char buf[INET6_ADDRSTRLEN]; const int success = getnameinfo((const sockaddr*)&addr, addrlen,
memset(buf, 0, sizeof(buf)); (char*)&address_string, sizeof(address_string),
NULL, 0,
if ((inet_ntop(addr.sin_family, &addr.sin_addr, buf, sizeof(buf))) == NULL) { NI_NUMERICHOST);
return ip; if(success != 0) {
return "";
} }
ip = buf; srs_verbose("get local ip of client ip=%s, fd=%d", address_string, fd);
return std::string(address_string);
srs_verbose("get local ip of client ip=%s, fd=%d", buf, fd);
return ip;
} }
int srs_get_local_port(int fd) int srs_get_local_port(int fd)
{ {
// discovery client information // discovery client information
sockaddr_in addr; sockaddr_storage addr;
socklen_t addrlen = sizeof(addr); socklen_t addrlen = sizeof(addr);
if (getsockname(fd, (sockaddr*)&addr, &addrlen) == -1) { if (getsockname(fd, (sockaddr*)&addr, &addrlen) == -1) {
return 0; return 0;
} }
srs_verbose("get local ip success."); srs_verbose("get local ip success.");
int port = ntohs(addr.sin_port); int port = 0;
switch(addr.ss_family) {
srs_verbose("get local ip of client port=%s, fd=%d", port, fd); 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; return port;
} }
string srs_get_peer_ip(int fd) string srs_get_peer_ip(int fd)
{ {
std::string ip;
// discovery client information // discovery client information
sockaddr_in addr; sockaddr_storage addr;
socklen_t addrlen = sizeof(addr); socklen_t addrlen = sizeof(addr);
if (getpeername(fd, (sockaddr*)&addr, &addrlen) == -1) { if (getsockname(fd, (sockaddr*)&addr, &addrlen) == -1) {
return ip; return "";
} }
srs_verbose("get peer name success."); srs_verbose("get peer ip success.");
// ip v4 or v6 char address_string[64];
char buf[INET6_ADDRSTRLEN]; const int success = getnameinfo((const sockaddr*)&addr, addrlen,
memset(buf, 0, sizeof(buf)); (char*)&address_string, sizeof(address_string),
NULL, 0,
if ((inet_ntop(addr.sin_family, &addr.sin_addr, buf, sizeof(buf))) == NULL) { NI_NUMERICHOST);
return ip; if(success != 0) {
return "";
} }
srs_verbose("get peer ip of client ip=%s, fd=%d", buf, fd);
srs_verbose("get peer ip of client ip=%s, fd=%d", address_string, fd);
ip = buf; return std::string(address_string);
srs_verbose("get peer ip success. ip=%s, fd=%d", ip.c_str(), fd);
return ip;
} }
bool srs_is_digit_number(const string& str) bool srs_is_digit_number(const string& str)

View file

@ -643,6 +643,9 @@ extern SrsNetworkRtmpServer* srs_get_network_rtmp_server();
// the deamon st-thread will update it. // the deamon st-thread will update it.
extern void srs_update_rtmp_server(int nb_conn, SrsKbps* kbps); 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. // get local or peer ip.
// where local ip is the server ip which client connected. // where local ip is the server ip which client connected.
extern std::string srs_get_local_ip(int fd); extern std::string srs_get_local_ip(int fd);

View file

@ -154,50 +154,79 @@ int64_t srs_update_system_time_ms()
return _srs_system_time_us_cache / 1000; 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) { addrinfo hints;
return host; memset(&hints, 0, sizeof(hints));
} hints.ai_family = family;
addrinfo* result = NULL;
hostent* answer = gethostbyname(host.c_str()); if(getaddrinfo(host.c_str(), NULL, NULL, &result) != 0) {
if (answer == NULL) {
return ""; return "";
} }
char ipv4[16]; char address_string[64];
memset(ipv4, 0, sizeof(ipv4)); const int success = getnameinfo(result->ai_addr, result->ai_addrlen,
(char*)&address_string, sizeof(address_string),
// covert the first entry to ip. NULL, 0,
if (answer->h_length > 0) { NI_NUMERICHOST);
inet_ntop(AF_INET, answer->h_addr_list[0], ipv4, sizeof(ipv4)); freeaddrinfo(result);
if(success) {
family = result->ai_family;
return string(address_string);
} }
return "";
return ipv4;
} }
void srs_parse_hostport(const string& hostport, string& host, int& port) 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) { if (pos != std::string::npos) {
string p = hostport.substr(pos + 1); const string p = hostport.substr(pos + 1);
host = hostport.substr(0, pos); 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()); port = ::atoi(p.c_str());
} else { } else {
host = hostport; 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) void srs_parse_endpoint(string hostport, string& ip, int& port)
{ {
ip = "0.0.0.0"; const size_t pos = hostport.rfind(":"); // Look for ":" from the end, to work with IPv6.
if (pos != std::string::npos) {
size_t pos = string::npos; if ((pos >= 1) &&
if ((pos = hostport.find(":")) != string::npos) { (hostport[0] == '[') &&
ip = hostport.substr(0, pos); (hostport[pos - 1] == ']')) {
string sport = hostport.substr(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()); port = ::atoi(sport.c_str());
} else { } else {
ip = check_ipv6() ? "::" : "0.0.0.0";
port = ::atoi(hostport.c_str()); 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) 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()); return (pos != string::npos) && (pos == str.length() - flag.length());
} }

View file

@ -47,7 +47,7 @@ extern int64_t srs_get_system_startup_time_ms();
extern int64_t srs_update_system_time_ms(); extern int64_t srs_update_system_time_ms();
// dns resolve utility, return the resolved ip address. // 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. // split the host:port to host and port.
// @remark the hostport format in <host[:port]>, where port is optional. // @remark the hostport format in <host[:port]>, where port is optional.

View file

@ -64,6 +64,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <errno.h> #include <errno.h>
#include <stdio.h>
#include <netdb.h>
#include <srs_kernel_utility.hpp> #include <srs_kernel_utility.hpp>
#include <srs_kernel_consts.hpp> #include <srs_kernel_consts.hpp>
@ -73,6 +75,7 @@
struct SrsBlockSyncSocket struct SrsBlockSyncSocket
{ {
SOCKET fd; SOCKET fd;
int family;
int64_t rbytes; int64_t rbytes;
int64_t sbytes; int64_t sbytes;
// The send/recv timeout in ms. // 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) int srs_hijack_io_create_socket(srs_hijack_io_t ctx, srs_rtmp_t owner)
{ {
SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; 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)) { if (!SOCKET_VALID(skt->fd)) {
return ERROR_SOCKET_CREATE; return ERROR_SOCKET_CREATE;
} }
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
int srs_hijack_io_connect(srs_hijack_io_t ctx, const char* server_ip, int port) int srs_hijack_io_connect(srs_hijack_io_t ctx, const char* server_ip, int port)
{ {
SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx;
sockaddr_in addr; char port_string[8];
addr.sin_family = AF_INET; snprintf(port_string, sizeof(port_string), "%d", port);
addr.sin_port = htons(port); addrinfo hints;
addr.sin_addr.s_addr = inet_addr(server_ip); memset(&hints, 0, sizeof(hints));
hints.ai_family = skt->family;
if(::connect(skt->fd, (const struct sockaddr*)&addr, sizeof(sockaddr_in)) < 0){ hints.ai_socktype = SOCK_STREAM;
return ERROR_SOCKET_CONNECT; 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; return ERROR_SUCCESS;
} }
int srs_hijack_io_read(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nread) int srs_hijack_io_read(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nread)

View file

@ -24,6 +24,7 @@
#include <srs_librtmp.hpp> #include <srs_librtmp.hpp>
#include <stdlib.h> #include <stdlib.h>
#include <sys/socket.h>
// for srs-librtmp, @see https://github.com/ossrs/srs/issues/213 // for srs-librtmp, @see https://github.com/ossrs/srs/issues/213
#ifndef _WIN32 #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) const char* inet_ntop(int af, const void *src, char *dst, socklen_t size)
{ {
switch (af) { switch (af) {
case AF_INET: case AF_INET:
return (inet_ntop4( (unsigned char*)src, (char*)dst, size)); // **** return (inet_ntop4( (unsigned char*)src, (char*)dst, size));
#ifdef AF_INET6 case AF_INET6:
#error "IPv6 not supported" return (char*)(inet_ntop6( (unsigned char*)src, (char*)dst, size));
//case AF_INET6: default:
// return (char*)(inet_ntop6( (unsigned char*)src, (char*)dst, size)); // **** return (NULL);
#endif
default:
// return (NULL); // ****
return 0 ; // ****
} }
/* NOTREACHED */ /* NOTREACHED */
} }
@ -498,7 +495,8 @@ int srs_librtmp_context_resolve_host(Context* context)
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
// connect to server:port // 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()) { if (context->ip.empty()) {
return ERROR_SYSTEM_DNS_RESOLVE; return ERROR_SYSTEM_DNS_RESOLVE;
} }

View file

@ -26,6 +26,7 @@
#include <st.h> #include <st.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netdb.h>
using namespace std; using namespace std;
#include <srs_kernel_error.hpp> #include <srs_kernel_error.hpp>
@ -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 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; st_utime_t timeout = ST_UTIME_NO_TIMEOUT;
if (tm != SRS_CONSTS_NO_TMMS) { if (tm != SRS_CONSTS_NO_TMMS) {
timeout = (st_utime_t)(tm * 1000); 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; *pstfd = NULL;
srs_netfd_t stfd = NULL; srs_netfd_t stfd = NULL;
sockaddr_in addr;
char port_string[8];
int sock = socket(AF_INET, SOCK_STREAM, 0); snprintf(port_string, sizeof(port_string), "%d", port);
if(sock == -1){ addrinfo hints;
return srs_error_new(ERROR_SOCKET_CREATE, "create socket"); 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); srs_assert(!stfd);
stfd = st_netfd_open_socket(sock); stfd = st_netfd_open_socket(sock);
if(stfd == NULL){ if(stfd == NULL){
srs_close_stfd(stfd);
freeaddrinfo(result);
return srs_error_new(ERROR_ST_OPEN_SOCKET, "open socket"); return srs_error_new(ERROR_ST_OPEN_SOCKET, "open socket");
} }
// connect to server. if (st_connect((st_netfd_t)stfd, result->ai_addr, result->ai_addrlen, timeout) == -1){
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) {
srs_close_stfd(stfd); 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() srs_cond_t srs_cond_new()

View file

@ -26,6 +26,7 @@
#include <unistd.h> #include <unistd.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <ifaddrs.h> #include <ifaddrs.h>
#include <netdb.h>
#include <map> #include <map>
#include <sstream> #include <sstream>
using namespace std; using namespace std;
@ -61,44 +62,54 @@ bool srs_net_device_is_internet(string ifname)
return _srs_device_ifs[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); if(addr->sa_family == AF_INET) {
const in_addr inaddr = ((sockaddr_in*)addr)->sin_addr;
// lo, 127.0.0.0-127.0.0.1 const uint32_t addr_h = ntohl(inaddr.s_addr);
if (addr_h >= 0x7f000000 && addr_h <= 0x7f000001) {
return false; // 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;
}
} }
else if(addr->sa_family == AF_INET6) {
// Class A 10.0.0.0-10.255.255.255 const sockaddr_in6* a6 = (const sockaddr_in6*)addr;
if (addr_h >= 0x0a000000 && addr_h <= 0x0affffff) { if ((IN6_IS_ADDR_LINKLOCAL(&a6->sin6_addr)) ||
return false; (IN6_IS_ADDR_SITELOCAL(&a6->sin6_addr))) {
} 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;
} }
return true; return true;
} }
vector<string> _srs_system_ipv4_ips; vector<string> _srs_system_ips;
void retrieve_local_ipv4_ips() void retrieve_local_ips()
{ {
vector<string>& ips = _srs_system_ipv4_ips; vector<string>& ips = _srs_system_ips;
ips.clear(); ips.clear();
ifaddrs* ifap; ifaddrs* ifap;
if (getifaddrs(&ifap) == -1) { if (getifaddrs(&ifap) == -1) {
srs_warn("retrieve local ips, ini ifaddrs failed."); srs_warn("retrieve local ips, getifaddrs failed.");
return; return;
} }
@ -111,32 +122,33 @@ void retrieve_local_ipv4_ips()
ifaddrs* p = ifap; ifaddrs* p = ifap;
while (p != NULL) { while (p != NULL) {
ifaddrs* cur = p; ifaddrs* cur = p;
sockaddr* addr = cur->ifa_addr;
p = p->ifa_next; p = p->ifa_next;
// retrieve ipv4 addr // retrieve IP address
// ignore the tun0 network device, // ignore the tun0 network device,
// which addr is NULL. // which addr is NULL.
// @see: https://github.com/ossrs/srs/issues/141 // @see: https://github.com/ossrs/srs/issues/141
if (addr && addr->sa_family == AF_INET) { if ( (cur->ifa_addr) &&
in_addr* inaddr = &((sockaddr_in*)addr)->sin_addr; ( (cur->ifa_addr->sa_family == AF_INET) ||
(cur->ifa_addr->sa_family == AF_INET6) ) ) {
char buf[16]; char address_string[64];
memset(buf, 0, sizeof(buf)); const int success = getnameinfo(cur->ifa_addr, sizeof(sockaddr_storage),
(char*)&address_string, sizeof(address_string),
if ((inet_ntop(addr->sa_family, inaddr, buf, sizeof(buf))) == NULL) { NULL, 0,
srs_warn("convert local ip failed"); NI_NUMERICHOST);
if(success != 0) {
srs_warn("convert local ip failed: %s", gai_strerror(success));
break; break;
} }
std::string ip = buf; std::string ip = address_string;
if (ip != SRS_CONSTS_LOCALHOST) { if (ip != SRS_CONSTS_LOCALHOST) {
ss0 << ", local[" << (int)ips.size() << "] ipv4 " << ip; ss0 << ", local[" << (int)ips.size() << "] ipv4 " << ip;
ips.push_back(ip); ips.push_back(ip);
} }
// set the device internet status. // 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 "; ss1 << ", intranet ";
_srs_device_ifs[cur->ifa_name] = false; _srs_device_ifs[cur->ifa_name] = false;
} else { } else {
@ -152,13 +164,13 @@ void retrieve_local_ipv4_ips()
freeifaddrs(ifap); freeifaddrs(ifap);
} }
vector<string>& srs_get_local_ipv4_ips() vector<string>& srs_get_local_ips()
{ {
if (_srs_system_ipv4_ips.empty()) { if (_srs_system_ips.empty()) {
retrieve_local_ipv4_ips(); retrieve_local_ips();
} }
return _srs_system_ipv4_ips; return _srs_system_ips;
} }
std::string _public_internet_address; std::string _public_internet_address;
@ -169,7 +181,7 @@ string srs_get_public_internet_address()
return _public_internet_address; return _public_internet_address;
} }
std::vector<std::string>& ips = srs_get_local_ipv4_ips(); std::vector<std::string>& ips = srs_get_local_ips();
// find the best match public address. // find the best match public address.
for (int i = 0; i < (int)ips.size(); i++) { for (int i = 0; i < (int)ips.size(); i++) {

View file

@ -37,14 +37,14 @@ extern bool srs_string_is_http(std::string url);
extern bool srs_string_is_rtmp(std::string url); extern bool srs_string_is_rtmp(std::string url);
// get local ip, fill to @param ips // get local ip, fill to @param ips
extern std::vector<std::string>& srs_get_local_ipv4_ips(); extern std::vector<std::string>& srs_get_local_ips();
// get local public ip, empty string if no public internet address found. // get local public ip, empty string if no public internet address found.
extern std::string srs_get_public_internet_address(); extern std::string srs_get_public_internet_address();
// detect whether specified device is internet public 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(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 #endif