Switch to side-by-side view

--- a/libupnpp/discovery.cxx
+++ b/libupnpp/discovery.cxx
@@ -1,18 +1,18 @@
 /* Copyright (C) 2013 J.F.Dockes
- *	 This program is free software; you can redistribute it and/or modify
- *	 it under the terms of the GNU General Public License as published by
- *	 the Free Software Foundation; either version 2 of the License, or
- *	 (at your option) any later version.
+ *       This program is free software; you can redistribute it and/or modify
+ *       it under the terms of the GNU General Public License as published by
+ *       the Free Software Foundation; either version 2 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 General Public License for more details.
+ *       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 General Public License for more details.
  *
- *	 You should have received a copy of the GNU General Public License
- *	 along with this program; if not, write to the
- *	 Free Software Foundation, Inc.,
- *	 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *       You should have received a copy of the GNU General Public License
+ *       along with this program; if not, write to the
+ *       Free Software Foundation, Inc.,
+ *       59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 #include "config.h"
 
@@ -37,148 +37,152 @@
 #include "discovery.hxx"
 #include "log.hxx"
 
-// The service type string we are looking for.
+#undef LOCAL_LOGINC
+#define LOCAL_LOGINC 0
+
+// The service type string for Content Directories:
 static const string
 ContentDirectorySType("urn:schemas-upnp-org:service:ContentDirectory:1");
+
 // We don't include a version in comparisons, as we are satisfied with
 // version 1
 static bool isCDService(const string& st)
 {
-	const string::size_type sz(ContentDirectorySType.size()-2);
-	return !ContentDirectorySType.compare(0, sz, st, 0, sz);
-}
-
-// The type of device we're asking for in search
+    const string::size_type sz(ContentDirectorySType.size()-2);
+    return !ContentDirectorySType.compare(0, sz, st, 0, sz);
+}
+
+// The device type string for Media Servers
 static const string
 MediaServerDType("urn:schemas-upnp-org:device:MediaServer:1") ;
+
+#if 0
 static bool isMSDevice(const string& st)
 {
-	const string::size_type sz(MediaServerDType.size()-2);
-	return !MediaServerDType.compare(0, sz, st, 0, sz);
-}
-
-#if defined(HAVE_UPNPSETLOGLEVEL)
+    const string::size_type sz(MediaServerDType.size()-2);
+    return !MediaServerDType.compare(0, sz, st, 0, sz);
+}
+#endif
+
 static string cluDiscoveryToStr(const struct Upnp_Discovery *disco)
 {
-	stringstream ss;
-	ss << "ErrCode: " << disco->ErrCode << endl;
-	ss << "Expires: " << disco->Expires << endl;
-	ss << "DeviceId: " << disco->DeviceId << endl;
-	ss << "DeviceType: " << disco->DeviceType << endl;
-	ss << "ServiceType: " << disco->ServiceType << endl;
-	ss << "ServiceVer: " << disco->ServiceVer	 << endl;
-	ss << "Location: " << disco->Location << endl;
-	ss << "Os: " << disco->Os << endl;
-	ss << "Date: " << disco->Date << endl;
-	ss << "Ext: " << disco->Ext << endl;
-
-	/** The host address of the device responding to the search. */
-	// struct sockaddr_storage DestAddr;
-	return ss.str();
-}
-#endif // DEBUG_DISCOVERY
+    stringstream ss;
+    ss << "ErrCode: " << disco->ErrCode << endl;
+    ss << "Expires: " << disco->Expires << endl;
+    ss << "DeviceId: " << disco->DeviceId << endl;
+    ss << "DeviceType: " << disco->DeviceType << endl;
+    ss << "ServiceType: " << disco->ServiceType << endl;
+    ss << "ServiceVer: " << disco->ServiceVer    << endl;
+    ss << "Location: " << disco->Location << endl;
+    ss << "Os: " << disco->Os << endl;
+    ss << "Date: " << disco->Date << endl;
+    ss << "Ext: " << disco->Ext << endl;
+
+    /** The host address of the device responding to the search. */
+    // struct sockaddr_storage DestAddr;
+    return ss.str();
+}
 
 // Each appropriate discovery event (executing in a libupnp thread
 // context) queues the following task object for processing by the
 // discovery thread.
 class DiscoveredTask {
 public:
-	DiscoveredTask(bool _alive, const struct Upnp_Discovery *disco)
-		: alive(_alive), url(disco->Location), deviceId(disco->DeviceId),
-		  expires(disco->Expires)
-		{}
-
-	bool alive;
-	string url;
-	string deviceId;
-	int expires; // Seconds valid
+    DiscoveredTask(bool _alive, const struct Upnp_Discovery *disco)
+        : alive(_alive), url(disco->Location), deviceId(disco->DeviceId),
+          expires(disco->Expires)
+        {}
+
+    bool alive;
+    string url;
+    string deviceId;
+    int expires; // Seconds valid
 };
 static WorkQueue<DiscoveredTask*> discoveredQueue("DiscoveredQueue");
 
 // Descriptor for one device having a Content Directory service found
 // on the network.
-class ContentDirectoryDescriptor {
+class DeviceDescriptor {
 public:
-	ContentDirectoryDescriptor(const string& url, const string& description,
-							   time_t last, int exp)
-		: device(url, description), last_seen(last), expires(exp+20)
-		{}
-	ContentDirectoryDescriptor()
-		{}
-	UPnPDevice device;
-	time_t last_seen;
-	int expires; // seconds valid
+    DeviceDescriptor(const string& url, const string& description,
+                     time_t last, int exp)
+        : device(url, description), last_seen(last), expires(exp+20)
+        {}
+    DeviceDescriptor()
+        {}
+    UPnPDeviceDesc device;
+    time_t last_seen;
+    int expires; // seconds valid
 };
 
-// A ContentDirectoryPool holds the characteristics of the servers
+// A DevicePool holds the characteristics of the devices
 // currently on the network.
 // The map is referenced by deviceId (==UDN)
 // The class is instanciated as a static (unenforced) singleton.
-class ContentDirectoryPool {
+class DevicePool {
 public:
-	PTMutexInit m_mutex;
-	map<string, ContentDirectoryDescriptor> m_directories;
+    PTMutexInit m_mutex;
+    map<string, DeviceDescriptor> m_devices;
 };
-static ContentDirectoryPool contentDirectories;
-typedef map<string, ContentDirectoryDescriptor>::iterator DirPoolIt;
+static DevicePool o_pool;
+typedef map<string, DeviceDescriptor>::iterator DevPoolIt;
 
 // Worker routine for the discovery queue. Get messages about devices
 // appearing and disappearing, and update the directory pool
 // accordingly.
 static void *discoExplorer(void *)
 {
-	for (;;) {
-		DiscoveredTask *tsk = 0;
-		size_t qsz;
-		if (!discoveredQueue.take(&tsk, &qsz)) {
-			discoveredQueue.workerExit();
-			return (void*)1;
-		}
-		PLOGDEB("discoExplorer: alive %d deviceId [%s] URL [%s]\n",
-				tsk->alive, tsk->deviceId.c_str(), tsk->url.c_str());
-		if (!tsk->alive) {
-			// Device signals it is going off.
-			PTMutexLocker lock(contentDirectories.m_mutex);
-			DirPoolIt it = contentDirectories.m_directories.find(tsk->deviceId);
-			if (it != contentDirectories.m_directories.end()) {
-				contentDirectories.m_directories.erase(it);
-				//LOGDEB("discoExplorer: delete " << tsk->deviceId.c_str() << 
-				// endl);
-			}
-		} else {
-			// Device signals its existence and well-being. Perform the
-			// UPnP "description" phase by downloading and decoding the
-			// description document.
-			char *buf = 0;
-			// LINE_SIZE is defined by libupnp's upnp.h...
-			char contentType[LINE_SIZE];
-			int code = UpnpDownloadUrlItem(tsk->url.c_str(), &buf, contentType);
-			if (code != UPNP_E_SUCCESS) {
-				LOGERR(LibUPnP::errAsString("discoExplorer", code) << endl);
-				continue;
-			}
-			string sdesc(buf);
-			free(buf);
-			
-			//LOGDEB("discoExplorer: downloaded description document of " <<
-			//   sdesc.size() << " bytes" << endl);
-
-			// Update or insert the device
-			ContentDirectoryDescriptor d(tsk->url, sdesc,
-										 time(0), tsk->expires);
-			if (!d.device.ok) {
-				LOGERR("discoExplorer: description parse failed for " << 
-					   tsk->deviceId << endl);
-				delete tsk;
-				continue;
-			}
-			PTMutexLocker lock(contentDirectories.m_mutex);
-			//LOGDEB("discoExplorer: inserting id "<< tsk->deviceId.c_str() << 
-			//   endl);
-			contentDirectories.m_directories[tsk->deviceId] = d;
-		}
-		delete tsk;
-	}
+    for (;;) {
+        DiscoveredTask *tsk = 0;
+        size_t qsz;
+        if (!discoveredQueue.take(&tsk, &qsz)) {
+            discoveredQueue.workerExit();
+            return (void*)1;
+        }
+        PLOGDEB("discoExplorer: alive %d deviceId [%s] URL [%s]\n",
+                tsk->alive, tsk->deviceId.c_str(), tsk->url.c_str());
+        if (!tsk->alive) {
+            // Device signals it is going off.
+            PTMutexLocker lock(o_pool.m_mutex);
+            DevPoolIt it = o_pool.m_devices.find(tsk->deviceId);
+            if (it != o_pool.m_devices.end()) {
+                o_pool.m_devices.erase(it);
+                //LOGDEB("discoExplorer: delete " << tsk->deviceId.c_str() << 
+                // endl);
+            }
+        } else {
+            // Device signals its existence and well-being. Perform the
+            // UPnP "description" phase by downloading and decoding the
+            // description document.
+            char *buf = 0;
+            // LINE_SIZE is defined by libupnp's upnp.h...
+            char contentType[LINE_SIZE];
+            int code = UpnpDownloadUrlItem(tsk->url.c_str(), &buf, contentType);
+            if (code != UPNP_E_SUCCESS) {
+                LOGERR(LibUPnP::errAsString("discoExplorer", code) << endl);
+                continue;
+            }
+            string sdesc(buf);
+            free(buf);
+                        
+            //LOGDEB("discoExplorer: downloaded description document of " <<
+            //   sdesc.size() << " bytes" << endl);
+
+            // Update or insert the device
+            DeviceDescriptor d(tsk->url, sdesc, time(0), tsk->expires);
+            if (!d.device.ok) {
+                LOGERR("discoExplorer: description parse failed for " << 
+                       tsk->deviceId << endl);
+                delete tsk;
+                continue;
+            }
+            PTMutexLocker lock(o_pool.m_mutex);
+            //LOGDEB("discoExplorer: inserting device id "<< tsk->deviceId << 
+            //       " description: " << endl << d.device.dump() << endl);
+            o_pool.m_devices[tsk->deviceId] = d;
+        }
+        delete tsk;
+    }
 }
 
 // This gets called in a libupnp thread context for all asynchronous
@@ -191,65 +195,63 @@
 static PTMutexInit cblock;
 static int cluCallBack(Upnp_EventType et, void* evp, void*)
 {
-	PTMutexLocker lock(cblock);
-	PLOGDEB("cluCallBack: evt type: [%s]\n",
-			LibUPnP::evTypeAsString(et).c_str());
-
-	switch (et) {
-	case UPNP_DISCOVERY_SEARCH_RESULT:
-	case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
-	{
-		struct Upnp_Discovery *disco = (struct Upnp_Discovery *)evp;
-		if (isMSDevice(disco->DeviceType) || isCDService(disco->ServiceType)) {
-			PLOGDEB("ALIVE : %s\n", cluDiscoveryToStr(disco).c_str());
-			DiscoveredTask *tp = new DiscoveredTask(1, disco);
-			if (discoveredQueue.put(tp)) {
-				return UPNP_E_FINISH;
-			}
-		}
-		break;
-	}
-	case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
-	{
-		struct Upnp_Discovery *disco = (struct Upnp_Discovery *)evp;
-
-		PLOGDEB("BYEBYE: %s\n", cluDiscoveryToStr(disco).c_str());
-		DiscoveredTask *tp = new DiscoveredTask(0, disco);
-		if (discoveredQueue.put(tp)) {
-			return UPNP_E_FINISH;
-		}
-		break;
-	}
-	default:
-		// Ignore other events for now
-		break;
-	}
-
-	return UPNP_E_SUCCESS;
+    PTMutexLocker lock(cblock);
+    //LOGDEB("discovery:cluCallBack: " << LibUPnP::evTypeAsString(et) << endl);
+
+    switch (et) {
+    case UPNP_DISCOVERY_SEARCH_RESULT:
+    case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
+    {
+        struct Upnp_Discovery *disco = (struct Upnp_Discovery *)evp;
+        //LOGDEB("discovery:cllb:ALIVE: " << cluDiscoveryToStr(disco) << endl);
+        DiscoveredTask *tp = new DiscoveredTask(1, disco);
+        if (discoveredQueue.put(tp)) {
+            return UPNP_E_FINISH;
+        }
+        break;
+    }
+    case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
+    {
+        struct Upnp_Discovery *disco = (struct Upnp_Discovery *)evp;
+        //LOGDEB("discovery:cllB:BYEBYE: " << cluDiscoveryToStr(disco) << endl);
+        DiscoveredTask *tp = new DiscoveredTask(0, disco);
+        if (discoveredQueue.put(tp)) {
+            return UPNP_E_FINISH;
+        }
+        break;
+    }
+    default:
+        // Ignore other events for now
+        LOGDEB("discovery:cluCallBack: unprocessed evt type: [" << 
+               LibUPnP::evTypeAsString(et) << "]"  << endl);
+        break;
+    }
+
+    return UPNP_E_SUCCESS;
 }
 
 // Look at the devices and get rid of those which have not been seen
 // for too long. We do this when listing the top directory
 void UPnPDeviceDirectory::expireDevices()
 {
-	PLOGDEB("expireDevices:\n");
-	PTMutexLocker lock(contentDirectories.m_mutex);
-	time_t now = time(0);
-	bool didsomething = false;
-
-	for (DirPoolIt it = contentDirectories.m_directories.begin();
-		 it != contentDirectories.m_directories.end();) {
-		if (now - it->second.last_seen > it->second.expires) {
-			//LOGDEB("expireDevices: deleting " <<  it->first.c_str() << " " << 
-			//   it->second.device.friendlyName.c_str() << endl);
-			contentDirectories.m_directories.erase(it++);
-			didsomething = true;
-		} else {
-			it++;
-		}
-	}
-	if (didsomething)
-		search();
+    LOGDEB1("discovery: expireDevices:" << endl);
+    PTMutexLocker lock(o_pool.m_mutex);
+    time_t now = time(0);
+    bool didsomething = false;
+
+    for (DevPoolIt it = o_pool.m_devices.begin();
+         it != o_pool.m_devices.end();) {
+        if (now - it->second.last_seen > it->second.expires) {
+            //LOGDEB("expireDevices: deleting " <<  it->first.c_str() << " " << 
+            //   it->second.device.friendlyName.c_str() << endl);
+            o_pool.m_devices.erase(it++);
+            didsomething = true;
+        } else {
+            it++;
+        }
+    }
+    if (didsomething)
+        search();
 }
 
 // m_searchTimeout is the UPnP device search timeout, which should
@@ -258,130 +260,124 @@
 // This means that you have to wait for the specified period before
 // the results are complete.
 UPnPDeviceDirectory::UPnPDeviceDirectory(time_t search_window)
-	: m_ok(false), m_searchTimeout(search_window), m_lastSearch(0)
-{
-	if (!discoveredQueue.start(1, discoExplorer, 0)) {
-		m_reason = "Discover work queue start failed";
-		return;
-	}
-	LibUPnP *lib = LibUPnP::getLibUPnP();
-	if (lib == 0) {
-		m_reason = "Can't get lib";
-		return;
-	}
-	lib->registerHandler(UPNP_DISCOVERY_SEARCH_RESULT, cluCallBack, this);
-	lib->registerHandler(UPNP_DISCOVERY_ADVERTISEMENT_ALIVE,
-						 cluCallBack, this);
-	lib->registerHandler(UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE,
-						 cluCallBack, this);
-
-	m_ok = search();
+    : m_ok(false), m_searchTimeout(search_window), m_lastSearch(0)
+{
+    if (!discoveredQueue.start(1, discoExplorer, 0)) {
+        m_reason = "Discover work queue start failed";
+        return;
+    }
+    LibUPnP *lib = LibUPnP::getLibUPnP();
+    if (lib == 0) {
+        m_reason = "Can't get lib";
+        return;
+    }
+    lib->registerHandler(UPNP_DISCOVERY_SEARCH_RESULT, cluCallBack, this);
+    lib->registerHandler(UPNP_DISCOVERY_ADVERTISEMENT_ALIVE,
+                         cluCallBack, this);
+    lib->registerHandler(UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE,
+                         cluCallBack, this);
+
+    m_ok = search();
 }
 
 bool UPnPDeviceDirectory::search()
 {
-	PLOGDEB("UPnPDeviceDirectory::search\n");
-	if (time(0) - m_lastSearch < 10)
-		return true;
-
-	LibUPnP *lib = LibUPnP::getLibUPnP();
-	if (lib == 0) {
-		m_reason = "Can't get lib";
-		return false;
-	}
-
-	// We search both for device and service just in case.
-	int code1 = UpnpSearchAsync(lib->getclh(), m_searchTimeout,
-								ContentDirectorySType.c_str(), lib);
-	if (code1 != UPNP_E_SUCCESS) {
-		m_reason = LibUPnP::errAsString("UpnpSearchAsync", code1);
-	}
-	int code2 = UpnpSearchAsync(lib->getclh(), m_searchTimeout,
-								MediaServerDType.c_str(), lib);
-	if (code2 != UPNP_E_SUCCESS) {
-		m_reason = LibUPnP::errAsString("UpnpSearchAsync", code2);
-	}
-	if (code1 != UPNP_E_SUCCESS && code2 != UPNP_E_SUCCESS)
-		return false;
-	m_lastSearch = time(0);
-	return true;
+    PLOGDEB("UPnPDeviceDirectory::search\n");
+    if (time(0) - m_lastSearch < 10)
+        return true;
+
+    LibUPnP *lib = LibUPnP::getLibUPnP();
+    if (lib == 0) {
+        m_reason = "Can't get lib";
+        return false;
+    }
+
+    // We search both for device and service just in case.
+    int code1 = UpnpSearchAsync(lib->getclh(), m_searchTimeout,
+                                ContentDirectorySType.c_str(), lib);
+    if (code1 != UPNP_E_SUCCESS) {
+        m_reason = LibUPnP::errAsString("UpnpSearchAsync", code1);
+    }
+    int code2 = UpnpSearchAsync(lib->getclh(), m_searchTimeout,
+                                MediaServerDType.c_str(), lib);
+    if (code2 != UPNP_E_SUCCESS) {
+        m_reason = LibUPnP::errAsString("UpnpSearchAsync", code2);
+    }
+    if (code1 != UPNP_E_SUCCESS && code2 != UPNP_E_SUCCESS)
+        return false;
+    m_lastSearch = time(0);
+    return true;
 }
 
 static UPnPDeviceDirectory *theDevDir;
 UPnPDeviceDirectory *UPnPDeviceDirectory::getTheDir(time_t search_window)
 {
-	if (theDevDir == 0)
-		theDevDir = new UPnPDeviceDirectory(search_window);
-	if (theDevDir && !theDevDir->ok())
-		return 0;
-	return theDevDir;
+    if (theDevDir == 0)
+        theDevDir = new UPnPDeviceDirectory(search_window);
+    if (theDevDir && !theDevDir->ok())
+        return 0;
+    return theDevDir;
 }
 
 void UPnPDeviceDirectory::terminate()
 {
-	discoveredQueue.setTerminateAndWait();
+    discoveredQueue.setTerminateAndWait();
 }
 
 time_t UPnPDeviceDirectory::getRemainingDelay()
 {
-	time_t now = time(0);
-	if (now - m_lastSearch >= m_searchTimeout)
-		return 0;
-	return  m_searchTimeout - (now - m_lastSearch);
+    time_t now = time(0);
+    if (now - m_lastSearch >= m_searchTimeout)
+        return 0;
+    return  m_searchTimeout - (now - m_lastSearch);
 }
 
 bool UPnPDeviceDirectory::getDirServices(vector<ContentDirectoryService>& out)
 {
-	//LOGDEB("UPnPDeviceDirectory::getDirServices" << endl);
-	if (m_ok == false)
-		return false;
-
-	if (getRemainingDelay() > 0)
-		sleep(getRemainingDelay());
-
-	// Has locking, do it before our own lock
-	expireDevices();
-
-	PTMutexLocker lock(contentDirectories.m_mutex);
-
-	for (DirPoolIt dit = contentDirectories.m_directories.begin();
-		 dit != contentDirectories.m_directories.end(); dit++) {
-		for (DevServIt sit = dit->second.device.services.begin();
-			 sit != dit->second.device.services.end(); sit++) {
-			if (isCDService(sit->serviceType)) {
-				out.push_back(ContentDirectoryService(dit->second.device,
-													  *sit));
-			}
-		}
-	}
-
-	return true;
+    //LOGDEB("UPnPDeviceDirectory::getDirServices" << endl);
+    if (m_ok == false)
+        return false;
+
+    if (getRemainingDelay() > 0)
+        sleep(getRemainingDelay());
+
+    // Has locking, do it before our own lock
+    expireDevices();
+
+    PTMutexLocker lock(o_pool.m_mutex);
+
+    for (DevPoolIt dit = o_pool.m_devices.begin();
+         dit != o_pool.m_devices.end(); dit++) {
+        for (DevServIt sit = dit->second.device.services.begin();
+             sit != dit->second.device.services.end(); sit++) {
+            if (isCDService(sit->serviceType)) {
+                out.push_back(ContentDirectoryService(dit->second.device,
+                                                      *sit));
+            }
+        }
+    }
+
+    return true;
 }
 
 // Get server by friendly name. It's a bit wasteful to copy all
 // servers for this, we could directly walk the list. Otoh there isn't
 // going to be millions...
 bool UPnPDeviceDirectory::getServer(const string& friendlyName,
-									ContentDirectoryService& server)
-{
-	vector<ContentDirectoryService> ds;
-	if (!getDirServices(ds)) {
-		PLOGDEB("UPnPDeviceDirectory::getServer: no servers?\n");
-		return false;
-	}
-	for (vector<ContentDirectoryService>::const_iterator it = ds.begin();
-		 it != ds.end(); it++) {
-		if (!friendlyName.compare(it->getFriendlyName())) {
-			server = *it;
-			return true;
-		}
-	}
-	return false;
-}
-
-/* Local Variables: */
-/* mode: c++ */
-/* c-basic-offset: 4 */
-/* tab-width: 4 */
-/* indent-tabs-mode: t */
-/* End: */
+                                    ContentDirectoryService& server)
+{
+    vector<ContentDirectoryService> ds;
+    if (!getDirServices(ds)) {
+        PLOGDEB("UPnPDeviceDirectory::getServer: no servers?\n");
+        return false;
+    }
+    for (vector<ContentDirectoryService>::const_iterator it = ds.begin();
+         it != ds.end(); it++) {
+        if (!friendlyName.compare(it->getFriendlyName())) {
+            server = *it;
+            return true;
+        }
+    }
+    return false;
+}
+