[vlc-devel] [PATCH 3/3] Add microdns services_advertisement submodule

Roland Bewick roland.bewick at gmail.com
Tue Sep 3 16:30:05 CEST 2019


On 2/09/2019 7:14 PM, Thomas Guillem wrote:
>
> On Mon, Sep 2, 2019, at 07:25, Roland Bewick wrote:
>> ---
>>   modules/services_discovery/microdns.c | 318 +++++++++++++++++++++-----
>>   1 file changed, 261 insertions(+), 57 deletions(-)
>>
>> diff --git a/modules/services_discovery/microdns.c
>> b/modules/services_discovery/microdns.c
>> index ad0d2691f7..d5dc5bda94 100644
>> --- a/modules/services_discovery/microdns.c
>> +++ b/modules/services_discovery/microdns.c
>> @@ -33,6 +33,7 @@
>>   #include <vlc_modules.h>
>>   #include <vlc_services_discovery.h>
>>   #include <vlc_renderer_discovery.h>
>> +#include <vlc_services_advertisement.h>
>>   
>>   #include <microdns/microdns.h>
>>   
>> @@ -40,6 +41,8 @@ static int OpenSD( vlc_object_t * );
>>   static void CloseSD( vlc_object_t * );
>>   static int OpenRD( vlc_object_t * );
>>   static void CloseRD( vlc_object_t * );
>> +static int OpenSA( vlc_object_t * );
>> +static void CloseSA( vlc_object_t * );
>>   
>>   VLC_SD_PROBE_HELPER( "microdns", N_("mDNS Network Discovery"), SD_CAT_LAN )
>>   VLC_RD_PROBE_HELPER( "microdns_renderer", "mDNS renderer Discovery" )
>> @@ -69,6 +72,14 @@ vlc_module_begin()
>>           set_callbacks( OpenRD, CloseRD )
>>           add_shortcut( "mdns_renderer", "microdns_renderer" )
>>           VLC_RD_PROBE_SUBMODULE
>> +    add_submodule() \
>> +        set_description( N_( "mDNS Services Advertisement" ) )
>> +        set_category( CAT_ADVANCED )
>> +        set_subcategory( SUBCAT_ADVANCED_NETWORK )
>> +        set_capability( "services_advertisement", 0 )
>> +        set_callbacks( OpenSA, CloseSA )
>> +        add_shortcut( "mdns", "microdns" )
>> +        VLC_RD_PROBE_SUBMODULE
>>   vlc_module_end ()
>>   
>>   static const struct
>> @@ -87,16 +98,37 @@ static const struct
>>   };
>>   #define NB_PROTOCOLS (sizeof(protocols) / sizeof(*protocols))
>>   
>> +/*
>> + * Services advertisement configuration
>> + */
>> +char sa_domain_name[] = "vlc.local"; /* Announce our service on this
>> domain name*/
>> +char sa_service_type[] = "_vlc._tcp.local"; /* respond to PTR query of
>> this type */
>> +char sa_service_type_link[] = "vlc VLC._vlc._tcp.local"; /* link
>> service type to domain */
> These 3 char * should be const and static.

I was trying to sneakily get around having to duplicate them when 
assigning them to the answer records :D

>
>> +
>>   struct discovery_sys
>>   {
>> -    vlc_thread_t        thread;
>> -    atomic_bool         stop;
>> -    struct mdns_ctx *   p_microdns;
>>       const char *        ppsz_service_names[NB_PROTOCOLS];
>>       unsigned int        i_nb_service_names;
>>       vlc_array_t         items;
>>   };
>>   
>> +struct advertisement_sys
>> +{
>> +    int i_http_port;
>> +};
>> +
>> +struct microdns_sys
>> +{
>> +    vlc_thread_t        thread;
>> +    atomic_bool         stop;
>> +    struct mdns_ctx *   p_microdns;
>> +    union
>> +    {
>> +        struct discovery_sys discovery_sys;
>> +        struct advertisement_sys advertisement_sys;
>> +    };
>> +};
>> +
>>   struct item
>>   {
>>       char *              psz_uri;
>> @@ -383,7 +415,7 @@ static void
>>   new_entries_sd_cb( void *p_this, int i_status, const struct rr_entry
>> *p_entries )
>>   {
>>       services_discovery_t *p_sd = (services_discovery_t *)p_this;
>> -    struct discovery_sys *p_sys = p_sd->p_sys;
>> +    struct microdns_sys *p_sys = p_sd->p_sys;
> If you do
>
> struct microdns_sys *p_mdns_sys = p_sd->p_sys;
> struct discovery_sys *p_sys = p_mdns_sys->p_sys;
>
> You won't have to modify every access of discovery_sys. The diff will be smaller and easier to read.
Ok, will do.
>
>
>>       if( i_status < 0 )
>>       {
>>           print_error( VLC_OBJECT( p_sd ), "entry callback", i_status );
>> @@ -408,12 +440,12 @@ new_entries_sd_cb( void *p_this, int i_status,
>> const struct rr_entry *p_entries
>>           if( psz_uri == NULL )
>>               break;
>>   
>> -        if( items_exists( p_sys, psz_uri ) )
>> +        if( items_exists( &p_sys->discovery_sys, psz_uri ) )
>>           {
>>               free( psz_uri );
>>               continue;
>>           }
>> -        items_add_input( p_sys, p_sd, psz_uri, p_srv->psz_device_name
>> );
>> +        items_add_input( &p_sys->discovery_sys, p_sd, psz_uri,
>> p_srv->psz_device_name );
>>       }
>>   
>>       for( unsigned int i = 0; i < i_nb_srv; ++i )
>> @@ -426,13 +458,13 @@ static bool
>>   stop_sd_cb( void *p_this )
>>   {
>>       services_discovery_t *p_sd = ( services_discovery_t* )p_this;
>> -    struct discovery_sys *p_sys = p_sd->p_sys;
>> +    struct microdns_sys *p_sys = p_sd->p_sys;
>>   
>>       if( atomic_load( &p_sys->stop ) )
>>           return true;
>>       else
>>       {
>> -        items_timeout( p_sys, p_sd, NULL );
>> +        items_timeout( &p_sys->discovery_sys, p_sd, NULL );
>>           return false;
>>       }
>>   }
>> @@ -441,11 +473,11 @@ static void *
>>   RunSD( void *p_this )
>>   {
>>       services_discovery_t *p_sd = ( services_discovery_t* )p_this;
>> -    struct discovery_sys *p_sys = p_sd->p_sys;
>> +    struct microdns_sys *p_sys = p_sd->p_sys;
>>   
>>       int i_status = mdns_listen( p_sys->p_microdns,
>> -                                p_sys->ppsz_service_names,
>> -                                p_sys->i_nb_service_names,
>> +                                p_sys->discovery_sys.ppsz_service_names,
>> +                                p_sys->discovery_sys.i_nb_service_names,
>>                                   RR_PTR, SEC_FROM_VLC_TICK(LISTEN_INTERVAL),
>>                                   stop_sd_cb, new_entries_sd_cb, p_sd );
>>   
>> @@ -459,7 +491,7 @@ static void
>>   new_entries_rd_cb( void *p_this, int i_status, const struct rr_entry
>> *p_entries )
>>   {
>>       vlc_renderer_discovery_t *p_rd = (vlc_renderer_discovery_t
>> *)p_this;
>> -    struct discovery_sys *p_sys = p_rd->p_sys;
>> +    struct microdns_sys *p_sys = p_rd->p_sys;
>>       if( i_status < 0 )
>>       {
>>           print_error( VLC_OBJECT( p_rd ), "entry callback", i_status );
>> @@ -506,7 +538,7 @@ new_entries_rd_cb( void *p_this, int i_status,
>> const struct rr_entry *p_entries
>>           if( psz_uri == NULL )
>>               break;
>>   
>> -        if( items_exists( p_sys, psz_uri ) )
>> +        if( items_exists( &p_sys->discovery_sys, psz_uri ) )
>>           {
>>               free( psz_uri );
>>               continue;
>> @@ -523,8 +555,8 @@ new_entries_rd_cb( void *p_this, int i_status,
>> const struct rr_entry *p_entries
>>           if( strcmp( p_srv->psz_protocol, "chromecast" ) == 0)
>>               psz_demux_filter = "cc_demux";
>>   
>> -        items_add_renderer( p_sys, p_rd, p_srv->psz_device_name,
>> psz_uri,
>> -                            psz_demux_filter, psz_icon_uri,
>> +        items_add_renderer( &p_sys->discovery_sys, p_rd,
>> p_srv->psz_device_name,
>> +                            psz_uri, psz_demux_filter, psz_icon_uri,
>>                               p_srv->i_renderer_flags );
>>           free(psz_icon_uri);
>>       }
>> @@ -538,13 +570,13 @@ static bool
>>   stop_rd_cb( void *p_this )
>>   {
>>       vlc_renderer_discovery_t *p_rd = p_this;
>> -    struct discovery_sys *p_sys = p_rd->p_sys;
>> +    struct microdns_sys *p_sys = p_rd->p_sys;
>>   
>>       if( atomic_load( &p_sys->stop ) )
>>           return true;
>>       else
>>       {
>> -        items_timeout( p_sys, NULL, p_rd );
>> +        items_timeout( &p_sys->discovery_sys, NULL, p_rd );
>>           return false;
>>       }
>>   }
>> @@ -553,11 +585,11 @@ static void *
>>   RunRD( void *p_this )
>>   {
>>       vlc_renderer_discovery_t *p_rd = p_this;
>> -    struct discovery_sys *p_sys = p_rd->p_sys;
>> +    struct microdns_sys *p_sys = p_rd->p_sys;
>>   
>>       int i_status = mdns_listen( p_sys->p_microdns,
>> -                                p_sys->ppsz_service_names,
>> -                                p_sys->i_nb_service_names,
>> +                                p_sys->discovery_sys.ppsz_service_names,
>> +                                p_sys->discovery_sys.i_nb_service_names,
>>                                   RR_PTR, SEC_FROM_VLC_TICK(LISTEN_INTERVAL),
>>                                   stop_rd_cb, new_entries_rd_cb, p_rd );
>>   
>> @@ -567,62 +599,195 @@ RunRD( void *p_this )
>>       return NULL;
>>   }
>>   
>> -static int
>> -OpenCommon( vlc_object_t *p_obj, struct discovery_sys *p_sys, bool b_renderer )
>> +static void
>> +request_sa_callback(void *cbarg, int r, const struct mdns_ip *mdns_ip,
>> +                    const struct rr_entry *entry)
>>   {
>> -    int i_ret = VLC_EGENERIC;
>> -    atomic_init( &p_sys->stop, false );
>> -    vlc_array_init( &p_sys->items );
>> +    VLC_UNUSED( r );  /* result code from mdns_recv */
>>   
>> -    /* Listen to protocols that are handled by VLC */
>> -    for( unsigned int i = 0; i < NB_PROTOCOLS; ++i )
>> +    services_advertisement_t *p_sa = ( services_advertisement_t*
>> )cbarg;
>> +    struct microdns_sys *p_sys = p_sa->p_sys;
>> +    struct mdns_ctx *ctx = p_sys->p_microdns;
>> +    struct mdns_hdr hdr = {0};  /* response header */
>> +
>> +    if( entry->type != RR_PTR || entry->rr_class != RR_IN )
>>       {
>> -        if( protocols[i].b_renderer == b_renderer )
>> -            p_sys->ppsz_service_names[p_sys->i_nb_service_names++] =
>> -                protocols[i].psz_service_name;
>> +        msg_Dbg( VLC_OBJECT( p_sa ),
>> +                 "mDNS-SA: Skipped unsupported request type: %d class:
>> %d\n",
>> +                 entry->type,
>> +                 entry->rr_class );
>> +        return;
>> +    }
>> +
>> +    /*
>> +     * When we receive a PTR record (question) from an mDNS client we
>> need to
>> +     * answer with four record types that will allow our domain name
>> (vlc.local)
>> +     * to resolve the IP address and port we are hosting the VLC
>> interface on.
>> +     *
>> +     * PTR: point service type (_vlc._tcp._local) to local domain
>> +     * TXT: provide additional information (HTTP server root directory
>> etc.)
>> +     * SRV: provide server information (port number etc.)
>> +     * A: link local domain to IP address
>> +     */
>> +
>> +    struct rr_entry answers[4] = {0};  /* PTR, TXT, SRV, A */
>> +
>> +    hdr.flags |= FLAG_QR;
>> +    hdr.flags |= FLAG_AA;
>> +
>> +    hdr.num_ans_rr = sizeof( answers ) / sizeof( answers[0] );
>> +
>> +    for( int i = 0; i < hdr.num_ans_rr; i++ )
>> +    {
>> +            answers[i].rr_class = RR_IN;
>> +            answers[i].ttl      = 120;
>> +
>> +            if (i + 1 < hdr.num_ans_rr)
>> +                    answers[i].next = &answers[i + 1];
>>       }
>>   
>> -    if( p_sys->i_nb_service_names == 0 )
>> +    // RR_PTR: point service type to local domain and instance name
>> (VLC)
>> +    answers[0].type     = RR_PTR;
>> +    answers[0].name     = sa_service_type;
>> +    answers[0].data.PTR.domain = sa_service_type_link;
>> +
>> +    // RR_TXT: provide additional information (HTTP server root
>> directory etc.)
>> +    answers[1].type     = RR_TXT;
>> +    answers[1].name     = sa_service_type_link;
>> +
>> +    // RR_SRV: provide info about the service we're announcing (port
>> no, etc.)
>> +    answers[2].type     = RR_SRV;
>> +    answers[2].name     = sa_service_type_link;
>> +    answers[2].data.SRV.port = p_sys->advertisement_sys.i_http_port;
>> +    answers[2].data.SRV.priority = 0;
>> +    answers[2].data.SRV.weight = 0;
>> +    answers[2].data.SRV.target = sa_domain_name;
>> +
>> +    // RR_A/AAAA: link .local domain to IP address
>> +    answers[3].name     = sa_domain_name;
>> +    if (mdns_ip->family == AF_INET)
>>       {
>> -        msg_Err( p_obj, "no services found" );
>> -        goto error;
>> +            answers[3].type     = RR_A;
>> +            memcpy(&answers[3].data.A.addr, &mdns_ip->ipv4,
>> +                    sizeof(answers[3].data.A.addr));
>>       }
>> -    for( unsigned int i = 0; i < p_sys->i_nb_service_names; ++i )
>> -        msg_Dbg( p_obj, "mDNS: listening to %s %s",
>> p_sys->ppsz_service_names[i],
>> -                 b_renderer ? "renderer" : "service" );
>> +    else
>> +    {
>> +            answers[3].type     = RR_AAAA;
>> +            memcpy(&answers[3].data.AAAA.addr, &mdns_ip->ipv6,
>> +                    sizeof(answers[3].data.AAAA.addr));
>> +    }
>> +
>> +    mdns_entries_send(ctx, &hdr, answers);
>> +}
>> +
>> +static bool
>> +stop_sa_cb( void *cbarg )
>> +{
>> +    services_advertisement_t *p_sa = ( services_advertisement_t*
>> )cbarg;
>> +    struct microdns_sys *p_sys = p_sa->p_sys;
>> +
>> +    return atomic_load( &p_sys->stop );
>> +}
>> +
>> +static void *
>> +RunSA( void *p_this )
>> +{
>> +    services_advertisement_t *p_sa = ( services_advertisement_t*
>> )p_this;
>> +    struct microdns_sys *p_sys = p_sa->p_sys;
>>   
>>       int i_status;
>> -    if( ( i_status = mdns_init( &p_sys->p_microdns, MDNS_ADDR_IPV4,
>> +
>> +    i_status = mdns_announce( p_sys->p_microdns,
>> +                              sa_service_type,
>> +                              RR_PTR,
>> +                              request_sa_callback,
>> +                              p_sa);
>> +
>> +    if( i_status < 0 )
>> +        print_error( VLC_OBJECT( p_sa ), "announce", i_status );
>> +
>> +    i_status = mdns_serve(p_sys->p_microdns, stop_sa_cb, p_sa);
>> +
>> +    return NULL;
>> +}
>> +
>> +static void
>> +CleanCommon( struct microdns_sys *p_sys )
>> +{
>> +    if ( p_sys->p_microdns )
>> +        mdns_destroy( p_sys->p_microdns );
>> +    free( p_sys );
>> +}
>> +
>> +static void
>> +CleanDiscoveryCommon( struct microdns_sys *p_sys )
>> +{
>> +    items_clear( &p_sys->discovery_sys );
>> +    CleanCommon( p_sys );
>> +}
>> +
>> +
>> +static void CloseCommon( struct microdns_sys *p_sys )
>> +{
>> +    atomic_store( &p_sys->stop, true );
>> +    vlc_join( p_sys->thread, NULL );
>> +}
>> +
>> +static int
>> +OpenCommon( vlc_object_t *p_obj, struct microdns_sys *p_sys,
>> +            const char *mdns_addr, void *(*entry)(void *) )
>> +{
>> +    int i_ret = VLC_EGENERIC;
>> +    atomic_init( &p_sys->stop, false );
>> +
>> +    int i_status;
>> +    if( ( i_status = mdns_init( &p_sys->p_microdns, mdns_addr,
>>                                   MDNS_PORT ) ) < 0 )
>>       {
>>           print_error( p_obj, "init", i_status );
>>           goto error;
>>       }
>>   
>> -    if( vlc_clone( &p_sys->thread, b_renderer ? RunRD : RunSD, p_obj,
>> -                   VLC_THREAD_PRIORITY_LOW) )
>> +    if( vlc_clone( &p_sys->thread, entry, p_obj, VLC_THREAD_PRIORITY_LOW) )
>>       {
>> -        msg_Err( p_obj, "Can't run the lookup thread" );
>> +        msg_Err( p_obj, "Can't run the mdns thread");
>>           goto error;
>>       }
>>   
>>       return VLC_SUCCESS;
>>   error:
>> -    if( p_sys->p_microdns != NULL )
>> -        mdns_destroy( p_sys->p_microdns );
>> -    free( p_sys );
>> +    CleanCommon( p_sys );
>>       return i_ret;
>>   }
>>   
>> -static void
>> -CleanCommon( struct discovery_sys *p_sys )
>> +static int OpenDiscoveryCommon( vlc_object_t *p_obj, struct
>> microdns_sys *p_sys,
>> +                               bool b_renderer, void *(*entry)(void *)
>> )
>>   {
>> -    atomic_store( &p_sys->stop, true );
>> -    vlc_join( p_sys->thread, NULL );
>> +    int i_ret = VLC_EGENERIC;
>> +    struct discovery_sys *discovery_sys = &p_sys->discovery_sys;
>>   
>> -    items_clear( p_sys );
>> -    mdns_destroy( p_sys->p_microdns );
>> -    free( p_sys );
>> +    vlc_array_init( &discovery_sys->items );
>> +    /* Listen to protocols that are handled by VLC */
>> +    for( unsigned int i = 0; i < NB_PROTOCOLS; ++i )
>> +    {
>> +        if( protocols[i].b_renderer == b_renderer )
>> +
>> discovery_sys->ppsz_service_names[discovery_sys->i_nb_service_names++] =
>> +                protocols[i].psz_service_name;
>> +    }
>> +    if( discovery_sys->i_nb_service_names == 0 )
>> +    {
>> +        msg_Err( p_obj, "no services found" );
>> +        goto error;
>> +    }
>> +    for( unsigned int i = 0; i < discovery_sys->i_nb_service_names;
>> ++i )
>> +        msg_Dbg( p_obj, "mDNS: listening to %s %s",
>> discovery_sys->ppsz_service_names[i],
>> +                b_renderer ? "renderer" : "service" );
>> +
>> +    return OpenCommon( p_obj, p_sys, MDNS_ADDR_IPV4, entry );
>> +error:
>> +    CleanCommon( p_sys );
>> +    return i_ret;
>>   }
>>   
>>   static int
>> @@ -630,7 +795,7 @@ OpenSD( vlc_object_t *p_obj )
>>   {
>>       services_discovery_t *p_sd = (services_discovery_t *)p_obj;
>>   
>> -    struct discovery_sys *p_sys = calloc( 1, sizeof(struct discovery_sys) );
>> +    struct microdns_sys *p_sys = calloc( 1, sizeof(struct microdns_sys) );
>>       if( !p_sys )
>>           return VLC_ENOMEM;
>>       p_sd->p_sys = p_sys;
>> @@ -638,16 +803,17 @@ OpenSD( vlc_object_t *p_obj )
>>       p_sd->description = _("mDNS Network Discovery");
>>       config_ChainParse( p_sd, CFG_PREFIX, ppsz_options, p_sd->p_cfg );
>>   
>> -    return OpenCommon( p_obj, p_sys, false );
>> +    return OpenDiscoveryCommon( p_obj, p_sys, false, RunSD );
>>   }
>>   
>>   static void
>>   CloseSD( vlc_object_t *p_this )
>>   {
>>       services_discovery_t *p_sd = (services_discovery_t *) p_this;
>> -    struct discovery_sys *p_sys = p_sd->p_sys;
>> +    struct microdns_sys *p_sys = p_sd->p_sys;
>>   
>> -    CleanCommon( p_sys );
>> +    CloseCommon( p_sys );
>> +    CleanDiscoveryCommon( p_sys );
>>   }
>>   
>>   static int
>> @@ -655,21 +821,59 @@ OpenRD( vlc_object_t *p_obj )
>>   {
>>       vlc_renderer_discovery_t *p_rd = (vlc_renderer_discovery_t *)p_obj;
>>   
>> -    struct discovery_sys *p_sys = calloc( 1, sizeof(struct discovery_sys) );
>> +    struct microdns_sys *p_sys = calloc( 1, sizeof(struct microdns_sys) );
>>       if( !p_sys )
>>           return VLC_ENOMEM;
>>       p_rd->p_sys = p_sys;
>>   
>>       config_ChainParse( p_rd, CFG_PREFIX, ppsz_options, p_rd->p_cfg );
>>   
>> -    return OpenCommon( p_obj, p_sys, true );
>> +    return OpenDiscoveryCommon( p_obj, p_sys, true, RunRD );
>>   }
>>   
>>   static void
>>   CloseRD( vlc_object_t *p_this )
>>   {
>>       vlc_renderer_discovery_t *p_rd = (vlc_renderer_discovery_t *) p_this;
>> -    struct discovery_sys *p_sys = p_rd->p_sys;
>> +    struct microdns_sys *p_sys = p_rd->p_sys;
>> +
>> +    CloseCommon( p_sys );
>> +    CleanDiscoveryCommon( p_sys );
>> +}
>> +
>> +static int
>> +OpenSA( vlc_object_t *p_obj )
>> +{
>> +    services_advertisement_t *p_sa = (services_advertisement_t *)p_obj;
>> +
>> +    struct microdns_sys *p_sys = calloc( 1, sizeof(struct microdns_sys) );
>> +    if( !p_sys )
>> +        return VLC_ENOMEM;
>> +
>> +    p_sa->p_sys = p_sys;
>> +    config_ChainParse( p_sa, CFG_PREFIX, ppsz_options, p_sa->p_cfg );
>> +
>> +    p_sys->advertisement_sys.i_http_port = var_InheritInteger(
>> +        p_obj, "http-port" ); /* 8080 if unset */
>> +    char *psz_address_family = var_InheritString(
>> +        p_obj, "services-advertisement-address-family" ); /* v6 if unset */
>> +
>> +
>> +    p_sa->description = _("mDNS Network Advertisement");
>> +
>> +    const char *mdns_addr = MDNS_ADDR_IPV6;
>> +    if( strcmp( psz_address_family, "v4" ) == 0 )
>> +        mdns_addr = MDNS_ADDR_IPV4;
>> +
>> +    return OpenCommon( p_obj, p_sys, mdns_addr, RunSA );
> YOu should free (psz_address_family).
Oops, will do.
>
>> +}
>> +
>> +static void
>> +CloseSA( vlc_object_t *p_this )
>> +{
>> +    services_advertisement_t *p_sa = (services_advertisement_t *) p_this;
>> +    struct microdns_sys *p_sys = p_sa->p_sys;
>>   
>> +    CloseCommon( p_sys );
>>       CleanCommon( p_sys );
>>   }
>> -- 
>> 2.17.1
>>
>> _______________________________________________
>> 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