bonjour.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:10k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * bonjour.c: Bonjour services discovery module
  3.  *****************************************************************************
  4.  * Copyright (C) 2005-2009 the VideoLAN team
  5.  * $Id: b4dfac3b3265ea0473677c67b84f59732e5fed24 $
  6.  *
  7.  * Authors: Jon Lech Johansen <jon@nanocrew.net>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Includes
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <vlc_plugin.h>
  31. #include <vlc_services_discovery.h>
  32. #include <avahi-client/client.h>
  33. #include <avahi-client/publish.h>
  34. #include <avahi-client/lookup.h>
  35. #include <avahi-common/thread-watch.h>
  36. #include <avahi-common/malloc.h>
  37. #include <avahi-common/error.h>
  38. /*****************************************************************************
  39.  * Module descriptor
  40.  *****************************************************************************/
  41. /* Callbacks */
  42.     static int  Open ( vlc_object_t * );
  43.     static void Close( vlc_object_t * );
  44. vlc_module_begin ()
  45.     set_shortname( "Bonjour" )
  46.     set_description( N_("Bonjour services") )
  47.     set_category( CAT_PLAYLIST )
  48.     set_subcategory( SUBCAT_PLAYLIST_SD )
  49.     set_capability( "services_discovery", 0 )
  50.     set_callbacks( Open, Close )
  51. vlc_module_end ()
  52. /*****************************************************************************
  53.  * Local structures
  54.  *****************************************************************************/
  55. struct services_discovery_sys_t
  56. {
  57.     AvahiThreadedPoll   *poll;
  58.     AvahiClient         *client;
  59.     AvahiServiceBrowser *sb;
  60.     vlc_dictionary_t    services_name_to_input_item;
  61. };
  62. /*****************************************************************************
  63.  * Local prototypes
  64.  *****************************************************************************/
  65. /*****************************************************************************
  66.  * client_callback
  67.  *****************************************************************************/
  68. static void client_callback( AvahiClient *c, AvahiClientState state,
  69.                              void * userdata )
  70. {
  71.     services_discovery_t *p_sd = ( services_discovery_t* )userdata;
  72.     services_discovery_sys_t *p_sys = p_sd->p_sys;
  73.     if( state == AVAHI_CLIENT_FAILURE &&
  74.         (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) )
  75.     {
  76.         msg_Err( p_sd, "avahi client disconnected" );
  77.         avahi_threaded_poll_quit( p_sys->poll );
  78.     }
  79. }
  80. /*****************************************************************************
  81.  * resolve_callback
  82.  *****************************************************************************/
  83. static void resolve_callback(
  84.     AvahiServiceResolver *r,
  85.     AvahiIfIndex interface,
  86.     AvahiProtocol protocol,
  87.     AvahiResolverEvent event,
  88.     const char *name,
  89.     const char *type,
  90.     const char *domain,
  91.     const char *host_name,
  92.     const AvahiAddress *address,
  93.     uint16_t port,
  94.     AvahiStringList *txt,
  95.     AvahiLookupResultFlags flags,
  96.     void* userdata )
  97. {
  98.     services_discovery_t *p_sd = ( services_discovery_t* )userdata;
  99.     services_discovery_sys_t *p_sys = p_sd->p_sys;
  100.     
  101.     VLC_UNUSED(interface); VLC_UNUSED(host_name);
  102.     VLC_UNUSED(flags);
  103.     if( event == AVAHI_RESOLVER_FAILURE )
  104.     {
  105.         msg_Err( p_sd,
  106.                  "failed to resolve service '%s' of type '%s' in domain '%s'",
  107.                  name, type, domain );
  108.     }
  109.     else if( event == AVAHI_RESOLVER_FOUND )
  110.     {
  111.         char a[128];
  112.         char *psz_uri = NULL;
  113.         char *psz_addr = NULL;
  114.         AvahiStringList *asl = NULL;
  115.         input_item_t *p_input = NULL;
  116.         msg_Dbg( p_sd, "service '%s' of type '%s' in domain '%s'",
  117.                  name, type, domain );
  118.         avahi_address_snprint(a, (sizeof(a)/sizeof(a[0]))-1, address);
  119.         if( protocol == AVAHI_PROTO_INET6 )
  120.             if( asprintf( &psz_addr, "[%s]", a ) == -1 )
  121.                 return;
  122.         if( txt != NULL )
  123.             asl = avahi_string_list_find( txt, "path" );
  124.         if( asl != NULL )
  125.         {
  126.             size_t size;
  127.             char *key = NULL;
  128.             char *value = NULL;
  129.             if( avahi_string_list_get_pair( asl, &key, &value, &size ) == 0 &&
  130.                 value != NULL )
  131.             {
  132.                 if( asprintf( &psz_uri, "http://%s:%d%s",
  133.                           psz_addr != NULL ? psz_addr : a, port, value ) == -1 )
  134.                 {
  135.                     free( psz_addr );
  136.                     return;
  137.                 }
  138.             }
  139.             if( key != NULL )
  140.                 avahi_free( (void *)key );
  141.             if( value != NULL )
  142.                 avahi_free( (void *)value );
  143.         }
  144.         else
  145.         {
  146.             if( asprintf( &psz_uri, "http://%s:%d",
  147.                       psz_addr != NULL ? psz_addr : a, port ) == -1 )
  148.             {
  149.                 free( psz_addr );
  150.                 return;
  151.             }
  152.         }
  153.         free( psz_addr );
  154.         if( psz_uri != NULL )
  155.         {
  156.             p_input = input_item_New( p_sd, psz_uri, name );
  157.             free( psz_uri );
  158.         }
  159.         if( p_input != NULL )
  160.         {
  161.             vlc_dictionary_insert( &p_sys->services_name_to_input_item,
  162.                 name, p_input );
  163.             services_discovery_AddItem( p_sd, p_input, NULL /* no category */ );
  164.             vlc_gc_decref( p_input );
  165.        }
  166.     }
  167.     avahi_service_resolver_free( r );
  168. }
  169. /*****************************************************************************
  170.  * browser_callback
  171.  *****************************************************************************/
  172. static void browse_callback(
  173.     AvahiServiceBrowser *b,
  174.     AvahiIfIndex interface,
  175.     AvahiProtocol protocol,
  176.     AvahiBrowserEvent event,
  177.     const char *name,
  178.     const char *type,
  179.     const char *domain,
  180.     AvahiLookupResultFlags flags,
  181.     void* userdata )
  182. {
  183.     VLC_UNUSED(b);
  184.     VLC_UNUSED(flags);
  185.     services_discovery_t *p_sd = ( services_discovery_t* )userdata;
  186.     services_discovery_sys_t *p_sys = p_sd->p_sys;
  187.     if( event == AVAHI_BROWSER_NEW )
  188.     {
  189.         if( avahi_service_resolver_new( p_sys->client, interface, protocol,
  190.                                         name, type, domain, AVAHI_PROTO_UNSPEC,
  191.                                         0,
  192.                                         resolve_callback, userdata ) == NULL )
  193.         {
  194.             msg_Err( p_sd, "failed to resolve service '%s': %s", name,
  195.                      avahi_strerror( avahi_client_errno( p_sys->client ) ) );
  196.         }
  197.     }
  198.     else if( name )
  199.     {
  200.         /** todo Store the input id and search it, rather than searching the items */
  201.         input_item_t *p_item;
  202.         p_item = vlc_dictionary_value_for_key(
  203.                         &p_sys->services_name_to_input_item,
  204.                         name );
  205.         if( !p_item )
  206.             msg_Err( p_sd, "failed to find service '%s' in playlist", name );
  207.         else
  208.         {
  209.             services_discovery_RemoveItem( p_sd, p_item );
  210.             vlc_dictionary_remove_value_for_key(
  211.                         &p_sys->services_name_to_input_item,
  212.                         name, NULL, NULL );
  213.         }
  214.     }
  215. }
  216. /*****************************************************************************
  217.  * Open: initialize and create stuff
  218.  *****************************************************************************/
  219. static int Open( vlc_object_t *p_this )
  220. {
  221.     services_discovery_t *p_sd = ( services_discovery_t* )p_this;
  222.     services_discovery_sys_t *p_sys;
  223.     int err;
  224.     p_sd->p_sys = p_sys = calloc( 1, sizeof( services_discovery_sys_t ) );
  225.     if( !p_sys )
  226.         return VLC_ENOMEM;
  227.     vlc_dictionary_init( &p_sys->services_name_to_input_item, 1 );
  228.     p_sys->poll = avahi_threaded_poll_new();
  229.     if( p_sys->poll == NULL )
  230.     {
  231.         msg_Err( p_sd, "failed to create Avahi threaded poll" );
  232.         goto error;
  233.     }
  234.     p_sys->client = avahi_client_new( avahi_threaded_poll_get(p_sys->poll),
  235.                                       0, client_callback, p_sd, &err );
  236.     if( p_sys->client == NULL )
  237.     {
  238.         msg_Err( p_sd, "failed to create avahi client: %s",
  239.                  avahi_strerror( err ) );
  240.         goto error;
  241.     }
  242.     p_sys->sb = avahi_service_browser_new( p_sys->client, AVAHI_IF_UNSPEC,
  243.                                            AVAHI_PROTO_UNSPEC,
  244.                                            "_vlc-http._tcp", NULL,
  245.                                            0, browse_callback, p_sd );
  246.     if( p_sys->sb == NULL )
  247.     {
  248.         msg_Err( p_sd, "failed to create avahi service browser" );
  249.         goto error;
  250.     }
  251.     return VLC_SUCCESS;
  252. error:
  253.     if( p_sys->sb != NULL )
  254.         avahi_service_browser_free( p_sys->sb );
  255.     if( p_sys->client != NULL )
  256.         avahi_client_free( p_sys->client );
  257.     if( p_sys->poll != NULL )
  258.         avahi_threaded_poll_free( p_sys->poll );
  259.     vlc_dictionary_clear( &p_sys->services_name_to_input_item, NULL, NULL );
  260.     free( p_sys );
  261.     return VLC_EGENERIC;
  262. }
  263. /*****************************************************************************
  264.  * Close: cleanup
  265.  *****************************************************************************/
  266. static void Close( vlc_object_t *p_this )
  267. {
  268.     services_discovery_t *p_sd = ( services_discovery_t* )p_this;
  269.     services_discovery_sys_t *p_sys = p_sd->p_sys;
  270.     avahi_service_browser_free( p_sys->sb );
  271.     avahi_client_free( p_sys->client );
  272.     avahi_threaded_poll_free( p_sys->poll );
  273.     vlc_dictionary_clear( &p_sys->services_name_to_input_item, NULL, NULL );
  274.     free( p_sys );
  275. }