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"
36 #include "oicresourcedirectory.h"
40 #define DEFAULT_CONTEXT_VALUE 0x99
41 #define DEFAULT_AUTH_SIGNUP "/oic/account"
42 #define DEFAULT_AUTH_SESSION "/oic/account/session"
43 #define DEFAULT_AUTH_REFRESH "/oic/account/tokenrefresh"
46 OCStackResult OCCloudSignup(const char *host, const char *deviceId,
47 const char *authprovider,
48 const char *authcode, OCClientResponseHandler response)
50 char targetUri[MAX_URI_LENGTH * 2] = { 0, };
51 snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, DEFAULT_AUTH_SIGNUP);
53 OCCallbackData cbData;
54 memset(&cbData, 0, sizeof(OCCallbackData));
57 cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
59 OCRepPayload *registerPayload = OCRepPayloadCreate();
65 OCRepPayloadSetPropString(registerPayload, "di", deviceId);
66 OCRepPayloadSetPropString(registerPayload, "authprovider", authprovider);
67 OCRepPayloadSetPropString(registerPayload, "authcode", authcode);
69 return OCDoResource(NULL, OC_REST_POST, targetUri, NULL, (OCPayload *)registerPayload,
70 CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
73 OCRepPayloadDestroy(registerPayload);
74 return OC_STACK_NO_MEMORY;
77 OCStackResult OCCloudSession(const char *host, const char *query, const char *uId,
79 const char *accesstoken,
80 bool isLogin, OCClientResponseHandler response)
82 char targetUri[MAX_URI_LENGTH * 2] = { 0, };
83 snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, query);
85 OCCallbackData cbData;
86 memset(&cbData, 0, sizeof(OCCallbackData));
89 cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
91 OCRepPayload *loginoutPayload = OCRepPayloadCreate();
99 OCRepPayloadSetPropString(loginoutPayload, "uid", uId);
102 if (deviceId != NULL)
104 OCRepPayloadSetPropString(loginoutPayload, "di", deviceId);
107 if (accesstoken != NULL)
109 OCRepPayloadSetPropString(loginoutPayload, "accesstoken", accesstoken);
111 OCRepPayloadSetPropBool(loginoutPayload, "login", isLogin);
113 return OCDoResource(NULL, OC_REST_POST, targetUri, NULL, (OCPayload *)loginoutPayload,
114 CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
117 OCRepPayloadDestroy(loginoutPayload);
118 return OC_STACK_NO_MEMORY;
121 //Client should call refresh before expiresin or when receive 4.01 during sign-in
122 OCStackResult OCCloudRefresh(const char *host, const char *query, const char *uId,
123 const char *deviceId, const char *refreshtoken, OCClientResponseHandler response)
125 char targetUri[MAX_URI_LENGTH * 2] = { 0, };
126 snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, query);
128 OCCallbackData cbData;
129 memset(&cbData, 0, sizeof(OCCallbackData));
130 cbData.cb = response;
132 cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
134 OCRepPayload *refreshPayload = OCRepPayloadCreate();
140 OCRepPayloadSetPropString(refreshPayload, "uid", uId);
141 OCRepPayloadSetPropString(refreshPayload, "di", deviceId);
142 OCRepPayloadSetPropString(refreshPayload, "granttype", "refresh_token");
143 OCRepPayloadSetPropString(refreshPayload, "refreshtoken", refreshtoken);
145 return OCDoResource(NULL, OC_REST_POST, targetUri, NULL, (OCPayload *)refreshPayload,
146 CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
149 OCRepPayloadDestroy(refreshPayload);
150 return OC_STACK_NO_MEMORY;
153 OCStackResult OCCloudLogin(const char *host, const char *uId, const char *deviceId,
154 const char *accesstoken, OCClientResponseHandler response)
156 return OCCloudSession(host, DEFAULT_AUTH_SESSION, uId, deviceId, accesstoken, true, response);
159 OCStackResult OCCloudLogout(const char *host, OCClientResponseHandler response)
161 return OCCloudSession(host, DEFAULT_AUTH_SESSION, NULL, NULL, NULL, false, response);
164 ////////////////////////////////////////Device Sample
166 #define SAMPLE_MAX_NUM_POST_INSTANCE 1
167 typedef struct LIGHTRESOURCE
169 OCResourceHandle handle;
173 static LightResource gLightInstance[SAMPLE_MAX_NUM_POST_INSTANCE];
176 OCRepPayload *responsePayload(int64_t power, bool state)
178 OCRepPayload *payload = OCRepPayloadCreate();
181 cout << "Failed to allocate Payload" << endl;
185 OCRepPayloadSetPropBool(payload, "state", state);
186 OCRepPayloadSetPropInt(payload, "power", power);
191 OCRepPayload *constructResponse(OCEntityHandlerRequest *ehRequest)
193 if (ehRequest->payload && ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
195 cout << "Incoming payload not a representation" << endl;
199 LightResource *currLightResource = NULL;
201 if (ehRequest->resource == gLightInstance[0].handle)
203 currLightResource = &gLightInstance[0];
205 else if (ehRequest->resource == gLightInstance[1].handle)
207 currLightResource = &gLightInstance[1];
210 if (OC_REST_PUT == ehRequest->method)
212 // Get pointer to query
214 OCRepPayload *input = reinterpret_cast<OCRepPayload *>(ehRequest->payload);
216 if (OCRepPayloadGetPropInt(input, "power", &pow))
218 currLightResource->power = pow;
222 if (OCRepPayloadGetPropBool(input, "state", &state))
224 currLightResource->state = state;
228 return responsePayload(currLightResource->power, currLightResource->state);
231 OCEntityHandlerResult ProcessGetRequest(OCEntityHandlerRequest *ehRequest,
232 OCRepPayload **payload)
234 OCRepPayload *getResp = constructResponse(ehRequest);
237 cout << "constructResponse failed" << endl;
246 OCEntityHandlerResult ProcessPutRequest(OCEntityHandlerRequest *ehRequest,
247 OCRepPayload **payload)
249 OCEntityHandlerResult ehResult;
250 OCRepPayload *putResp = constructResponse(ehRequest);
254 cout << "Failed to construct Json response" << endl;
264 #define SAMPLE_MAX_NUM_OBSERVATIONS 2
265 static bool observeThreadStarted = false;
266 int gLightUnderObservation = 0;
267 pthread_t threadId_observe;
270 OCObservationId observationId;
272 OCResourceHandle resourceHandle;
274 Observers interestedObservers[SAMPLE_MAX_NUM_OBSERVATIONS];
276 void *ChangeLightRepresentation(void *param)
279 OCStackResult result = OC_STACK_ERROR;
284 gLightInstance[0].power += 1;
285 gLightInstance[1].power += 3;
287 if (gLightUnderObservation)
289 cout << " =====> Notifying stack of new power level " << gLightInstance[0].power << endl;
290 cout << " =====> Notifying stack of new power level " << gLightInstance[1].power << endl;
291 // Notifying all observers
292 result = OCNotifyAllObservers(gLightInstance[0].handle, OC_NA_QOS);
293 result = OCNotifyAllObservers(gLightInstance[1].handle, OC_NA_QOS);
295 cout << " =====> Notifying result " << result << endl;
301 void ProcessObserveRegister(OCEntityHandlerRequest *ehRequest)
303 cout << "Received observation registration request with observation Id " <<
304 ehRequest->obsInfo.obsId << endl;
306 if (!observeThreadStarted)
308 pthread_create(&threadId_observe, NULL, ChangeLightRepresentation, (void *)NULL);
309 observeThreadStarted = 1;
311 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
313 if (interestedObservers[i].valid == false)
315 interestedObservers[i].observationId = ehRequest->obsInfo.obsId;
316 interestedObservers[i].valid = true;
317 gLightUnderObservation = 1;
323 void ProcessObserveDeregister(OCEntityHandlerRequest *ehRequest)
325 bool clientStillObserving = false;
327 cout << "Received observation deregistration request for observation Id " <<
328 ehRequest->obsInfo.obsId << endl;
329 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
331 if (interestedObservers[i].observationId == ehRequest->obsInfo.obsId)
333 interestedObservers[i].valid = false;
335 if (interestedObservers[i].valid == true)
337 // Even if there is one single client observing we continue notifying entity handler
338 clientStillObserving = true;
341 if (clientStillObserving == false)
342 gLightUnderObservation = 0;
345 OCEntityHandlerResult
346 OCEntityHandlerCb(OCEntityHandlerFlag flag,
347 OCEntityHandlerRequest *entityHandlerRequest, void * /*callback*/)
349 OCEntityHandlerResult ehResult = OC_EH_OK;
350 OCEntityHandlerResponse response = { 0, 0, OC_EH_ERROR, 0, 0, {}, { 0 }, false };
353 if (!entityHandlerRequest)
355 cout << "Invalid request pointer" << endl;
359 // Initialize certain response fields
360 response.numSendVendorSpecificHeaderOptions = 0;
361 memset(response.sendVendorSpecificHeaderOptions,
362 0, sizeof response.sendVendorSpecificHeaderOptions);
363 memset(response.resourceUri, 0, sizeof response.resourceUri);
364 OCRepPayload *payload = nullptr;
366 if (flag & OC_REQUEST_FLAG)
368 cout << "Flag includes OC_REQUEST_FLAG" << endl;
370 if (OC_REST_GET == entityHandlerRequest->method)
372 cout << "Received OC_REST_GET from client" << endl;
373 ehResult = ProcessGetRequest(entityHandlerRequest, &payload);
375 else if (OC_REST_PUT == entityHandlerRequest->method)
377 cout << "Received OC_REST_PUT from client" << endl;
378 ehResult = ProcessPutRequest(entityHandlerRequest, &payload);
382 cout << "Received unsupported method %d from client " << entityHandlerRequest->method <<
384 ehResult = OC_EH_ERROR;
386 // If the result isn't an error or forbidden, send response
387 if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
389 // Format the response. Note this requires some info about the request
390 response.requestHandle = entityHandlerRequest->requestHandle;
391 response.resourceHandle = entityHandlerRequest->resource;
392 response.ehResult = ehResult;
393 response.payload = reinterpret_cast<OCPayload *>(payload);
394 // Indicate that response is NOT in a persistent buffer
395 response.persistentBufferFlag = 0;
398 if (OCDoResponse(&response) != OC_STACK_OK)
400 cout << "Error sending response" << endl;
401 ehResult = OC_EH_ERROR;
406 if (flag & OC_OBSERVE_FLAG)
408 cout << "Flag includes OC_OBSERVE_FLAG" << endl;
409 if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
411 cout << "Received OC_OBSERVE_REGISTER from client" << endl;
412 ProcessObserveRegister(entityHandlerRequest);
414 else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
416 cout << "Received OC_OBSERVE_DEREGISTER from client" << endl;
417 ProcessObserveDeregister(entityHandlerRequest);
421 OCPayloadDestroy(response.payload);
425 int createLightResource(char *uri, LightResource *lightResource)
429 cout << "Resource URI cannot be NULL" << endl;
433 lightResource->state = false;
434 lightResource->power = 0;
435 OCStackResult res = OCCreateResource(&(lightResource->handle),
441 OC_DISCOVERABLE | OC_OBSERVABLE);
442 cout << "Created Light resource with result:" << res << endl;
447 OCStackApplicationResult handlePublishCB(void *ctx,
448 OCDoHandle /*handle*/,
449 OCClientResponse *clientResponse)
451 if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
453 cout << "Invalid Publish callback received" << endl;
456 cout << "Publish resource response received, code: " << clientResponse->result << endl;
458 return OC_STACK_KEEP_TRANSACTION;
461 void PublishResources(string host)
463 cout << "Publishing resources..." << endl;
465 if (createLightResource((char *)"/a/light/0", &gLightInstance[0]) != 0)
467 cout << "Unable to create sample resource" << endl;
470 OCResourceHandle resourceHandles[1] = { gLightInstance[0].handle,
472 OCCallbackData cbData;
473 cbData.cb = handlePublishCB;
474 cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
477 cout << "Publish default resources" << endl;
479 OCDeviceInfo devInfoRoomLight;
480 OCStringLL deviceType;
482 deviceType.value = "oic.d.light";
483 deviceType.next = NULL;
484 devInfoRoomLight.deviceName = "Living Room Light";
485 devInfoRoomLight.types = &deviceType;
486 devInfoRoomLight.specVersion = NULL;
487 devInfoRoomLight.dataModelVersions = NULL;
489 OCStackResult res = OCSetDeviceInfo(devInfoRoomLight);
491 if (res != OC_STACK_OK)
493 cout << "Setting device info failed" << endl;
496 res = OCRDPublish(host.c_str(), CT_ADAPTER_TCP, NULL, 0, &cbData,
498 if (res != OC_STACK_OK)
500 cout << "Unable to publish default resources to cloud" << endl;
503 cout << "Publish user resources" << endl;
505 res = OCRDPublish(host.c_str(), CT_ADAPTER_TCP, resourceHandles, 1, &cbData,
507 if (res != OC_STACK_OK)
509 cout << "Unable to publish user resources to cloud" << endl;
513 /////////////////////////////////////////////Common sample
514 void printRepresentation(OCRepPayloadValue *value)
518 cout << "Key: " << value->name;
521 case OCREP_PROP_NULL:
522 cout << " Value: None" << endl;
525 cout << " Value: " << value->i << endl;
527 case OCREP_PROP_DOUBLE:
528 cout << " Value: " << value->d << endl;
530 case OCREP_PROP_BOOL:
531 cout << " Value: " << value->b << endl;
533 case OCREP_PROP_STRING:
534 cout << " Value: " << value->str << endl;
536 case OCREP_PROP_BYTE_STRING:
537 cout << " Value: Byte String" << endl;
539 case OCREP_PROP_OBJECT:
540 cout << " Value: Object" << endl;
542 case OCREP_PROP_ARRAY:
543 cout << " Value: Array" << endl;
550 string g_host = "coap+tcp://";
552 OCStackApplicationResult handleLoginoutCB(void *ctx,
553 OCDoHandle /*handle*/,
554 OCClientResponse *clientResponse)
556 if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
558 cout << "Invalid Login/out callback received" << endl;
561 cout << "Login/out response received code: " << clientResponse->result << endl;
563 if (clientResponse->payload != NULL &&
564 clientResponse->payload->type == PAYLOAD_TYPE_REPRESENTATION)
566 cout << "PAYLOAD_TYPE_REPRESENTATION received" << endl;
568 OCRepPayloadValue *val = ((OCRepPayload *)clientResponse->payload)->values;
570 printRepresentation(val);
573 if (clientResponse->result < 5)
575 PublishResources(g_host);
578 return OC_STACK_KEEP_TRANSACTION;
581 OCStackApplicationResult handleRegisterCB(void *ctx,
582 OCDoHandle /*handle*/,
583 OCClientResponse *clientResponse)
585 if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
587 cout << "Invalid Register callback received" << endl;
590 cout << "Register response received code: " << clientResponse->result << endl;
592 if (clientResponse->payload != NULL &&
593 clientResponse->payload->type == PAYLOAD_TYPE_REPRESENTATION)
595 cout << "PAYLOAD_TYPE_REPRESENTATION received" << endl;
596 cout << "You can Sign-In using retrieved accesstoken when disconnected or reboot" <<
599 OCRepPayloadValue *val = ((OCRepPayload *)clientResponse->payload)->values;
601 printRepresentation(val);
604 return OC_STACK_KEEP_TRANSACTION;
610 cout << "Usage : thin_cloud_device <addr:port> <uid> <accesstoken>\n";
611 cout << "<addr:port>: Cloud Address, \"127.0.0.1:5683\"\n";
613 "<accesstoken>: String value, Provided by response of onboarding scenario\n\tor kind of registration portal\n\n";
615 "sample: \"cloud_device 127.0.0.1:5683\"\n\t-Sign-Up mode\n\n";
617 "sample: \"cloud_device 127.0.0.1:5683 abcdefg 1234567890123456\"\n\t-Sign-in and Publish resource to registered account\n\n";
620 static FILE *client_open(const char * /*path*/, const char *mode)
622 return fopen("./thin_resource_server.dat", mode);
625 int main(int argc, char *argv[])
633 OCMode stackMode = OC_CLIENT_SERVER;
638 cout << "Put auth provider name(ex: github)" << endl;
640 cout << "Put auth code(provided by auth provider)" << endl;
646 accessToken = argv[3];
656 cout << "Host " << g_host.c_str() << endl;
658 OCPersistentStorage ps{ client_open, fread, fwrite, fclose, unlink };
659 if (OCRegisterPersistentStorageHandler(&ps) != OC_STACK_OK)
661 cout << "OCStack init persistent storage error" << endl;
665 if (OCInit(NULL, 0, stackMode) != OC_STACK_OK)
667 cout << "OCStack init error" << endl;
671 OCStackResult res = OC_STACK_ERROR;
676 cout << "Sign-Up to cloud using " << authProvider << " " << authCode << endl;
677 res = OCCloudSignup(g_host.c_str(), OCGetServerInstanceIDString(), authProvider.c_str(),
678 authCode.c_str(), handleRegisterCB);
679 cout << "OCCloudSignup return " << res << endl;
683 cout << "Sign-In to cloud using " << accessToken << endl;
684 res = OCCloudLogin(g_host.c_str(), uId.c_str(), OCGetServerInstanceIDString(), accessToken.c_str(),
686 cout << "OCCloudLogin return " << res << endl;
696 cout << "Waiting response.." << endl;
700 if (OCProcess() != OC_STACK_OK)
702 cout << "OCProcess process error" << endl;
708 if (OCStop() != OC_STACK_OK)
710 cout << "OCStop process error" << endl;