[vlc-devel] [PATCH 3/3] Implement a liBDSM SMB/CIFS access module

Julien 'Lta' BALLET elthariel at gmail.com
Wed Jun 18 19:11:52 CEST 2014


From: Julien 'Lta' BALLET <contact at lta.io>

liBSDM service discovery has been merged as a submodule of the access module
---
 modules/access/Makefile.am             |   8 +
 modules/access/bdsm/bdsm.c             | 421 +++++++++++++++++++++++++++++++++
 modules/access/bdsm/common.h           |  34 +++
 modules/access/bdsm/sd.c               | 112 +++++++++
 modules/services_discovery/Makefile.am |   6 +-
 modules/services_discovery/bdsm.c      | 131 ----------
 6 files changed, 576 insertions(+), 136 deletions(-)
 create mode 100644 modules/access/bdsm/bdsm.c
 create mode 100644 modules/access/bdsm/common.h
 create mode 100644 modules/access/bdsm/sd.c
 delete mode 100644 modules/services_discovery/bdsm.c

diff --git a/modules/access/Makefile.am b/modules/access/Makefile.am
index 40d65dc..87d9e6d 100644
--- a/modules/access/Makefile.am
+++ b/modules/access/Makefile.am
@@ -386,6 +386,14 @@ libsmb_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(accessdir)'
 access_LTLIBRARIES += $(LTLIBsmb)
 EXTRA_LTLIBRARIES += libsmb_plugin.la
 
+libdsm_plugin_la_SOURCES = access/bdsm/bdsm.c access/bdsm/sd.c \
+	access/bdsm/common.h
+libdsm_plugin_la_CFLAGS = $(AM_CFLAGS) $(BDSM_CFLAGS)
+libdsm_plugin_la_LIBADD = $(BDSM_LIBS)
+libdsm_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(sddir)'
+access_LTLIBRARIES += $(LTLIBdsm)
+EXTRA_LTLIBRARIES += libdsm_plugin.la
+
 libtcp_plugin_la_SOURCES = access/tcp.c
 libtcp_plugin_la_LIBADD = $(SOCKET_LIBS)
 access_LTLIBRARIES += libtcp_plugin.la
diff --git a/modules/access/bdsm/bdsm.c b/modules/access/bdsm/bdsm.c
new file mode 100644
index 0000000..78edc61
--- /dev/null
+++ b/modules/access/bdsm/bdsm.c
@@ -0,0 +1,421 @@
+/*****************************************************************************
+ * bdsm.c: liBDSM based SMB/CIFS access module
+ *****************************************************************************
+ * Copyright (C) 2001-2009 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 <vlc_access.h>
+#include <vlc_url.h>
+#include <vlc_variables.h>
+
+#include <string.h>
+#include <bsd/string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+
+#define USER_TEXT N_("SMB user name")
+#define USER_LONGTEXT N_("User name that will " \
+    "be used for the connection. username in uri take precedence over this")
+#define PASS_TEXT N_("SMB password")
+#define PASS_LONGTEXT N_("Password that will be " \
+    "used for the connection. Password in uri take precedence over this.")
+#define DOMAIN_TEXT N_("SMB domain")
+#define DOMAIN_LONGTEXT N_("Domain/Workgroup that " \
+    "will be used for the connection. Domain of uri will also be tried.")
+
+#define BDSM_HELP N_("liBDSM's SMB (Windows network shares) input")
+vlc_module_begin ()
+    set_shortname( "BDSM" )
+    set_description( N_("liBDSM SMB input") )
+    set_help(BDSM_HELP)
+    set_capability( "access", 0 )
+    set_category( CAT_INPUT )
+    set_subcategory( SUBCAT_INPUT_ACCESS )
+    add_string( "smb-user", NULL, USER_TEXT, USER_LONGTEXT,
+                false )
+    add_password( "smb-pwd", NULL, PASS_TEXT,
+                  PASS_LONGTEXT, false )
+    add_string( "smb-domain", NULL, DOMAIN_TEXT,
+                DOMAIN_LONGTEXT, false )
+    add_shortcut( "smb" )
+    set_callbacks( Open, Close )
+
+    add_submodule()
+        set_shortname( N_( "Windows networks" ) )
+        set_description( N_( "Netbios speaking host on the Local network" ) )
+        set_category( CAT_PLAYLIST )
+        set_subcategory( SUBCAT_PLAYLIST_SD )
+        set_capability( "services_discovery", 20 )
+        set_callbacks( SdOpen, SdClose )
+        add_shortcut( "smb", "bdsm" )
+
+        VLC_SD_PROBE_SUBMODULE
+
+vlc_module_end ()
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+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 );
+
+struct access_sys_t
+{
+    smb_session        *p_session;
+    netbios_ns         *p_ns;
+    smb_fd              i_fd;
+
+    struct {
+        char       *psz_username;
+        char       *psz_password;
+        char       *psz_domain;
+    } creds;
+
+    char               *psz_share;
+    char               *psz_path;
+
+    char                netbios_name[16];
+    struct in_addr      addr;
+    vlc_url_t           url;
+};
+
+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.psz_password = var_InheritString( p_access, "smb-pwd" );
+    else
+        p_sys->creds.psz_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 )
+    {
+        char *user;
+        p_sys->creds.psz_username = strdup( p_sys->url.psz_username );
+        if( (user = strchr( p_sys->creds.psz_username, '\\' ) ) != NULL )
+        {
+            p_sys->creds.psz_domain = p_sys->creds.psz_username;
+            *user = '\0';
+            p_sys->creds.psz_username = strdup( user + 1 );
+        }
+    }
+    else
+    {
+        p_sys->creds.psz_username = var_InheritString( p_access, "smb-user" );
+        if( p_sys->creds.psz_username == NULL )
+            p_sys->creds.psz_username = strdup( "Guest" );
+    }
+
+    if( p_sys->creds.psz_domain == NULL )
+        p_sys->creds.psz_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.psz_domain == NULL && p_sys->netbios_name[0] )
+        p_sys->creds.psz_domain = strdup( p_sys->netbios_name );
+
+    return true;
+}
+
+static bool get_path(access_t *p_access, access_sys_t *p_sys)
+{
+    if( p_sys->url.psz_path == NULL )
+        return false;
+
+    /* Let's switch the path delimiters from / to \ */
+    char *iter = p_sys->url.psz_path;
+    while( *iter != '\0' )
+    {
+        if( *iter == '/' )
+            *iter = '\\';
+        iter++;
+    }
+
+    iter = strchr(p_sys->url.psz_path + 1, '\\');
+    if( iter == NULL )
+    {
+        msg_Err(p_access, "No share name to connect to");
+        return false;
+    }
+    p_sys->psz_path = strdup( iter ); /* Skip the first / */
+    *iter = '\0';
+    p_sys->psz_share = strdup( p_sys->url.psz_path + 1 ); /* Skip the first / */
+    *iter = '\\';
+
+    if (p_sys->psz_path == NULL || p_sys->psz_share == NULL)
+        return false;
+
+    return true;
+}
+
+int Open( vlc_object_t *p_this )
+{
+    access_t     *p_access = (access_t*)p_this;
+    access_sys_t *p_sys;
+
+    /* Init p_access */
+    STANDARD_READ_ACCESS_INIT;
+
+    p_sys->url.psz_buffer     = NULL;
+    p_sys->creds.psz_username = NULL;
+    p_sys->creds.psz_password = NULL;
+    p_sys->creds.psz_domain   = NULL;
+    p_sys->psz_share          = NULL;
+    p_sys->psz_path           = NULL;
+
+
+    p_sys->p_session = smb_session_new();
+    if( p_sys->p_session == NULL )
+        goto error;
+
+    p_sys->p_ns = netbios_ns_new();
+    if( p_sys->p_ns == NULL )
+        goto error;
+
+    vlc_UrlParse( &p_sys->url, p_access->psz_location, 0 );
+    get_credentials( p_access, p_sys );
+    if( !get_address( p_access, p_sys ) )
+        goto error;
+    if( !get_path( p_access, p_sys ) )
+        goto error;
+
+    if( p_sys->creds.psz_domain == NULL )
+        p_sys->creds.psz_domain = strdup( "WORKGROUP" );
+
+    msg_Dbg( p_access, "Creds: username = %s, password = %s, domain = %s",
+             p_sys->creds.psz_username, p_sys->creds.psz_password,
+             p_sys->creds.psz_domain );
+    msg_Dbg( p_access, "Session: Host name = %s, ip = %s", p_sys->netbios_name,
+             inet_ntoa( p_sys->addr ) );
+    msg_Dbg( p_access, "Path: Share name = %s, path = %s", p_sys->psz_share,
+             p_sys->psz_path );
+
+    /* 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");
+        goto error;
+    }
+
+    /* Try to authenticate on the remote machine */
+    smb_session_set_creds( p_sys->p_session, p_sys->creds.psz_domain,
+                           p_sys->creds.psz_username, p_sys->creds.psz_password );
+    if( !smb_session_login(p_sys->p_session ) )
+    {
+        /* 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.psz_username, p_sys->creds.psz_password,
+                   p_sys->creds.psz_domain );
+        goto error;
+    }
+
+    /* Connect to the share */
+    smb_tid i_tid = smb_tree_connect( p_sys->p_session, p_sys->psz_share );
+    if( !i_tid )
+    {
+        msg_Err( p_access, "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, 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 );
+        goto error;
+    }
+    p_access->info.i_pos = 0;
+
+    msg_Dbg( p_access, "Successfully opened smb://%s", p_access->psz_location );
+    return VLC_SUCCESS;
+
+    error:
+        smb_session_destroy( p_sys->p_session );
+        netbios_ns_destroy( p_sys->p_ns );
+
+        free( p_sys->creds.psz_username );
+        free( p_sys->creds.psz_password );
+        free( p_sys->creds.psz_domain );
+        free( p_sys->url.psz_buffer );
+        free( p_sys->psz_share );
+        free( p_sys->psz_path );
+        free( p_sys );
+
+        return VLC_EGENERIC;
+}
+
+/*****************************************************************************
+ * Seek: try to go at the right place
+ *****************************************************************************/
+static int Seek( access_t *p_access, uint64_t i_pos )
+{
+    access_sys_t *p_sys = p_access->p_sys;
+    int64_t      i_ret;
+
+    if( i_pos >= INT64_MAX )
+        return VLC_EGENERIC;
+
+    msg_Dbg( p_access, "seeking to %"PRId64, i_pos );
+
+    /* seek cannot fail in bdsm, but the subsequent read can */
+    i_ret = smb_fseek(p_sys->p_session, p_sys->i_fd, i_pos, SMB_SEEK_SET);
+
+    p_access->info.b_eof = false;
+    p_access->info.i_pos = i_ret;
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Read:
+ *****************************************************************************/
+static ssize_t Read( access_t *p_access, uint8_t *p_buffer, size_t i_len )
+{
+    access_sys_t *p_sys = p_access->p_sys;
+    int i_read;
+
+    if( p_access->info.b_eof ) return 0;
+
+    i_read = smb_fread( p_sys->p_session, p_sys->i_fd, p_buffer, i_len );
+    if( i_read < 0 )
+    {
+        msg_Err( p_access, "read failed" );
+        return -1;
+    }
+
+    if( i_read == 0 ) p_access->info.b_eof = true;
+    else if( i_read > 0 ) p_access->info.i_pos += i_read;
+
+    return i_read;
+}
+
+/*****************************************************************************
+ * Control:
+ *****************************************************************************/
+static int Control( access_t *p_access, int i_query, va_list args )
+{
+    switch( i_query )
+    {
+    case ACCESS_CAN_SEEK:
+    case ACCESS_CAN_FASTSEEK:
+    case ACCESS_CAN_PAUSE:
+    case ACCESS_CAN_CONTROL_PACE:
+        *va_arg( args, bool* ) = true;
+        break;
+
+    case ACCESS_GET_SIZE:
+    {
+        smb_stat st = smb_stat_fd( p_access->p_sys->p_session,
+                                   p_access->p_sys->i_fd );
+        *va_arg( args, uint64_t * ) = smb_stat_get( st, SMB_STAT_SIZE );
+        break;
+    }
+    case ACCESS_GET_PTS_DELAY:
+        *va_arg( args, int64_t * ) = INT64_C(1000)
+            * var_InheritInteger( p_access, "network-caching" );
+        break;
+
+    case ACCESS_SET_PAUSE_STATE:
+        /* Nothing to do */
+        break;
+
+    default:
+        return VLC_EGENERIC;
+    }
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close: free unused data structures
+ *****************************************************************************/
+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);
+    if( p_sys->p_session != NULL )
+        smb_session_destroy( p_sys->p_session );
+    free( p_sys );
+}
diff --git a/modules/access/bdsm/common.h b/modules/access/bdsm/common.h
new file mode 100644
index 0000000..62724f7
--- /dev/null
+++ b/modules/access/bdsm/common.h
@@ -0,0 +1,34 @@
+/**
+ * @file bdsm/common.h
+ * @brief List host supporting NETBIOS on the local network
+ */
+/*****************************************************************************
+ * Copyright © 2014 Authors and the VideoLAN team
+ *
+ * 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.
+ *****************************************************************************/
+
+#include <bdsm/bdsm.h>
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_services_discovery.h>
+
+int Open( vlc_object_t * );
+void Close( vlc_object_t * );
+int SdOpen( vlc_object_t * );
+void SdClose( vlc_object_t * );
+int vlc_sd_probe_Open( vlc_object_t * );
diff --git a/modules/access/bdsm/sd.c b/modules/access/bdsm/sd.c
new file mode 100644
index 0000000..fc4e4a5
--- /dev/null
+++ b/modules/access/bdsm/sd.c
@@ -0,0 +1,112 @@
+/**
+ * @file bdsm.c
+ * @brief List host supporting NETBIOS on the local network
+ */
+/*****************************************************************************
+ * Copyright © 2014 Authors and the VideoLAN team
+ *
+ * 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"
+
+struct services_discovery_sys_t
+{
+    netbios_ns      *ns;
+};
+
+int vlc_sd_probe_Open (vlc_object_t *p_this)
+{
+    vlc_probe_t *p_probe = (vlc_probe_t *)p_this;
+
+    vlc_sd_probe_Add( p_probe, "dsm{longname=\"Windows networks\"}",
+                      N_( "Windows networks" ), SD_CAT_LAN );
+
+    return VLC_PROBE_CONTINUE;
+}
+
+int SdOpen (vlc_object_t *p_this)
+{
+    services_discovery_t *p_sd = (services_discovery_t *)p_this;
+    services_discovery_sys_t *p_sys = malloc (sizeof (*p_sys));
+
+    if( p_sys == NULL )
+        return VLC_ENOMEM;
+    p_sd->p_sys = p_sys;
+
+    /* Let's create a NETBIOS name service object */
+    p_sys->ns = netbios_ns_new();
+    if( p_sys->ns == NULL )
+        goto error;
+
+    if( !netbios_ns_discover( p_sys->ns ) )
+        goto error;
+
+    for( size_t i = 0; i < netbios_ns_entry_count( p_sys->ns ); i++ )
+    {
+        netbios_ns_entry *p_entry = netbios_ns_entry_at( p_sys->ns, i );
+
+        if( p_entry->type == 0x20 )
+        {
+            input_item_t *p_item;
+            char *psz_mrl;
+
+            /* XXX: Remove trailing whitespaces */
+            if( asprintf(&psz_mrl, "smb://%#s/", p_entry->name) < 0 )
+                goto error;
+
+            p_item = input_item_NewWithType( psz_mrl, p_entry->name, 0, NULL,
+                                             0, -1, ITEM_TYPE_NODE );
+            msg_Dbg( p_sd, "Adding item %s", psz_mrl );
+
+            services_discovery_AddItem( p_sd, p_item, NULL );
+
+            free( psz_mrl );
+        }
+    }
+
+    return VLC_SUCCESS;
+
+    error:
+        if( p_sys->ns != NULL )
+            netbios_ns_destroy( p_sys->ns );
+        free( p_sys );
+        p_sd->p_sys = NULL;
+
+        return VLC_EGENERIC;
+}
+
+void SdClose (vlc_object_t *p_this)
+{
+    services_discovery_t *sd = (services_discovery_t *)p_this;
+    services_discovery_sys_t *p_sys = sd->p_sys;
+
+    if( p_sys == NULL )
+        return;
+
+    if( p_sys->ns != NULL )
+        netbios_ns_destroy( p_sys->ns );
+}
+
diff --git a/modules/services_discovery/Makefile.am b/modules/services_discovery/Makefile.am
index 2cbc92a..eeaf570 100644
--- a/modules/services_discovery/Makefile.am
+++ b/modules/services_discovery/Makefile.am
@@ -69,9 +69,5 @@ if HAVE_OS2
 sd_LTLIBRARIES += libos2drive_plugin.la
 endif
 
-libdsm_plugin_la_SOURCES = services_discovery/bdsm.c
-libdsm_plugin_la_CFLAGS = $(AM_CFLAGS) $(BDSM_CFLAGS)
-libdsm_plugin_la_LIBADD = $(BDSM_LIBS)
-libdsm_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(sddir)'
 sd_LTLIBRARIES += $(LTLIBdsm)
-EXTRA_LTLIBRARIES += libdsm_plugin.la
+
diff --git a/modules/services_discovery/bdsm.c b/modules/services_discovery/bdsm.c
deleted file mode 100644
index c13434e..0000000
--- a/modules/services_discovery/bdsm.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/**
- * @file bdsm.c
- * @brief List host supporting NETBIOS on the local network
- */
-/*****************************************************************************
- * Copyright © 2014 Authors and the VideoLAN team
- *
- * 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 <bdsm/netbios_ns.h>
-
-#include <vlc_common.h>
-#include <vlc_services_discovery.h>
-#include <vlc_plugin.h>
-
-static int Open( vlc_object_t * );
-static void Close( vlc_object_t * );
-static int vlc_sd_probe_Open( vlc_object_t * );
-
-vlc_module_begin()
-    set_shortname( N_( "Windows networks" ) )
-    set_description( N_( "Netbios speaking host on the Local network" ) )
-    set_category( CAT_PLAYLIST )
-    set_subcategory( SUBCAT_PLAYLIST_SD )
-    set_capability( "services_discovery", 0 )
-    set_callbacks( Open, Close )
-    add_shortcut( "smb", "bdsm" )
-
-    VLC_SD_PROBE_SUBMODULE
-
-vlc_module_end()
-
-struct services_discovery_sys_t
-{
-    netbios_ns      *ns;
-};
-
-static int vlc_sd_probe_Open (vlc_object_t *p_this)
-{
-    vlc_probe_t *p_probe = (vlc_probe_t *)p_this;
-
-    vlc_sd_probe_Add( p_probe, "dsm{longname=\"Windows networks\"}",
-                      N_( "Windows networks" ), SD_CAT_LAN );
-
-    return VLC_PROBE_CONTINUE;
-}
-
-static int Open (vlc_object_t *p_this)
-{
-    services_discovery_t *p_sd = (services_discovery_t *)p_this;
-    services_discovery_sys_t *p_sys = malloc (sizeof (*p_sys));
-
-    if( p_sys == NULL )
-        return VLC_ENOMEM;
-    p_sd->p_sys = p_sys;
-
-    /* Let's create a NETBIOS name service object */
-    p_sys->ns = netbios_ns_new();
-    if( p_sys->ns == NULL )
-        goto error;
-
-    if( !netbios_ns_discover( p_sys->ns ) )
-        goto error;
-
-    for( size_t i = 0; i < netbios_ns_entry_count( p_sys->ns ); i++ )
-    {
-        netbios_ns_entry *p_entry = netbios_ns_entry_at( p_sys->ns, i );
-
-        if( p_entry->type == 0x20 )
-        {
-            input_item_t *p_item;
-            char *psz_mrl;
-
-            /* XXX: Remove trailing whitespaces */
-            if( asprintf(&psz_mrl, "smb://%#s/", p_entry->name) < 0 )
-                goto error;
-
-            p_item = input_item_NewWithType( psz_mrl, p_entry->name, 0, NULL,
-                                             0, -1, ITEM_TYPE_NODE );
-            msg_Dbg( p_sd, "Adding item %s", psz_mrl );
-
-            services_discovery_AddItem( p_sd, p_item, NULL );
-
-            free( psz_mrl );
-        }
-    }
-
-    return VLC_SUCCESS;
-
-    error:
-        if( p_sys->ns != NULL )
-            netbios_ns_destroy( p_sys->ns );
-        free( p_sys );
-        p_sd->p_sys = NULL;
-
-        return VLC_EGENERIC;
-}
-
-static void Close (vlc_object_t *p_this)
-{
-    services_discovery_t *sd = (services_discovery_t *)p_this;
-    services_discovery_sys_t *p_sys = sd->p_sys;
-
-    if( p_sys == NULL )
-        return;
-
-    if( p_sys->ns != NULL )
-        netbios_ns_destroy( p_sys->ns );
-}
-
-- 
2.0.0




More information about the vlc-devel mailing list