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