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

bonjour.c

00001 /*****************************************************************************
00002  * bonjour.c
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  * Preamble
00026  *****************************************************************************/
00027 #include <stdlib.h>
00028 
00029 #include <vlc/vlc.h>
00030 
00031 #ifdef HAVE_AVAHI_CLIENT
00032 #include <vlc/intf.h>
00033 #include <vlc/sout.h>
00034 
00035 #include <avahi-client/client.h>
00036 #ifdef HAVE_AVAHI_06
00037 # include <avahi-client/publish.h>
00038 # include <avahi-client/lookup.h>
00039 #endif
00040 #include <avahi-common/alternative.h>
00041 #include <avahi-common/simple-watch.h>
00042 #include <avahi-common/malloc.h>
00043 #include <avahi-common/error.h>
00044 
00045 /*****************************************************************************
00046  * Structures
00047  *****************************************************************************/
00048 typedef struct poll_thread_t
00049 {
00050     VLC_COMMON_MEMBERS
00051 
00052     AvahiSimplePoll     *simple_poll;
00053 } poll_thread_t;
00054 
00055 typedef struct bonjour_t
00056 {
00057     vlc_object_t        *p_log;
00058 
00059     poll_thread_t       *poll_thread;
00060     AvahiSimplePoll     *simple_poll;
00061     AvahiEntryGroup     *group;
00062     AvahiClient         *client;
00063     char                *psz_stype;
00064     char                *psz_name;
00065     int                 i_port;
00066     char                *psz_txt;
00067 } bonjour_t;
00068 
00069 /*****************************************************************************
00070  * Prototypes
00071  *****************************************************************************/
00072 static int create_service( bonjour_t * );
00073 
00074 /*****************************************************************************
00075  * entry_group_callback
00076  *****************************************************************************/
00077 static void entry_group_callback( AvahiEntryGroup *g,
00078                                   AvahiEntryGroupState state,
00079                                   void *userdata )
00080 {
00081     bonjour_t *p_sys = (bonjour_t *)userdata;
00082 
00083     if( state == AVAHI_ENTRY_GROUP_ESTABLISHED )
00084     {
00085         msg_Dbg( p_sys->p_log, "service '%s' successfully established",
00086                  p_sys->psz_name );
00087     }
00088     else if( state == AVAHI_ENTRY_GROUP_COLLISION )
00089     {
00090         char *n;
00091 
00092         n = avahi_alternative_service_name( p_sys->psz_name );
00093         avahi_free( p_sys->psz_name );
00094         p_sys->psz_name = n;
00095 
00096         create_service( p_sys );
00097     }
00098 }
00099 
00100 /*****************************************************************************
00101  * create_service
00102  *****************************************************************************/
00103 static int create_service( bonjour_t *p_sys )
00104 {
00105     int error;
00106 
00107     if( p_sys->group == NULL )
00108     {
00109         p_sys->group = avahi_entry_group_new( p_sys->client,
00110                                               entry_group_callback,
00111                                               p_sys );
00112         if( p_sys->group == NULL )
00113         {
00114             msg_Err( p_sys->p_log, "failed to create avahi entry group: %s",
00115                      avahi_strerror( avahi_client_errno( p_sys->client ) ) );
00116             return VLC_EGENERIC;
00117         }
00118     }
00119 
00120     error = avahi_entry_group_add_service( p_sys->group, AVAHI_IF_UNSPEC,
00121 #ifdef HAVE_AVAHI_06
00122                                            AVAHI_PROTO_UNSPEC, 0, p_sys->psz_name,
00123 #else
00124                                            AVAHI_PROTO_UNSPEC, p_sys->psz_name,
00125 #endif
00126                                            p_sys->psz_stype, NULL, NULL,
00127                                            p_sys->i_port,
00128                                            p_sys->psz_txt, NULL );
00129     if( error < 0 )
00130     {
00131         msg_Err( p_sys->p_log, "failed to add %s service: %s",
00132                  p_sys->psz_stype, avahi_strerror( error ) );
00133         return VLC_EGENERIC;
00134     }
00135 
00136     error = avahi_entry_group_commit( p_sys->group );
00137     if( error < 0 )
00138     {
00139         msg_Err( p_sys->p_log, "failed to commit entry group: %s",
00140                  avahi_strerror( error ) );
00141         return VLC_EGENERIC;
00142     }
00143 
00144     return VLC_SUCCESS;
00145 }
00146 
00147 /*****************************************************************************
00148  * client_callback
00149  *****************************************************************************/
00150 static void client_callback( AvahiClient *c,
00151                              AvahiClientState state,
00152                              void * userdata )
00153 {
00154     bonjour_t *p_sys = (bonjour_t *)userdata;
00155 
00156     if( state == AVAHI_CLIENT_S_RUNNING )
00157     {
00158         p_sys->client = c;
00159         create_service( p_sys );
00160     }
00161     else if( state == AVAHI_CLIENT_S_COLLISION )
00162     {
00163         if( p_sys->group != NULL )
00164             avahi_entry_group_reset( p_sys->group );
00165     }
00166 #ifdef HAVE_AVAHI_06
00167     else if( state == AVAHI_CLIENT_FAILURE &&
00168               (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) )
00169 #else
00170     else if( state == AVAHI_CLIENT_DISCONNECTED )
00171 #endif
00172     {
00173         msg_Err( p_sys->p_log, "avahi client disconnected" );
00174         avahi_simple_poll_quit( p_sys->simple_poll );
00175     }
00176 }
00177 
00178 /*****************************************************************************
00179  * poll_iterate_thread
00180  *****************************************************************************/
00181 static void poll_iterate_thread( poll_thread_t *p_pt )
00182 {
00183     vlc_thread_ready( p_pt );
00184 
00185     while( !p_pt->b_die )
00186         if( avahi_simple_poll_iterate( p_pt->simple_poll, 100 ) != 0 )
00187             break;
00188 }
00189 
00190 /*****************************************************************************
00191  * bonjour_start_service
00192  *****************************************************************************/
00193 void *bonjour_start_service( vlc_object_t *p_log, char *psz_stype,
00194                             char *psz_name, int i_port, char *psz_txt )
00195 {
00196     int err;
00197     bonjour_t *p_sys;
00198 
00199     p_sys = (bonjour_t *)malloc( sizeof(*p_sys) );
00200     if( p_sys == NULL )
00201     {
00202         msg_Err( p_log, "out of memory" );
00203         return NULL;
00204     }
00205 
00206     memset( p_sys, 0, sizeof(*p_sys) );
00207 
00208     p_sys->p_log = p_log;
00209 
00210     p_sys->i_port = i_port;
00211     p_sys->psz_name = avahi_strdup( psz_name );
00212     p_sys->psz_stype = avahi_strdup( psz_stype );
00213     if( p_sys->psz_name == NULL || p_sys->psz_stype == NULL )
00214     {
00215         msg_Err( p_sys->p_log, "out of memory" );
00216         goto error;
00217     }
00218 
00219     if( psz_txt != NULL )
00220     {
00221         p_sys->psz_txt = avahi_strdup( psz_txt );
00222         if( p_sys->psz_txt == NULL )
00223         {
00224             msg_Err( p_sys->p_log, "out of memory" );
00225             goto error;
00226         }
00227     }
00228 
00229     p_sys->simple_poll = avahi_simple_poll_new();
00230     if( p_sys->simple_poll == NULL )
00231     {
00232         msg_Err( p_sys->p_log, "failed to create avahi simple pool" );
00233         goto error;
00234     }
00235 
00236     p_sys->client = avahi_client_new( avahi_simple_poll_get(p_sys->simple_poll),
00237 #ifdef HAVE_AVAHI_06
00238                                       0,
00239 #endif
00240                                       client_callback, p_sys, &err );
00241     if( p_sys->client == NULL )
00242     {
00243         msg_Err( p_sys->p_log, "failed to create avahi client: %s",
00244                  avahi_strerror( err ) );
00245         goto error;
00246     }
00247 
00248     p_sys->poll_thread = vlc_object_create( p_sys->p_log,
00249                                             sizeof(poll_thread_t) );
00250     if( p_sys->poll_thread == NULL )
00251     {
00252         msg_Err( p_sys->p_log, "out of memory" );
00253         goto error;
00254     }
00255     p_sys->poll_thread->simple_poll = p_sys->simple_poll;
00256 
00257     if( vlc_thread_create( p_sys->poll_thread, "Avahi Poll Iterate Thread",
00258                            poll_iterate_thread,
00259                            VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) )
00260     {
00261         msg_Err( p_sys->p_log, "failed to create poll iterate thread" );
00262         goto error;
00263     }
00264 
00265     return (void *)p_sys;
00266 
00267 error:
00268     if( p_sys->poll_thread != NULL )
00269         vlc_object_destroy( p_sys->poll_thread );
00270     if( p_sys->client != NULL )
00271         avahi_client_free( p_sys->client );
00272     if( p_sys->simple_poll != NULL )
00273         avahi_simple_poll_free( p_sys->simple_poll );
00274     if( p_sys->psz_stype != NULL )
00275         avahi_free( p_sys->psz_stype );
00276     if( p_sys->psz_name != NULL )
00277         avahi_free( p_sys->psz_name );
00278     if( p_sys->psz_txt != NULL )
00279         avahi_free( p_sys->psz_txt );
00280 
00281     free( (void *)p_sys );
00282 
00283     return NULL;
00284 }
00285 
00286 /*****************************************************************************
00287  * bonjour_stop_service
00288  *****************************************************************************/
00289 void bonjour_stop_service( void *_p_sys )
00290 {
00291     bonjour_t *p_sys = (bonjour_t *)_p_sys;
00292 
00293     if( p_sys->poll_thread->b_thread )
00294     {
00295         p_sys->poll_thread->b_die = 1;
00296         vlc_thread_join( p_sys->poll_thread );
00297     }
00298 
00299     vlc_object_destroy( p_sys->poll_thread );
00300 
00301     if( p_sys->group != NULL )
00302         avahi_entry_group_free( p_sys->group );
00303 
00304     avahi_client_free( p_sys->client );
00305     avahi_simple_poll_free( p_sys->simple_poll );
00306 
00307     if( p_sys->psz_name != NULL )
00308         avahi_free( p_sys->psz_name );
00309 
00310     if( p_sys->psz_txt != NULL )
00311         avahi_free( p_sys->psz_txt );
00312 
00313     avahi_free( p_sys->psz_stype );
00314 
00315     free( _p_sys );
00316 }
00317 
00318 #endif /* HAVE_AVAHI_CLIENT */

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