apply register / find / get functions
[platform/core/iot/iotcon.git] / daemon / icd-ioty.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stdint.h> /* for uint8_t etc */
20 #include <stdbool.h>
21 #include <errno.h>
22 #include <glib.h>
23 #include <json-glib/json-glib.h>
24
25 #include <octypes.h>
26 #include <ocstack.h>
27
28 #include "iotcon.h"
29 #include "ic-utils.h"
30 #include "icd.h"
31 #include "icd-ioty-repr.h"
32 #include "icd-ioty.h"
33 #include "icd-ioty-ocprocess.h"
34
35 GHashTable *icd_worker_table;
36
37 GMutex icd_csdk_mutex;
38
39 void icd_ioty_csdk_lock()
40 {
41         g_mutex_lock(&icd_csdk_mutex);
42 }
43
44
45 void icd_ioty_csdk_unlock()
46 {
47         g_mutex_unlock(&icd_csdk_mutex);
48 }
49
50
51 GThread* icd_ioty_init(const char *addr, unsigned short port)
52 {
53         FN_CALL;
54         GError *error;
55         GThread *thread;
56
57         OCStackResult result = OCInit(addr, port, OC_CLIENT_SERVER);
58         if (OC_STACK_OK != result) {
59                 ERR("OCInit() Fail(%d)", result);
60                 return NULL;
61         }
62
63         DBG("OCInit() Success");
64
65         thread = g_thread_try_new("packet_receive_thread", icd_ioty_ocprocess_thread,
66                         NULL, &error);
67         if (NULL == thread) {
68                 ERR("g_thread_try_new() Fail(%s)", error->message);
69                 g_error_free(error);
70                 return NULL;
71         }
72
73         return thread;
74 }
75
76 void icd_ioty_deinit(GThread *thread)
77 {
78         OCStackResult result;
79
80         icd_ioty_ocprocess_stop();
81         g_thread_join(thread);
82
83         result = OCStop();
84         if (OC_STACK_OK != result)
85                 ERR("OCStop() Fail(%d)", result);
86 }
87
88
89 OCResourceHandle icd_ioty_register_resource(const char *uri_path,
90                 const char* const* res_types, int ifaces, uint8_t properties)
91 {
92         FN_CALL;
93         int i;
94         OCStackResult ret;
95         OCResourceHandle handle;
96         const char *resInterface = NULL;
97
98         if (IOTCON_INTERFACE_DEFAULT & ifaces) {
99                 resInterface = IC_INTERFACE_DEFAULT;
100                 ifaces ^= IOTCON_INTERFACE_DEFAULT;
101         } else if (IOTCON_INTERFACE_LINK & ifaces) {
102                 resInterface = IC_INTERFACE_LINK;
103                 ifaces ^= IOTCON_INTERFACE_LINK;
104         } else if (IOTCON_INTERFACE_BATCH & ifaces) {
105                 resInterface = IC_INTERFACE_BATCH;
106                 ifaces ^= IOTCON_INTERFACE_BATCH;
107         } else if (IOTCON_INTERFACE_GROUP & ifaces) {
108                 resInterface = IC_INTERFACE_GROUP;
109                 ifaces ^= IOTCON_INTERFACE_GROUP;
110         } else {
111                 ERR("Invalid interface type(%d)", ifaces);
112                 return NULL;
113         }
114
115         icd_ioty_csdk_lock();
116         ret = OCCreateResource(&handle, res_types[0], resInterface, uri_path, EntityHandlerWrapper,
117                         properties);
118         icd_ioty_csdk_unlock();
119         if (OC_STACK_OK != ret) {
120                 ERR("OCCreateResource() Fail(%d)", ret);
121                 return NULL;
122         }
123
124         for (i = 1; res_types[i]; i++)
125                 icd_ioty_bind_type(handle, res_types[i]);
126
127         if (IOTCON_INTERFACE_DEFAULT & ifaces)
128                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_DEFAULT);
129         if (IOTCON_INTERFACE_LINK & ifaces)
130                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_LINK);
131         if (IOTCON_INTERFACE_BATCH & ifaces)
132                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_BATCH);
133         if (IOTCON_INTERFACE_GROUP & ifaces)
134                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_GROUP);
135
136         return handle;
137 }
138
139
140 int icd_ioty_unregister_resource(OCResourceHandle resource_handle)
141 {
142         // TODO : To be implemented
143         return IOTCON_ERROR_NONE;
144 }
145
146
147 static int _ioty_convert_interface_flag(iotcon_interface_e src, const char **dest)
148 {
149         switch (src) {
150         case IOTCON_INTERFACE_DEFAULT:
151                 *dest = IC_INTERFACE_DEFAULT;
152                 break;
153         case IOTCON_INTERFACE_LINK:
154                 *dest = IC_INTERFACE_LINK;
155                 break;
156         case IOTCON_INTERFACE_BATCH:
157                 *dest = IC_INTERFACE_BATCH;
158                 break;
159         case IOTCON_INTERFACE_GROUP:
160                 *dest = IC_INTERFACE_GROUP;
161                 break;
162         case IOTCON_INTERFACE_NONE:
163         default:
164                 ERR("Invalid interface(%d)", src);
165                 return IOTCON_ERROR_INVALID_PARAMETER;
166         }
167         return IOTCON_ERROR_NONE;
168 }
169
170
171 int icd_ioty_bind_interface(OCResourceHandle resourceHandle, iotcon_interface_e iface)
172 {
173         int ret;
174         OCStackResult result;
175         const char *resource_interface;
176
177         ret = _ioty_convert_interface_flag(iface, &resource_interface);
178         if (IOTCON_ERROR_NONE != ret) {
179                 ERR("_ioty_convert_interface_flag(%d) Fail(%d)", iface, ret);
180                 return ret;
181         }
182
183         result = OCBindResourceInterfaceToResource(resourceHandle, resource_interface);
184         if (OC_STACK_OK != result) {
185                 ERR("OCBindResourceInterfaceToResource() Fail(%d)", result);
186                 return IOTCON_ERROR_IOTIVITY;
187         }
188
189         return IOTCON_ERROR_NONE;
190 }
191
192 int icd_ioty_bind_type(OCResourceHandle resource_handle, const char *resource_type)
193 {
194         OCStackResult ret;
195
196         ret = OCBindResourceTypeToResource(resource_handle, resource_type);
197         if (OC_STACK_OK != ret) {
198                 ERR("OCBindResourceTypeToResource() Fail(%d)", ret);
199                 return IOTCON_ERROR_IOTIVITY;
200         }
201
202         return IOTCON_ERROR_NONE;
203 }
204
205
206 int icd_ioty_bind_resource(OCResourceHandle parent, OCResourceHandle child)
207 {
208         // TODO : To be implemented
209         return IOTCON_ERROR_NONE;
210 }
211
212
213 int icd_ioty_unbind_resource(OCResourceHandle parent, OCResourceHandle child)
214 {
215         // TODO : To be implemented
216         return IOTCON_ERROR_NONE;
217 }
218
219
220 int icd_ioty_notify_list_of_observers(int resHandle, GVariant *msg, GVariant *observers)
221 {
222         // TODO : To be implemented
223         return IOTCON_ERROR_NONE;
224 }
225
226
227 int icd_ioty_notify_all(int resHandle)
228 {
229         // TODO : To be implemented
230         return IOTCON_ERROR_NONE;
231 }
232
233
234 int icd_ioty_send_response(GVariant *resp)
235 {
236         // TODO : To be implemented
237         return IOTCON_ERROR_NONE;
238 }
239
240
241 void _ioty_free_signal_context(void *data)
242 {
243         icd_sig_ctx_s *context = data;
244         free(context->sender);
245         free(context);
246 }
247
248 int icd_ioty_find_resource(const char *host_address, const char *resource_type,
249                 unsigned int signum, const char *sender)
250 {
251         int len;
252         OCStackResult result;
253         OCCallbackData cbdata = {0};
254         icd_sig_ctx_s *context;
255         char uri[PATH_MAX] = {0};
256         iotcon_connectivity_type_e conn_type = IOTCON_CONNECTIVITY_IPV4;
257
258         if (IC_STR_EQUAL == strcmp(IOTCON_MULTICAST_ADDRESS, host_address)) {
259                 len = snprintf(uri, sizeof(uri), "%s", OC_MULTICAST_DISCOVERY_URI);
260                 conn_type = IOTCON_CONNECTIVITY_ALL;
261         } else {
262                 len = snprintf(uri, sizeof(uri), ICD_IOTY_COAP"%s%s", host_address,
263                                 OC_MULTICAST_DISCOVERY_URI);
264         }
265         if (len <= 0 || sizeof(uri) <= len) {
266                 ERR("snprintf() Fail(%d)", len);
267                 return IOTCON_ERROR_UNKNOWN;
268         }
269
270         if (IC_STR_EQUAL != strcmp(IC_STR_NULL, resource_type))
271                 snprintf(uri + len, sizeof(uri), "?rt=%s", resource_type);
272
273         context = calloc(1, sizeof(icd_sig_ctx_s));
274         if (NULL == context) {
275                 ERR("calloc() Fail(%d)", errno);
276                 return IOTCON_ERROR_OUT_OF_MEMORY;
277         }
278
279         context->sender = ic_utils_strdup(sender);
280         context->signum = signum;
281
282         cbdata.context = context;
283         cbdata.cb = icd_ioty_ocprocess_find_cb;
284         cbdata.cd = _ioty_free_signal_context;
285
286         icd_ioty_csdk_lock();
287         result = OCDoResource(NULL, OC_REST_GET, uri, NULL, NULL, conn_type, OC_LOW_QOS,
288                         &cbdata, NULL, 0);
289         icd_ioty_csdk_unlock();
290
291         if (OC_STACK_OK != result) {
292                 ERR("OCDoResource() Fail(%d)", result);
293                 free(context->sender);
294                 free(context);
295                 return IOTCON_ERROR_IOTIVITY;
296         }
297
298         return IOTCON_ERROR_NONE;
299 }
300
301
302 static int _ioty_get_header_options(GVariantIter *src, int src_size,
303                 OCHeaderOption dest[], int dest_size)
304 {
305         gsize len;
306         char *option_data;
307         unsigned short option_id;
308
309         RETV_IF(NULL == dest, IOTCON_ERROR_INVALID_PARAMETER);
310
311         if (dest_size < src_size) {
312                 ERR("Exceed Size(%d)", src_size);
313                 return IOTCON_ERROR_INVALID_PARAMETER;
314         }
315
316         while (g_variant_iter_loop(src, "(q&s)", &option_id, &option_data)) {
317                 dest[i].protocolID = OC_COAP_ID;
318                 dest[i].optionID = option_id;
319                 dest[i].optionLength = strlen(option_data)+1;
320                 memcpy(dest[i].optionData, option_data, dest[i].optionLength);
321         }
322
323         return IOTCON_ERROR_NONE;
324 }
325
326 /*
327  * returned string SHOULD be released by you
328  */
329 static char* _icd_ioty_resource_generate_uri(char *host, char *uri_path, GVariant *query)
330 {
331         int len;
332         bool loop_first = true;
333         char *key, *value;
334         GVariantIter *queryIter;
335         char uri_buf[PATH_MAX] = {0};
336
337         len = snprintf(uri_buf, sizeof(uri_buf), "%s%s", host, uri_path);
338         if (len < 0) {
339                 ERR("snprintf() Fail");
340                 return NULL;
341         }
342
343         /* remove suffix '/' */
344         if ('/' == uri_buf[strlen(uri_buf) - 1]) {
345                 uri_buf[strlen(uri_buf) - 1] = '\0';
346                 len--;
347         }
348
349         g_variant_get(query, "a(ss)", &queryIter);
350
351         while (g_variant_iter_loop(queryIter, "(&s&s)", &key, &value)) {
352                 int query_len;
353
354                 DBG("query exist. key(%s), value(%s)", key, value);
355
356                 if (true == loop_first) {
357                         query_len = snprintf(uri_buf + len, sizeof(uri_buf), "?%s=%s", key, value);
358                         loop_first = false;
359                 } else {
360                         query_len = snprintf(uri_buf + len, sizeof(uri_buf), "&%s=%s", key, value);
361                 }
362
363                 if (0 > query_len) {
364                         ERR("snprintf() Fail");
365                         g_variant_iter_free(queryIter);
366                         return NULL;
367                 }
368
369                 len += query_len;
370         }
371         g_variant_iter_free(queryIter);
372
373         return strdup(uri_buf);
374 }
375
376
377 int icd_ioty_get(GVariant *resource, GVariant *query, unsigned int signal_number,
378                 const char *sender)
379 {
380         FN_CALL;
381         int conn_type, options_size;
382         char *uri_path, *host, *uri;
383         OCStackResult result;
384         GVariantIter *options;
385         OCCallbackData cbdata = {0};
386         icd_sig_ctx_s *context;
387         int is_observable, ifaces, observe_handle;
388         OCHeaderOption oic_options[MAX_HEADER_OPTIONS];
389
390         g_variant_get(resource, "(&s&sba(qs)iii)", &uri_path, &host, &is_observable, &options,
391                         &ifaces, &observe_handle, &conn_type);
392
393         uri = _icd_ioty_resource_generate_uri(host, uri_path, query);
394         if (NULL == uri) {
395                 ERR("_icd_ioty_resource_generate_uri() Fail");
396                 g_variant_iter_free(options);
397                 return IOTCON_ERROR_INVALID_PARAMETER;
398         }
399
400         context = calloc(1, sizeof(icd_sig_ctx_s));
401         if (NULL == context) {
402                 ERR("calloc() Fail(%d)", errno);
403                 g_variant_iter_free(options);
404                 return IOTCON_ERROR_OUT_OF_MEMORY;
405         }
406         context->sender = ic_utils_strdup(sender);
407         context->signum = signal_number;
408
409         cbdata.context = context;
410         cbdata.cb = icd_ioty_ocprocess_get_cb;
411         cbdata.cd = _ioty_free_signal_context;
412
413         options_size = g_variant_iter_n_children(options);
414         if (0 != options_size) {
415                 int ret = _ioty_get_header_options(options, options_size, oic_options,
416                                 sizeof(oic_options) / sizeof(oic_options[0]));
417                 if (IOTCON_ERROR_NONE != ret) {
418                         ERR("_ioty_get_header_options() Fail(%d)", ret);
419                         free(context->sender);
420                         free(context);
421                         free(uri);
422                         g_variant_iter_free(options);
423                         return ret;
424                 }
425         }
426         g_variant_iter_free(options);
427
428         icd_ioty_csdk_lock();
429         /* TODO : QoS is come from lib. And user can set QoS to client structure.  */
430         result = OCDoResource(NULL, OC_REST_GET, uri, NULL, NULL, conn_type, OC_HIGH_QOS,
431                         &cbdata, options_size?oic_options:NULL, options_size);
432         icd_ioty_csdk_unlock();
433
434         free(uri);
435
436         if (OC_STACK_OK != result) {
437                 ERR("OCDoResource() Fail(%d)", result);
438                 free(context->sender);
439                 free(context);
440                 return IOTCON_ERROR_IOTIVITY;
441         }
442
443         return IOTCON_ERROR_NONE;
444 }
445
446
447 int icd_ioty_put(GVariant *resource, const char *repr, GVariant *query,
448                 unsigned int signal_number, const char *sender)
449 {
450         // TODO : To be implemented
451         return IOTCON_ERROR_NONE;
452 }
453
454
455 int icd_ioty_post(GVariant *resource, const char *repr, GVariant *query,
456                 unsigned int signal_number, const char *sender)
457 {
458         // TODO : To be implemented
459         return IOTCON_ERROR_NONE;
460 }
461
462
463 int icd_ioty_delete(GVariant *resource, unsigned int signal_number,
464                 const char *sender)
465 {
466         // TODO : To be implemented
467         return IOTCON_ERROR_NONE;
468 }
469
470
471 int icd_ioty_observer_start(GVariant *resource, int observe_type,
472                 GVariant *query, unsigned int signal_number, const char *sender, int *observe_h)
473 {
474         // TODO : To be implemented
475         return IOTCON_ERROR_NONE;
476 }
477
478
479 int icd_ioty_observer_stop(void *observe_h)
480 {
481         // TODO : To be implemented
482         return IOTCON_ERROR_NONE;
483 }
484
485
486 #ifdef DEVICE_INFO_IMPL /* not implemented in iotivity 0.9.1 */
487 int icd_ioty_register_device_info(GVariant *value)
488 {
489         // TODO : To be implemented
490         return IOTCON_ERROR_NONE;
491 }
492
493
494 int icd_ioty_get_device_info(const char *host_address,
495                 unsigned int signal_number, const char *sender)
496 {
497         // TODO : To be implemented
498         return IOTCON_ERROR_NONE;
499 }
500 #endif
501
502
503 int icd_ioty_register_platform_info(GVariant *value)
504 {
505         // TODO : To be implemented
506         return IOTCON_ERROR_NONE;
507 }
508
509
510 int icd_ioty_get_platform_info(const char *host_address, unsigned int signal_number,
511                 const char *sender)
512 {
513         // TODO : To be implemented
514         return IOTCON_ERROR_NONE;
515 }
516
517
518 iotcon_presence_h icd_ioty_subscribe_presence(const char *host_address,
519                 const char *resource_type, unsigned int signal_number, const char *sender)
520 {
521         // TODO : To be implemented
522         return NULL;
523 }
524
525
526 int icd_ioty_unsubscribe_presence(iotcon_presence_h presence_handle)
527 {
528         // TODO : To be implemented
529         return IOTCON_ERROR_NONE;
530 }
531
532
533 int icd_ioty_start_presence(unsigned int time_to_live)
534 {
535         // TODO : To be implemented
536         return IOTCON_ERROR_NONE;
537 }
538
539
540 int icd_ioty_stop_presence()
541 {
542         // TODO : To be implemented
543         return IOTCON_ERROR_NONE;
544 }