Commit 48353325 authored by Michael Niedermayer's avatar Michael Niedermayer

Merge commit '36fb0d02'

* commit '36fb0d02':
  rtsp: Support multicast source filters (RFC 4570)
  rtpproto: Check the source IP if one single source has been specified
  rtpproto: Support IGMPv3 source specific multicast inclusion

Conflicts:
	libavformat/rtpproto.c
	libavformat/rtsp.c
	libavformat/rtsp.h
Merged-by: 's avatarMichael Niedermayer <michaelni@gmx.at>
parents 73b2043d 36fb0d02
...@@ -81,20 +81,13 @@ static struct addrinfo* rtp_resolve_host(const char *hostname, int port, ...@@ -81,20 +81,13 @@ static struct addrinfo* rtp_resolve_host(const char *hostname, int port,
{ {
struct addrinfo hints = { 0 }, *res = 0; struct addrinfo hints = { 0 }, *res = 0;
int error; int error;
char sport[16]; char service[16];
const char *node = 0, *service = "0";
if (port > 0) { snprintf(service, sizeof(service), "%d", port);
snprintf(sport, sizeof(sport), "%d", port);
service = sport;
}
if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) {
node = hostname;
}
hints.ai_socktype = type; hints.ai_socktype = type;
hints.ai_family = family; hints.ai_family = family;
hints.ai_flags = flags; hints.ai_flags = flags;
if ((error = getaddrinfo(node, service, &hints, &res))) { if ((error = getaddrinfo(hostname, service, &hints, &res))) {
res = NULL; res = NULL;
av_log(NULL, AV_LOG_ERROR, "rtp_resolve_host: %s\n", gai_strerror(error)); 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, ...@@ -102,6 +95,26 @@ static struct addrinfo* rtp_resolve_host(const char *hostname, int port,
return res; 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: * add option to url of the form:
* "http://host:port/path?option1=val1&option2=val2... * "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 ...@@ -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, static void build_udp_url(char *buf, int buf_size,
const char *hostname, int port, const char *hostname, int port,
int ssm, const char* source_addr,
int local_port, int ttl, 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); ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL);
if (local_port >= 0) if (local_port >= 0)
...@@ -135,11 +148,11 @@ static void build_udp_url(char *buf, int buf_size, ...@@ -135,11 +148,11 @@ static void build_udp_url(char *buf, int buf_size,
url_add_option(buf, buf_size, "ttl=%d", ttl); url_add_option(buf, buf_size, "ttl=%d", ttl);
if (max_packet_size >=0) if (max_packet_size >=0)
url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size); 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) if (connect)
url_add_option(buf, buf_size, "connect=1"); url_add_option(buf, buf_size, "connect=1");
url_add_option(buf, buf_size, "fifo_size=0"); 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, ...@@ -152,7 +165,7 @@ static void build_udp_url(char *buf, int buf_size,
* 'connect=0/1' : do a connect() on the UDP socket * 'connect=0/1' : do a connect() on the UDP socket
* deprecated option: * deprecated option:
* 'localport=n' : set the local port to n * '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 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 * 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) ...@@ -166,11 +179,10 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
int rtp_port, rtcp_port, int rtp_port, rtcp_port,
ttl, connect, ttl, connect,
local_rtp_port, local_rtcp_port, max_packet_size; local_rtp_port, local_rtcp_port, max_packet_size;
char hostname[256],source_ip[50]; char hostname[256], sources[1024] = "";
char buf[1024]; char buf[1024];
char path[1024]; char path[1024];
const char *p; const char *p;
struct addrinfo *sourceaddr;
av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port, av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
path, sizeof(path), uri); path, sizeof(path), uri);
...@@ -180,7 +192,6 @@ static int rtp_open(URLContext *h, const char *uri, int flags) ...@@ -180,7 +192,6 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
local_rtp_port = -1; local_rtp_port = -1;
local_rtcp_port = -1; local_rtcp_port = -1;
max_packet_size = -1; max_packet_size = -1;
s->ssm = 0;
connect = 0; connect = 0;
p = strchr(uri, '?'); p = strchr(uri, '?');
...@@ -206,30 +217,35 @@ static int rtp_open(URLContext *h, const char *uri, int flags) ...@@ -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)) { if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
connect = strtol(buf, NULL, 10); connect = strtol(buf, NULL, 10);
} }
if (av_find_info_tag(buf, sizeof(buf), "ssm", p)) { if (av_find_info_tag(buf, sizeof(buf), "sources", p)) {
s->ssm = 1; struct addrinfo *sourceaddr = NULL;
snprintf(source_ip, sizeof(source_ip), "%s", buf); av_strlcpy(sources, buf, sizeof(sources));
sourceaddr = rtp_resolve_host(source_ip, 0, /* 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, SOCK_DGRAM, AF_UNSPEC,
AI_NUMERICHOST); AI_NUMERICHOST);
if (sourceaddr) {
s->ssm = 1;
memcpy(&s->ssm_addr, sourceaddr->ai_addr, sourceaddr->ai_addrlen); memcpy(&s->ssm_addr, sourceaddr->ai_addr, sourceaddr->ai_addrlen);
freeaddrinfo(sourceaddr); freeaddrinfo(sourceaddr);
} }
} }
}
build_udp_url(buf, sizeof(buf), build_udp_url(buf, sizeof(buf),
hostname, rtp_port, s->ssm, source_ip, local_rtp_port, ttl, max_packet_size, hostname, rtp_port, local_rtp_port, ttl, max_packet_size,
connect); connect, sources);
if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
goto fail; goto fail;
if (local_rtp_port>=0 && local_rtcp_port<0) if (local_rtp_port>=0 && local_rtcp_port<0)
local_rtcp_port = ff_udp_get_local_port(s->rtp_hd) + 1; local_rtcp_port = ff_udp_get_local_port(s->rtp_hd) + 1;
build_udp_url(buf, sizeof(buf), build_udp_url(buf, sizeof(buf),
hostname, rtcp_port, s->ssm, source_ip, local_rtcp_port, ttl, max_packet_size, hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size,
connect); connect, sources);
if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
goto fail; goto fail;
...@@ -275,27 +291,8 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size) ...@@ -275,27 +291,8 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size)
continue; continue;
return AVERROR(EIO); return AVERROR(EIO);
} }
if (s->ssm) { if (s->ssm && compare_addr(&from, &s->ssm_addr))
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; 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
}
break; break;
} }
/* then RTP */ /* then RTP */
...@@ -309,27 +306,8 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size) ...@@ -309,27 +306,8 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size)
continue; continue;
return AVERROR(EIO); return AVERROR(EIO);
} }
if (s->ssm) { if (s->ssm && compare_addr(&from, &s->ssm_addr))
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; continue;
}
}
#endif
}
break; break;
} }
} else if (n < 0) { } else if (n < 0) {
......
...@@ -498,8 +498,10 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, ...@@ -498,8 +498,10 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
p += strspn(p, SPACE_CHARS); p += strspn(p, SPACE_CHARS);
if (av_strstart(p, "inline:", &p)) if (av_strstart(p, "inline:", &p))
get_word(rtsp_st->crypto_params, sizeof(rtsp_st->crypto_params), &p); get_word(rtsp_st->crypto_params, sizeof(rtsp_st->crypto_params), &p);
} else if (av_strstart(p, "source-filter", &p) && s->nb_streams > 0) { } else if (av_strstart(p, "source-filter:", &p) && s->nb_streams > 0) {
get_word(buf1, sizeof(buf1), &p); // ignore tag get_word(buf1, sizeof(buf1), &p);
if (strcmp(buf1, "incl"))
return;
get_word(buf1, sizeof(buf1), &p); get_word(buf1, sizeof(buf1), &p);
if (strcmp(buf1, "IN") != 0) if (strcmp(buf1, "IN") != 0)
...@@ -507,14 +509,11 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, ...@@ -507,14 +509,11 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
get_word(buf1, sizeof(buf1), &p); get_word(buf1, sizeof(buf1), &p);
if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6")) if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6"))
return; return;
get_word(buf1, sizeof(buf1), &p); //ignore repeated multicast address // not checking that the destination address actually matches
get_word(buf1, sizeof(buf1), &p); get_word(buf1, sizeof(buf1), &p);
if (get_sockaddr(buf1, &sdp_ip))
return;
rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1]; rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
rtsp_st->ssm = 1; get_word(rtsp_st->source_addr, sizeof(rtsp_st->source_addr), &p);
rtsp_st->source_ip = sdp_ip;
} else { } else {
if (rt->server_type == RTSP_SERVER_WMS) if (rt->server_type == RTSP_SERVER_WMS)
ff_wms_parse_sdp_a_line(s, p); ff_wms_parse_sdp_a_line(s, p);
...@@ -2101,11 +2100,8 @@ static int sdp_read_header(AVFormatContext *s) ...@@ -2101,11 +2100,8 @@ static int sdp_read_header(AVFormatContext *s)
"?localport=%d&ttl=%d&connect=%d", rtsp_st->sdp_port, "?localport=%d&ttl=%d&connect=%d", rtsp_st->sdp_port,
rtsp_st->sdp_ttl, rtsp_st->sdp_ttl,
rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0); rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0);
if (rtsp_st->ssm) { if (rtsp_st->source_addr[0])
getnameinfo((struct sockaddr*) &rtsp_st->source_ip, sizeof(rtsp_st->source_ip), av_strlcatf(url, sizeof(url), "&sources=%s", rtsp_st->source_addr);
namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
av_strlcatf(url, sizeof(url), "&ssm=%s", namebuf);
}
if (ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE, if (ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
&s->interrupt_callback, NULL) < 0) { &s->interrupt_callback, NULL) < 0) {
err = AVERROR_INVALIDDATA; err = AVERROR_INVALIDDATA;
......
...@@ -435,8 +435,7 @@ typedef struct RTSPStream { ...@@ -435,8 +435,7 @@ typedef struct RTSPStream {
//@{ //@{
int sdp_port; /**< port (from SDP content) */ int sdp_port; /**< port (from SDP content) */
struct sockaddr_storage sdp_ip; /**< IP address (from SDP content) */ struct sockaddr_storage sdp_ip; /**< IP address (from SDP content) */
int ssm; /**< Whether the stream should use source-specific multicast or not (from SDP content) */ char source_addr[100]; /**< Source-specific multicast source IP address (from SDP content) */
struct sockaddr_storage source_ip; /**< Source-specific multicast source IP address (from SDP content) */
int sdp_ttl; /**< IP Time-To-Live (from SDP content) */ int sdp_ttl; /**< IP Time-To-Live (from SDP content) */
int sdp_payload_type; /**< payload type */ int sdp_payload_type; /**< payload type */
//@} //@}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment