RD client features in base layer
[platform/upstream/iotivity.git] / resource / csdk / stack / src / rdpayload.c
1 //******************************************************************
2 //
3 // Copyright 2015 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 at
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 "rdpayload.h"
21
22 #include "oic_malloc.h"
23 #include "oic_string.h"
24 #include "octypes.h"
25 #include "ocstack.h"
26 #include "ocpayload.h"
27 #include "payload_logging.h"
28
29 #define TAG "OIC_RI_RDPAYLOAD"
30
31 #define CBOR_ROOT_ARRAY_LENGTH 1
32
33 static int64_t OCTagsPayloadToCbor(OCTagsPayload *tags, CborEncoder *setMap);
34 static int64_t OCLinksPayloadToCbor(OCLinksPayload *links, CborEncoder *setMap);
35 static int64_t ConditionalAddTextStringToMap(CborEncoder* map, const char* key, const char *value);
36 static int64_t ConditionalAddIntToMap(CborEncoder *map, const char *tags, const uint64_t *value);
37 static int64_t AddStringLLToMap(CborEncoder *map, const char *tag, const OCStringLL *value);
38 static CborError OCTagsCborToPayload(CborValue *tagsMap, OCTagsPayload **tagsPayload);
39 static CborError OCLinksCborToPayload(CborValue *linksArray, OCLinksPayload **linksPayload);
40 static CborError FindStringInMap(const CborValue *map, const char *tags, char **value);
41 static CborError FindIntInMap(const CborValue *map, const char *tags, uint64_t *value);
42 static CborError FindStringLLInMap(const CborValue *linksMap, const char *tag, OCStringLL **links);
43 static OCStackResult CreateStringLL(uint8_t numElements, OCResourceHandle handle,
44                                     const char* (*getValue)(OCResourceHandle handle, uint8_t i),
45                                     OCStringLL **stringLL);
46
47 int64_t OCRDPayloadToCbor(const OCRDPayload *rdPayload, uint8_t *outPayload, size_t *size)
48 {
49     int64_t cborEncoderResult = CborNoError;
50     int flags = 0;
51     CborEncoder encoder;
52     VERIFY_PARAM_NON_NULL(TAG, rdPayload, "Invalid input parameter rdPayload");
53     VERIFY_PARAM_NON_NULL(TAG, outPayload, "Invalid input parameter outPayload");
54     VERIFY_PARAM_NON_NULL(TAG, size, "Invalid input parameter size");
55
56     cbor_encoder_init(&encoder, outPayload, *size, flags);
57
58     if (rdPayload->rdDiscovery)
59     {
60         CborEncoder map;
61         cborEncoderResult |= cbor_encoder_create_map(&encoder, &map, CborIndefiniteLength);
62         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to create discovery map");
63
64         cborEncoderResult |= ConditionalAddTextStringToMap(&map, OC_RSRVD_DEVICE_NAME,
65             rdPayload->rdDiscovery->n.deviceName);
66         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add OC_RSRVD_DEVICE_NAME in map");
67
68         cborEncoderResult |= ConditionalAddTextStringToMap(&map, OC_RSRVD_DEVICE_ID,
69             (char *)rdPayload->rdDiscovery->di.id);
70         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add OC_RSRVD_DEVICE_ID in map");
71
72         {
73             uint64_t value = rdPayload->rdDiscovery->sel;
74             cborEncoderResult |= ConditionalAddIntToMap(&map, OC_RSRVD_RD_DISCOVERY_SEL, &value);
75             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add RD_DISCOVERY_SEL in map");
76         }
77         cborEncoderResult |= cbor_encoder_close_container(&encoder, &map);
78         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing discovery map");
79     }
80     else if (rdPayload->rdPublish)
81     {
82         CborEncoder collMap;
83         cborEncoderResult |= cbor_encoder_create_map(&encoder, &collMap, CborIndefiniteLength);
84         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to create collection map");
85
86         OCResourceCollectionPayload *rdPublish = rdPayload->rdPublish;
87         cborEncoderResult |= OCTagsPayloadToCbor(rdPublish->tags, &collMap);
88         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding tags payload");
89         cborEncoderResult |= OCLinksPayloadToCbor(rdPublish->setLinks, &collMap);
90         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding setLinks payload");
91
92         cborEncoderResult |= cbor_encoder_close_container(&encoder, &collMap);
93         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing collection map");
94     }
95     else
96     {
97         CborEncoder map;
98         cborEncoderResult |= cbor_encoder_create_map(&encoder, &map, CborIndefiniteLength);
99         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed entering discovery map");
100         cborEncoderResult |= cbor_encoder_close_container(&encoder, &map);
101         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing discovery map");
102     }
103
104     if (cborEncoderResult == CborErrorOutOfMemory)
105     {
106         *size += encoder.ptr - encoder.end;
107     }
108     else
109     {
110         *size = encoder.ptr - outPayload;
111     }
112
113     return cborEncoderResult;
114
115 exit:
116     OICFree(outPayload);
117     return cborEncoderResult;
118 }
119
120 static int64_t OCTagsPayloadToCbor(OCTagsPayload *tags, CborEncoder *setMap)
121 {
122     int64_t cborEncoderResult = CborNoError;
123
124     cborEncoderResult |= ConditionalAddTextStringToMap(setMap, OC_RSRVD_DEVICE_NAME,
125         tags->n.deviceName);
126     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add OC_RSRVD_DEVICE_NAME in tags map");
127
128     cborEncoderResult |= ConditionalAddTextStringToMap(setMap, OC_RSRVD_DEVICE_ID,
129         (char *)tags->di.id);
130     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add OC_RSRVD_DEVICE_ID in tags map");
131
132     cborEncoderResult |= ConditionalAddIntToMap(setMap, OC_RSRVD_DEVICE_TTL, &tags->ttl);
133     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add OC_RSRVD_TTL in tags map");
134 exit:
135     return cborEncoderResult;
136 }
137
138 static int64_t OCLinksPayloadToCbor(OCLinksPayload *links, CborEncoder *setMap)
139 {
140     CborEncoder linksArray;
141     int64_t cborEncoderResult = CborNoError;
142
143     cborEncoderResult |= cbor_encode_text_string(setMap, OC_RSRVD_LINKS,
144         sizeof(OC_RSRVD_LINKS) - 1);
145
146     cborEncoderResult |= cbor_encoder_create_array(setMap, &linksArray, CborIndefiniteLength);
147     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to create Links array");
148
149     while (links)
150     {
151         CborEncoder linksMap;
152         cborEncoderResult |= cbor_encoder_create_map(&linksArray, &linksMap, CborIndefiniteLength);
153         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to create links map");
154
155         cborEncoderResult |= ConditionalAddTextStringToMap(&linksMap, OC_RSRVD_HREF, links->href);
156         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add OC_RSRVD_HREF in links map");
157
158         cborEncoderResult |= ConditionalAddTextStringToMap(&linksMap, OC_RSRVD_REL, links->rel);
159         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add OC_RSRVD_REL in links map");
160
161         cborEncoderResult |= AddStringLLToMap(&linksMap, OC_RSRVD_RESOURCE_TYPE, links->rt);
162         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add OC_RSRVD_RT in links map");
163
164         cborEncoderResult |= AddStringLLToMap(&linksMap, OC_RSRVD_INTERFACE, links->itf);
165         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add OC_RSRVD_ITF in links map");
166
167         // Policy
168         CborEncoder policyMap;
169         cborEncoderResult |= cbor_encode_text_string(&linksMap, OC_RSRVD_POLICY,
170             sizeof(OC_RSRVD_POLICY) - 1);
171         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding policy tag to links map");
172         cborEncoderResult |= cbor_encoder_create_map(&linksMap, &policyMap, CborIndefiniteLength);
173         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding policy map to links map");
174
175         // Bitmap
176         cborEncoderResult |= cbor_encode_text_string(&policyMap, OC_RSRVD_BITMAP,
177             sizeof(OC_RSRVD_BITMAP) - 1);
178         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding bitmap tag to policy map");
179         cborEncoderResult |= cbor_encode_uint(&policyMap, links->p);
180         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding bitmap value to policy map");
181
182         cborEncoderResult |= cbor_encoder_close_container(&linksMap, &policyMap);
183         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing policy map");
184
185         cborEncoderResult |= ConditionalAddTextStringToMap(&linksMap, OC_RSRVD_TITLE, links->title);
186         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add OC_RSRVD_TITLE in links map");
187
188         cborEncoderResult |= ConditionalAddTextStringToMap(&linksMap, OC_RSRVD_URI, links->anchor);
189         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add OC_RSRVD_URI in links map");
190
191         cborEncoderResult |= ConditionalAddIntToMap(&linksMap, OC_RSRVD_INS, (uint64_t *) &links->ins);
192         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add OC_RSRVD_INS in links map");
193
194         cborEncoderResult |= ConditionalAddIntToMap(&linksMap, OC_RSRVD_TTL, &links->ttl);
195         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add OC_RSRVD_TTL in links map");
196
197         cborEncoderResult |= AddStringLLToMap(&linksMap, OC_RSRVD_MEDIA_TYPE, links->type);
198         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add OC_RSRVD_MT in links map");
199
200         // Finsihed encoding a resource, close the map.
201         cborEncoderResult |= cbor_encoder_close_container(&linksArray, &linksMap);
202         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing links map");
203
204         links = links->next;
205     }
206     cborEncoderResult |= cbor_encoder_close_container(setMap, &linksArray);
207     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing links array");
208
209 exit:
210     return cborEncoderResult;
211 }
212
213 OCStackResult OCRDCborToPayload(const CborValue *cborPayload, OCPayload **outPayload)
214 {
215     CborValue *rdCBORPayload = (CborValue *)cborPayload;
216     OCStackResult ret = OC_STACK_NO_MEMORY;
217     CborError cborFindResult;
218
219     OCRDPayload *rdPayload = OCRDPayloadCreate();
220     VERIFY_PARAM_NON_NULL(TAG, rdPayload, "Failed allocating rdPayload");
221
222     ret = OC_STACK_MALFORMED_RESPONSE;
223
224     if (cbor_value_is_map(rdCBORPayload))
225     {
226         // rdCBORPayload is already inside the main root map.
227         OCTagsPayload *tagsPayload = NULL;
228         OCLinksPayload *linksPayload = NULL;
229
230         cborFindResult = OCTagsCborToPayload(rdCBORPayload, &tagsPayload);
231         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed parsing tags payload.");
232
233         cborFindResult = OCLinksCborToPayload(rdCBORPayload, &linksPayload);
234         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed parsing links payload.");
235
236         // Move from tags payload to links array.
237         cborFindResult = cbor_value_advance(rdCBORPayload);
238         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing rdCborPayload.");
239
240         rdPayload->rdPublish = OCCopyCollectionResource(tagsPayload, linksPayload);
241         VERIFY_PARAM_NON_NULL(TAG, rdPayload->rdPublish, "Failed allocating rdPayload->rdPublish");
242     }
243     // TODO: This logic needs to be modified to check the payload type exactly..
244     else if (cbor_value_is_map(rdCBORPayload))
245     {
246         rdPayload->rdDiscovery = (OCRDDiscoveryPayload *)OICCalloc(1, sizeof(OCRDDiscoveryPayload));
247         VERIFY_PARAM_NON_NULL(TAG, rdPayload->rdDiscovery, "Failed allocating discoveryPayload");
248
249         cborFindResult = FindStringInMap(rdCBORPayload, OC_RSRVD_DEVICE_NAME,
250                                          &rdPayload->rdDiscovery->n.deviceName);
251         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding OC_RSRVD_DEVICE_NAME.");
252         char *deviceId = NULL;
253         cborFindResult = FindStringInMap(rdCBORPayload, OC_RSRVD_DEVICE_ID, &deviceId);
254         if (deviceId)
255         {
256             memcpy(rdPayload->rdDiscovery->di.id, deviceId, strlen(deviceId));
257             OICFree(deviceId);
258         }
259         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding OC_RSRVD_DEVICE_ID.");
260
261         {
262             uint64_t value = 0;
263             cborFindResult = FindIntInMap(rdCBORPayload, OC_RSRVD_RD_DISCOVERY_SEL, &value);
264             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding OC_RSRVD_RD_DISCOVERY_SEL.");
265             rdPayload->rdDiscovery->sel = value;
266         }
267
268         cborFindResult =  cbor_value_advance(rdCBORPayload);
269         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing rdCBORPayload.");
270     }
271     OIC_LOG_PAYLOAD(DEBUG, (OCPayload *) rdPayload);
272     *outPayload = (OCPayload *)rdPayload;
273     return OC_STACK_OK;
274
275 exit:
276     OCRDPayloadDestroy(rdPayload);
277     return ret;
278 }
279
280 static CborError FindStringInMap(const CborValue *map, const char *tags, char **value)
281 {
282     CborValue curVal;
283     CborError cborFindResult = cbor_value_map_find_value(map, tags, &curVal);
284     if (CborNoError == cborFindResult && cbor_value_is_text_string(&curVal))
285     {
286         size_t len = 0;
287         cborFindResult = cbor_value_dup_text_string(&curVal, value, &len, NULL);
288     }
289     return cborFindResult;
290 }
291
292 static CborError FindIntInMap(const CborValue *map, const char *tags, uint64_t *value)
293 {
294     CborValue curVal;
295     CborError cborFindResult = cbor_value_map_find_value(map, tags, &curVal);
296     if (CborNoError == cborFindResult && cbor_value_is_unsigned_integer(&curVal))
297     {
298         cborFindResult = cbor_value_get_uint64(&curVal, value);
299     }
300     return cborFindResult;
301 }
302
303 static CborError FindStringLLInMap(const CborValue *linksMap, const char *tag, OCStringLL **links)
304 {
305     size_t len;
306     CborValue rtArray;
307     OCStringLL* llPtr = *links;
308     CborError cborFindResult = cbor_value_map_find_value(linksMap, tag, &rtArray);
309     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding tag");
310
311     CborValue rtVal;
312     cborFindResult = cbor_value_enter_container(&rtArray, &rtVal);
313     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed entering container");
314
315     while (cbor_value_is_text_string(&rtVal))
316     {
317         if (llPtr == NULL)
318         {
319             llPtr = (OCStringLL *)OICCalloc(1, sizeof(OCStringLL));
320             VERIFY_PARAM_NON_NULL(TAG, llPtr, "Failed allocating OCStringLL");
321             *links = llPtr;
322         }
323         else if (llPtr)
324         {
325             while (llPtr->next)
326             {
327                 llPtr = llPtr->next;
328             }
329             llPtr->next = (OCStringLL *)OICCalloc(1, sizeof(OCStringLL));
330             llPtr = llPtr->next;
331             VERIFY_PARAM_NON_NULL(TAG, llPtr, "Failed allocating OCStringLL->next");
332         }
333         cborFindResult = cbor_value_dup_text_string(&rtVal, &(llPtr->value), &len, NULL);
334         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed duplicating value");
335         cborFindResult = cbor_value_advance(&rtVal);
336         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing OCStringLL");
337     }
338
339     cborFindResult = cbor_value_leave_container(&rtArray, &rtVal);
340     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed leaving container");
341
342 exit:
343     return cborFindResult;
344 }
345
346 static CborError OCTagsCborToPayload(CborValue *tagsMap, OCTagsPayload **tagsPayload)
347 {
348     CborError cborFindResult = CborErrorOutOfMemory;
349     OCTagsPayload *tags = (OCTagsPayload *)OICCalloc(1, sizeof(OCTagsPayload));
350     VERIFY_PARAM_NON_NULL(TAG, tags, "Failed allocating tags");
351
352     cborFindResult = FindStringInMap(tagsMap, OC_RSRVD_DEVICE_NAME, &tags->n.deviceName);
353     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding deviceName");
354
355     {
356         char *deviceId = NULL;
357         cborFindResult = FindStringInMap(tagsMap, OC_RSRVD_DEVICE_ID, &deviceId);
358         if (deviceId)
359         {
360             memcpy(tags->di.id, deviceId, strlen(deviceId));
361             OICFree(deviceId);
362         }
363         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding deviceId");
364     }
365
366     cborFindResult = FindIntInMap(tagsMap, OC_RSRVD_DEVICE_TTL, &tags->ttl);
367     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding ttl");
368
369     *tagsPayload = tags;
370     return cborFindResult;
371
372 exit:
373     OCFreeTagsResource(tags);
374     return cborFindResult;
375 }
376
377 static CborError OCLinksCborToPayload(CborValue *links, OCLinksPayload **linksPayload)
378 {
379     OCLinksPayload *setLinks = NULL;
380     CborValue linksMap;
381     CborValue linksArray;
382     CborError cborFindResult = CborErrorOutOfMemory;
383
384     cborFindResult = cbor_value_map_find_value(links, OC_RSRVD_LINKS, &linksArray);
385     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding links array");
386
387     cborFindResult = cbor_value_enter_container(&linksArray, &linksMap);
388     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed entering links map container");
389
390     while (cbor_value_is_map(&linksMap))
391     {
392         setLinks = (OCLinksPayload *)OICCalloc(1, sizeof(OCLinksPayload));
393         VERIFY_PARAM_NON_NULL(TAG, setLinks, "Failed allocating setLinks");
394
395         cborFindResult = FindStringInMap(&linksMap, OC_RSRVD_HREF, &setLinks->href);
396         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding href value");
397
398         cborFindResult = FindStringInMap(&linksMap, OC_RSRVD_REL, &setLinks->rel);
399         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding rel value");
400
401         cborFindResult = FindStringLLInMap(&linksMap, OC_RSRVD_RESOURCE_TYPE, &setLinks->rt);
402         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding rt value");
403
404         cborFindResult = FindStringLLInMap(&linksMap, OC_RSRVD_INTERFACE, &setLinks->itf);
405         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding itf value");
406
407         // Policy
408         CborValue policyMap;
409         cborFindResult = cbor_value_map_find_value(&linksMap, OC_RSRVD_POLICY, &policyMap);
410         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "to find policy tag");
411
412         // Bitmap
413         cborFindResult = FindIntInMap(&policyMap, OC_RSRVD_BITMAP, (uint64_t *) &setLinks->p);
414         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding bitmap value");
415
416         cborFindResult = FindStringInMap(&linksMap, OC_RSRVD_TITLE, &setLinks->title);
417         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding title value");
418
419         cborFindResult = FindStringInMap(&linksMap, OC_RSRVD_URI, &setLinks->anchor);
420         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding uri value");
421
422         cborFindResult = FindIntInMap(&linksMap, OC_RSRVD_INS, (uint64_t *) &setLinks->ins);
423         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding ins value");
424
425         cborFindResult = FindIntInMap(&linksMap, OC_RSRVD_TTL, &setLinks->ttl);
426         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding ttl");
427
428         cborFindResult = FindStringLLInMap(&linksMap, OC_RSRVD_MEDIA_TYPE, &setLinks->type);
429         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding mt value");
430
431         if (!*linksPayload)
432         {
433             *linksPayload = setLinks;
434         }
435         else
436         {
437             OCLinksPayload *temp = *linksPayload;
438             while (temp->next)
439             {
440                 temp = temp->next;
441             }
442             temp->next = setLinks;
443         }
444         cborFindResult = cbor_value_advance(&linksMap);
445         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing links map");
446     }
447
448     return cborFindResult;
449
450 exit:
451     OCFreeLinksResource(*linksPayload);
452     OCFreeLinksResource(setLinks);
453     return cborFindResult;
454 }
455
456 static int64_t AddTextStringToMap(CborEncoder* map, const char* key, const char* value)
457 {
458     int64_t err = cbor_encode_text_string(map, key, strlen(key));
459     VERIFY_CBOR_SUCCESS(TAG, err, "Failed setting key value");
460     err |= cbor_encode_text_string(map, value, strlen(value));
461 exit:
462     return err;
463 }
464
465 static int64_t ConditionalAddTextStringToMap(CborEncoder* map, const char* key, const char* value)
466 {
467     return value ? AddTextStringToMap(map, key, value) : CborNoError;
468 }
469
470 static int64_t ConditionalAddIntToMap(CborEncoder *map, const char *tags, const uint64_t *value)
471 {
472     int64_t err = CborNoError;
473     if (*value)
474     {
475         err |= cbor_encode_text_string(map, tags, strlen(tags));
476         VERIFY_CBOR_SUCCESS(TAG, err, "failed setting value");
477         err |= cbor_encode_uint(map, *value);
478     }
479 exit:
480     return err;
481 }
482
483 static int64_t AddStringLLToMap(CborEncoder *map, const char *tag, const OCStringLL *strType)
484 {
485     CborEncoder array;
486     int64_t cborEncoderResult = CborNoError;
487
488     cborEncoderResult |= cbor_encode_text_string(map, tag, strlen(tag));
489     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed encoding string tag name");
490     cborEncoderResult |= cbor_encoder_create_array(map, &array, CborIndefiniteLength);
491     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed creating stringLL array");
492     while (strType)
493     {
494         cborEncoderResult |= cbor_encode_text_string(&array, strType->value, strlen(strType->value));
495         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed encoding string value");
496         strType = strType->next;
497     }
498     cborEncoderResult |= cbor_encoder_close_container(map, &array);
499     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing string array");
500 exit:
501     return cborEncoderResult;
502 }
503
504 OCRDPayload *OCRDPayloadCreate()
505 {
506     OCRDPayload *rdPayload = (OCRDPayload *)OICCalloc(1, sizeof(OCRDPayload));
507     VERIFY_PARAM_NON_NULL(TAG, rdPayload, "Failed allocating rdPayload");
508     rdPayload->base.type = PAYLOAD_TYPE_RD;
509
510 exit:
511     return rdPayload;
512 }
513
514 #ifdef RD_CLIENT
515 OCRDPayload *OCRDPublishPayloadCreate(OCResourceHandle resourceHandles[], uint8_t nHandles,
516                                       uint64_t ttl)
517 {
518     OCTagsPayload *tagsPayload = NULL;
519     OCLinksPayload *linksPayload = NULL;
520     OCStringLL *rt = NULL;
521     OCStringLL *itf = NULL;
522     OCStringLL *mt = NULL;
523     OCResourceProperty p = OC_RES_PROP_NONE;
524     uint8_t ins = 0;
525
526     OCRDPayload *rdPayload = OCRDPayloadCreate();
527     if (!rdPayload)
528     {
529         return NULL;
530     }
531
532     const unsigned char *id = (const unsigned char *) OCGetServerInstanceIDString();
533     tagsPayload = OCCopyTagsResources(NULL, id, ttl);
534     if (!tagsPayload)
535     {
536         goto exit;
537     }
538
539     for (uint8_t j = 0; j < nHandles; j++)
540     {
541         OCResourceHandle handle = resourceHandles[j];
542         if (handle)
543         {
544             rt = NULL;
545             itf = NULL;
546             mt = NULL;
547             ins = 0;
548             const char *uri = OCGetResourceUri(handle);
549             uint8_t numElement = 0;
550             if (OC_STACK_OK == OCGetNumberOfResourceTypes(handle, &numElement))
551             {
552                 OCStackResult res = CreateStringLL(numElement, handle, OCGetResourceTypeName, &rt);
553                 if (OC_STACK_OK != res || !rt)
554                 {
555                     goto exit;
556                 }
557             }
558
559             if (OC_STACK_OK == OCGetNumberOfResourceInterfaces(handle, &numElement))
560             {
561                 OCStackResult res = CreateStringLL(numElement, handle, OCGetResourceInterfaceName,
562                                                    &itf);
563                 if (OC_STACK_OK != res || !itf)
564                 {
565                     goto exit;
566                 }
567             }
568
569             p = OCGetResourceProperties(handle);
570             p = (OCResourceProperty) ((p & OC_DISCOVERABLE) | (p & OC_OBSERVABLE));
571
572             OCStackResult res = OCGetResourceIns(handle, &ins);
573             if (OC_STACK_OK != res)
574             {
575                 goto exit;
576             }
577
578             mt = (OCStringLL *)OICCalloc(1, sizeof(OCStringLL));
579             if (!mt)
580             {
581                 goto exit;
582             }
583             mt->value = OICStrdup(DEFAULT_MESSAGE_TYPE);
584             if (!mt->value)
585             {
586                 goto exit;
587             }
588
589             if (!linksPayload)
590             {
591                 linksPayload = OCCopyLinksResources(uri, NULL, rt, itf, p, NULL,
592                                                     NULL, ins, ttl, mt);;
593                 if (!linksPayload)
594                 {
595                     goto exit;
596                 }
597             }
598             else
599             {
600                 OCLinksPayload *temp = linksPayload;
601                 while (temp->next)
602                 {
603                     temp = temp->next;
604                 }
605                 temp->next = OCCopyLinksResources(uri, NULL, rt, itf, p, NULL,
606                                                   NULL, ins, ttl, mt);
607                 if (!temp->next)
608                 {
609                     goto exit;
610                 }
611             }
612             OCFreeOCStringLL(rt);
613             OCFreeOCStringLL(itf);
614             OCFreeOCStringLL(mt);
615         }
616     }
617
618     rdPayload->rdPublish = OCCopyCollectionResource(tagsPayload, linksPayload);
619     if (!rdPayload->rdPublish)
620     {
621         goto exit;
622     }
623
624     return rdPayload;
625
626 exit:
627     if (rt)
628     {
629         OCFreeOCStringLL(rt);
630     }
631     if (itf)
632     {
633         OCFreeOCStringLL(itf);
634     }
635     if (mt)
636     {
637         OCFreeOCStringLL(mt);
638     }
639     if (tagsPayload)
640     {
641         OCFreeTagsResource(tagsPayload);
642     }
643     if (linksPayload)
644     {
645         OCFreeLinksResource(linksPayload);
646     }
647     OCRDPayloadDestroy(rdPayload);
648     return NULL;
649 }
650 #endif
651 OCRDDiscoveryPayload *OCRDDiscoveryPayloadCreate(const char *deviceName, const char *id, int biasFactor)
652 {
653     OCRDDiscoveryPayload *discoveryPayload = (OCRDDiscoveryPayload *)OICCalloc(1, sizeof(OCRDDiscoveryPayload));
654     VERIFY_PARAM_NON_NULL(TAG, discoveryPayload, "Failed allocating memory for discovery payload");
655
656     if (deviceName)
657     {
658         discoveryPayload->n.deviceName = OICStrdup(deviceName);
659         VERIFY_PARAM_NON_NULL(TAG, discoveryPayload->n.deviceName,
660                 "Failed allocating memory for discovery device name");
661     }
662     if (id)
663     {
664         OICStrcpy((char*)discoveryPayload->di.id, MAX_IDENTITY_SIZE, id);
665     }
666
667     discoveryPayload->sel = biasFactor;
668     return discoveryPayload;
669 exit:
670     OICFree(discoveryPayload);
671     discoveryPayload = NULL;
672     return discoveryPayload;
673 }
674
675 void OCRDPayloadDestroy(OCRDPayload *payload)
676 {
677     if (!payload)
678     {
679         return;
680     }
681
682     if (payload->rdDiscovery)
683     {
684         if (payload->rdDiscovery->n.deviceName)
685         {
686             OICFree(payload->rdDiscovery->n.deviceName);
687         }
688         OICFree(payload->rdDiscovery);
689     }
690
691     if (payload->rdPublish)
692     {
693         OCResourceCollectionPayload *col = payload->rdPublish;
694
695         if (col->setLinks)
696         {
697             OCFreeLinksResource(col->setLinks);
698         }
699
700         if (col->tags)
701         {
702             OCFreeTagsResource(col->tags);
703         }
704         OICFree(col);
705     }
706
707     OICFree(payload);
708 }
709
710 OCTagsPayload* OCCopyTagsResources(const char *deviceName, const unsigned char *id, uint64_t ttl)
711 {
712     OCTagsPayload *tags = (OCTagsPayload *)OICCalloc(1, sizeof(OCTagsPayload));
713     if (!tags)
714     {
715         return NULL;
716     }
717     if (deviceName)
718     {
719         tags->n.deviceName = OICStrdup(deviceName);
720         if (!tags->n.deviceName)
721         {
722             goto memory_allocation_failed;
723         }
724     }
725     if (id)
726     {
727         OICStrcpy((char*)tags->di.id, MAX_IDENTITY_SIZE, (char *)id);
728     }
729     tags->ttl = ttl;
730     return tags;
731
732 memory_allocation_failed:
733     OIC_LOG(ERROR, TAG, "Memory allocation failed.");
734     OCFreeTagsResource(tags);
735     return NULL;
736 }
737
738 OCLinksPayload* OCCopyLinksResources(const char *href, const char *rel, OCStringLL *rt,
739                                      OCStringLL *itf, uint8_t p, const char *title,
740                                      const char *anchor, uint8_t ins, uint64_t ttl,
741                                      OCStringLL *mt)
742 {
743     OCLinksPayload *links = (OCLinksPayload *)OICCalloc(1, sizeof(OCLinksPayload));
744     if (!links)
745     {
746         OIC_LOG(ERROR, TAG, "Failed allocating memory.");
747         return NULL;
748     }
749     if (href)
750     {
751         links->href = OICStrdup(href);
752         if (!links->href)
753         {
754             goto memory_allocation_failed;
755         }
756     }
757     if (rel)
758     {
759         links->rel = OICStrdup(rel);
760         if (!links->rel)
761         {
762             goto memory_allocation_failed;
763         }
764     }
765     if (rt)
766     {
767         links->rt = CloneOCStringLL(rt);
768         if (!links->rt)
769         {
770             goto memory_allocation_failed;
771         }
772     }
773     if (itf)
774     {
775         links->itf = CloneOCStringLL(itf);
776         if (!links->itf)
777         {
778             goto memory_allocation_failed;
779         }
780     }
781     links->p = p;
782     if (title)
783     {
784         links->title = OICStrdup(title);
785         if (!links->title)
786         {
787             goto memory_allocation_failed;
788         }
789     }
790     if (anchor)
791     {
792         links->anchor = OICStrdup(anchor);
793         if (!links->anchor)
794         {
795             goto memory_allocation_failed;
796         }
797     }
798     links->ins = ins;
799     links->ttl = ttl;
800     if (mt)
801     {
802         links->type = CloneOCStringLL(mt);
803         if (!links->type)
804         {
805             goto memory_allocation_failed;
806         }
807     }
808     links->next = NULL;
809     return links;
810
811 memory_allocation_failed:
812     OIC_LOG(ERROR, TAG, "Memory allocation failed.");
813     OCFreeLinksResource(links);
814     return NULL;
815 }
816
817 OCResourceCollectionPayload* OCCopyCollectionResource(OCTagsPayload *tags, OCLinksPayload *links)
818 {
819     OCResourceCollectionPayload *pl =  NULL;
820     VERIFY_PARAM_NON_NULL(TAG, tags, "Invalid param tags");
821     VERIFY_PARAM_NON_NULL(TAG, links, "Invalid param links");
822
823     pl = (OCResourceCollectionPayload *)OICCalloc(1, sizeof(OCResourceCollectionPayload));
824     VERIFY_PARAM_NON_NULL(TAG, pl, "Failed allocating memory for the OCResourceCollectionPayload");
825
826     pl->tags = tags;
827     pl->setLinks = links;
828
829 exit:
830     return pl;
831 }
832
833 void OCFreeLinksResource(OCLinksPayload *links)
834 {
835     if (!links)
836     {
837         return;
838     }
839     OICFree(links->href);
840     OICFree(links->rel);
841     OCFreeOCStringLL(links->rt);
842     OCFreeOCStringLL(links->itf);
843     OICFree(links->title);
844     OICFree(links->anchor);
845     OCFreeOCStringLL(links->type);
846     OCFreeLinksResource(links->next);
847     OICFree(links);
848 }
849
850 void OCFreeTagsResource(OCTagsPayload *payload)
851 {
852     if (!payload)
853     {
854         return;
855     }
856     OICFree(payload->n.deviceName);;
857     OICFree(payload);
858 }
859
860 void OCFreeCollectionResource(OCResourceCollectionPayload *payload)
861 {
862     if (!payload)
863     {
864         return;
865     }
866     if (payload->tags)
867     {
868         OCFreeTagsResource(payload->tags);
869     }
870     if (payload->setLinks)
871     {
872         OCFreeLinksResource(payload->setLinks);
873     }
874     OICFree(payload);
875 }
876
877 static OCStackResult CreateStringLL(uint8_t numElements, OCResourceHandle handle,
878                                     const char* (*getValue)(OCResourceHandle handle, uint8_t i),
879                                     OCStringLL **stringLL)
880 {
881     for (uint8_t i = 0; i < numElements; ++i)
882     {
883         const char *value = getValue(handle, i);
884         OIC_LOG_V(ERROR, TAG, "value: %s", value);
885         if (!*stringLL)
886         {
887             *stringLL = (OCStringLL *)OICCalloc(1, sizeof(OCStringLL));
888             if (!*stringLL)
889             {
890                 OIC_LOG(ERROR, TAG, "Failed allocating memory.");
891                 return OC_STACK_NO_MEMORY;
892             }
893             (*stringLL)->value = OICStrdup(value);
894             if (!(*stringLL)->value)
895             {
896                 OIC_LOG(ERROR, TAG, "Failed copying to OCStringLL.");
897                 return OC_STACK_NO_MEMORY;
898             }
899         }
900         else
901         {
902             OCStringLL *cur = *stringLL;
903             while (cur->next)
904             {
905                 cur = cur->next;
906             }
907             cur->next = (OCStringLL *)OICCalloc(1, sizeof(OCStringLL));
908             if (!cur->next)
909             {
910                 OIC_LOG(ERROR, TAG, "Failed allocating memory.");
911                 return OC_STACK_NO_MEMORY;
912             }
913             cur->next->value = OICStrdup(value);
914             if (!cur->next->value)
915             {
916                 OIC_LOG(ERROR, TAG, "Failed copying to OCStringLL.");
917                 return OC_STACK_NO_MEMORY;
918             }
919         }
920     }
921     return OC_STACK_OK;
922 }