/*****************************************************************************
* Preamble
*****************************************************************************/
+
+#include <vlc/vlc.h>
+
#include <stdlib.h> /* free() */
#include <stdio.h> /* sprintf() */
#include <string.h> /* strerror() */
#include <ctype.h> /* tolower(), isxdigit() */
-#include <vlc/vlc.h>
-#include <vlc/sout.h>
+#include <vlc_sout.h>
+#include <vlc_network.h>
+#include <vlc_charset.h>
-#include "network.h"
-#include "charset.h"
+#include "stream_output.h"
/* SAP is always on that port */
#define SAP_PORT 9875
int i_limit;
};
+/* A SAP session descriptor, enqueued in the SAP handler queue */
+struct sap_session_t {
+ char *psz_sdp;
+ uint8_t *psz_data;
+ unsigned i_length;
+ sap_address_t *p_address;
+ session_descriptor_t *p_sd;
+
+ /* Last and next send */
+ mtime_t i_last;
+ mtime_t i_next;
+};
+
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int CalculateRate( sap_handler_t *p_sap, sap_address_t *p_address );
static char *SDPGenerate( sap_handler_t *p_sap,
const session_descriptor_t *p_session,
- const sap_address_t *p_addr );
+ const sap_address_t *p_addr, vlc_bool_t b_ssm );
static int announce_SendSAPAnnounce( sap_handler_t *p_sap,
sap_session_t *p_session );
static int announce_SAPAnnounceDel( sap_handler_t *p_sap,
session_descriptor_t *p_session );
-#define FREE( p ) if( p ) { free( p ); (p) = NULL; }
-
/**
* Create the SAP handler
for( i = 0 ; i< p_sap->i_sessions ; i++)
{
sap_session_t *p_session = p_sap->pp_sessions[i];
- FREE( p_session->psz_sdp );
- FREE( p_session->psz_data );
+ FREENULL( p_session->psz_sdp );
+ FREENULL( p_session->psz_data );
REMOVE_ELEM( p_sap->pp_sessions, p_sap->i_sessions , i );
- FREE( p_session );
+ FREENULL( p_session );
}
/* Free the remaining addresses */
for( i = 0 ; i< p_sap->i_addresses ; i++)
{
sap_address_t *p_address = p_sap->pp_addresses[i];
- FREE( p_address->psz_address );
+ FREENULL( p_address->psz_address );
if( p_address->i_rfd > -1 )
{
net_Close( p_address->i_rfd );
net_Close( p_address->i_wfd );
}
REMOVE_ELEM( p_sap->pp_addresses, p_sap->i_addresses, i );
- FREE( p_address );
+ FREENULL( p_address );
}
/* Free the structure */
{
int i_header_size, i;
char *psz_head, psz_addr[NI_MAXNUMERICHOST];
- vlc_bool_t b_ipv6 = VLC_FALSE;
+ vlc_bool_t b_ipv6 = VLC_FALSE, b_ssm = VLC_FALSE;
sap_session_t *p_sap_session;
mtime_t i_hash;
struct addrinfo hints, *res;
struct sockaddr_storage addr;
+ socklen_t addrlen;
vlc_mutex_lock( &p_sap->object_lock );
msg_Err( p_sap, "This should not happen. VLC needs fixing." );
return VLC_EGENERIC;
}
-
/* Determine SAP multicast address automatically */
memset( &hints, 0, sizeof( hints ) );
hints.ai_socktype = SOCK_DGRAM;
return VLC_EGENERIC;
}
- if( (unsigned)res->ai_addrlen > sizeof( addr ) )
+ addrlen = res->ai_addrlen;
+ if ((unsigned)addrlen > sizeof (addr))
{
vlc_mutex_unlock( &p_sap->object_lock );
vlc_freeaddrinfo( res );
return VLC_EGENERIC;
}
- memcpy( &addr, res->ai_addr, res->ai_addrlen );
+ memcpy (&addr, res->ai_addr, addrlen);
+ vlc_freeaddrinfo (res);
switch( addr.ss_family )
{
memcpy( a6->s6_addr + 2, "\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x02\x7f\xfe", 14 );
if( IN6_IS_ADDR_MULTICAST( a6 ) )
- /* force flags to zero, preserve scope */
+ {
+ /* SSM <=> ff3x::/32 */
+ b_ssm = (U32_AT (a6->s6_addr) & 0xfff0ffff) == 0xff300000;
+
+ /* force flags to zero, preserve scope */
a6->s6_addr[1] &= 0xf;
+ }
else
/* Unicast IPv6 - assume global scope */
memcpy( a6->s6_addr, "\xff\x0e", 2 );
ipv4 = 0;
else
/* other addresses => 224.2.127.254 */
+ {
+ /* SSM: 232.0.0.0/8 */
+ b_ssm = (ipv4 >> 24) == 232;
ipv4 = 0xe0027ffe;
+ }
if( ipv4 == 0 )
{
msg_Err( p_sap, "Out-of-scope multicast address "
"not supported by SAP: %s", p_session->psz_uri );
vlc_mutex_unlock( &p_sap->object_lock );
- vlc_freeaddrinfo( res );
return VLC_EGENERIC;
}
default:
vlc_mutex_unlock( &p_sap->object_lock );
- vlc_freeaddrinfo( res );
msg_Err( p_sap, "Address family %d not supported by SAP",
addr.ss_family );
return VLC_EGENERIC;
}
- i = vlc_getnameinfo( (struct sockaddr *)&addr, res->ai_addrlen,
+ i = vlc_getnameinfo( (struct sockaddr *)&addr, addrlen,
psz_addr, sizeof( psz_addr ), NULL, NI_NUMERICHOST );
- vlc_freeaddrinfo( res );
if( i )
{
/* XXX: Check for dupes */
p_sap_session = (sap_session_t*)malloc(sizeof(sap_session_t));
+ p_sap_session->p_sd = p_session;
p_sap_session->p_address = NULL;
/* Add the address to the buffer */
return VLC_ENOMEM;
}
p_address->psz_address = strdup( psz_addr );
- p_address->i_wfd = net_ConnectUDP( p_sap, psz_addr, SAP_PORT, 255 );
+ p_address->i_wfd = net_ConnectUDP( VLC_OBJECT(p_sap), psz_addr, SAP_PORT, 255 );
if( p_address->i_wfd != -1 )
{
char *ptr;
if( p_sap->b_control == VLC_TRUE )
{
- p_address->i_rfd = net_OpenUDP( p_sap, psz_addr, SAP_PORT, "", 0 );
+ p_address->i_rfd = net_ListenUDP1( (vlc_object_t*)p_sap, psz_addr, SAP_PORT );
if( p_address->i_rfd != -1 )
net_StopSend( p_address->i_rfd );
p_address->i_buff = 0;
if( p_session->psz_sdp == NULL )
{
p_session->psz_sdp = SDPGenerate( p_sap, p_session,
- p_sap_session->p_address );
+ p_sap_session->p_address, b_ssm );
if( p_session->psz_sdp == NULL )
{
vlc_mutex_unlock( &p_sap->object_lock );
msg_Dbg( p_sap,"%i addresses, %i sessions",
p_sap->i_addresses,p_sap->i_sessions);
- /* Remember the SAP session for later deletion */
- p_session->p_sap = p_sap_session;
-
vlc_mutex_unlock( &p_sap->object_lock );
return VLC_SUCCESS;
int i;
vlc_mutex_lock( &p_sap->object_lock );
- msg_Dbg( p_sap,"removing SAP announce %p",p_session->p_sap);
+ msg_Dbg( p_sap, "removing session %p from SAP", p_session);
/* Dequeue the announce */
for( i = 0; i< p_sap->i_sessions; i++)
{
- if( p_session->p_sap == p_sap->pp_sessions[i] )
+ if( p_session == p_sap->pp_sessions[i]->p_sd )
{
+ sap_session_t *p_mysession = p_sap->pp_sessions[i];
REMOVE_ELEM( p_sap->pp_sessions,
p_sap->i_sessions,
i );
- FREE( p_session->p_sap->psz_sdp );
- FREE( p_session->p_sap->psz_data );
- free( p_session->p_sap );
+ free( p_mysession->psz_sdp );
+ free( p_mysession->psz_data );
+ free( p_mysession );
break;
}
}
static char *SDPGenerate( sap_handler_t *p_sap,
const session_descriptor_t *p_session,
- const sap_address_t *p_addr )
+ const sap_address_t *p_addr, vlc_bool_t b_ssm )
{
int64_t i_sdp_id = mdate();
int i_sdp_version = 1 + p_sap->i_sessions + (rand()&0xfff);
else
psz_uri = p_session->psz_uri;
- /* see the lists in modules/stream_out/rtp.c for compliance stuff */
- if( asprintf( &psz_sdp,
- "v=0\r\n"
- "o=- "I64Fd" %d IN IP%c %s\r\n"
- "s=%s\r\n"
- "t=0 0\r\n"
- "c=IN IP%c %s/%d\r\n"
- "m=video %d %s %d\r\n"
- "a=tool:"PACKAGE_STRING"\r\n"
- "a=type:broadcast\r\n"
- "%s%s%s",
- i_sdp_id, i_sdp_version,
- ipv, p_addr->psz_machine,
- psz_name, ipv, psz_uri,
- /* FIXME: 1 is IPv4 default TTL, not that of IPv6 */
- p_session->i_ttl ?: (config_GetInt( p_sap, "ttl" ) ?: 1),
- p_session->i_port,
- p_session->b_rtp ? "RTP/AVP" : "udp",
- p_session->i_payload,
- psz_group ? "a=x-plgroup:" : "",
- psz_group ? psz_group : "", psz_group ? "\r\n" : "" ) == -1 )
+ char *sfilter = NULL;
+ if (b_ssm)
+ {
+ if (asprintf (&sfilter, "a=source-filter: incl IN IP%c * %s\r\n",
+ ipv, p_addr->psz_machine) == -1)
+ return NULL;
+ }
+
+ int res = asprintf (&psz_sdp,
+ "v=0\r\n"
+ "o=- "I64Fd" %d IN IP%c %s\r\n"
+ "s=%s\r\n"
+ "c=IN IP%c %s/255\r\n"
+ "t=0 0\r\n"
+ "a=tool:"PACKAGE_STRING"\r\n"
+ "a=recvonly\r\n"
+ "a=type:broadcast\n"
+ "%s"
+ "m=video %d %s %d\r\n"
+ "%s%s%s",
+ i_sdp_id, i_sdp_version,
+ ipv, p_addr->psz_machine,
+ psz_name, ipv, psz_uri,
+ (sfilter != NULL) ? sfilter : "",
+ p_session->i_port,
+ p_session->b_rtp ? "RTP/AVP" : "udp",
+ p_session->i_payload,
+ psz_group ? "a=x-plgroup:" : "",
+ psz_group ? psz_group : "", psz_group ? "\r\n" : "");
+ if (sfilter != NULL)
+ free (sfilter);
+
+ if (res == -1)
return NULL;
msg_Dbg( p_sap, "Generated SDP (%i bytes):\n%s", strlen(psz_sdp),
i_read = net_ReadNonBlock( p_sap, p_address->i_rfd, NULL, buffer,
SAP_MAX_BUFFER, 0 );
i_tot += i_read;
- } while( i_read > 0 && i_tot < SAP_MAX_BUFFER );
+ } while( i_read > 0 );
i_temp = mdate();