Imported Upstream version 1.0.1
[platform/upstream/iotivity.git] / service / resource-directory / src / rd_client.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 "rd_client.h"
21
22 #include <stdarg.h>
23
24 #include "oic_string.h"
25 #include "oic_malloc.h"
26 #include "payload_logging.h"
27
28 #include "rdpayload.h"
29 #include "ocpayload.h"
30
31 #define DEFAULT_CONTEXT_VALUE 0x99
32 #define OC_RD_PUBLISH_TTL 86400
33
34 #define TAG  PCF("RDClient")
35
36 static OCStackResult sendRequest(OCMethod method, char *uri, OCDevAddr *addr,
37         OCPayload *payload, OCCallbackData cbData)
38 {
39     OCDoHandle handle;
40     OCStackResult result;
41
42     result = OCDoResource(&handle,
43         method,
44         uri,
45         addr,
46         payload,
47         CT_ADAPTER_IP,
48         OC_LOW_QOS,
49         &cbData,
50         NULL,
51         0);
52
53     if (result == OC_STACK_OK)
54     {
55         OC_LOG(DEBUG, TAG, "Resource Directory send successful...");
56     }
57     else
58     {
59         OC_LOG(ERROR, TAG, "Resource Directory send failed...");
60     }
61
62     return result;
63 }
64
65 static OCStackApplicationResult handlePublishCB(__attribute__((unused))void *ctx,
66         __attribute__((unused)) OCDoHandle handle,
67         __attribute__((unused)) OCClientResponse *clientResponse)
68 {
69     OCStackApplicationResult ret = OC_STACK_DELETE_TRANSACTION;
70     OC_LOG(DEBUG, TAG, "Successfully published resources.");
71
72     if (OC_STACK_OK == OCStopMulticastServer())
73     {
74         OC_LOG_V(DEBUG, TAG, "Stopped receiving the multicast traffic.");
75     }
76     else
77     {
78         OC_LOG_V(DEBUG, TAG, "Failed stopping the multicast traffic.");
79     }
80
81     return ret;
82 }
83
84 static void retreiveRDDetails(OCClientResponse *clientResponse, OCRDBiasFactorCB clientCB)
85 {
86     OC_LOG_V(DEBUG, TAG, "\tAddress of the RD: %s:%d", clientResponse->devAddr.addr,
87             clientResponse->devAddr.port);
88
89     OCRDPayload *payload = (OCRDPayload *) clientResponse->payload;
90     OC_LOG_PAYLOAD(DEBUG, (OCPayload *) payload);
91
92     // TODO: Multiple Resource Directory will have different biasFactor,
93     // needs to cache here detail
94     // and after certain timeout then decide based on the biasFactor.
95     //if (biasFactor > 75)
96     if (clientCB)
97     {
98         clientCB(clientResponse->devAddr.addr, clientResponse->devAddr.port);
99     }
100 }
101
102 static OCStackApplicationResult handleDiscoverCB(void *ctx,
103         __attribute__((unused)) OCDoHandle handle, OCClientResponse *clientResponse)
104 {
105     OC_LOG(DEBUG, TAG, "Found Resource Directory");
106     OCStackApplicationResult ret = OC_STACK_DELETE_TRANSACTION;
107
108     OCRDClientContextCB *cb = (OCRDClientContextCB *)ctx;
109     if (!cb)
110     {
111         OC_LOG(ERROR, TAG, "RD Context Invalid Parameters.");
112         return ret;
113     }
114
115     if (cb->context != (void *) DEFAULT_CONTEXT_VALUE)
116     {
117         OC_LOG(ERROR, TAG, "RD Context Invalid Context Value Parameters.");
118         return ret;
119     }
120
121     OC_LOG_V(DEBUG, TAG, "Callback Context for DISCOVER query received successfully :%d.", clientResponse->result);
122
123     if (clientResponse && clientResponse->result == OC_STACK_OK)
124     {
125         retreiveRDDetails(clientResponse, cb->cbFunc);
126     }
127     else
128     {
129         OC_LOG(ERROR, TAG, "Discovery of RD Failed");
130     }
131
132     OICFree(cb);
133
134     return ret;
135 }
136
137 OCStackResult OCRDDiscover(OCRDBiasFactorCB cbBiasFactor)
138 {
139     if (!cbBiasFactor)
140     {
141         OC_LOG(DEBUG, TAG, "No callback function specified.");
142         return OC_STACK_INVALID_CALLBACK;
143     }
144
145     /* Start a discovery query*/
146     char queryUri[MAX_URI_LENGTH] = { '\0' };
147     snprintf(queryUri, MAX_URI_LENGTH, "coap://%s%s", OC_MULTICAST_PREFIX, OC_RSRVD_RD_URI);
148
149     OC_LOG_V(DEBUG, TAG, "Querying RD: %s\n", queryUri);
150
151     OCRDClientContextCB *cbContext = (OCRDClientContextCB *)OICCalloc(1, sizeof(OCRDClientContextCB));
152     if (!cbContext)
153     {
154         OC_LOG(ERROR, TAG, "Failed allocating memory.");
155         return OC_STACK_NO_MEMORY;
156     }
157
158     cbContext->context = (void *)DEFAULT_CONTEXT_VALUE;
159     cbContext->cbFunc = cbBiasFactor;
160
161     OCCallbackData cbData;
162     cbData.cb = handleDiscoverCB;
163     cbData.context = (void *)(cbContext);
164     cbData.cd = NULL;
165
166     return sendRequest(OC_REST_DISCOVER, queryUri, NULL, NULL, cbData);
167 }
168
169 static OCStackResult createStringLL(uint8_t numElements, OCResourceHandle handle,
170     const char* (*getValue)(OCResourceHandle handle, uint8_t i), OCStringLL **stringLL)
171 {
172     for (uint8_t i = 0; i < numElements; ++i)
173     {
174         const char *value = getValue(handle, i);
175         if (!*stringLL)
176         {
177             *stringLL = (OCStringLL *)OICCalloc(1, sizeof(OCStringLL));
178             if (!*stringLL)
179             {
180                 OC_LOG(ERROR, TAG, "Failed allocating memory.");
181                 return OC_STACK_NO_MEMORY;
182             }
183             (*stringLL)->value = OICStrdup(value);
184             if (!(*stringLL)->value)
185             {
186                 OC_LOG(ERROR, TAG, "Failed copying to OCStringLL.");
187                 return OC_STACK_NO_MEMORY;
188             }
189         }
190         else
191         {
192             OCStringLL *cur = *stringLL;
193             while (cur->next)
194             {
195                 cur = cur->next;
196             }
197             cur->next = (OCStringLL *)OICCalloc(1, sizeof(OCStringLL));
198             if (!cur->next)
199             {
200                 OC_LOG(ERROR, TAG, "Failed allocating memory.");
201                 return OC_STACK_NO_MEMORY;
202             }
203             cur->next->value = OICStrdup(value);
204             if (!cur->next->value)
205             {
206                 OC_LOG(ERROR, TAG, "Failed copying to OCStringLL.");
207                 return OC_STACK_NO_MEMORY;
208             }
209         }
210     }
211     return OC_STACK_OK;
212 }
213
214 OCStackResult OCRDPublish(char *addr, uint16_t port, int numArg, ... )
215 {
216     if (!addr)
217     {
218         OC_LOG(ERROR, TAG, "RD address not specified.");
219         return OC_STACK_INVALID_PARAM;
220     }
221
222     char targetUri[MAX_URI_LENGTH];
223     snprintf(targetUri, MAX_URI_LENGTH, "coap://%s:%d%s?rt=%s", addr, port,
224             OC_RSRVD_RD_URI, OC_RSRVD_RESOURCE_TYPE_RDPUBLISH);
225     OC_LOG_V(DEBUG, TAG, "Target URI : %s", targetUri);
226
227     // Gather all resources locally and do publish
228     OCCallbackData cbData = { 0 };
229     cbData.cb = &handlePublishCB;
230     cbData.cd = NULL;
231     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
232
233     OCTagsPayload *tagsPayload = NULL;
234     OCLinksPayload *linksPayload = NULL;
235     OCStringLL *rt = NULL;
236     OCStringLL *itf = NULL;
237     OCStringLL *mt = NULL;
238
239     OCRDPayload *rdPayload = OCRDPayloadCreate();
240     if (!rdPayload)
241     {
242         goto no_memory;
243     }
244
245     const unsigned char *id = (unsigned char*) OCGetServerInstanceIDString();
246     tagsPayload = OCCopyTagsResources(NULL, id,
247             NULL, OC_DISCOVERABLE, 0, 0, NULL, NULL, OC_RD_PUBLISH_TTL);
248     if (!tagsPayload)
249     {
250         goto no_memory;
251     }
252
253     va_list arguments;
254     va_start (arguments, numArg);
255
256     for (int j = 0 ; j < numArg; j++)
257     {
258         OCResourceHandle handle = va_arg(arguments, OCResourceHandle);
259         if (handle)
260         {
261             rt = itf = mt = NULL;
262             const char *uri = OCGetResourceUri(handle);
263             uint8_t numElement;
264             if (OC_STACK_OK == OCGetNumberOfResourceTypes(handle, &numElement))
265             {
266                 OCStackResult res = createStringLL(numElement, handle, OCGetResourceTypeName, &rt);
267                 if (res != OC_STACK_OK || !rt)
268                 {
269                     va_end(arguments);
270                     goto no_memory;
271                 }
272             }
273
274             if (OC_STACK_OK == OCGetNumberOfResourceTypes(handle, &numElement))
275             {
276                 OCStackResult res = createStringLL(numElement, handle, OCGetResourceInterfaceName, &itf);
277                 if (res != OC_STACK_OK || !itf)
278                 {
279                     va_end(arguments);
280                     goto no_memory;
281                 }
282             }
283
284             mt = (OCStringLL *)OICCalloc(1, sizeof(OCStringLL));
285             if (!mt)
286             {
287                 va_end(arguments);
288                 goto no_memory;
289             }
290             mt->value = OICStrdup("application/json");
291             if (!mt->value)
292             {
293                 va_end(arguments);
294                 goto no_memory;
295             }
296
297             if (!linksPayload)
298             {
299                 linksPayload = OCCopyLinksResources(uri, rt, itf, NULL, 0, NULL,
300                         NULL, j, mt);;
301                 if (!linksPayload)
302                 {
303                     goto no_memory;
304                 }
305             }
306             else
307             {
308                 OCLinksPayload *temp = linksPayload;
309                 while (temp->next)
310                 {
311                     temp = temp->next;
312                 }
313                 temp->next = OCCopyLinksResources(uri, rt, itf, NULL, 0, NULL,
314                         NULL, j, mt);
315                 if (!temp->next)
316                 {
317                     goto no_memory;
318                 }
319             }
320             OCFreeOCStringLL(rt);
321             OCFreeOCStringLL(itf);
322             OCFreeOCStringLL(mt);
323         }
324     }
325     va_end(arguments);
326
327     rdPayload->rdPublish = OCCopyCollectionResource(tagsPayload, linksPayload);
328     if (!rdPayload->rdPublish)
329     {
330         goto no_memory;
331     }
332
333     OCTagsLog(DEBUG, rdPayload->rdPublish->tags);
334     OCLinksLog(DEBUG, rdPayload->rdPublish->setLinks);
335
336     OCDevAddr rdAddr = { 0 };
337     OICStrcpy(rdAddr.addr, MAX_ADDR_STR_SIZE, addr);
338     rdAddr.port = port;
339
340     OC_LOG_PAYLOAD(DEBUG, (OCPayload *) rdPayload);
341
342     return sendRequest(OC_REST_POST, targetUri, &rdAddr, (OCPayload *)rdPayload, cbData);
343
344 no_memory:
345     OC_LOG(ERROR, TAG, "Failed allocating memory.");
346     OCFreeOCStringLL(rt);
347     OCFreeOCStringLL(itf);
348     OCFreeOCStringLL(mt);
349     OCFreeTagsResource(tagsPayload);
350     OCFreeLinksResource(linksPayload);
351     OCRDPayloadDestroy(rdPayload);
352     return OC_STACK_NO_MEMORY;
353 }