b381b9f7d597c33f1a1d88430cd89244e8a8484f
[platform/upstream/iotivity.git] / resource / src / OCResource.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include "OCResource.h"
22 #include "OCUtilities.h"
23
24 #include <boost/lexical_cast.hpp>
25 #include <sstream>
26 #ifdef HAVE_ARPA_INET_H
27 #include <arpa/inet.h>
28 #endif
29 #ifdef HAVE_WS2TCPIP_H
30 #include <ws2tcpip.h>
31 #endif
32 #ifdef HAVE_IN6ADDR_H
33 #include <in6addr.h>
34 #endif
35
36 namespace OC {
37
38 static const char COAP[] = "coap://";
39 static const char COAPS[] = "coaps://";
40 static const char COAP_TCP[] = "coap+tcp://";
41
42 using OC::nil_guard;
43 using OC::result_guard;
44 using OC::checked_guard;
45
46 OCResource::OCResource(std::weak_ptr<IClientWrapper> clientWrapper,
47                         const OCDevAddr& devAddr, const std::string& uri,
48                         const std::string& serverId, bool observable,
49                         const std::vector<std::string>& resourceTypes,
50                         const std::vector<std::string>& interfaces)
51  :  m_clientWrapper(clientWrapper), m_uri(uri),
52     m_resourceId(serverId, m_uri), m_devAddr(devAddr),
53     m_isObservable(observable), m_isCollection(false),
54     m_resourceTypes(resourceTypes), m_interfaces(interfaces),
55     m_observeHandle(nullptr)
56 {
57     m_isCollection = std::find(m_interfaces.begin(), m_interfaces.end(), LINK_INTERFACE)
58                         != m_interfaces.end();
59
60     if (m_uri.empty() ||
61         resourceTypes.empty() ||
62         interfaces.empty()||
63         m_clientWrapper.expired())
64     {
65         throw ResourceInitException(m_uri.empty(), resourceTypes.empty(),
66                 interfaces.empty(), m_clientWrapper.expired(), false, false);
67     }
68 }
69
70 OCResource::OCResource(std::weak_ptr<IClientWrapper> clientWrapper,
71                         const std::string& host, const std::string& uri,
72                         const std::string& serverId,
73                         OCConnectivityType connectivityType, bool observable,
74                         const std::vector<std::string>& resourceTypes,
75                         const std::vector<std::string>& interfaces)
76  :  m_clientWrapper(clientWrapper), m_uri(uri),
77     m_resourceId(serverId, m_uri),
78     m_isObservable(observable), m_isCollection(false),
79     m_resourceTypes(resourceTypes), m_interfaces(interfaces),
80     m_observeHandle(nullptr)
81 {
82     m_devAddr = OCDevAddr{OC_DEFAULT_ADAPTER, OC_DEFAULT_FLAGS, 0, {0}, 0,
83 #if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
84                           {0}
85 #endif
86                         };
87     m_isCollection = std::find(m_interfaces.begin(), m_interfaces.end(), LINK_INTERFACE)
88                         != m_interfaces.end();
89
90     if (m_uri.empty() ||
91         resourceTypes.empty() ||
92         interfaces.empty()||
93         m_clientWrapper.expired())
94     {
95         throw ResourceInitException(m_uri.empty(), resourceTypes.empty(),
96                 interfaces.empty(), m_clientWrapper.expired(), false, false);
97     }
98
99     if (uri.length() == 1 && uri[0] == '/')
100     {
101         throw ResourceInitException(m_uri.empty(), resourceTypes.empty(),
102                 interfaces.empty(), m_clientWrapper.expired(), false, false);
103     }
104
105     if (uri[0] != '/')
106     {
107         throw ResourceInitException(m_uri.empty(), resourceTypes.empty(),
108                 interfaces.empty(), m_clientWrapper.expired(), false, false);
109     }
110
111     // construct the devAddr from the pieces we have
112     m_devAddr.adapter = static_cast<OCTransportAdapter>(connectivityType >> CT_ADAPTER_SHIFT);
113     m_devAddr.flags = static_cast<OCTransportFlags>(connectivityType & CT_MASK_FLAGS);
114
115     this->setHost(host);
116 }
117
118 OCResource::~OCResource()
119 {
120 }
121
122 void OCResource::setHost(const std::string& host)
123 {
124     size_t prefix_len;
125
126     if(host.compare(0, sizeof(COAP) - 1, COAP) == 0)
127     {
128         prefix_len = sizeof(COAP) - 1;
129     }
130     else if(host.compare(0, sizeof(COAPS) - 1, COAPS) == 0)
131     {
132         prefix_len = sizeof(COAPS) - 1;
133         m_devAddr.flags = static_cast<OCTransportFlags>(m_devAddr.flags & OC_SECURE);
134     }
135     else if (host.compare(0, sizeof(COAP_TCP) - 1, COAP_TCP) == 0)
136     {
137         prefix_len = sizeof(COAP_TCP) - 1;
138     }
139     else
140     {
141         throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
142             m_interfaces.empty(), m_clientWrapper.expired(), false, false);
143     }
144
145     // remove 'coap://' or 'coaps://' or 'coap+tcp://'
146     std::string host_token = host.substr(prefix_len);
147
148     if(host_token[0] == '[') // IPv6
149     {
150         size_t bracket = host_token.find(']');
151
152         if(bracket == std::string::npos || bracket == 0)
153         {
154             throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
155                 m_interfaces.empty(), m_clientWrapper.expired(), false, false);
156         }
157         // extract the ipv6 address
158         std::string ip6Addr = host_token.substr(1, bracket - 1);
159
160         // address validity check
161         struct in6_addr buf;
162         const char *cAddr = ip6Addr.c_str();
163         if(0 == inet_pton(AF_INET6, cAddr, &buf))
164         {
165             throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
166                 m_interfaces.empty(), m_clientWrapper.expired(), false, false);
167         }
168
169         //skip ']' and ':' characters in host string
170         host_token = host_token.substr(bracket + 2);
171         int port = std::stoi(host_token);
172
173         if (0 > port || UINT16_MAX < port)
174         {
175             throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
176                 m_interfaces.empty(), m_clientWrapper.expired(), false, false);
177         }
178
179         ip6Addr.copy(m_devAddr.addr, sizeof(m_devAddr.addr));
180         m_devAddr.addr[ip6Addr.length()] = '\0';
181         m_devAddr.port = static_cast<uint16_t>(port);
182         m_devAddr.flags = static_cast<OCTransportFlags>(m_devAddr.flags & OC_IP_USE_V6);
183     }
184     else if (host_token[0] == ':')
185     {
186         throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
187             m_interfaces.empty(), m_clientWrapper.expired(), false, false);
188     }
189     else
190     {
191         size_t dot = host_token.find('.');
192         if (std::string::npos == dot) // MAC
193         {
194             std::string macAddr = host_token;
195
196             // address validity check
197             if (MAC_ADDR_STR_SIZE != macAddr.length())
198             {
199                 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
200                     m_interfaces.empty(), m_clientWrapper.expired(), false, false);
201             }
202
203             for (size_t blockCnt = 0; blockCnt < MAC_ADDR_BLOCKS; blockCnt++)
204             {
205                 std::string block = macAddr.substr(blockCnt * 3, 2);
206
207                 if (std::string::npos != block.find_first_not_of("0123456789ABCDEFabcdef"))
208                 {
209                     throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
210                         m_interfaces.empty(), m_clientWrapper.expired(), false, false);
211                 }
212
213                 if (MAC_ADDR_BLOCKS - 1 > blockCnt)
214                 {
215                     char delimiter = macAddr[blockCnt * 3 + 2];
216
217                     if (':' != delimiter)
218                     {
219                         throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
220                             m_interfaces.empty(), m_clientWrapper.expired(), false, false);
221                     }
222                 }
223             }
224
225             macAddr.copy(m_devAddr.addr, sizeof(m_devAddr.addr));
226             m_devAddr.addr[MAC_ADDR_STR_SIZE] = '\0';
227         }
228         else // IPv4
229         {
230             size_t colon = host_token.find(':');
231
232             if (colon == std::string::npos || colon == 0)
233             {
234                 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
235                     m_interfaces.empty(), m_clientWrapper.expired(), false, false);
236             }
237
238             // extract the ipv4 address
239             std::string ip4Addr = host_token.substr(0, colon);
240
241             // address validity check
242             struct in_addr buf;
243             const char *cAddr = ip4Addr.c_str();
244             if(0 == inet_pton(AF_INET, cAddr, &buf))
245             {
246                 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
247                     m_interfaces.empty(), m_clientWrapper.expired(), false, false);
248             }
249
250             //skip ':' characters in host string
251             host_token = host_token.substr(colon + 1);
252             int port = std::stoi(host_token);
253
254             if (0 > port || UINT16_MAX < port)
255             {
256                 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
257                     m_interfaces.empty(), m_clientWrapper.expired(), false, false);
258             }
259
260             ip4Addr.copy(m_devAddr.addr, sizeof(m_devAddr.addr));
261             m_devAddr.addr[ip4Addr.length()] = '\0';
262             m_devAddr.port = static_cast<uint16_t>(port);
263         }
264     }
265 }
266
267 OCStackResult OCResource::get(const QueryParamsMap& queryParametersMap,
268                               GetCallback attributeHandler, QualityOfService QoS)
269 {
270     return checked_guard(m_clientWrapper.lock(),
271                             &IClientWrapper::GetResourceRepresentation,
272                             m_devAddr, m_uri,
273                             queryParametersMap, m_headerOptions,
274                             attributeHandler, QoS);
275 }
276
277 OCStackResult OCResource::get(const QueryParamsMap& queryParametersMap,
278                               GetCallback attributeHandler)
279 {
280     QualityOfService defaultQos = OC::QualityOfService::NaQos;
281     checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQos);
282     return result_guard(get(queryParametersMap, attributeHandler, defaultQos));
283 }
284
285 OCStackResult OCResource::get(const std::string& resourceType,
286                      const std::string& resourceInterface, const QueryParamsMap& queryParametersMap,
287                      GetCallback attributeHandler)
288 {
289     QualityOfService defaultQoS = OC::QualityOfService::NaQos;
290     checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQoS);
291
292     return result_guard(get(resourceType, resourceInterface, queryParametersMap, attributeHandler, defaultQoS));
293 }
294
295 OCStackResult OCResource::get(const std::string& resourceType, const std::string& resourceInterface, const QueryParamsMap& queryParametersMap, GetCallback attributeHandler,
296         QualityOfService QoS)
297 {
298     QueryParamsMap mapCpy(queryParametersMap);
299
300     if(!resourceType.empty())
301     {
302         mapCpy[OC::Key::RESOURCETYPESKEY]=resourceType;
303     }
304
305     if(!resourceInterface.empty())
306     {
307         mapCpy[OC::Key::INTERFACESKEY]= resourceInterface;
308     }
309
310     return result_guard(get(mapCpy, attributeHandler, QoS));
311 }
312
313 OCStackResult OCResource::put(const OCRepresentation& rep,
314                               const QueryParamsMap& queryParametersMap, PutCallback attributeHandler,
315                               QualityOfService QoS)
316 {
317     return checked_guard(m_clientWrapper.lock(), &IClientWrapper::PutResourceRepresentation,
318                          m_devAddr, m_uri, rep, queryParametersMap,
319                          m_headerOptions, attributeHandler, QoS);
320 }
321
322 OCStackResult OCResource::put(const OCRepresentation& rep,
323                               const QueryParamsMap& queryParametersMap, PutCallback attributeHandler)
324 {
325     QualityOfService defaultQos = OC::QualityOfService::NaQos;
326     checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQos);
327     return result_guard(put(rep, queryParametersMap, attributeHandler, defaultQos));
328 }
329
330 OCStackResult OCResource::put(const std::string& resourceType,
331                               const std::string& resourceInterface, const OCRepresentation& rep,
332                               const QueryParamsMap& queryParametersMap,
333                               PutCallback attributeHandler)
334 {
335     QualityOfService defaultQos = OC::QualityOfService::NaQos;
336     checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQos);
337
338     return result_guard(put(resourceType, resourceInterface, rep, queryParametersMap,
339             attributeHandler, defaultQos));
340 }
341
342 OCStackResult OCResource::put(const std::string& resourceType,
343                               const std::string& resourceInterface, const OCRepresentation& rep,
344                               const QueryParamsMap& queryParametersMap,
345                               PutCallback attributeHandler,
346                               QualityOfService QoS)
347 {
348     QueryParamsMap mapCpy(queryParametersMap);
349
350     if(!resourceType.empty())
351     {
352         mapCpy[OC::Key::RESOURCETYPESKEY]=resourceType;
353     }
354
355     if(!resourceInterface.empty())
356     {
357         mapCpy[OC::Key::INTERFACESKEY]=resourceInterface;
358     }
359
360     return result_guard(put(rep, mapCpy, attributeHandler, QoS));
361 }
362
363 OCStackResult OCResource::post(const OCRepresentation& rep,
364                                const QueryParamsMap& queryParametersMap, PostCallback attributeHandler,
365                                QualityOfService QoS)
366 {
367     return checked_guard(m_clientWrapper.lock(), &IClientWrapper::PostResourceRepresentation,
368                          m_devAddr, m_uri, rep, queryParametersMap,
369                          m_headerOptions, attributeHandler, QoS);
370 }
371
372 OCStackResult OCResource::post(const OCRepresentation& rep,
373                               const QueryParamsMap& queryParametersMap, PutCallback attributeHandler)
374 {
375     QualityOfService defaultQos = OC::QualityOfService::NaQos;
376     checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQos);
377     return result_guard(post(rep, queryParametersMap, attributeHandler, defaultQos));
378 }
379
380 OCStackResult OCResource::post(const std::string& resourceType,
381                                const std::string& resourceInterface, const OCRepresentation& rep,
382                                const QueryParamsMap& queryParametersMap,
383                                PostCallback attributeHandler)
384 {
385     QualityOfService defaultQoS = OC::QualityOfService::NaQos;
386     checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQoS);
387
388     return result_guard(post(resourceType, resourceInterface, rep, queryParametersMap, attributeHandler,
389             defaultQoS));
390 }
391
392 OCStackResult OCResource::post(const std::string& resourceType,
393                                const std::string& resourceInterface, const OCRepresentation& rep,
394                                const QueryParamsMap& queryParametersMap,
395                                PostCallback attributeHandler,
396                                QualityOfService QoS)
397 {
398     QueryParamsMap mapCpy(queryParametersMap);
399
400     if(!resourceType.empty())
401     {
402         mapCpy[OC::Key::RESOURCETYPESKEY]=resourceType;
403     }
404
405     if(!resourceInterface.empty())
406     {
407         mapCpy[OC::Key::INTERFACESKEY]=resourceInterface;
408     }
409
410     return result_guard(post(rep, mapCpy, attributeHandler, QoS));
411 }
412
413 OCStackResult OCResource::deleteResource(DeleteCallback deleteHandler, QualityOfService QoS)
414 {
415     return checked_guard(m_clientWrapper.lock(), &IClientWrapper::DeleteResource,
416                          m_devAddr, m_uri, m_headerOptions, deleteHandler, QoS);
417 }
418
419 OCStackResult OCResource::deleteResource(DeleteCallback deleteHandler)
420 {
421     QualityOfService defaultQos = OC::QualityOfService::NaQos;
422     checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQos);
423
424     return result_guard(deleteResource(deleteHandler, defaultQos));
425 }
426
427 OCStackResult OCResource::observe(ObserveType observeType,
428         const QueryParamsMap& queryParametersMap, ObserveCallback observeHandler,
429         QualityOfService QoS)
430 {
431     if(m_observeHandle != nullptr)
432     {
433         return result_guard(OC_STACK_INVALID_PARAM);
434     }
435
436     return checked_guard(m_clientWrapper.lock(), &IClientWrapper::ObserveResource,
437                          observeType, &m_observeHandle, m_devAddr,
438                          m_uri, queryParametersMap, m_headerOptions,
439                          observeHandler, QoS);
440 }
441
442 OCStackResult OCResource::observe(ObserveType observeType,
443         const QueryParamsMap& queryParametersMap, ObserveCallback observeHandler)
444 {
445     QualityOfService defaultQoS = OC::QualityOfService::NaQos;
446     checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQoS);
447
448     return result_guard(observe(observeType, queryParametersMap, observeHandler, defaultQoS));
449 }
450
451 OCStackResult OCResource::cancelObserve()
452 {
453     QualityOfService defaultQoS = OC::QualityOfService::NaQos;
454     checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQoS);
455     return result_guard(cancelObserve(defaultQoS));
456 }
457
458 OCStackResult OCResource::cancelObserve(QualityOfService QoS)
459 {
460     if(m_observeHandle == nullptr)
461     {
462         return result_guard(OC_STACK_INVALID_PARAM);
463     }
464
465     OCStackResult result =  checked_guard(m_clientWrapper.lock(),
466             &IClientWrapper::CancelObserveResource,
467             m_observeHandle, (const char*)"", m_uri, m_headerOptions, QoS);
468
469     if(result == OC_STACK_OK)
470     {
471         m_observeHandle = nullptr;
472     }
473
474     return result;
475 }
476
477 void OCResource::setHeaderOptions(const HeaderOptions& headerOptions)
478 {
479     m_headerOptions = headerOptions;
480 }
481
482 void OCResource::unsetHeaderOptions()
483 {
484     m_headerOptions.clear();
485 }
486
487 std::string OCResource::host() const
488 {
489     std::ostringstream ss;
490     if (m_devAddr.flags & OC_SECURE)
491     {
492         ss << COAPS;
493     }
494     else if ((m_devAddr.adapter & OC_ADAPTER_TCP)
495             || (m_devAddr.adapter & OC_ADAPTER_GATT_BTLE)
496             || (m_devAddr.adapter & OC_ADAPTER_RFCOMM_BTEDR))
497     {
498         ss << COAP_TCP;
499     }
500     else
501     {
502         ss << COAP;
503     }
504     if (m_devAddr.flags & OC_IP_USE_V6)
505     {
506         ss << '[' << m_devAddr.addr << ']';
507     }
508     else
509     {
510         ss << m_devAddr.addr;
511     }
512     if (m_devAddr.port)
513     {
514         ss << ':' << m_devAddr.port;
515     }
516     return ss.str();
517 }
518
519 std::string OCResource::uri() const
520 {
521     return m_uri;
522 }
523
524 OCConnectivityType OCResource::connectivityType() const
525 {
526     return static_cast<OCConnectivityType>(
527            (m_devAddr.adapter << CT_ADAPTER_SHIFT) | (m_devAddr.flags & CT_MASK_FLAGS));
528 }
529
530 bool OCResource::isObservable() const
531 {
532     return m_isObservable;
533 }
534
535 std::vector<std::string> OCResource::getResourceTypes() const
536 {
537     return m_resourceTypes;
538 }
539
540 std::vector<std::string> OCResource::getResourceInterfaces(void) const
541 {
542     return m_interfaces;
543 }
544
545 OCResourceIdentifier OCResource::uniqueIdentifier() const
546 {
547     return m_resourceId;
548 }
549
550 std::string OCResource::sid() const
551 {
552     return this->uniqueIdentifier().m_representation;
553 }
554
555 bool OCResource::operator==(const OCResource &other) const
556 {
557     return m_resourceId == other.m_resourceId;
558 }
559
560 bool OCResource::operator!=(const OCResource &other) const
561 {
562     return m_resourceId != other.m_resourceId;
563 }
564
565 bool OCResource::operator<(const OCResource &other) const
566 {
567     return m_resourceId < other.m_resourceId;
568 }
569
570 bool OCResource::operator>(const OCResource &other) const
571 {
572     return m_resourceId > other.m_resourceId;
573 }
574
575 bool OCResource::operator<=(const OCResource &other) const
576 {
577     return m_resourceId <= other.m_resourceId;
578 }
579
580 bool OCResource::operator>=(const OCResource &other) const
581 {
582     return m_resourceId >= other.m_resourceId;
583 }
584
585 OCResourceIdentifier::OCResourceIdentifier(const std::string& wireServerIdentifier,
586         const std::string& resourceUri)
587     :m_representation(wireServerIdentifier), m_resourceUri(resourceUri)
588 {
589 }
590
591 std::ostream& operator <<(std::ostream& os, const OCResourceIdentifier& ri)
592 {
593     os << ri.m_representation<<ri.m_resourceUri;
594
595     return os;
596 }
597
598 bool OCResourceIdentifier::operator==(const OCResourceIdentifier &other) const
599 {
600     return m_representation == other.m_representation
601         && m_resourceUri == other.m_resourceUri;
602 }
603
604 bool OCResourceIdentifier::operator!=(const OCResourceIdentifier &other) const
605 {
606     return !(*this == other);
607 }
608
609 bool OCResourceIdentifier::operator<(const OCResourceIdentifier &other) const
610 {
611     return m_resourceUri < other.m_resourceUri
612         || (m_resourceUri == other.m_resourceUri &&
613                 m_representation < other.m_representation);
614 }
615
616 bool OCResourceIdentifier::operator>(const OCResourceIdentifier &other) const
617 {
618     return *this != other && !(*this<other);
619 }
620
621 bool OCResourceIdentifier::operator<=(const OCResourceIdentifier &other) const
622 {
623     return !(*this > other);
624 }
625
626 bool OCResourceIdentifier::operator>=(const OCResourceIdentifier &other) const
627 {
628     return !(*this < other);
629 }
630
631 } // namespace OC