[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