[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