When using ffmpeg to start a local-only server (i.e. setting ttl=0) using multicast ip (i.e. 224.1.1.1) you can see packets going to network. Bug is due to kernel handling multicast ttl 0 differently (as noted in kernel code net/ipv4/route.c:2191 see: https://github.com/torvalds/linux/blob/master/net/ipv4/route.c ) /* Special hack: user can direct multicasts and limited broadcast via necessary interface without fiddling with IP_MULTICAST_IF or IP_PKTINFO. This hack is not just for fun, it allows vic,vat and friends to work. They bind socket to loopback, set ttl to zero and expect that it will work. From the viewpoint of routing cache they are broken, because we are not allowed to build multicast path with loopback source addr (look, routing cache cannot know, that ttl is zero, so that packet will not leave this host and route is valid). Luckily, this hack is good workaround. */
Signed-off-by: Omid Ghaffarinia <omid.ghaffari...@gmail.com> --- libavformat/sdp.c | 2 +- libavformat/udp.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/libavformat/sdp.c b/libavformat/sdp.c index 01b564b..0401f7a 100644 --- a/libavformat/sdp.c +++ b/libavformat/sdp.c @@ -61,7 +61,7 @@ static void sdp_write_address(char *buff, int size, const char *dest_addr, if (dest_addr) { if (!dest_type) dest_type = "IP4"; - if (ttl > 0 && !strcmp(dest_type, "IP4")) { + if (ttl >= 0 && !strcmp(dest_type, "IP4")) { /* The TTL should only be specified for IPv4 multicast addresses, * not for IPv6. */ av_strlcatf(buff, size, "c=IN %s %s/%d\r\n", dest_type, dest_addr, ttl); diff --git a/libavformat/udp.c b/libavformat/udp.c index 8699c1c..fe46ba5 100644 --- a/libavformat/udp.c +++ b/libavformat/udp.c @@ -176,6 +176,28 @@ static int udp_set_multicast_ttl(int sockfd, int mcastTTL, } } #endif + if (mcastTTL == 0) { +#ifdef IP_MULTICAST_IF + if (addr->sa_family == AF_INET) { + struct in_addr localhost_addr; + inet_pton(AF_INET, "127.0.0.1", &localhost_addr); + if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, &localhost_addr, sizeof(localhost_addr)) < 0) { + log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_IF)"); + return -1; + } + } +#endif +#if defined(IPPROTO_IPV6) && defined(IPV6_MULTICAST_IF) + if (addr->sa_family == AF_INET6) { + struct in6_addr localhost_addr; + inet_pton(AF_INET6, "::1", &localhost_addr); + if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &localhost_addr, sizeof(localhost_addr)) < 0) { + log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_IF)"); + return -1; + } + } +#endif + } return 0; } @@ -882,6 +904,12 @@ static int udp_open(URLContext *h, const char *uri, int flags) } if (h->flags & AVIO_FLAG_READ) { /* input */ + if (s->ttl == 0) { + if (s->dest_addr.ss_family == AF_INET) + inet_pton(AF_INET, "127.0.0.1", &((struct sockaddr_in *)&s->local_addr_storage)->sin_addr); + else + inet_pton(AF_INET6, "::1", &((struct sockaddr_in6 *)&s->local_addr_storage)->sin6_addr); + } if (num_include_sources && num_exclude_sources) { av_log(h, AV_LOG_ERROR, "Simultaneously including and excluding multicast sources is not supported\n"); goto fail; -- 1.7.9.5 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel