--- a/libupnpp/control/service.cxx
+++ b/libupnpp/control/service.cxx
@@ -15,12 +15,19 @@
  *       59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 #include <string>
+#include <unordered_map>
+#include <functional>
 using namespace std;
+using namespace std::placeholders;
+
+#include <upnp/upnp.h>
 
 #include "libupnpp/log.hxx"
+#include "libupnpp/ptmutex.hxx"
 #include "libupnpp/upnpplib.hxx"
 #include "libupnpp/control/service.hxx"
 #include "libupnpp/control/cdirectory.hxx"
+#include "libupnpp/control/avlastchg.hxx"
 
 namespace UPnPClient {
 
@@ -78,7 +85,7 @@
                UpnpGetErrorMessage(ret) << endl);
         return ret;
     }
-    LOGDEB("Result xml: [" << ixmlPrintDocument(response) << "]" << endl);
+    LOGDEB("Service::runAction: Result xml: [" << ixmlPrintDocument(response) << "]" << endl);
 
     if (!decodeSoapBody(args.name.c_str(), response, &data)) {
         LOGERR("Service::runAction: Could not decode response: " <<
@@ -88,4 +95,118 @@
     return UPNP_E_SUCCESS;
 }
 
-}
+
+static PTMutexInit cblock;
+int Service::srvCB(Upnp_EventType et, void* vevp, void*)
+{
+    PTMutexLocker lock(cblock);
+
+    //LOGDEB("Service:srvCB: " << LibUPnP::evTypeAsString(et) << endl);
+
+    switch (et) {
+    case UPNP_EVENT_RENEWAL_COMPLETE:
+    case UPNP_EVENT_SUBSCRIBE_COMPLETE:
+    case UPNP_EVENT_UNSUBSCRIBE_COMPLETE:
+    case UPNP_EVENT_AUTORENEWAL_FAILED:
+    {
+        const char *ff = (const char *)vevp;
+        LOGDEB("Service:srvCB: subs event: " << ff << endl);
+        break;
+    }
+
+    case UPNP_EVENT_RECEIVED:
+    {
+        struct Upnp_Event *evp = (struct Upnp_Event *)vevp;
+        LOGDEB1("Service:srvCB: var change event: Sid: " <<
+               evp->Sid << " EventKey " << evp->EventKey << 
+               " changed: " << ixmlPrintDocument(evp->ChangedVariables)<< endl);
+
+        
+        unordered_map<string, string> props;
+        if (!decodePropertySet(evp->ChangedVariables, props)) {
+            LOGERR("Service::srvCB: could not decode EVENT propertyset" <<endl);
+            return UPNP_E_BAD_RESPONSE;
+        }
+        //for (auto& entry: props) {
+        //LOGDEB(entry.first << " -> " << entry.second << endl;);
+        //}
+        std::unordered_map<std::string, evtCBFunc>::iterator it = 
+            o_calls.find(evp->Sid);
+
+        if (it!= o_calls.end()) {
+            (it->second)(props);
+        } else {
+            LOGINF("Service::srvCB: no callback found for " << evp->Sid << 
+                   endl);
+        }
+        break;
+    }
+
+    default:
+        // Ignore other events for now
+        LOGDEB("Service:srvCB: unprocessed evt type: [" << 
+               LibUPnP::evTypeAsString(et) << "]"  << endl);
+        break;
+    }
+
+    return UPNP_E_SUCCESS;
+}
+
+bool Service::initEvents()
+{
+    LOGDEB("Service::initEvents" << endl);
+
+    PTMutexLocker lock(cblock);
+    static bool eventinit(false);
+    if (eventinit)
+        return true;
+    eventinit = true;
+
+    LibUPnP *lib = LibUPnP::getLibUPnP();
+    if (lib == 0) {
+        LOGERR("Service::initEvents: Can't get lib" << endl);
+        return false;
+    }
+    lib->registerHandler(UPNP_EVENT_RENEWAL_COMPLETE, srvCB, 0);
+    lib->registerHandler(UPNP_EVENT_SUBSCRIBE_COMPLETE, srvCB, 0);
+    lib->registerHandler(UPNP_EVENT_UNSUBSCRIBE_COMPLETE, srvCB, 0);
+    lib->registerHandler(UPNP_EVENT_AUTORENEWAL_FAILED, srvCB, 0);
+    lib->registerHandler(UPNP_EVENT_RECEIVED, srvCB, 0);
+    return true;
+}
+
+//void Service::evtCallback(
+//    const std::unordered_map<std::string, std::string>*)
+//{
+//    LOGDEB("Service::evtCallback!! service: " << m_serviceType << endl);
+//}
+
+bool Service::subscribe()
+{
+    //LOGDEB("Service::subscribe" << endl);
+    LibUPnP* lib = LibUPnP::getLibUPnP();
+    if (lib == 0) {
+        LOGINF("Service::runAction: no lib" << endl);
+        return UPNP_E_OUTOF_MEMORY;
+    }
+    int timeout = 1800;
+    int ret = UpnpSubscribe(lib->getclh(), m_eventURL.c_str(),
+                            &timeout, m_SID);
+    if (ret != UPNP_E_SUCCESS) {
+        LOGERR("Service:subscribe: failed: " << 
+               UpnpGetErrorMessage(ret) << endl);
+        return false;
+    } 
+    LOGDEB("Service::subscribe: sid: " << m_SID << endl);
+    return true;
+}
+
+void Service::registerCallback(evtCBFunc c)
+{
+    PTMutexLocker lock(cblock);
+    o_calls[m_SID] = c;
+}
+
+std::unordered_map<std::string, evtCBFunc> Service::o_calls;
+
+}