1 //******************************************************************
3 // Copyright 2016 Samsung Electronics 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 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
22 /// This sample provides the way to create cloud sample
27 #include <condition_variable>
35 #include "ocpayload.h"
37 #include "cloud_connector.h"
39 #define DEFAULT_CONTEXT_VALUE 0x99
40 #define DEFAULT_PUBLISH_QUERY "/oic/rd?rt=oic.wk.rdpub"
41 #define DEFAULT_DISCOVER_QUERY "/oic/res?rt=core.light"
43 ////////////////////////////////////////Device Sample
44 #define SAMPLE_MAX_NUM_POST_INSTANCE 2
45 typedef struct LIGHTRESOURCE
47 OCResourceHandle handle;
51 static LightResource gLightInstance[SAMPLE_MAX_NUM_POST_INSTANCE];
54 OCRepPayload *responsePayload(int64_t power, bool state)
56 OCRepPayload *payload = OCRepPayloadCreate();
59 std::cout << "Failed to allocate Payload" << std::endl;
63 OCRepPayloadSetPropBool(payload, "state", state);
64 OCRepPayloadSetPropInt(payload, "power", power);
69 OCRepPayload *constructResponse(OCEntityHandlerRequest *ehRequest)
71 if (ehRequest->payload && ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
73 std::cout << "Incoming payload not a representation" << std::endl;
77 LightResource *currLightResource = NULL;
79 if (ehRequest->resource == gLightInstance[0].handle)
81 currLightResource = &gLightInstance[0];
83 else if (ehRequest->resource == gLightInstance[1].handle)
85 currLightResource = &gLightInstance[1];
88 if (OC_REST_PUT == ehRequest->method)
90 // Get pointer to query
92 OCRepPayload *input = reinterpret_cast<OCRepPayload *>(ehRequest->payload);
94 if (OCRepPayloadGetPropInt(input, "power", &pow))
96 currLightResource->power = pow;
100 if (OCRepPayloadGetPropBool(input, "state", &state))
102 currLightResource->state = state;
106 return responsePayload(currLightResource->power, currLightResource->state);
109 OCEntityHandlerResult ProcessGetRequest(OCEntityHandlerRequest *ehRequest,
110 OCRepPayload **payload)
112 OCRepPayload *getResp = constructResponse(ehRequest);
115 std::cout << "constructResponse failed" << std::endl;
124 OCEntityHandlerResult ProcessPutRequest(OCEntityHandlerRequest *ehRequest,
125 OCRepPayload **payload)
127 OCEntityHandlerResult ehResult;
128 OCRepPayload *putResp = constructResponse(ehRequest);
132 std::cout << "Failed to construct Json response" << std::endl;
142 #define SAMPLE_MAX_NUM_OBSERVATIONS 2
143 static bool observeThreadStarted = false;
144 int gLightUnderObservation = 0;
145 pthread_t threadId_observe;
148 OCObservationId observationId;
150 OCResourceHandle resourceHandle;
152 Observers interestedObservers[SAMPLE_MAX_NUM_OBSERVATIONS];
154 void *ChangeLightRepresentation(void *param)
157 OCStackResult result = OC_STACK_ERROR;
162 gLightInstance[0].power += 1;
163 gLightInstance[1].power += 3;
165 if (gLightUnderObservation)
167 std::cout << " =====> Notifying stack of new power level " << gLightInstance[0].power << std::endl;
168 std::cout << " =====> Notifying stack of new power level " << gLightInstance[1].power << std::endl;
169 // Notifying all observers
170 result = OCNotifyAllObservers(gLightInstance[0].handle, OC_NA_QOS);
171 result = OCNotifyAllObservers(gLightInstance[1].handle, OC_NA_QOS);
173 std::cout << " =====> Notifying result " << result << std::endl;
179 void ProcessObserveRegister(OCEntityHandlerRequest *ehRequest)
181 std::cout << "Received observation registration request with observation Id " <<
182 ehRequest->obsInfo.obsId << std::endl;
184 if (!observeThreadStarted)
186 pthread_create(&threadId_observe, NULL, ChangeLightRepresentation, (void *)NULL);
187 observeThreadStarted = 1;
189 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
191 if (interestedObservers[i].valid == false)
193 interestedObservers[i].observationId = ehRequest->obsInfo.obsId;
194 interestedObservers[i].valid = true;
195 gLightUnderObservation = 1;
201 void ProcessObserveDeregister(OCEntityHandlerRequest *ehRequest)
203 bool clientStillObserving = false;
205 std::cout << "Received observation deregistration request for observation Id " <<
206 ehRequest->obsInfo.obsId << std::endl;
207 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
209 if (interestedObservers[i].observationId == ehRequest->obsInfo.obsId)
211 interestedObservers[i].valid = false;
213 if (interestedObservers[i].valid == true)
215 // Even if there is one single client observing we continue notifying entity handler
216 clientStillObserving = true;
219 if (clientStillObserving == false)
220 gLightUnderObservation = 0;
223 OCEntityHandlerResult
224 OCEntityHandlerCb(OCEntityHandlerFlag flag,
225 OCEntityHandlerRequest *entityHandlerRequest, void * /*callback*/)
227 OCEntityHandlerResult ehResult = OC_EH_OK;
228 OCEntityHandlerResponse response = { 0, 0, OC_EH_ERROR, 0, 0, {}, { 0 }, false };
231 if (!entityHandlerRequest)
233 std::cout << "Invalid request pointer" << std::endl;
237 // Initialize certain response fields
238 response.numSendVendorSpecificHeaderOptions = 0;
239 memset(response.sendVendorSpecificHeaderOptions,
240 0, sizeof response.sendVendorSpecificHeaderOptions);
241 memset(response.resourceUri, 0, sizeof response.resourceUri);
242 OCRepPayload *payload = nullptr;
244 if (flag & OC_REQUEST_FLAG)
246 std::cout << "Flag includes OC_REQUEST_FLAG" << std::endl;
248 if (OC_REST_GET == entityHandlerRequest->method)
250 std::cout << "Received OC_REST_GET from client" << std::endl;
251 ehResult = ProcessGetRequest(entityHandlerRequest, &payload);
253 else if (OC_REST_PUT == entityHandlerRequest->method)
255 std::cout << "Received OC_REST_PUT from client" << std::endl;
256 ehResult = ProcessPutRequest(entityHandlerRequest, &payload);
260 std::cout << "Received unsupported method %d from client " << entityHandlerRequest->method <<
262 ehResult = OC_EH_ERROR;
264 // If the result isn't an error or forbidden, send response
265 if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
267 // Format the response. Note this requires some info about the request
268 response.requestHandle = entityHandlerRequest->requestHandle;
269 response.resourceHandle = entityHandlerRequest->resource;
270 response.ehResult = ehResult;
271 response.payload = reinterpret_cast<OCPayload *>(payload);
272 // Indicate that response is NOT in a persistent buffer
273 response.persistentBufferFlag = 0;
276 if (OCDoResponse(&response) != OC_STACK_OK)
278 std::cout << "Error sending response" << std::endl;
279 ehResult = OC_EH_ERROR;
284 if (flag & OC_OBSERVE_FLAG)
286 std::cout << "Flag includes OC_OBSERVE_FLAG" << std::endl;
287 if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
289 std::cout << "Received OC_OBSERVE_REGISTER from client" << std::endl;
290 ProcessObserveRegister(entityHandlerRequest);
292 else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
294 std::cout << "Received OC_OBSERVE_DEREGISTER from client" << std::endl;
295 ProcessObserveDeregister(entityHandlerRequest);
299 OCPayloadDestroy(response.payload);
303 int createLightResource(char *uri, LightResource *lightResource)
307 std::cout << "Resource URI cannot be NULL" << std::endl;
311 lightResource->state = false;
312 lightResource->power = 0;
313 OCStackResult res = OCCreateResource(&(lightResource->handle),
319 OC_DISCOVERABLE | OC_OBSERVABLE);
320 std::cout << "Created Light resource with result:" << res << std::endl;
325 OCStackApplicationResult handlePublishCB(void *ctx,
326 OCDoHandle /*handle*/,
327 OCClientResponse *clientResponse)
329 if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
331 std::cout << "Invalid Publish callback received" << std::endl;
334 std::cout << "Publish resource response received, code: " << clientResponse->result << std::endl;
336 return OC_STACK_KEEP_TRANSACTION;
339 void PublishResources(std::string host, std::string additionalQuery)
341 std::cout << "Running as Server mode" << std::endl;
343 std::string requestQuery = DEFAULT_PUBLISH_QUERY;
344 requestQuery += additionalQuery;
346 std::cout << "Publishing resources..." << std::endl;
347 std::cout << host.c_str() << requestQuery.c_str() << std::endl;
349 if (createLightResource((char *)"/a/light/0", &gLightInstance[0]) != 0)
351 std::cout << "Unable to create sample resource" << std::endl;
354 if (createLightResource((char *)"/a/light/1", &gLightInstance[1]) != 0)
356 std::cout << "Unable to create sample resource" << std::endl;
359 if (OCCloudPublish(host.c_str(), requestQuery.c_str(), &handlePublishCB, 2,
360 gLightInstance[0].handle, gLightInstance[1].handle) != OC_STACK_OK)
362 std::cout << "Unable to publish resources to cloud" << std::endl;
366 ////////////////////////////////////////Client Sample
367 std::string g_host = "coap+tcp://";
369 void PrintRepresentation(OCRepPayloadValue *val)
373 std::cout << "Key: " << val->name << " Value: ";
376 case OCREP_PROP_NULL:
377 std::cout << "NULL" << std::endl;
381 std::cout << val->i << std::endl;
384 case OCREP_PROP_DOUBLE:
385 std::cout << val->d << std::endl;
388 case OCREP_PROP_BOOL:
389 std::cout << val->b << std::endl;
392 case OCREP_PROP_STRING:
393 std::cout << val->str << std::endl;
396 case OCREP_PROP_BYTE_STRING:
397 std::cout << "[ByteString]" << std::endl;
400 case OCREP_PROP_OBJECT:
401 std::cout << "[Object]" << std::endl;
404 case OCREP_PROP_ARRAY:
405 std::cout << "[Array]" << std::endl;
414 int gNumObserveNotifies = 0;
416 OCStackApplicationResult obsReqCB(void *ctx, OCDoHandle handle,
417 OCClientResponse *clientResponse)
419 std::cout << "Observe response received from " << clientResponse->resourceUri << std::endl;
421 if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
423 std::cout << "Invalid Put callback received" << std::endl;
428 if (clientResponse->payload == NULL)
430 std::cout << "No payload received" << std::endl;
433 OCRepPayloadValue *val = ((OCRepPayload *)clientResponse->payload)->values;
435 PrintRepresentation(val);
437 gNumObserveNotifies++;
438 if (gNumObserveNotifies > 5) //large number to test observing in DELETE case.
440 std::cout << "Cancelling with OC_HIGH_QOS" << std::endl;
441 if (OCCancel(handle, OC_HIGH_QOS, NULL, 0) != OC_STACK_OK)
443 std::cout << "Observe cancel error" << std::endl;
446 if (clientResponse->sequenceNumber == OC_OBSERVE_REGISTER)
448 std::cout << "This also serves as a registration confirmation" << std::endl;
450 else if (clientResponse->sequenceNumber == OC_OBSERVE_DEREGISTER)
452 std::cout << "This also serves as a deregistration confirmation" << std::endl;
453 return OC_STACK_DELETE_TRANSACTION;
455 else if (clientResponse->sequenceNumber == OC_OBSERVE_NO_OPTION)
457 std::cout << "This also tells you that registration/deregistration failed" << std::endl;
458 return OC_STACK_DELETE_TRANSACTION;
463 std::cout << "obsReqCB received Null clientResponse" << std::endl;
466 return OC_STACK_KEEP_TRANSACTION;
469 void ObserveResource(std::string uri, std::string additionalQuery)
471 OCCallbackData cbData;
472 cbData.cb = obsReqCB;
473 cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
476 uri += additionalQuery;
478 std::cout << "Request OBSERVE to resource " << uri.c_str() << std::endl;
480 OCStackResult res = OCDoResource(NULL, OC_REST_OBSERVE, uri.c_str(), NULL, NULL,
481 CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
483 std::cout << "Requesting OBSERVE res=" << res << std::endl;
486 OCStackApplicationResult putReqCB(void *ctx, OCDoHandle /*handle*/,
487 OCClientResponse *clientResponse)
489 std::cout << "Put response received from " << clientResponse->resourceUri << std::endl;
491 if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
493 std::cout << "Invalid Put callback received" << std::endl;
496 if (clientResponse->payload == NULL)
498 std::cout << "No payload received" << std::endl;
501 OCRepPayloadValue *val = ((OCRepPayload *)clientResponse->payload)->values;
503 PrintRepresentation(val);
505 std::string requestUri = g_host;
506 requestUri += clientResponse->resourceUri;
508 ObserveResource(requestUri, "");
510 return OC_STACK_KEEP_TRANSACTION;
513 OCPayload *putRequestPayload()
515 OCRepPayload *payload = OCRepPayloadCreate();
519 std::cout << "Failed to create put payload object" << std::endl;
523 OCRepPayloadSetPropInt(payload, "power", 15);
524 OCRepPayloadSetPropBool(payload, "state", true);
526 return (OCPayload *)payload;
529 void PutResource(std::string uri, std::string additionalQuery)
531 OCCallbackData cbData;
532 cbData.cb = putReqCB;
533 cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
536 uri += additionalQuery;
538 std::cout << "Request PUT to resource " << uri.c_str() << std::endl;
540 OCStackResult res = OCDoResource(NULL, OC_REST_PUT, uri.c_str(), NULL, putRequestPayload(),
541 CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
543 std::cout << "Requesting PUT res=" << res << std::endl;
546 OCStackApplicationResult handleGetCB(void *ctx,
547 OCDoHandle /*handle*/,
548 OCClientResponse *clientResponse)
550 std::cout << "Get response received from " << clientResponse->resourceUri << std::endl;
552 if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
554 std::cout << "Invalid Get callback received" << std::endl;
557 if (clientResponse->payload == NULL)
559 std::cout << "No payload received" << std::endl;
562 if (clientResponse->payload != NULL &&
563 clientResponse->payload->type == PAYLOAD_TYPE_REPRESENTATION)
565 OCRepPayloadValue *val = ((OCRepPayload *)clientResponse->payload)->values;
567 PrintRepresentation(val);
569 std::string requestUri = g_host;
570 requestUri += clientResponse->resourceUri;
572 PutResource(requestUri, "");
575 return OC_STACK_KEEP_TRANSACTION;
578 void GetResource(std::string uri, std::string additionalQuery)
580 OCCallbackData cbData;
581 cbData.cb = handleGetCB;
582 cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
585 uri += additionalQuery;
587 std::cout << "Request GET to resource " << uri.c_str() << std::endl;
589 OCStackResult res = OCDoResource(NULL, OC_REST_GET, uri.c_str(), NULL, NULL,
590 CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
592 std::cout << "Requesting GET res=" << res << std::endl;
595 // This is a function called back when a device is discovered
596 OCStackApplicationResult discoveryReqCB(void *ctx, OCDoHandle /*handle*/,
597 OCClientResponse *clientResponse)
599 if (ctx == (void *)DEFAULT_CONTEXT_VALUE)
601 std::cout << "Callback Context for DISCOVER query recvd successfully" << std::endl;
606 std::cout << "StackResult: " << clientResponse->result << std::endl;
608 OCDiscoveryPayload *payload = (OCDiscoveryPayload *)clientResponse->payload;
611 std::cout << "Empty payload" << std::endl;
612 return OC_STACK_DELETE_TRANSACTION;
615 OCResourcePayload *resource = (OCResourcePayload *)payload->resources;
618 std::cout << "No resources in payload" << std::endl;
619 return OC_STACK_DELETE_TRANSACTION;
624 std::cout << "Found Resource " << resource->uri << std::endl;
626 std::string requestUri = g_host;
627 requestUri += resource->uri;
629 GetResource(requestUri, "");
631 resource = resource->next;
636 std::cout << "discoveryReqCB received Null clientResponse" << std::endl;
638 return OC_STACK_KEEP_TRANSACTION;
641 void DiscoverResources(std::string host, std::string additionalQuery)
643 std::cout << "Running as Client mode" << std::endl;
645 std::string requestQuery = host;
646 requestQuery += DEFAULT_DISCOVER_QUERY;
647 requestQuery += additionalQuery;
649 std::cout << "Finding resources..." << std::endl;
650 std::cout << requestQuery.c_str() << std::endl;
652 OCCallbackData cbData;
654 cbData.cb = discoveryReqCB;
655 cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
658 if (OCDoResource(NULL, OC_REST_DISCOVER, requestQuery.c_str(), NULL, 0, CT_ADAPTER_TCP,
659 OC_LOW_QOS, &cbData, NULL, 0) != OC_STACK_OK)
661 std::cout << "Unable to find resources from cloud" << std::endl;
667 /////////////////////////////////////////////Common sample
669 int g_runningMode = 0;
671 OCStackApplicationResult handleLoginoutCB(void *ctx,
672 OCDoHandle /*handle*/,
673 OCClientResponse *clientResponse)
675 if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
677 std::cout << "Invalid Login/out callback received" << std::endl;
680 std::cout << "Login/out response received code: " << clientResponse->result << std::endl;
682 if (clientResponse->payload != NULL &&
683 clientResponse->payload->type == PAYLOAD_TYPE_REPRESENTATION)
685 std::cout << "PAYLOAD_TYPE_REPRESENTATION received" << std::endl;
687 OCRepPayloadValue *val = ((OCRepPayload *)clientResponse->payload)->values;
691 std::cout << "Key: " << val->name << " Value: " << val->str << std::endl;
695 if (g_runningMode == 1)
697 PublishResources(g_host, "");
699 else if (g_runningMode == 2)
701 DiscoverResources(g_host, "");
706 return OC_STACK_KEEP_TRANSACTION;
709 OCStackApplicationResult handleRegisterCB(void *ctx,
710 OCDoHandle /*handle*/,
711 OCClientResponse *clientResponse)
713 if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
715 std::cout << "Invalid Register callback received" << std::endl;
718 std::cout << "Register response received code: " << clientResponse->result << std::endl;
720 if (clientResponse->payload != NULL &&
721 clientResponse->payload->type == PAYLOAD_TYPE_REPRESENTATION)
723 std::cout << "PAYLOAD_TYPE_REPRESENTATION received" << std::endl;
724 std::cout << "You can login using received session variable after disconnected or reboot" <<
727 OCRepPayloadValue *val = ((OCRepPayload *)clientResponse->payload)->values;
731 std::cout << "Key: " << val->name << " Value: " << val->str << std::endl;
736 return OC_STACK_KEEP_TRANSACTION;
741 std::cout << std::endl;
742 std::cout << "Usage : cloud_device <addr:port> <session> <mode>\n";
743 std::cout << "<addr:port>: Cloud Address, \"127.0.0.1:5683\"\n";
745 "<session>: String value, Provided by response of onboarding scenario\n\tor kind of registration portal\n\n";
747 "<mode>: String value, 's' for publish resource, 'c' for start discovery\n\n";
749 "If you want to get session key using OAuth 2 auth code,\n\tleave blank to <session>, <mode> fields\n";
751 "sample: \"cloud_device 127.0.0.1:5683\"\n\t-OAuth 2 registration mode\n\n";
753 "sample: \"cloud_device 127.0.0.1:5683 1234567890123456 s\"\n\t-Publish resource under registered session\n\n";
755 "sample: \"cloud_device 127.0.0.1:5683 1234567890123456 c\"\n\t-Discover resource under registered session\n\n";
758 int main(int argc, char *argv[])
762 std::string authProvider;
763 std::string authCode;
765 OCMode stackMode = OC_CLIENT;
770 std::cout << "Put auth provider name(ex: github)" << std::endl;
771 std::cin >> authProvider;
772 std::cout << "Put auth code(provided by auth provider)" << std::endl;
773 std::cin >> authCode;
778 if (argv[3][0] == 's')
780 stackMode = OC_CLIENT_SERVER;
783 else if (argv[3][0] == 'c')
796 std::cout << "Host " << g_host.c_str() << std::endl;
798 if (OCInit(NULL, 0, stackMode) != OC_STACK_OK)
800 std::cout << "OCStack init error" << std::endl;
804 OCStackResult res = OC_STACK_ERROR;
809 std::cout << "Register account to cloud using " << authProvider << " " << authCode << std::endl;
810 res = OCCloudRegisterLogin(g_host.c_str(), authProvider.c_str(), authCode.c_str(),
812 std::cout << "OCCloudRegisterLogin return " << res << std::endl;
816 res = OCCloudLogin(g_host.c_str(), session.c_str(), handleLoginoutCB);
817 std::cout << "OCCloudLogin return " << res << std::endl;
825 std::cout << "Waiting response.." << std::endl;
829 if (OCProcess() != OC_STACK_OK)
831 std::cout << "OCProcess process error" << std::endl;
837 if (OCStop() != OC_STACK_OK)
839 std::cout << "OCStop process error" << std::endl;