1 //******************************************************************
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21 #include "OCResource.h"
22 #include "OCUtilities.h"
24 #include <boost/lexical_cast.hpp>
29 static const char COAP[] = "coap://";
30 static const char COAPS[] = "coaps://";
31 static const char COAP_TCP[] = "coap+tcp://";
34 using OC::result_guard;
35 using OC::checked_guard;
37 OCResource::OCResource(std::weak_ptr<IClientWrapper> clientWrapper,
38 const OCDevAddr& devAddr, const std::string& uri,
39 const std::string& serverId, bool observable,
40 const std::vector<std::string>& resourceTypes,
41 const std::vector<std::string>& interfaces)
42 : m_clientWrapper(clientWrapper), m_uri(uri),
43 m_resourceId(serverId, m_uri), m_devAddr(devAddr),
44 m_isObservable(observable), m_isCollection(false),
45 m_resourceTypes(resourceTypes), m_interfaces(interfaces),
46 m_observeHandle(nullptr)
48 m_isCollection = std::find(m_interfaces.begin(), m_interfaces.end(), LINK_INTERFACE)
49 != m_interfaces.end();
52 resourceTypes.empty() ||
54 m_clientWrapper.expired())
56 throw ResourceInitException(m_uri.empty(), resourceTypes.empty(),
57 interfaces.empty(), m_clientWrapper.expired(), false, false);
61 OCResource::OCResource(std::weak_ptr<IClientWrapper> clientWrapper,
62 const std::string& host, const std::string& uri,
63 const std::string& serverId,
64 OCConnectivityType connectivityType, bool observable,
65 const std::vector<std::string>& resourceTypes,
66 const std::vector<std::string>& interfaces)
67 : m_clientWrapper(clientWrapper), m_uri(uri),
68 m_resourceId(serverId, m_uri),
69 m_devAddr{ OC_DEFAULT_ADAPTER, OC_DEFAULT_FLAGS, 0, {0}, 0
70 #if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
74 m_isObservable(observable), m_isCollection(false),
75 m_resourceTypes(resourceTypes), m_interfaces(interfaces),
76 m_observeHandle(nullptr)
78 m_isCollection = std::find(m_interfaces.begin(), m_interfaces.end(), LINK_INTERFACE)
79 != m_interfaces.end();
82 resourceTypes.empty() ||
84 m_clientWrapper.expired())
86 throw ResourceInitException(m_uri.empty(), resourceTypes.empty(),
87 interfaces.empty(), m_clientWrapper.expired(), false, false);
90 if (uri.length() == 1 && uri[0] == '/')
92 throw ResourceInitException(m_uri.empty(), resourceTypes.empty(),
93 interfaces.empty(), m_clientWrapper.expired(), false, false);
98 throw ResourceInitException(m_uri.empty(), resourceTypes.empty(),
99 interfaces.empty(), m_clientWrapper.expired(), false, false);
102 // construct the devAddr from the pieces we have
103 m_devAddr.adapter = static_cast<OCTransportAdapter>(connectivityType >> CT_ADAPTER_SHIFT);
104 m_devAddr.flags = static_cast<OCTransportFlags>(connectivityType & CT_MASK_FLAGS);
109 OCResource::~OCResource()
113 void OCResource::setHost(const std::string& host)
117 if(host.compare(0, sizeof(COAP) - 1, COAP) == 0)
119 prefix_len = sizeof(COAP) - 1;
121 else if(host.compare(0, sizeof(COAPS) - 1, COAPS) == 0)
123 prefix_len = sizeof(COAPS) - 1;
124 m_devAddr.flags = static_cast<OCTransportFlags>(m_devAddr.flags & OC_SECURE);
126 else if (host.compare(0, sizeof(COAP_TCP) - 1, COAP_TCP) == 0)
128 prefix_len = sizeof(COAP_TCP) - 1;
129 m_devAddr.adapter = static_cast<OCTransportAdapter>(m_devAddr.adapter & OC_ADAPTER_TCP);
133 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
134 m_interfaces.empty(), m_clientWrapper.expired(), false, false);
137 // removed 'coap://' or 'coaps://' or 'coap+tcp://'
138 std::string host_token = host.substr(prefix_len);
140 if (host_token[0] == '[') // ipv6 address
142 m_devAddr.flags = static_cast< OCTransportFlags >(m_devAddr.flags & OC_IP_USE_V6);
144 size_t found = host_token.find(']');
146 if (found == std::string::npos || found == 0)
148 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
149 m_interfaces.empty(), m_clientWrapper.expired(), false,
152 // extract the ipv6 address
153 std::string ip6Addr = host_token.substr(1, found - 1);
155 size_t addrLength = ip6Addr.length();
157 if (MAX_ADDR_STR_SIZE <= addrLength)
159 throw std::length_error("host address is too long.");
162 // address validity check
163 size_t colon = ip6Addr.find(':');
165 if (std::string::npos == colon)
167 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
168 m_interfaces.empty(), m_clientWrapper.expired(), false,
173 int omittedColon = -2;
175 while (std::string::npos != colon)
177 size_t nextColon = ip6Addr.find(':', colon + 1);
179 if (nextColon == colon + 1)
181 if (0 < omittedColon)
183 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
184 m_interfaces.empty(), m_clientWrapper.expired(), false,
187 omittedColon = colon;
194 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
195 m_interfaces.empty(), m_clientWrapper.expired(), false,
200 if (7 >= colonCnt && 0 > omittedColon)
202 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
203 m_interfaces.empty(), m_clientWrapper.expired(), false,
207 size_t startPoint = 0;
209 if (0 == omittedColon)
217 colon = ip6Addr.find(':', startPoint);
219 if (std::string::npos != colon)
221 block = ip6Addr.substr(startPoint, colon - startPoint);
223 if (4 < block.length() ||
224 std::string::npos != block.find_first_not_of("0123456789ABCDEFabcdef") ||
227 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
228 m_interfaces.empty(), m_clientWrapper.expired(), false,
232 startPoint = colon + 1;
236 block = ip6Addr.substr(startPoint);
238 if (4 < block.length() ||
239 std::string::npos != block.find_first_not_of("0123456789ABCDEFabcdef") ||
242 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
243 m_interfaces.empty(), m_clientWrapper.expired(), false,
250 if ((int)colon == omittedColon)
252 if (colon == addrLength - 2)
256 startPoint = colon + 2;
261 // end of address validity check
263 ip6Addr.copy(m_devAddr.addr, sizeof(m_devAddr.addr));
264 m_devAddr.addr[ip6Addr.length()] = '\0';
265 //skip ']' and ':' characters in host string
266 host_token = host_token.substr(found + 2);
268 int port = std::stoi(host_token);
270 if (0 > port || UINT16_MAX < port)
272 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
273 m_interfaces.empty(), m_clientWrapper.expired(), false,
277 m_devAddr.port = static_cast< uint16_t >(port);
279 else if (host_token[0] == ':')
281 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
282 m_interfaces.empty(), m_clientWrapper.expired(), false,
287 size_t dot = host_token.find('.');
288 if (dot == std::string::npos) // MAC address
290 std::string macAddr = host_token;
292 // address validity check
293 if (MAC_ADDR_STR_SIZE != macAddr.length())
295 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
296 m_interfaces.empty(), m_clientWrapper.expired(), false,
300 for (size_t blockCnt = 0; blockCnt < 6; blockCnt++)
302 std::string block = macAddr.substr(blockCnt * 3, 2);
304 if (std::string::npos != block.find_first_not_of("0123456789ABCDEFabcdef"))
306 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
307 m_interfaces.empty(), m_clientWrapper.expired(), false,
313 char delimiter = macAddr[blockCnt * 3 + 2];
315 if (':' != delimiter || '-' != delimiter)
317 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
318 m_interfaces.empty(), m_clientWrapper.expired(),
323 // end of address validity check
325 macAddr.copy(m_devAddr.addr, sizeof(m_devAddr.addr));
326 m_devAddr.addr[macAddr.length()] = '\0';
330 size_t colon = host_token.find(':');
332 if (colon == std::string::npos)
334 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
335 m_interfaces.empty(), m_clientWrapper.expired(), false,
339 std::string ip4Addr = host_token.substr(0, colon);
340 size_t addrLength = ip4Addr.length();
342 if (MAX_ADDR_STR_SIZE <= addrLength)
344 throw std::length_error("host address is too long.");
347 // address validity check
348 size_t startPoint = 0;
350 for (size_t blockCnt = 1; blockCnt <= 4; blockCnt++)
352 size_t dot = ip4Addr.find('.', startPoint);
353 std::string addrBlock;
357 if (std::string::npos == dot || dot <= startPoint)
359 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
360 m_interfaces.empty(), m_clientWrapper.expired(),
363 addrBlock = ip4Addr.substr(startPoint, dot - startPoint);
367 if (std::string::npos != dot)
369 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
370 m_interfaces.empty(), m_clientWrapper.expired(),
373 addrBlock = ip4Addr.substr(startPoint, colon - startPoint);
376 int i_addrBlock = std::stoi(addrBlock);
378 if (std::string::npos != addrBlock.find_first_not_of("0123456789") ||
379 0 > i_addrBlock || 255 < i_addrBlock)
381 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
382 m_interfaces.empty(), m_clientWrapper.expired(), false,
385 startPoint = dot + 1;
387 if (addrLength <= startPoint)
389 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
390 m_interfaces.empty(), m_clientWrapper.expired(), false,
394 // end of address validity check
396 ip4Addr.copy(m_devAddr.addr, sizeof(m_devAddr.addr));
397 m_devAddr.addr[ip4Addr.length()] = '\0';
398 //skip ':' character in host string
399 host_token = host_token.substr(colon + 1);
401 int port = std::stoi(host_token);
403 if (0 > port || UINT16_MAX < port)
405 throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(),
406 m_interfaces.empty(), m_clientWrapper.expired(), false,
410 m_devAddr.port = static_cast< uint16_t >(port);
415 OCStackResult OCResource::get(const QueryParamsMap& queryParametersMap,
416 GetCallback attributeHandler, QualityOfService QoS)
418 return checked_guard(m_clientWrapper.lock(),
419 &IClientWrapper::GetResourceRepresentation,
421 queryParametersMap, m_headerOptions,
422 attributeHandler, QoS);
425 OCStackResult OCResource::get(const QueryParamsMap& queryParametersMap,
426 GetCallback attributeHandler)
428 QualityOfService defaultQos = OC::QualityOfService::NaQos;
429 checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQos);
430 return result_guard(get(queryParametersMap, attributeHandler, defaultQos));
433 OCStackResult OCResource::get(const std::string& resourceType,
434 const std::string& resourceInterface, const QueryParamsMap& queryParametersMap,
435 GetCallback attributeHandler)
437 QualityOfService defaultQoS = OC::QualityOfService::NaQos;
438 checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQoS);
440 return result_guard(get(resourceType, resourceInterface, queryParametersMap, attributeHandler, defaultQoS));
443 OCStackResult OCResource::get(const std::string& resourceType, const std::string& resourceInterface, const QueryParamsMap& queryParametersMap, GetCallback attributeHandler,
444 QualityOfService QoS)
446 QueryParamsMap mapCpy(queryParametersMap);
448 if(!resourceType.empty())
450 mapCpy[OC::Key::RESOURCETYPESKEY]=resourceType;
453 if(!resourceInterface.empty())
455 mapCpy[OC::Key::INTERFACESKEY]= resourceInterface;
458 return result_guard(get(mapCpy, attributeHandler, QoS));
461 OCStackResult OCResource::put(const OCRepresentation& rep,
462 const QueryParamsMap& queryParametersMap, PutCallback attributeHandler,
463 QualityOfService QoS)
465 return checked_guard(m_clientWrapper.lock(), &IClientWrapper::PutResourceRepresentation,
466 m_devAddr, m_uri, rep, queryParametersMap,
467 m_headerOptions, attributeHandler, QoS);
470 OCStackResult OCResource::put(const OCRepresentation& rep,
471 const QueryParamsMap& queryParametersMap, PutCallback attributeHandler)
473 QualityOfService defaultQos = OC::QualityOfService::NaQos;
474 checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQos);
475 return result_guard(put(rep, queryParametersMap, attributeHandler, defaultQos));
478 OCStackResult OCResource::put(const std::string& resourceType,
479 const std::string& resourceInterface, const OCRepresentation& rep,
480 const QueryParamsMap& queryParametersMap,
481 PutCallback attributeHandler)
483 QualityOfService defaultQos = OC::QualityOfService::NaQos;
484 checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQos);
486 return result_guard(put(resourceType, resourceInterface, rep, queryParametersMap,
487 attributeHandler, defaultQos));
490 OCStackResult OCResource::put(const std::string& resourceType,
491 const std::string& resourceInterface, const OCRepresentation& rep,
492 const QueryParamsMap& queryParametersMap,
493 PutCallback attributeHandler,
494 QualityOfService QoS)
496 QueryParamsMap mapCpy(queryParametersMap);
498 if(!resourceType.empty())
500 mapCpy[OC::Key::RESOURCETYPESKEY]=resourceType;
503 if(!resourceInterface.empty())
505 mapCpy[OC::Key::INTERFACESKEY]=resourceInterface;
508 return result_guard(put(rep, mapCpy, attributeHandler, QoS));
511 OCStackResult OCResource::post(const OCRepresentation& rep,
512 const QueryParamsMap& queryParametersMap, PostCallback attributeHandler,
513 QualityOfService QoS)
515 return checked_guard(m_clientWrapper.lock(), &IClientWrapper::PostResourceRepresentation,
516 m_devAddr, m_uri, rep, queryParametersMap,
517 m_headerOptions, attributeHandler, QoS);
520 OCStackResult OCResource::post(const OCRepresentation& rep,
521 const QueryParamsMap& queryParametersMap, PutCallback attributeHandler)
523 QualityOfService defaultQos = OC::QualityOfService::NaQos;
524 checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQos);
525 return result_guard(post(rep, queryParametersMap, attributeHandler, defaultQos));
528 OCStackResult OCResource::post(const std::string& resourceType,
529 const std::string& resourceInterface, const OCRepresentation& rep,
530 const QueryParamsMap& queryParametersMap,
531 PostCallback attributeHandler)
533 QualityOfService defaultQoS = OC::QualityOfService::NaQos;
534 checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQoS);
536 return result_guard(post(resourceType, resourceInterface, rep, queryParametersMap, attributeHandler,
540 OCStackResult OCResource::post(const std::string& resourceType,
541 const std::string& resourceInterface, const OCRepresentation& rep,
542 const QueryParamsMap& queryParametersMap,
543 PostCallback attributeHandler,
544 QualityOfService QoS)
546 QueryParamsMap mapCpy(queryParametersMap);
548 if(!resourceType.empty())
550 mapCpy[OC::Key::RESOURCETYPESKEY]=resourceType;
553 if(!resourceInterface.empty())
555 mapCpy[OC::Key::INTERFACESKEY]=resourceInterface;
558 return result_guard(post(rep, mapCpy, attributeHandler, QoS));
561 OCStackResult OCResource::deleteResource(DeleteCallback deleteHandler, QualityOfService QoS)
563 return checked_guard(m_clientWrapper.lock(), &IClientWrapper::DeleteResource,
564 m_devAddr, m_uri, m_headerOptions, deleteHandler, QoS);
567 OCStackResult OCResource::deleteResource(DeleteCallback deleteHandler)
569 QualityOfService defaultQos = OC::QualityOfService::NaQos;
570 checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQos);
572 return result_guard(deleteResource(deleteHandler, defaultQos));
575 OCStackResult OCResource::observe(ObserveType observeType,
576 const QueryParamsMap& queryParametersMap, ObserveCallback observeHandler,
577 QualityOfService QoS)
579 if(m_observeHandle != nullptr)
581 return result_guard(OC_STACK_INVALID_PARAM);
584 return checked_guard(m_clientWrapper.lock(), &IClientWrapper::ObserveResource,
585 observeType, &m_observeHandle, m_devAddr,
586 m_uri, queryParametersMap, m_headerOptions,
587 observeHandler, QoS);
590 OCStackResult OCResource::observe(ObserveType observeType,
591 const QueryParamsMap& queryParametersMap, ObserveCallback observeHandler)
593 QualityOfService defaultQoS = OC::QualityOfService::NaQos;
594 checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQoS);
596 return result_guard(observe(observeType, queryParametersMap, observeHandler, defaultQoS));
599 OCStackResult OCResource::cancelObserve()
601 QualityOfService defaultQoS = OC::QualityOfService::NaQos;
602 checked_guard(m_clientWrapper.lock(), &IClientWrapper::GetDefaultQos, defaultQoS);
603 return result_guard(cancelObserve(defaultQoS));
606 OCStackResult OCResource::cancelObserve(QualityOfService QoS)
608 if(m_observeHandle == nullptr)
610 return result_guard(OC_STACK_INVALID_PARAM);
613 OCStackResult result = checked_guard(m_clientWrapper.lock(),
614 &IClientWrapper::CancelObserveResource,
615 m_observeHandle, "", m_uri, m_headerOptions, QoS);
617 if(result == OC_STACK_OK)
619 m_observeHandle = nullptr;
625 void OCResource::setHeaderOptions(const HeaderOptions& headerOptions)
627 m_headerOptions = headerOptions;
630 void OCResource::unsetHeaderOptions()
632 m_headerOptions.clear();
635 std::string OCResource::host() const
637 std::ostringstream ss;
638 if (m_devAddr.flags & OC_SECURE)
642 else if (m_devAddr.adapter & OC_ADAPTER_TCP)
650 if (m_devAddr.flags & OC_IP_USE_V6)
652 ss << '[' << m_devAddr.addr << ']';
656 ss << m_devAddr.addr;
660 ss << ':' << m_devAddr.port;
665 std::string OCResource::uri() const
670 OCConnectivityType OCResource::connectivityType() const
672 return static_cast<OCConnectivityType>(
673 (m_devAddr.adapter << CT_ADAPTER_SHIFT) | (m_devAddr.flags & CT_MASK_FLAGS));
676 bool OCResource::isObservable() const
678 return m_isObservable;
681 std::vector<std::string> OCResource::getResourceTypes() const
683 return m_resourceTypes;
686 std::vector<std::string> OCResource::getResourceInterfaces(void) const
691 OCResourceIdentifier OCResource::uniqueIdentifier() const
696 std::string OCResource::sid() const
698 return this->uniqueIdentifier().m_representation;
701 bool OCResource::operator==(const OCResource &other) const
703 return m_resourceId == other.m_resourceId;
706 bool OCResource::operator!=(const OCResource &other) const
708 return m_resourceId != other.m_resourceId;
711 bool OCResource::operator<(const OCResource &other) const
713 return m_resourceId < other.m_resourceId;
716 bool OCResource::operator>(const OCResource &other) const
718 return m_resourceId > other.m_resourceId;
721 bool OCResource::operator<=(const OCResource &other) const
723 return m_resourceId <= other.m_resourceId;
726 bool OCResource::operator>=(const OCResource &other) const
728 return m_resourceId >= other.m_resourceId;
731 OCResourceIdentifier::OCResourceIdentifier(const std::string& wireServerIdentifier,
732 const std::string& resourceUri)
733 :m_representation(wireServerIdentifier), m_resourceUri(resourceUri)
737 std::ostream& operator <<(std::ostream& os, const OCResourceIdentifier& ri)
739 os << ri.m_representation<<ri.m_resourceUri;
744 bool OCResourceIdentifier::operator==(const OCResourceIdentifier &other) const
746 return m_representation == other.m_representation
747 && m_resourceUri == other.m_resourceUri;
750 bool OCResourceIdentifier::operator!=(const OCResourceIdentifier &other) const
752 return !(*this == other);
755 bool OCResourceIdentifier::operator<(const OCResourceIdentifier &other) const
757 return m_resourceUri < other.m_resourceUri
758 || (m_resourceUri == other.m_resourceUri &&
759 m_representation < other.m_representation);
762 bool OCResourceIdentifier::operator>(const OCResourceIdentifier &other) const
764 return *this != other && !(*this<other);
767 bool OCResourceIdentifier::operator<=(const OCResourceIdentifier &other) const
769 return !(*this > other);
772 bool OCResourceIdentifier::operator>=(const OCResourceIdentifier &other) const
774 return !(*this < other);