IOT-2258: Allow secure and nonsecure endpoints with OCCreateResource.
[iotivity.git] / resource / csdk / resource-directory / src / rd_client.c
1 //******************************************************************
2 //
3 // Copyright 2016 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
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 a
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
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.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20 #include "rd_client.h"
21
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <inttypes.h>
26
27 #include "oic_malloc.h"
28 #include "oic_string.h"
29 #include "octypes.h"
30 #include "ocstack.h"
31 #include "ocpayload.h"
32 #include "ocendpoint.h"
33 #include "payload_logging.h"
34 #include "cainterface.h"
35
36 #define TAG "OIC_RD_CLIENT"
37
38 #ifdef RD_CLIENT
39
40 OCStackResult OCRDDiscover(OCDoHandle *handle, OCConnectivityType connectivityType,
41                            OCCallbackData *cbBiasFactor, OCQualityOfService qos)
42 {
43     if (!cbBiasFactor || !cbBiasFactor->cb)
44     {
45         OIC_LOG(DEBUG, TAG, "No callback function specified.");
46         return OC_STACK_INVALID_CALLBACK;
47     }
48
49     /* Start a discovery query*/
50     char queryUri[MAX_URI_LENGTH] = { '\0' };
51     snprintf(queryUri, MAX_URI_LENGTH, "coap://%s%s", OC_MULTICAST_PREFIX, OC_RSRVD_RD_URI);
52     OIC_LOG_V(DEBUG, TAG, "Querying RD: %s\n", queryUri);
53
54     return OCDoResource(handle, OC_REST_DISCOVER, queryUri, NULL, NULL, connectivityType, qos,
55                         cbBiasFactor, NULL, 0);
56 }
57
58 static void RDPublishContextDeleter(void *ctx)
59 {
60     OCCallbackData *cbData = (OCCallbackData*)ctx;
61     if (cbData->cd)
62     {
63         cbData->cd(cbData->context);
64     }
65     OICFree(cbData);
66 }
67
68 OCStackApplicationResult RDPublishCallback(void *ctx,
69                                            OCDoHandle handle,
70                                            OCClientResponse *clientResponse)
71 {
72     OCCallbackData *cbData = (OCCallbackData*)ctx;
73
74     // Update resource unique id in stack.
75     OCRepPayload **links = NULL;
76     size_t dimensions[MAX_REP_ARRAY_DEPTH] = {0};
77     if (clientResponse && clientResponse->payload)
78     {
79         OCRepPayload *rdPayload = (OCRepPayload *) clientResponse->payload;
80         if (!OCRepPayloadGetPropObjectArray(rdPayload, OC_RSRVD_LINKS, &links, dimensions))
81         {
82             OIC_LOG(DEBUG, TAG, "No links in publish response");
83             goto exit;
84         }
85         for(size_t i = 0; i < dimensions[0]; i++)
86         {
87             char *uri = NULL;
88             if (!OCRepPayloadGetPropString(links[i], OC_RSRVD_HREF, &uri))
89             {
90                 OIC_LOG(ERROR, TAG, "Missing 'href' in publish response");
91                 goto next;
92             }
93             OCResourceHandle handle = OCGetResourceHandleAtUri(uri);
94             if (handle == NULL)
95             {
96                 OIC_LOG_V(ERROR, TAG, "No resource exists with uri: %s", uri);
97                 goto next;
98             }
99             int64_t ins = 0;
100             if (!OCRepPayloadGetPropInt(links[i], OC_RSRVD_INS, &ins))
101             {
102                 OIC_LOG(ERROR, TAG, "Missing 'ins' in publish response");
103                 goto next;
104             }
105             OCBindResourceInsToResource(handle, ins);
106         next:
107             OICFree(uri);
108         }
109     }
110
111 exit:
112     for (size_t i = 0; i < dimensions[0]; i++)
113     {
114         OCRepPayloadDestroy(links[i]);
115     }
116     OICFree(links);
117     return cbData->cb(cbData->context, handle, clientResponse);
118 }
119
120 OCStackResult OCRDPublish(OCDoHandle *handle, const char *host,
121                           OCConnectivityType connectivityType,
122                           OCResourceHandle *resourceHandles, uint8_t nHandles,
123                           OCCallbackData *cbData, OCQualityOfService qos)
124 {
125     // Validate input parameters.
126     if (!host)
127     {
128         return OC_STACK_INVALID_IP;
129     }
130
131     if (!cbData || !cbData->cb)
132     {
133         return OC_STACK_INVALID_CALLBACK;
134     }
135
136     // Get Device ID from stack.
137     const unsigned char *id = (const unsigned char *) OCGetServerInstanceIDString();
138
139     return OCRDPublishWithDeviceId(handle, host, id, connectivityType, resourceHandles, nHandles,
140                                    cbData, qos);
141 }
142
143 static OCRepPayload *RDPublishPayloadCreate(const unsigned char *id,
144         const OCResourceHandle *resourceHandles, uint8_t nHandles)
145 {
146     assert(id);
147
148     OCStackResult result = OC_STACK_ERROR;
149     OCRepPayload *rdPayload = NULL;
150     size_t dim[MAX_REP_ARRAY_DEPTH] = {0};
151     CAEndpoint_t *caEps = NULL;
152     size_t nCaEps = 0;
153     OCRepPayload **eps = NULL;
154
155     rdPayload =  (OCRepPayload *)OCRepPayloadCreate();
156     if (!rdPayload)
157     {
158         OIC_LOG(ERROR, TAG, "Memory allocation failed!");
159         goto exit;
160     }
161
162     // Common properties
163     dim[0] = 1;
164     char **rts = (char **)OICCalloc(dim[0], sizeof(char *));
165     if (!rts)
166     {
167         OIC_LOG(ERROR, TAG, "Memory allocation failed!");
168         goto exit;
169     }
170     rts[0] = OICStrdup(OC_RSRVD_RESOURCE_TYPE_RES);
171     OCRepPayloadSetStringArrayAsOwner(rdPayload, OC_RSRVD_RESOURCE_TYPE, rts, dim);
172
173     dim[0] = 2;
174     char **ifs = (char **)OICCalloc(dim[0], sizeof(char *));
175     if (!ifs)
176     {
177         OIC_LOG(ERROR, TAG, "Memory allocation failed!");
178         goto exit;
179     }
180     ifs[0] = OICStrdup(OC_RSRVD_INTERFACE_LL);
181     ifs[1] = OICStrdup(OC_RSRVD_INTERFACE_DEFAULT);
182     OCRepPayloadSetStringArrayAsOwner(rdPayload, OC_RSRVD_INTERFACE, ifs, dim);
183
184     char *n;
185     OCGetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DEVICE_NAME, (void **) &n);
186     if (n)
187     {
188         OCRepPayloadSetPropStringAsOwner(rdPayload, OC_RSRVD_DEVICE_NAME, n);
189     }
190
191     // oic.wk.rdpub properties
192     OCRepPayloadSetPropString(rdPayload, OC_RSRVD_DEVICE_ID, (const char*) id);
193     OCRepPayloadSetPropInt(rdPayload, OC_RSRVD_DEVICE_TTL, OIC_RD_PUBLISH_TTL);
194
195     dim[0] = nHandles;
196     OCRepPayload **links = (OCRepPayload **)OICCalloc(dim[0], sizeof(OCRepPayload *));
197     if (!links)
198     {
199         goto exit;
200     }
201     OCRepPayloadSetPropObjectArrayAsOwner(rdPayload, OC_RSRVD_LINKS, links, dim);
202     for (uint8_t j = 0; j < nHandles; j++)
203     {
204         OCResourceHandle handle = resourceHandles[j];
205         if (handle)
206         {
207             links[j] = OCRepPayloadCreate();
208
209             const char *uri = OCGetResourceUri(handle);
210             if (uri)
211             {
212                 OCRepPayloadSetPropString(links[j], OC_RSRVD_HREF, uri);
213             }
214
215             uint8_t n;
216             if (OC_STACK_OK == OCGetNumberOfResourceTypes(handle, &n))
217             {
218                 dim[0] = n;
219                 char **rts = (char **)OICCalloc(n, sizeof(char *));
220                 for (uint8_t i = 0; i < n; i++)
221                 {
222                     rts[i] = OICStrdup(OCGetResourceTypeName(handle, i));
223                     OIC_LOG_V(DEBUG, TAG, "value: %s", rts[i]);
224                 }
225                 OCRepPayloadSetStringArrayAsOwner(links[j], OC_RSRVD_RESOURCE_TYPE, rts, dim);
226             }
227
228             if (OC_STACK_OK == OCGetNumberOfResourceInterfaces(handle, &n))
229             {
230                 dim[0] = n;
231                 char **ifs = (char **)OICCalloc(n, sizeof(char *));
232                 for (uint8_t i = 0; i < n; i++)
233                 {
234                     ifs[i] = OICStrdup(OCGetResourceInterfaceName(handle, i));
235                     OIC_LOG_V(DEBUG, TAG, "value: %s", ifs[i]);
236                 }
237                 OCRepPayloadSetStringArrayAsOwner(links[j], OC_RSRVD_INTERFACE, ifs, dim);
238             }
239
240             // rel is always the default ("hosts")
241
242             char anchor[MAX_URI_LENGTH];
243             snprintf(anchor, MAX_URI_LENGTH, "ocf://%s", id);
244             OCRepPayloadSetPropString(links[j], OC_RSRVD_URI, anchor);
245
246             int64_t ins;
247             if (OC_STACK_OK == OCGetResourceIns(handle, &ins))
248             {
249                 OCRepPayloadSetPropInt(links[j], OC_RSRVD_INS, ins);
250             }
251
252             OCResourceProperty p = OCGetResourceProperties(handle);
253             bool includeSecure = (p & OC_SECURE);
254             bool includeNonsecure = (p & OC_NONSECURE);
255             p &= (OC_DISCOVERABLE | OC_OBSERVABLE);
256             OCRepPayload *policy = OCRepPayloadCreate();
257             if (!policy)
258             {
259                 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
260                 goto exit;
261             }
262             OCRepPayloadSetPropInt(policy, OC_RSRVD_BITMAP, p);
263             OCRepPayloadSetPropObjectAsOwner(links[j], OC_RSRVD_POLICY, policy);
264
265             CAResult_t caResult = CAGetNetworkInformation(&caEps, &nCaEps);
266             if (CA_STATUS_FAILED == caResult)
267             {
268                 OIC_LOG(ERROR, TAG, "CAGetNetworkInformation failed!");
269                 goto exit;
270             }
271             if (nCaEps)
272             {
273                 eps = (OCRepPayload **)OICCalloc(nCaEps, sizeof(OCRepPayload *));
274                 if (!eps)
275                 {
276                     OIC_LOG(ERROR, TAG, "Memory allocation failed!");
277                     goto exit;
278                 }
279                 uint32_t k = 0;
280                 for (size_t i = 0; i < nCaEps; i++)
281                 {
282                     bool isSecure = (caEps[i].flags & OC_FLAG_SECURE);
283                     if ((isSecure && includeSecure) || (!isSecure && includeNonsecure))
284                     {
285                         char *epStr = OCCreateEndpointStringFromCA(&caEps[i]);
286                         if (!epStr)
287                         {
288                             OIC_LOG(INFO, TAG, "Create endpoint string failed!");
289                             continue;
290                         }
291                         eps[k] = OCRepPayloadCreate();
292                         if (!eps[k])
293                         {
294                             OIC_LOG(ERROR, TAG, "Memory allocation failed!");
295                             OICFree(epStr);
296                             break;
297                         }
298                         OCRepPayloadSetPropStringAsOwner(eps[k], OC_RSRVD_ENDPOINT, epStr);
299                         OCRepPayloadSetPropInt(eps[k], OC_RSRVD_PRIORITY, 1);
300                         ++k;
301                     }
302                 }
303                 dim[0] = k;
304                 OCRepPayloadSetPropObjectArrayAsOwner(links[j], OC_RSRVD_ENDPOINTS, eps, dim);
305             }
306         }
307     }
308
309     OIC_LOG_PAYLOAD(DEBUG, (OCPayload *) rdPayload);
310     result = OC_STACK_OK;
311
312 exit:
313     OICFree(caEps);
314     if (OC_STACK_OK != result)
315     {
316         OCRepPayloadDestroy(rdPayload);
317         rdPayload = NULL;
318     }
319     return rdPayload;
320 }
321
322 OCStackResult OCRDPublishWithDeviceId(OCDoHandle *handle, const char *host,
323                                       const unsigned char *id,
324                                       OCConnectivityType connectivityType,
325                                       OCResourceHandle *resourceHandles, uint8_t nHandles,
326                                       OCCallbackData *cbData, OCQualityOfService qos)
327 {
328     // Validate input parameters.
329     if (!host || !cbData || !cbData->cb || !id)
330     {
331         return OC_STACK_INVALID_CALLBACK;
332     }
333
334     OIC_LOG_V(DEBUG, TAG, "Publish Resource to RD with device id [%s]", id);
335
336     OCStackResult result = OC_STACK_OK;
337     OCHeaderOption options[2];
338     size_t numOptions = 0;
339     uint16_t format = COAP_MEDIATYPE_APPLICATION_VND_OCF_CBOR;
340
341     result = OCSetHeaderOption(options, &numOptions, CA_OPTION_CONTENT_FORMAT, &format, sizeof(format));
342     if (OC_STACK_OK != result)
343     {
344         return result;
345     }
346
347     result = OCSetHeaderOption(options, &numOptions, CA_OPTION_ACCEPT, &format, sizeof(format));
348     if (OC_STACK_OK != result)
349     {
350         return result;
351     }
352
353     OCResourceHandle *pubResHandle = resourceHandles;
354     OCResourceHandle defaultResHandles[OIC_RD_DEFAULT_RESOURCE] = { 0 };
355     uint8_t nPubResHandles = nHandles;
356
357     // if resource handles is null, "/oic/p" and "/oic/d" resource will be published to RD.
358     if (!pubResHandle)
359     {
360         // get "/oic/d" and "/oic/p" resource handle from stack.
361         defaultResHandles[0] = OCGetResourceHandleAtUri(OC_RSRVD_DEVICE_URI);
362         defaultResHandles[1] = OCGetResourceHandleAtUri(OC_RSRVD_PLATFORM_URI);
363
364         for (uint8_t j = 0; j < OIC_RD_DEFAULT_RESOURCE; j++)
365         {
366             if (defaultResHandles[j])
367             {
368                 OIC_LOG_V(DEBUG, TAG, "Add virtual resource(%s) to resource handle list",
369                           OCGetResourceUri(defaultResHandles[j]));
370             }
371         }
372
373         pubResHandle = defaultResHandles;
374         nPubResHandles = OIC_RD_DEFAULT_RESOURCE;
375     }
376
377     char targetUri[MAX_URI_LENGTH] = { 0 };
378     snprintf(targetUri, MAX_URI_LENGTH, "%s%s?rt=%s", host,
379              OC_RSRVD_RD_URI, OC_RSRVD_RESOURCE_TYPE_RDPUBLISH);
380     OIC_LOG_V(DEBUG, TAG, "Target URI: %s", targetUri);
381
382     OCRepPayload *rdPayload = RDPublishPayloadCreate(id, pubResHandle, nPubResHandles);
383     if (!rdPayload)
384     {
385         return OC_STACK_ERROR;
386     }
387
388     OCCallbackData *rdPublishContext = (OCCallbackData*)OICMalloc(sizeof(OCCallbackData));
389     if (!rdPublishContext)
390     {
391         return OC_STACK_NO_MEMORY;
392     }
393     memcpy(rdPublishContext, cbData, sizeof(OCCallbackData));
394     OCCallbackData rdPublishCbData;
395     rdPublishCbData.context = rdPublishContext;
396     rdPublishCbData.cb = RDPublishCallback;
397     rdPublishCbData.cd = RDPublishContextDeleter;
398
399     return OCDoResource(handle, OC_REST_POST, targetUri, NULL, (OCPayload *)rdPayload,
400                         connectivityType, qos, &rdPublishCbData, options, (uint8_t)numOptions);
401 }
402
403 OCStackResult OCRDDelete(OCDoHandle *handle, const char *host,
404                          OCConnectivityType connectivityType,
405                          OCResourceHandle *resourceHandles, uint8_t nHandles,
406                          OCCallbackData *cbData, OCQualityOfService qos)
407 {
408     // Validate input parameters
409     if (!host)
410     {
411         return OC_STACK_INVALID_IP;
412     }
413
414     if (!cbData || !cbData->cb)
415     {
416         return OC_STACK_INVALID_CALLBACK;
417     }
418
419     const unsigned char *id = (const unsigned char *) OCGetServerInstanceIDString();
420
421     return OCRDDeleteWithDeviceId(handle, host, id, connectivityType, resourceHandles, nHandles,
422                                   cbData, qos);
423 }
424
425 OCStackResult OCRDDeleteWithDeviceId(OCDoHandle *handle, const char *host,
426                                      const unsigned char *id,
427                                      OCConnectivityType connectivityType,
428                                      OCResourceHandle *resourceHandles, uint8_t nHandles,
429                                      OCCallbackData *cbData, OCQualityOfService qos)
430 {
431     // Validate input parameters
432     if (!host || !cbData || !cbData->cb || !id)
433     {
434         return OC_STACK_INVALID_CALLBACK;
435     }
436
437     OIC_LOG_V(DEBUG, TAG, "Delete Resource to RD with device id [%s]", id);
438
439     char targetUri[MAX_URI_LENGTH] = { 0 };
440     int targetUriBufferRequired = snprintf(targetUri, MAX_URI_LENGTH, "%s%s?di=%s", host, OC_RSRVD_RD_URI, id);
441     if (targetUriBufferRequired >= MAX_URI_LENGTH || targetUriBufferRequired < 0)
442     {
443         return OC_STACK_INVALID_URI;
444     }
445
446
447     int queryLength = 0;
448     char queryParam[MAX_URI_LENGTH] = { 0 };
449     for (uint8_t j = 0; j < nHandles; j++)
450     {
451         OCResource *handle = (OCResource *) resourceHandles[j];
452         int64_t ins = 0;
453         OCGetResourceIns(handle, &ins);
454         int lenBufferRequired = snprintf((queryParam + queryLength),
455                                          (MAX_URI_LENGTH - queryLength), "&ins=%" PRId64, ins);
456         if (lenBufferRequired >= (MAX_URI_LENGTH - queryLength) || lenBufferRequired < 0)
457         {
458             return OC_STACK_INVALID_URI;
459         }
460         queryLength += lenBufferRequired;
461         OIC_LOG_V(DEBUG, TAG, "queryParam [%s]", queryParam);
462     }
463
464     if (targetUriBufferRequired + queryLength + 1 > MAX_URI_LENGTH)
465     {
466         return OC_STACK_INVALID_URI;
467     }
468
469     OICStrcatPartial(targetUri, sizeof(targetUri), queryParam, strlen(queryParam));
470     OIC_LOG_V(DEBUG, TAG, "Target URI: %s", targetUri);
471
472     return OCDoResource(handle, OC_REST_DELETE, targetUri, NULL, NULL, connectivityType,
473                         qos, cbData, NULL, 0);
474 }
475 #endif