Prevent out-of-bounds memory access
[platform/upstream/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 <stdlib.h>
23 #include <string.h>
24
25 #include "oic_malloc.h"
26 #include "oic_string.h"
27 #include "octypes.h"
28 #include "ocstack.h"
29 #include "ocpayload.h"
30 #include "payload_logging.h"
31
32 #define TAG "OIC_RD_CLIENT"
33
34 #ifdef RD_CLIENT
35
36 OCStackResult OCRDDiscover(OCConnectivityType connectivityType, OCCallbackData *cbBiasFactor,
37                            OCQualityOfService qos)
38 {
39     if (!cbBiasFactor || !cbBiasFactor->cb)
40     {
41         OIC_LOG(DEBUG, TAG, "No callback function specified.");
42         return OC_STACK_INVALID_CALLBACK;
43     }
44
45     /* Start a discovery query*/
46     char queryUri[MAX_URI_LENGTH] = { '\0' };
47     snprintf(queryUri, MAX_URI_LENGTH, "coap://%s%s", OC_MULTICAST_PREFIX, OC_RSRVD_RD_URI);
48     OIC_LOG_V(DEBUG, TAG, "Querying RD: %s\n", queryUri);
49
50     return OCDoResource(NULL, OC_REST_DISCOVER, queryUri, NULL, NULL, connectivityType, qos,
51                         cbBiasFactor, NULL, 0);
52 }
53
54 OCStackResult OCRDPublish(const char *host, OCConnectivityType connectivityType,
55                           OCResourceHandle *resourceHandles, uint8_t nHandles,
56                           OCCallbackData *cbData, OCQualityOfService qos)
57 {
58     // Validate input parameters.
59     if (!host)
60     {
61         return OC_STACK_INVALID_IP;
62     }
63
64     if (!cbData || !cbData->cb)
65     {
66         return OC_STACK_INVALID_CALLBACK;
67     }
68
69     // Get Device ID from stack.
70     const unsigned char *id = (const unsigned char *) OCGetServerInstanceIDString();
71
72     return OCRDPublishWithDeviceId(host, id, connectivityType, resourceHandles, nHandles,
73                                    cbData, qos);
74 }
75
76 OCStackResult OCRDPublishWithDeviceId(const char *host, const unsigned char *id,
77                                       OCConnectivityType connectivityType,
78                                       OCResourceHandle *resourceHandles, uint8_t nHandles,
79                                       OCCallbackData *cbData, OCQualityOfService qos)
80 {
81     // Validate input parameters.
82     if (!host || !cbData || !cbData->cb || !id)
83     {
84         return OC_STACK_INVALID_CALLBACK;
85     }
86
87     OIC_LOG_V(DEBUG, TAG, "Publish Resource to RD with device id [%s]", id);
88
89     OCResourceHandle *pubResHandle = resourceHandles;
90     OCResourceHandle defaultResHandles[OIC_RD_DEFAULT_RESOURCE] = { 0 };
91     uint8_t nPubResHandles = nHandles;
92
93     // if resource handles is null, "/oic/p" and "/oic/d" resource will be published to RD.
94     if (!pubResHandle)
95     {
96         // get "/oic/d" and "/oic/p" resource handle from stack.
97         defaultResHandles[0] = OCGetResourceHandleAtUri(OC_RSRVD_DEVICE_URI);
98         defaultResHandles[1] = OCGetResourceHandleAtUri(OC_RSRVD_PLATFORM_URI);
99
100         for (uint8_t j = 0; j < OIC_RD_DEFAULT_RESOURCE; j++)
101         {
102             if (defaultResHandles[j])
103             {
104                 OIC_LOG_V(DEBUG, TAG, "Add virtual resource(%s) to resource handle list",
105                           OCGetResourceUri(defaultResHandles[j]));
106             }
107         }
108
109         pubResHandle = defaultResHandles;
110         nPubResHandles = OIC_RD_DEFAULT_RESOURCE;
111     }
112
113     char targetUri[MAX_URI_LENGTH] = { 0 };
114     snprintf(targetUri, MAX_URI_LENGTH, "%s%s?rt=%s", host,
115              OC_RSRVD_RD_URI, OC_RSRVD_RESOURCE_TYPE_RDPUBLISH);
116     OIC_LOG_V(DEBUG, TAG, "Target URI: %s", targetUri);
117
118     OCRepPayload *rdPayload =  (OCRepPayload *)OCRepPayloadCreate();
119     if (!rdPayload)
120     {
121         return OC_STACK_NO_MEMORY;
122     }
123
124     OCRepPayloadSetPropString(rdPayload, OC_RSRVD_DEVICE_ID, (const char *) id);
125
126     char *deviceName = NULL;
127     OCGetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DEVICE_NAME, (void **) &deviceName);
128     if (deviceName)
129     {
130         OCRepPayloadSetPropString(rdPayload, OC_RSRVD_DEVICE_NAME, deviceName);
131         OICFree(deviceName);
132     }
133
134     char *platformModelName = NULL;
135     OCGetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_MODEL_NUM, (void **) &platformModelName);
136     if (platformModelName)
137     {
138         OCRepPayloadSetPropString(rdPayload, OC_DATA_MODEL_NUMBER, platformModelName);
139         OICFree(platformModelName);
140     }
141
142     OCRepPayloadSetPropInt(rdPayload, OC_RSRVD_DEVICE_TTL, OIC_RD_PUBLISH_TTL);
143
144     OCRepPayload **linkArr = OICCalloc(nPubResHandles, sizeof(OCRepPayload *));
145     if (!linkArr)
146     {
147         OCRepPayloadDestroy(rdPayload);
148         return OC_STACK_NO_MEMORY;
149     }
150
151     size_t dimensions[MAX_REP_ARRAY_DEPTH] = {nPubResHandles, 0, 0};
152     for (uint8_t j = 0; j < nPubResHandles; j++)
153     {
154         OCResourceHandle handle = pubResHandle[j];
155         if (handle)
156         {
157             OCRepPayload *link = OCRepPayloadCreate();
158
159             const char *uri = OCGetResourceUri(handle);
160             if (uri)
161             {
162                 OCRepPayloadSetPropString(link, OC_RSRVD_HREF, uri);
163             }
164
165             uint8_t numElement = 0;
166             if (OC_STACK_OK == OCGetNumberOfResourceTypes(handle, &numElement))
167             {
168                 size_t rtDim[MAX_REP_ARRAY_DEPTH] = {numElement, 0, 0};
169                 char **rt = (char **)OICMalloc(sizeof(char *) * numElement);
170                 for (uint8_t i = 0; i < numElement; ++i)
171                 {
172                     const char *value = OCGetResourceTypeName(handle, i);
173                     OIC_LOG_V(DEBUG, TAG, "value: %s", value);
174                     rt[i] = OICStrdup(value);
175                 }
176                 OCRepPayloadSetStringArrayAsOwner(link, OC_RSRVD_RESOURCE_TYPE, rt, rtDim);
177             }
178
179             numElement = 0;
180             if (OC_STACK_OK == OCGetNumberOfResourceInterfaces(handle, &numElement))
181             {
182                 size_t ifDim[MAX_REP_ARRAY_DEPTH] = {numElement, 0, 0};
183                 char **itf = (char **)OICMalloc(sizeof(char *) * numElement);
184                 for (uint8_t i = 0; i < numElement; ++i)
185                 {
186                     const char *value = OCGetResourceInterfaceName(handle, i);
187                     OIC_LOG_V(DEBUG, TAG, "value: %s", value);
188                     itf[i] = OICStrdup(value);
189                 }
190                 OCRepPayloadSetStringArrayAsOwner(link, OC_RSRVD_INTERFACE, itf, ifDim);
191             }
192
193             uint8_t ins = 0;
194             if (OC_STACK_OK == OCGetResourceIns(handle, &ins))
195             {
196                 OCRepPayloadSetPropInt(link, OC_RSRVD_INS, ins);
197             }
198
199             size_t mtDim[MAX_REP_ARRAY_DEPTH] = {1, 0, 0};
200             char **mediaType = (char **)OICMalloc(sizeof(char *) * 1);
201             if (!mediaType)
202             {
203                 OIC_LOG(ERROR, TAG, "Memory allocation failed!");
204
205                 for(uint8_t i = 0; i < nPubResHandles; i++)
206                 {
207                     OCRepPayloadDestroy(linkArr[i]);
208                 }
209                 OICFree(linkArr);
210                 OCRepPayloadDestroy(rdPayload);
211                 return OC_STACK_NO_MEMORY;
212             }
213
214             mediaType[0] = OICStrdup(DEFAULT_MESSAGE_TYPE);
215             OCRepPayloadSetStringArrayAsOwner(link, OC_RSRVD_MEDIA_TYPE, mediaType,
216             mtDim);
217
218             OCResourceProperty p = OCGetResourceProperties(handle);
219             p = (OCResourceProperty) ((p & OC_DISCOVERABLE) | (p & OC_OBSERVABLE));
220             OCRepPayload *policy = OCRepPayloadCreate();
221             OCRepPayloadSetPropInt(policy, OC_RSRVD_BITMAP, p);
222             OCRepPayloadSetPropObjectAsOwner(link, OC_RSRVD_POLICY, policy);
223
224             linkArr[j] = link;
225         }
226     }
227
228     OCRepPayloadSetPropObjectArray(rdPayload, OC_RSRVD_LINKS, (const OCRepPayload **)linkArr, dimensions);
229     OIC_LOG_PAYLOAD(DEBUG, (OCPayload *) rdPayload);
230
231     for (uint8_t i = 0; i < nPubResHandles; i++)
232     {
233         OCRepPayloadDestroy(linkArr[i]);
234     }
235     OICFree(linkArr);
236
237     return OCDoResource(NULL, OC_REST_POST, targetUri, NULL, (OCPayload *)rdPayload,
238                         connectivityType, qos, cbData, NULL, 0);
239 }
240
241 OCStackResult OCRDDelete(const char *host, OCConnectivityType connectivityType,
242                          OCResourceHandle *resourceHandles, uint8_t nHandles,
243                          OCCallbackData *cbData, OCQualityOfService qos)
244 {
245     // Validate input parameters
246     if (!host)
247     {
248         return OC_STACK_INVALID_IP;
249     }
250
251     if (!cbData || !cbData->cb)
252     {
253         return OC_STACK_INVALID_CALLBACK;
254     }
255
256     const unsigned char *id = (const unsigned char *) OCGetServerInstanceIDString();
257
258     return OCRDDeleteWithDeviceId(host, id, connectivityType, resourceHandles, nHandles,
259                                   cbData, qos);
260 }
261
262 OCStackResult OCRDDeleteWithDeviceId(const char *host, const unsigned char *id,
263                                      OCConnectivityType connectivityType,
264                                      OCResourceHandle *resourceHandles, uint8_t nHandles,
265                                      OCCallbackData *cbData, OCQualityOfService qos)
266 {
267     // Validate input parameters
268     if (!host || !cbData || !cbData->cb || !id)
269     {
270         return OC_STACK_INVALID_CALLBACK;
271     }
272
273     OIC_LOG_V(DEBUG, TAG, "Delete Resource to RD with device id [%s]", id);
274
275     char targetUri[MAX_URI_LENGTH] = { 0 };
276     int targetUriBufferRequired = snprintf(targetUri, MAX_URI_LENGTH, "%s%s?di=%s", host, OC_RSRVD_RD_URI, id);
277     if (targetUriBufferRequired >= MAX_URI_LENGTH || targetUriBufferRequired < 0)
278     {
279         return OC_STACK_INVALID_URI;
280     }
281
282
283     int queryLength = 0;
284     char queryParam[MAX_URI_LENGTH] = { 0 };
285     for (uint8_t j = 0; j < nHandles; j++)
286     {
287         OCResource *handle = (OCResource *) resourceHandles[j];
288         uint8_t ins = 0;
289         OCGetResourceIns(handle, &ins);
290         int lenBufferRequired = snprintf(queryParam + queryLength, MAX_URI_LENGTH - queryLength, "&ins=%d", ins);
291         if (lenBufferRequired >= (MAX_URI_LENGTH - queryLength) || lenBufferRequired < 0)
292         {
293             return OC_STACK_INVALID_URI;
294         }
295         queryLength += lenBufferRequired;
296         OIC_LOG_V(DEBUG, TAG, "queryParam [%s]", queryParam);
297     }
298
299     if (targetUriBufferRequired + queryLength + 1 > MAX_URI_LENGTH)
300     {
301         return OC_STACK_INVALID_URI;
302     }
303
304     OICStrcatPartial(targetUri, sizeof(targetUri), queryParam, strlen(queryParam));
305     OIC_LOG_V(DEBUG, TAG, "Target URI: %s", targetUri);
306
307     return OCDoResource(NULL, OC_REST_DELETE, targetUri, NULL, NULL, connectivityType,
308                         qos, cbData, NULL, 0);
309 }
310 #endif