Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

bonjour.c

00001 /*****************************************************************************
00002  * bonjour.c: Bonjour services discovery module
00003  *****************************************************************************
00004  * Copyright (C) 2005 the VideoLAN team
00005  * $Id: bonjour.c 13521 2005-12-04 11:55:35Z zorglub $
00006  *
00007  * Authors: Jon Lech Johansen <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 /*****************************************************************************
00025  * Includes
00026  *****************************************************************************/
00027 #include <stdlib.h>                                      /* malloc(), free() */
00028 
00029 #include <vlc/vlc.h>
00030 #include <vlc/intf.h>
00031 
00032 #include <avahi-client/client.h>
00033 #ifdef HAVE_AVAHI_06
00034 # include <avahi-client/publish.h>
00035 # include <avahi-client/lookup.h>
00036 #endif
00037 #include <avahi-common/simple-watch.h>
00038 #include <avahi-common/malloc.h>
00039 #include <avahi-common/error.h>
00040 
00041 /*****************************************************************************
00042  * Module descriptor
00043  *****************************************************************************/
00044 
00045 /* Callbacks */
00046     static int  Open ( vlc_object_t * );
00047     static void Close( vlc_object_t * );
00048 
00049 vlc_module_begin();
00050     set_shortname( "Bonjour" );
00051     set_description( _("Bonjour services") );
00052     set_category( CAT_PLAYLIST );
00053     set_subcategory( SUBCAT_PLAYLIST_SD );
00054     set_capability( "services_discovery", 0 );
00055     set_callbacks( Open, Close );
00056 vlc_module_end();
00057 
00058 /*****************************************************************************
00059  * Local structures
00060  *****************************************************************************/
00061 
00062 struct services_discovery_sys_t
00063 {
00064     /* playlist node */
00065     playlist_item_t     *p_node;
00066     playlist_t          *p_playlist;
00067 
00068     AvahiSimplePoll     *simple_poll;
00069     AvahiClient         *client;
00070     AvahiServiceBrowser *sb;
00071 };
00072 
00073 /*****************************************************************************
00074  * Local prototypes
00075  *****************************************************************************/
00076 
00077 /* Main functions */
00078     static void Run    ( services_discovery_t *p_intf );
00079 
00080 /*****************************************************************************
00081  * client_callback
00082  *****************************************************************************/
00083 static void client_callback( AvahiClient *c, AvahiClientState state,
00084                              void * userdata )
00085 {
00086     services_discovery_t *p_sd = ( services_discovery_t* )userdata;
00087     services_discovery_sys_t *p_sys = p_sd->p_sys;
00088 
00089 #ifdef HAVE_AVAHI_06
00090     if( state == AVAHI_CLIENT_FAILURE &&
00091         (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) )
00092 #else
00093     if( state == AVAHI_CLIENT_DISCONNECTED )
00094 #endif
00095     {
00096         msg_Err( p_sd, "avahi client disconnected" );
00097         avahi_simple_poll_quit( p_sys->simple_poll );
00098     }
00099 }
00100 
00101 /*****************************************************************************
00102  * resolve_callback
00103  *****************************************************************************/
00104 static void resolve_callback(
00105     AvahiServiceResolver *r,
00106     AvahiIfIndex interface,
00107     AvahiProtocol protocol,
00108     AvahiResolverEvent event,
00109     const char *name,
00110     const char *type,
00111     const char *domain,
00112     const char *host_name,
00113     const AvahiAddress *address,
00114     uint16_t port,
00115     AvahiStringList *txt,
00116 #ifdef HAVE_AVAHI_06
00117     AvahiLookupResultFlags flags,
00118 #endif
00119     void* userdata )
00120 {
00121     services_discovery_t *p_sd = ( services_discovery_t* )userdata;
00122     services_discovery_sys_t *p_sys = p_sd->p_sys;
00123 
00124 #ifdef HAVE_AVAHI_06
00125     if( event == AVAHI_RESOLVER_FAILURE )
00126 #else
00127     if( event == AVAHI_RESOLVER_TIMEOUT )
00128 #endif
00129     {
00130         msg_Err( p_sd,
00131                  "failed to resolve service '%s' of type '%s' in domain '%s'",
00132                  name, type, domain );
00133     }
00134     else if( event == AVAHI_RESOLVER_FOUND )
00135     {
00136         char a[128];
00137         char *psz_uri = NULL;
00138         char *psz_addr = NULL;
00139         AvahiStringList *asl = NULL;
00140         playlist_item_t *p_item = NULL;
00141 
00142         msg_Dbg( p_sd, "service '%s' of type '%s' in domain '%s'",
00143                  name, type, domain );
00144 
00145         avahi_address_snprint(a, (sizeof(a)/sizeof(a[0]))-1, address);
00146         if( protocol == AVAHI_PROTO_INET6 )
00147             asprintf( &psz_addr, "[%s]", a );
00148 
00149         if( txt != NULL )
00150             asl = avahi_string_list_find( txt, "path" );
00151         if( asl != NULL )
00152         {
00153             size_t size;
00154             char *key = NULL;
00155             char *value = NULL;
00156             if( avahi_string_list_get_pair( asl, &key, &value, &size ) == 0 &&
00157                 value != NULL )
00158             {
00159                 asprintf( &psz_uri, "http://%s:%d%s",
00160                           psz_addr != NULL ? psz_addr : a, port, value );
00161             }
00162             if( key != NULL )
00163                 avahi_free( (void *)key );
00164             if( value != NULL )
00165                 avahi_free( (void *)value );
00166         }
00167         else
00168         {
00169             asprintf( &psz_uri, "http://%s:%d",
00170                       psz_addr != NULL ? psz_addr : a, port );
00171         }
00172 
00173         if( psz_addr != NULL )
00174             free( (void *)psz_addr );
00175 
00176         if( psz_uri != NULL )
00177         {
00178             p_item = playlist_ItemNew( p_sd, psz_uri, name );
00179             free( (void *)psz_uri );
00180         }
00181         if( p_item != NULL )
00182         {
00183             p_item->i_flags &= ~PLAYLIST_SKIP_FLAG;
00184 
00185             playlist_NodeAddItem( p_sys->p_playlist, p_item,
00186                                   VIEW_CATEGORY, p_sys->p_node,
00187                                   PLAYLIST_APPEND, PLAYLIST_END );
00188         }
00189     }
00190 
00191     avahi_service_resolver_free( r );
00192 }
00193 
00194 /*****************************************************************************
00195  * browser_callback
00196  *****************************************************************************/
00197 static void browse_callback(
00198     AvahiServiceBrowser *b,
00199     AvahiIfIndex interface,
00200     AvahiProtocol protocol,
00201     AvahiBrowserEvent event,
00202     const char *name,
00203     const char *type,
00204     const char *domain,
00205 #ifdef HAVE_AVAHI_06
00206     AvahiLookupResultFlags flags,
00207 #endif
00208     void* userdata )
00209 {
00210     services_discovery_t *p_sd = ( services_discovery_t* )userdata;
00211     services_discovery_sys_t *p_sys = p_sd->p_sys;
00212 
00213     if( event == AVAHI_BROWSER_NEW )
00214     {
00215         if( avahi_service_resolver_new( p_sys->client, interface, protocol,
00216                                         name, type, domain, AVAHI_PROTO_UNSPEC,
00217 #ifdef HAVE_AVAHI_06
00218                                         0,
00219 #endif
00220                                         resolve_callback, userdata ) == NULL )
00221         {
00222             msg_Err( p_sd, "failed to resolve service '%s': %s", name,
00223                      avahi_strerror( avahi_client_errno( p_sys->client ) ) );
00224         }
00225     }
00226     else
00227     {
00228         playlist_item_t *p_item;
00229 
00230         p_item = playlist_ChildSearchName( p_sys->p_node, name );
00231         if( p_item == NULL )
00232         {
00233             msg_Err( p_sd, "failed to find service '%s' in playlist", name );
00234         }
00235         else
00236         {
00237             playlist_Delete( p_sys->p_playlist, p_item->input.i_id );
00238         }
00239     }
00240 }
00241 
00242 /*****************************************************************************
00243  * Open: initialize and create stuff
00244  *****************************************************************************/
00245 static int Open( vlc_object_t *p_this )
00246 {
00247     services_discovery_t *p_sd = ( services_discovery_t* )p_this;
00248     services_discovery_sys_t *p_sys;
00249     playlist_view_t *p_view;
00250     vlc_value_t val;
00251     int err;
00252 
00253     p_sd->p_sys = p_sys = (services_discovery_sys_t *)malloc(
00254         sizeof( services_discovery_sys_t ) );
00255     if( p_sd->p_sys == NULL )
00256     {
00257         msg_Err( p_sd, "out of memory" );
00258         return VLC_EGENERIC;
00259     }
00260 
00261     memset( p_sys, 0, sizeof(*p_sys) );
00262 
00263     p_sys->simple_poll = avahi_simple_poll_new();
00264     if( p_sys->simple_poll == NULL )
00265     {
00266         msg_Err( p_sd, "failed to create avahi simple poll" );
00267         goto error;
00268     }
00269 
00270     p_sys->client = avahi_client_new( avahi_simple_poll_get(p_sys->simple_poll),
00271 #ifdef HAVE_AVAHI_06
00272                                       0,
00273 #endif
00274                                       client_callback, p_sd, &err );
00275     if( p_sys->client == NULL )
00276     {
00277         msg_Err( p_sd, "failed to create avahi client: %s",
00278                  avahi_strerror( err ) );
00279         goto error;
00280     }
00281 
00282     p_sys->sb = avahi_service_browser_new( p_sys->client, AVAHI_IF_UNSPEC,
00283                                            AVAHI_PROTO_UNSPEC,
00284                                            "_vlc-http._tcp", NULL,
00285 #ifdef HAVE_AVAHI_06
00286                                            0,
00287 #endif
00288                                            browse_callback, p_sd );
00289     if( p_sys->sb == NULL )
00290     {
00291         msg_Err( p_sd, "failed to create avahi service browser" );
00292         goto error;
00293     }
00294 
00295     /* Create our playlist node */
00296     p_sys->p_playlist = (playlist_t *)vlc_object_find( p_sd,
00297                                                        VLC_OBJECT_PLAYLIST,
00298                                                        FIND_ANYWHERE );
00299     if( !p_sys->p_playlist )
00300     {
00301         msg_Warn( p_sd, "unable to find playlist, cancelling");
00302         goto error;
00303     }
00304 
00305     p_view = playlist_ViewFind( p_sys->p_playlist, VIEW_CATEGORY );
00306     p_sys->p_node = playlist_NodeCreate( p_sys->p_playlist, VIEW_CATEGORY,
00307                                          _("Bonjour"), p_view->p_root );
00308 
00309     p_sys->p_node->i_flags |= PLAYLIST_RO_FLAG;
00310     val.b_bool = VLC_TRUE;
00311     var_Set( p_sys->p_playlist, "intf-change", val );
00312 
00313     p_sd->pf_run = Run;
00314 
00315     return VLC_SUCCESS;
00316 
00317 error:
00318     if( p_sys->p_playlist != NULL )
00319         vlc_object_release( p_sys->p_playlist );
00320     if( p_sys->sb != NULL )
00321         avahi_service_browser_free( p_sys->sb );
00322     if( p_sys->client != NULL )
00323         avahi_client_free( p_sys->client );
00324     if( p_sys->simple_poll != NULL )
00325         avahi_simple_poll_free( p_sys->simple_poll );
00326 
00327     free( (void *)p_sys );
00328 
00329     return VLC_EGENERIC;
00330 }
00331 
00332 /*****************************************************************************
00333  * Close: cleanup
00334  *****************************************************************************/
00335 static void Close( vlc_object_t *p_this )
00336 {
00337     services_discovery_t *p_sd = ( services_discovery_t* )p_this;
00338     services_discovery_sys_t *p_sys = p_sd->p_sys;
00339 
00340     avahi_service_browser_free( p_sys->sb );
00341     avahi_client_free( p_sys->client );
00342     avahi_simple_poll_free( p_sys->simple_poll );
00343 
00344     playlist_NodeDelete( p_sys->p_playlist, p_sys->p_node, VLC_TRUE, VLC_TRUE );
00345     vlc_object_release( p_sys->p_playlist );
00346 
00347     free( p_sys );
00348 }
00349 
00350 /*****************************************************************************
00351  * Run: main thread
00352  *****************************************************************************/
00353 static void Run( services_discovery_t *p_sd )
00354 {
00355     services_discovery_sys_t *p_sys = p_sd->p_sys;
00356 
00357     while( !p_sd->b_die )
00358     {
00359         if( avahi_simple_poll_iterate( p_sys->simple_poll, 100 ) != 0 )
00360         {
00361             msg_Err( p_sd, "poll iterate failed" );
00362             break;
00363         }
00364     }
00365 }

Generated on Tue Dec 20 10:14:27 2005 for vlc-0.8.4a by  doxygen 1.4.2