Switch to unified view

a b/libupnpp/device.cxx
1
/* Copyright (C) 2014 J.F.Dockes
2
 *     This program is free software; you can redistribute it and/or modify
3
 *     it under the terms of the GNU General Public License as published by
4
 *     the Free Software Foundation; either version 2 of the License, or
5
 *     (at your option) any later version.
6
 *
7
 *     This program is distributed in the hope that it will be useful,
8
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 *     GNU General Public License for more details.
11
 *
12
 *     You should have received a copy of the GNU General Public License
13
 *     along with this program; if not, write to the
14
 *     Free Software Foundation, Inc.,
15
 *     59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16
 */
17
#include <iostream>
18
using namespace std;
19
20
#include "upnpplib.hxx"
21
#include "device.hxx"
22
23
unordered_map<std::string, UpnpDevice *> UpnpDevice::o_devices;
24
25
UpnpDevice::UpnpDevice(const string& deviceId)
26
    : m_deviceId(deviceId)
27
{
28
    cerr << "UpnpDevice::UpnpDevice(" << m_deviceId << ")" << endl;
29
30
    m_lib = LibUPnP::getLibUPnP(true);
31
    if (!m_lib) {
32
        cerr << " Can't get LibUPnP" << endl;
33
        return;
34
    }
35
    if (!m_lib->ok()) {
36
        cerr << "Lib init failed: " <<
37
            m_lib->errAsString("main", m_lib->getInitError()) << endl;
38
        m_lib = 0;
39
        return;
40
    }
41
42
    if (o_devices.empty()) {
43
        // First call: init callbacks
44
        m_lib->registerHandler(UPNP_CONTROL_ACTION_REQUEST, sCallBack, this);
45
  m_lib->registerHandler(UPNP_CONTROL_GET_VAR_REQUEST, sCallBack, this);
46
  m_lib->registerHandler(UPNP_EVENT_SUBSCRIPTION_REQUEST, sCallBack,this);
47
    }
48
49
    cerr << "UpnpDevice::UpnpDevice: adding myself[" << this << "] to dev table" << endl;
50
    o_devices[m_deviceId] = this;
51
}
52
53
int UpnpDevice::sCallBack(Upnp_EventType et, void* evp, void* tok)
54
{
55
    cerr << "UpnpDevice::sCallBack" << endl;
56
57
    string deviceid;
58
    switch (et) {
59
    case UPNP_CONTROL_ACTION_REQUEST:
60
        deviceid = ((struct Upnp_Action_Request *)evp)->DevUDN;
61
    break;
62
63
    case UPNP_CONTROL_GET_VAR_REQUEST:
64
        deviceid = ((struct Upnp_State_Var_Request *)evp)->DevUDN;
65
    break;
66
67
    case UPNP_EVENT_SUBSCRIPTION_REQUEST:
68
        deviceid = ((struct  Upnp_Subscription_Request*)evp)->UDN;
69
    break;
70
71
    default:
72
        cerr << "UpnpDevice::sCallBack: unknown event " << et << endl;
73
        return UPNP_E_INVALID_PARAM;
74
    }
75
    // cerr << "UpnpDevice::sCallBack: deviceid[" << deviceid << "]" << endl;
76
77
    unordered_map<std::string, UpnpDevice *> *devmap = 
78
        (unordered_map<std::string, UpnpDevice *> *) tok;
79
    unordered_map<std::string, UpnpDevice *>::iterator it =
80
        o_devices.find(deviceid);
81
82
    if (it == o_devices.end()) {
83
        cerr << "UpnpDevice::sCallBack: Device not found: [" << 
84
            deviceid << "]" << endl;
85
        return UPNP_E_INVALID_PARAM;
86
    }
87
    // cerr << "UpnpDevice::sCallBack: device found: [" << it->second 
88
    // << "]" << endl;
89
    return (it->second)->callBack(et, evp);
90
}
91
92
static PTMutexInit cblock;
93
int UpnpDevice::callBack(Upnp_EventType et, void* evp)
94
{
95
    PTMutexLocker lock(cblock);
96
    cerr << "UpnpDevice::callBack: evt type:" << 
97
        LibUPnP::evTypeAsString(et).c_str() << endl;
98
99
    switch (et) {
100
    case UPNP_CONTROL_ACTION_REQUEST:
101
    {
102
        struct Upnp_Action_Request *act = (struct Upnp_Action_Request *)evp;
103
        cerr << "UPNP_CONTROL_ACTION_REQUEST: " << act->ActionName <<
104
            " Params: " << ixmlPrintDocument(act->ActionRequest) << endl;
105
106
        unordered_map<string, string>::const_iterator servit = 
107
            m_serviceTypes.find(serviceKey(act->DevUDN,act->ServiceID));
108
        if (servit == m_serviceTypes.end()) {
109
            cerr << "Bad serviceID" << endl;
110
            return UPNP_E_INVALID_PARAM;
111
        }
112
        const string& servicetype = servit->second;
113
114
        unordered_map<string, soapfun>::iterator callit = 
115
            m_calls.find(act->ActionName);
116
        if (callit == m_calls.end()) {
117
            cerr << "No such action: " << act->ActionName << endl;
118
            return UPNP_E_INVALID_PARAM;
119
        }
120
121
        SoapArgs sc;
122
        if (!decodeSoapBody(act->ActionName, act->ActionRequest, &sc)) {
123
            cerr << "Error decoding Action call arguments" << endl;
124
            return UPNP_E_INVALID_PARAM;
125
        }
126
        SoapData dt;
127
        dt.name = act->ActionName;
128
        dt.serviceType = servicetype;
129
130
        // Call the action routine
131
        int ret = callit->second(sc, dt);
132
        if (ret != UPNP_E_SUCCESS) {
133
            cerr << "Action failed: " << sc.name << endl;
134
            return ret;
135
        }
136
137
        // Encode result data
138
        act->ActionResult = buildSoapBody(dt);
139
        cerr << "Response data: " << 
140
            ixmlPrintDocument(act->ActionResult) << endl;
141
142
        return ret;
143
144
    }
145
    break;
146
147
    case UPNP_CONTROL_GET_VAR_REQUEST:
148
        // Note that the "Control: query for variable" action is
149
        // deprecated (upnp arch v1), and we should never get these.
150
    {
151
        struct Upnp_State_Var_Request *act = 
152
            (struct Upnp_State_Var_Request *)evp;
153
        cerr << "UPNP_CONTROL_GET_VAR__REQUEST?: " << act->StateVarName << endl;
154
    }
155
    break;
156
157
    case UPNP_EVENT_SUBSCRIPTION_REQUEST:
158
    {
159
        struct Upnp_Subscription_Request *act = 
160
            (struct  Upnp_Subscription_Request*)evp;
161
        cerr << "UPNP_EVENT_SUBSCRIPTION_REQUEST: " << act->ServiceId << endl;
162
163
        vector<string> names;
164
        vector<string> values;
165
        if (!getEventData(names, values)) {
166
            break;
167
        }
168
        if (names.size() != values.size()) {
169
            break;
170
        }
171
172
        vector<const char *>cnames;
173
        cnames.reserve(names.size());
174
        for (unsigned int i = 0; i < names.size(); i++) {
175
            cnames.push_back(names[i].c_str());
176
        }
177
178
        vector<const char *>cvalues;
179
        cvalues.reserve(values.size());
180
        for (unsigned int i = 0; i < values.size(); i++) {
181
            cvalues.push_back(values[i].c_str());
182
        }
183
184
        int ret = 
185
            UpnpAcceptSubscription(m_lib->getdvh(), act->UDN, act->ServiceId,
186
                                   &cnames[0], &cvalues[0],
187
                                   int(cnames.size()), act->Sid);
188
        if (ret != UPNP_E_SUCCESS) {
189
            cerr << "UpnpDevice::callBack: UpnpAcceptSubscription failed: " 
190
                 << ret << endl;
191
        }
192
193
        return ret;
194
    }
195
    break;
196
197
    default:
198
        cerr << "UpnpDevice::callBack: unknown op" << endl;
199
        return UPNP_E_INVALID_PARAM;
200
    }
201
    return UPNP_E_INVALID_PARAM;
202
}
203
204
void UpnpDevice::addServiceType(const std::string& serviceId, 
205
                                const std::string& serviceType)
206
{
207
    cerr << "UpnpDevice::addServiceType: [" << 
208
        serviceKey(m_deviceId, serviceId) << "] -> [" << serviceType << endl;
209
    m_serviceTypes[serviceKey(m_deviceId, serviceId)] = serviceType;
210
}
211
212
void UpnpDevice::addActionMapping(const std::string& actName, soapfun fun)
213
{
214
    cerr << "UpnpDevice::addActionMapping:" << actName << endl;
215
    m_calls[actName] = fun;
216
}
217
218
void UpnpDevice::notifyEvent(const string& serviceId,
219
                             const vector<string>& names, 
220
                             const vector<string>& values)
221
{
222
    cerr << "UpnpDevice::notifyEvent" << endl;
223
    vector<const char *>cnames;
224
    cnames.reserve(names.size());
225
    for (unsigned int i = 0; i < names.size(); i++) {
226
        cnames.push_back(names[i].c_str());
227
    }
228
229
    vector<const char *>cvalues;
230
    cvalues.reserve(values.size());
231
    for (unsigned int i = 0; i < values.size(); i++) {
232
        cvalues.push_back(values[i].c_str());
233
    }
234
235
    int ret = UpnpNotify(m_lib->getdvh(), m_deviceId.c_str(), 
236
                         serviceId.c_str(),
237
                         &cnames[0], &cvalues[0],
238
                         int(cnames.size()));
239
    if (ret != UPNP_E_SUCCESS) {
240
        cerr << "UpnpDevice::notifyEvent: UpnpNotify failed: " << ret << endl;
241
    }
242
}