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