1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2005 the VideoLAN team
7 * Authors: Jon Lech Johansen <jon@nanocrew.net>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
35 #ifdef HAVE_AVAHI_CLIENT
38 #include <avahi-client/client.h>
40 # include <avahi-client/publish.h>
41 # include <avahi-client/lookup.h>
43 #include <avahi-common/alternative.h>
44 #include <avahi-common/simple-watch.h>
45 #include <avahi-common/malloc.h>
46 #include <avahi-common/error.h>
48 /*****************************************************************************
50 *****************************************************************************/
51 typedef struct poll_thread_t
55 AvahiSimplePoll *simple_poll;
58 typedef struct bonjour_t
62 poll_thread_t *poll_thread;
63 AvahiSimplePoll *simple_poll;
64 AvahiEntryGroup *group;
72 /*****************************************************************************
74 *****************************************************************************/
75 static int create_service( bonjour_t * );
77 /*****************************************************************************
78 * entry_group_callback
79 *****************************************************************************/
80 static void entry_group_callback( AvahiEntryGroup *g,
81 AvahiEntryGroupState state,
85 bonjour_t *p_sys = (bonjour_t *)userdata;
87 if( state == AVAHI_ENTRY_GROUP_ESTABLISHED )
89 msg_Dbg( p_sys->p_log, "service '%s' successfully established",
92 else if( state == AVAHI_ENTRY_GROUP_COLLISION )
96 n = avahi_alternative_service_name( p_sys->psz_name );
97 avahi_free( p_sys->psz_name );
100 create_service( p_sys );
104 /*****************************************************************************
106 *****************************************************************************/
107 static int create_service( bonjour_t *p_sys )
111 if( p_sys->group == NULL )
113 p_sys->group = avahi_entry_group_new( p_sys->client,
114 entry_group_callback,
116 if( p_sys->group == NULL )
118 msg_Err( p_sys->p_log, "failed to create avahi entry group: %s",
119 avahi_strerror( avahi_client_errno( p_sys->client ) ) );
124 error = avahi_entry_group_add_service( p_sys->group, AVAHI_IF_UNSPEC,
126 AVAHI_PROTO_UNSPEC, 0, p_sys->psz_name,
128 AVAHI_PROTO_UNSPEC, p_sys->psz_name,
130 p_sys->psz_stype, NULL, NULL,
132 p_sys->psz_txt, NULL );
135 msg_Err( p_sys->p_log, "failed to add %s service: %s",
136 p_sys->psz_stype, avahi_strerror( error ) );
140 error = avahi_entry_group_commit( p_sys->group );
143 msg_Err( p_sys->p_log, "failed to commit entry group: %s",
144 avahi_strerror( error ) );
151 /*****************************************************************************
153 *****************************************************************************/
154 static void client_callback( AvahiClient *c,
155 AvahiClientState state,
158 bonjour_t *p_sys = (bonjour_t *)userdata;
160 if( state == AVAHI_CLIENT_S_RUNNING )
163 create_service( p_sys );
165 else if( state == AVAHI_CLIENT_S_COLLISION )
167 if( p_sys->group != NULL )
168 avahi_entry_group_reset( p_sys->group );
171 else if( state == AVAHI_CLIENT_FAILURE &&
172 (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) )
174 else if( state == AVAHI_CLIENT_DISCONNECTED )
177 msg_Err( p_sys->p_log, "avahi client disconnected" );
178 avahi_simple_poll_quit( p_sys->simple_poll );
182 /*****************************************************************************
183 * poll_iterate_thread
184 *****************************************************************************/
185 static void* poll_iterate_thread( vlc_object_t *p_this )
187 poll_thread_t *p_pt = (poll_thread_t*)p_this;
188 vlc_thread_ready( p_pt );
190 while( vlc_object_alive (p_pt) )
191 if( avahi_simple_poll_iterate( p_pt->simple_poll, 100 ) != 0 )
197 /*****************************************************************************
198 * bonjour_start_service
199 *****************************************************************************/
200 void *bonjour_start_service( vlc_object_t *p_log, const char *psz_stype,
201 const char *psz_name, int i_port, char *psz_txt )
206 p_sys = (bonjour_t *)malloc( sizeof(*p_sys) );
210 memset( p_sys, 0, sizeof(*p_sys) );
212 p_sys->p_log = p_log;
214 p_sys->i_port = i_port;
215 p_sys->psz_name = avahi_strdup( psz_name );
216 p_sys->psz_stype = avahi_strdup( psz_stype );
217 if( p_sys->psz_name == NULL || p_sys->psz_stype == NULL )
220 if( psz_txt != NULL )
222 p_sys->psz_txt = avahi_strdup( psz_txt );
223 if( p_sys->psz_txt == NULL )
227 p_sys->simple_poll = avahi_simple_poll_new();
228 if( p_sys->simple_poll == NULL )
230 msg_Err( p_sys->p_log, "failed to create avahi simple pool" );
234 p_sys->client = avahi_client_new( avahi_simple_poll_get(p_sys->simple_poll),
238 client_callback, p_sys, &err );
239 if( p_sys->client == NULL )
241 msg_Err( p_sys->p_log, "failed to create avahi client: %s",
242 avahi_strerror( err ) );
246 p_sys->poll_thread = vlc_object_create( p_sys->p_log,
247 sizeof(poll_thread_t) );
248 if( p_sys->poll_thread == NULL )
250 p_sys->poll_thread->simple_poll = p_sys->simple_poll;
252 if( vlc_thread_create( p_sys->poll_thread, "Avahi Poll Iterate Thread",
254 VLC_THREAD_PRIORITY_HIGHEST, false ) )
256 msg_Err( p_sys->p_log, "failed to create poll iterate thread" );
260 return (void *)p_sys;
263 if( p_sys->poll_thread != NULL )
264 vlc_object_release( p_sys->poll_thread );
265 if( p_sys->client != NULL )
266 avahi_client_free( p_sys->client );
267 if( p_sys->simple_poll != NULL )
268 avahi_simple_poll_free( p_sys->simple_poll );
269 if( p_sys->psz_stype != NULL )
270 avahi_free( p_sys->psz_stype );
271 if( p_sys->psz_name != NULL )
272 avahi_free( p_sys->psz_name );
273 if( p_sys->psz_txt != NULL )
274 avahi_free( p_sys->psz_txt );
281 /*****************************************************************************
282 * bonjour_stop_service
283 *****************************************************************************/
284 void bonjour_stop_service( void *_p_sys )
286 bonjour_t *p_sys = (bonjour_t *)_p_sys;
288 vlc_object_kill( p_sys->poll_thread );
289 vlc_thread_join( p_sys->poll_thread );
290 vlc_object_release( p_sys->poll_thread );
292 if( p_sys->group != NULL )
293 avahi_entry_group_free( p_sys->group );
295 avahi_client_free( p_sys->client );
296 avahi_simple_poll_free( p_sys->simple_poll );
298 if( p_sys->psz_name != NULL )
299 avahi_free( p_sys->psz_name );
301 if( p_sys->psz_txt != NULL )
302 avahi_free( p_sys->psz_txt );
304 avahi_free( p_sys->psz_stype );
309 #endif /* HAVE_AVAHI_CLIENT */