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 "rd_client.h"
37 #include "OCPlatform.h"
41 #define VERIFY_SUCCESS(op) \
43 if (op != OC_STACK_OK) \
45 cout << #op << " failed!!" << endl; \
50 #define DEFAULT_CONTEXT_VALUE 0x99
51 #define DEFAULT_AUTH_SIGNUP "/oic/account"
52 #define DEFAULT_AUTH_SESSION "/oic/account/session"
53 #define DEFAULT_AUTH_REFRESH "/oic/account/tokenrefresh"
55 OCStackResult OCCloudSignup(const char *host, const char *deviceId, const char *authprovider,
56 const char *authcode, OCClientResponseHandler response)
58 char targetUri[MAX_URI_LENGTH * 2] =
60 snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, DEFAULT_AUTH_SIGNUP);
62 OCCallbackData cbData;
63 memset(&cbData, 0, sizeof(OCCallbackData));
66 cbData.context = (void *) DEFAULT_CONTEXT_VALUE;
68 OCRepPayload *registerPayload = OCRepPayloadCreate();
74 OCRepPayloadSetPropString(registerPayload, "di", deviceId);
75 OCRepPayloadSetPropString(registerPayload, "authprovider", authprovider);
76 OCRepPayloadSetPropString(registerPayload, "authcode", authcode);
78 return OCDoResource(NULL, OC_REST_POST, targetUri, NULL, (OCPayload *) registerPayload,
79 CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
82 OCRepPayloadDestroy(registerPayload);
83 return OC_STACK_NO_MEMORY;
86 OCStackResult OCCloudSession(const char *host, const char *query, const char *uId,
87 const char *deviceId, const char *accesstoken, bool isLogin,
88 OCClientResponseHandler response)
90 char targetUri[MAX_URI_LENGTH * 2] =
92 snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, query);
94 OCCallbackData cbData;
95 memset(&cbData, 0, sizeof(OCCallbackData));
98 cbData.context = (void *) DEFAULT_CONTEXT_VALUE;
100 OCRepPayload *loginoutPayload = OCRepPayloadCreate();
101 if (!loginoutPayload)
108 OCRepPayloadSetPropString(loginoutPayload, "uid", uId);
111 if (deviceId != NULL)
113 OCRepPayloadSetPropString(loginoutPayload, "di", deviceId);
116 if (accesstoken != NULL)
118 OCRepPayloadSetPropString(loginoutPayload, "accesstoken", accesstoken);
120 OCRepPayloadSetPropBool(loginoutPayload, "login", isLogin);
122 return OCDoResource(NULL, OC_REST_POST, targetUri, NULL, (OCPayload *) loginoutPayload,
123 CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
126 OCRepPayloadDestroy(loginoutPayload);
127 return OC_STACK_NO_MEMORY;
130 //Client should call refresh before expiresin or when receive 4.01 during sign-in
131 OCStackResult OCCloudRefresh(const char *host, const char *query, const char *uId,
132 const char *deviceId, const char *refreshtoken, OCClientResponseHandler response)
134 char targetUri[MAX_URI_LENGTH * 2] =
136 snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, query);
138 OCCallbackData cbData;
139 memset(&cbData, 0, sizeof(OCCallbackData));
140 cbData.cb = response;
142 cbData.context = (void *) DEFAULT_CONTEXT_VALUE;
144 OCRepPayload *refreshPayload = OCRepPayloadCreate();
150 OCRepPayloadSetPropString(refreshPayload, "uid", uId);
151 OCRepPayloadSetPropString(refreshPayload, "di", deviceId);
152 OCRepPayloadSetPropString(refreshPayload, "granttype", "refresh_token");
153 OCRepPayloadSetPropString(refreshPayload, "refreshtoken", refreshtoken);
155 return OCDoResource(NULL, OC_REST_POST, targetUri, NULL, (OCPayload *) refreshPayload,
156 CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
159 OCRepPayloadDestroy(refreshPayload);
160 return OC_STACK_NO_MEMORY;
163 OCStackResult OCCloudLogin(const char *host, const char *uId, const char *deviceId,
164 const char *accesstoken, OCClientResponseHandler response)
166 return OCCloudSession(host, DEFAULT_AUTH_SESSION, uId, deviceId, accesstoken, true, response);
169 OCStackResult OCCloudLogout(const char *host, OCClientResponseHandler response)
171 return OCCloudSession(host, DEFAULT_AUTH_SESSION, NULL, NULL, NULL, false, response);
174 ////////////////////////////////////////Device Sample
176 #define SAMPLE_MAX_NUM_POST_INSTANCE 1
177 typedef struct LIGHTRESOURCE
179 OCResourceHandle handle;
183 static LightResource gLightInstance[SAMPLE_MAX_NUM_POST_INSTANCE];
185 OCRepPayload *responsePayload(int64_t power, bool state)
187 OCRepPayload *payload = OCRepPayloadCreate();
190 cout << "Failed to allocate Payload" << endl;
194 OCRepPayloadSetPropBool(payload, "state", state);
195 OCRepPayloadSetPropInt(payload, "power", power);
200 OCRepPayload *constructResponse(OCEntityHandlerRequest *ehRequest)
202 if (ehRequest->payload && ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
204 cout << "Incoming payload not a representation" << endl;
208 LightResource *currLightResource = NULL;
210 if (ehRequest->resource == gLightInstance[0].handle)
212 currLightResource = &gLightInstance[0];
215 if (OC_REST_PUT == ehRequest->method)
217 // Get pointer to query
219 OCRepPayload *input = reinterpret_cast< OCRepPayload * >(ehRequest->payload);
221 if (OCRepPayloadGetPropInt(input, "power", &pow))
223 currLightResource->power = pow;
227 if (OCRepPayloadGetPropBool(input, "state", &state))
229 currLightResource->state = state;
233 return responsePayload(currLightResource->power, currLightResource->state);
236 OCEntityHandlerResult ProcessGetRequest(OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
238 OCRepPayload *getResp = constructResponse(ehRequest);
241 cout << "constructResponse failed" << endl;
250 OCEntityHandlerResult ProcessPutRequest(OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
252 OCEntityHandlerResult ehResult;
253 OCRepPayload *putResp = constructResponse(ehRequest);
257 cout << "Failed to construct Json response" << endl;
267 #define SAMPLE_MAX_NUM_OBSERVATIONS 2
268 static bool observeThreadStarted = false;
269 int gLightUnderObservation = 0;
270 pthread_t threadId_observe;
273 OCObservationId observationId;
275 OCResourceHandle resourceHandle;
277 Observers interestedObservers[SAMPLE_MAX_NUM_OBSERVATIONS];
279 void *ChangeLightRepresentation(void *param)
282 OCStackResult result = OC_STACK_ERROR;
287 gLightInstance[0].power += 1;
289 if (gLightUnderObservation)
291 cout << " =====> Notifying stack of new power level " << gLightInstance[0].power
293 // Notifying all observers
294 result = OCNotifyAllObservers(gLightInstance[0].handle, OC_NA_QOS);
296 cout << " =====> Notifying result " << result << endl;
302 void ProcessObserveRegister(OCEntityHandlerRequest *ehRequest)
304 cout << "Received observation registration request with observation Id "
305 << ehRequest->obsInfo.obsId << endl;
307 if (!observeThreadStarted)
309 pthread_create(&threadId_observe, NULL, ChangeLightRepresentation, (void *) NULL);
310 observeThreadStarted = 1;
312 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
314 if (interestedObservers[i].valid == false)
316 interestedObservers[i].observationId = ehRequest->obsInfo.obsId;
317 interestedObservers[i].valid = true;
318 gLightUnderObservation = 1;
324 void ProcessObserveDeregister(OCEntityHandlerRequest *ehRequest)
326 bool clientStillObserving = false;
328 cout << "Received observation deregistration request for observation Id "
329 << ehRequest->obsInfo.obsId << endl;
330 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
332 if (interestedObservers[i].observationId == ehRequest->obsInfo.obsId)
334 interestedObservers[i].valid = false;
336 if (interestedObservers[i].valid == true)
338 // Even if there is one single client observing we continue notifying entity handler
339 clientStillObserving = true;
342 if (clientStillObserving == false)
343 gLightUnderObservation = 0;
346 OCEntityHandlerResult OCEntityHandlerCb(OCEntityHandlerFlag flag,
347 OCEntityHandlerRequest *entityHandlerRequest, void * /*callback*/)
349 OCEntityHandlerResult ehResult = OC_EH_OK;
350 OCEntityHandlerResponse response =
352 0, 0, OC_EH_ERROR, 0, 0,
358 if (!entityHandlerRequest)
360 cout << "Invalid request pointer" << endl;
364 // Initialize certain response fields
365 response.numSendVendorSpecificHeaderOptions = 0;
366 memset(response.sendVendorSpecificHeaderOptions, 0,
367 sizeof response.sendVendorSpecificHeaderOptions);
368 memset(response.resourceUri, 0, sizeof response.resourceUri);
369 OCRepPayload *payload = nullptr;
371 if (flag & OC_REQUEST_FLAG)
373 cout << "Flag includes OC_REQUEST_FLAG" << endl;
375 if (OC_REST_GET == entityHandlerRequest->method)
377 cout << "Received OC_REST_GET from client" << endl;
378 ehResult = ProcessGetRequest(entityHandlerRequest, &payload);
380 else if (OC_REST_PUT == entityHandlerRequest->method)
382 cout << "Received OC_REST_PUT from client" << endl;
383 ehResult = ProcessPutRequest(entityHandlerRequest, &payload);
387 cout << "Received unsupported method %d from client " << entityHandlerRequest->method
389 ehResult = OC_EH_ERROR;
391 // If the result isn't an error or forbidden, send response
392 if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
394 // Format the response. Note this requires some info about the request
395 response.requestHandle = entityHandlerRequest->requestHandle;
396 response.resourceHandle = entityHandlerRequest->resource;
397 response.ehResult = ehResult;
398 response.payload = reinterpret_cast< OCPayload * >(payload);
399 // Indicate that response is NOT in a persistent buffer
400 response.persistentBufferFlag = 0;
403 if (OCDoResponse(&response) != OC_STACK_OK)
405 cout << "Error sending response" << endl;
406 ehResult = OC_EH_ERROR;
411 if (flag & OC_OBSERVE_FLAG)
413 cout << "Flag includes OC_OBSERVE_FLAG" << endl;
414 if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
416 cout << "Received OC_OBSERVE_REGISTER from client" << endl;
417 ProcessObserveRegister(entityHandlerRequest);
419 else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
421 cout << "Received OC_OBSERVE_DEREGISTER from client" << endl;
422 ProcessObserveDeregister(entityHandlerRequest);
426 OCPayloadDestroy(response.payload);
430 int createLightResource(char *uri, LightResource *lightResource)
434 cout << "Resource URI cannot be NULL" << endl;
438 lightResource->state = false;
439 lightResource->power = 0;
440 OCStackResult res = OCCreateResource(&(lightResource->handle), "core.light", "oc.mi.def", uri,
441 OCEntityHandlerCb, NULL, OC_DISCOVERABLE | OC_OBSERVABLE);
442 cout << "Created Light resource with result:" << res << endl;
447 OCStackApplicationResult handlePublishCB(void *ctx, OCDoHandle /*handle*/,
448 OCClientResponse *clientResponse)
450 if (ctx != (void *) DEFAULT_CONTEXT_VALUE)
452 cout << "Invalid Publish callback received" << endl;
455 cout << "Publish resource response received, code: " << clientResponse->result << endl;
457 return OC_STACK_KEEP_TRANSACTION;
460 OCStackResult SetDeviceInfo()
462 OCResourceHandle resourceHandle = OCGetResourceHandleAtUri(OC_RSRVD_DEVICE_URI);
463 if (resourceHandle == NULL)
465 cout << "Device Resource does not exist." << endl;
469 VERIFY_SUCCESS(OCBindResourceTypeToResource(resourceHandle, "oic.d.light"));
471 if (OCGetServerInstanceIDString() == NULL)
473 cout << "Device ID generation failed" << endl;
477 VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DEVICE_NAME, "Living Room Light"));
479 cout << "Device information published successfully." << endl;
483 return OC_STACK_ERROR;
486 void PublishResources(string host)
488 cout << "Publishing resources..." << endl;
490 if (createLightResource((char *) "/a/light/0", &gLightInstance[0]) != 0)
492 cout << "Unable to create sample resource" << endl;
495 OCResourceHandle resourceHandles[1] =
496 { gLightInstance[0].handle, };
497 OCCallbackData cbData;
498 cbData.cb = handlePublishCB;
499 cbData.context = (void *) DEFAULT_CONTEXT_VALUE;
502 cout << "Publishing default resources" << endl;
504 OCStackResult res = SetDeviceInfo();
506 if (res != OC_STACK_OK)
508 cout << "Publishing device info failed" << endl;
511 res = OCRDPublish(host.c_str(), CT_ADAPTER_TCP, NULL, 0, &cbData, OC_LOW_QOS);
512 if (res != OC_STACK_OK)
514 cout << "Unable to publish default resources to cloud" << endl;
517 cout << "Publishing user resources" << endl;
519 res = OCRDPublish(host.c_str(), CT_ADAPTER_TCP, resourceHandles, 1, &cbData, OC_LOW_QOS);
520 if (res != OC_STACK_OK)
522 cout << "Unable to publish user resources to cloud" << endl;
526 /////////////////////////////////////////////Common sample
527 void printRepresentation(OCRepPayloadValue *value)
531 cout << "Key: " << value->name;
534 case OCREP_PROP_NULL:
535 cout << " Value: None" << endl;
538 cout << " Value: " << value->i << endl;
540 case OCREP_PROP_DOUBLE:
541 cout << " Value: " << value->d << endl;
543 case OCREP_PROP_BOOL:
544 cout << " Value: " << value->b << endl;
546 case OCREP_PROP_STRING:
547 cout << " Value: " << value->str << endl;
549 case OCREP_PROP_BYTE_STRING:
550 cout << " Value: Byte String" << endl;
552 case OCREP_PROP_OBJECT:
553 cout << " Value: Object" << endl;
555 case OCREP_PROP_ARRAY:
556 cout << " Value: Array" << endl;
563 string g_host = "coap+tcp://";
565 OCStackApplicationResult handleLoginoutCB(void *ctx, OCDoHandle /*handle*/,
566 OCClientResponse *clientResponse)
568 if (ctx != (void *) DEFAULT_CONTEXT_VALUE)
570 cout << "Invalid Login/out callback received" << endl;
573 cout << "Login/out response received code: " << clientResponse->result << endl;
575 if (clientResponse->payload != NULL
576 && clientResponse->payload->type == PAYLOAD_TYPE_REPRESENTATION)
578 cout << "PAYLOAD_TYPE_REPRESENTATION received" << endl;
580 OCRepPayloadValue *val = ((OCRepPayload *) clientResponse->payload)->values;
582 printRepresentation(val);
585 if (clientResponse->result < 5)
587 PublishResources(g_host);
590 return OC_STACK_KEEP_TRANSACTION;
593 OCStackApplicationResult handleRegisterCB(void *ctx, OCDoHandle /*handle*/,
594 OCClientResponse *clientResponse)
596 if (ctx != (void *) DEFAULT_CONTEXT_VALUE)
598 cout << "Invalid Register callback received" << endl;
601 cout << "Register response received code: " << clientResponse->result << endl;
603 if (clientResponse->payload != NULL
604 && clientResponse->payload->type == PAYLOAD_TYPE_REPRESENTATION)
606 cout << "PAYLOAD_TYPE_REPRESENTATION received" << endl;
607 cout << "You can Sign-In using retrieved accesstoken when disconnected or reboot" << endl;
609 OCRepPayloadValue *val = ((OCRepPayload *) clientResponse->payload)->values;
611 printRepresentation(val);
614 return OC_STACK_KEEP_TRANSACTION;
620 cout << "Usage : thin_room_light <addr:port> <uid> <accesstoken>\n";
621 cout << "<addr:port>: Cloud Address, \"127.0.0.1:5683\"\n";
623 << "<accesstoken>: String value, Provided by response of onboarding scenario\n\tor kind of registration portal\n\n";
624 cout << "sample: \"thin_room_light 127.0.0.1:5683\"\n\t-Sign-Up mode\n\n";
626 << "sample: \"thin_room_light 127.0.0.1:5683 abcdefg 1234567890123456\"\n\t-Sign-in and Publish resource to registered account\n\n";
629 cout << "Usage : thin_room_light <addr:port> <uid> <refreshtoken> 1\n";
631 << "<refreshtoken>: String value, Provided by response of onboarding scenario\n\tor kind of registration portal\n\n";
633 << "sample: \"thin_room_light 127.0.0.1:5683 abcdefg 6543210987654321 1\"\n\t-token refresh and get renewed access token\n\n";
637 static FILE *client_open(const char * /*path*/, const char *mode)
639 return fopen("./thin_resource_server.dat", mode);
642 int main(int argc, char *argv[])
650 OCMode stackMode = OC_CLIENT_SERVER;
655 cout << "Put auth provider name(ex: github)" << endl;
657 cout << "Put auth code(provided by auth provider)" << endl;
663 accessToken = argv[3];
668 refreshToken = argv[3];
678 cout << "Host " << g_host.c_str() << endl;
680 OCPersistentStorage ps
681 { client_open, fread, fwrite, fclose, unlink };
682 if (OCRegisterPersistentStorageHandler(&ps) != OC_STACK_OK)
684 cout << "OCStack init persistent storage error" << endl;
688 if (OCInit(NULL, 0, stackMode) != OC_STACK_OK)
690 cout << "OCStack init error" << endl;
694 OCStackResult res = OC_STACK_ERROR;
699 cout << "Sign-Up to cloud using " << authProvider << " " << authCode << endl;
700 res = OCCloudSignup(g_host.c_str(), OCGetServerInstanceIDString(), authProvider.c_str(),
701 authCode.c_str(), handleRegisterCB);
702 cout << "OCCloudSignup return " << res << endl;
706 cout << "Sign-In to cloud using " << accessToken << endl;
707 res = OCCloudLogin(g_host.c_str(), uId.c_str(), OCGetServerInstanceIDString(),
708 accessToken.c_str(), handleLoginoutCB);
709 cout << "OCCloudLogin return " << res << endl;
713 cout << "Token refresh to cloud using the refresh token " << refreshToken << endl;
714 res = OCCloudRefresh(g_host.c_str(), DEFAULT_AUTH_REFRESH, uId.c_str(),
715 OCGetServerInstanceIDString(), refreshToken.c_str(), handleRegisterCB);
716 cout << "OCCloudRefresh return " << res << endl;
724 cout << "Waiting response.." << endl;
728 if (OCProcess() != OC_STACK_OK)
730 cout << "OCProcess process error" << endl;
736 if (OCStop() != OC_STACK_OK)
738 cout << "OCStop process error" << endl;