[vlc-devel] [RFC PATCH 3/8] dsm: refactorize
Rémi Denis-Courmont
remi at remlab.net
Thu Nov 27 21:28:42 CET 2014
Refactorize sounds cooler but refactor is English enough.
--
Rémi Denis-Courmont
Sent from my NVIDIA Tegra-powered device
----- Reply message -----
De : "Thomas Guillem" <thomas at gllm.fr>
Pour : <vlc-devel at videolan.org>
Objet : [vlc-devel] [RFC PATCH 3/8] dsm: refactorize
Date : jeu., nov. 27, 2014 13:00
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;
+};
+
+/* 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
_______________________________________________
vlc-devel mailing list
To unsubscribe or modify your subscription options:
https://mailman.videolan.org/listinfo/vlc-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20141127/9cc1e005/attachment.html>
More information about the vlc-devel
mailing list