[vlc-devel] [RFC PATCH 3/8] dsm: refactorize
Thomas Guillem
thomas at gllm.fr
Thu Nov 27 14:01:45 CET 2014
On Thu, Nov 27, 2014, at 12:00, Thomas Guillem wrote:
> Move browser.c to common.c. This new file contains common browsing
> functions
> that can be used from an access_t or from a services_discovery_t.
> ---
> modules/access/Makefile.am | 2 +-
> modules/access/dsm/access.c | 340 ++++++------------------------
> modules/access/dsm/browser.c | 191 -----------------
> modules/access/dsm/common.c | 483
> +++++++++++++++++++++++++++++++++++++++++++
> modules/access/dsm/common.h | 25 ++-
> 5 files changed, 572 insertions(+), 469 deletions(-)
> delete mode 100644 modules/access/dsm/browser.c
> create mode 100644 modules/access/dsm/common.c
>
> diff --git a/modules/access/Makefile.am b/modules/access/Makefile.am
> index e154bee..528ddc0 100644
> --- a/modules/access/Makefile.am
> +++ b/modules/access/Makefile.am
> @@ -413,7 +413,7 @@ access_LTLIBRARIES += $(LTLIBsmb)
> EXTRA_LTLIBRARIES += libsmb_plugin.la
>
> libdsm_plugin_la_SOURCES = access/dsm/access.c access/dsm/common.h \
> - access/dsm/browser.c access/dsm/sd.c
> + access/dsm/common.c access/dsm/sd.c
> libdsm_plugin_la_CFLAGS = $(AM_CFLAGS) $(DSM_CFLAGS)
> libdsm_plugin_la_LIBADD = $(DSM_LIBS)
> libdsm_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(sddir)'
> diff --git a/modules/access/dsm/access.c b/modules/access/dsm/access.c
> index 6269b77..5ec3b2a 100644
> --- a/modules/access/dsm/access.c
> +++ b/modules/access/dsm/access.c
> @@ -33,12 +33,6 @@
> #include <vlc_variables.h>
> #include <vlc_dialog.h>
>
> -#include <string.h>
> -#include <sys/socket.h>
> -#include <netinet/in.h>
> -#include <arpa/inet.h>
> -#include <netdb.h>
> -
> /*****************************************************************************
> * Module descriptor
> *****************************************************************************/
> @@ -87,15 +81,9 @@ static ssize_t Read( access_t *, uint8_t *, size_t );
> static int Seek( access_t *, uint64_t );
> static int Control( access_t *, int, va_list );
>
> -static void split_domain_login( char **psz_login, char **psz_domain );
> -static void get_credentials( access_t *p_access, access_sys_t *p_sys );
> -static bool get_address( access_t *p_access, access_sys_t *p_sys );
> static void login_dialog( access_t *p_access, access_sys_t *p_sys );
> -static bool login( access_t *p_access, access_sys_t *p_sys );
> -static void backslash_path( vlc_url_t *p_url );
> -static bool get_path( access_t *p_access, access_sys_t *p_sys );
> -static bool bdsm_init( access_t *p_access, access_sys_t *p_sys );
> -static void bdsm_destroy( access_sys_t *p_sys );
> +static void login( void *p_ctx );
> +static int BrowserInit( access_t *p_access );
>
> /*****************************************************************************
> * Dialog strings
> @@ -112,6 +100,7 @@ int Open( vlc_object_t *p_this )
> {
> access_t *p_access = (access_t*)p_this;
> access_sys_t *p_sys;
> + bdsm_login_cb_t login_cb;
>
> /* Init p_access */
> access_InitFields( p_access );
> @@ -119,46 +108,24 @@ int Open( vlc_object_t *p_this )
> if( p_access->p_sys == NULL )
> return VLC_ENOMEM;
>
> - if( !bdsm_init( p_access, p_sys ) )
> - goto error;
> -
> - if( !get_path( p_access, p_sys ) )
> - return BrowserInit( p_access );
> - msg_Dbg( p_access, "Path: Share name = %s, path = %s",
> p_sys->psz_share,
> - p_sys->psz_path );
> -
> -
> - /* Connect to the share */
> - p_sys->i_tid = smb_tree_connect( p_sys->p_session, p_sys->psz_share
> );
> - if( !p_sys->i_tid )
> - {
> - msg_Err( p_access, "Unable to connect to share %s",
> p_sys->psz_share );
> + if( bdsm_Init( p_sys, VLC_OBJECT(p_access) ) != VLC_SUCCESS )
> goto error;
> - }
>
> - /* Let's finally ask a handle to the file we wanna read ! */
> - p_sys->i_fd = smb_fopen( p_sys->p_session, p_sys->i_tid,
> p_sys->psz_path,
> - SMB_MOD_RO );
> - if( !p_sys->i_fd )
> - {
> - msg_Err( p_access, "Unable to open file with path %s (in share
> %s)",
> - p_sys->psz_path, p_sys->psz_share );
> + login_cb.pf_login = login;
> + login_cb.p_ctx = p_access;
> + if( bdsm_Connect( p_sys, &login_cb, p_access->psz_location ) !=
> VLC_SUCCESS )
> goto error;
> - }
>
> - smb_stat st = smb_stat_fd( p_sys->p_session, p_sys->i_fd );
> - if( smb_stat_get( st, SMB_STAT_ISDIR ) )
> - {
> - smb_fclose( p_sys->p_session, p_sys->i_fd );
> + if( p_sys->b_is_browsing )
> return BrowserInit( p_access );
> - }
>
> msg_Dbg( p_access, "Successfully opened smb://%s",
> p_access->psz_location );
> +
> ACCESS_SET_CALLBACKS( Read, NULL, Control, Seek );
> return VLC_SUCCESS;
>
> error:
> - bdsm_destroy( p_sys );
> + bdsm_Destroy( p_sys );
> free( p_sys );
> return VLC_EGENERIC;
> }
> @@ -171,8 +138,7 @@ void Close( vlc_object_t *p_this )
> access_t *p_access = (access_t*)p_this;
> access_sys_t *p_sys = p_access->p_sys;
>
> - smb_fclose( p_sys->p_session, p_sys->i_fd );
> - bdsm_destroy( p_sys );
> + bdsm_Destroy( p_sys );
> free( p_sys );
> }
>
> @@ -180,96 +146,6 @@ void Close( vlc_object_t *p_this )
> * Local functions
> *****************************************************************************/
>
> -/* Split DOMAIN\User if it finds a '\' in psz_login. */
> -static void split_domain_login( char **psz_login, char **psz_domain )
> -{
> - char *user = strchr( *psz_login, '\\' );
> -
> - if( user != NULL )
> - {
> - *psz_domain = *psz_login;
> - *user = '\0';
> - *psz_login = strdup( user + 1 );
> - }
> -}
> -
> -/* Get credentials from uri or variables. */
> -static void get_credentials( access_t *p_access, access_sys_t *p_sys )
> -{
> - /* Fetch credentials, either from URI or from options if not
> provided */
> - if( p_sys->url.psz_password == NULL )
> - p_sys->creds.password = var_InheritString( p_access, "smb-pwd"
> );
> - else
> - p_sys->creds.password = strdup( p_sys->url.psz_password );
> -
> - /* Here we support smb://DOMAIN\User:password@XXX, get user from
> options
> - or default to "Guest" as last resort */
> - if( p_sys->url.psz_username != NULL )
> - {
> - p_sys->creds.login = strdup( p_sys->url.psz_username );
> - split_domain_login( &p_sys->creds.login, &p_sys->creds.domain );
> - }
> - else
> - {
> - p_sys->creds.login = var_InheritString( p_access, "smb-user" );
> - if( p_sys->creds.login == NULL )
> - p_sys->creds.login = strdup( "Guest" );
> - }
> -
> - if( p_sys->creds.domain == NULL )
> - p_sys->creds.domain = var_InheritString( p_access, "smb-domain"
> );
> -
> -}
> -
> -/* Returns false if it wasn't able to get an ip address to connect to */
> -static bool get_address( access_t *p_access, access_sys_t *p_sys )
> -{
> - if( !inet_aton( p_sys->url.psz_host, &p_sys->addr ) )
> - {
> - /* This is not an ip address, let's try netbios/dns resolve */
> - struct addrinfo *p_info = NULL;
> -
> - /* Is this a netbios name on this LAN ? */
> - if( netbios_ns_resolve( p_sys->p_ns, p_sys->url.psz_host, 0x20,
> - &p_sys->addr.s_addr) )
> - {
> - strlcpy( p_sys->netbios_name, p_sys->url.psz_host, 16);
> - return true;
> - }
> - /* or is it an existing dns name ? */
> - else if( getaddrinfo( p_sys->url.psz_host, NULL, NULL, &p_info )
> == 0 )
> - {
> - if( p_info->ai_family == AF_INET )
> - {
> - struct sockaddr_in *in = (struct sockaddr_in
> *)p_info->ai_addr;
> - p_sys->addr.s_addr = in->sin_addr.s_addr;
> - }
> - freeaddrinfo( p_info );
> - if( p_info->ai_family != AF_INET )
> - return false;
> - }
> - else
> - return false;
> - }
> -
> - /* We have an IP address, let's find the NETBIOS name */
> - const char *psz_nbt = netbios_ns_inverse( p_sys->p_ns,
> p_sys->addr.s_addr );
> - if( psz_nbt != NULL )
> - strlcpy( p_sys->netbios_name, psz_nbt, 16 );
> - else
> - {
> - msg_Warn( p_access, "Unable to get netbios name of %s",
> - p_sys->url.psz_host );
> - p_sys->netbios_name[0] = '\0';
> - }
> -
> - /* If no domain was explicitly specified, let's use the machine name
> */
> - if( p_sys->creds.domain == NULL && p_sys->netbios_name[0] )
> - p_sys->creds.domain = strdup( p_sys->netbios_name );
> -
> - return true;
> -}
> -
> /* Displays a dialog for the user to enter his/her credentials */
> static void login_dialog( access_t *p_access, access_sys_t *p_sys )
> {
> @@ -290,7 +166,7 @@ static void login_dialog( access_t *p_access,
> access_sys_t *p_sys )
> if( p_sys->creds.login != NULL )
> free( p_sys->creds.login );
> p_sys->creds.login = psz_login;
> - split_domain_login( &p_sys->creds.login, &p_sys->creds.domain );
> + bdsm_SplitDomainLogin( &p_sys->creds.login, &p_sys->creds.domain
> );
> }
>
> if( psz_pass != NULL )
> @@ -301,164 +177,78 @@ static void login_dialog( access_t *p_access,
> access_sys_t *p_sys )
> }
> }
>
> -/* Performs login with existing credentials and ask the user for new
> ones on
> - failure */
> -static bool login( access_t *p_access, access_sys_t *p_sys )
> +static void login( void *p_ctx )
> {
> - if( p_sys->creds.login == NULL )
> - p_sys->creds.login = strdup( "Guest" );
> - if( p_sys->creds.password == NULL )
> - p_sys->creds.password = strdup( "Guest" );
> - if( p_sys->creds.domain == NULL )
> - p_sys->creds.domain = strdup( "WORKGROUP" );
> -
> - /* Try to authenticate on the remote machine */
> - smb_session_set_creds( p_sys->p_session, p_sys->creds.domain,
> - p_sys->creds.login, p_sys->creds.password );
> - if( !smb_session_login( p_sys->p_session ) )
> - {
> - for( int i = 0; i < BDSM_LOGIN_DIALOG_RETRY; i++ )
> - {
> - login_dialog( p_access, p_sys );
> - smb_session_set_creds( p_sys->p_session,
> p_sys->creds.domain,
> - p_sys->creds.login,
> p_sys->creds.password );
> - if( smb_session_login( p_sys->p_session ) )
> - return true;
> - }
> -
> - /* FIXME, Try to force netbios name as domain then WORKGROUP
> here */
> - msg_Err( p_access, "Unable to login with username = %s, password
> = %s, domain = %s",
> - p_sys->creds.login, p_sys->creds.password,
> - p_sys->creds.domain );
> - return false;
> - }
> - else if( smb_session_is_guest( p_sys->p_session ) == 1 )
> - msg_Warn( p_access, "Login failure but you were logged in as a
> Guest");
> + access_t *p_access = p_ctx;
> + access_sys_t *p_sys = p_access->p_sys;
>
> - return true;
> + for( int i = 0; i < BDSM_LOGIN_DIALOG_RETRY; i++ )
> + login_dialog( p_access, p_sys );
> }
>
> -static void backslash_path( vlc_url_t *p_url )
> +static int AddToNode( void *p_ctx, input_item_t *p_item )
> {
> - char *iter = p_url->psz_path;
> -
> - /* Let's switch the path delimiters from / to \ */
> - while( *iter != '\0' )
> - {
> - if( *iter == '/' )
> - *iter = '\\';
> - iter++;
> - }
> + input_item_node_t *p_node = p_ctx;
> + input_item_CopyOptions( p_node->p_item, p_item );
> + return input_item_node_AppendItem( p_node, p_item ) != NULL ?
> VLC_SUCCESS
> + :
> VLC_EGENERIC;
> }
>
> -/* Get the share and filepath from uri (also replace all / by \ in
> url.psz_path) */
> -static bool get_path( access_t *p_access, access_sys_t *p_sys )
> +static int BrowseShare( access_t *p_access, input_item_node_t *p_node )
> {
> - VLC_UNUSED( p_access );
> -
> - char *iter;
> -
> - if( p_sys->url.psz_path == NULL )
> - return false;
> -
> - backslash_path( &p_sys->url );
> -
> - /* Is path longer than just "/" ? */
> - if( strlen( p_sys->url.psz_path ) > 1 )
> - {
> - iter = p_sys->url.psz_path;
> - while( *iter == '\\' ) iter++; /* Handle smb://Host/////Share/
> */
> + bdsm_item_cb_t cb;
> + cb.pf_add_item = AddToNode;
> + cb.p_ctx = p_node;
> + return bdsm_BrowseShare( p_access->p_sys, &cb,
> p_node->p_item->psz_uri );
> +}
>
> - p_sys->psz_share = strdup( iter );
> - if ( p_sys->psz_share == NULL )
> - return false;
> - }
> - else
> - {
> - msg_Dbg( p_access, "no share, nor file path provided, will
> switch to browser");
> - return false;
> - }
> +static int BrowseDirectory( access_t *p_access, input_item_node_t
> *p_node )
> +{
> + bdsm_item_cb_t cb;
> + cb.pf_add_item = AddToNode;
> + cb.p_ctx = p_node;
> + return bdsm_BrowseDirectory( p_access->p_sys, &cb,
> p_node->p_item->psz_uri );
> +}
>
> +static int BrowserControl( access_t *p_access, int i_query, va_list args
> )
> +{
> + VLC_UNUSED( p_access );
>
> - iter = strchr( p_sys->psz_share, '\\' );
> - if( iter == NULL || strlen(iter + 1) == 0 )
> + switch( i_query )
> {
> - if( iter != NULL ) /* Remove the trailing \ */
> - *iter = '\0';
> - p_sys->psz_path = strdup( "" );
> -
> - msg_Dbg( p_access, "no file path provided, will switch to
> browser ");
> - return true;
> - }
> -
> - p_sys->psz_path = strdup( iter + 1); /* Skip the first \ */
> - *iter = '\0';
> - if( p_sys->psz_path == NULL )
> - return false;
> -
> - return true;
> + case ACCESS_CAN_SEEK:
> + case ACCESS_CAN_FASTSEEK:
> + *va_arg( args, bool* ) = false;
> + break;
> +
> + case ACCESS_CAN_PAUSE:
> + case ACCESS_CAN_CONTROL_PACE:
> + *va_arg( args, bool* ) = true;
> + break;
> +
> + case ACCESS_GET_PTS_DELAY:
> + *va_arg( args, int64_t * ) = DEFAULT_PTS_DELAY * 1000;
> + break;
> +
> + default:
> + return VLC_EGENERIC;
> + }
> + return VLC_SUCCESS;
> }
>
> -/* get ip address/path/creds, then connects and try to authenticate */
> -static bool bdsm_init( access_t *p_access, access_sys_t *p_sys )
> +static int BrowserInit( access_t *p_access )
> {
> - p_sys->url.psz_buffer = NULL;
> - p_sys->creds.login = NULL;
> - p_sys->creds.password = NULL;
> - p_sys->creds.domain = NULL;
> - p_sys->psz_share = NULL;
> - p_sys->psz_path = NULL;
> - p_sys->i_fd = 0;
> - p_sys->i_tid = 0;
> -
> - p_sys->p_session = smb_session_new();
> - if( p_sys->p_session == NULL )
> - return false;
> -
> - p_sys->p_ns = netbios_ns_new();
> - if( p_sys->p_ns == NULL )
> - return false;
> -
> - vlc_UrlParse( &p_sys->url, p_access->psz_location, 0 );
> - get_credentials( p_access, p_sys );
> - if( !get_address( p_access, p_sys ) )
> - return false;
> -
> - msg_Dbg( p_access, "Creds: username = %s, password = %s, domain =
> %s",
> - p_sys->creds.login, p_sys->creds.password,
> - p_sys->creds.domain );
> - msg_Dbg( p_access, "Session: Host name = %s, ip = %s",
> p_sys->netbios_name,
> - inet_ntoa( p_sys->addr ) );
> -
> - /* Now that we have the required data, let's establish a session */
> - if( !smb_session_connect( p_sys->p_session, p_sys->netbios_name,
> - p_sys->addr.s_addr, SMB_TRANSPORT_TCP ))
> - {
> - msg_Err( p_access, "Unable to connect/negotiate SMB session");
> - return false;
> - }
> -
> - if( !login( p_access, p_sys ) )
> - return false;
> -
> + access_sys_t *p_sys = p_access->p_sys;
>
> + if( p_sys->psz_share == NULL )
> + p_access->pf_readdir = BrowseShare;
> + else
> + p_access->pf_readdir = BrowseDirectory;
> + p_access->pf_control = BrowserControl;
>
> - return true;
> + return VLC_SUCCESS;
> }
>
> -/* Cleanup libdsm stuff */
> -static void bdsm_destroy( access_sys_t *p_sys )
> -{
> - smb_session_destroy( p_sys->p_session );
> - netbios_ns_destroy( p_sys->p_ns );
> -
> - free( p_sys->creds.login );
> - free( p_sys->creds.password );
> - free( p_sys->creds.domain );
> - free( p_sys->url.psz_buffer );
> - free( p_sys->psz_share );
> - free( p_sys->psz_path );
> -}
>
> /*****************************************************************************
> * Seek: try to go at the right place
> diff --git a/modules/access/dsm/browser.c b/modules/access/dsm/browser.c
> deleted file mode 100644
> index 40dd314..0000000
> --- a/modules/access/dsm/browser.c
> +++ /dev/null
> @@ -1,191 +0,0 @@
> -/*****************************************************************************
> - * bdsm/access.c: liBDSM based SMB/CIFS access module
> -
> *****************************************************************************
> - * Copyright (C) 2001-2014 VLC authors and VideoLAN
> - *
> - * Authors: Julien 'Lta' BALLET <contact # lta 'dot' io>
> - *
> - * 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 Lesser General Public License for more details.
> - *
> - * 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.
> -
> *****************************************************************************/
> -
> -/*****************************************************************************
> - * Preamble
> -
> *****************************************************************************/
> -#ifdef HAVE_CONFIG_H
> -# include "config.h"
> -#endif
> -
> -#include "common.h"
> -
> -static int Control (access_t *p_access, int i_query, va_list args);
> -static int BrowseShare( access_t *p_access, input_item_node_t *p_node );
> -static int BrowseDirectory( access_t *p_access, input_item_node_t
> *p_node );
> -static bool AddToNode( access_t *p_access, input_item_node_t *p_node,
> - const char *psz_name );
> -
> -int BrowserInit( access_t *p_access )
> -{
> - access_sys_t *p_sys = p_access->p_sys;
> -
> - if( p_sys->psz_share == NULL )
> - p_access->pf_readdir = BrowseShare;
> - else
> - p_access->pf_readdir = BrowseDirectory;
> - p_access->pf_control = Control;
> -
> - return VLC_SUCCESS;
> -}
> -
> -static int BrowseShare( access_t *p_access, input_item_node_t *p_node )
> -{
> - smb_share_list shares;
> - const char *psz_name;
> - size_t share_count;
> -
> - share_count = smb_share_get_list( p_access->p_sys->p_session,
> &shares );
> - if( !share_count )
> - return VLC_ENOITEM;
> -
> - for( size_t i = 0; i < share_count; i++ )
> - {
> - psz_name = smb_share_list_at( shares, i );
> -
> - if( psz_name[strlen( psz_name ) - 1] == '$')
> - continue;
> -
> - AddToNode( p_access, p_node, psz_name );
> - }
> -
> - smb_share_list_destroy( shares );
> - return VLC_SUCCESS;
> -}
> -
> -static int BrowseDirectory( access_t *p_access, input_item_node_t
> *p_node )
> -{
> - access_sys_t *p_sys = p_access->p_sys;
> - smb_stat_list files;
> - smb_stat st;
> - char *psz_query;
> - const char *psz_name;
> - size_t files_count;
> - int i_ret;
> -
> - if( p_sys->psz_path != NULL )
> - {
> - i_ret = asprintf( &psz_query, "%s\\*", p_sys->psz_path );
> - if( i_ret == -1 )
> - return VLC_ENOMEM;
> - files = smb_find( p_sys->p_session, p_sys->i_tid, psz_query );
> - free( psz_query );
> - }
> - else
> - files = smb_find( p_sys->p_session, p_sys->i_tid, "\\*" );
> -
> - if( files == NULL )
> - return VLC_ENOITEM;
> -
> - files_count = smb_stat_list_count( files );
> - for( size_t i = 0; i < files_count; i++ )
> - {
> - st = smb_stat_list_at( files, i );
> -
> - if( st == NULL )
> - goto error;
> -
> - psz_name = smb_stat_name( st );
> -
> - /* Avoid infinite loop */
> - if( !strcmp( psz_name, ".") || !strcmp( psz_name, "..") )
> - continue;
> -
> - AddToNode( p_access, p_node, psz_name );
> - }
> -
> - smb_stat_list_destroy( files );
> - return VLC_SUCCESS;
> -
> - error:
> - smb_stat_list_destroy( files );
> - return VLC_ENOITEM;
> -}
> -
> -/*****************************************************************************
> - * Control:
> -
> *****************************************************************************/
> -static int Control( access_t *p_access, int i_query, va_list args )
> -{
> - VLC_UNUSED( p_access );
> -
> - switch( i_query )
> - {
> - case ACCESS_CAN_SEEK:
> - case ACCESS_CAN_FASTSEEK:
> - *va_arg( args, bool* ) = false;
> - break;
> -
> - case ACCESS_CAN_PAUSE:
> - case ACCESS_CAN_CONTROL_PACE:
> - *va_arg( args, bool* ) = true;
> - break;
> -
> - case ACCESS_GET_PTS_DELAY:
> - *va_arg( args, int64_t * ) = DEFAULT_PTS_DELAY * 1000;
> - break;
> -
> - default:
> - return VLC_EGENERIC;
> - }
> - return VLC_SUCCESS;
> - }
> -
> -static bool AddToNode( access_t *p_access, input_item_node_t *p_node,
> - const char *psz_name )
> -{
> - access_sys_t *p_sys = p_access->p_sys;
> - input_item_t *p_item;
> - char *psz_uri, *psz_option;
> - int i_ret;
> -
> - i_ret = asprintf( &psz_uri, "%s/%s", p_node->p_item->psz_uri,
> psz_name );
> - /* XXX Handle ENOMEM by enabling retry */
> - if( i_ret == -1 )
> - return false;
> -
> - p_item = input_item_New( psz_uri, psz_name );
> - free( psz_uri );
> - if( p_item == NULL )
> - return false;
> -
> - input_item_CopyOptions( p_node->p_item, p_item );
> - input_item_node_AppendItem( p_node, p_item );
> -
> - /* Here we save on the node the credentials that allowed us to
> login.
> - * That way the user isn't prompted more than once for credentials
> */
> - i_ret = asprintf( &psz_option, "smb-user=%s", p_sys->creds.login );
> - if( i_ret != -1 )
> - input_item_AddOption( p_item, psz_option,
> VLC_INPUT_OPTION_TRUSTED );
> - free( psz_option );
> - i_ret = asprintf( &psz_option, "smb-pwd=%s", p_sys->creds.password
> );
> - if( i_ret != -1 )
> - input_item_AddOption( p_item, psz_option,
> VLC_INPUT_OPTION_TRUSTED );
> - free( psz_option );
> - asprintf( &psz_option, "smb-domain=%s", p_sys->creds.domain );
> - if( i_ret != -1 )
> - input_item_AddOption( p_item, psz_option,
> VLC_INPUT_OPTION_TRUSTED );
> - free( psz_option );
> -
> - input_item_Release( p_item );
> - return true;
> -}
> diff --git a/modules/access/dsm/common.c b/modules/access/dsm/common.c
> new file mode 100644
> index 0000000..2b566d4
> --- /dev/null
> +++ b/modules/access/dsm/common.c
> @@ -0,0 +1,483 @@
> +/*****************************************************************************
> + * bdsm/common.c: liBDSM based SMB/CIFS access module
> +
> *****************************************************************************
> + * Copyright (C) 2001-2014 VLC authors and VideoLAN
> + *
> + * Authors: Julien 'Lta' BALLET <contact # lta 'dot' io>
> + *
> + * 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 Lesser General Public License for more details.
> + *
> + * 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.
> +
> *****************************************************************************/
> +
> +/*****************************************************************************
> + * Preamble
> +
> *****************************************************************************/
> +#ifdef HAVE_CONFIG_H
> +# include "config.h"
> +#endif
> +
> +#include "common.h"
> +
> +#include <netinet/in.h>
> +#include <arpa/inet.h>
> +#include <netdb.h>
> +
> +static void cleanup( bdsm_sys_t *p_sys );
> +static bool get_path( bdsm_sys_t *p_sys );
> +static int get_address( bdsm_sys_t *p_sys );
> +static void get_credentials( bdsm_sys_t *p_sys );
> +static int login( bdsm_sys_t *p_sys, bdsm_login_cb_t *p_login_cb );
> +static int add_item( bdsm_sys_t *p_sys, bdsm_item_cb_t *p_cb,
> + const char *psz_parent_uri, const char *psz_name );
> +
> +/* get ip address/path/creds, then connects and try to authenticate */
> +int bdsm_Init( bdsm_sys_t *p_sys, vlc_object_t *p_obj )
> +{
> + memset( p_sys, 0, sizeof(bdsm_sys_t) );
> +
> + p_sys->p_obj = p_obj;
> +
> + p_sys->p_ns = netbios_ns_new();
> + if( p_sys->p_ns == NULL )
> + return VLC_EGENERIC;
> +
> + return VLC_SUCCESS;
> +}
> +
> +int bdsm_Connect( bdsm_sys_t *p_sys, bdsm_login_cb_t *p_login_cb,
> + const char *psz_uri )
> +{
> + smb_stat st;
> +
> + cleanup( p_sys );
> +
> + p_sys->p_session = smb_session_new();
> + if( p_sys->p_session == NULL )
> + goto error;
> +
> + vlc_UrlParse( &p_sys->url, psz_uri, 0 );
> + get_credentials( p_sys );
> + if( get_address( p_sys ) != VLC_SUCCESS )
> + goto error;
> +
> + msg_Dbg( p_sys->p_obj, "Creds: username = %s, password = %s, domain
> = %s",
> + p_sys->creds.login, p_sys->creds.password,
> + p_sys->creds.domain );
> + msg_Dbg( p_sys->p_obj, "Session: Host name = %s, ip = %s",
> p_sys->netbios_name,
> + inet_ntoa( p_sys->addr ) );
> +
> + /* Now that we have the required data, let's establish a session */
> + if( !smb_session_connect( p_sys->p_session, p_sys->netbios_name,
> + p_sys->addr.s_addr, SMB_TRANSPORT_TCP ) )
> + {
> + msg_Err( p_sys->p_obj, "Unable to connect/negotiate SMB
> session");
> + goto error;
> + }
> +
> + if( login( p_sys, p_login_cb ) != VLC_SUCCESS )
> + goto error;
> +
> + if( !get_path( p_sys ) )
> + {
> + p_sys->b_is_browsing = true;
> + return VLC_SUCCESS;
> + }
> +
> + msg_Dbg( p_sys->p_obj, "Path: Share name = %s, path = %s",
> p_sys->psz_share,
> + p_sys->psz_path );
> +
> + /* Connect to the share */
> + p_sys->i_tid = smb_tree_connect( p_sys->p_session, p_sys->psz_share
> );
> + if( !p_sys->i_tid )
> + {
> + msg_Err( p_sys->p_obj, "Unable to connect to share %s",
> p_sys->psz_share );
> + goto error;
> + }
> +
> + /* Let's finally ask a handle to the file we wanna read ! */
> + p_sys->i_fd = smb_fopen( p_sys->p_session, p_sys->i_tid,
> p_sys->psz_path,
> + SMB_MOD_RO );
> + if( !p_sys->i_fd )
> + {
> + msg_Err( p_sys->p_obj, "Unable to open file with path %s (in
> share %s)",
> + p_sys->psz_path, p_sys->psz_share );
> + goto error;
> + }
> +
> + st = smb_stat_fd( p_sys->p_session, p_sys->i_fd );
> + if( smb_stat_get( st, SMB_STAT_ISDIR ) )
> + {
> + smb_fclose( p_sys->p_session, p_sys->i_fd );
> + p_sys->b_is_browsing = true;
> + }
> + return VLC_SUCCESS;
> + error:
> + cleanup( p_sys );
> + return VLC_EGENERIC;
> +}
> +
> +/* cleanup libdsm stuff */
> +void bdsm_Destroy( bdsm_sys_t *p_sys )
> +{
> + cleanup( p_sys );
> + if( p_sys->p_ns )
> + netbios_ns_destroy( p_sys->p_ns );
> +}
> +
> +/* Split DOMAIN\User if it finds a '\' in psz_login. */
> +void bdsm_SplitDomainLogin( char **psz_login, char **psz_domain )
> +{
> + char *user = strchr( *psz_login, '\\' );
> +
> + if( user != NULL )
> + {
> + *psz_domain = *psz_login;
> + *user = '\0';
> + *psz_login = strdup( user + 1 );
> + }
> +}
> +
> +int bdsm_BrowseShare( bdsm_sys_t *p_sys, bdsm_item_cb_t *p_cb,
> + const char *psz_uri )
> +{
> + smb_share_list shares;
> + const char *psz_name;
> + size_t share_count;
> + int i_ret;
> +
> + share_count = smb_share_get_list( p_sys->p_session, &shares );
> + if( !share_count )
> + return VLC_ENOITEM;
> +
> + for( size_t i = 0; i < share_count; i++ )
> + {
> + psz_name = smb_share_list_at( shares, i );
> +
> + if( psz_name[strlen( psz_name ) - 1] == '$')
> + continue;
> +
> + i_ret = add_item( p_sys, p_cb, psz_uri, psz_name );
> + if( i_ret != VLC_SUCCESS )
> + goto error;
> + }
> +
> + smb_share_list_destroy( shares );
> + return VLC_SUCCESS;
> + error:
> + smb_share_list_destroy( shares );
> + return i_ret;
> +}
> +
> +int bdsm_BrowseDirectory( bdsm_sys_t *p_sys, bdsm_item_cb_t *p_cb,
> + const char *psz_uri )
> +{
> + smb_stat_list files;
> + smb_stat st;
> + char *psz_query;
> + const char *psz_name;
> + size_t files_count;
> + int i_ret;
> +
> + if( p_sys->psz_path != NULL )
> + {
> + i_ret = asprintf( &psz_query, "%s\\*", p_sys->psz_path );
> + if( i_ret == -1 )
> + return VLC_ENOMEM;
> + files = smb_find( p_sys->p_session, p_sys->i_tid, psz_query );
> + free( psz_query );
> + }
> + else
> + files = smb_find( p_sys->p_session, p_sys->i_tid, "\\*" );
> +
> + if( files == NULL )
> + return VLC_ENOITEM;
> +
> + files_count = smb_stat_list_count( files );
> + for( size_t i = 0; i < files_count; i++ )
> + {
> + st = smb_stat_list_at( files, i );
> +
> + if( st == NULL ) {
> + i_ret = VLC_ENOITEM;
> + goto error;
> + }
> +
> + psz_name = smb_stat_name( st );
> +
> + /* Avoid infinite loop */
> + if( !strcmp( psz_name, ".") || !strcmp( psz_name, "..") )
> + continue;
> +
> + i_ret = add_item( p_sys, p_cb, psz_uri, psz_name );
> + if( i_ret != VLC_SUCCESS )
> + goto error;
> + }
> +
> + smb_stat_list_destroy( files );
> + return VLC_SUCCESS;
> +
> + error:
> + smb_stat_list_destroy( files );
> + return i_ret;
> +}
> +
> +/*****************************************************************************
> + * Local functions
> +
> *****************************************************************************/
> +
> +static void cleanup( bdsm_sys_t *p_sys )
> +{
> + p_sys->b_is_browsing = false;
> +
> + if( p_sys->i_fd )
> + smb_fclose( p_sys->p_session, p_sys->i_fd );
> + p_sys->i_fd = 0;
> +
> + if( p_sys->p_session )
> + smb_session_destroy( p_sys->p_session );
> + p_sys->p_session = NULL;
> + p_sys->i_tid = 0;
> +
> + free( p_sys->creds.login );
> + p_sys->creds.login = NULL;
> +
> + free( p_sys->creds.password );
> + p_sys->creds.password = NULL;
> +
> + free( p_sys->creds.domain );
> + p_sys->creds.domain = NULL;
> +
> + free( p_sys->url.psz_buffer );
> + p_sys->url.psz_buffer = NULL;
> +
> + free( p_sys->psz_share );
> + p_sys->psz_share = NULL;
> +
> + free( p_sys->psz_path );
> + p_sys->psz_path = NULL;
> +}
> +
> +static void backslash_path( vlc_url_t *p_url )
> +{
> + char *iter = p_url->psz_path;
> +
> + /* Let's switch the path delimiters from / to \ */
> + while( *iter != '\0' )
> + {
> + if( *iter == '/' )
> + *iter = '\\';
> + iter++;
> + }
> +}
> +
> +/* Get the share and filepath from uri (also replace all / by \ in
> url.psz_path) */
> +static bool get_path( bdsm_sys_t *p_sys )
> +{
> + char *iter;
> +
> + if( p_sys->url.psz_path == NULL )
> + return false;
> +
> + backslash_path( &p_sys->url );
> +
> + /* Is path longer than just "/" ? */
> + if( strlen( p_sys->url.psz_path ) > 1 )
> + {
> + iter = p_sys->url.psz_path;
> + while( *iter == '\\' ) iter++; /* Handle smb://Host/////Share/
> */
> +
> + p_sys->psz_share = strdup( iter );
> + if ( p_sys->psz_share == NULL )
> + return false;
> + }
> + else
> + {
> + msg_Dbg( p_sys->p_obj, "no share, nor file path provided, will
> switch to browser");
> + return false;
> + }
> +
> +
> + iter = strchr( p_sys->psz_share, '\\' );
> + if( iter == NULL || strlen(iter + 1) == 0 )
> + {
> + if( iter != NULL ) /* Remove the trailing \ */
> + *iter = '\0';
> + p_sys->psz_path = strdup( "" );
> +
> + msg_Dbg( p_sys->p_obj, "no file path provided, will switch to
> browser ");
> + return true;
> + }
> +
> + p_sys->psz_path = strdup( iter + 1); /* Skip the first \ */
> + *iter = '\0';
> + if( p_sys->psz_path == NULL )
> + return false;
> +
> + return true;
> +}
> +
> +/* Returns false if it wasn't able to get an ip address to connect to */
> +static int get_address( bdsm_sys_t *p_sys )
> +{
> + if( !inet_aton( p_sys->url.psz_host, &p_sys->addr ) )
> + {
> + /* This is not an ip address, let's try netbios/dns resolve */
> + struct addrinfo *p_info = NULL;
> +
> + /* Is this a netbios name on this LAN ? */
> + if( netbios_ns_resolve( p_sys->p_ns, p_sys->url.psz_host, 0x20,
> + &p_sys->addr.s_addr) )
> + {
> + strlcpy( p_sys->netbios_name, p_sys->url.psz_host, 16);
> + return VLC_SUCCESS;
> + }
> + /* or is it an existing dns name ? */
> + else if( getaddrinfo( p_sys->url.psz_host, NULL, NULL, &p_info )
> == 0 )
> + {
> + if( p_info->ai_family == AF_INET )
> + {
> + struct sockaddr_in *in = (struct sockaddr_in
> *)p_info->ai_addr;
> + p_sys->addr.s_addr = in->sin_addr.s_addr;
> + }
> + freeaddrinfo( p_info );
> + if( p_info->ai_family != AF_INET )
> + return VLC_EGENERIC;
> + }
> + else
> + return VLC_EGENERIC;
> + }
> +
> + /* We have an IP address, let's find the NETBIOS name */
> + const char *psz_nbt = netbios_ns_inverse( p_sys->p_ns,
> p_sys->addr.s_addr );
> + if( psz_nbt != NULL )
> + strlcpy( p_sys->netbios_name, psz_nbt, 16 );
> + else
> + {
> + msg_Warn( p_sys->p_obj, "Unable to get netbios name of %s",
> + p_sys->url.psz_host );
> + p_sys->netbios_name[0] = '\0';
> + }
> +
> + /* If no domain was explicitly specified, let's use the machine name
> */
> + if( p_sys->creds.domain == NULL && p_sys->netbios_name[0] )
> + p_sys->creds.domain = strdup( p_sys->netbios_name );
> +
> + return VLC_SUCCESS;
> +}
> +
> +/* Get credentials from uri or variables. */
> +static void get_credentials( bdsm_sys_t *p_sys )
> +{
> + /* Fetch credentials, either from URI or from options if not
> provided */
> + if( p_sys->url.psz_password == NULL )
> + p_sys->creds.password = var_InheritString( p_sys->p_obj,
> "smb-pwd" );
> + else
> + p_sys->creds.password = strdup( p_sys->url.psz_password );
> +
> + /* Here we support smb://DOMAIN\User:password@XXX, get user from
> options
> + or default to "Guest" as last resort */
> + if( p_sys->url.psz_username != NULL )
> + {
> + p_sys->creds.login = strdup( p_sys->url.psz_username );
> + bdsm_SplitDomainLogin( &p_sys->creds.login, &p_sys->creds.domain
> );
> + }
> + else
> + {
> + p_sys->creds.login = var_InheritString( p_sys->p_obj, "smb-user"
> );
> + if( p_sys->creds.login == NULL )
> + p_sys->creds.login = strdup( "Guest" );
> + }
> +
> + if( p_sys->creds.domain == NULL )
> + p_sys->creds.domain = var_InheritString( p_sys->p_obj,
> "smb-domain" );
> +}
> +
> +/* Performs login with existing credentials and ask the user for new
> ones on
> + failure */
> +static int login( bdsm_sys_t *p_sys, bdsm_login_cb_t *p_login_cb )
> +{
> + if( p_sys->creds.login == NULL )
> + p_sys->creds.login = strdup( "Guest" );
> + if( p_sys->creds.password == NULL )
> + p_sys->creds.password = strdup( "Guest" );
> + if( p_sys->creds.domain == NULL )
> + p_sys->creds.domain = strdup( "WORKGROUP" );
> +
> + /* Try to authenticate on the remote machine */
> + smb_session_set_creds( p_sys->p_session, p_sys->creds.domain,
> + p_sys->creds.login, p_sys->creds.password );
> + if( !smb_session_login( p_sys->p_session ) )
> + {
> + if( p_login_cb != NULL )
> + {
> + p_login_cb->pf_login( p_login_cb->p_ctx );
> + smb_session_set_creds( p_sys->p_session,
> p_sys->creds.domain,
> + p_sys->creds.login,
> p_sys->creds.password );
> + if( smb_session_login( p_sys->p_session ) )
> + return VLC_SUCCESS;
> + }
> +
> + /* FIXME, Try to force netbios name as domain then WORKGROUP
> here */
> + msg_Err( p_sys->p_obj, "Unable to login with username = %s,
> password = %s, domain = %s",
> + p_sys->creds.login, p_sys->creds.password,
> + p_sys->creds.domain );
> + return VLC_EGENERIC;
> + }
> + else if( smb_session_is_guest( p_sys->p_session ) == 1 )
> + msg_Warn( p_sys->p_obj, "Login failure but you were logged in as
> a Guest");
> +
> + return VLC_SUCCESS;
> +}
> +
> +static int add_item( bdsm_sys_t *p_sys, bdsm_item_cb_t *p_cb,
> + const char *psz_parent_uri, const char *psz_name )
> +{
> + input_item_t *p_item;
> + char *psz_uri, *psz_option;
> + int i_ret;
> +
> + i_ret = asprintf( &psz_uri, "%s/%s", psz_parent_uri, psz_name );
> + if( i_ret == -1 )
> + return VLC_ENOMEM;
> +
> + p_item = input_item_New( psz_uri, psz_name );
> + free( psz_uri );
> + if( p_item == NULL )
> + return VLC_ENOMEM;
> +
> + /* Here we save on the node the credentials that allowed us to
> login.
> + * That way the user isn't prompted more than once for credentials
> */
> + i_ret = asprintf( &psz_option, "smb-user=%s", p_sys->creds.login );
> + if( i_ret == -1 )
> + return VLC_ENOMEM;
> + input_item_AddOption( p_item, psz_option, VLC_INPUT_OPTION_TRUSTED
> );
> + free( psz_option );
> +
> + i_ret = asprintf( &psz_option, "smb-pwd=%s", p_sys->creds.password
> );
> + if( i_ret == -1 )
> + return VLC_ENOMEM;
> + input_item_AddOption( p_item, psz_option, VLC_INPUT_OPTION_TRUSTED
> );
> + free( psz_option );
> +
> + i_ret = asprintf( &psz_option, "smb-domain=%s", p_sys->creds.domain
> );
> + if( i_ret == -1 )
> + return VLC_ENOMEM;
> + input_item_AddOption( p_item, psz_option, VLC_INPUT_OPTION_TRUSTED
> );
> + free( psz_option );
> +
> + i_ret = p_cb->pf_add_item( p_cb->p_ctx, p_item );
> +
> + input_item_Release( p_item );
> + return i_ret;
> +}
> diff --git a/modules/access/dsm/common.h b/modules/access/dsm/common.h
> index cae5ab7..9e14b6d 100644
> --- a/modules/access/dsm/common.h
> +++ b/modules/access/dsm/common.h
> @@ -36,10 +36,9 @@ int SdOpen( vlc_object_t * );
> void SdClose( vlc_object_t * );
> int vlc_sd_probe_Open( vlc_object_t * );
>
> -int BrowserInit( access_t *p_access );
> -
> struct access_sys_t
> {
> + vlc_object_t *p_obj;
> netbios_ns *p_ns; /**< Netbios name service */
> smb_session *p_session; /**< bdsm SMB Session object
> */
> smb_creds creds; /**< Credentials used to
> connect */
> @@ -53,5 +52,27 @@ struct access_sys_t
>
> smb_fd i_fd; /**< SMB fd for the file
> we're reading */
> smb_tid i_tid; /**< SMB Tree ID we're
> connected to */
> + bool b_is_browsing;
> +};
> +typedef struct access_sys_t bdsm_sys_t;
> +
> +typedef struct bdsm_item_cb_t bdsm_item_cb_t;
> +struct bdsm_item_cb_t {
> + int ( *pf_add_item ) ( void *p_ctx, input_item_t * );
> + void *p_ctx;
> };
>
> +typedef struct bdsm_login_cb_t bdsm_login_cb_t;
> +struct bdsm_login_cb_t {
> + void ( *pf_login ) ( void *p_ctx );
> + void *p_ctx;
> +};
Finally, it's not needed. It's better to add dialog in libvlc. see Trac
#8704
> +
> +/* get ip address/path/creds, then connects and try to authenticate */
> +int bdsm_Init( bdsm_sys_t *, vlc_object_t * );
> +int bdsm_Connect( bdsm_sys_t *, bdsm_login_cb_t *, const char * );
> +void bdsm_Destroy( bdsm_sys_t * );
> +void bdsm_SplitDomainLogin( char **psz_login, char **psz_domain );
> +
> +int bdsm_BrowseShare( bdsm_sys_t *, bdsm_item_cb_t *, const char * );
> +int bdsm_BrowseDirectory( bdsm_sys_t *, bdsm_item_cb_t *, const char *
> );
> --
> 2.1.3
>
More information about the vlc-devel
mailing list