]> git.sesse.net Git - vlc/blob - modules/access_output/bonjour.c
Remove stdlib.h
[vlc] / modules / access_output / bonjour.c
1 /*****************************************************************************
2  * bonjour.c
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  * $Id$
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 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #include <vlc/vlc.h>
29
30 #ifdef HAVE_AVAHI_CLIENT
31 #include <vlc_sout.h>
32
33 #include <avahi-client/client.h>
34 #ifdef HAVE_AVAHI_06
35 # include <avahi-client/publish.h>
36 # include <avahi-client/lookup.h>
37 #endif
38 #include <avahi-common/alternative.h>
39 #include <avahi-common/simple-watch.h>
40 #include <avahi-common/malloc.h>
41 #include <avahi-common/error.h>
42
43 /*****************************************************************************
44  * Structures
45  *****************************************************************************/
46 typedef struct poll_thread_t
47 {
48     VLC_COMMON_MEMBERS
49
50     AvahiSimplePoll     *simple_poll;
51 } poll_thread_t;
52
53 typedef struct bonjour_t
54 {
55     vlc_object_t        *p_log;
56
57     poll_thread_t       *poll_thread;
58     AvahiSimplePoll     *simple_poll;
59     AvahiEntryGroup     *group;
60     AvahiClient         *client;
61     char                *psz_stype;
62     char                *psz_name;
63     int                 i_port;
64     char                *psz_txt;
65 } bonjour_t;
66
67 /*****************************************************************************
68  * Prototypes
69  *****************************************************************************/
70 static int create_service( bonjour_t * );
71
72 /*****************************************************************************
73  * entry_group_callback
74  *****************************************************************************/
75 static void entry_group_callback( AvahiEntryGroup *g,
76                                   AvahiEntryGroupState state,
77                                   void *userdata )
78 {
79     bonjour_t *p_sys = (bonjour_t *)userdata;
80
81     if( state == AVAHI_ENTRY_GROUP_ESTABLISHED )
82     {
83         msg_Dbg( p_sys->p_log, "service '%s' successfully established",
84                  p_sys->psz_name );
85     }
86     else if( state == AVAHI_ENTRY_GROUP_COLLISION )
87     {
88         char *n;
89
90         n = avahi_alternative_service_name( p_sys->psz_name );
91         avahi_free( p_sys->psz_name );
92         p_sys->psz_name = n;
93
94         create_service( p_sys );
95     }
96 }
97
98 /*****************************************************************************
99  * create_service
100  *****************************************************************************/
101 static int create_service( bonjour_t *p_sys )
102 {
103     int error;
104
105     if( p_sys->group == NULL )
106     {
107         p_sys->group = avahi_entry_group_new( p_sys->client,
108                                               entry_group_callback,
109                                               p_sys );
110         if( p_sys->group == NULL )
111         {
112             msg_Err( p_sys->p_log, "failed to create avahi entry group: %s",
113                      avahi_strerror( avahi_client_errno( p_sys->client ) ) );
114             return VLC_EGENERIC;
115         }
116     }
117
118     error = avahi_entry_group_add_service( p_sys->group, AVAHI_IF_UNSPEC,
119 #ifdef HAVE_AVAHI_06
120                                            AVAHI_PROTO_UNSPEC, 0, p_sys->psz_name,
121 #else
122                                            AVAHI_PROTO_UNSPEC, p_sys->psz_name,
123 #endif
124                                            p_sys->psz_stype, NULL, NULL,
125                                            p_sys->i_port,
126                                            p_sys->psz_txt, NULL );
127     if( error < 0 )
128     {
129         msg_Err( p_sys->p_log, "failed to add %s service: %s",
130                  p_sys->psz_stype, avahi_strerror( error ) );
131         return VLC_EGENERIC;
132     }
133
134     error = avahi_entry_group_commit( p_sys->group );
135     if( error < 0 )
136     {
137         msg_Err( p_sys->p_log, "failed to commit entry group: %s",
138                  avahi_strerror( error ) );
139         return VLC_EGENERIC;
140     }
141
142     return VLC_SUCCESS;
143 }
144
145 /*****************************************************************************
146  * client_callback
147  *****************************************************************************/
148 static void client_callback( AvahiClient *c,
149                              AvahiClientState state,
150                              void * userdata )
151 {
152     bonjour_t *p_sys = (bonjour_t *)userdata;
153
154     if( state == AVAHI_CLIENT_S_RUNNING )
155     {
156         p_sys->client = c;
157         create_service( p_sys );
158     }
159     else if( state == AVAHI_CLIENT_S_COLLISION )
160     {
161         if( p_sys->group != NULL )
162             avahi_entry_group_reset( p_sys->group );
163     }
164 #ifdef HAVE_AVAHI_06
165     else if( state == AVAHI_CLIENT_FAILURE &&
166               (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) )
167 #else
168     else if( state == AVAHI_CLIENT_DISCONNECTED )
169 #endif
170     {
171         msg_Err( p_sys->p_log, "avahi client disconnected" );
172         avahi_simple_poll_quit( p_sys->simple_poll );
173     }
174 }
175
176 /*****************************************************************************
177  * poll_iterate_thread
178  *****************************************************************************/
179 static void poll_iterate_thread( poll_thread_t *p_pt )
180 {
181     vlc_thread_ready( p_pt );
182
183     while( !p_pt->b_die )
184         if( avahi_simple_poll_iterate( p_pt->simple_poll, 100 ) != 0 )
185             break;
186 }
187
188 /*****************************************************************************
189  * bonjour_start_service
190  *****************************************************************************/
191 void *bonjour_start_service( vlc_object_t *p_log, char *psz_stype,
192                             char *psz_name, int i_port, char *psz_txt )
193 {
194     int err;
195     bonjour_t *p_sys;
196
197     p_sys = (bonjour_t *)malloc( sizeof(*p_sys) );
198     if( p_sys == NULL )
199     {
200         msg_Err( p_log, "out of memory" );
201         return NULL;
202     }
203
204     memset( p_sys, 0, sizeof(*p_sys) );
205
206     p_sys->p_log = p_log;
207
208     p_sys->i_port = i_port;
209     p_sys->psz_name = avahi_strdup( psz_name );
210     p_sys->psz_stype = avahi_strdup( psz_stype );
211     if( p_sys->psz_name == NULL || p_sys->psz_stype == NULL )
212     {
213         msg_Err( p_sys->p_log, "out of memory" );
214         goto error;
215     }
216
217     if( psz_txt != NULL )
218     {
219         p_sys->psz_txt = avahi_strdup( psz_txt );
220         if( p_sys->psz_txt == NULL )
221         {
222             msg_Err( p_sys->p_log, "out of memory" );
223             goto error;
224         }
225     }
226
227     p_sys->simple_poll = avahi_simple_poll_new();
228     if( p_sys->simple_poll == NULL )
229     {
230         msg_Err( p_sys->p_log, "failed to create avahi simple pool" );
231         goto error;
232     }
233
234     p_sys->client = avahi_client_new( avahi_simple_poll_get(p_sys->simple_poll),
235 #ifdef HAVE_AVAHI_06
236                                       0,
237 #endif
238                                       client_callback, p_sys, &err );
239     if( p_sys->client == NULL )
240     {
241         msg_Err( p_sys->p_log, "failed to create avahi client: %s",
242                  avahi_strerror( err ) );
243         goto error;
244     }
245
246     p_sys->poll_thread = vlc_object_create( p_sys->p_log,
247                                             sizeof(poll_thread_t) );
248     if( p_sys->poll_thread == NULL )
249     {
250         msg_Err( p_sys->p_log, "out of memory" );
251         goto error;
252     }
253     p_sys->poll_thread->simple_poll = p_sys->simple_poll;
254
255     if( vlc_thread_create( p_sys->poll_thread, "Avahi Poll Iterate Thread",
256                            poll_iterate_thread,
257                            VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) )
258     {
259         msg_Err( p_sys->p_log, "failed to create poll iterate thread" );
260         goto error;
261     }
262
263     return (void *)p_sys;
264
265 error:
266     if( p_sys->poll_thread != NULL )
267         vlc_object_destroy( p_sys->poll_thread );
268     if( p_sys->client != NULL )
269         avahi_client_free( p_sys->client );
270     if( p_sys->simple_poll != NULL )
271         avahi_simple_poll_free( p_sys->simple_poll );
272     if( p_sys->psz_stype != NULL )
273         avahi_free( p_sys->psz_stype );
274     if( p_sys->psz_name != NULL )
275         avahi_free( p_sys->psz_name );
276     if( p_sys->psz_txt != NULL )
277         avahi_free( p_sys->psz_txt );
278
279     free( (void *)p_sys );
280
281     return NULL;
282 }
283
284 /*****************************************************************************
285  * bonjour_stop_service
286  *****************************************************************************/
287 void bonjour_stop_service( void *_p_sys )
288 {
289     bonjour_t *p_sys = (bonjour_t *)_p_sys;
290
291     vlc_object_kill( p_sys->poll_thread );
292     vlc_thread_join( p_sys->poll_thread );
293     vlc_object_destroy( p_sys->poll_thread );
294
295     if( p_sys->group != NULL )
296         avahi_entry_group_free( p_sys->group );
297
298     avahi_client_free( p_sys->client );
299     avahi_simple_poll_free( p_sys->simple_poll );
300
301     if( p_sys->psz_name != NULL )
302         avahi_free( p_sys->psz_name );
303
304     if( p_sys->psz_txt != NULL )
305         avahi_free( p_sys->psz_txt );
306
307     avahi_free( p_sys->psz_stype );
308
309     free( _p_sys );
310 }
311
312 #endif /* HAVE_AVAHI_CLIENT */