2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #include <ocpayload.h>
29 #include "icd-payload.h"
32 #include "icd-ioty-type.h"
33 #include "icd-ioty-ocprocess.h"
35 static int icd_ioty_alive;
37 typedef int (*_ocprocess_cb)(void *user_data);
39 struct icd_ioty_worker
46 struct icd_req_context {
47 int64_t signal_number;
52 OCRequestHandle request_h;
53 OCResourceHandle resource_h;
55 GVariantBuilder *options;
56 GVariantBuilder *query;
61 struct icd_find_context {
62 int64_t signal_number;
69 struct icd_crud_context {
73 GVariantBuilder *options;
74 GDBusMethodInvocation *invocation;
78 struct icd_info_context {
79 int64_t signal_number;
86 struct icd_observe_context {
87 int64_t signal_number;
92 GVariantBuilder *options;
96 struct icd_presence_context {
101 iotcon_presence_trigger_e trigger;
106 struct icd_encap_context {
107 int64_t signal_number;
108 OCRepPayload *oic_payload;
110 icd_encap_info_s *encap_info;
114 void icd_ioty_ocprocess_stop()
120 static void* _ocprocess_worker_thread(void *data)
123 struct icd_ioty_worker *worker = data;
126 ERR("worker is NULL");
130 ret = worker->cb(worker->ctx);
131 if (IOTCON_ERROR_NONE != ret)
132 ERR("cb() Fail(%d)", ret);
134 /* worker was allocated from _ocprocess_worker_start() */
137 /* GCC warning happen if use g_thread_exit() */
142 static int _ocprocess_worker_start(_ocprocess_cb cb, void *ctx)
146 struct icd_ioty_worker *worker;
148 RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
150 worker = calloc(1, sizeof(struct icd_ioty_worker));
151 if (NULL == worker) {
152 ERR("calloc() Fail(%d)", errno);
153 return IOTCON_ERROR_OUT_OF_MEMORY;
159 /* TODO : consider thread pool mechanism */
160 thread = g_thread_try_new("worker_thread", _ocprocess_worker_thread, worker, &error);
161 if (NULL == thread) {
162 ERR("g_thread_try_new() Fail(%s)", error->message);
165 return IOTCON_ERROR_SYSTEM;
168 /* DO NOT join thread. It was already detached by calling g_thread_unref() */
169 g_thread_unref(thread);
171 /* DO NOT FREE worker. It MUST be freed in the _ocprocess_worker_thread() */
173 return IOTCON_ERROR_NONE;
177 static int _ocprocess_response_signal(const char *dest, const char *signal_prefix,
178 int64_t signal_number, GVariant *value)
181 char signal_name[IC_DBUS_SIGNAL_LENGTH] = {0};
183 ret = snprintf(signal_name, sizeof(signal_name), "%s_%llx", signal_prefix, signal_number);
184 if (ret <= 0 || sizeof(signal_name) <= ret) {
185 ERR("snprintf() Fail(%d)", ret);
186 return IOTCON_ERROR_IO_ERROR;
189 ret = icd_dbus_emit_signal(dest, signal_name, value);
190 if (IOTCON_ERROR_NONE != ret) {
191 ERR("icd_dbus_emit_signal() Fail(%d)", ret);
195 return IOTCON_ERROR_NONE;
199 static inline GVariantBuilder* _ocprocess_parse_header_options(
200 OCHeaderOption *oic_option, int option_size)
203 GVariantBuilder *options;
205 options = g_variant_builder_new(G_VARIANT_TYPE("a(qs)"));
206 for (i = 0; i < option_size; i++) {
207 g_variant_builder_add(options, "(qs)", oic_option[i].optionID,
208 oic_option[i].optionData);
214 static int _ioty_oic_action_to_ioty_action(int oic_action)
218 switch (oic_action) {
219 case OC_OBSERVE_REGISTER:
220 action = IOTCON_OBSERVE_REGISTER;
222 case OC_OBSERVE_DEREGISTER:
223 action = IOTCON_OBSERVE_DEREGISTER;
225 case OC_OBSERVE_NO_OPTION:
227 ERR("Invalid action (%d)", oic_action);
228 action = IOTCON_OBSERVE_NO_TYPE;
234 static void _icd_req_context_free(struct icd_req_context *ctx)
238 g_variant_unref(ctx->payload);
239 g_variant_builder_unref(ctx->options);
240 g_variant_builder_unref(ctx->query);
246 static int _worker_req_handler(void *context)
251 GVariantBuilder payload_builder;
252 struct icd_req_context *ctx = context;
254 RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
256 g_variant_builder_init(&payload_builder, G_VARIANT_TYPE("av"));
258 g_variant_builder_add(&payload_builder, "v", ctx->payload);
262 ret = icd_ioty_get_host_address(ctx->dev_addr, &host_address, &conn_type);
263 if (IOTCON_ERROR_NONE != ret) {
264 ERR("icd_ioty_get_host_address() Fail(%d)", ret);
265 g_variant_builder_clear(&payload_builder);
266 _icd_req_context_free(ctx);
270 value = g_variant_new("(siia(qs)a(ss)iiavxx)",
279 ICD_POINTER_TO_INT64(ctx->request_h),
280 ICD_POINTER_TO_INT64(ctx->resource_h));
284 ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_REQUEST_HANDLER,
285 ctx->signal_number, value);
286 if (IOTCON_ERROR_NONE != ret)
287 ERR("_ocprocess_response_signal() Fail(%d)", ret);
289 _icd_req_context_free(ctx);
295 OCEntityHandlerResult icd_ioty_ocprocess_req_handler(OCEntityHandlerFlag flag,
296 OCEntityHandlerRequest *request, void *user_data)
300 int64_t signal_number;
301 char *query_str, *query_key, *query_value;
302 char *token, *save_ptr1, *save_ptr2;
303 char *bus_name = NULL;
304 struct icd_req_context *req_ctx;
307 RETV_IF(NULL == request, OC_EH_ERROR);
309 req_ctx = calloc(1, sizeof(struct icd_req_context));
310 if (NULL == req_ctx) {
311 ERR("calloc() Fail(%d)", errno);
316 req_ctx->request_h = request->requestHandle;
317 req_ctx->resource_h = request->resource;
319 ret = icd_dbus_client_list_get_info(req_ctx->resource_h, &signal_number, &bus_name);
320 if (IOTCON_ERROR_NONE != ret) {
321 ERR("icd_dbus_client_list_get_info() Fail(%d)", ret);
326 /* signal number & bus_name */
327 req_ctx->signal_number = signal_number;
328 req_ctx->bus_name = bus_name;
330 dev_addr = calloc(1, sizeof(OCDevAddr));
331 if (NULL == dev_addr) {
332 ERR("calloc() Fail(%d)", errno);
333 free(req_ctx->bus_name);
337 memcpy(dev_addr, &request->devAddr, sizeof(OCDevAddr));
338 req_ctx->dev_addr = dev_addr;
341 if (OC_REQUEST_FLAG & flag) {
342 switch (request->method) {
344 req_ctx->request_type = IOTCON_REQUEST_GET;
345 req_ctx->payload = NULL;
348 req_ctx->request_type = IOTCON_REQUEST_PUT;
349 req_ctx->payload = icd_payload_to_gvariant(request->payload);
352 req_ctx->request_type = IOTCON_REQUEST_POST;
353 req_ctx->payload = icd_payload_to_gvariant(request->payload);
356 req_ctx->request_type = IOTCON_REQUEST_DELETE;
357 req_ctx->payload = NULL;
360 free(req_ctx->dev_addr);
361 free(req_ctx->bus_name);
367 if (OC_OBSERVE_FLAG & flag) {
368 /* observation info*/
369 req_ctx->observe_id = request->obsInfo.obsId;
370 req_ctx->observe_type = _ioty_oic_action_to_ioty_action(request->obsInfo.action);
372 req_ctx->observe_type = IOTCON_OBSERVE_NO_TYPE;
376 req_ctx->options = _ocprocess_parse_header_options(
377 request->rcvdVendorSpecificHeaderOptions,
378 request->numRcvdVendorSpecificHeaderOptions);
381 req_ctx->query = g_variant_builder_new(G_VARIANT_TYPE("a(ss)"));
382 query_str = request->query;
383 while ((token = strtok_r(query_str, "&;", &save_ptr1))) {
384 while ((query_key = strtok_r(token, "=", &save_ptr2))) {
386 query_value = strtok_r(token, "=", &save_ptr2);
387 if (NULL == query_value)
390 g_variant_builder_add(req_ctx->query, "(ss)", query_key, query_value);
395 ret = _ocprocess_worker_start(_worker_req_handler, req_ctx);
396 if (IOTCON_ERROR_NONE != ret) {
397 ERR("_ocprocess_worker_start() Fail(%d)", ret);
398 _icd_req_context_free(req_ctx);
402 /* DO NOT FREE req_ctx. It MUST be freed in the _worker_req_handler func */
408 gpointer icd_ioty_ocprocess_thread(gpointer data)
411 OCStackResult result;
412 const struct timespec delay = {0, 10 * 1000 * 1000}; /* 10 ms */
415 while (icd_ioty_alive) {
416 icd_ioty_csdk_lock();
417 result = OCProcess();
418 icd_ioty_csdk_unlock();
419 if (OC_STACK_OK != result) {
420 ERR("OCProcess() Fail(%d)", result);
424 /* TODO : Current '10ms' is not proven sleep time. Revise the time after test.
425 * Or recommend changes to event driven architecture */
426 nanosleep(&delay, NULL);
433 static int _worker_find_cb(void *context)
437 struct icd_find_context *ctx = context;
439 RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
441 for (i = 0; ctx->payload[i]; i++) {
442 value = g_variant_new("(vi)", ctx->payload[i], ctx->conn_type);
443 /* TODO : If one device has multi resources, it comes as bulk data.
444 * To reduce the number of emit_signal, let's send signal only one time for one device.
445 * for ex, client list. */
446 ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_FOUND_RESOURCE,
447 ctx->signal_number, value);
448 if (IOTCON_ERROR_NONE != ret) {
449 ERR("_ocprocess_response_signal() Fail(%d)", ret);
450 g_variant_unref(value);
455 /* ctx was allocated from icd_ioty_ocprocess_find_cb() */
463 OCStackApplicationResult icd_ioty_ocprocess_find_cb(void *ctx, OCDoHandle handle,
464 OCClientResponse *resp)
467 struct icd_find_context *find_ctx;
468 icd_sig_ctx_s *sig_context = ctx;
470 RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
471 RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
472 if (NULL == resp->payload)
473 /* normal case : payload COULD be NULL */
474 return OC_STACK_KEEP_TRANSACTION;
475 RETVM_IF(PAYLOAD_TYPE_DISCOVERY != resp->payload->type,
476 OC_STACK_KEEP_TRANSACTION, "Invalid payload type(%d)", resp->payload->type);
478 find_ctx = calloc(1, sizeof(struct icd_find_context));
479 if (NULL == find_ctx) {
480 ERR("calloc() Fail(%d)", errno);
481 return OC_STACK_KEEP_TRANSACTION;
484 find_ctx->signal_number = sig_context->signal_number;
485 find_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
486 find_ctx->payload = icd_payload_res_to_gvariant(resp->payload, &resp->devAddr);
487 find_ctx->conn_type = icd_ioty_transport_flag_to_conn_type(resp->devAddr.adapter,
488 resp->devAddr.flags);
490 ret = _ocprocess_worker_start(_worker_find_cb, find_ctx);
491 if (IOTCON_ERROR_NONE != ret) {
492 ERR("_ocprocess_worker_start() Fail(%d)", ret);
493 free(find_ctx->bus_name);
494 ic_utils_gvariant_array_free(find_ctx->payload);
496 return OC_STACK_KEEP_TRANSACTION;
499 /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
500 /* DO NOT FREE find_ctx. It MUST be freed in the _worker_find_cb func */
502 return OC_STACK_KEEP_TRANSACTION;
506 static int _worker_crud_cb(void *context)
509 struct icd_crud_context *ctx = context;
511 RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
513 if (ICD_CRUD_DELETE == ctx->crud_type)
514 value = g_variant_new("(a(qs)i)", ctx->options, ctx->res);
516 value = g_variant_new("(a(qs)vi)", ctx->options, ctx->payload, ctx->res);
517 icd_ioty_complete(ctx->crud_type, ctx->invocation, value);
519 /* ctx was allocated from icd_ioty_ocprocess_xxx_cb() */
520 g_variant_builder_unref(ctx->options);
523 return IOTCON_ERROR_NONE;
527 static int _worker_info_cb(void *context)
530 const char *signal_prefix = NULL;
531 struct icd_info_context *ctx = context;
533 RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
535 if (ICD_DEVICE_INFO == ctx->info_type)
536 signal_prefix = IC_DBUS_SIGNAL_DEVICE;
537 else if (ICD_PLATFORM_INFO == ctx->info_type)
538 signal_prefix = IC_DBUS_SIGNAL_PLATFORM;
540 ret = _ocprocess_response_signal(ctx->bus_name, signal_prefix, ctx->signal_number,
542 if (IOTCON_ERROR_NONE != ret)
543 ERR("_ocprocess_response_signal() Fail(%d)", ret);
545 /* ctx was allocated from icd_ioty_ocprocess_info_cb() */
553 static int _ocprocess_worker(_ocprocess_cb cb, int type, OCPayload *payload, int res,
554 GVariantBuilder *options, void *ctx)
557 struct icd_crud_context *crud_ctx;
559 crud_ctx = calloc(1, sizeof(struct icd_crud_context));
560 if (NULL == crud_ctx) {
561 ERR("calloc() Fail(%d)", errno);
562 return IOTCON_ERROR_OUT_OF_MEMORY;
565 crud_ctx->crud_type = type;
566 crud_ctx->payload = icd_payload_to_gvariant(payload);
568 crud_ctx->options = options;
569 crud_ctx->invocation = ctx;
571 ret = _ocprocess_worker_start(cb, crud_ctx);
572 if (IOTCON_ERROR_NONE != ret) {
573 ERR("_ocprocess_worker_start() Fail(%d)", ret);
574 if (crud_ctx->payload)
575 g_variant_unref(crud_ctx->payload);
576 g_variant_builder_unref(crud_ctx->options);
580 /* DO NOT FREE crud_ctx. It MUST be freed in the _worker_crud_cb func */
585 static int _ocprocess_parse_oic_result(OCStackResult result)
591 res = IOTCON_RESPONSE_OK;
593 case OC_STACK_RESOURCE_CREATED:
594 res = IOTCON_RESPONSE_RESOURCE_CREATED;
596 case OC_STACK_RESOURCE_DELETED:
597 res = IOTCON_RESPONSE_RESULT_DELETED;
599 case OC_STACK_UNAUTHORIZED_REQ:
600 res = IOTCON_RESPONSE_FORBIDDEN;
603 WARN("response error(%d)", result);
604 res = IOTCON_RESPONSE_ERROR;
612 OCStackApplicationResult icd_ioty_ocprocess_get_cb(void *ctx, OCDoHandle handle,
613 OCClientResponse *resp)
617 GVariantBuilder *options;
619 RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
621 if (NULL == resp->payload) {
622 ERR("payload is empty");
623 icd_ioty_complete_error(ICD_CRUD_GET, ctx, IOTCON_ERROR_IOTIVITY);
624 return OC_STACK_DELETE_TRANSACTION;
627 res = _ocprocess_parse_oic_result(resp->result);
629 options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
630 resp->numRcvdVendorSpecificHeaderOptions);
632 ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_GET, resp->payload, res,
634 if (IOTCON_ERROR_NONE != ret) {
635 ERR("_ocprocess_worker() Fail(%d)", ret);
636 icd_ioty_complete_error(ICD_CRUD_GET, ctx, ret);
637 return OC_STACK_DELETE_TRANSACTION;
640 return OC_STACK_DELETE_TRANSACTION;
644 OCStackApplicationResult icd_ioty_ocprocess_put_cb(void *ctx, OCDoHandle handle,
645 OCClientResponse *resp)
649 GVariantBuilder *options;
651 RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
653 if (NULL == resp->payload) {
654 ERR("payload is empty");
655 icd_ioty_complete_error(ICD_CRUD_PUT, ctx, IOTCON_ERROR_IOTIVITY);
656 return OC_STACK_DELETE_TRANSACTION;
659 res = _ocprocess_parse_oic_result(resp->result);
661 options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
662 resp->numRcvdVendorSpecificHeaderOptions);
664 ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_PUT, resp->payload, res,
666 if (IOTCON_ERROR_NONE != ret) {
667 ERR("_ocprocess_worker() Fail(%d)", ret);
668 icd_ioty_complete_error(ICD_CRUD_PUT, ctx, ret);
669 return OC_STACK_DELETE_TRANSACTION;
672 return OC_STACK_DELETE_TRANSACTION;
676 OCStackApplicationResult icd_ioty_ocprocess_post_cb(void *ctx, OCDoHandle handle,
677 OCClientResponse *resp)
681 GVariantBuilder *options;
683 RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
685 if (NULL == resp->payload) {
686 ERR("payload is empty");
687 icd_ioty_complete_error(ICD_CRUD_POST, ctx, IOTCON_ERROR_IOTIVITY);
688 return OC_STACK_DELETE_TRANSACTION;
691 res = _ocprocess_parse_oic_result(resp->result);
693 options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
694 resp->numRcvdVendorSpecificHeaderOptions);
696 ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_POST, resp->payload, res,
698 if (IOTCON_ERROR_NONE != ret) {
699 ERR("_ocprocess_worker() Fail(%d)", ret);
700 icd_ioty_complete_error(ICD_CRUD_POST, ctx, ret);
701 return OC_STACK_DELETE_TRANSACTION;
704 return OC_STACK_DELETE_TRANSACTION;
708 OCStackApplicationResult icd_ioty_ocprocess_delete_cb(void *ctx, OCDoHandle handle,
709 OCClientResponse *resp)
713 GVariantBuilder *options;
715 RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
717 if (NULL == resp->payload) {
718 ERR("payload is empty");
719 icd_ioty_complete_error(ICD_CRUD_DELETE, ctx, IOTCON_ERROR_IOTIVITY);
720 return OC_STACK_DELETE_TRANSACTION;
723 res = _ocprocess_parse_oic_result(resp->result);
725 options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
726 resp->numRcvdVendorSpecificHeaderOptions);
728 ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_DELETE, NULL, res, options, ctx);
729 if (IOTCON_ERROR_NONE != ret) {
730 ERR("_ocprocess_worker() Fail(%d)", ret);
731 icd_ioty_complete_error(ICD_CRUD_DELETE, ctx, ret);
732 return OC_STACK_DELETE_TRANSACTION;
735 return OC_STACK_DELETE_TRANSACTION;
739 static int _worker_observe_cb(void *context)
743 struct icd_observe_context *ctx = context;
745 RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
747 value = g_variant_new("(a(qs)vii)", ctx->options, ctx->payload, ctx->res,
750 ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_OBSERVE,
751 ctx->signal_number, value);
752 if (IOTCON_ERROR_NONE != ret)
753 ERR("_ocprocess_response_signal() Fail(%d)", ret);
755 /* ctx was allocated from icd_ioty_ocprocess_observe_cb() */
757 g_variant_builder_unref(ctx->options);
764 static void _observe_cb_response_error(const char *dest,
765 int64_t signal_number, int ret_val)
770 GVariantBuilder options;
772 g_variant_builder_init(&options, G_VARIANT_TYPE("a(qs)"));
773 payload = icd_payload_representation_empty_gvariant();
775 value = g_variant_new("(a(qs)vii)", &options, payload, ret_val, 0);
777 ret = _ocprocess_response_signal(dest, IC_DBUS_SIGNAL_OBSERVE, signal_number, value);
778 if (IOTCON_ERROR_NONE != ret)
779 ERR("_ocprocess_response_signal() Fail(%d)", ret);
783 OCStackApplicationResult icd_ioty_ocprocess_observe_cb(void *ctx,
784 OCDoHandle handle, OCClientResponse *resp)
787 GVariantBuilder *options;
788 struct icd_observe_context *observe_ctx;
789 icd_sig_ctx_s *sig_context = ctx;
791 RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
793 if (NULL == resp->payload) {
794 ERR("payload is empty");
795 _observe_cb_response_error(sig_context->bus_name, sig_context->signal_number,
796 IOTCON_ERROR_IOTIVITY);
797 return OC_STACK_KEEP_TRANSACTION;
800 observe_ctx = calloc(1, sizeof(struct icd_observe_context));
801 if (NULL == observe_ctx) {
802 ERR("calloc() Fail(%d)", errno);
803 _observe_cb_response_error(sig_context->bus_name, sig_context->signal_number,
804 IOTCON_ERROR_OUT_OF_MEMORY);
805 return OC_STACK_KEEP_TRANSACTION;
808 res = _ocprocess_parse_oic_result(resp->result);
810 options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
811 resp->numRcvdVendorSpecificHeaderOptions);
813 observe_ctx->payload = icd_payload_to_gvariant(resp->payload);
814 observe_ctx->signal_number = sig_context->signal_number;
815 observe_ctx->res = res;
816 observe_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
817 observe_ctx->options = options;
819 ret = _ocprocess_worker_start(_worker_observe_cb, observe_ctx);
820 if (IOTCON_ERROR_NONE != ret) {
821 ERR("_ocprocess_worker_start() Fail(%d)", ret);
822 _observe_cb_response_error(sig_context->bus_name, sig_context->signal_number, ret);
823 free(observe_ctx->bus_name);
824 if (observe_ctx->payload)
825 g_variant_unref(observe_ctx->payload);
826 g_variant_builder_unref(observe_ctx->options);
828 return OC_STACK_KEEP_TRANSACTION;
831 /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
832 /* DO NOT FREE observe_ctx. It MUST be freed in the _worker_observe_cb func */
834 return OC_STACK_KEEP_TRANSACTION;
838 static int _worker_presence_cb(void *context)
843 GVariant *value, *value2;
844 int ret = IOTCON_ERROR_NONE;
845 struct icd_presence_context *ctx = context;
847 RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
849 ret = icd_ioty_get_host_address(ctx->dev_addr, &host_address, &conn_type);
850 if (IOTCON_ERROR_NONE != ret) {
851 ERR("icd_ioty_get_host_address() Fail(%d)", ret);
852 free(ctx->resource_type);
858 value = g_variant_new("(iusiis)", ctx->result, ctx->nonce, host_address, conn_type,
859 ctx->trigger, ic_utils_dbus_encode_str(ctx->resource_type));
860 value2 = g_variant_ref(value);
864 ret = _ocprocess_response_signal(NULL, IC_DBUS_SIGNAL_PRESENCE,
865 ICD_POINTER_TO_INT64(ctx->handle), value);
866 if (IOTCON_ERROR_NONE != ret)
867 ERR("_ocprocess_response_signal() Fail(%d)", ret);
869 handle = icd_ioty_presence_table_get_handle(ICD_MULTICAST_ADDRESS);
870 if (handle && (handle != ctx->handle)) {
871 ret = _ocprocess_response_signal(NULL, IC_DBUS_SIGNAL_PRESENCE,
872 ICD_POINTER_TO_INT64(handle), value2);
873 if (IOTCON_ERROR_NONE != ret)
874 ERR("_ocprocess_response_signal() Fail(%d)", ret);
876 g_variant_unref(value2);
879 /* ctx was allocated from icd_ioty_ocprocess_presence_cb() */
880 free(ctx->resource_type);
888 static void _presence_cb_response_error(OCDoHandle handle, int ret_val)
893 GVariant *value, *value2;
895 value = g_variant_new("(iusiis)", ret_val, 0, IC_STR_NULL, IOTCON_CONNECTIVITY_ALL,
896 IOTCON_PRESENCE_RESOURCE_CREATED, IC_STR_NULL);
897 value2 = g_variant_ref(value);
899 ret = _ocprocess_response_signal(NULL, IC_DBUS_SIGNAL_PRESENCE,
900 ICD_POINTER_TO_INT64(handle), value);
901 if (IOTCON_ERROR_NONE != ret)
902 ERR("_ocprocess_response_signal() Fail(%d)", ret);
904 handle2 = icd_ioty_presence_table_get_handle(ICD_MULTICAST_ADDRESS);
905 if (handle2 && (handle2 != handle)) {
906 ret = _ocprocess_response_signal(NULL, IC_DBUS_SIGNAL_PRESENCE,
907 ICD_POINTER_TO_INT64(handle), value2);
908 if (IOTCON_ERROR_NONE != ret)
909 ERR("_ocprocess_response_signal() Fail(%d)", ret);
911 g_variant_unref(value2);
916 static int _presence_trigger_to_ioty_trigger(OCPresenceTrigger src,
917 iotcon_presence_trigger_e *dest)
919 RETV_IF(NULL == dest, IOTCON_ERROR_INVALID_PARAMETER);
922 case OC_PRESENCE_TRIGGER_CREATE:
923 *dest = IOTCON_PRESENCE_RESOURCE_CREATED;
925 case OC_PRESENCE_TRIGGER_CHANGE:
926 *dest = IOTCON_PRESENCE_RESOURCE_UPDATED;
928 case OC_PRESENCE_TRIGGER_DELETE:
929 *dest = IOTCON_PRESENCE_RESOURCE_DESTROYED;
932 ERR("Invalid trigger(%d)", src);
933 return IOTCON_ERROR_INVALID_PARAMETER;
936 return IOTCON_ERROR_NONE;
940 OCStackApplicationResult icd_ioty_ocprocess_presence_cb(void *ctx, OCDoHandle handle,
941 OCClientResponse *resp)
946 OCPresencePayload *payload;
947 struct icd_presence_context *presence_ctx;
949 RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
951 presence_ctx = calloc(1, sizeof(struct icd_presence_context));
952 if (NULL == presence_ctx) {
953 ERR("calloc() Fail(%d)", errno);
954 _presence_cb_response_error(handle, IOTCON_ERROR_OUT_OF_MEMORY);
955 return OC_STACK_KEEP_TRANSACTION;
958 dev_addr = calloc(1, sizeof(OCDevAddr));
959 if (NULL == dev_addr) {
960 ERR("calloc() Fail(%d)", errno);
961 _presence_cb_response_error(handle, IOTCON_ERROR_OUT_OF_MEMORY);
963 return OC_STACK_KEEP_TRANSACTION;
965 memcpy(dev_addr, &resp->devAddr, sizeof(OCDevAddr));
967 payload = (OCPresencePayload*)resp->payload;
969 switch (resp->result) {
971 presence_ctx->result = IOTCON_PRESENCE_OK;
972 ret = _presence_trigger_to_ioty_trigger(payload->trigger, &presence_ctx->trigger);
973 if (IOTCON_ERROR_NONE != ret) {
974 ERR("_presence_trigger_to_ioty_trigger() Fail(%d)", ret);
975 _presence_cb_response_error(handle, ret);
977 return OC_STACK_KEEP_TRANSACTION;
980 case OC_STACK_PRESENCE_STOPPED:
981 presence_ctx->result = IOTCON_PRESENCE_STOPPED;
983 case OC_STACK_PRESENCE_TIMEOUT:
984 presence_ctx->result = IOTCON_PRESENCE_TIMEOUT;
988 DBG("Presence error(%d)", resp->result);
989 presence_ctx->result = IOTCON_ERROR_IOTIVITY;
992 presence_ctx->handle = handle;
993 presence_ctx->nonce = resp->sequenceNumber;
994 presence_ctx->dev_addr = dev_addr;
996 if (payload->resourceType)
997 presence_ctx->resource_type = strdup(payload->resourceType);
999 ret = _ocprocess_worker_start(_worker_presence_cb, presence_ctx);
1000 if (IOTCON_ERROR_NONE != ret) {
1001 ERR("_ocprocess_worker_start() Fail(%d)", ret);
1002 _presence_cb_response_error(handle, ret);
1003 free(presence_ctx->resource_type);
1004 free(presence_ctx->dev_addr);
1006 return OC_STACK_KEEP_TRANSACTION;
1009 /* DO NOT FREE presence_ctx. It MUST be freed in the _worker_presence_cb func */
1011 return OC_STACK_KEEP_TRANSACTION;
1015 OCStackApplicationResult icd_ioty_ocprocess_info_cb(void *ctx, OCDoHandle handle,
1016 OCClientResponse *resp)
1020 struct icd_info_context *info_ctx;
1021 icd_sig_ctx_s *sig_context = ctx;
1023 RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
1024 RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
1025 RETV_IF(NULL == resp->payload, OC_STACK_KEEP_TRANSACTION);
1027 if (PAYLOAD_TYPE_DEVICE == resp->payload->type)
1028 info_type = ICD_DEVICE_INFO;
1029 else if (PAYLOAD_TYPE_PLATFORM == resp->payload->type)
1030 info_type = ICD_PLATFORM_INFO;
1032 return OC_STACK_KEEP_TRANSACTION;
1034 info_ctx = calloc(1, sizeof(struct icd_info_context));
1035 if (NULL == info_ctx) {
1036 ERR("calloc() Fail(%d)", errno);
1037 return OC_STACK_KEEP_TRANSACTION;
1040 info_ctx->info_type = info_type;
1041 info_ctx->payload = icd_payload_to_gvariant(resp->payload);
1042 info_ctx->signal_number = sig_context->signal_number;
1043 info_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
1045 ret = _ocprocess_worker_start(_worker_info_cb, info_ctx);
1046 if (IOTCON_ERROR_NONE != ret) {
1047 ERR("_ocprocess_worker_start() Fail(%d)", ret);
1048 free(info_ctx->bus_name);
1049 if (info_ctx->payload)
1050 g_variant_unref(info_ctx->payload);
1052 return OC_STACK_KEEP_TRANSACTION;
1055 /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
1056 /* DO NOT FREE info_ctx. It MUST be freed in the _worker_info_cb func */
1058 return OC_STACK_KEEP_TRANSACTION;
1062 static int _worker_encap_get_cb(void *context)
1065 struct icd_encap_context *ctx = context;
1066 iotcon_remote_resource_state_e resource_state;
1067 GVariant *monitoring_value, *caching_value;
1069 RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
1072 if (0 < ctx->encap_info->monitoring_count) {
1075 resource_state = IOTCON_REMOTE_RESOURCE_ALIVE;
1077 case OC_STACK_ERROR:
1079 resource_state = IOTCON_REMOTE_RESOURCE_LOST_SIGNAL;
1081 if (resource_state != ctx->encap_info->resource_state) {
1082 ctx->encap_info->resource_state = resource_state;
1083 monitoring_value = g_variant_new("(i)", resource_state);
1084 ret = _ocprocess_response_signal(NULL, IC_DBUS_SIGNAL_MONITORING,
1085 ctx->encap_info->signal_number, monitoring_value);
1086 if (IOTCON_ERROR_NONE != ret) {
1087 ERR("_ocprocess_response_signal() Fail(%d)", ret);
1088 OCRepPayloadDestroy(ctx->oic_payload);
1096 if (0 < ctx->encap_info->caching_count) {
1097 if (OC_STACK_OK != ctx->ret) {
1098 OCRepPayloadDestroy(ctx->oic_payload);
1100 return IOTCON_ERROR_NONE;
1103 ret = icd_payload_representation_compare(ctx->encap_info->oic_payload,
1105 if (IC_EQUAL == ret) {
1106 OCRepPayloadDestroy(ctx->oic_payload);
1108 return IOTCON_ERROR_NONE;
1111 ctx->encap_info->oic_payload = ctx->oic_payload;
1112 caching_value = icd_payload_to_gvariant((OCPayload*)ctx->oic_payload);
1114 ret = _ocprocess_response_signal(NULL, IC_DBUS_SIGNAL_CACHING,
1115 ctx->encap_info->signal_number, caching_value);
1116 if (IOTCON_ERROR_NONE != ret) {
1117 ERR("_ocprocess_response_signal() Fail(%d)", ret);
1118 OCRepPayloadDestroy(ctx->oic_payload);
1124 OCRepPayloadDestroy(ctx->oic_payload);
1127 return IOTCON_ERROR_NONE;
1131 OCStackApplicationResult icd_ioty_ocprocess_encap_get_cb(void *ctx, OCDoHandle handle,
1132 OCClientResponse *resp)
1136 icd_encap_info_s *encap_info = ctx;
1137 struct icd_encap_context *encap_ctx;
1139 RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
1141 encap_ctx = calloc(1, sizeof(struct icd_encap_context));
1142 if (NULL == encap_ctx) {
1143 ERR("calloc() Fail(%d)", errno);
1144 return OC_STACK_DELETE_TRANSACTION;
1147 encap_ctx->ret = resp->result;
1148 encap_ctx->oic_payload = OCRepPayloadClone((OCRepPayload*)resp->payload);
1149 encap_ctx->encap_info = encap_info;
1151 ret = _ocprocess_worker_start(_worker_encap_get_cb, encap_ctx);
1152 if (IOTCON_ERROR_NONE != ret) {
1153 ERR("_ocprocess_worker_start() Fail(%d)", ret);
1154 OCRepPayloadDestroy((OCRepPayload*)encap_ctx->oic_payload);
1156 return OC_STACK_DELETE_TRANSACTION;
1159 return OC_STACK_DELETE_TRANSACTION;
1163 static int _worker_encap_get(void *context)
1165 icd_encap_info_s *encap_info = context;
1167 g_source_remove(encap_info->get_timer_id);
1168 icd_ioty_encap_get(encap_info);
1169 encap_info->get_timer_id = g_timeout_add_seconds(icd_ioty_encap_get_time_interval(),
1170 icd_ioty_encap_get, encap_info);
1172 return IOTCON_ERROR_NONE;
1176 OCStackApplicationResult icd_ioty_ocprocess_encap_observe_cb(void *ctx, OCDoHandle handle,
1177 OCClientResponse *resp)
1182 RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
1184 ret = _ocprocess_worker_start(_worker_encap_get, ctx);
1185 if (IOTCON_ERROR_NONE != ret) {
1186 ERR("_ocprocess_worker_start() Fail(%d)", ret);
1187 return OC_STACK_KEEP_TRANSACTION;
1190 return OC_STACK_KEEP_TRANSACTION;
1194 OCStackApplicationResult icd_ioty_ocprocess_encap_presence_cb(void *ctx,
1195 OCDoHandle handle, OCClientResponse *resp)
1199 OCPresencePayload *payload = (OCPresencePayload*)resp->payload;
1201 RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
1203 if ((OC_STACK_OK == resp->result) && (OC_PRESENCE_TRIGGER_DELETE != payload->trigger))
1204 return OC_STACK_KEEP_TRANSACTION;
1206 ret = _ocprocess_worker_start(_worker_encap_get, ctx);
1207 if (IOTCON_ERROR_NONE != ret) {
1208 ERR("_ocprocess_worker_start() Fail(%d)", ret);
1209 return OC_STACK_KEEP_TRANSACTION;
1212 return OC_STACK_KEEP_TRANSACTION;