Switch to unified view

a/libupnpp/control/discovery.cxx b/libupnpp/control/discovery.cxx
...
...
28
#include <functional>                   // for _Bind, bind, function, _1, etc
28
#include <functional>                   // for _Bind, bind, function, _1, etc
29
#include <iostream>                     // for operator<<, basic_ostream, etc
29
#include <iostream>                     // for operator<<, basic_ostream, etc
30
#include <map>                          // for _Rb_tree_iterator, map, etc
30
#include <map>                          // for _Rb_tree_iterator, map, etc
31
#include <utility>                      // for pair
31
#include <utility>                      // for pair
32
#include <vector>                       // for vector
32
#include <vector>                       // for vector
33
#include <unordered_set>
33
34
34
#include "description.hxx"              // for UPnPDeviceDesc, etc
35
#include "description.hxx"              // for UPnPDeviceDesc, etc
35
36
36
#include "libupnpp/log.hxx"             // for LOGDEB1, LOGERR, LOGDEB
37
#include "libupnpp/log.hxx"             // for LOGDEB1, LOGERR, LOGDEB
37
#include "libupnpp/ptmutex.hxx"         // for PTMutexLocker, PTMutexInit
38
#include "libupnpp/ptmutex.hxx"         // for PTMutexLocker, PTMutexInit
38
#include "libupnpp/upnpplib.hxx"        // for LibUPnP
39
#include "libupnpp/upnpplib.hxx"        // for LibUPnP
39
#include "libupnpp/upnpputils.hxx"      // for timespec_addnanos
40
#include "libupnpp/upnpputils.hxx"      // for timespec_addnanos
40
#include "libupnpp/workqueue.hxx"       // for WorkQueue
41
#include "libupnpp/workqueue.hxx"       // for WorkQueue
42
#include "libupnpp/control/httpdownload.hxx"
41
43
42
using namespace std;
44
using namespace std;
43
using namespace std::placeholders;
45
using namespace std::placeholders;
44
using namespace UPnPP;
46
using namespace UPnPP;
45
47
...
...
79
          expires(disco->Expires)
81
          expires(disco->Expires)
80
        {}
82
        {}
81
83
82
    bool alive;
84
    bool alive;
83
    string url;
85
    string url;
86
    string description;
84
    string deviceId;
87
    string deviceId;
85
    int expires; // Seconds valid
88
    int expires; // Seconds valid
86
};
89
};
87
90
88
// The workqueue on which callbacks from libupnp (cluCallBack()) queue
91
// The workqueue on which callbacks from libupnp (cluCallBack()) queue
89
// discovered object descriptors for processing by our dedicated
92
// discovered object descriptors for processing by our dedicated
90
// thread.
93
// thread.
91
static WorkQueue<DiscoveredTask*> discoveredQueue("DiscoveredQueue");
94
static WorkQueue<DiscoveredTask*> discoveredQueue("DiscoveredQueue");
95
static unordered_set<string> o_downloading;
96
static PTMutexInit o_downloading_mutex;
92
97
93
// This gets called in a libupnp thread context for all asynchronous
98
// This gets called in a libupnp thread context for all asynchronous
94
// events which we asked for.
99
// events which we asked for.
95
// Example: ContentDirectories appearing and disappearing from the network
100
// Example: ContentDirectories appearing and disappearing from the network
96
// We queue a task for our worker thread(s)
101
// We queue a task for our worker thread(s)
97
// It seems that this can get called by several threads. We have a
102
// We can get called by several threads.
98
// mutex just for clarifying the message printing, the workqueue is
99
// mt-safe of course.
100
static int cluCallBack(Upnp_EventType et, void* evp, void*)
103
static int cluCallBack(Upnp_EventType et, void* evp, void*)
101
{
104
{
102
    static PTMutexInit cblock;
103
    PTMutexLocker lock(cblock);
104
    LOGDEB1("discovery:cluCallBack: " << LibUPnP::evTypeAsString(et) << endl);
105
    LOGDEB1("discovery:cluCallBack: " << LibUPnP::evTypeAsString(et) << endl);
105
106
106
    switch (et) {
107
    switch (et) {
107
    case UPNP_DISCOVERY_SEARCH_RESULT:
108
    case UPNP_DISCOVERY_SEARCH_RESULT:
108
    case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
109
    case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
...
...
114
        // one message per device: the one which probably correspond to the 
115
        // one message per device: the one which probably correspond to the 
115
        // upnp "root device" message and has empty service and device types:
116
        // upnp "root device" message and has empty service and device types:
116
        if (!disco->DeviceType[0] && !disco->ServiceType[0]) {
117
        if (!disco->DeviceType[0] && !disco->ServiceType[0]) {
117
            LOGDEB1("discovery:cllb:ALIVE: " << cluDiscoveryToStr(disco) 
118
            LOGDEB1("discovery:cllb:ALIVE: " << cluDiscoveryToStr(disco) 
118
                   << endl);
119
                   << endl);
120
            // Device signals its existence and well-being. Perform the
121
            // UPnP "description" phase by downloading and decoding the
122
            // description document.
123
119
            DiscoveredTask *tp = new DiscoveredTask(1, disco);
124
            DiscoveredTask *tp = new DiscoveredTask(1, disco);
125
126
            {
127
                // Note that this does not prevent multiple successive
128
                // downloads of a normal url, just multiple
129
                // simultaneous downloads of a slow one, to avoid
130
                // tying up threads.
131
                PTMutexLocker lock(o_downloading_mutex);
132
                auto res = o_downloading.insert(tp->url);
133
                if (!res.second) {
134
                    LOGDEB("discoExplorer: already downloading " << 
135
                           tp->url << endl);
136
                    return UPNP_E_SUCCESS;
137
                }
138
            }
139
140
            LOGDEB("discoExplorer: downloading " << tp->url << endl);
141
            string sdesc;
142
            if (!downloadUrlWithCurl(tp->url, tp->description, 5)) {
143
                LOGERR("discoExplorer: downloadUrlWithCurl error for: " << 
144
                       tp->url << endl);
145
                {PTMutexLocker lock(o_downloading_mutex);
146
                    o_downloading.erase(tp->url);
147
                }
148
                delete tp;
149
                return UPNP_E_SUCCESS;
150
            }
151
            LOGDEB1("discoExplorer: downloaded description document of " <<
152
                    tp->description.size() << " bytes" << endl);
153
154
            {PTMutexLocker lock(o_downloading_mutex);
155
                o_downloading.erase(tp->url);
156
            }
157
120
            if (discoveredQueue.put(tp)) {
158
            if (discoveredQueue.put(tp)) {
121
                return UPNP_E_FINISH;
159
                return UPNP_E_FINISH;
122
            }
160
            }
123
        }
161
        }
124
        break;
162
        break;
...
...
213
                o_pool.m_devices.erase(it);
251
                o_pool.m_devices.erase(it);
214
                //LOGDEB("discoExplorer: delete " << tsk->deviceId.c_str() << 
252
                //LOGDEB("discoExplorer: delete " << tsk->deviceId.c_str() << 
215
                // endl);
253
                // endl);
216
            }
254
            }
217
        } else {
255
        } else {
218
            // Device signals its existence and well-being. Perform the
219
            // UPnP "description" phase by downloading and decoding the
220
            // description document.
221
            char *buf = 0;
222
            // LINE_SIZE is defined by libupnp's upnp.h...
223
            char contentType[LINE_SIZE];
224
            int code = UpnpDownloadUrlItem(tsk->url.c_str(), &buf, contentType);
225
            if (code != UPNP_E_SUCCESS) {
226
                LOGERR(LibUPnP::errAsString("discoExplorer:UpnpDownloadUrlItem", code) << 
227
                       " trying to fetch " << tsk->url << endl);
228
                delete tsk;
229
                continue;
230
            }
231
            string sdesc(buf);
232
            free(buf);
233
                        
234
            LOGDEB1("discoExplorer: downloaded description document of " <<
235
                    sdesc.size() << " bytes" << endl);
236
237
            // Update or insert the device
256
            // Update or insert the device
238
            DeviceDescriptor d(tsk->url, sdesc, time(0), tsk->expires);
257
            DeviceDescriptor d(tsk->url, tsk->description, time(0), tsk->expires);
239
            if (!d.device.ok) {
258
            if (!d.device.ok) {
240
                LOGERR("discoExplorer: description parse failed for " << 
259
                LOGERR("discoExplorer: description parse failed for " << 
241
                       tsk->deviceId << endl);
260
                       tsk->deviceId << endl);
242
                delete tsk;
261
                delete tsk;
243
                continue;
262
                continue;