|
|
@@ -81,20 +81,13 @@ static struct addrinfo* rtp_resolve_host(const char *hostname, int port, |
|
|
|
{ |
|
|
|
struct addrinfo hints = { 0 }, *res = 0; |
|
|
|
int error; |
|
|
|
char sport[16]; |
|
|
|
const char *node = 0, *service = "0"; |
|
|
|
char service[16]; |
|
|
|
|
|
|
|
if (port > 0) { |
|
|
|
snprintf(sport, sizeof(sport), "%d", port); |
|
|
|
service = sport; |
|
|
|
} |
|
|
|
if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) { |
|
|
|
node = hostname; |
|
|
|
} |
|
|
|
snprintf(service, sizeof(service), "%d", port); |
|
|
|
hints.ai_socktype = type; |
|
|
|
hints.ai_family = family; |
|
|
|
hints.ai_flags = flags; |
|
|
|
if ((error = getaddrinfo(node, service, &hints, &res))) { |
|
|
|
hints.ai_flags = flags; |
|
|
|
if ((error = getaddrinfo(hostname, service, &hints, &res))) { |
|
|
|
res = NULL; |
|
|
|
av_log(NULL, AV_LOG_ERROR, "rtp_resolve_host: %s\n", gai_strerror(error)); |
|
|
|
} |
|
|
@@ -102,6 +95,26 @@ static struct addrinfo* rtp_resolve_host(const char *hostname, int port, |
|
|
|
return res; |
|
|
|
} |
|
|
|
|
|
|
|
static int compare_addr(const struct sockaddr_storage *a, |
|
|
|
const struct sockaddr_storage *b) |
|
|
|
{ |
|
|
|
if (a->ss_family != b->ss_family) |
|
|
|
return 1; |
|
|
|
if (a->ss_family == AF_INET) { |
|
|
|
return (((const struct sockaddr_in *)a)->sin_addr.s_addr != |
|
|
|
((const struct sockaddr_in *)b)->sin_addr.s_addr); |
|
|
|
} |
|
|
|
|
|
|
|
#if defined(IPPROTO_IPV6) |
|
|
|
if (a->ss_family == AF_INET6) { |
|
|
|
const uint8_t *s6_addr_a = ((const struct sockaddr_in6 *)a)->sin6_addr.s6_addr; |
|
|
|
const uint8_t *s6_addr_b = ((const struct sockaddr_in6 *)b)->sin6_addr.s6_addr; |
|
|
|
return memcmp(s6_addr_a, s6_addr_b, 16); |
|
|
|
} |
|
|
|
#endif |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* add option to url of the form: |
|
|
|
* "http://host:port/path?option1=val1&option2=val2... |
|
|
@@ -124,9 +137,9 @@ static av_printf_format(3, 4) void url_add_option(char *buf, int buf_size, const |
|
|
|
|
|
|
|
static void build_udp_url(char *buf, int buf_size, |
|
|
|
const char *hostname, int port, |
|
|
|
int ssm, const char* source_addr, |
|
|
|
int local_port, int ttl, |
|
|
|
int max_packet_size, int connect) |
|
|
|
int max_packet_size, int connect, |
|
|
|
const char* sources) |
|
|
|
{ |
|
|
|
ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL); |
|
|
|
if (local_port >= 0) |
|
|
@@ -135,11 +148,11 @@ static void build_udp_url(char *buf, int buf_size, |
|
|
|
url_add_option(buf, buf_size, "ttl=%d", ttl); |
|
|
|
if (max_packet_size >=0) |
|
|
|
url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size); |
|
|
|
if (ssm) |
|
|
|
url_add_option(buf, buf_size, "sources=%s", source_addr); |
|
|
|
if (connect) |
|
|
|
url_add_option(buf, buf_size, "connect=1"); |
|
|
|
url_add_option(buf, buf_size, "fifo_size=0"); |
|
|
|
if (sources && sources[0]) |
|
|
|
url_add_option(buf, buf_size, "sources=%s", sources); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@@ -152,7 +165,7 @@ static void build_udp_url(char *buf, int buf_size, |
|
|
|
* 'connect=0/1' : do a connect() on the UDP socket |
|
|
|
* deprecated option: |
|
|
|
* 'localport=n' : set the local port to n |
|
|
|
* 'ssm=ip' : use ip as source-specific multicast address |
|
|
|
* 'sources=ip[,ip]' : list allowed source IP addresses |
|
|
|
* |
|
|
|
* if rtcpport isn't set the rtcp port will be the rtp port + 1 |
|
|
|
* if local rtp port isn't set any available port will be used for the local |
|
|
@@ -166,11 +179,10 @@ static int rtp_open(URLContext *h, const char *uri, int flags) |
|
|
|
int rtp_port, rtcp_port, |
|
|
|
ttl, connect, |
|
|
|
local_rtp_port, local_rtcp_port, max_packet_size; |
|
|
|
char hostname[256],source_ip[50]; |
|
|
|
char hostname[256], sources[1024] = ""; |
|
|
|
char buf[1024]; |
|
|
|
char path[1024]; |
|
|
|
const char *p; |
|
|
|
struct addrinfo *sourceaddr; |
|
|
|
|
|
|
|
av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port, |
|
|
|
path, sizeof(path), uri); |
|
|
@@ -180,7 +192,6 @@ static int rtp_open(URLContext *h, const char *uri, int flags) |
|
|
|
local_rtp_port = -1; |
|
|
|
local_rtcp_port = -1; |
|
|
|
max_packet_size = -1; |
|
|
|
s->ssm = 0; |
|
|
|
connect = 0; |
|
|
|
|
|
|
|
p = strchr(uri, '?'); |
|
|
@@ -206,30 +217,35 @@ static int rtp_open(URLContext *h, const char *uri, int flags) |
|
|
|
if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { |
|
|
|
connect = strtol(buf, NULL, 10); |
|
|
|
} |
|
|
|
if (av_find_info_tag(buf, sizeof(buf), "ssm", p)) { |
|
|
|
s->ssm = 1; |
|
|
|
snprintf(source_ip, sizeof(source_ip), "%s", buf); |
|
|
|
|
|
|
|
sourceaddr = rtp_resolve_host(source_ip, 0, |
|
|
|
SOCK_DGRAM, AF_UNSPEC, |
|
|
|
AI_NUMERICHOST); |
|
|
|
|
|
|
|
memcpy(&s->ssm_addr, sourceaddr->ai_addr, sourceaddr->ai_addrlen); |
|
|
|
freeaddrinfo(sourceaddr); |
|
|
|
if (av_find_info_tag(buf, sizeof(buf), "sources", p)) { |
|
|
|
struct addrinfo *sourceaddr = NULL; |
|
|
|
av_strlcpy(sources, buf, sizeof(sources)); |
|
|
|
|
|
|
|
/* Try resolving the IP if only one IP is specified - we don't |
|
|
|
* support manually checking more than one IP. */ |
|
|
|
if (!strchr(sources, ',')) |
|
|
|
sourceaddr = rtp_resolve_host(sources, 0, |
|
|
|
SOCK_DGRAM, AF_UNSPEC, |
|
|
|
AI_NUMERICHOST); |
|
|
|
if (sourceaddr) { |
|
|
|
s->ssm = 1; |
|
|
|
memcpy(&s->ssm_addr, sourceaddr->ai_addr, sourceaddr->ai_addrlen); |
|
|
|
freeaddrinfo(sourceaddr); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
build_udp_url(buf, sizeof(buf), |
|
|
|
hostname, rtp_port, s->ssm, source_ip, local_rtp_port, ttl, max_packet_size, |
|
|
|
connect); |
|
|
|
hostname, rtp_port, local_rtp_port, ttl, max_packet_size, |
|
|
|
connect, sources); |
|
|
|
if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) |
|
|
|
goto fail; |
|
|
|
if (local_rtp_port>=0 && local_rtcp_port<0) |
|
|
|
local_rtcp_port = ff_udp_get_local_port(s->rtp_hd) + 1; |
|
|
|
|
|
|
|
build_udp_url(buf, sizeof(buf), |
|
|
|
hostname, rtcp_port, s->ssm, source_ip, local_rtcp_port, ttl, max_packet_size, |
|
|
|
connect); |
|
|
|
hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size, |
|
|
|
connect, sources); |
|
|
|
if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) |
|
|
|
goto fail; |
|
|
|
|
|
|
@@ -275,27 +291,8 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size) |
|
|
|
continue; |
|
|
|
return AVERROR(EIO); |
|
|
|
} |
|
|
|
if (s->ssm) { |
|
|
|
if (from.ss_family == AF_INET && s->ssm_addr.ss_family == AF_INET) { |
|
|
|
uint32_t intended_source = ((struct sockaddr_in *)&s->ssm_addr)->sin_addr.s_addr; |
|
|
|
uint32_t actual_source = ((struct sockaddr_in *)&from)->sin_addr.s_addr; |
|
|
|
if (intended_source != actual_source) { |
|
|
|
// discard the packet without any processing |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#if defined(IPPROTO_IPV6) |
|
|
|
if (from.ss_family == AF_INET6 && s->ssm_addr.ss_family == AF_INET6) { |
|
|
|
unsigned char* intended_source = ((struct sockaddr_in6 *)&s->ssm_addr)->sin6_addr.s6_addr; |
|
|
|
unsigned char* actual_source = ((struct sockaddr_in6 *)&from)->sin6_addr.s6_addr; |
|
|
|
if (memcmp(intended_source, actual_source, 16) != 0) { |
|
|
|
// discard the packet without any processing |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
} |
|
|
|
if (s->ssm && compare_addr(&from, &s->ssm_addr)) |
|
|
|
continue; |
|
|
|
break; |
|
|
|
} |
|
|
|
/* then RTP */ |
|
|
@@ -309,27 +306,8 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size) |
|
|
|
continue; |
|
|
|
return AVERROR(EIO); |
|
|
|
} |
|
|
|
if (s->ssm) { |
|
|
|
if (from.ss_family == AF_INET && s->ssm_addr.ss_family == AF_INET) { |
|
|
|
uint32_t intended_source = ((struct sockaddr_in *)&s->ssm_addr)->sin_addr.s_addr; |
|
|
|
uint32_t actual_source = ((struct sockaddr_in *)&from)->sin_addr.s_addr; |
|
|
|
if (intended_source != actual_source) { |
|
|
|
// discard the packet without any processing |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#if defined(IPPROTO_IPV6) |
|
|
|
if (from.ss_family == AF_INET6 && s->ssm_addr.ss_family == AF_INET6) { |
|
|
|
unsigned char* intended_source = ((struct sockaddr_in6 *)&s->ssm_addr)->sin6_addr.s6_addr; |
|
|
|
unsigned char* actual_source = ((struct sockaddr_in6 *)&from)->sin6_addr.s6_addr; |
|
|
|
if (memcmp(intended_source, actual_source, 16) != 0) { |
|
|
|
// discard the packet without any processing |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
} |
|
|
|
if (s->ssm && compare_addr(&from, &s->ssm_addr)) |
|
|
|
continue; |
|
|
|
break; |
|
|
|
} |
|
|
|
} else if (n < 0) { |
|
|
|