[vlc-commits] upnp: make pf_readdir interruptible

Thomas Guillem git at videolan.org
Wed Dec 9 12:11:12 CET 2015


vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Tue Dec  8 10:34:35 2015 +0100| [d76bc0b91a275006f337ddcf3de8a0fef7060b89] | committer: Thomas Guillem

upnp: make pf_readdir interruptible

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=d76bc0b91a275006f337ddcf3de8a0fef7060b89
---

 modules/services_discovery/upnp.cpp |   89 +++++++++++++++++++++++++++++++++--
 modules/services_discovery/upnp.hpp |   17 +++++++
 2 files changed, 101 insertions(+), 5 deletions(-)

diff --git a/modules/services_discovery/upnp.cpp b/modules/services_discovery/upnp.cpp
index 5dfaf3f..3b092c5 100644
--- a/modules/services_discovery/upnp.cpp
+++ b/modules/services_discovery/upnp.cpp
@@ -30,6 +30,7 @@
 
 #include <vlc_access.h>
 #include <vlc_plugin.h>
+#include <vlc_interrupt.h>
 #include <vlc_services_discovery.h>
 
 #include <assert.h>
@@ -620,6 +621,60 @@ int MediaServerList::Callback( Upnp_EventType event_type, void* p_event, void* p
 namespace Access
 {
 
+Upnp_i11e_cb::Upnp_i11e_cb( Upnp_FunPtr callback, void *cookie )
+    : refCount_( 2 ) /* 2: owned by the caller, and the Upnp Async function */
+    , callback_( callback )
+    , cookie_( cookie )
+
+{
+    vlc_mutex_init( &lock_ );
+    vlc_sem_init( &sem_, 0 );
+}
+
+Upnp_i11e_cb::~Upnp_i11e_cb()
+{
+    vlc_mutex_destroy( &lock_ );
+    vlc_sem_destroy( &sem_ );
+}
+
+void Upnp_i11e_cb::waitAndRelease( void )
+{
+    vlc_sem_wait_i11e( &sem_ );
+
+    vlc_mutex_lock( &lock_ );
+    if ( --refCount_ == 0 )
+    {
+        /* The run callback is processed, we can destroy this object */
+        vlc_mutex_unlock( &lock_ );
+        delete this;
+    } else
+    {
+        /* Interrupted, let the run callback destroy this object */
+        vlc_mutex_unlock( &lock_ );
+    }
+}
+
+int Upnp_i11e_cb::run( Upnp_EventType eventType, void *p_event, void *p_cookie )
+{
+    Upnp_i11e_cb *self = static_cast<Upnp_i11e_cb*>( p_cookie );
+
+    vlc_mutex_lock( &self->lock_ );
+    if ( --self->refCount_ == 0 )
+    {
+        /* Interrupted, we can destroy self */
+        vlc_mutex_unlock( &self->lock_ );
+        delete self;
+        return 0;
+    }
+    /* Process the user callback_ */
+    self->callback_( eventType, p_event, self->cookie_);
+    vlc_mutex_unlock( &self->lock_ );
+
+    /* Signal that the callback is processed */
+    vlc_sem_post( &self->sem_ );
+    return 0;
+}
+
 MediaServer::MediaServer( access_t *p_access )
     : psz_root_( NULL )
     , psz_objectId_( NULL )
@@ -670,6 +725,24 @@ input_item_t* MediaServer::newItem(const char* title, const char*, const char*,
                                       duration, ITEM_TYPE_FILE, 1 );
 }
 
+int MediaServer::sendActionCb( Upnp_EventType eventType,
+                               void *p_event, void *p_cookie )
+{
+    if( eventType != UPNP_CONTROL_ACTION_COMPLETE )
+        return 0;
+    IXML_Document** pp_sendActionResult = (IXML_Document** )p_cookie;
+    Upnp_Action_Complete *p_result = (Upnp_Action_Complete *)p_event;
+
+    /* The only way to dup the result is to print it and parse it again */
+    DOMString tmpStr = ixmlPrintNode( ( IXML_Node * ) p_result->ActionResult );
+    if (tmpStr == NULL)
+        return 0;
+
+    *pp_sendActionResult = ixmlParseBuffer( tmpStr );
+    ixmlFreeDOMString( tmpStr );
+    return 0;
+}
+
 /* Access part */
 IXML_Document* MediaServer::_browseAction( const char* psz_object_id_,
                                            const char* psz_browser_flag_,
@@ -679,9 +752,13 @@ IXML_Document* MediaServer::_browseAction( const char* psz_object_id_,
 {
     IXML_Document* p_action = NULL;
     IXML_Document* p_response = NULL;
+    Upnp_i11e_cb *i11eCb = NULL;
 
     int i_res;
 
+    if ( vlc_killed() )
+        return NULL;
+
     i_res = UpnpAddToAction( &p_action, "Browse",
             CONTENT_DIRECTORY_SERVICE_TYPE, "ObjectID", psz_object_id_ );
 
@@ -741,21 +818,23 @@ IXML_Document* MediaServer::_browseAction( const char* psz_object_id_,
         goto browseActionCleanup;
     }
 
-    i_res = UpnpSendAction( access_->p_sys->p_upnp->handle(),
+    /* Setup an interruptible callback that will call sendActionCb if not
+     * interrupted by vlc_interrupt_kill */
+    i11eCb = new Upnp_i11e_cb( sendActionCb, &p_response );
+    i_res = UpnpSendActionAsync( access_->p_sys->p_upnp->handle(),
               psz_root_,
               CONTENT_DIRECTORY_SERVICE_TYPE,
               NULL, /* ignored in SDK, must be NULL */
               p_action,
-              &p_response );
+              Upnp_i11e_cb::run, i11eCb );
 
     if ( i_res != UPNP_E_SUCCESS )
     {
         msg_Err( access_, "%s when trying the send() action with URL: %s",
                 UpnpGetErrorMessage( i_res ), access_->psz_location );
-
-        ixmlDocument_free( p_response );
-        p_response = NULL;
     }
+    /* Wait for the callback to fill p_response or wait for an interrupt */
+    i11eCb->waitAndRelease();
 
 browseActionCleanup:
     ixmlDocument_free( p_action );
diff --git a/modules/services_discovery/upnp.hpp b/modules/services_discovery/upnp.hpp
index 8b6e9f9..e59af18 100644
--- a/modules/services_discovery/upnp.hpp
+++ b/modules/services_discovery/upnp.hpp
@@ -118,6 +118,22 @@ private:
 namespace Access
 {
 
+class Upnp_i11e_cb
+{
+public:
+    Upnp_i11e_cb( Upnp_FunPtr callback, void *cookie );
+    ~Upnp_i11e_cb();
+    void waitAndRelease( void );
+    static int run( Upnp_EventType, void *, void *);
+
+private:
+    sem_t           sem_;
+    vlc_mutex_t     lock_;
+    int             refCount_;
+    Upnp_FunPtr     callback_;
+    void*           cookie_;
+};
+
 class MediaServer
 {
 public:
@@ -135,6 +151,7 @@ private:
 
     IXML_Document* _browseAction(const char*, const char*,
             const char*, const char*, const char* );
+    static int sendActionCb( Upnp_EventType, void *, void *);
 
 private:
     char* psz_root_;



More information about the vlc-commits mailing list