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