00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
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
00071
00072 static int create_service( bonjour_t * );
00073
00074
00075
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
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
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
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
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
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