[vlc-devel] [PATCH 6/7] mdns: Add basic ip address detection (Linux)

Roland Bewick roland.bewick at gmail.com
Sun Aug 4 07:55:49 CEST 2019


On 2/08/2019 4:19 PM, Marvin Scholz wrote:
>
>
> On 2 Aug 2019, at 8:03, Thomas Guillem wrote:
>
>> On Wed, Jul 31, 2019, at 08:35, Roland Bewick wrote:
>>>
>>> On 27/07/2019 2:04 PM, Roland Bewick wrote:
>>>>
>>>> On 26/07/2019 1:07 AM, Rémi Denis-Courmont wrote:
>>>>> Le torstaina 25. heinäkuuta 2019, 20.51.09 EEST Roland Bewick a 
>>>>> écrit :
>>>>>> On Fri, 26 Jul 2019 at 12:15 AM, Rémi Denis-Courmont 
>>>>>> <remi at remlab.net>
>>>>>>
>>>>>> wrote:
>>>>>>> Le torstaina 25. heinäkuuta 2019, 8.39.11 EEST Roland Bewick a 
>>>>>>> écrit :
>>>>>>>> On 24/07/2019 11:18 PM, Rémi Denis-Courmont wrote:
>>>>>>>>> Le keskiviikkona 24. heinäkuuta 2019, 19.10.50 EEST Roland 
>>>>>>>>> Bewick a
>>>>>>> écrit
>>>>>>>
>>>>>>>>>> Hi Rémi,
>>>>>>>>>>
>>>>>>>>>> Thanks for the reply.
>>>>>>>>>>
>>>>>>>>>> On 24/07/2019 10:59 PM, Rémi Denis-Courmont wrote:
>>>>>>>>>>> Le keskiviikkona 24. heinäkuuta 2019, 18.43.49 EEST Roland
>>>>>>>>>>> Bewick a
>>>>>>>>>>> écrit
>>>>>>>>>>>
>>>>>>>>>>>> ---
>>>>>>>>>>>>
>>>>>>>>>>>>     modules/services_discovery/microdns.c | 62
>>>>>>>>>>>>
>>>>>>>>>>>> +++++++++++++++++++++++++++++++++-- 1 file changed, 59
>>>>>>> insertions(+), 3
>>>>>>>
>>>>>>>>>>>> deletions(-)
>>>>>>>>>>>>
>>>>>>>>>>>> diff --git a/modules/services_discovery/microdns.c
>>>>>>>>>>>> b/modules/services_discovery/microdns.c index
>>>>>>>>>>>> c460126b58..fa34ffa8d8
>>>>>>>>>>>> 100644
>>>>>>>>>>>> --- a/modules/services_discovery/microdns.c
>>>>>>>>>>>> +++ b/modules/services_discovery/microdns.c
>>>>>>>>>>>> @@ -28,6 +28,12 @@
>>>>>>>>>>>>
>>>>>>>>>>>>     #include <stdatomic.h>
>>>>>>>>>>>>     #include <assert.h>
>>>>>>>>>>>>
>>>>>>>>>>>> +#if defined( _WIN32 )
>>>>>>>>>>>> +
>>>>>>>>>>>> +#else
>>>>>>>>>>>> +    #include <ifaddrs.h>
>>>>>>>>>>>> +#endif
>>>>>>>>>>>> +
>>>>>>>>>>>>
>>>>>>>>>>>>     #include <vlc_common.h>
>>>>>>>>>>>>     #include <vlc_plugin.h>
>>>>>>>>>>>>     #include <vlc_modules.h>
>>>>>>>>>>>>
>>>>>>>>>>>> @@ -868,9 +874,59 @@ CloseRD( vlc_object_t *p_this )
>>>>>>>>>>>>
>>>>>>>>>>>>         CleanDiscoveryCommon( p_sys );
>>>>>>>>>>>>         }
>>>>>>>>>>>>
>>>>>>>>>>>> -static char * detect_ip_address()
>>>>>>>>>>>> +static char * detect_ip_address( vlc_object_t *p_obj )
>>>>>>>>>>>>
>>>>>>>>>>>>     {
>>>>>>>>>>>>
>>>>>>>>>>>> -    return strdup("127.0.0.1"); /* TODO: actually detect ip
>>>>>>> address */
>>>>>>>
>>>>>>>>>>>> +    char result[16] = "127.0.0.1";
>>>>>>>>>>>> +    bool found = false;
>>>>>>>>>>>> +#if defined( _WIN32 )
>>>>>>>>>>>> +
>>>>>>>>>>>> +#else
>>>>>>>>>>>> +    struct ifaddrs *id;
>>>>>>>>>>>> +    if( getifaddrs( &id ) == 0 )
>>>>>>>>>>>> +    {
>>>>>>>>>>>> +        int selected_priority = 0;
>>>>>>>>>>>> +
>>>>>>>>>>>> +        for( ; id != NULL; id = id->ifa_next )
>>>>>>>>>>>> +        {
>>>>>>>>>>>> +            if( id->ifa_addr->sa_family == AF_INET )
>>>>>>>>>>>> +            {
>>>>>>>>>>>> +                struct sockaddr_in *addr_in = (struct
>>>>>>>>>>>> sockaddr_in
>>>>>>>>>>>> *)id->ifa_addr; +
>>>>>>>>>>>> +                char *ip_address = inet_ntoa(
>>>>>>>>>>>> addr_in->sin_addr );
>>>>>>>>>>>> +
>>>>>>>>>>>> +                /* TODO: smarter priority function. */
>>>>>>>>>>>> +                int priority = 0;
>>>>>>>>>>>> +                if( strncmp( "eth0", id->ifa_name, strlen(
>>>>>>>>>>>> "eth0"
>>>>>>> ) )
>>>>>>>
>>>>>>>>>>>> ==
>>>>>>>>>>>> 0
>>>>>>>>>>>> ) +                {
>>>>>>>>>>>> +                    priority = 1000;
>>>>>>>>>>>> +                }
>>>>>>>>>>>> +                else if( strncmp( "wifi0", id->ifa_name, 
>>>>>>>>>>>> strlen(
>>>>>>>>>>>> "wifi0"
>>>>>>>>>>>> )
>>>>>>>>>>>> ) == 0 ) +                {
>>>>>>>>>>>> +                    priority = 2000;
>>>>>>>>>>>> +                }
>>>>>>>>>>>> +
>>>>>>>>>>>> +                msg_Dbg( p_obj, "Assigned interface %s 
>>>>>>>>>>>> priority
>>>>>>> %d",
>>>>>>>
>>>>>>>>>>>> + id->ifa_name, priority);
>>>>>>>>>>>> +
>>>>>>>>>>>> +                if( priority > selected_priority )
>>>>>>>>>>>> +                {
>>>>>>>>>>>> +                    strcpy( result, ip_address );
>>>>>>>>>>>> +                    selected_priority = priority;
>>>>>>>>>>>> +                    found = true;
>>>>>>>>>>>> +                }
>>>>>>>>>>>> +            }
>>>>>>>>>>>> +        }
>>>>>>>>>>>> +    }
>>>>>>>>>>>> +    else
>>>>>>>>>>>> +    {
>>>>>>>>>>>> +        msg_Err( p_obj, "Couldn't get interface addresses");
>>>>>>>>>>>> +    }
>>>>>>>>>>> That could have worked in the nineties. Machines, especially
>>>>>>>>>>> laptops,
>>>>>>>>>>> change IP addresses and have multiple addresses routinely
>>>>>>>>>>> nowadays,
>>>>>>> and
>>>>>>>
>>>>>>>>>>> Linux desktops interfaces are not always called eth0 or wifi0.
>>>>>>>>>> I will take Alexandre's suggestion.
>>>>>>>>>>
>>>>>>>>>>> Besides, you need to respond with the correct IP address for 
>>>>>>>>>>> the
>>>>>>>>>>> interface
>>>>>>>>>>> on which the request came, usually with 
>>>>>>>>>>> IP_PKTINFO/IP6_PKTINFO if
>>>>>>>>>>> you
>>>>>>>>>>> use
>>>>>>>>>>> UDP.
>>>>>>>>>> Respond to what? I don't understand.
>>>>>>>>> Typically, discovery protocols wait for inbound client requests.
>>>>>>>> Oh - so I don't even have to do the detection myself. Great!
>>>>>>> You should never do detection.
>>>>>>>
>>>>>>> For unsolicited announcements, you should either enumerate all
>>>>>>> eligible
>>>>>>> interfaces and spam all of them, or leave the IP stack routing
>>>>>>> table to
>>>>>>> pick
>>>>>>> the correct one at a given time.
>>>>>>>
>>>>>>> For responses to unicast, you should copy the destination IP of the
>>>>>>> request as
>>>>>>> the source IP of the response.
>>>>>>>
>>>>>>> And for responses to multicast, you should again let the IP stack
>>>>>>> routing
>>>>>>> table pick the correct source address for the inbound interface.
>>>>>>>
>>>>>>> In any case, that can only work with packet info ancillary data.
>>>>>>> There are
>>>>>>> no
>>>>>>> reason to write OS-specific code here.
>>>>>> In this case we are responding to multicast (works currently as you
>>>>>> mentioned above I think) BUT also we are providing a unicast ip
>>>>>> address in
>>>>>> the A/AAAA record in the response packet.
>>>>>> The relationship between the unicast address and the multicast
>>>>>> response is
>>>>>> that they share the same interface. Right?
>>>>> Multicast addresses do not have an interface; you can have the same
>>>>> multicast
>>>>> addresses on different interfaces referring to the same or to
>>>>> different actual
>>>>> group(s). AFAIK, you have to get the correct interface index from the
>>>>> incoming
>>>>> packet ancillary data.
>>>> Ok, thanks for the information.
>>>>
>>>> libmicrodns scans all interface addresses on initialisation and for
>>>> each valid one opens a socket.
>>>>
>>>> Each socket and interface [address (linux) / index (Windows)] are
>>>> paired so when we get an incoming packet we know what interface it is.
>>>> Therefore, I don't think we have to deal with packet ancillary data?
>>>>
>>>> The problem though is getting the unicast address for that interface
>>>> so we can put it in the response body (A/AAAA record).
>>>>
>>>> If I'm correct, this needs to be calculated on Windows which will
>>>> require OS-specific code. Then I will update libmicrodns to pass the
>>>> IP address string to the callback so VLC can use it to populate the
>>>> A/AAAA record.
>>>>
>>>> Does this sound like a valid approach?
>>>>
>>>> Thanks,
>>>>
>>>> Roland
>>>
>>>
>>> Hi,
>>>
>>> I've made the necessary changes to libmicrodns. My pull request is
>>> here:
>>> https://github.com/videolabs/libmicrodns/pull/20/commits/fb58b2fffdce80be6381431845fc8e743920e054 
>>>
>>
>> Hello, I will do the review on libmicrodns.
Thanks Thomas
>>
>> I have one question though. Will it be possible to do the same with 
>> avahi (used by default on linux Desktop) and bonjour (used by macOS) ?
>>
>
> On macOS/iOS you would do something like:
>
>     NSNetService *service = [[NSNetService alloc] 
> initWithDomain:@"local."
> type:@"_http._tcp."
> name:@"VLC media player something"
> port:8080];
>     [service publish];
>
> (We probably want to use CFNetServices instead as that is pure C, but 
> it works really similar)
>
> It seems to work similar for avahi, see
> https://www.avahi.org/doxygen/html/publish_8h.html#acb05a7d3d23a3b825ca77cb1c7d00ce4 
>
> When passing NULL for host, the daemon will use the local host name, 
> just like what
> happens in the above snippet for macOS/iOS.
>
> So we do not have to worry about which exact addresses to announce at 
> all there.


libmicrodns is our cross-platform solution for mDNS discovery / 
advertisement. Why do we need to write specific code for Avahi / Bonjour 
implementations?

I've tested service discovery on Linux and Windows and it works. I have 
no access to macOS.


>
>>>
>>> Please have a look and let me know if it's a viable solution.
>>>
>>> Thanks,
>>>
>>> Roland
>>>
>>> _______________________________________________
>>> vlc-devel mailing list
>>> To unsubscribe or modify your subscription options:
>>> https://mailman.videolan.org/listinfo/vlc-devel
>> _______________________________________________
>> vlc-devel mailing list
>> To unsubscribe or modify your subscription options:
>> https://mailman.videolan.org/listinfo/vlc-devel
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list