diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2013-07-20 12:37:25 +0400 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2013-07-20 12:39:53 +0400 |
commit | 48353325372ae7c1721c55bafe33cf0816301a5e (patch) | |
tree | 02c84e6d19e4caba3afb91dbb5771cea7216dcb2 /libavformat/rtpproto.c | |
parent | 73b2043d727029ecde19c1d92bda8411f18b8e55 (diff) | |
parent | 36fb0d02a1faa11eaee51de01fb4061ad6092af9 (diff) |
Merge commit '36fb0d02a1faa11eaee51de01fb4061ad6092af9'
* commit '36fb0d02a1faa11eaee51de01fb4061ad6092af9':
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: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat/rtpproto.c')
-rw-r--r-- | libavformat/rtpproto.c | 128 |
1 files changed, 53 insertions, 75 deletions
diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c index 000bd1e966..33affc31d9 100644 --- a/libavformat/rtpproto.c +++ b/libavformat/rtpproto.c @@ -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) { |