/*****************************************************************************
* sap.c : SAP announce handler
*****************************************************************************
- * Copyright (C) 2002-2008 the VideoLAN team
+ * Copyright (C) 2002-2008 VLC authors and VideoLAN
* $Id$
*
* Authors: Clément Stenac <zorglub@videolan.org>
* Rémi Denis-Courmont <rem # videolan.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
#define IPPORT_SAP 9875
/* A SAP session descriptor, enqueued in the SAP handler queue */
-typedef struct sap_session_t
+struct session_descriptor_t
{
- struct sap_session_t *next;
- const session_descriptor_t *p_sd;
- size_t length;
- uint8_t data[];
-} sap_session_t;
+ struct session_descriptor_t *next;
+ size_t length;
+ uint8_t data[];
+};
/* A SAP announce address. For each of these, we run the
* control flow algorithm */
unsigned interval;
unsigned session_count;
- sap_session_t *first;
+ session_descriptor_t *first;
} sap_address_t;
-/* The SAP handler, running in a separate thread */
-struct sap_handler_t
-{
- VLC_COMMON_MEMBERS
-
- vlc_mutex_t lock;
- sap_address_t *first;
-};
+static sap_address_t *sap_addrs = NULL;
+static vlc_mutex_t sap_mutex = VLC_STATIC_MUTEX;
#define SAP_MAX_BUFFER 65534
#define MIN_INTERVAL 2
#define MAX_INTERVAL 300
-/*****************************************************************************
- * Local prototypes
- *****************************************************************************/
static void *RunThread (void *);
-/**
- * Create the SAP handler
- *
- * \param p_announce a VLC object
- * \return the newly created SAP handler or NULL on error
- */
-sap_handler_t *SAP_Create (vlc_object_t *p_announce)
-{
- sap_handler_t *p_sap;
-
- p_sap = vlc_custom_create (p_announce, sizeof (*p_sap),
- VLC_OBJECT_GENERIC, "sap sender");
- if (p_sap == NULL)
- return NULL;
-
- vlc_mutex_init (&p_sap->lock);
- p_sap->first = NULL;
- return p_sap;
-}
-
-void SAP_Destroy (sap_handler_t *p_sap)
-{
- assert (p_sap->first == NULL);
- vlc_mutex_destroy (&p_sap->lock);
- vlc_object_release (p_sap);
-}
-
static sap_address_t *AddressCreate (vlc_object_t *obj, const char *group)
{
int fd = net_ConnectUDP (obj, group, IPPORT_SAP, 255);
* \param p_this the SAP Handler object
* \return nothing
*/
+VLC_NORETURN
static void *RunThread (void *self)
{
sap_address_t *addr = self;
for (;;)
{
- sap_session_t *p_session;
+ session_descriptor_t *p_session;
mtime_t deadline;
while (addr->first == NULL)
}
vlc_cleanup_pop ();
- assert (0);
+ vlc_assert_unreachable ();
}
+#undef sout_AnnounceRegisterSDP
/**
- * Add a SAP announce
+ * Registers a new session with the announce handler, using a pregenerated SDP
+ *
+ * \param obj a VLC object
+ * \param sdp the SDP to register
+ * \param dst session address (needed for SAP address auto detection)
+ * \return the new session descriptor structure
*/
-int SAP_Add (sap_handler_t *p_sap, session_descriptor_t *p_session)
+session_descriptor_t *
+sout_AnnounceRegisterSDP (vlc_object_t *obj, const char *sdp,
+ const char *dst)
{
int i;
char psz_addr[NI_MAXNUMERICHOST];
- bool b_ipv6 = false, b_ssm = false;
- sap_session_t *p_sap_session;
- mtime_t i_hash;
union
{
struct sockaddr a;
struct sockaddr_in in;
struct sockaddr_in6 in6;
} addr;
- socklen_t addrlen;
+ socklen_t addrlen = 0;
+ struct addrinfo *res;
- addrlen = p_session->addrlen;
- if ((addrlen == 0) || (addrlen > sizeof (addr)))
+ msg_Dbg (obj, "adding SAP session");
+
+ if (vlc_getaddrinfo (dst, 0, NULL, &res) == 0)
{
- msg_Err( p_sap, "No/invalid address specified for SAP announce" );
- return VLC_EGENERIC;
+ if (res->ai_addrlen <= sizeof (addr))
+ memcpy (&addr, res->ai_addr, res->ai_addrlen);
+ addrlen = res->ai_addrlen;
+ freeaddrinfo (res);
}
- /* Determine SAP multicast address automatically */
- memcpy (&addr, &p_session->addr, addrlen);
+ if (addrlen == 0 || addrlen > sizeof (addr))
+ {
+ msg_Err (obj, "No/invalid address specified for SAP announce" );
+ return NULL;
+ }
+ /* Determine SAP multicast address automatically */
switch (addr.a.sa_family)
{
-#if defined (HAVE_INET_PTON) || defined (WIN32)
+#if defined (HAVE_INET_PTON) || defined (_WIN32)
case AF_INET6:
{
/* See RFC3513 for list of valid IPv6 scopes */
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 ) )
- {
- /* 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 );
-
- b_ipv6 = true;
break;
}
#endif
ipv4 = 0;
else
/* other addresses => 224.2.127.254 */
- {
- /* SSM: 232.0.0.0/8 */
- b_ssm = (ipv4 & htonl (255 << 24)) == htonl (232 << 24);
ipv4 = htonl (0xe0027ffe);
- }
if( ipv4 == 0 )
{
- msg_Err( p_sap, "Out-of-scope multicast address "
- "not supported by SAP" );
- return VLC_EGENERIC;
+ msg_Err (obj, "Out-of-scope multicast address "
+ "not supported by SAP");
+ return NULL;
}
addr.in.sin_addr.s_addr = ipv4;
}
default:
- msg_Err( p_sap, "Address family %d not supported by SAP",
- addr.a.sa_family );
- return VLC_EGENERIC;
+ msg_Err (obj, "Address family %d not supported by SAP",
+ addr.a.sa_family);
+ return NULL;
}
i = vlc_getnameinfo( &addr.a, addrlen,
if( i )
{
- msg_Err( p_sap, "%s", vlc_gai_strerror( i ) );
- return VLC_EGENERIC;
+ msg_Err (obj, "%s", gai_strerror (i));
+ return NULL;
}
/* Find/create SAP address thread */
- msg_Dbg( p_sap, "using SAP address: %s", psz_addr);
-
- vlc_mutex_lock (&p_sap->lock);
sap_address_t *sap_addr;
- for (sap_addr = p_sap->first; sap_addr; sap_addr = sap_addr->next)
+
+ msg_Dbg (obj, "using SAP address: %s", psz_addr);
+ vlc_mutex_lock (&sap_mutex);
+ for (sap_addr = sap_addrs; sap_addr; sap_addr = sap_addr->next)
if (!strcmp (psz_addr, sap_addr->group))
break;
if (sap_addr == NULL)
{
- sap_addr = AddressCreate (VLC_OBJECT(p_sap), psz_addr);
+ sap_addr = AddressCreate (obj, psz_addr);
if (sap_addr == NULL)
{
- vlc_mutex_unlock (&p_sap->lock);
- return VLC_EGENERIC;
+ vlc_mutex_unlock (&sap_mutex);
+ return NULL;
}
- sap_addr->next = p_sap->first;
- p_sap->first = sap_addr;
+ sap_addr->next = sap_addrs;
+ sap_addrs = sap_addr;
}
/* Switch locks.
* NEVER take the global SAP lock when holding a SAP thread lock! */
vlc_mutex_lock (&sap_addr->lock);
- vlc_mutex_unlock (&p_sap->lock);
-
- memcpy (&p_session->orig, &sap_addr->orig, sap_addr->origlen);
- p_session->origlen = sap_addr->origlen;
+ vlc_mutex_unlock (&sap_mutex);
- size_t headsize = 20, length;
- switch (p_session->orig.ss_family)
+ size_t length = 20;
+ switch (sap_addr->orig.ss_family)
{
#ifdef AF_INET6
case AF_INET6:
- headsize += 16;
+ length += 16;
break;
#endif
case AF_INET:
- headsize += 4;
+ length += 4;
break;
default:
- assert (0);
+ vlc_assert_unreachable ();
}
/* XXX: Check for dupes */
- length = headsize + strlen (p_session->psz_sdp);
- p_sap_session = malloc (sizeof (*p_sap_session) + length + 1);
- if (p_sap_session == NULL)
+ length += strlen (sdp);
+
+ session_descriptor_t *session = malloc (sizeof (*session) + length);
+ if (unlikely(session == NULL))
{
vlc_mutex_unlock (&sap_addr->lock);
- return VLC_EGENERIC; /* NOTE: we should destroy the thread if left unused */
+ return NULL; /* NOTE: we should destroy the thread if left unused */
}
- p_sap_session->next = sap_addr->first;
- sap_addr->first = p_sap_session;
- p_sap_session->p_sd = p_session;
- p_sap_session->length = length;
+ session->next = sap_addr->first;
+ sap_addr->first = session;
+ session->length = length;
/* Build the SAP Headers */
- uint8_t *psz_head = p_sap_session->data;
+ uint8_t *buf = session->data;
/* SAPv1, not encrypted, not compressed */
- psz_head[0] = 0x20;
- psz_head[1] = 0x00; /* No authentication length */
+ buf[0] = 0x20;
+ buf[1] = 0x00; /* No authentication length */
+ SetWBE(buf + 2, mdate()); /* ID hash */
- i_hash = mdate();
- psz_head[2] = i_hash >> 8; /* Msg id hash */
- psz_head[3] = i_hash; /* Msg id hash 2 */
-
- headsize = 4;
- switch (p_session->orig.ss_family)
+ size_t offset = 4;
+ switch (sap_addr->orig.ss_family)
{
#ifdef AF_INET6
case AF_INET6:
{
- struct in6_addr *a6 =
- &((struct sockaddr_in6 *)&p_session->orig)->sin6_addr;
- memcpy (psz_head + headsize, a6, 16);
- psz_head[0] |= 0x10; /* IPv6 flag */
- headsize += 16;
+ const struct in6_addr *a6 =
+ &((const struct sockaddr_in6 *)&sap_addr->orig)->sin6_addr;
+ memcpy (buf + offset, a6, 16);
+ buf[0] |= 0x10; /* IPv6 flag */
+ offset += 16;
break;
}
#endif
case AF_INET:
{
- uint32_t ipv4 =
- (((struct sockaddr_in *)&p_session->orig)->sin_addr.s_addr);
- memcpy (psz_head + headsize, &ipv4, 4);
- headsize += 4;
+ const struct in_addr *a4 =
+ &((const struct sockaddr_in *)&sap_addr->orig)->sin_addr;
+ memcpy (buf + offset, a4, 4);
+ offset += 4;
break;
}
}
- memcpy (psz_head + headsize, "application/sdp", 16);
- headsize += 16;
+ memcpy (buf + offset, "application/sdp", 16);
+ offset += 16;
/* Build the final message */
- strcpy( (char *)psz_head + headsize, p_session->psz_sdp);
+ strcpy((char *)buf + offset, sdp);
sap_addr->session_count++;
vlc_cond_signal (&sap_addr->wait);
vlc_mutex_unlock (&sap_addr->lock);
- return VLC_SUCCESS;
+ return session;
}
+#undef sout_AnnounceUnRegister
/**
- * Remove a SAP Announce
+ * Unregisters an existing session
+ *
+ * \param obj a VLC object
+ * \param session the session descriptor
*/
-void SAP_Del (sap_handler_t *p_sap, const session_descriptor_t *p_session)
+void sout_AnnounceUnRegister (vlc_object_t *obj, session_descriptor_t *session)
{
- vlc_mutex_lock (&p_sap->lock);
-
- /* TODO: give a handle back in SAP_Add, and use that... */
sap_address_t *addr, **paddr;
- sap_session_t *session, **psession;
+ session_descriptor_t **psession;
- paddr = &p_sap->first;
- for (addr = p_sap->first; addr; addr = addr->next)
+ msg_Dbg (obj, "removing SAP session");
+ vlc_mutex_lock (&sap_mutex);
+ paddr = &sap_addrs;
+ for (;;)
{
+ addr = *paddr;
+ assert (addr != NULL);
+
psession = &addr->first;
vlc_mutex_lock (&addr->lock);
- for (session = addr->first; session; session = session->next)
+ while (*psession != NULL)
{
- if (session->p_sd == p_session)
+ if (*psession == session)
goto found;
- psession = &session->next;
+ psession = &(*psession)->next;
}
vlc_mutex_unlock (&addr->lock);
paddr = &addr->next;
}
- assert (0);
found:
*psession = session->next;
if (addr->first == NULL)
/* Last session for this address -> unlink the address */
*paddr = addr->next;
- vlc_mutex_unlock (&p_sap->lock);
+ vlc_mutex_unlock (&sap_mutex);
if (addr->first == NULL)
{