X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fstream_output%2Fsap.c;h=5eae84d65937bd42a509da55191ab50c5a2d0a31;hb=0336f13424548f4028f40c57cd1ed534cb58d26f;hp=5a5f6535a895b55478eacea083c2bc7f14304568;hpb=533d6dbf37d7a32ee339058f6657f64ba1009525;p=vlc diff --git a/src/stream_output/sap.c b/src/stream_output/sap.c index 5a5f6535a8..5eae84d659 100644 --- a/src/stream_output/sap.c +++ b/src/stream_output/sap.c @@ -25,16 +25,19 @@ /***************************************************************************** * Preamble *****************************************************************************/ + +#include + #include /* free() */ #include /* sprintf() */ #include /* strerror() */ #include /* tolower(), isxdigit() */ -#include -#include +#include +#include +#include -#include "network.h" -#include "charset.h" +#include "stream_output.h" /* SAP is always on that port */ #define SAP_PORT 9875 @@ -69,6 +72,19 @@ struct sap_address_t 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 *****************************************************************************/ @@ -76,7 +92,7 @@ static void RunThread( vlc_object_t *p_this); 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 ); @@ -88,8 +104,6 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, 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 @@ -146,17 +160,17 @@ void announce_SAPHandlerDestroy( sap_handler_t *p_sap ) 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 ); @@ -166,7 +180,7 @@ void announce_SAPHandlerDestroy( sap_handler_t *p_sap ) 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 */ @@ -235,11 +249,12 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, { 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 ); @@ -250,7 +265,6 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, 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; @@ -266,7 +280,8 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, 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 ); @@ -275,7 +290,8 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, return VLC_EGENERIC; } - memcpy( &addr, res->ai_addr, res->ai_addrlen ); + memcpy (&addr, res->ai_addr, addrlen); + vlc_freeaddrinfo (res); switch( addr.ss_family ) { @@ -288,8 +304,13 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, 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 ); @@ -321,14 +342,17 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, 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; } @@ -338,15 +362,13 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, 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 ) { @@ -359,6 +381,7 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, /* 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 */ @@ -381,7 +404,7 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, 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; @@ -398,7 +421,7 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, 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; @@ -468,7 +491,7 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, 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 ); @@ -500,9 +523,6 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, 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; @@ -515,20 +535,21 @@ static int announce_SAPAnnounceDel( sap_handler_t *p_sap, 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; } } @@ -584,7 +605,7 @@ static int announce_SendSAPAnnounce( sap_handler_t *p_sap, 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); @@ -614,27 +635,39 @@ static char *SDPGenerate( sap_handler_t *p_sap, 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), @@ -661,7 +694,7 @@ static int CalculateRate( sap_handler_t *p_sap, sap_address_t *p_address ) 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();