📄 sap.c
字号:
/***************************************************************************** * CloseDemux: Close the demuxer *****************************************************************************/static void CloseDemux( vlc_object_t *p_this ){}/***************************************************************************** * Run: main SAP thread ***************************************************************************** * Listens to SAP packets, and sends them to packet_handle *****************************************************************************/#define MAX_SAP_BUFFER 5000static void Run( services_discovery_t *p_sd ){ int i; /* read SAP packets */ while( !p_sd->b_die ) { int i_read; uint8_t p_buffer[MAX_SAP_BUFFER + 1]; i_read = net_Select( p_sd, p_sd->p_sys->pi_fd, NULL, p_sd->p_sys->i_fd, p_buffer, MAX_SAP_BUFFER, 500000 ); /* Check for items that need deletion */ for( i = 0; i < p_sd->p_sys->i_announces; i++ ) { mtime_t i_timeout = ( mtime_t ) 1000000 * p_sd->p_sys->i_timeout; if( mdate() - p_sd->p_sys->pp_announces[i]->i_last > i_timeout ) { struct sap_announce_t *p_announce; p_announce = p_sd->p_sys->pp_announces[i]; /* Remove the playlist item */ playlist_LockDelete( p_sd->p_sys->p_playlist, p_announce->i_item_id ); /* Remove the sap_announce from the array */ REMOVE_ELEM( p_sd->p_sys->pp_announces, p_sd->p_sys->i_announces, i ); free( p_announce ); } } /* Minimum length is > 6 */ if( i_read <= 6 ) { if( i_read < 0 ) { msg_Warn( p_sd, "socket read error" ); } continue; } p_buffer[i_read] = '\0'; /* Parse the packet */ ParseSAP( p_sd, p_buffer, i_read ); }}/********************************************************************** * Demux: reads and demuxes data packets * Return -1 if error, 0 if EOF, 1 else **********************************************************************/static int Demux( demux_t *p_demux ){ sdp_t *p_sdp = p_demux->p_sys->p_sdp; playlist_t *p_playlist; p_playlist = (playlist_t *)vlc_object_find( p_demux, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); p_playlist->status.p_item->i_flags |= PLAYLIST_DEL_FLAG; playlist_Add( p_playlist, p_sdp->psz_uri, p_sdp->psz_sessionname, PLAYLIST_APPEND, PLAYLIST_END ); vlc_object_release( p_playlist ); if( p_sdp ) FreeSDP( p_sdp ); return VLC_SUCCESS;}static int Control( demux_t *p_demux, int i_query, va_list args ){ return VLC_EGENERIC;}/************************************************************** * Local functions **************************************************************//* i_read is at least > 6 */static int ParseSAP( services_discovery_t *p_sd, uint8_t *p_buffer, int i_read ){ int i_version, i_address_type, i_hash, i; uint8_t *psz_sdp; uint8_t *psz_initial_sdp; sdp_t *p_sdp; vlc_bool_t b_compressed; vlc_bool_t b_need_delete = VLC_FALSE;#ifdef HAVE_ZLIB_H int i_decompressed_size; uint8_t *p_decompressed_buffer;#endif uint8_t *psz_foo; /* First, check the sap announce is correct */ i_version = p_buffer[0] >> 5; if( i_version != 1 ) { msg_Dbg( p_sd, "strange sap version %d found", i_version ); } i_address_type = p_buffer[0] & 0x10; if( (p_buffer[0] & 0x08) != 0 ) { msg_Dbg( p_sd, "reserved bit incorrectly set" ); return VLC_EGENERIC; } if( (p_buffer[0] & 0x04) != 0 ) { msg_Dbg( p_sd, "session deletion packet" ); b_need_delete = VLC_TRUE; } if( p_buffer[0] & 0x02 ) { msg_Dbg( p_sd, "encrypted packet, unsupported" ); return VLC_EGENERIC; } b_compressed = p_buffer[0] & 0x01; i_hash = ( p_buffer[2] << 8 ) + p_buffer[3]; if( p_sd->p_sys->b_strict && i_hash == 0 ) { msg_Dbg( p_sd, "strict mode, discarding announce with null id hash"); return VLC_EGENERIC; } psz_sdp = &p_buffer[4]; psz_initial_sdp = psz_sdp; if( i_address_type == 0 ) /* ipv4 source address */ { psz_sdp += 4; if( i_read <= 9 ) { msg_Warn( p_sd, "too short SAP packet\n" ); return VLC_EGENERIC; } } else /* ipv6 source address */ { psz_sdp += 16; if( i_read <= 21 ) { msg_Warn( p_sd, "too short SAP packet\n" ); return VLC_EGENERIC; } } if( b_compressed ) {#ifdef HAVE_ZLIB_H i_decompressed_size = Decompress( psz_sdp, &p_decompressed_buffer,i_read - ( psz_sdp - p_buffer ) ); if( i_decompressed_size > 0 && i_decompressed_size < MAX_SAP_BUFFER ) { memcpy( psz_sdp, p_decompressed_buffer, i_decompressed_size ); psz_sdp[i_decompressed_size] = '\0'; free( p_decompressed_buffer ); }#else msg_Warn( p_sd, "Ignoring compressed sap packet" ); return VLC_EGENERIC;#endif } /* Add the size of authentification info */ if( i_read < p_buffer[1] + (psz_sdp - psz_initial_sdp ) ) { msg_Warn( p_sd, "too short SAP packet\n"); return VLC_EGENERIC; } psz_sdp += p_buffer[1]; psz_foo = psz_sdp; /* Skip payload type */ /* Handle announces without \0 between SAP and SDP */ while( *psz_sdp != '\0' && ( psz_sdp[0] != 'v' && psz_sdp[1] != '=' ) ) { if( psz_sdp - psz_initial_sdp >= i_read - 5 ) { msg_Warn( p_sd, "empty SDP ?"); } psz_sdp++; } if( *psz_sdp == '\0' ) { psz_sdp++; } if( psz_sdp != psz_foo && strcasecmp( psz_foo, "application/sdp" ) ) { msg_Dbg( p_sd, "unhandled content type: %s", psz_foo ); } if( psz_sdp -p_buffer >= i_read ) { msg_Warn( p_sd, "package without content" ); return VLC_EGENERIC; } /* Parse SDP info */ p_sdp = ParseSDP( VLC_OBJECT(p_sd), psz_sdp ); if( p_sdp == NULL ) { return VLC_EGENERIC; } /* Decide whether we should add a playlist item for this SDP */ /* Parse connection information (c= & m= ) */ if( ParseConnection( VLC_OBJECT(p_sd), p_sdp ) ) { p_sdp->psz_uri = NULL; } /* Multi-media or no-parse -> pass to LIVE.COM */ if( p_sdp->i_media > 1 || ( p_sdp->i_media_type != 14 && p_sdp->i_media_type != 32 && p_sdp->i_media_type != 33) || p_sd->p_sys->b_parse == VLC_FALSE ) { if( p_sdp->psz_uri ) free( p_sdp->psz_uri ); asprintf( &p_sdp->psz_uri, "sdp://%s", p_sdp->psz_sdp ); } if( p_sdp->psz_uri == NULL ) return VLC_EGENERIC; for( i = 0 ; i< p_sd->p_sys->i_announces ; i++ ) { /* FIXME: slow */ /* FIXME: we create a new announce each time the sdp changes */ if( IsSameSession( p_sd->p_sys->pp_announces[i]->p_sdp, p_sdp ) ) { if( b_need_delete ) { RemoveAnnounce( p_sd, p_sd->p_sys->pp_announces[i]); return VLC_SUCCESS; } else { p_sd->p_sys->pp_announces[i]->i_last = mdate(); FreeSDP( p_sdp ); return VLC_SUCCESS; } } } /* Add item */ if( p_sdp->i_media > 1 ) { msg_Dbg( p_sd, "passing to LIVE.COM" ); } CreateAnnounce( p_sd, i_hash, p_sdp ); return VLC_SUCCESS;}sap_announce_t *CreateAnnounce( services_discovery_t *p_sd, uint16_t i_hash, sdp_t *p_sdp ){ playlist_item_t *p_item, *p_child; char *psz_value; sap_announce_t *p_sap = (sap_announce_t *)malloc( sizeof(sap_announce_t ) ); psz_value = convert_from_utf8( p_sd, p_sdp->psz_sessionname ); if( p_sap == NULL || psz_value == NULL ) { FREE( p_sap ); FREE( psz_value ); return NULL; } p_sap->i_last = mdate(); p_sap->i_hash = i_hash; p_sap->p_sdp = p_sdp; p_sap->i_item_id = -1; /* Create the playlist item here */ p_item = playlist_ItemNew( p_sd, p_sap->p_sdp->psz_uri, psz_value ); free( psz_value ); if( !p_item ) { free( p_sap ); return NULL; } psz_value = GetAttribute( p_sap->p_sdp, "tool" ); if( psz_value != NULL ) { vlc_input_item_AddInfo( &p_item->input, _("Session"), _("Tool"), psz_value ); } if( strcmp( p_sdp->psz_username, "-" ) ) { vlc_input_item_AddInfo( &p_item->input, _("Session"), _("User"), p_sdp->psz_username ); } psz_value = GetAttribute( p_sap->p_sdp, "x-plgroup" ); if( psz_value == NULL ) { psz_value = GetAttribute( p_sap->p_sdp, "plgroup" ); } if( psz_value != NULL ) { char *psz_grp = convert_from_utf8( p_sd, psz_value ); if( psz_grp != NULL ) { p_child = playlist_ChildSearchName( p_sd->p_sys->p_node, psz_grp ); if( p_child == NULL ) { p_child = playlist_NodeCreate( p_sd->p_sys->p_playlist, VIEW_CATEGORY, psz_grp, p_sd->p_sys->p_node ); p_child->i_flags =~ PLAYLIST_SKIP_FLAG; } free( psz_grp ); } else { msg_Err( p_sd, "out of memory"); free( p_sap ); return NULL; } } else { p_child = p_sd->p_sys->p_node; } p_item->i_flags &= ~PLAYLIST_SKIP_FLAG; p_item->i_flags &= ~PLAYLIST_SAVE_FLAG; playlist_NodeAddItem( p_sd->p_sys->p_playlist, p_item, VIEW_CATEGORY, p_child, PLAYLIST_APPEND, PLAYLIST_END ); p_sap->i_item_id = p_item->input.i_id; TAB_APPEND( p_sd->p_sys->i_announces, p_sd->p_sys->pp_announces, p_sap ); return p_sap;}static char *GetAttribute( sdp_t *p_sdp, const char *psz_search ){ int i; for( i = 0 ; i< p_sdp->i_attributes; i++ ) { if( !strncmp( p_sdp->pp_attributes[i]->psz_field, psz_search, strlen( p_sdp->pp_attributes[i]->psz_field ) ) ) { return p_sdp->pp_attributes[i]->psz_value; } } return NULL;}/* Fill p_sdp->psz_uri */static int ParseConnection( vlc_object_t *p_obj, sdp_t *p_sdp ){ char *psz_eof; char *psz_parse; char *psz_uri = NULL; char *psz_proto = NULL; int i_port = 0; /* Parse c= field */ if( p_sdp->psz_connection ) { psz_parse = p_sdp->psz_connection; psz_eof = strchr( psz_parse, ' ' ); if( psz_eof ) { *psz_eof = '\0'; psz_parse = psz_eof + 1; } else { msg_Warn( p_obj, "unable to parse c field (1)"); return VLC_EGENERIC; } psz_eof = strchr( psz_parse, ' ' ); if( psz_eof ) { *psz_eof = '\0'; if( !strncmp( psz_parse, "IP4", 3 ) ) { p_sdp->i_in = 4; } else if( !strncmp( psz_parse, "IP6", 3 ) ) { p_sdp->i_in = 6; } else { p_sdp->i_in = 0; } psz_parse = psz_eof + 1; } else { msg_Warn( p_obj, "unable to parse c field (2)"); return VLC_EGENERIC; } psz_eof = strchr( psz_parse, '/' ); if( psz_eof ) { *psz_eof = 0; } else { msg_Dbg( p_obj, "incorrect c field, %s", p_sdp->psz_connection ); } psz_uri = strdup( psz_parse ); } /* Parse m= field */ if( p_sdp->psz_media ) { psz_parse = p_sdp->psz_media; psz_eof = strchr( psz_parse, ' ' ); if( psz_eof ) { *psz_eof = '\0'; if( strncmp( psz_parse, "audio", 5 ) && strncmp( psz_parse, "video",5 ) ) { msg_Warn( p_obj, "unhandled media type -%s-", psz_parse ); FREE( psz_uri ); return VLC_EGENERIC; } psz_parse = psz_eof + 1; } else { msg_Warn( p_obj, "unable to parse m field (1)"); FREE( psz_uri ); return VLC_EGENERIC; } psz_eof = strchr( psz_parse, ' ' ); if( psz_eof ) { *psz_eof = '\0'; /* FIXME : multiple port ! */ i_port = atoi( psz_parse ); if( i_port <= 0 || i_port >= 65536 ) { msg_Warn( p_obj, "invalid transport port %i", i_port ); } psz_parse = psz_eof + 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -