cleaned up service client code and moved common call code into Service superclass, using the soaphelp functions

Jean-Francois Dockes Jean-Francois Dockes 2014-08-07

added libupnpp/control/service.cxx
added libupnpp/control/mediarenderer.cxx
added libupnpp/control/mediarenderer.hxx
added libupnpp/control/renderingcontrol.hxx
changed libupnpp/discovery.cxx
changed libupnpp/discovery.hxx
changed libupnpp/ixmlwrap.hxx
changed libupnpp/soaphelp.cxx
changed libupnpp/soaphelp.hxx
changed upexplo/upexplo.cxx
changed Makefile.am
copied libupnpp/cdircontent.cxx -> libupnpp/control/cdircontent.cxx
copied libupnpp/cdircontent.hxx -> libupnpp/control/cdircontent.hxx
copied libupnpp/cdirectory.cxx -> libupnpp/control/cdirectory.cxx
copied libupnpp/cdirectory.hxx -> libupnpp/control/cdirectory.hxx
copied libupnpp/service.cxx -> libupnpp/control/renderingcontrol.cxx
copied libupnpp/service.hxx -> libupnpp/control/service.hxx
libupnpp/control/service.cxx Diff Switch to side-by-side view
Loading...
libupnpp/control/mediarenderer.cxx Diff Switch to side-by-side view
Loading...
libupnpp/control/mediarenderer.hxx Diff Switch to side-by-side view
Loading...
libupnpp/control/renderingcontrol.hxx Diff Switch to side-by-side view
Loading...
libupnpp/discovery.cxx Diff Switch to side-by-side view
Loading...
libupnpp/discovery.hxx Diff Switch to side-by-side view
Loading...
libupnpp/ixmlwrap.hxx Diff Switch to side-by-side view
Loading...
libupnpp/soaphelp.cxx Diff Switch to side-by-side view
Loading...
libupnpp/soaphelp.hxx Diff Switch to side-by-side view
Loading...
upexplo/upexplo.cxx Diff Switch to side-by-side view
Loading...
Makefile.am Diff Switch to side-by-side view
Loading...
libupnpp/cdirectory.cxx to libupnpp/control/cdirectory.cxx
--- a/libupnpp/cdirectory.cxx
+++ b/libupnpp/control/cdirectory.cxx
@@ -37,6 +37,8 @@
 #include "cdirectory.hxx"
 #include "cdircontent.hxx"
 #include "discovery.hxx"
+#include "soaphelp.hxx"
+#include "log.hxx"
 
 namespace UPnPClient {
 
@@ -98,84 +100,62 @@
 }
 
 
-class DirBResFree {
-public:
-    IXML_Document **rqpp, **rspp;
-    DirBResFree(IXML_Document** _rqpp, IXML_Document **_rspp)
-        :rqpp(_rqpp), rspp(_rspp)
-        {}
-    ~DirBResFree()
-        {
-            if (*rqpp)
-                ixmlDocument_free(*rqpp);
-            if (*rspp)
-                ixmlDocument_free(*rspp);
-        }
-};
+#if 0
+static int asyncReaddirCB(Upnp_EventType et, void *vev, void *cookie)
+{
+    LOGDEB("asyncReaddirCB: " << LibUPnP::evTypeAsString(et) << endl);
+    struct Upnp_Action_Complete *act = (struct Upnp_Action_Complete*)vev;
+
+    LOGDEB("asyncReaddirCB: errcode " << act->ErrCode << 
+           " cturl " <<  UpnpString_get_String(act->CtrlUrl) << 
+           " actionrequest " << endl << 
+           ixmlPrintDocument(act->ActionRequest) << endl <<
+           " actionresult " << ixmlPrintDocument(act->ActionResult) << endl);
+    return 0;
+}
+    int ret = 
+        UpnpSendActionAsync(hdl, m_actionURL.c_str(), m_serviceType.c_str(),
+        0 /*devUDN*/, request, asyncReaddirCB, 0);
+    sleep(10);
+    return -1;
+#endif
+
 
 int ContentDirectoryService::readDirSlice(const string& objectId, int offset,
                                           int count, UPnPDirContent& dirbuf,
                                           int *didreadp, int *totalp)
 {
-    LOGDEB("CDService::readDirSlice: objId ["<< objectId << "] offset " << 
+    LOGDEB("CDService::readDirSlice: objId [" << objectId << "] offset " << 
            offset << " count " << count << endl);
 
-    LibUPnP* lib = LibUPnP::getLibUPnP();
-    if (lib == 0) {
-        LOGINF("CDService::readDir: no lib" << endl);
-        return UPNP_E_OUTOF_MEMORY;
-    }
-    UpnpClient_Handle hdl = lib->getclh();
-
-    IXML_Document *request(0);
-    IXML_Document *response(0);
-    DirBResFree cleaner(&request, &response);
-
     // Create request
-    char ofbuf[100], cntbuf[100];
-    sprintf(ofbuf, "%d", offset);
-    sprintf(cntbuf, "%d", count);
-    int argcnt = 6;
     // Some devices require an empty SortCriteria, else bad params
-    request = UpnpMakeAction("Browse", m_serviceType.c_str(), argcnt,
-                             "ObjectID", objectId.c_str(),
-                             "BrowseFlag", "BrowseDirectChildren",
-                             "Filter", "*",
-                             "SortCriteria", "",
-                             "StartingIndex", ofbuf,
-                             "RequestedCount", cntbuf,
-                             NULL, NULL);
-    if (request == 0) {
-        LOGINF("CDService::readDir: UpnpMakeAction failed" << endl);
-        return  UPNP_E_OUTOF_MEMORY;
-    }
-
-    //cerr << "Action xml: [" << ixmlPrintDocument(request) << "]" << endl;
-
-    int ret = UpnpSendAction(hdl, m_actionURL.c_str(), m_serviceType.c_str(),
-                             0 /*devUDN*/, request, &response);
-
+    SoapData args(m_serviceType, "Browse");
+    args("ObjectID", objectId)
+        ("BrowseFlag", "BrowseDirectChildren")
+        ("Filter", "*")
+        ("SortCriteria", "")
+        ("StartingIndex", SoapEncodeInput::i2s(offset))
+        ("RequestedCount", SoapEncodeInput::i2s(count));
+
+    SoapArgs data;
+    int ret = runAction(args, data);
     if (ret != UPNP_E_SUCCESS) {
-        LOGINF("CDService::readDir: UpnpSendAction failed: " <<
-               UpnpGetErrorMessage(ret) << endl);
         return ret;
     }
-
-    int didread = -1;
-    string tbuf = ixmlwrap::getFirstElementValue(response, "NumberReturned");
-    if (!tbuf.empty())
-        didread = atoi(tbuf.c_str());
-
-    if (count == -1 || count == 0) {
+    int didread;
+    string tbuf;
+    if (!data.getInt("NumberReturned", &didread) ||
+        !data.getInt("TotalMatches", totalp) ||
+        !data.getString("Result", &tbuf)) {
+        LOGERR("CDService::readDir: missing elts in response" << endl);
+        return UPNP_E_BAD_RESPONSE;
+    }
+
+    if (didread <= 0) {
         LOGINF("CDService::readDir: got -1 or 0 entries" << endl);
         return UPNP_E_BAD_RESPONSE;
     }
-
-    tbuf = ixmlwrap::getFirstElementValue(response, "TotalMatches");
-    if (!tbuf.empty())
-        *totalp = atoi(tbuf.c_str());
-
-    tbuf = ixmlwrap::getFirstElementValue(response, "Result");
 
 #if 0
     cerr << "CDService::readDirSlice: count " << count <<
@@ -186,9 +166,9 @@
 
     dirbuf.parse(tbuf);
     *didreadp = didread;
+
     return UPNP_E_SUCCESS;
 }
-
 
 int ContentDirectoryService::readDir(const string& objectId,
                                      UPnPDirContent& dirbuf)
@@ -219,46 +199,23 @@
 {
     LOGDEB("CDService::search: url [" << m_actionURL << "] type [" << 
            m_serviceType << "] udn [" << m_deviceId << "] objid [" << 
-           objectId <<  "] search [" << ss << "]" << endl;
-
-    LibUPnP* lib = LibUPnP::getLibUPnP();
-    if (lib == 0) {
-        LOGINF("CDService::search: no lib" << endl);
-        return UPNP_E_OUTOF_MEMORY;
-    }
-    UpnpClient_Handle hdl = lib->getclh();
-
-    int ret = UPNP_E_SUCCESS;
-    IXML_Document *request(0);
-    IXML_Document *response(0);
+           objectId <<  "] search [" << ss << "]" << endl);
 
     int offset = 0;
     int total = 1000;// Updated on first read.
 
     while (offset < total) {
-        DirBResFree cleaner(&request, &response);
-        char ofbuf[100];
-        sprintf(ofbuf, "%d", offset);
         // Create request
-        int argcnt = 6;
-        request = UpnpMakeAction(
-            "Search", m_serviceType.c_str(), argcnt,
-            "ContainerID", objectId.c_str(),
-            "SearchCriteria", ss.c_str(),
-            "Filter", "*",
-            "SortCriteria", "",
-            "StartingIndex", ofbuf,
-            "RequestedCount", "0", // Setting a value here gets twonky into fits
-            NULL, NULL);
-        if (request == 0) {
-            LOGINF("CDService::search: UpnpMakeAction failed" << endl);
-            return  UPNP_E_OUTOF_MEMORY;
-        }
-
-        // cerr << "Action xml: [" << ixmlPrintDocument(request) << "]" << endl;
-
-        ret = UpnpSendAction(hdl, m_actionURL.c_str(), m_serviceType.c_str(),
-                             0 /*devUDN*/, request, &response);
+        SoapData args(m_serviceType, "Search");
+        args("ContainerID", objectId)
+            ("SearchCriteria", ss)
+            ("Filter", "*")
+            ("SortCriteria", "")
+            ("StartingIndex", SoapEncodeInput::i2s(offset))
+            ("RequestedCount", "10"); 
+
+        SoapArgs data;
+        int ret = runAction(args, data);
 
         if (ret != UPNP_E_SUCCESS) {
             LOGINF("CDService::search: UpnpSendAction failed: " <<
@@ -267,30 +224,19 @@
         }
 
         int count = -1;
-        string tbuf =
-            ixmlwrap::getFirstElementValue(response, "NumberReturned");
-        if (!tbuf.empty())
-            count = atoi(tbuf.c_str());
-
-        if (count == -1 || count == 0) {
+        string tbuf;
+        if (!data.getInt("NumberReturned", &count) ||
+            !data.getInt("TotalMatches", &total) ||
+            !data.getString("Result", &tbuf)) {
+            LOGERR("CDService::search: missing elts in response" << endl);
+            return UPNP_E_BAD_RESPONSE;
+        }
+        if (count <=  0) {
             LOGINF("CDService::search: got -1 or 0 entries" << endl);
-            return count == -1 ? UPNP_E_BAD_RESPONSE : UPNP_E_SUCCESS;
+            return count < 0 ? UPNP_E_BAD_RESPONSE : UPNP_E_SUCCESS;
         }
         offset += count;
 
-        tbuf = ixmlwrap::getFirstElementValue(response, "TotalMatches");
-        if (!tbuf.empty())
-            total = atoi(tbuf.c_str());
-
-        tbuf = ixmlwrap::getFirstElementValue(response, "Result");
-
-#if 0
-        cerr << "CDService::search: count " << count <<
-            " offset " << offset <<
-            " total " << total << endl;
-        cerr << " result " << tbuf << endl;
-#endif
-
         dirbuf.parse(tbuf);
     }
 
@@ -300,41 +246,21 @@
 int ContentDirectoryService::getSearchCapabilities(set<string>& result)
 {
     LOGDEB("CDService::getSearchCapabilities:" << endl);
-    LibUPnP* lib = LibUPnP::getLibUPnP();
-    if (lib == 0) {
-        LOGINF("CDService::getSearchCapabilities: no lib" << endl);
-        return UPNP_E_OUTOF_MEMORY;
-    }
-    UpnpClient_Handle hdl = lib->getclh();
-
-    int ret = UPNP_E_SUCCESS;
-    IXML_Document *request(0);
-    IXML_Document *response(0);
-
-    request = UpnpMakeAction("GetSearchCapabilities", m_serviceType.c_str(),
-                             0,
-                             NULL, NULL);
-
-    if (request == 0) {
-        LOGINF("CDService::getSearchCapa: UpnpMakeAction failed" << endl);
-        return  UPNP_E_OUTOF_MEMORY;
-    }
-
-    //cerr << "Action xml: [" << ixmlPrintDocument(request) << "]" << endl;
-
-    ret = UpnpSendAction(hdl, m_actionURL.c_str(), m_serviceType.c_str(),
-                         0 /*devUDN*/, request, &response);
-
+
+    SoapData args(m_serviceType, "GetSearchCapabilities");
+    SoapArgs data;
+    int ret = runAction(args, data);
     if (ret != UPNP_E_SUCCESS) {
         LOGINF("CDService::getSearchCapa: UpnpSendAction failed: " << 
                UpnpGetErrorMessage(ret) << endl);
         return ret;
     }
-    //cerr << "getSearchCapa: response xml: [" << ixmlPrintDocument(response)
-    // << "]" << endl;
-
-    string tbuf = ixmlwrap::getFirstElementValue(response, "SearchCaps");
-    // cerr << "getSearchCapa: capa: [" << tbuf << "]" << endl;
+    string tbuf;
+    if (!data.getString("SearchCaps", &tbuf)) {
+        LOGERR("CDService::getSearchCaps: missing Result in response" << endl);
+        cerr << tbuf << endl;
+        return UPNP_E_BAD_RESPONSE;
+    }
 
     result.clear();
     if (!tbuf.compare("*")) {
@@ -355,44 +281,26 @@
            m_serviceType << "] udn [" << m_deviceId << "] objId [" <<
            objectId << "]" << endl);
 
-    LibUPnP* lib = LibUPnP::getLibUPnP();
-    if (lib == 0) {
-        LOGINF("CDService::getMetadata: no lib" << endl);
-        return UPNP_E_OUTOF_MEMORY;
-    }
-    UpnpClient_Handle hdl = lib->getclh();
-
-    int ret = UPNP_E_SUCCESS;
-    IXML_Document *request(0);
-    IXML_Document *response(0);
-
-    DirBResFree cleaner(&request, &response);
-    // Create request
-    int argcnt = 6;
-    request = UpnpMakeAction("Browse", m_serviceType.c_str(), argcnt,
-                             "ObjectID", objectId.c_str(),
-                             "BrowseFlag", "BrowseMetadata",
-                             "Filter", "*",
-                             "SortCriteria", "",
-                             "StartingIndex", "0",
-                             "RequestedCount", "1",
-                             NULL, NULL);
-    if (request == 0) {
-        LOGINF("CDService::getmetadata: UpnpMakeAction failed" << endl);
-        return  UPNP_E_OUTOF_MEMORY;
-    }
-
-    //cerr << "Action xml: [" << ixmlPrintDocument(request) << "]" << endl;
-
-    ret = UpnpSendAction(hdl, m_actionURL.c_str(), m_serviceType.c_str(),
-                         0 /*devUDN*/, request, &response);
-
+    SoapData args(m_serviceType, "Browse");
+    SoapArgs data;
+    args("ObjectID", objectId)
+        ("BrowseFlag", "BrowseMetadata")
+        ("Filter", "*")
+        ("SortCriteria", "")
+        ("StartingIndex", "0")
+        ("RequestedCount", "1");
+    int ret = runAction(args, data);
     if (ret != UPNP_E_SUCCESS) {
         LOGINF("CDService::getmetadata: UpnpSendAction failed: " << 
                UpnpGetErrorMessage(ret) << endl);
         return ret;
     }
-    string tbuf = ixmlwrap::getFirstElementValue(response, "Result");
+    string tbuf;
+    if (!data.getString("Result", &tbuf)) {
+        LOGERR("CDService::getmetadata: missing Result in response" << endl);
+        return UPNP_E_BAD_RESPONSE;
+    }
+
     if (dirbuf.parse(tbuf))
         return UPNP_E_SUCCESS;
     else
libupnpp/service.cxx to libupnpp/control/renderingcontrol.cxx
--- a/libupnpp/service.cxx
+++ b/libupnpp/control/renderingcontrol.cxx
@@ -15,22 +15,23 @@
  *       59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
-#include "service.h"
-#include "cdirectory.h"
-#include "log.h"
+#include <string>
+using namespace std;
+
+#include "libupnpp/control/renderingcontrol.hxx"
 
 namespace UPnPClient {
 
-Service *service_factory(const string& servicetype,
-                         const UPnPDeviceDesc& device,
-                         const UPnPServiceDesc& service)
+const string 
+RenderingControl::SType("urn:schemas-upnp-org:service:RenderingControl:1");
+
+// We don't include a version in comparisons, as we are satisfied with
+// version 1
+bool RenderingControl::isRDCService(const string& st)
 {
-    if (ContentDirectoryService::isCDService(servicetype)) {
-        return new ContentDirectoryService(device, service);
-    } else {
-        LOGERR("service_factory: unknown service type " << servicetype << endl);
-        return 0;
-    }
+    const string::size_type sz(SType.size()-2);
+    return !SType.compare(0, sz, st, 0, sz);
 }
 
-}
+
+};
libupnpp/service.hxx to libupnpp/control/service.hxx
--- a/libupnpp/service.hxx
+++ b/libupnpp/control/service.hxx
@@ -19,7 +19,11 @@
 
 #include <string>
 
-#include "upnpp_p.hxx"
+#include <upnp/ixml.h>
+
+#include "libupnpp/soaphelp.hxx"
+#include "libupnpp/upnpp_p.hxx"
+#include "libupnpp/description.hxx"
 
 namespace UPnPClient {
 
@@ -32,6 +36,7 @@
     Service(const UPnPDeviceDesc& device,
             const UPnPServiceDesc& service)
         : m_actionURL(caturl(device.URLBase, service.controlURL)),
+          m_eventURL(caturl(device.URLBase, service.eventSubURL)),
           m_serviceType(service.serviceType),
           m_deviceId(device.UDN),
           m_friendlyName(device.friendlyName),
@@ -50,8 +55,12 @@
     /** Return my root device id */
     std::string getDeviceId() const {return m_deviceId;}
 
+    int runAction(const SoapEncodeInput& args, SoapDecodeOutput& data);
+
 protected:
+
     std::string m_actionURL;
+    std::string m_eventURL;
     std::string m_serviceType;
     std::string m_deviceId;
     std::string m_friendlyName;