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