]> git.sesse.net Git - vlc/blob - modules/access/slp.c
* src/input/control.c: added INPUT_ADD_INFO/INPUT_SET_NAME to input_Control().
[vlc] / modules / access / slp.c
1 /*****************************************************************************
2  * slp.c: SLP access plugin
3  *****************************************************************************
4  * Copyright (C) 2002-2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Loïc Minier <lool@videolan.org>
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                                /* malloc */
28
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31
32 #include <vlc_playlist.h>
33
34 #include <slp.h>
35
36 /*****************************************************************************
37  * Local prototypes
38  *****************************************************************************/
39 static int  Open  ( vlc_object_t * );
40 static void Close ( vlc_object_t * );
41 static ssize_t Read( input_thread_t *, byte_t *, size_t );
42
43 static int  Init  ( vlc_object_t * );
44 static void End   ( vlc_object_t * );
45 static int  Demux ( input_thread_t * );
46
47 int i_group;
48
49 /*****************************************************************************
50  * Module descriptor
51  *****************************************************************************/
52
53 #if 0
54 #define SRVTYPE_TEXT /*N_*/("SLP service type")
55 #define SRVTYPE_LONGTEXT /*N_*/( \
56     "The service type string for SLP queries, including the authority " \
57     "string (if any) for the request. May not be empty." )
58 #endif
59
60 #define ATTRIDS_TEXT N_("SLP attribute identifiers")
61 #define ATTRIDS_LONGTEXT N_( \
62     "This string is a comma separated list of attribute identifiers to " \
63     "search for a playlist title or empty to use all attributes." )
64
65 #define SCOPELIST_TEXT N_("SLP scopes list")
66 #define SCOPELIST_LONGTEXT N_( \
67     "This string is a comma separated list of scope names or empty if you " \
68     "want to use the default scopes. It is used in all SLP queries." )
69
70 #define NAMINGAUTHORITY_TEXT N_("SLP naming authority")
71 #define NAMINGAUTHORITY_LONGTEXT N_( \
72     "This string is a list of naming authorities to search. " \
73     "Use \"*\" for all and the empty string for the default of IANA." )
74
75 #define FILTER_TEXT N_("SLP LDAP filter")
76 #define FILTER_LONGTEXT N_( \
77     "This is a query formulated of attribute pattern matching expressions " \
78     "in the form of an LDAPv3 search filter or empty for all answers." )
79
80 #define LANG_TEXT N_("Language requested in SLP requests")
81 #define LANG_LONGTEXT N_( \
82     "RFC 1766 Language tag for the natural language locale of requests, " \
83     "leave empty to use the default locale. It is used in all SLP queries." )
84
85 vlc_module_begin();
86     set_description( _("SLP input") );
87
88     add_string( "slp-attrids", "", NULL, ATTRIDS_TEXT, ATTRIDS_LONGTEXT,
89                 VLC_TRUE );
90     add_string( "slp-scopelist", "", NULL, SCOPELIST_TEXT,
91                 SCOPELIST_LONGTEXT, VLC_TRUE );
92     add_string( "slp-namingauthority", "*", NULL, NAMINGAUTHORITY_TEXT,
93                 NAMINGAUTHORITY_LONGTEXT, VLC_TRUE );
94     add_string( "slp-filter", "", NULL, FILTER_TEXT, FILTER_LONGTEXT,
95                 VLC_TRUE );
96     add_string( "slp-lang", "", NULL, LANG_TEXT, LANG_LONGTEXT, VLC_TRUE );
97
98     set_capability( "access", 0 );
99     set_callbacks( Open, Close );
100
101     add_submodule();
102         add_shortcut( "demux_slp" );
103         set_capability( "demux", 0 );
104         set_callbacks( Init, End );
105 vlc_module_end();
106
107 /*****************************************************************************
108  * AttrCallback: updates the description of a playlist item
109  *****************************************************************************/
110 static SLPBoolean AttrCallback( SLPHandle slph_slp,
111                            const char * psz_attrlist,
112                            SLPError slpe_errcode,
113                            void * p_cookie )
114 {
115     playlist_item_t * p_playlist_item = (playlist_item_t *)p_cookie;
116
117     /* our callback was only called to tell us there's nothing more to read */
118     if( slpe_errcode == SLP_LAST_CALL )
119     {
120         return SLP_TRUE;
121     }
122
123     /* or there was a problem with getting the data we requested */
124     if( (slpe_errcode != SLP_OK) )
125     {
126 #if 0
127         msg_Err( (vlc_object_t*)NULL,
128                  "AttrCallback got an error %i with attribute %s",
129                  slpe_errcode,
130                  psz_attrlist );
131 #endif
132         return SLP_TRUE;
133     }
134
135     if( p_playlist_item->input.psz_name )
136         free( p_playlist_item->input.psz_name );
137
138     p_playlist_item->input.psz_name = strdup(psz_attrlist); /* NULL is checked */
139     return SLP_TRUE;
140 }
141
142 /*****************************************************************************
143  * SrvUrlCallback: adds an entry to the playlist
144  *****************************************************************************/
145 static SLPBoolean SrvUrlCallback( SLPHandle slph_slp,
146                            const char * psz_srvurl,
147                            uint16_t i_lifetime,
148                            SLPError slpe_errcode,
149                            void * p_cookie )
150 {
151     input_thread_t *p_input = (input_thread_t  *)p_cookie;
152     playlist_t * p_playlist;
153     char psz_item[42] = ""; //"udp:@";
154     char * psz_s;                           /* to hold the uri of the stream */
155     SLPHandle slph_slp3;
156     SLPError slpe_result;
157     playlist_item_t * p_playlist_item;
158
159     /* our callback was only called to tell us there's nothing more to read */
160     if( slpe_errcode == SLP_LAST_CALL )
161     {
162         return SLP_TRUE;
163     }
164
165     msg_Dbg( p_input,"URL: %s", psz_srvurl );
166
167     /* or there was a problem with getting the data we requested */
168     if( (slpe_errcode != SLP_OK) )
169     {
170         msg_Err( p_input, "SrvUrlCallback got an error %i with URL %s",
171                  slpe_errcode, psz_srvurl );
172         return SLP_TRUE;
173     }
174
175     /* search the returned address after a double-slash */
176     psz_s = strstr( psz_srvurl, "//" );
177     if( psz_s == NULL )
178     {
179         msg_Err( p_input,
180                  "SrvUrlCallback got a strange string of your libslp" );
181         return SLP_TRUE;
182     }
183     /* skip the slashes */
184     psz_s = &psz_s[2];
185     /* add udp:@ in front of the address */
186     psz_s = strncat( psz_item,
187                      psz_s,
188                      sizeof(psz_item) - strlen(psz_item) - 1 );
189
190     /* create a playlist  item */
191     p_playlist_item = playlist_ItemNew( p_input, psz_s, NULL );
192     if( p_playlist_item == NULL )
193     {
194         msg_Err( p_input, "out of memory" );
195         return SLP_TRUE;
196     }
197
198     p_playlist_item->i_group = i_group;
199     p_playlist_item->b_enabled = VLC_TRUE;
200
201     /* search the description of the stream */
202     if( SLPOpen( config_GetPsz( p_input, "slp-lang" ),
203                  SLP_FALSE,                              /* synchronous ops */
204                  &slph_slp3 ) == SLP_OK )
205     {
206         /* search all attributes */
207         slpe_result = SLPFindAttrs( slph_slp3,
208                                     psz_srvurl,
209                                     config_GetPsz( p_input, "slp-scopelist" ),
210                                     config_GetPsz( p_input, "slp-attrids" ),
211                                     AttrCallback,
212                                     p_playlist_item
213                                   );
214
215         /* we're done, clean up */
216         SLPClose( slph_slp3 );
217     }
218
219     /* search the main playlist object */
220     p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
221                                   FIND_ANYWHERE );
222     if( p_playlist == NULL )
223     {
224         msg_Warn( p_input, "could not find playlist, not adding entries" );
225         return SLP_TRUE;
226     }
227
228     playlist_AddItem( p_playlist, p_playlist_item,
229                       PLAYLIST_APPEND, PLAYLIST_END );
230     vlc_object_release( p_playlist );
231
232     msg_Info( p_input, "added « %s » (lifetime %i) to playlist",
233               psz_srvurl, i_lifetime );
234
235     return SLP_TRUE;
236 }
237
238 /*****************************************************************************
239  * SrvTypeCallback: searchs all servers of a certain type
240  *****************************************************************************/
241 static SLPBoolean SrvTypeCallback( SLPHandle slph_slp,
242                            const char * psz_srvurl,
243                            SLPError slpe_errcode,
244                            void * p_cookie )
245 {
246     input_thread_t * p_input = (input_thread_t  *)p_cookie;
247     SLPError slpe_result;
248     SLPHandle slph_slp2;
249     char *psz_eos;
250     char *psz_service;
251
252     msg_Dbg( p_input, "services: %s", psz_srvurl );
253     /* our callback was only called to tell us there's nothing more to read */
254     if( slpe_errcode == SLP_LAST_CALL )
255     {
256         return SLP_TRUE;
257     }
258
259     msg_Dbg( p_input, "services: %s", psz_srvurl );
260
261     /* or there was a problem with getting the data we requested */
262     if( slpe_errcode != SLP_OK )
263     {
264         msg_Err( p_input, "SrvTypeCallback got an error %i with URL %s",
265                  slpe_errcode, psz_srvurl );
266         return SLP_TRUE;
267     }
268
269     /* get a new handle to the library */
270     if( SLPOpen( config_GetPsz( p_input, "slp-lang" ),
271                  SLP_FALSE,                              /* synchronous ops */
272                  &slph_slp2 ) == SLP_OK )
273     {
274         /* search for services */
275         while(1)
276         {
277             if( *psz_srvurl == '\0')  break;
278
279             if( !strncasecmp( psz_srvurl, "service:", 8 ) )
280             {
281                 while(1)
282                 {
283                     psz_eos = strchr( psz_srvurl, ',');
284                     if(!psz_eos) break;
285                     if(!strncasecmp(psz_eos+1,"service:",8)) break;
286                 }
287
288                 if(psz_eos)
289                     *psz_eos = '\0';
290
291                 psz_service = strdup( psz_srvurl);
292
293                 msg_Dbg( p_input, "getting details for %s", psz_service );
294
295                 slpe_result = SLPFindSrvs( slph_slp2,
296                                    psz_service,
297                                    config_GetPsz( p_input, "slp-scopelist" ),
298                                    config_GetPsz( p_input, "slp-filter" ),
299                                    SrvUrlCallback,
300                                    p_input );
301
302                 if(psz_eos)
303                     psz_srvurl = psz_eos;
304
305 #if 0
306                 SLPClose( slph_slp2 );
307 #endif
308                 if( slpe_result != SLP_OK )
309                 {
310                    msg_Err( p_input,
311                            "SLPFindSrvs error %i finding servers of type %s",
312                            slpe_result, psz_service );
313                 }
314             }
315             psz_srvurl++;
316         }
317     }
318                 SLPClose( slph_slp2 );
319
320     return SLP_TRUE;
321 }
322
323 /*****************************************************************************
324  * Open: initialize library for the access module
325  *****************************************************************************/
326 static int Open( vlc_object_t * p_this )
327 {
328     input_thread_t *   p_input = (input_thread_t *)p_this;
329     SLPError           slpe_result;
330     SLPHandle          slph_slp;
331     playlist_t *       p_playlist;
332     playlist_group_t * p_group;
333
334     /* remove the "slp:" entry of the playlist */
335     p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
336                                                  FIND_ANYWHERE );
337     if( !p_playlist )
338     {
339         msg_Warn( p_input, "hey I can't find the main playlist, I need it" );
340         return VLC_FALSE;
341     }
342
343     p_group = playlist_CreateGroup( p_playlist , "SLP" );
344     i_group = p_group->i_id;
345     p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
346     vlc_object_release( (vlc_object_t *)p_playlist );
347
348     /* get a new handle to the library */
349     if( SLPOpen( config_GetPsz( p_input, "slp-lang" ),
350                  SLP_FALSE,                              /* synchronous ops */
351                  &slph_slp ) == SLP_OK )
352     {
353         /* search all service types */
354         slpe_result =
355             SLPFindSrvTypes( slph_slp,
356                              config_GetPsz( p_input, "slp-namingauthority" ),
357                              config_GetPsz( p_input, "slp-scopelist" ),
358                              SrvTypeCallback,
359                              p_input );
360         /* we're done, clean up */
361         SLPClose( slph_slp );
362     }
363
364     if( !p_input->psz_demux || !*p_input->psz_demux )
365     {
366         p_input->psz_demux = "demux_slp";
367     }
368
369     p_input->pf_read = Read;
370     p_input->pf_set_program = NULL;
371     p_input->pf_set_area = NULL;
372     p_input->pf_seek = NULL;
373
374     vlc_mutex_lock( &p_input->stream.stream_lock );
375     p_input->stream.b_pace_control = VLC_FALSE;
376     p_input->stream.b_seekable = VLC_FALSE;
377     p_input->stream.p_selected_area->i_tell = 0;
378     p_input->stream.p_selected_area->i_size = 0;
379     p_input->stream.i_method = INPUT_METHOD_SLP;
380     vlc_mutex_unlock( &p_input->stream.stream_lock );
381     p_input->i_mtu = 0;
382
383     return VLC_SUCCESS;
384 }
385
386 /*****************************************************************************
387  * Close: close access
388  *****************************************************************************/
389 static void Close( vlc_object_t * p_this )
390 {
391     return;
392 }
393
394 /*****************************************************************************
395  * Read: should fill but zeroes the buffer
396  *****************************************************************************/
397 static ssize_t Read  ( input_thread_t *p_input, byte_t *p_buffer, size_t s )
398 {
399     memset( p_buffer, 0, s );
400     return s;
401 }
402
403 /*****************************************************************************
404  * Init: initialize demux
405  *****************************************************************************/
406 static int Init ( vlc_object_t *p_this )
407 {
408     input_thread_t *p_input = (input_thread_t *)p_this;
409
410     if( p_input->stream.i_method != INPUT_METHOD_SLP )
411     {
412         return VLC_FALSE;
413     }
414
415     p_input->pf_demux  = Demux;
416     p_input->pf_demux_control = demux_vaControlDefault;
417     p_input->pf_rewind = NULL;
418
419     return VLC_SUCCESS;
420 }
421
422 /*****************************************************************************
423  * Demux: should demux but does nothing
424  *****************************************************************************/
425 static int Demux ( input_thread_t * p_input )
426 {
427     return 0;
428 }
429
430 /*****************************************************************************
431  * End: end demux
432  *****************************************************************************/
433 static void End ( vlc_object_t *p_this )
434 {
435     return;
436 }