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 "InProcClientWrapper.h"
24 #include "OCPlatform.h"
25 #include "OCResource.h"
26 #include "ocpayload.h"
27 #include <OCSerialization.h>
32 InProcClientWrapper::InProcClientWrapper(
33 std::weak_ptr<std::recursive_mutex> csdkLock, PlatformConfig cfg)
34 : m_threadRun(false), m_csdkLock(csdkLock),
37 // if the config type is server, we ought to never get called. If the config type
38 // is both, we count on the server to run the thread and do the initialize
40 if(m_cfg.mode == ModeType::Client)
42 OCTransportFlags serverFlags =
43 static_cast<OCTransportFlags>(m_cfg.serverConnectivity & CT_MASK_FLAGS);
44 OCTransportFlags clientFlags =
45 static_cast<OCTransportFlags>(m_cfg.clientConnectivity & CT_MASK_FLAGS);
46 OCStackResult result = OCInit1(OC_CLIENT, serverFlags, clientFlags);
48 if(OC_STACK_OK != result)
50 throw InitializeException(OC::InitException::STACK_INIT_ERROR, result);
54 m_listeningThread = std::thread(&InProcClientWrapper::listeningFunc, this);
58 InProcClientWrapper::~InProcClientWrapper()
60 if(m_threadRun && m_listeningThread.joinable())
63 m_listeningThread.join();
66 // only stop if we are the ones who actually called 'init'. We are counting
67 // on the server to do the stop.
68 if(m_cfg.mode == ModeType::Client)
74 void InProcClientWrapper::listeningFunc()
79 auto cLock = m_csdkLock.lock();
82 std::lock_guard<std::recursive_mutex> lock(*cLock);
87 result = OC_STACK_ERROR;
90 if(result != OC_STACK_OK)
92 // TODO: do something with result if failed?
95 // To minimize CPU utilization we may wish to do this with sleep
96 std::this_thread::sleep_for(std::chrono::milliseconds(10));
100 OCRepresentation parseGetSetCallback(OCClientResponse* clientResponse)
102 if(clientResponse->payload == nullptr ||
104 clientResponse->payload->type != PAYLOAD_TYPE_DEVICE &&
105 clientResponse->payload->type != PAYLOAD_TYPE_PLATFORM &&
106 clientResponse->payload->type != PAYLOAD_TYPE_REPRESENTATION
110 //OCPayloadDestroy(clientResponse->payload);
111 return OCRepresentation();
115 oc.setPayload(clientResponse->payload);
116 //OCPayloadDestroy(clientResponse->payload);
118 std::vector<OCRepresentation>::const_iterator it = oc.representations().begin();
119 if(it == oc.representations().end())
121 return OCRepresentation();
124 // first one is considered the root, everything else is considered a child of this one.
125 OCRepresentation root = *it;
126 root.setDevAddr(clientResponse->devAddr);
127 root.setUri(clientResponse->resourceUri);
130 std::for_each(it, oc.representations().end(),
131 [&root](const OCRepresentation& repItr)
132 {root.addChild(repItr);});
137 OCStackApplicationResult listenCallback(void* ctx, OCDoHandle /*handle*/,
138 OCClientResponse* clientResponse)
140 ClientCallbackContext::ListenContext* context =
141 static_cast<ClientCallbackContext::ListenContext*>(ctx);
143 if(clientResponse->result != OC_STACK_OK)
145 oclog() << "listenCallback(): failed to create resource. clientResponse: "
146 << clientResponse->result
149 return OC_STACK_KEEP_TRANSACTION;
152 if(!clientResponse->payload || clientResponse->payload->type != PAYLOAD_TYPE_DISCOVERY)
154 oclog() << "listenCallback(): clientResponse payload was null or the wrong type"
156 return OC_STACK_KEEP_TRANSACTION;
159 auto clientWrapper = context->clientWrapper.lock();
163 oclog() << "listenCallback(): failed to get a shared_ptr to the client wrapper"
165 return OC_STACK_KEEP_TRANSACTION;
169 ListenOCContainer container(clientWrapper, clientResponse->devAddr,
170 reinterpret_cast<OCDiscoveryPayload*>(clientResponse->payload));
171 // loop to ensure valid construction of all resources
172 for(auto resource : container.Resources())
174 std::thread exec(context->callback, resource);
178 catch (std::exception &e){
179 oclog() << "Exception in listCallback, ignoring response: "
180 << e.what() << std::flush;
184 return OC_STACK_KEEP_TRANSACTION;
187 OCStackApplicationResult listenErrorCallback(void* ctx, OCDoHandle /*handle*/,
188 OCClientResponse* clientResponse)
190 if (!ctx || !clientResponse)
192 return OC_STACK_KEEP_TRANSACTION;
195 ClientCallbackContext::ListenErrorContext* context =
196 static_cast<ClientCallbackContext::ListenErrorContext*>(ctx);
199 return OC_STACK_KEEP_TRANSACTION;
202 OCStackResult result = clientResponse->result;
203 if (result == OC_STACK_OK)
205 if (!clientResponse->payload || clientResponse->payload->type != PAYLOAD_TYPE_DISCOVERY)
207 oclog() << "listenCallback(): clientResponse payload was null or the wrong type"
209 return OC_STACK_KEEP_TRANSACTION;
212 auto clientWrapper = context->clientWrapper.lock();
216 oclog() << "listenCallback(): failed to get a shared_ptr to the client wrapper"
218 return OC_STACK_KEEP_TRANSACTION;
221 ListenOCContainer container(clientWrapper, clientResponse->devAddr,
222 reinterpret_cast<OCDiscoveryPayload*>(clientResponse->payload));
223 // loop to ensure valid construction of all resources
224 for (auto resource : container.Resources())
226 std::thread exec(context->callback, resource);
229 return OC_STACK_KEEP_TRANSACTION;
232 std::string resourceURI = clientResponse->resourceUri;
233 std::thread exec(context->errorCallback, resourceURI, result);
235 return OC_STACK_DELETE_TRANSACTION;
238 OCStackResult InProcClientWrapper::ListenForResource(
239 const std::string& serviceUrl,
240 const std::string& resourceType,
241 OCConnectivityType connectivityType,
242 FindCallback& callback, QualityOfService QoS)
246 return OC_STACK_INVALID_PARAM;
249 OCStackResult result;
250 ostringstream resourceUri;
251 resourceUri << serviceUrl << resourceType;
253 ClientCallbackContext::ListenContext* context =
254 new ClientCallbackContext::ListenContext(callback, shared_from_this());
255 OCCallbackData cbdata(
256 static_cast<void*>(context),
258 [](void* c){delete static_cast<ClientCallbackContext::ListenContext*>(c);}
261 auto cLock = m_csdkLock.lock();
264 std::lock_guard<std::recursive_mutex> lock(*cLock);
265 result = OCDoResource(nullptr, OC_REST_DISCOVER,
266 resourceUri.str().c_str(),
267 nullptr, nullptr, connectivityType,
268 static_cast<OCQualityOfService>(QoS),
275 result = OC_STACK_ERROR;
280 OCStackResult InProcClientWrapper::ListenErrorForResource(
281 const std::string& serviceUrl,
282 const std::string& resourceType,
283 OCConnectivityType connectivityType,
284 FindCallback& callback, FindErrorCallback& errorCallback,
285 QualityOfService QoS)
289 return OC_STACK_INVALID_PARAM;
292 ostringstream resourceUri;
293 resourceUri << serviceUrl << resourceType;
295 ClientCallbackContext::ListenErrorContext* context =
296 new ClientCallbackContext::ListenErrorContext(callback, errorCallback,
300 return OC_STACK_ERROR;
303 OCCallbackData cbdata(
304 static_cast<void*>(context),
306 [](void* c){delete static_cast<ClientCallbackContext::ListenErrorContext*>(c);}
309 OCStackResult result;
310 auto cLock = m_csdkLock.lock();
313 std::lock_guard<std::recursive_mutex> lock(*cLock);
314 result = OCDoResource(nullptr, OC_REST_DISCOVER,
315 resourceUri.str().c_str(),
316 nullptr, nullptr, connectivityType,
317 static_cast<OCQualityOfService>(QoS),
324 result = OC_STACK_ERROR;
329 OCStackApplicationResult listenDeviceCallback(void* ctx,
330 OCDoHandle /*handle*/,
331 OCClientResponse* clientResponse)
333 ClientCallbackContext::DeviceListenContext* context =
334 static_cast<ClientCallbackContext::DeviceListenContext*>(ctx);
338 OCRepresentation rep = parseGetSetCallback(clientResponse);
339 std::thread exec(context->callback, rep);
342 catch(OC::OCException& e)
344 oclog() <<"Exception in listenDeviceCallback, ignoring response: "
345 <<e.what() <<std::flush;
348 return OC_STACK_KEEP_TRANSACTION;
351 OCStackResult InProcClientWrapper::ListenForDevice(
352 const std::string& serviceUrl,
353 const std::string& deviceURI,
354 OCConnectivityType connectivityType,
355 FindDeviceCallback& callback,
356 QualityOfService QoS)
360 return OC_STACK_INVALID_PARAM;
362 OCStackResult result;
363 ostringstream deviceUri;
364 deviceUri << serviceUrl << deviceURI;
366 ClientCallbackContext::DeviceListenContext* context =
367 new ClientCallbackContext::DeviceListenContext(callback, shared_from_this());
368 OCCallbackData cbdata(
369 static_cast<void*>(context),
370 listenDeviceCallback,
371 [](void* c){delete static_cast<ClientCallbackContext::DeviceListenContext*>(c);}
374 auto cLock = m_csdkLock.lock();
377 std::lock_guard<std::recursive_mutex> lock(*cLock);
378 result = OCDoResource(nullptr, OC_REST_DISCOVER,
379 deviceUri.str().c_str(),
380 nullptr, nullptr, connectivityType,
381 static_cast<OCQualityOfService>(QoS),
388 result = OC_STACK_ERROR;
393 void parseServerHeaderOptions(OCClientResponse* clientResponse,
394 HeaderOptions& serverHeaderOptions)
398 // Parse header options from server
400 std::string optionData;
402 for(int i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions; i++)
404 optionID = clientResponse->rcvdVendorSpecificHeaderOptions[i].optionID;
405 optionData = reinterpret_cast<const char*>
406 (clientResponse->rcvdVendorSpecificHeaderOptions[i].optionData);
407 HeaderOption::OCHeaderOption headerOption(optionID, optionData);
408 serverHeaderOptions.push_back(headerOption);
413 // clientResponse is invalid
414 // TODO check proper logging
415 std::cout << " Invalid response " << std::endl;
419 OCStackApplicationResult getResourceCallback(void* ctx,
420 OCDoHandle /*handle*/,
421 OCClientResponse* clientResponse)
423 ClientCallbackContext::GetContext* context =
424 static_cast<ClientCallbackContext::GetContext*>(ctx);
426 OCRepresentation rep;
427 HeaderOptions serverHeaderOptions;
428 OCStackResult result = clientResponse->result;
429 if(result == OC_STACK_OK)
431 parseServerHeaderOptions(clientResponse, serverHeaderOptions);
434 rep = parseGetSetCallback(clientResponse);
436 catch(OC::OCException& e)
442 std::thread exec(context->callback, serverHeaderOptions, rep, result);
444 return OC_STACK_DELETE_TRANSACTION;
447 OCStackResult InProcClientWrapper::GetResourceRepresentation(
448 const OCDevAddr& devAddr,
449 const std::string& resourceUri,
450 const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,
451 GetCallback& callback, QualityOfService QoS)
455 return OC_STACK_INVALID_PARAM;
457 OCStackResult result;
458 ClientCallbackContext::GetContext* ctx =
459 new ClientCallbackContext::GetContext(callback);
460 OCCallbackData cbdata(
461 static_cast<void*>(ctx),
463 [](void* c){delete static_cast<ClientCallbackContext::GetContext*>(c);}
466 std::string uri = assembleSetResourceUri(resourceUri, queryParams);
468 auto cLock = m_csdkLock.lock();
472 std::lock_guard<std::recursive_mutex> lock(*cLock);
473 OCHeaderOption options[MAX_HEADER_OPTIONS];
475 result = OCDoResource(
476 nullptr, OC_REST_GET,
480 static_cast<OCQualityOfService>(QoS),
482 assembleHeaderOptions(options, headerOptions),
483 headerOptions.size());
488 result = OC_STACK_ERROR;
494 OCStackApplicationResult setResourceCallback(void* ctx,
495 OCDoHandle /*handle*/,
496 OCClientResponse* clientResponse)
498 ClientCallbackContext::SetContext* context =
499 static_cast<ClientCallbackContext::SetContext*>(ctx);
500 OCRepresentation attrs;
501 HeaderOptions serverHeaderOptions;
503 OCStackResult result = clientResponse->result;
504 if (OC_STACK_OK == result ||
505 OC_STACK_RESOURCE_CREATED == result ||
506 OC_STACK_RESOURCE_DELETED == result)
508 parseServerHeaderOptions(clientResponse, serverHeaderOptions);
511 attrs = parseGetSetCallback(clientResponse);
513 catch(OC::OCException& e)
519 std::thread exec(context->callback, serverHeaderOptions, attrs, result);
521 return OC_STACK_DELETE_TRANSACTION;
524 std::string InProcClientWrapper::assembleSetResourceUri(std::string uri,
525 const QueryParamsMap& queryParams)
527 if(uri.back() == '/')
529 uri.resize(uri.size()-1);
532 ostringstream paramsList;
533 if(queryParams.size() > 0)
538 for(auto& param : queryParams)
540 paramsList << param.first <<'='<<param.second<<';';
543 std::string queryString = paramsList.str();
544 if(queryString.back() == ';')
546 queryString.resize(queryString.size() - 1);
549 std::string ret = uri + queryString;
553 OCPayload* InProcClientWrapper::assembleSetResourcePayload(const OCRepresentation& rep)
555 MessageContainer ocInfo;
556 ocInfo.addRepresentation(rep);
557 for(const OCRepresentation& r : rep.getChildren())
559 ocInfo.addRepresentation(r);
562 return reinterpret_cast<OCPayload*>(ocInfo.getPayload());
565 OCStackResult InProcClientWrapper::PostResourceRepresentation(
566 const OCDevAddr& devAddr,
567 const std::string& uri,
568 const OCRepresentation& rep,
569 const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,
570 PostCallback& callback, QualityOfService QoS)
574 return OC_STACK_INVALID_PARAM;
576 OCStackResult result;
577 ClientCallbackContext::SetContext* ctx = new ClientCallbackContext::SetContext(callback);
578 OCCallbackData cbdata(
579 static_cast<void*>(ctx),
581 [](void* c){delete static_cast<ClientCallbackContext::SetContext*>(c);}
584 std::string url = assembleSetResourceUri(uri, queryParams);
586 auto cLock = m_csdkLock.lock();
590 std::lock_guard<std::recursive_mutex> lock(*cLock);
591 OCHeaderOption options[MAX_HEADER_OPTIONS];
593 result = OCDoResource(nullptr, OC_REST_POST,
594 url.c_str(), &devAddr,
595 assembleSetResourcePayload(rep),
597 static_cast<OCQualityOfService>(QoS),
599 assembleHeaderOptions(options, headerOptions),
600 headerOptions.size());
605 result = OC_STACK_ERROR;
611 OCStackResult InProcClientWrapper::PutResourceRepresentation(
612 const OCDevAddr& devAddr,
613 const std::string& uri,
614 const OCRepresentation& rep,
615 const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,
616 PutCallback& callback, QualityOfService QoS)
620 return OC_STACK_INVALID_PARAM;
622 OCStackResult result;
623 ClientCallbackContext::SetContext* ctx = new ClientCallbackContext::SetContext(callback);
624 OCCallbackData cbdata(
625 static_cast<void*>(ctx),
627 [](void* c){delete static_cast<ClientCallbackContext::SetContext*>(c);}
630 std::string url = assembleSetResourceUri(uri, queryParams).c_str();
632 auto cLock = m_csdkLock.lock();
636 std::lock_guard<std::recursive_mutex> lock(*cLock);
638 OCHeaderOption options[MAX_HEADER_OPTIONS];
640 result = OCDoResource(&handle, OC_REST_PUT,
641 url.c_str(), &devAddr,
642 assembleSetResourcePayload(rep),
644 static_cast<OCQualityOfService>(QoS),
646 assembleHeaderOptions(options, headerOptions),
647 headerOptions.size());
652 result = OC_STACK_ERROR;
658 OCStackApplicationResult deleteResourceCallback(void* ctx,
659 OCDoHandle /*handle*/,
660 OCClientResponse* clientResponse)
662 ClientCallbackContext::DeleteContext* context =
663 static_cast<ClientCallbackContext::DeleteContext*>(ctx);
664 HeaderOptions serverHeaderOptions;
666 if(clientResponse->result == OC_STACK_OK)
668 parseServerHeaderOptions(clientResponse, serverHeaderOptions);
670 std::thread exec(context->callback, serverHeaderOptions, clientResponse->result);
672 return OC_STACK_DELETE_TRANSACTION;
675 OCStackResult InProcClientWrapper::DeleteResource(
676 const OCDevAddr& devAddr,
677 const std::string& uri,
678 const HeaderOptions& headerOptions,
679 DeleteCallback& callback,
680 QualityOfService /*QoS*/)
684 return OC_STACK_INVALID_PARAM;
686 OCStackResult result;
687 ClientCallbackContext::DeleteContext* ctx =
688 new ClientCallbackContext::DeleteContext(callback);
689 OCCallbackData cbdata(
690 static_cast<void*>(ctx),
691 deleteResourceCallback,
692 [](void* c){delete static_cast<ClientCallbackContext::DeleteContext*>(c);}
695 auto cLock = m_csdkLock.lock();
699 OCHeaderOption options[MAX_HEADER_OPTIONS];
701 std::lock_guard<std::recursive_mutex> lock(*cLock);
703 result = OCDoResource(nullptr, OC_REST_DELETE,
704 uri.c_str(), &devAddr,
707 static_cast<OCQualityOfService>(m_cfg.QoS),
709 assembleHeaderOptions(options, headerOptions),
710 headerOptions.size());
715 result = OC_STACK_ERROR;
721 OCStackApplicationResult observeResourceCallback(void* ctx,
722 OCDoHandle /*handle*/,
723 OCClientResponse* clientResponse)
725 ClientCallbackContext::ObserveContext* context =
726 static_cast<ClientCallbackContext::ObserveContext*>(ctx);
727 OCRepresentation attrs;
728 HeaderOptions serverHeaderOptions;
729 uint32_t sequenceNumber = clientResponse->sequenceNumber;
730 OCStackResult result = clientResponse->result;
731 if(clientResponse->result == OC_STACK_OK)
733 parseServerHeaderOptions(clientResponse, serverHeaderOptions);
736 attrs = parseGetSetCallback(clientResponse);
738 catch(OC::OCException& e)
743 std::thread exec(context->callback, serverHeaderOptions, attrs,
744 result, sequenceNumber);
746 if(sequenceNumber == OC_OBSERVE_DEREGISTER)
748 return OC_STACK_DELETE_TRANSACTION;
750 return OC_STACK_KEEP_TRANSACTION;
753 OCStackResult InProcClientWrapper::ObserveResource(ObserveType observeType, OCDoHandle* handle,
754 const OCDevAddr& devAddr,
755 const std::string& uri,
756 const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,
757 ObserveCallback& callback, QualityOfService QoS)
761 return OC_STACK_INVALID_PARAM;
763 OCStackResult result;
765 ClientCallbackContext::ObserveContext* ctx =
766 new ClientCallbackContext::ObserveContext(callback);
767 OCCallbackData cbdata(
768 static_cast<void*>(ctx),
769 observeResourceCallback,
770 [](void* c){delete static_cast<ClientCallbackContext::ObserveContext*>(c);}
774 if (observeType == ObserveType::Observe)
776 method = OC_REST_OBSERVE;
778 else if (observeType == ObserveType::ObserveAll)
780 method = OC_REST_OBSERVE_ALL;
784 method = OC_REST_OBSERVE_ALL;
787 std::string url = assembleSetResourceUri(uri, queryParams).c_str();
789 auto cLock = m_csdkLock.lock();
793 std::lock_guard<std::recursive_mutex> lock(*cLock);
794 OCHeaderOption options[MAX_HEADER_OPTIONS];
796 result = OCDoResource(handle, method,
797 url.c_str(), &devAddr,
800 static_cast<OCQualityOfService>(QoS),
802 assembleHeaderOptions(options, headerOptions),
803 headerOptions.size());
808 return OC_STACK_ERROR;
814 OCStackResult InProcClientWrapper::CancelObserveResource(
816 const std::string& /*host*/,
817 const std::string& /*uri*/,
818 const HeaderOptions& headerOptions,
819 QualityOfService QoS)
821 OCStackResult result;
822 auto cLock = m_csdkLock.lock();
826 std::lock_guard<std::recursive_mutex> lock(*cLock);
827 OCHeaderOption options[MAX_HEADER_OPTIONS];
829 result = OCCancel(handle,
830 static_cast<OCQualityOfService>(QoS),
831 assembleHeaderOptions(options, headerOptions),
832 headerOptions.size());
836 result = OC_STACK_ERROR;
842 OCStackApplicationResult subscribePresenceCallback(void* ctx,
843 OCDoHandle /*handle*/,
844 OCClientResponse* clientResponse)
846 ClientCallbackContext::SubscribePresenceContext* context =
847 static_cast<ClientCallbackContext::SubscribePresenceContext*>(ctx);
850 * This a hack while we rethink presence subscription.
852 std::string url = clientResponse->devAddr.addr;
854 std::thread exec(context->callback, clientResponse->result,
855 clientResponse->sequenceNumber, url);
859 return OC_STACK_KEEP_TRANSACTION;
862 OCStackResult InProcClientWrapper::SubscribePresence(OCDoHandle* handle,
863 const std::string& host, const std::string& resourceType,
864 OCConnectivityType connectivityType, SubscribeCallback& presenceHandler)
868 return OC_STACK_INVALID_PARAM;
871 ClientCallbackContext::SubscribePresenceContext* ctx =
872 new ClientCallbackContext::SubscribePresenceContext(presenceHandler);
873 OCCallbackData cbdata(
874 static_cast<void*>(ctx),
875 subscribePresenceCallback,
877 {delete static_cast<ClientCallbackContext::SubscribePresenceContext*>(c);}
880 auto cLock = m_csdkLock.lock();
882 std::ostringstream os;
883 os << host << OC_RSRVD_PRESENCE_URI;
885 if(!resourceType.empty())
887 os << "?rt=" << resourceType;
893 return OC_STACK_ERROR;
896 return OCDoResource(handle, OC_REST_PRESENCE,
897 os.str().c_str(), nullptr,
898 nullptr, connectivityType,
899 OC_LOW_QOS, &cbdata, NULL, 0);
902 OCStackResult InProcClientWrapper::UnsubscribePresence(OCDoHandle handle)
904 OCStackResult result;
905 auto cLock = m_csdkLock.lock();
909 std::lock_guard<std::recursive_mutex> lock(*cLock);
910 result = OCCancel(handle, OC_LOW_QOS, NULL, 0);
914 result = OC_STACK_ERROR;
920 OCStackResult InProcClientWrapper::GetDefaultQos(QualityOfService& qos)
926 OCHeaderOption* InProcClientWrapper::assembleHeaderOptions(OCHeaderOption options[],
927 const HeaderOptions& headerOptions)
931 if( headerOptions.size() == 0)
936 for (auto it=headerOptions.begin(); it != headerOptions.end(); ++it)
938 options[i] = OCHeaderOption(OC_COAP_ID,
940 it->getOptionData().length() + 1,
941 reinterpret_cast<const uint8_t*>(it->getOptionData().c_str()));