📄 sap.c
字号:
/***************************************************************************** * sap.c : SAP interface module ***************************************************************************** * Copyright (C) 2004-2005 the VideoLAN team * Copyright © 2007 Rémi Denis-Courmont * $Id: ec84aa964e2cbc2b4197e3fdc7ac45ef9ee9379d $ * * Authors: Clément Stenac <zorglub@videolan.org> * Rémi Denis-Courmont * * 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 * (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. * * 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. *****************************************************************************//***************************************************************************** * Includes *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_plugin.h>#include <assert.h>#include <vlc_demux.h>#include <vlc_services_discovery.h>#include <vlc_network.h>#include <vlc_charset.h>#include <ctype.h>#include <errno.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#ifdef HAVE_SYS_TIME_H# include <sys/time.h>#endif#ifdef HAVE_POLL# include <poll.h>#endif#ifdef HAVE_ZLIB_H# include <zlib.h>#endif#ifndef WIN32# include <net/if.h>#endif/************************************************************************ * Macros and definitions ************************************************************************/#define MAX_LINE_LENGTH 256/* SAP is always on that port */#define SAP_PORT 9875/* Global-scope SAP address */#define SAP_V4_GLOBAL_ADDRESS "224.2.127.254"/* Organization-local SAP address */#define SAP_V4_ORG_ADDRESS "239.195.255.255"/* Local (smallest non-link-local scope) SAP address */#define SAP_V4_LOCAL_ADDRESS "239.255.255.255"/* Link-local SAP address */#define SAP_V4_LINK_ADDRESS "224.0.0.255"#define ADD_SESSION 1/***************************************************************************** * Module descriptor *****************************************************************************/#define SAP_ADDR_TEXT N_( "SAP multicast address" )#define SAP_ADDR_LONGTEXT N_( "The SAP module normally chooses itself the " \ "right addresses to listen to. However, you " \ "can specify a specific address." )#define SAP_IPV4_TEXT N_( "IPv4 SAP" )#define SAP_IPV4_LONGTEXT N_( \ "Listen to IPv4 announcements on the standard addresses." )#define SAP_IPV6_TEXT N_( "IPv6 SAP" )#define SAP_IPV6_LONGTEXT N_( \ "Listen to IPv6 announcements on the standard addresses." )#define SAP_SCOPE_TEXT N_( "IPv6 SAP scope" )#define SAP_SCOPE_LONGTEXT N_( \ "Scope for IPv6 announcements (default is 8)." )#define SAP_TIMEOUT_TEXT N_( "SAP timeout (seconds)" )#define SAP_TIMEOUT_LONGTEXT N_( \ "Delay after which SAP items get deleted if no new announcement " \ "is received." )#define SAP_PARSE_TEXT N_( "Try to parse the announce" )#define SAP_PARSE_LONGTEXT N_( \ "This enables actual parsing of the announces by the SAP module. " \ "Otherwise, all announcements are parsed by the \"live555\" " \ "(RTP/RTSP) module." )#define SAP_STRICT_TEXT N_( "SAP Strict mode" )#define SAP_STRICT_LONGTEXT N_( \ "When this is set, the SAP parser will discard some non-compliant " \ "announcements." )#define SAP_CACHE_TEXT N_("Use SAP cache")#define SAP_CACHE_LONGTEXT N_( \ "This enables a SAP caching mechanism. " \ "This will result in lower SAP startup time, but you could end up " \ "with items corresponding to legacy streams." )#define SAP_TIMESHIFT_TEXT N_("Allow timeshifting")#define SAP_TIMESHIFT_LONGTEXT N_( "This automatically enables timeshifting " \ "for streams discovered through SAP announcements." )/* Callbacks */ static int Open ( vlc_object_t * ); static void Close( vlc_object_t * ); static int OpenDemux ( vlc_object_t * ); static void CloseDemux ( vlc_object_t * );vlc_module_begin(); set_shortname( N_("SAP")); set_description( N_("SAP Announcements") ); set_category( CAT_PLAYLIST ); set_subcategory( SUBCAT_PLAYLIST_SD ); add_string( "sap-addr", NULL, NULL, SAP_ADDR_TEXT, SAP_ADDR_LONGTEXT, true ); add_bool( "sap-ipv4", 1 , NULL, SAP_IPV4_TEXT,SAP_IPV4_LONGTEXT, true ); add_bool( "sap-ipv6", 1 , NULL, SAP_IPV6_TEXT, SAP_IPV6_LONGTEXT, true ); add_integer( "sap-timeout", 1800, NULL, SAP_TIMEOUT_TEXT, SAP_TIMEOUT_LONGTEXT, true ); add_bool( "sap-parse", 1 , NULL, SAP_PARSE_TEXT,SAP_PARSE_LONGTEXT, true ); add_bool( "sap-strict", 0 , NULL, SAP_STRICT_TEXT,SAP_STRICT_LONGTEXT, true );#if 0 add_bool( "sap-cache", 0 , NULL, SAP_CACHE_TEXT,SAP_CACHE_LONGTEXT, true );#endif add_bool( "sap-timeshift", 0 , NULL, SAP_TIMESHIFT_TEXT,SAP_TIMESHIFT_LONGTEXT, true ); set_capability( "services_discovery", 0 ); set_callbacks( Open, Close ); add_submodule(); set_description( N_("SDP Descriptions parser") ); add_shortcut( "sdp" ); set_capability( "demux", 51 ); set_callbacks( OpenDemux, CloseDemux );vlc_module_end();/***************************************************************************** * Local structures *****************************************************************************/typedef struct sdp_t sdp_t;typedef struct attribute_t attribute_t;typedef struct sap_announce_t sap_announce_t;struct sdp_media_t{ struct sdp_t *parent; char *fmt; struct sockaddr_storage addr; socklen_t addrlen; unsigned n_addr; int i_attributes; attribute_t **pp_attributes;};/* The structure that contains sdp information */struct sdp_t{ const char *psz_sdp; /* o field */ char username[64]; uint64_t session_id; uint64_t session_version; unsigned orig_ip_version; char orig_host[1024]; /* s= field */ char *psz_sessionname; /* old cruft */ /* "computed" URI */ char *psz_uri; int i_media_type; /* a= global attributes */ int i_attributes; attribute_t **pp_attributes; /* medias (well, we only support one atm) */ unsigned mediac; struct sdp_media_t *mediav;};struct attribute_t{ const char *value; char name[0];};struct sap_announce_t{ mtime_t i_last; mtime_t i_period; uint8_t i_period_trust; uint16_t i_hash; uint32_t i_source[4]; /* SAP annnounces must only contain one SDP */ sdp_t *p_sdp; input_item_t * p_item;};struct services_discovery_sys_t{ /* Socket descriptors */ int i_fd; int *pi_fd; /* Table of announces */ int i_announces; struct sap_announce_t **pp_announces; /* Modes */ bool b_strict; bool b_parse; bool b_timeshift; int i_timeout;};struct demux_sys_t{ sdp_t *p_sdp;};/***************************************************************************** * Local prototypes *****************************************************************************//* Main functions */ static int Demux( demux_t *p_demux ); static int Control( demux_t *, int, va_list ); static void Run ( services_discovery_t *p_sd );/* Main parsing functions */ static int ParseConnection( vlc_object_t *p_obj, sdp_t *p_sdp ); static int ParseSAP( services_discovery_t *p_sd, const uint8_t *p_buffer, size_t i_read ); static sdp_t *ParseSDP (vlc_object_t *p_sd, const char *psz_sdp); static sap_announce_t *CreateAnnounce( services_discovery_t *, uint16_t, sdp_t * ); static int RemoveAnnounce( services_discovery_t *p_sd, sap_announce_t *p_announce );/* Helper functions */ static inline attribute_t *MakeAttribute (const char *str); static const char *GetAttribute (attribute_t **tab, unsigned n, const char *name); static inline void FreeAttribute (attribute_t *a); static const char *FindAttribute (const sdp_t *sdp, unsigned media, const char *name); static bool IsSameSession( sdp_t *p_sdp1, sdp_t *p_sdp2 ); static int InitSocket( services_discovery_t *p_sd, const char *psz_address, int i_port ); static int Decompress( const unsigned char *psz_src, unsigned char **_dst, int i_len ); static void FreeSDP( sdp_t *p_sdp );static inline int min_int( int a, int b ){ return a > b ? b : a;}/***************************************************************************** * Open: initialize and create stuff *****************************************************************************/static int Open( vlc_object_t *p_this ){ services_discovery_t *p_sd = ( services_discovery_t* )p_this; services_discovery_sys_t *p_sys = (services_discovery_sys_t *) malloc( sizeof( services_discovery_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; p_sys->i_timeout = var_CreateGetInteger( p_sd, "sap-timeout" ); p_sd->pf_run = Run; p_sd->p_sys = p_sys; p_sys->pi_fd = NULL; p_sys->i_fd = 0; p_sys->b_strict = var_CreateGetInteger( p_sd, "sap-strict"); p_sys->b_parse = var_CreateGetInteger( p_sd, "sap-parse" );#if 0 if( var_CreateGetInteger( p_sd, "sap-cache" ) ) { CacheLoad( p_sd ); }#endif /* Cache sap_timeshift value */ p_sys->b_timeshift = var_CreateGetInteger( p_sd, "sap-timeshift" ); /* Set our name */ services_discovery_SetLocalizedName( p_sd, _("SAP") ); p_sys->i_announces = 0; p_sys->pp_announces = NULL; return VLC_SUCCESS;}/***************************************************************************** * OpenDemux: initialize and create stuff *****************************************************************************/static int OpenDemux( vlc_object_t *p_this ){ demux_t *p_demux = (demux_t *)p_this; const uint8_t *p_peek; char *psz_sdp = NULL; sdp_t *p_sdp = NULL; int errval = VLC_EGENERIC; size_t i_len; if( !var_CreateGetInteger( p_demux, "sap-parse" ) ) { /* We want livedotcom module to parse this SDP file */ return VLC_EGENERIC; } assert( p_demux->s ); /* this is NOT an access_demux */ /* Probe for SDP */ if( stream_Peek( p_demux->s, &p_peek, 7 ) < 7 ) return VLC_EGENERIC; if( memcmp( p_peek, "v=0\r\no=", 7 ) && memcmp( p_peek, "v=0\no=", 6 ) ) return VLC_EGENERIC; /* Gather the complete sdp file */ for( i_len = 0, psz_sdp = NULL; i_len < 65536; ) { const int i_read_max = 1024; char *psz_sdp_new = realloc( psz_sdp, i_len + i_read_max ); size_t i_read; if( psz_sdp_new == NULL ) { errval = VLC_ENOMEM; goto error; } psz_sdp = psz_sdp_new; i_read = stream_Read( p_demux->s, &psz_sdp[i_len], i_read_max ); if( (int)i_read < 0 ) { msg_Err( p_demux, "cannot read SDP" ); goto error; } i_len += i_read; psz_sdp[i_len] = '\0'; if( (int)i_read < i_read_max ) break; // EOF } p_sdp = ParseSDP( VLC_OBJECT(p_demux), psz_sdp ); if( !p_sdp ) { msg_Warn( p_demux, "invalid SDP"); goto error; } if( ParseConnection( VLC_OBJECT( p_demux ), p_sdp ) ) { p_sdp->psz_uri = NULL; } switch (p_sdp->i_media_type) { /* Should be in sync with modules/demux/rtp.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -