[vlc-devel] [PATCH 4/9] microdns: Add a services_advertisement submodule
Hugo Beauzée-Luyssen
hugo at beauzee.fr
Wed Sep 2 15:47:26 CEST 2020
refs #18090
Co-authored-by: Roland Bewick <roland.bewick at gmail.com>
---
configure.ac | 2 +-
modules/services_discovery/microdns.c | 458 ++++++++++++++++++++++----
2 files changed, 401 insertions(+), 59 deletions(-)
diff --git a/configure.ac b/configure.ac
index 7b40650216..6f78b9c258 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4335,7 +4335,7 @@ PKG_ENABLE_MODULES_VLC([UPNP], [upnp], [libupnp], [Intel UPNP SDK],[auto])
dnl
dnl mDNS using libmicrodns
dnl
-PKG_ENABLE_MODULES_VLC([MICRODNS], [], [microdns >= 0.1.2], [mDNS services discovery], [auto])
+PKG_ENABLE_MODULES_VLC([MICRODNS], [], [microdns >= 0.2.0], [mDNS services discovery], [auto])
EXTEND_HELP_STRING([Misc options:])
diff --git a/modules/services_discovery/microdns.c b/modules/services_discovery/microdns.c
index 16f23d914c..30e29bb3b6 100644
--- a/modules/services_discovery/microdns.c
+++ b/modules/services_discovery/microdns.c
@@ -1,7 +1,7 @@
/*****************************************************************************
* microdns.c: mDNS services discovery module
*****************************************************************************
- * Copyright © 2016 VLC authors, VideoLAN and VideoLabs
+ * Copyright © 2016-2020 VLC authors, VideoLAN and VideoLabs
*
* Authors: Steve Lhomme <robux4 at videolabs.io>
* Thomas Guillem <thomas at gllm.fr>
@@ -33,6 +33,8 @@
#include <vlc_modules.h>
#include <vlc_services_discovery.h>
#include <vlc_renderer_discovery.h>
+#include <vlc_services_advertisement.h>
+#include <vlc_vector.h>
#include <microdns/microdns.h>
@@ -40,6 +42,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 +73,13 @@ 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_module_end ()
static const struct
@@ -89,14 +100,39 @@ static const struct
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 sa_item
+{
+ struct services_advertisement_entry_t* entry;
+ bool announced;
+};
+
+typedef struct VLC_VECTOR(struct sa_item*) items_vec;
+
+struct advertisement_sys
+{
+ items_vec services;
+ vlc_mutex_t lock;
+ char *host;
+ bool started;
+};
+
+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;
@@ -407,7 +443,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( i_status < 0 )
{
print_error( VLC_OBJECT( p_sd ), "entry callback", i_status );
@@ -432,12 +468,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 );
}
clear_srvs( p_srvs, i_nb_srv );
@@ -448,13 +484,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;
}
}
@@ -463,11 +499,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 );
@@ -481,7 +517,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 );
@@ -508,7 +544,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;
@@ -535,8 +571,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->renderer.i_renderer_flags );
free(psz_icon_uri);
}
@@ -548,13 +584,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;
}
}
@@ -563,11 +599,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 );
@@ -577,62 +613,318 @@ RunRD( void *p_this )
return NULL;
}
-static int
-OpenCommon( vlc_object_t *p_obj, struct discovery_sys *p_sys, bool b_renderer )
+static uint32_t sa_compute_ttl( enum rr_type rr_type,
+ enum mdns_announce_type announce_type )
{
- int i_ret = VLC_EGENERIC;
- atomic_init( &p_sys->stop, false );
- vlc_array_init( &p_sys->items );
+ if( announce_type == MDNS_ANNOUNCE_GOODBYE )
+ return 0;
+ /*
+ * As a general rule, the recommended TTL value for Multicast DNS
+ * resource records with a host name as the resource record's name
+ * (e.g., A, AAAA, HINFO) or a host name contained within the resource
+ * record's rdata (e.g., SRV, reverse mapping PTR record) SHOULD be 120
+ * seconds.
+ * The recommended TTL value for other Multicast DNS resource records is
+ * 75 minutes.
+ */
+ switch ( rr_type )
+ {
+ case RR_A:
+ case RR_AAAA:
+ case RR_SRV:
+ return 120;
+ default:
+ return 75 * 60;
+ }
+}
- /* Listen to protocols that are handled by VLC */
- for( unsigned int i = 0; i < NB_PROTOCOLS; ++i )
+static bool
+sa_announce_item( struct microdns_sys* sys, const struct sockaddr* mdns_ip,
+ struct sa_item* item,
+ enum mdns_announce_type type )
+{
+ vlc_mutex_assert( &sys->advertisement_sys.lock );
+ struct mdns_hdr hdr = {0}; /* response header */
+
+ size_t nb_records = 3;
+ if ( mdns_ip )
+ nb_records += 1;
+ struct rr_entry *answers = calloc( nb_records, sizeof( *answers ) );
+ if( !answers )
+ return false;
+ struct rr_entry *a = answers;
+
+ hdr.num_qn = 0;
+ hdr.num_ans_rr = nb_records;
+ hdr.flags |= FLAG_QR;
+ hdr.flags |= FLAG_AA;
+
+ for( size_t i = 0; i < nb_records; i++ )
{
- if( protocols[i].b_renderer == b_renderer )
- p_sys->ppsz_service_names[p_sys->i_nb_service_names++] =
- protocols[i].psz_service_name;
+ answers[i].rr_class = RR_IN;
+ answers[i].msbit = 1;
+
+ if( i < nb_records - 1 )
+ answers[i].next = &answers[i + 1];
+ else
+ answers[i].next = NULL;
}
- if( p_sys->i_nb_service_names == 0 )
+ const char* name = vlc_sa_entry_Name( item->entry );
+ char* full_name;
+ char* type_local;
+ if( asprintf(&type_local, "%s.local", vlc_sa_entry_Type( item->entry ) ) < 0 )
{
- msg_Err( p_obj, "no services found" );
- goto error;
+ free( answers );
+ return false;
+ }
+ if( asprintf( &full_name, "%s.%s", name, type_local ) < 0 )
+ {
+ free( answers );
+ free(type_local);
+ return false;
+ }
+ // RR_PTR: point service type to local domain and instance name (VLC)
+
+ a->type = RR_PTR;
+ a->name = (char*)type_local;
+ a->data.PTR.domain = full_name;
+ a->ttl = sa_compute_ttl( a->type, type );
+ a++;
+
+ // RR_SRV: provide info about the service we're announcing (port no, etc.)
+ a->type = RR_SRV;
+ a->name = (char*)full_name;
+ a->data.SRV.port = vlc_sa_entry_Port( item->entry );
+ a->data.SRV.priority = 0;
+ a->data.SRV.weight = 0;
+ a->data.SRV.target = (char*)sys->advertisement_sys.host;
+ a->ttl = sa_compute_ttl( a->type, type );
+ a++;
+
+ if( mdns_ip )
+ {
+ a->name = (char*)sys->advertisement_sys.host;
+ // RR_A/AAAA: link .local domain to IP address
+ if ( mdns_ip->sa_family == AF_INET)
+ {
+ const struct sockaddr_in* sin = (const struct sockaddr_in*)mdns_ip;
+ a->type = RR_A;
+ memcpy(&a->data.A.addr, &sin->sin_addr,
+ sizeof(a->data.A.addr));
+ }
+ else
+ {
+ const struct sockaddr_in6* sin = (const struct sockaddr_in6*)mdns_ip;
+ a->type = RR_AAAA;
+ memcpy(&a->data.AAAA.addr, &sin->sin6_addr,
+ sizeof(a->data.AAAA.addr));
+ }
+ a->ttl = sa_compute_ttl( a->type, type );
+ a++;
+ }
+
+ a->type = RR_TXT;
+ a->name = full_name;
+ a->ttl = sa_compute_ttl( a->type, type );
+ size_t nb_txts = vlc_sa_entry_Count_TXT( item->entry );
+ a->data.TXT = NULL;
+ if( nb_txts > 0 )
+ {
+ struct rr_data_txt* txts = a->data.TXT =
+ calloc( nb_txts, sizeof( *a->data.TXT ) );
+ const char** txts_in = vlc_sa_entry_Get_TXT( item->entry );
+ for ( size_t t = 0; t < nb_txts; ++t )
+ {
+ strncpy( txts->txt, txts_in[t], sizeof( txts->txt ) );
+ if( t < nb_txts - 1 )
+ txts->next = txts + 1;
+ else
+ txts->next = NULL;
+ txts++;
+ }
}
- 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" );
+
+ mdns_entries_send( sys->p_microdns, &hdr, answers );
+
+ free( a->data.TXT );
+ free( type_local );
+ free( full_name );
+ free( answers );
+ item->announced = true;
+ return true;
+}
+
+static void
+request_sa_callback( void *cbarg, const struct sockaddr* mdns_ip,
+ const char* service, enum mdns_announce_type type )
+{
+ services_advertisement_t *sa = ( services_advertisement_t* )cbarg;
+ struct microdns_sys *sys = sa->p_sys;
+
+ vlc_mutex_lock( &sys->advertisement_sys.lock );
+ sys->advertisement_sys.started = true;
+ for ( size_t i = 0; i < sys->advertisement_sys.services.size; ++i )
+ {
+ struct sa_item* item = sys->advertisement_sys.services.data[i];
+ if ( service != NULL && strcmp( service, vlc_sa_entry_Type( item->entry ) ) )
+ continue;
+ sa_announce_item( sys, mdns_ip, item, type );
+ }
+
+ vlc_mutex_unlock( &sys->advertisement_sys.lock );
+}
+
+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,
+ 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 int sa_announce( services_advertisement_t *sa,
+ services_advertisement_entry_t* entry )
+{
+ struct microdns_sys* sys = (struct microdns_sys*)sa->p_sys;
+ struct sa_item* item = malloc( sizeof( *item ) );
+ item->entry = vlc_sa_entry_Hold( entry );
+ item->announced = false;
+ vlc_mutex_lock( &sys->advertisement_sys.lock );
+ if ( !vlc_vector_push( &sys->advertisement_sys.services, item ) )
+ {
+ vlc_sa_entry_Release( entry );
+ free( item );
+ vlc_mutex_unlock( &sys->advertisement_sys.lock );
+ return VLC_ENOMEM;
+ }
+ bool announce = sys->advertisement_sys.started;
+ vlc_mutex_unlock( &sys->advertisement_sys.lock );
+ if( announce )
+ mdns_request_initial_announce(sys->p_microdns, vlc_sa_entry_Type( entry ) );
+ return VLC_SUCCESS;
+}
+
+static int sa_conceal( services_advertisement_t *sa,
+ services_advertisement_entry_t* entry )
+{
+ struct microdns_sys* sys = (struct microdns_sys*)sa->p_sys;
+ vlc_mutex_lock( &sys->advertisement_sys.lock );
+ for ( size_t i = 0; i < sys->advertisement_sys.services.size; ++i )
+ {
+ struct sa_item* item = sys->advertisement_sys.services.data[i];
+ if( vlc_sa_entry_Port( item->entry ) != vlc_sa_entry_Port( entry ) ||
+ strcmp( vlc_sa_entry_Type( item->entry ), vlc_sa_entry_Type( entry ) ) )
+ continue;
+ sa_announce_item( sys, NULL, item, MDNS_ANNOUNCE_GOODBYE );
+ vlc_sa_entry_Release( item->entry );
+ free( item );
+ vlc_vector_remove( &sys->advertisement_sys.services, i );
+ vlc_mutex_unlock( &sys->advertisement_sys.lock );
+ return VLC_SUCCESS;
+ }
+ vlc_mutex_unlock( &sys->advertisement_sys.lock );
+ return VLC_EGENERIC;
+}
+
+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, NULL, entry );
+error:
+ CleanCommon( p_sys );
+ return i_ret;
}
static int
@@ -640,7 +932,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;
@@ -648,16 +940,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
@@ -665,21 +958,70 @@ 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 *sa = (services_advertisement_t *)p_obj;
+ char hostname[256];
+
+ struct microdns_sys *sys = calloc( 1, sizeof(struct microdns_sys) );
+ if( !sys )
+ return VLC_ENOMEM;
+
+ sa->p_sys = sys;
+ vlc_mutex_init( &sys->advertisement_sys.lock );
+ if( gethostname( hostname, sizeof( hostname ) ) ||
+ asprintf( &sys->advertisement_sys.host, "%s.local", hostname ) < 0 )
+ {
+ free( sys );
+ return VLC_EGENERIC;
+ }
+ vlc_vector_init( &sys->advertisement_sys.services );
+ sys->advertisement_sys.started = false;
+ config_ChainParse( sa, CFG_PREFIX, ppsz_options, sa->p_cfg );
+
+ sa->description = _("mDNS Network Advertisement");
+
+ sa->pf_announce = sa_announce;
+ sa->pf_conceal = sa_conceal;
+
+ return OpenCommon( p_obj, sys, NULL, RunSA );
+}
+
+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 );
+ for ( size_t i = 0; i < p_sys->advertisement_sys.services.size; ++i )
+ {
+ struct sa_item *item = p_sys->advertisement_sys.services.data[i];
+ vlc_sa_entry_Release( item->entry );
+ free( item );
+ }
+ vlc_vector_destroy( &p_sys->advertisement_sys.services );
+ free( p_sys->advertisement_sys.host );
CleanCommon( p_sys );
}
--
2.20.1
More information about the vlc-devel
mailing list