(ACR) Integrate notify_list and notify_all
[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
24 #include <octypes.h>
25 #include <ocstack.h>
26
27 #include "iotcon.h"
28 #include "ic-dbus.h"
29 #include "ic-utils.h"
30 #include "icd.h"
31 #include "icd-payload.h"
32 #include "icd-dbus.h"
33 #include "icd-ioty.h"
34 #include "icd-ioty-type.h"
35 #include "icd-ioty-ocprocess.h"
36
37 static 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
77 void icd_ioty_deinit(GThread *thread)
78 {
79         OCStackResult result;
80
81         icd_ioty_ocprocess_stop();
82         g_thread_join(thread);
83
84         result = OCStop();
85         if (OC_STACK_OK != result)
86                 ERR("OCStop() Fail(%d)", result);
87 }
88
89
90 OCResourceHandle icd_ioty_register_resource(const char *uri_path,
91                 const char* const* res_types, int ifaces, uint8_t properties)
92 {
93         FN_CALL;
94         int i;
95         OCStackResult ret;
96         OCResourceHandle handle;
97         const char *res_iface = NULL;
98
99         if (IOTCON_INTERFACE_DEFAULT & ifaces) {
100                 res_iface = IC_INTERFACE_DEFAULT;
101                 ifaces ^= IOTCON_INTERFACE_DEFAULT;
102         } else if (IOTCON_INTERFACE_LINK & ifaces) {
103                 res_iface = IC_INTERFACE_LINK;
104                 ifaces ^= IOTCON_INTERFACE_LINK;
105         } else if (IOTCON_INTERFACE_BATCH & ifaces) {
106                 res_iface = IC_INTERFACE_BATCH;
107                 ifaces ^= IOTCON_INTERFACE_BATCH;
108         } else if (IOTCON_INTERFACE_GROUP & ifaces) {
109                 res_iface = IC_INTERFACE_GROUP;
110                 ifaces ^= IOTCON_INTERFACE_GROUP;
111         } else {
112                 ERR("Invalid interface type(%d)", ifaces);
113                 return NULL;
114         }
115
116         /* Secure option is not supported yet. */
117         properties = (properties & OC_SECURE)? (properties ^ OC_SECURE):properties;
118
119         icd_ioty_csdk_lock();
120         ret = OCCreateResource(&handle, res_types[0], res_iface, uri_path,
121                         icd_ioty_ocprocess_req_handler, NULL, properties);
122         icd_ioty_csdk_unlock();
123         if (OC_STACK_OK != ret) {
124                 ERR("OCCreateResource() Fail(%d)", ret);
125                 return NULL;
126         }
127
128         for (i = 1; res_types[i]; i++)
129                 icd_ioty_bind_type(handle, res_types[i]);
130
131         if (IOTCON_INTERFACE_DEFAULT & ifaces)
132                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_DEFAULT);
133         if (IOTCON_INTERFACE_LINK & ifaces)
134                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_LINK);
135         if (IOTCON_INTERFACE_BATCH & ifaces)
136                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_BATCH);
137         if (IOTCON_INTERFACE_GROUP & ifaces)
138                 icd_ioty_bind_interface(handle, IOTCON_INTERFACE_GROUP);
139
140         return handle;
141 }
142
143
144 int icd_ioty_unregister_resource(OCResourceHandle handle)
145 {
146         OCStackResult ret;
147
148         icd_ioty_csdk_lock();
149         ret = OCDeleteResource(handle);
150         icd_ioty_csdk_unlock();
151
152         if (OC_STACK_OK != ret) {
153                 ERR("OCDeleteResource() Fail(%d)", ret);
154                 return icd_ioty_convert_error(ret);
155         }
156
157         return IOTCON_ERROR_NONE;
158 }
159
160
161 int icd_ioty_bind_interface(OCResourceHandle handle, iotcon_interface_e iface)
162 {
163         int ret;
164         OCStackResult result;
165         char *resource_interface;
166
167         ret = ic_utils_convert_interface_flag(iface, &resource_interface);
168         if (IOTCON_ERROR_NONE != ret) {
169                 ERR("ic_utils_convert_interface_flag(%d) Fail(%d)", iface, ret);
170                 return ret;
171         }
172
173         icd_ioty_csdk_lock();
174         result = OCBindResourceInterfaceToResource(handle, resource_interface);
175         icd_ioty_csdk_unlock();
176
177         if (OC_STACK_OK != result) {
178                 ERR("OCBindResourceInterfaceToResource() Fail(%d)", result);
179                 return icd_ioty_convert_error(result);
180         }
181
182         return IOTCON_ERROR_NONE;
183 }
184
185
186 int icd_ioty_bind_type(OCResourceHandle handle, const char *resource_type)
187 {
188         OCStackResult ret;
189
190         icd_ioty_csdk_lock();
191         ret = OCBindResourceTypeToResource(handle, resource_type);
192         icd_ioty_csdk_unlock();
193
194         if (OC_STACK_OK != ret) {
195                 ERR("OCBindResourceTypeToResource() Fail(%d)", ret);
196                 return icd_ioty_convert_error(ret);
197         }
198
199         return IOTCON_ERROR_NONE;
200 }
201
202
203 int icd_ioty_bind_resource(OCResourceHandle parent, OCResourceHandle child)
204 {
205         OCStackResult ret;
206
207         icd_ioty_csdk_lock();
208         ret = OCBindResource(parent, child);
209         icd_ioty_csdk_unlock();
210
211         if (OC_STACK_OK != ret) {
212                 ERR("OCBindResource() Fail(%d)", ret);
213                 return icd_ioty_convert_error(ret);
214         }
215
216         return IOTCON_ERROR_NONE;
217 }
218
219
220 int icd_ioty_unbind_resource(OCResourceHandle parent, OCResourceHandle child)
221 {
222         OCStackResult ret;
223
224         icd_ioty_csdk_lock();
225         ret = OCUnBindResource(parent, child);
226         icd_ioty_csdk_unlock();
227
228         if (OC_STACK_OK != ret) {
229                 ERR("OCUnBindResource() Fail(%d)", ret);
230                 return icd_ioty_convert_error(ret);
231         }
232
233         return IOTCON_ERROR_NONE;
234 }
235
236
237 int icd_ioty_notify(OCResourceHandle handle, GVariant *msg, GVariant *observers)
238 {
239         int i, error_code, obs_length, msg_length;
240         GVariant *repr_gvar;
241         GVariantIter obs_iter, msg_iter;
242         OCStackResult ret;
243         OCRepPayload *payload;
244
245         g_variant_iter_init(&obs_iter, observers);
246         obs_length = g_variant_iter_n_children(&obs_iter);
247
248         /* Variable-length Array */
249         OCObservationId obs_ids[obs_length];
250
251         for (i = 0; i < obs_length; i++)
252                 g_variant_iter_loop(&obs_iter, "i", &obs_ids[i]);
253
254         g_variant_iter_init(&msg_iter, msg);
255         msg_length = g_variant_iter_n_children(&msg_iter);
256         if (msg_length) {
257                 g_variant_iter_loop(&msg_iter, "(iv)", &error_code, &repr_gvar);
258                 /* TODO : How to use error_code. */
259                 payload = icd_payload_representation_from_gvariant(repr_gvar);
260         }
261
262         icd_ioty_csdk_lock();
263         /* TODO : QoS is come from lib. */
264         if (msg_length) {
265                 ret = OCNotifyListOfObservers(handle, obs_ids, obs_length, payload, OC_LOW_QOS);
266         } else {
267                 ret = OCNotifyAllObservers(handle, OC_LOW_QOS);
268         }
269         icd_ioty_csdk_unlock();
270
271         if (OC_STACK_NO_OBSERVERS == ret) {
272                 WARN("No Observers. Stop Notifying");
273                 return IOTCON_ERROR_NONE;
274         } else if (OC_STACK_OK != ret) {
275                 ERR("OCNotifyListOfObservers() Fail(%d)", ret);
276                 return icd_ioty_convert_error(ret);
277         }
278
279         return IOTCON_ERROR_NONE;
280 }
281
282
283 static int _ioty_get_header_options(GVariantIter *src, int src_size,
284                 OCHeaderOption dest[], int dest_size)
285 {
286         int i = 0;
287         char *option_data;
288         unsigned short option_id;
289
290         RETV_IF(NULL == dest, IOTCON_ERROR_INVALID_PARAMETER);
291
292         if (dest_size < src_size) {
293                 ERR("Exceed Size(%d)", src_size);
294                 return IOTCON_ERROR_INVALID_PARAMETER;
295         }
296
297         while (g_variant_iter_loop(src, "(q&s)", &option_id, &option_data)) {
298                 dest[i].protocolID = OC_COAP_ID;
299                 dest[i].optionID = option_id;
300                 dest[i].optionLength = strlen(option_data) + 1;
301                 memcpy(dest[i].optionData, option_data, dest[i].optionLength);
302                 i++;
303         }
304
305         return IOTCON_ERROR_NONE;
306 }
307
308
309 int icd_ioty_send_response(GVariant *resp)
310 {
311         char *new_uri_path;
312         GVariant *repr_gvar;
313         GVariantIter *options;
314         OCStackResult ret;
315         OCEntityHandlerResponse response = {0};
316         int result, error_code, options_size;
317         int64_t request_handle, resource_handle;
318
319         g_variant_get(resp, "(&sia(qs)ivxx)",
320                         &new_uri_path,
321                         &error_code,
322                         &options,
323                         &result,
324                         &repr_gvar,
325                         &request_handle,
326                         &resource_handle);
327
328         response.requestHandle = ICD_INT64_TO_POINTER(request_handle);
329         response.resourceHandle = ICD_INT64_TO_POINTER(resource_handle);
330         response.ehResult = (OCEntityHandlerResult)result;
331
332         if (OC_EH_RESOURCE_CREATED == response.ehResult)
333                 snprintf(response.resourceUri, sizeof(response.resourceUri), "%s", new_uri_path);
334
335         options_size = g_variant_iter_n_children(options);
336         response.numSendVendorSpecificHeaderOptions = options_size;
337
338         if (0 != options_size) {
339                 int ret= _ioty_get_header_options(options,
340                                 response.numSendVendorSpecificHeaderOptions,
341                                 response.sendVendorSpecificHeaderOptions,
342                                 sizeof(response.sendVendorSpecificHeaderOptions)
343                                 / sizeof(response.sendVendorSpecificHeaderOptions[0]));
344
345                 if (IOTCON_ERROR_NONE != ret)
346                         ERR("_ioty_get_header_options() Fail(%d)", ret);
347         }
348         g_variant_iter_free(options);
349
350         response.payload = (OCPayload*)icd_payload_representation_from_gvariant(repr_gvar);
351
352         /* related to block transfer */
353         response.persistentBufferFlag = 0;
354
355         icd_ioty_csdk_lock();
356         ret = OCDoResponse(&response);
357         icd_ioty_csdk_unlock();
358
359         if (OC_STACK_OK != ret) {
360                 ERR("OCDoResponse() Fail(%d)", ret);
361                 return icd_ioty_convert_error(ret);
362         }
363
364         return IOTCON_ERROR_NONE;
365 }
366
367
368 static void _ioty_free_signal_context(void *data)
369 {
370         icd_sig_ctx_s *context = data;
371         free(context->bus_name);
372         free(context);
373 }
374
375
376 int icd_ioty_find_resource(const char *host_address, const char *resource_type,
377                 unsigned int signum, const char *bus_name)
378 {
379         int len;
380         OCStackResult result;
381         icd_sig_ctx_s *context;
382         char uri[PATH_MAX] = {0};
383         OCCallbackData cbdata = {0};
384         OCConnectivityType oic_conn_type;
385         iotcon_connectivity_type_e conn_type = IOTCON_CONNECTIVITY_IPV4;
386
387         if (IC_STR_EQUAL == strcmp(IOTCON_MULTICAST_ADDRESS, host_address)) {
388                 len = snprintf(uri, sizeof(uri), "%s", OC_RSRVD_WELL_KNOWN_URI);
389         } else {
390                 len = snprintf(uri, sizeof(uri), ICD_IOTY_COAP"%s%s", host_address,
391                                 OC_RSRVD_WELL_KNOWN_URI);
392         }
393         if (len <= 0 || sizeof(uri) <= len) {
394                 ERR("snprintf() Fail(%d)", len);
395                 return IOTCON_ERROR_IO_ERROR;
396         }
397
398         if (IC_STR_EQUAL != strcmp(IC_STR_NULL, resource_type))
399                 snprintf(uri + len, sizeof(uri) - len, "?rt=%s", resource_type);
400
401         context = calloc(1, sizeof(icd_sig_ctx_s));
402         if (NULL == context) {
403                 ERR("calloc() Fail(%d)", errno);
404                 return IOTCON_ERROR_OUT_OF_MEMORY;
405         }
406
407         context->bus_name = ic_utils_strdup(bus_name);
408         context->signum = signum;
409
410         cbdata.context = context;
411         cbdata.cb = icd_ioty_ocprocess_find_cb;
412         cbdata.cd = _ioty_free_signal_context;
413
414         oic_conn_type = icd_ioty_conn_type_to_oic_conn_type(conn_type);
415
416         icd_ioty_csdk_lock();
417         /* TODO : QoS is come from lib. */
418         result = OCDoResource(NULL, OC_REST_DISCOVER, uri, NULL, NULL, oic_conn_type,
419                         OC_LOW_QOS, &cbdata, NULL, 0);
420         icd_ioty_csdk_unlock();
421
422         if (OC_STACK_OK != result) {
423                 ERR("OCDoResource() Fail(%d)", result);
424                 free(context->bus_name);
425                 free(context);
426                 return icd_ioty_convert_error(result);
427         }
428
429         return IOTCON_ERROR_NONE;
430 }
431
432
433 /*
434  * returned string SHOULD be released by you
435  */
436 static char* _icd_ioty_resource_generate_uri(char *uri_path, GVariant *query)
437 {
438         int len;
439         bool loop_first = true;
440         char *key, *value;
441         GVariantIter query_iter;
442         char uri_buf[PATH_MAX] = {0};
443
444         len = snprintf(uri_buf, sizeof(uri_buf), "%s", uri_path);
445
446         /* remove suffix '/' */
447         if ('/' == uri_buf[strlen(uri_buf) - 1]) {
448                 uri_buf[strlen(uri_buf) - 1] = '\0';
449                 len--;
450         }
451
452         g_variant_iter_init(&query_iter, query);
453
454         while (g_variant_iter_loop(&query_iter, "(&s&s)", &key, &value)) {
455                 int query_len;
456
457                 DBG("query exist. key(%s), value(%s)", key, value);
458
459                 if (true == loop_first) {
460                         query_len = snprintf(uri_buf + len, sizeof(uri_buf) - len, "?%s=%s", key, value);
461                         loop_first = false;
462                 } else {
463                         query_len = snprintf(uri_buf + len, sizeof(uri_buf) - len, "&%s=%s", key, value);
464                 }
465
466                 len += query_len;
467         }
468
469         return strdup(uri_buf);
470 }
471
472
473 void icd_ioty_complete(int type, GDBusMethodInvocation *invocation, GVariant *value)
474 {
475         switch(type) {
476         case ICD_CRUD_GET:
477                 ic_dbus_complete_get(icd_dbus_get_object(), invocation, value);
478                 break;
479         case ICD_CRUD_PUT:
480                 ic_dbus_complete_put(icd_dbus_get_object(), invocation, value);
481                 break;
482         case ICD_CRUD_POST:
483                 ic_dbus_complete_post(icd_dbus_get_object(), invocation, value);
484                 break;
485         case ICD_CRUD_DELETE:
486                 ic_dbus_complete_delete(icd_dbus_get_object(), invocation, value);
487                 break;
488         }
489 }
490
491
492 void icd_ioty_complete_error(int type, GDBusMethodInvocation *invocation, int ret_val)
493 {
494         GVariant *value;
495
496         switch (type) {
497         case ICD_CRUD_GET:
498                 value = g_variant_new("(a(qs)vi)", NULL, NULL, ret_val);
499                 ic_dbus_complete_get(icd_dbus_get_object(), invocation, value);
500                 break;
501         case ICD_CRUD_PUT:
502                 value = g_variant_new("(a(qs)vi)", NULL, NULL, ret_val);
503                 ic_dbus_complete_put(icd_dbus_get_object(), invocation, value);
504                 break;
505         case ICD_CRUD_POST:
506                 value = g_variant_new("(a(qs)vi)", NULL, NULL, ret_val);
507                 ic_dbus_complete_post(icd_dbus_get_object(), invocation, value);
508                 break;
509         case ICD_CRUD_DELETE:
510                 value = g_variant_new("(a(qs)i)", NULL, ret_val);
511                 ic_dbus_complete_delete(icd_dbus_get_object(), invocation, value);
512                 break;
513         }
514 }
515
516
517 static gboolean _icd_ioty_crud(int type, icDbus *object, GDBusMethodInvocation *invocation,
518                 GVariant *resource, GVariant *query, GVariant *repr)
519 {
520         bool is_secure;
521         OCMethod rest_type;
522         OCStackResult result;
523         GVariantIter *options;
524         OCCallbackData cbdata = {0};
525         int conn_type, options_size;
526         char *uri_path, *host, *uri, *dev_host, *ptr = NULL;
527         OCHeaderOption oic_options[MAX_HEADER_OPTIONS];
528         OCHeaderOption *oic_options_ptr = NULL;
529         OCPayload *payload = NULL;
530         OCConnectivityType oic_conn_type;
531         OCDevAddr dev_addr = {0};
532
533         switch (type) {
534         case ICD_CRUD_GET:
535                 cbdata.cb = icd_ioty_ocprocess_get_cb;
536                 rest_type = OC_REST_GET;
537                 break;
538         case ICD_CRUD_PUT:
539                 cbdata.cb = icd_ioty_ocprocess_put_cb;
540                 rest_type = OC_REST_PUT;
541                 break;
542         case ICD_CRUD_POST:
543                 cbdata.cb = icd_ioty_ocprocess_post_cb;
544                 rest_type = OC_REST_POST;
545                 break;
546         case ICD_CRUD_DELETE:
547                 cbdata.cb = icd_ioty_ocprocess_delete_cb;
548                 rest_type = OC_REST_DELETE;
549                 break;
550         default:
551                 ERR("Invalid CRUD Type(%d)", type);
552                 return FALSE;
553         }
554
555         g_variant_get(resource, "(&s&sba(qs)i)", &uri_path, &host, &is_secure, &options,
556                         &conn_type);
557
558         switch (type) {
559         case ICD_CRUD_GET:
560         case ICD_CRUD_PUT:
561         case ICD_CRUD_POST:
562                 uri = _icd_ioty_resource_generate_uri(uri_path, query);
563                 if (NULL == uri) {
564                         ERR("_icd_ioty_resource_generate_uri() Fail");
565                         g_variant_iter_free(options);
566                         icd_ioty_complete_error(type, invocation, IOTCON_ERROR_INVALID_PARAMETER);
567                         return TRUE;
568                 }
569                 break;
570         case ICD_CRUD_DELETE:
571                 uri = strdup(uri_path);
572                 break;
573         }
574
575         cbdata.context = invocation;
576
577         options_size = g_variant_iter_n_children(options);
578         if (0 != options_size) {
579                 int ret = _ioty_get_header_options(options, options_size, oic_options,
580                                 sizeof(oic_options) / sizeof(oic_options[0]));
581                 if (IOTCON_ERROR_NONE != ret) {
582                         ERR("_ioty_get_header_options() Fail(%d)", ret);
583                         free(uri);
584                         g_variant_iter_free(options);
585                         icd_ioty_complete_error(type, invocation, ret);
586                         return TRUE;
587                 }
588                 oic_options_ptr = oic_options;
589         }
590         g_variant_iter_free(options);
591
592         if (repr)
593                 payload = (OCPayload*)icd_payload_representation_from_gvariant(repr);
594
595         oic_conn_type = icd_ioty_conn_type_to_oic_conn_type(conn_type);
596
597         icd_ioty_conn_type_to_oic_transport_type(conn_type, &dev_addr.adapter,
598                         &dev_addr.flags);
599
600         switch (conn_type) {
601         case IOTCON_CONNECTIVITY_IPV4:
602                 dev_host = strtok_r(host, ":", &ptr);
603                 snprintf(dev_addr.addr, sizeof(dev_addr.addr), "%s", dev_host);
604                 dev_addr.port = atoi(strtok_r(NULL, ":", &ptr));
605                 break;
606         case IOTCON_CONNECTIVITY_IPV6:
607                 dev_host = strtok_r(host, "]", &ptr);
608                 snprintf(dev_addr.addr, sizeof(dev_addr.addr), "%s", dev_host);
609                 dev_addr.port = atoi(strtok_r(NULL, "]", &ptr));
610                 break;
611         default:
612                 ERR("Invalid Connectivitiy Type");
613                 icd_ioty_complete_error(type, invocation, IOTCON_ERROR_IOTIVITY);
614                 free(uri);
615                 return TRUE;
616         }
617
618         icd_ioty_csdk_lock();
619         /* TODO : QoS is come from lib. And user can set QoS to client structure.  */
620         result = OCDoResource(NULL, rest_type, uri, &dev_addr, payload, oic_conn_type,
621                         OC_LOW_QOS, &cbdata, oic_options_ptr, options_size);
622         icd_ioty_csdk_unlock();
623
624         free(uri);
625
626         if (OC_STACK_OK != result) {
627                 ERR("OCDoResource() Fail(%d)", result);
628                 return icd_ioty_convert_error(result);
629                 return TRUE;
630         }
631
632         return TRUE;
633 }
634
635 gboolean icd_ioty_get(icDbus *object, GDBusMethodInvocation *invocation,
636                 GVariant *resource, GVariant *query)
637 {
638         return _icd_ioty_crud(ICD_CRUD_GET, object, invocation, resource, query, NULL);
639 }
640
641
642 gboolean icd_ioty_put(icDbus *object, GDBusMethodInvocation *invocation,
643                 GVariant *resource, GVariant *repr, GVariant *query)
644 {
645         return _icd_ioty_crud(ICD_CRUD_PUT, object, invocation, resource, query, repr);
646 }
647
648
649 gboolean icd_ioty_post(icDbus *object, GDBusMethodInvocation *invocation,
650                 GVariant *resource, GVariant *repr, GVariant *query)
651 {
652         return _icd_ioty_crud(ICD_CRUD_POST, object, invocation, resource, query, repr);
653 }
654
655
656 gboolean icd_ioty_delete(icDbus *object, GDBusMethodInvocation *invocation,
657                 GVariant *resource)
658 {
659         return _icd_ioty_crud(ICD_CRUD_DELETE, object, invocation, resource, NULL, NULL);
660 }
661
662
663 OCDoHandle icd_ioty_observer_start(GVariant *resource, int observe_type, GVariant *query,
664                 unsigned int signal_number, const char *bus_name)
665 {
666         bool is_secure;
667         OCMethod method;
668         OCDoHandle handle;
669         OCStackResult result;
670         GVariantIter *options;
671         icd_sig_ctx_s *context;
672         OCCallbackData cbdata = {0};
673         int conn_type, options_size;
674         char *uri_path, *host, *uri, *dev_host, *ptr = NULL;
675         OCHeaderOption oic_options[MAX_HEADER_OPTIONS];
676         OCHeaderOption *oic_options_ptr = NULL;
677         OCConnectivityType oic_conn_type;
678         OCDevAddr dev_addr = {0};
679
680         g_variant_get(resource, "(&s&sba(qs)i)", &uri_path, &host, &is_secure, &options,
681                         &conn_type);
682
683         uri = _icd_ioty_resource_generate_uri(uri_path, query);
684         if (NULL == uri) {
685                 ERR("_icd_ioty_resource_generate_uri() Fail");
686                 g_variant_iter_free(options);
687                 return NULL;
688         }
689
690         if (IOTCON_OBSERVE == observe_type)
691                 method = OC_REST_OBSERVE;
692         else if (IOTCON_OBSERVE_ALL == observe_type)
693                 method = OC_REST_OBSERVE_ALL;
694         else
695                 method = OC_REST_OBSERVE_ALL;
696
697         context = calloc(1, sizeof(icd_sig_ctx_s));
698         if (NULL == context) {
699                 ERR("calloc() Fail(%d)", errno);
700                 return NULL;
701         }
702         context->bus_name = ic_utils_strdup(bus_name);
703         context->signum = signal_number;
704
705         cbdata.context = context;
706         cbdata.cb = icd_ioty_ocprocess_observe_cb;
707         cbdata.cd = _ioty_free_signal_context;
708
709         options_size = g_variant_iter_n_children(options);
710         if (0 != options_size) {
711                 int ret = _ioty_get_header_options(options, options_size, oic_options,
712                                 sizeof(oic_options) / sizeof(oic_options[0]));
713                 if (IOTCON_ERROR_NONE != ret) {
714                         ERR("_ioty_get_header_options() Fail(%d)", ret);
715                         free(context->bus_name);
716                         free(context);
717                         free(uri);
718                         g_variant_iter_free(options);
719                         return NULL;
720                 }
721                 oic_options_ptr = oic_options;
722         }
723         g_variant_iter_free(options);
724
725         oic_conn_type = icd_ioty_conn_type_to_oic_conn_type(conn_type);
726
727         icd_ioty_conn_type_to_oic_transport_type(conn_type, &dev_addr.adapter,
728                         &dev_addr.flags);
729
730         switch (conn_type) {
731         case IOTCON_CONNECTIVITY_IPV4:
732                 dev_host = strtok_r(host, ":", &ptr);
733                 snprintf(dev_addr.addr, sizeof(dev_addr.addr), "%s", dev_host);
734                 dev_addr.port = atoi(strtok_r(NULL, ":", &ptr));
735                 break;
736         case IOTCON_CONNECTIVITY_IPV6:
737                 dev_host = strtok_r(host, "]", &ptr);
738                 snprintf(dev_addr.addr, sizeof(dev_addr.addr), "%s", dev_host);
739                 dev_addr.port = atoi(strtok_r(NULL, "]", &ptr));
740                 break;
741         default:
742                 ERR("Invalid Connectivitiy Type");
743                 free(context->bus_name);
744                 free(context);
745                 free(uri);
746                 return NULL;
747         }
748
749         icd_ioty_csdk_lock();
750         /* TODO : QoS is come from lib. And user can set QoS to client structure.  */
751         result = OCDoResource(&handle, method, uri, &dev_addr, NULL, oic_conn_type,
752                         OC_LOW_QOS, &cbdata, oic_options_ptr, options_size);
753         icd_ioty_csdk_unlock();
754         free(uri);
755         if (OC_STACK_OK != result) {
756                 ERR("OCDoResource() Fail(%d)", result);
757                 free(context->bus_name);
758                 free(context);
759                 return NULL;
760         }
761
762         return handle;
763 }
764
765
766 int icd_ioty_observer_stop(OCDoHandle handle, GVariant *options)
767 {
768         int options_size;
769         OCStackResult ret;
770         GVariantIter options_iter;
771         OCHeaderOption oic_options[MAX_HEADER_OPTIONS];
772         OCHeaderOption *oic_options_ptr = NULL;
773
774         g_variant_iter_init(&options_iter, options);
775
776         options_size = g_variant_iter_n_children(&options_iter);
777         if (0 != options_size) {
778                 int ret = _ioty_get_header_options(&options_iter, options_size, oic_options,
779                                 sizeof(oic_options) / sizeof(oic_options[0]));
780                 if (IOTCON_ERROR_NONE != ret) {
781                         ERR("_ioty_get_header_options() Fail(%d)", ret);
782                         return ret;
783                 }
784                 oic_options_ptr = oic_options;
785         }
786
787         icd_ioty_csdk_lock();
788         ret = OCCancel(handle, OC_HIGH_QOS, oic_options_ptr, options_size);
789         icd_ioty_csdk_unlock();
790         if (OC_STACK_OK != ret) {
791                 ERR("OCCancel() Fail(%d)", ret);
792                 return icd_ioty_convert_error(ret);
793         }
794
795         return IOTCON_ERROR_NONE;
796 }
797
798
799 int icd_ioty_register_device_info(GVariant *value)
800 {
801         OCStackResult result;
802         OCDeviceInfo device_info = {0};
803
804         g_variant_get(value, "(&s)", &device_info.deviceName);
805
806         icd_ioty_csdk_lock();
807         result = OCSetDeviceInfo(device_info);
808         icd_ioty_csdk_unlock();
809
810         if (OC_STACK_OK != result) {
811                 ERR("OCSetDeviceInfo() Fail(%d)", result);
812                 return icd_ioty_convert_error(result);
813         }
814
815         return IOTCON_ERROR_NONE;
816 }
817
818
819 int icd_ioty_register_platform_info(GVariant *value)
820 {
821         OCStackResult result;
822         OCPlatformInfo platform_info = {0};
823
824         g_variant_get(value, "(&s&s&s&s&s&s&s&s&s&s&s)",
825                         &platform_info.platformID,
826                         &platform_info.manufacturerName,
827                         &platform_info.manufacturerUrl,
828                         &platform_info.modelNumber,
829                         &platform_info.dateOfManufacture,
830                         &platform_info.platformVersion,
831                         &platform_info.operatingSystemVersion,
832                         &platform_info.hardwareVersion,
833                         &platform_info.firmwareVersion,
834                         &platform_info.supportUrl,
835                         &platform_info.systemTime);
836
837         icd_ioty_csdk_lock();
838         result = OCSetPlatformInfo(platform_info);
839         icd_ioty_csdk_unlock();
840
841         if (OC_STACK_OK != result) {
842                 ERR("OCSetPlatformInfo() Fail(%d)", result);
843                 return icd_ioty_convert_error(result);
844         }
845
846         return IOTCON_ERROR_NONE;
847 }
848
849
850 int icd_ioty_get_info(int type, const char *host_address, unsigned int signal_number,
851                 const char *bus_name)
852 {
853         OCStackResult result;
854         icd_sig_ctx_s *context;
855         OCCallbackData cbdata = {0};
856         char uri[PATH_MAX] = {0};
857         char *uri_path = NULL;
858         iotcon_connectivity_type_e conn_type = IOTCON_CONNECTIVITY_IPV4;
859         OCConnectivityType oic_conn_type;
860
861         if (ICD_DEVICE_INFO == type)
862                 uri_path = OC_RSRVD_DEVICE_URI;
863         else if (ICD_PLATFORM_INFO == type)
864                 uri_path = OC_RSRVD_PLATFORM_URI;
865         else
866                 return IOTCON_ERROR_INVALID_PARAMETER;
867
868         if (IC_STR_EQUAL == strcmp(IOTCON_MULTICAST_ADDRESS, host_address))
869                 snprintf(uri, sizeof(uri), "%s", uri_path);
870         else
871                 snprintf(uri, sizeof(uri), "%s%s", host_address, uri_path);
872
873         context = calloc(1, sizeof(icd_sig_ctx_s));
874         if (NULL == context) {
875                 ERR("calloc() Fail(%d)", errno);
876                 return IOTCON_ERROR_OUT_OF_MEMORY;
877         }
878         context->bus_name = ic_utils_strdup(bus_name);
879         context->signum = signal_number;
880
881         cbdata.context = context;
882         cbdata.cb = icd_ioty_ocprocess_info_cb;
883         cbdata.cd = _ioty_free_signal_context;
884
885         oic_conn_type = icd_ioty_conn_type_to_oic_conn_type(conn_type);
886
887         icd_ioty_csdk_lock();
888         /* TODO : QoS is come from lib. And user can set QoS to client structure.  */
889         result = OCDoResource(NULL, OC_REST_DISCOVER, uri, NULL, NULL, oic_conn_type,
890                         OC_LOW_QOS, &cbdata, NULL, 0);
891         icd_ioty_csdk_unlock();
892
893         if (OC_STACK_OK != result) {
894                 ERR("OCDoResource() Fail(%d)", result);
895                 free(context->bus_name);
896                 free(context);
897                 return icd_ioty_convert_error(result);
898         }
899
900         return IOTCON_ERROR_NONE;
901 }
902
903
904 OCDoHandle icd_ioty_subscribe_presence(const char *host_address,
905                 const char *resource_type, unsigned int signal_number, const char *bus_name)
906 {
907         int len;
908         OCDoHandle handle;
909         OCStackResult result;
910         char uri[PATH_MAX] = {0};
911         OCCallbackData cbdata = {0};
912         icd_sig_ctx_s *context;
913
914         len = snprintf(uri, sizeof(uri), "%s%s", host_address, OC_RSRVD_PRESENCE_URI);
915         if (len <= 0 || sizeof(uri) <= len) {
916                 ERR("snprintf() Fail(%d)", len);
917                 return NULL;
918         }
919
920         if (IC_STR_EQUAL != strcmp(IC_STR_NULL, resource_type))
921                 snprintf(uri + len, sizeof(uri) - len, "?rt=%s", resource_type);
922
923         context = calloc(1, sizeof(icd_sig_ctx_s));
924         if (NULL == context) {
925                 ERR("calloc() Fail(%d)", errno);
926                 return NULL;
927         }
928         context->bus_name = ic_utils_strdup(bus_name);
929         context->signum = signal_number;
930
931         cbdata.context = context;
932         cbdata.cb = icd_ioty_ocprocess_presence_cb;
933         cbdata.cd = _ioty_free_signal_context;
934
935         /* In case of IPV4 or IPV6, connectivity type is CT_ADAPTER_IP in iotivity 0.9.2 */
936         icd_ioty_csdk_lock();
937         result = OCDoResource(&handle, OC_REST_PRESENCE, uri, NULL, NULL, CT_ADAPTER_IP,
938                         OC_LOW_QOS, &cbdata, NULL, 0);
939         icd_ioty_csdk_unlock();
940
941         if (OC_STACK_OK != result) {
942                 ERR("OCDoResource() Fail(%d)", result);
943                 free(context->bus_name);
944                 free(context);
945                 return NULL;
946         }
947         return handle;
948 }
949
950
951 int icd_ioty_unsubscribe_presence(OCDoHandle handle)
952 {
953         OCStackResult ret;
954
955         icd_ioty_csdk_lock();
956         ret = OCCancel(handle, OC_LOW_QOS, NULL, 0);
957         icd_ioty_csdk_unlock();
958         if (OC_STACK_OK != ret) {
959                 ERR("OCCancel() Fail(%d)", ret);
960                 return icd_ioty_convert_error(ret);
961         }
962
963         return IOTCON_ERROR_NONE;
964 }
965
966
967 int icd_ioty_start_presence(unsigned int time_to_live)
968 {
969         OCStackResult ret;
970
971         icd_ioty_csdk_lock();
972         ret = OCStartPresence(time_to_live);
973         icd_ioty_csdk_unlock();
974         if (OC_STACK_OK != ret) {
975                 ERR("OCStartPresence() Fail(%d)", ret);
976                 return icd_ioty_convert_error(ret);
977         }
978
979         return IOTCON_ERROR_NONE;
980 }
981
982
983 int icd_ioty_stop_presence()
984 {
985         OCStackResult ret;
986
987         icd_ioty_csdk_lock();
988         ret = OCStopPresence();
989         icd_ioty_csdk_unlock();
990         if (OC_STACK_OK != ret) {
991                 ERR("OCStopPresence() Fail(%d)", ret);
992                 return icd_ioty_convert_error(ret);
993         }
994
995         return IOTCON_ERROR_NONE;
996 }