summaryrefslogtreecommitdiff
path: root/libavformat/rtpproto.c
diff options
context:
space:
mode:
authorMartin Storsjö <martin@martin.st>2013-07-18 21:12:14 +0300
committerMartin Storsjö <martin@martin.st>2013-07-19 12:02:09 +0300
commit4d97ca040b40eb4771d1a6cacdb611f61a53afd8 (patch)
treeafc7868d87fdcf641953777f45b83fc0285a0e1b /libavformat/rtpproto.c
parent336353deaad6e4da28665f50a36988b02b55c20c (diff)
rtpproto: Check the source IP if one single source has been specified
If another peer is sending unicast packets to the same port that we are listening on, those packets can end up being received despite using source specific multicast. For those cases, manually check the source address of received packets against the intended source address. This only handles the case when the source list is one single IP address for now, which probably is the most common case. Based on a patch by Ed Torbett. Signed-off-by: Martin Storsjö <martin@martin.st>
Diffstat (limited to 'libavformat/rtpproto.c')
-rw-r--r--libavformat/rtpproto.c58
1 files changed, 57 insertions, 1 deletions
diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c
index 20ffdab491..b050382301 100644
--- a/libavformat/rtpproto.c
+++ b/libavformat/rtpproto.c
@@ -42,7 +42,8 @@
typedef struct RTPContext {
URLContext *rtp_hd, *rtcp_hd;
- int rtp_fd, rtcp_fd;
+ int rtp_fd, rtcp_fd, ssm;
+ struct sockaddr_storage ssm_addr;
} RTPContext;
/**
@@ -75,6 +76,44 @@ int ff_rtp_set_remote_url(URLContext *h, const char *uri)
return 0;
}
+static struct addrinfo* rtp_resolve_host(const char *hostname, int port,
+ int type, int family, int flags)
+{
+ struct addrinfo hints = { 0 }, *res = 0;
+ int error;
+ char service[16];
+
+ snprintf(service, sizeof(service), "%d", port);
+ hints.ai_socktype = type;
+ hints.ai_family = family;
+ 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));
+ }
+
+ 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:
@@ -178,7 +217,20 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
connect = strtol(buf, NULL, 10);
}
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);
+ }
}
}
@@ -238,6 +290,8 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size)
continue;
return AVERROR(EIO);
}
+ if (s->ssm && compare_addr(&from, &s->ssm_addr))
+ continue;
break;
}
/* then RTP */
@@ -251,6 +305,8 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size)
continue;
return AVERROR(EIO);
}
+ if (s->ssm && compare_addr(&from, &s->ssm_addr))
+ continue;
break;
}
} else if (n < 0) {