1 /*****************************************************************************
2 * sap.c : SAP interface module
3 *****************************************************************************
4 * Copyright (C) 2001 VideoLAN
5 * $Id: sap.c,v 1.18 2003/07/05 15:00:28 zorglub Exp $
7 * Authors: Arnaud Schauly <gitan@via.ecp.fr>
8 * Clément Stenac <zorglub@via.ecp.fr>
9 * Damien Lucas <nitrox@videolan.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
29 #include <stdlib.h> /* malloc(), free() */
32 #include <errno.h> /* ENOMEM */
45 #ifdef HAVE_SYS_TIME_H
46 # include <sys/time.h>
48 #include <sys/types.h>
52 # include <winsock2.h>
53 # include <ws2tcpip.h>
55 # define IN_MULTICAST(a) IN_CLASSD(a)
58 # include <sys/socket.h>
59 # include <netinet/in.h>
61 # include <arpa/inet.h>
62 # elif defined( SYS_BEOS )
63 # include <net/netdb.h>
68 # define close(a) CloseHandle(a);
69 #elif defined( WIN32 )
70 # define close(a) closesocket(a);
75 #define MAX_LINE_LENGTH 256
77 /* SAP is always on that port */
78 #define HELLO_PORT 9875
79 #define HELLO_GROUP "224.2.127.254"
82 #define IPV6_ADDR_1 "FF0" /* Scope is inserted between them */
83 #define IPV6_ADDR_2 "::2:7FFE"
85 /*****************************************************************************
87 *****************************************************************************/
89 typedef struct media_descr_t media_descr_t;
90 typedef struct sess_descr_t sess_descr_t;
92 static int Activate ( vlc_object_t * );
93 static void Run ( intf_thread_t *p_intf );
94 static int Kill ( intf_thread_t * );
96 static ssize_t NetRead ( intf_thread_t*, int, int , byte_t *, size_t );
98 /* playlist related functions */
99 static int sess_toitem( intf_thread_t *, sess_descr_t * );
101 /* sap/sdp related functions */
102 static int parse_sap ( char * );
103 static int packet_handle ( intf_thread_t *, char *, int );
104 static sess_descr_t * parse_sdp( intf_thread_t *, char * ) ;
106 /* specific sdp fields parsing */
108 static void cfield_parse( char *, char ** );
109 static void mfield_parse( char *psz_mfield, char **ppsz_proto,
112 static void free_sd( sess_descr_t * );
114 /* Detect multicast addresses */
115 static int ismult( char * );
117 /* The struct that contains sdp informations */
118 struct sess_descr_t {
121 char *psz_sessionname;
122 char *psz_information;
129 char *psz_connection;
131 media_descr_t ** pp_media;
134 /* All this informations are not useful yet. */
135 struct media_descr_t {
137 char *psz_mediaconnection;
140 /*****************************************************************************
142 *****************************************************************************/
144 #define SAP_ADDR_TEXT N_("SAP multicast address")
145 #define SAP_ADDR_LONGTEXT N_("SAP multicast address")
146 #define SAP_IPV4_TEXT N_("No IPv4-SAP listening")
147 #define SAP_IPV4_LONGTEXT N_("Set this if you do not want SAP to listen for IPv4 announces")
148 #define SAP_IPV6_TEXT N_("IPv6-SAP listening")
149 #define SAP_IPV6_LONGTEXT N_("Set this if you want SAP to listen for IPv6 announces")
150 #define SAP_SCOPE_TEXT N_("IPv6 SAP scope")
151 #define SAP_SCOPE_LONGTEXT N_("Sets the scope for IPv6 announces (default is 8)")
154 add_category_hint( N_("SAP"), NULL, VLC_TRUE );
155 add_string( "sap-addr", NULL, NULL,
156 SAP_ADDR_TEXT, SAP_ADDR_LONGTEXT, VLC_TRUE );
158 add_bool( "no-sap-ipv4", 0 , NULL,
159 SAP_IPV4_TEXT,SAP_IPV4_LONGTEXT, VLC_TRUE);
161 add_bool( "sap-ipv6", 0 , NULL,
162 SAP_IPV6_TEXT, SAP_IPV6_LONGTEXT, VLC_TRUE);
164 add_string( "sap-ipv6-scope", "8" , NULL,
165 SAP_SCOPE_TEXT, SAP_SCOPE_LONGTEXT, VLC_TRUE);
167 set_description( _("SAP interface") );
168 set_capability( "interface", 0 );
169 set_callbacks( Activate, NULL);
172 /*****************************************************************************
173 * Activate: initialize and create stuff
174 *****************************************************************************/
175 static int Activate( vlc_object_t *p_this )
177 intf_thread_t *p_intf = (intf_thread_t*)p_this;
179 p_intf->pf_run = Run;
184 /*****************************************************************************
186 *****************************************************************************
187 * Listens to SAP packets, and sends them to packet_handle
188 *****************************************************************************/
189 #define MAX_SAP_BUFFER 2000
191 static void Run( intf_thread_t *p_intf )
195 char *psz_network = NULL;
199 int no_sap_ipv4 = config_GetInt( p_intf, "no-sap-ipv4" );
200 int sap_ipv6 = config_GetInt( p_intf, "sap-ipv6" );
201 char *sap_ipv6_scope = config_GetPsz( p_intf, "sap-ipv6-scope" );
203 char buffer[MAX_SAP_BUFFER + 1];
206 network_socket_t socket_desc;
208 if( no_sap_ipv4 == -1 || sap_ipv6 == -1 || sap_ipv6_scope == NULL )
210 msg_Warn( p_intf, "Unable to parse module configuration" );
214 /* Prepare IPv4 Networking */
215 if ( no_sap_ipv4 == 0)
217 if( !(psz_addr = config_GetPsz( p_intf, "sap-addr" ) ) )
219 psz_addr = strdup( HELLO_GROUP );
222 /* Prepare the network_socket_t structure */
223 socket_desc.i_type = NETWORK_UDP;
224 socket_desc.psz_bind_addr = psz_addr;
225 socket_desc.i_bind_port = HELLO_PORT;
226 socket_desc.psz_server_addr = "";
227 socket_desc.i_server_port = 0;
228 p_intf->p_private = (void*) &socket_desc;
230 psz_network = "ipv4";
232 /* Create, Bind the socket, ... with the appropriate module */
234 if( !( p_network = module_Need( p_intf, "network", psz_network ) ) )
236 msg_Warn( p_intf, "failed to open a connection (udp)" );
239 module_Unneed( p_intf, p_network );
241 fd = socket_desc.i_handle;
244 /* Prepare IPv6 Networking */
247 /* Prepare the network_socket_t structure */
249 psz_addrv6=(char *)malloc(sizeof(char)*38);
250 /* Max size of an IPv6 address */
252 sprintf(psz_addrv6,"[%s%c%s]",IPV6_ADDR_1,
253 sap_ipv6_scope[0],IPV6_ADDR_2);
255 socket_desc.i_type = NETWORK_UDP;
256 socket_desc.psz_bind_addr = psz_addrv6;
257 socket_desc.i_bind_port = HELLO_PORT;
258 socket_desc.psz_server_addr = "";
259 socket_desc.i_server_port = 0;
260 p_intf->p_private = (void*) &socket_desc;
262 psz_network = "ipv6";
264 /* Create, Bind the socket, ... with the appropriate module */
266 if( !( p_network = module_Need( p_intf, "network", psz_network ) ) )
268 msg_Warn( p_intf, "failed to open a connection (udp)" );
271 module_Unneed( p_intf, p_network );
273 fdv6 = socket_desc.i_handle;
277 /* read SAP packets */
278 while( !p_intf->b_die )
282 //memset( buffer, 0, MAX_SAP_BUFFER + 1);
284 i_read = NetRead( p_intf, fd, fdv6, buffer, MAX_SAP_BUFFER );
288 msg_Err( p_intf, "Cannot read in the socket" );
294 buffer[i_read] = '\0';
296 packet_handle( p_intf, buffer, i_read );
301 close( socket_desc.i_handle );
304 /********************************************************************
306 *******************************************************************
307 * Kills the SAP interface.
308 ********************************************************************/
309 static int Kill( intf_thread_t *p_intf )
312 p_intf->b_die = VLC_TRUE;
317 /*******************************************************************
318 * sess_toitem : changes a sess_descr_t into a hurd of
319 * playlist_item_t, which are enqueued.
320 *******************************************************************
321 * Note : does not support sessions that take place on consecutive
322 * port or adresses yet.
323 *******************************************************************/
325 static int sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
327 playlist_item_t * p_item;
328 char *psz_uri, *psz_proto;
330 char *psz_uri_default;
333 playlist_t *p_playlist;
335 psz_uri_default = NULL;
336 cfield_parse( p_sd->psz_connection, &psz_uri_default );
338 for( i_count = 0 ; i_count < p_sd->i_media ; i_count++ )
340 p_item = malloc( sizeof( playlist_item_t ) );
343 msg_Err( p_intf, "Not enough memory for p_item in sesstoitem()" );
346 p_item->psz_name = strdup( p_sd->psz_sessionname );
348 p_item->i_status = 0;
349 p_item->b_autodeletion = VLC_FALSE;
350 p_item->psz_uri = NULL;
354 /* Build what we have to put in p_item->psz_uri, with the m and
357 if( !p_sd->pp_media[i_count] )
362 mfield_parse( p_sd->pp_media[i_count]->psz_medianame,
363 & psz_proto, & psz_port );
365 if( !psz_proto || !psz_port )
370 if( p_sd->pp_media[i_count]->psz_mediaconnection )
372 cfield_parse( p_sd->pp_media[i_count]->psz_mediaconnection,
377 psz_uri = psz_uri_default;
380 if( psz_uri == NULL )
386 /* Filling p_item->psz_uri */
387 i_multicast = ismult( psz_uri );
389 p_item->psz_uri = malloc( strlen( psz_proto ) + strlen( psz_uri ) +
390 strlen( psz_port ) + 5 +i_multicast );
391 if( p_item->psz_uri == NULL )
393 msg_Err( p_intf, "Not enough memory");
398 if( i_multicast == 1)
400 sprintf( p_item->psz_uri, "%s://@%s:%s", psz_proto,
405 sprintf( p_item->psz_uri, "%s://%s:%s", psz_proto,
409 /* Enqueueing p_item in the playlist */
413 p_playlist = vlc_object_find( p_intf,
414 VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
416 playlist_AddItem ( p_playlist, p_item,
417 PLAYLIST_CHECK_INSERT, PLAYLIST_END);
418 vlc_object_release( p_playlist );
429 /**********************************************************************
431 *********************************************************************
432 * put into *ppsz_uri, the the uri in the cfield, psz_cfield.
433 *********************************************************************/
435 static void cfield_parse( char *psz_cfield, char **ppsz_uri )
441 psz_pos = psz_cfield;
443 while( *psz_pos != ' ' && *psz_pos !='\0' )
448 while( *psz_pos != ' ' && *psz_pos !='\0' )
454 while( *psz_pos != ' ' && *psz_pos !='/'
455 && *psz_pos != '\0' )
471 /**********************************************************************
473 *********************************************************************
474 * put into *ppsz_proto, and *ppsz_port, the protocol and the port.
475 *********************************************************************/
478 static void mfield_parse( char *psz_mfield, char **ppsz_proto,
484 psz_pos = psz_mfield;
485 while( *psz_pos != '\0' && *psz_pos != ' ' )
490 *ppsz_port = psz_pos;
491 while( *psz_pos != '\0' && *psz_pos && *psz_pos !=' ' && *psz_pos!='/' )
495 if( *psz_pos == '/' ) // FIXME does not support multi-port
499 while( *psz_pos != '\0' && *psz_pos !=' ' )
506 *ppsz_proto = psz_pos;
507 while( *psz_pos!='\0' && *psz_pos !=' ' &&
510 *psz_pos = tolower( *psz_pos );
523 /***********************************************************************
524 * parse_sap : Takes care of the SAP headers
525 ***********************************************************************
526 * checks if the packet has the true headers ;
527 * returns the SAP header lenhth
528 ***********************************************************************/
530 static int parse_sap( char *p_packet )
532 // According to RFC 2974
533 int i_hlen = 4; // Minimum header length is 4
534 i_hlen += (p_packet[0] & 0x10) ? 16 : 4; // Address type IPv6=16bytes
535 i_hlen += p_packet[1]; // Authentification length
537 //Looks for the first '\0' byte after length
538 for(;p_packet[i_hlen]!='\0'; i_hlen++);
543 /*************************************************************************
544 * packet_handle : handle the received packet and enques the
545 * the understated session
546 *************************************************************************/
548 static int packet_handle( intf_thread_t * p_intf, char *p_packet, int i_len )
551 int i_hlen; // Header length
553 i_hlen = parse_sap(p_packet);
555 if( (i_hlen > 0) && (i_hlen < i_len) )
557 p_sd = parse_sdp( p_intf, p_packet + i_hlen +1);
560 sess_toitem ( p_intf, p_sd );
566 return VLC_FALSE; // Invalid Packet
572 /***********************************************************************
573 * parse_sdp : SDP parsing
574 * *********************************************************************
575 * Make a sess_descr_t with a psz
576 ***********************************************************************/
578 static sess_descr_t * parse_sdp( intf_thread_t * p_intf, char *p_packet )
582 // According to RFC 2327, the first bytes should be exactly "v="
583 if((p_packet[0] != 'v') || (p_packet[1] != '='))
585 msg_Warn(p_intf, "Bad SDP packet");
589 if( ( sd = malloc( sizeof(sess_descr_t) ) ) == NULL )
591 msg_Err( p_intf, "Not enough memory for sd in parse_sdp()" );
596 sd->psz_origin = NULL;
597 sd->psz_sessionname = NULL;
598 sd->psz_information = NULL;
600 sd->psz_emails = NULL;
601 sd->psz_phone = NULL;
603 sd->psz_repeat = NULL;
604 sd->psz_attribute = NULL;
605 sd->psz_connection = NULL;
609 while( *p_packet != '\0' )
611 #define FIELD_COPY( p ) \
612 p = strndup( &p_packet[2], i_field_len );
617 while( *p_packet == '\n' || *p_packet == ' ' || *p_packet == '\t' )
621 if( *p_packet == '\0' )
626 if( ( psz_end = strchr( p_packet, '\n' ) ) == NULL )
628 psz_end = p_packet + strlen( p_packet );
630 i_field_len = psz_end - &p_packet[2];
632 if( p_packet[1] == '=' && i_field_len > 0)
637 FIELD_COPY( sd->psz_version );
640 FIELD_COPY( sd->psz_origin );
643 FIELD_COPY( sd->psz_sessionname );
646 FIELD_COPY( sd->psz_information );
649 FIELD_COPY( sd->psz_uri );
652 FIELD_COPY( sd->psz_emails );
655 FIELD_COPY( sd->psz_phone );
658 FIELD_COPY( sd->psz_time );
661 FIELD_COPY( sd->psz_repeat );
664 FIELD_COPY( sd->psz_attribute );
671 realloc( sd->pp_media,
672 sizeof( media_descr_t ) * ( sd->i_media + 1 ) );
676 sd->pp_media = malloc( sizeof( void * ) );
679 sd->pp_media[sd->i_media] =
680 malloc( sizeof( media_descr_t ) );
681 sd->pp_media[sd->i_media]->psz_medianame = NULL;
682 sd->pp_media[sd->i_media]->psz_mediaconnection = NULL;
683 sd->pp_media[sd->i_media]->psz_medianame = strndup( &p_packet[2], i_field_len );
689 if( sd->i_media <= 0 )
691 FIELD_COPY(sd->psz_connection);
695 FIELD_COPY(sd->pp_media[sd->i_media - 1]->psz_mediaconnection);
710 if( p ) { free( p ); (p) = NULL; }
711 static void free_sd( sess_descr_t * p_sd )
716 FREE( p_sd->psz_origin );
717 FREE( p_sd->psz_sessionname );
718 FREE( p_sd->psz_information );
719 FREE( p_sd->psz_uri );
720 FREE( p_sd->psz_emails );
721 FREE( p_sd->psz_phone );
722 FREE( p_sd->psz_time );
723 FREE( p_sd->psz_repeat );
724 FREE( p_sd->psz_attribute );
725 FREE( p_sd->psz_connection );
727 for( i = 0; i < p_sd->i_media ; i++ )
729 FREE( p_sd->pp_media[i]->psz_medianame );
730 FREE( p_sd->pp_media[i]->psz_mediaconnection );
732 FREE( p_sd->pp_media );
743 /***********************************************************************
744 * ismult: returns true if we have a multicast address
745 ***********************************************************************/
747 static int ismult( char *psz_uri )
752 i_value = strtol( psz_uri, &psz_end, 0 );
755 if( psz_uri[0] == '[')
757 if( strncasecmp( &psz_uri[1], "FF0" , 3) ||
758 strncasecmp( &psz_uri[2], "FF0" , 3))
764 if( *psz_end != '.' ) { return( VLC_FALSE ); }
766 return( i_value < 224 ? VLC_FALSE : VLC_TRUE );
771 /*****************************************************************************
772 * Read: read on a file descriptor, checking b_die periodically
773 *****************************************************************************
775 ******************************************************************************/
776 static ssize_t NetRead( intf_thread_t *p_intf,
777 int i_handle, int i_handle_v6,
778 byte_t *p_buffer, size_t i_len)
784 struct timeval timeout;
791 /* Get the max handle for select */
792 if( i_handle_v6 > i_handle )
793 i_max_handle = i_handle_v6;
795 i_max_handle = i_handle;
798 /* Initialize file descriptor set */
800 if( i_handle > 0 ) FD_SET( i_handle, &fds );
801 if( i_handle_v6 > 0 ) FD_SET( i_handle_v6, &fds);
804 /* We'll wait 0.5 second if nothing happens */
806 timeout.tv_usec = 500000;
808 /* Find if some data is available */
809 i_ret = select( i_max_handle + 1, &fds,
810 NULL, NULL, &timeout );
812 if( i_ret == -1 && errno != EINTR )
814 msg_Err( p_intf, "network select error (%s)", strerror(errno) );
821 if(FD_ISSET( i_handle, &fds ))
823 i_recv = recv( i_handle, p_buffer, i_len, 0 );
828 if(FD_ISSET( i_handle_v6, &fds ))
830 i_recv = recv( i_handle_v6, p_buffer, i_len, 0 );
836 msg_Err( p_intf, "recv failed (%s)", strerror(errno) );