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"
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"
45 OCStackResult OCCloudSignup(const char *host, const char *deviceId, const char *authprovider,
46 const char *authcode, OCClientResponseHandler response)
48 char targetUri[MAX_URI_LENGTH * 2] =
50 snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, DEFAULT_AUTH_SIGNUP);
52 OCCallbackData cbData;
53 memset(&cbData, 0, sizeof(OCCallbackData));
56 cbData.context = (void *) DEFAULT_CONTEXT_VALUE;
58 OCRepPayload *registerPayload = OCRepPayloadCreate();
64 OCRepPayloadSetPropString(registerPayload, "di", deviceId);
65 OCRepPayloadSetPropString(registerPayload, "authprovider", authprovider);
66 OCRepPayloadSetPropString(registerPayload, "authcode", authcode);
68 return OCDoResource(NULL, OC_REST_POST, targetUri, NULL, (OCPayload *) registerPayload,
69 CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
72 OCRepPayloadDestroy(registerPayload);
73 return OC_STACK_NO_MEMORY;
76 OCStackResult OCCloudSession(const char *host, const char *query, const char *uId,
77 const char *deviceId, const char *accesstoken, bool isLogin,
78 OCClientResponseHandler response)
80 char targetUri[MAX_URI_LENGTH * 2] =
82 snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, query);
84 OCCallbackData cbData;
85 memset(&cbData, 0, sizeof(OCCallbackData));
88 cbData.context = (void *) DEFAULT_CONTEXT_VALUE;
90 OCRepPayload *loginoutPayload = OCRepPayloadCreate();
98 OCRepPayloadSetPropString(loginoutPayload, "uid", uId);
101 if (deviceId != NULL)
103 OCRepPayloadSetPropString(loginoutPayload, "di", deviceId);
106 if (accesstoken != NULL)
108 OCRepPayloadSetPropString(loginoutPayload, "accesstoken", accesstoken);
110 OCRepPayloadSetPropBool(loginoutPayload, "login", isLogin);
112 return OCDoResource(NULL, OC_REST_POST, targetUri, NULL, (OCPayload *) loginoutPayload,
113 CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
116 OCRepPayloadDestroy(loginoutPayload);
117 return OC_STACK_NO_MEMORY;
120 //Client should call refresh before expiresin or when receive 4.01 during sign-in
121 OCStackResult OCCloudRefresh(const char *host, const char *query, const char *uId,
122 const char *deviceId, const char *refreshtoken, OCClientResponseHandler response)
124 char targetUri[MAX_URI_LENGTH * 2] =
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];
175 OCRepPayload *responsePayload(int64_t power, bool state)
177 OCRepPayload *payload = OCRepPayloadCreate();
180 cout << "Failed to allocate Payload" << endl;
184 OCRepPayloadSetPropBool(payload, "state", state);
185 OCRepPayloadSetPropInt(payload, "power", power);
190 OCRepPayload *constructResponse(OCEntityHandlerRequest *ehRequest)
192 if (ehRequest->payload && ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
194 cout << "Incoming payload not a representation" << endl;
198 LightResource *currLightResource = NULL;
200 if (ehRequest->resource == gLightInstance[0].handle)
202 currLightResource = &gLightInstance[0];
205 if (OC_REST_PUT == ehRequest->method)
207 // Get pointer to query
209 OCRepPayload *input = reinterpret_cast< OCRepPayload * >(ehRequest->payload);
211 if (OCRepPayloadGetPropInt(input, "power", &pow))
213 currLightResource->power = pow;
217 if (OCRepPayloadGetPropBool(input, "state", &state))
219 currLightResource->state = state;
223 return responsePayload(currLightResource->power, currLightResource->state);
226 OCEntityHandlerResult ProcessGetRequest(OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
228 OCRepPayload *getResp = constructResponse(ehRequest);
231 cout << "constructResponse failed" << endl;
240 OCEntityHandlerResult ProcessPutRequest(OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
242 OCEntityHandlerResult ehResult;
243 OCRepPayload *putResp = constructResponse(ehRequest);
247 cout << "Failed to construct Json response" << endl;
257 #define SAMPLE_MAX_NUM_OBSERVATIONS 2
258 static bool observeThreadStarted = false;
259 int gLightUnderObservation = 0;
260 pthread_t threadId_observe;
263 OCObservationId observationId;
265 OCResourceHandle resourceHandle;
267 Observers interestedObservers[SAMPLE_MAX_NUM_OBSERVATIONS];
269 void *ChangeLightRepresentation(void *param)
272 OCStackResult result = OC_STACK_ERROR;
277 gLightInstance[0].power += 1;
279 if (gLightUnderObservation)
281 cout << " =====> Notifying stack of new power level " << gLightInstance[0].power
283 // Notifying all observers
284 result = OCNotifyAllObservers(gLightInstance[0].handle, OC_NA_QOS);
286 cout << " =====> Notifying result " << result << endl;
292 void ProcessObserveRegister(OCEntityHandlerRequest *ehRequest)
294 cout << "Received observation registration request with observation Id "
295 << ehRequest->obsInfo.obsId << endl;
297 if (!observeThreadStarted)
299 pthread_create(&threadId_observe, NULL, ChangeLightRepresentation, (void *) NULL);
300 observeThreadStarted = 1;
302 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
304 if (interestedObservers[i].valid == false)
306 interestedObservers[i].observationId = ehRequest->obsInfo.obsId;
307 interestedObservers[i].valid = true;
308 gLightUnderObservation = 1;
314 void ProcessObserveDeregister(OCEntityHandlerRequest *ehRequest)
316 bool clientStillObserving = false;
318 cout << "Received observation deregistration request for observation Id "
319 << ehRequest->obsInfo.obsId << endl;
320 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
322 if (interestedObservers[i].observationId == ehRequest->obsInfo.obsId)
324 interestedObservers[i].valid = false;
326 if (interestedObservers[i].valid == true)
328 // Even if there is one single client observing we continue notifying entity handler
329 clientStillObserving = true;
332 if (clientStillObserving == false)
333 gLightUnderObservation = 0;
336 OCEntityHandlerResult OCEntityHandlerCb(OCEntityHandlerFlag flag,
337 OCEntityHandlerRequest *entityHandlerRequest, void * /*callback*/)
339 OCEntityHandlerResult ehResult = OC_EH_OK;
340 OCEntityHandlerResponse response =
342 0, 0, OC_EH_ERROR, 0, 0,
348 if (!entityHandlerRequest)
350 cout << "Invalid request pointer" << endl;
354 // Initialize certain response fields
355 response.numSendVendorSpecificHeaderOptions = 0;
356 memset(response.sendVendorSpecificHeaderOptions, 0,
357 sizeof response.sendVendorSpecificHeaderOptions);
358 memset(response.resourceUri, 0, sizeof response.resourceUri);
359 OCRepPayload *payload = nullptr;
361 if (flag & OC_REQUEST_FLAG)
363 cout << "Flag includes OC_REQUEST_FLAG" << endl;
365 if (OC_REST_GET == entityHandlerRequest->method)
367 cout << "Received OC_REST_GET from client" << endl;
368 ehResult = ProcessGetRequest(entityHandlerRequest, &payload);
370 else if (OC_REST_PUT == entityHandlerRequest->method)
372 cout << "Received OC_REST_PUT from client" << endl;
373 ehResult = ProcessPutRequest(entityHandlerRequest, &payload);
377 cout << "Received unsupported method %d from client " << entityHandlerRequest->method
379 ehResult = OC_EH_ERROR;
381 // If the result isn't an error or forbidden, send response
382 if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
384 // Format the response. Note this requires some info about the request
385 response.requestHandle = entityHandlerRequest->requestHandle;
386 response.resourceHandle = entityHandlerRequest->resource;
387 response.ehResult = ehResult;
388 response.payload = reinterpret_cast< OCPayload * >(payload);
389 // Indicate that response is NOT in a persistent buffer
390 response.persistentBufferFlag = 0;
393 if (OCDoResponse(&response) != OC_STACK_OK)
395 cout << "Error sending response" << endl;
396 ehResult = OC_EH_ERROR;
401 if (flag & OC_OBSERVE_FLAG)
403 cout << "Flag includes OC_OBSERVE_FLAG" << endl;
404 if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
406 cout << "Received OC_OBSERVE_REGISTER from client" << endl;
407 ProcessObserveRegister(entityHandlerRequest);
409 else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
411 cout << "Received OC_OBSERVE_DEREGISTER from client" << endl;
412 ProcessObserveDeregister(entityHandlerRequest);
416 OCPayloadDestroy(response.payload);
420 int createLightResource(char *uri, LightResource *lightResource)
424 cout << "Resource URI cannot be NULL" << endl;
428 lightResource->state = false;
429 lightResource->power = 0;
430 OCStackResult res = OCCreateResource(&(lightResource->handle), "core.light", "oc.mi.def", uri,
431 OCEntityHandlerCb, NULL, OC_DISCOVERABLE | OC_OBSERVABLE);
432 cout << "Created Light resource with result:" << res << endl;
437 OCStackApplicationResult handlePublishCB(void *ctx, OCDoHandle /*handle*/,
438 OCClientResponse *clientResponse)
440 if (ctx != (void *) DEFAULT_CONTEXT_VALUE)
442 cout << "Invalid Publish callback received" << endl;
445 cout << "Publish resource response received, code: " << clientResponse->result << endl;
447 return OC_STACK_KEEP_TRANSACTION;
450 void PublishResources(string host)
452 cout << "Publishing resources..." << endl;
454 if (createLightResource((char *) "/a/light/0", &gLightInstance[0]) != 0)
456 cout << "Unable to create sample resource" << endl;
459 OCResourceHandle resourceHandles[1] =
460 { gLightInstance[0].handle, };
461 OCCallbackData cbData;
462 cbData.cb = handlePublishCB;
463 cbData.context = (void *) DEFAULT_CONTEXT_VALUE;
466 cout << "Publish default resources" << endl;
468 OCDeviceInfo devInfoRoomLight;
469 OCStringLL deviceType;
471 deviceType.value = "oic.d.light";
472 deviceType.next = NULL;
473 devInfoRoomLight.deviceName = "Living Room Light";
474 devInfoRoomLight.types = &deviceType;
475 devInfoRoomLight.specVersion = NULL;
476 devInfoRoomLight.dataModelVersions = NULL;
478 OCStackResult res = OCSetDeviceInfo(devInfoRoomLight);
480 if (res != OC_STACK_OK)
482 cout << "Setting device info failed" << endl;
485 res = OCRDPublish(nullptr, host.c_str(), CT_ADAPTER_TCP, NULL, 0, &cbData, OC_LOW_QOS);
486 if (res != OC_STACK_OK)
488 cout << "Unable to publish default resources to cloud" << endl;
491 cout << "Publish user resources" << endl;
493 res = OCRDPublish(nullptr, host.c_str(), CT_ADAPTER_TCP, resourceHandles, 1, &cbData, OC_LOW_QOS);
494 if (res != OC_STACK_OK)
496 cout << "Unable to publish user resources to cloud" << endl;
500 /////////////////////////////////////////////Common sample
501 void printRepresentation(OCRepPayloadValue *value)
505 cout << "Key: " << value->name;
508 case OCREP_PROP_NULL:
509 cout << " Value: None" << endl;
512 cout << " Value: " << value->i << endl;
514 case OCREP_PROP_DOUBLE:
515 cout << " Value: " << value->d << endl;
517 case OCREP_PROP_BOOL:
518 cout << " Value: " << value->b << endl;
520 case OCREP_PROP_STRING:
521 cout << " Value: " << value->str << endl;
523 case OCREP_PROP_BYTE_STRING:
524 cout << " Value: Byte String" << endl;
526 case OCREP_PROP_OBJECT:
527 cout << " Value: Object" << endl;
529 case OCREP_PROP_ARRAY:
530 cout << " Value: Array" << endl;
537 string g_host = "coap+tcp://";
539 OCStackApplicationResult handleLoginoutCB(void *ctx, OCDoHandle /*handle*/,
540 OCClientResponse *clientResponse)
542 if (ctx != (void *) DEFAULT_CONTEXT_VALUE)
544 cout << "Invalid Login/out callback received" << endl;
547 cout << "Login/out response received code: " << clientResponse->result << endl;
549 if (clientResponse->payload != NULL
550 && clientResponse->payload->type == PAYLOAD_TYPE_REPRESENTATION)
552 cout << "PAYLOAD_TYPE_REPRESENTATION received" << endl;
554 OCRepPayloadValue *val = ((OCRepPayload *) clientResponse->payload)->values;
556 printRepresentation(val);
559 if (clientResponse->result < 5)
561 PublishResources(g_host);
564 return OC_STACK_KEEP_TRANSACTION;
567 OCStackApplicationResult handleRegisterCB(void *ctx, OCDoHandle /*handle*/,
568 OCClientResponse *clientResponse)
570 if (ctx != (void *) DEFAULT_CONTEXT_VALUE)
572 cout << "Invalid Register callback received" << endl;
575 cout << "Register response received code: " << clientResponse->result << endl;
577 if (clientResponse->payload != NULL
578 && clientResponse->payload->type == PAYLOAD_TYPE_REPRESENTATION)
580 cout << "PAYLOAD_TYPE_REPRESENTATION received" << endl;
581 cout << "You can Sign-In using retrieved accesstoken when disconnected or reboot" << endl;
583 OCRepPayloadValue *val = ((OCRepPayload *) clientResponse->payload)->values;
585 printRepresentation(val);
588 return OC_STACK_KEEP_TRANSACTION;
594 cout << "Usage : thin_room_light <addr:port> <uid> <accesstoken>\n";
595 cout << "<addr:port>: Cloud Address, \"127.0.0.1:5683\"\n";
597 << "<accesstoken>: String value, Provided by response of onboarding scenario\n\tor kind of registration portal\n\n";
598 cout << "sample: \"thin_room_light 127.0.0.1:5683\"\n\t-Sign-Up mode\n\n";
600 << "sample: \"thin_room_light 127.0.0.1:5683 abcdefg 1234567890123456\"\n\t-Sign-in and Publish resource to registered account\n\n";
603 cout << "Usage : thin_room_light <addr:port> <uid> <refreshtoken> 1\n";
605 << "<refreshtoken>: String value, Provided by response of onboarding scenario\n\tor kind of registration portal\n\n";
607 << "sample: \"thin_room_light 127.0.0.1:5683 abcdefg 6543210987654321 1\"\n\t-token refresh and get renewed access token\n\n";
611 static FILE *client_open(const char * /*path*/, const char *mode)
613 return fopen("./thin_resource_server.dat", mode);
616 int main(int argc, char *argv[])
624 OCMode stackMode = OC_CLIENT_SERVER;
629 cout << "Put auth provider name(ex: github)" << endl;
631 cout << "Put auth code(provided by auth provider)" << endl;
637 accessToken = argv[3];
642 refreshToken = argv[3];
652 cout << "Host " << g_host.c_str() << endl;
654 OCPersistentStorage ps
655 { client_open, fread, fwrite, fclose, unlink };
656 if (OCRegisterPersistentStorageHandler(&ps) != OC_STACK_OK)
658 cout << "OCStack init persistent storage error" << endl;
662 if (OCInit(NULL, 0, stackMode) != OC_STACK_OK)
664 cout << "OCStack init error" << endl;
668 OCStackResult res = OC_STACK_ERROR;
673 cout << "Sign-Up to cloud using " << authProvider << " " << authCode << endl;
674 res = OCCloudSignup(g_host.c_str(), OCGetServerInstanceIDString(), authProvider.c_str(),
675 authCode.c_str(), handleRegisterCB);
676 cout << "OCCloudSignup return " << res << endl;
680 cout << "Sign-In to cloud using " << accessToken << endl;
681 res = OCCloudLogin(g_host.c_str(), uId.c_str(), OCGetServerInstanceIDString(),
682 accessToken.c_str(), handleLoginoutCB);
683 cout << "OCCloudLogin return " << res << endl;
687 cout << "Token refresh to cloud using the refresh token " << refreshToken << endl;
688 res = OCCloudRefresh(g_host.c_str(), DEFAULT_AUTH_REFRESH, uId.c_str(),
689 OCGetServerInstanceIDString(), refreshToken.c_str(), handleRegisterCB);
690 cout << "OCCloudRefresh return " << res << endl;
698 cout << "Waiting response.." << endl;
702 if (OCProcess() != OC_STACK_OK)
704 cout << "OCProcess process error" << endl;
710 if (OCStop() != OC_STACK_OK)
712 cout << "OCStop process error" << endl;