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.
18 #include <unistd.h> /* for usleep() */
20 #include <json-glib/json-glib.h>
30 #include "icd-ioty-ocprocess.h"
32 static int icd_ioty_alive;
34 typedef int (*_ocprocess_fn)(void *user_data);
36 struct icd_ioty_worker
45 ICD_TRANSPORT_IPV4_SECURE,
50 struct icd_req_context {
57 OCRequestHandle request_h;
58 OCResourceHandle resource_h;
59 GVariantBuilder *options;
60 GVariantBuilder *query;
64 struct icd_find_context {
73 struct icd_crud_context {
77 GVariantBuilder *options;
78 GDBusMethodInvocation *invocation;
82 struct icd_observe_context {
88 GVariantBuilder *options;
92 struct icd_presence_context {
100 void icd_ioty_ocprocess_stop()
105 static void* _ocprocess_worker_thread(void *data)
108 struct icd_ioty_worker *worker = data;
111 ERR("worker is NULL");
115 ret = worker->fn(worker->ctx);
116 if (IOTCON_ERROR_NONE != ret)
117 ERR("fn() Fail(%d)", ret);
119 /* worker was allocated from _ocprocess_worker_start() */
122 /* GCC warning happen if use g_thread_exit() */
127 static int _ocprocess_worker_start(_ocprocess_fn fn, void *ctx)
131 struct icd_ioty_worker *worker;
133 RETV_IF(NULL == fn, IOTCON_ERROR_INVALID_PARAMETER);
135 worker = calloc(1, sizeof(struct icd_ioty_worker));
136 if (NULL == worker) {
137 ERR("calloc() Fail(%d)", errno);
138 return IOTCON_ERROR_OUT_OF_MEMORY;
144 /* TODO : consider thread pool mechanism */
145 thread = g_thread_try_new("worker_thread", _ocprocess_worker_thread, worker, &error);
146 if (NULL == thread) {
147 ERR("g_thread_try_new() Fail(%s)", error->message);
150 return IOTCON_ERROR_SYSTEM;
153 /* DO NOT join thread. It was already detached by calling g_thread_unref() */
154 g_thread_unref(thread);
156 /* DO NOT FREE worker. It MUST be freed in the _ocprocess_worker_thread() */
158 return IOTCON_ERROR_NONE;
162 static int _ocprocess_response_signal(const char *dest, const char *signal,
163 unsigned int signum, GVariant *value)
166 char sig_name[IC_DBUS_SIGNAL_LENGTH] = {0};
168 ret = snprintf(sig_name, sizeof(sig_name), "%s_%u", signal, signum);
169 if (ret <= 0 || sizeof(sig_name) <= ret) {
170 ERR("snprintf() Fail(%d)", ret);
171 return IOTCON_ERROR_UNKNOWN;
174 ret = icd_dbus_emit_signal(dest, sig_name, value);
175 if (IOTCON_ERROR_NONE != ret) {
176 ERR("icd_dbus_emit_signal() Fail(%d)", ret);
180 return IOTCON_ERROR_NONE;
184 static inline GVariantBuilder* _ocprocess_parse_header_options(
185 OCHeaderOption *oic_option, int option_size)
188 GVariantBuilder *options;
190 options = g_variant_builder_new(G_VARIANT_TYPE("a(qs)"));
191 for (i = 0; i < option_size; i++) {
192 g_variant_builder_add(options, "(qs)", oic_option[i].optionID,
193 oic_option[i].optionData);
200 static int _worker_req_handler(void *context)
204 struct icd_req_context *ctx = context;
206 RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
208 value = g_variant_new("(ia(qs)a(ss)iisii)",
215 GPOINTER_TO_INT(ctx->request_h),
216 GPOINTER_TO_INT(ctx->resource_h));
218 ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_REQUEST_HANDLER,
220 if (IOTCON_ERROR_NONE != ret)
221 ERR("_ocprocess_response_signal() Fail(%d)", ret);
225 g_variant_builder_unref(ctx->options);
226 g_variant_builder_unref(ctx->query);
233 OCEntityHandlerResult icd_ioty_ocprocess_req_handler(OCEntityHandlerFlag flag,
234 OCEntityHandlerRequest *request)
238 unsigned int signal_number;
239 char *query_str, *query_key, *query_value;
240 char *token, *save_ptr1, *save_ptr2;
241 char *bus_name = NULL;
242 struct icd_req_context *req_ctx;
244 RETV_IF(NULL == request, OC_EH_ERROR);
246 req_ctx = calloc(1, sizeof(struct icd_req_context));
247 if (NULL == req_ctx) {
248 ERR("calloc() Fail(%d)", errno);
253 req_ctx->request_h = request->requestHandle;
254 req_ctx->resource_h = request->resource;
256 ret = icd_dbus_client_list_get_info(req_ctx->resource_h, &signal_number, &bus_name);
257 if (IOTCON_ERROR_NONE != ret) {
258 ERR("icd_dbus_client_list_get_info() Fail(%d)", ret);
263 /* signal number & bus_name */
264 req_ctx->signum = signal_number;
265 req_ctx->bus_name = bus_name;
268 if (OC_REQUEST_FLAG & flag) {
269 switch (request->method) {
271 req_ctx->types = IOTCON_REQUEST_GET;
272 req_ctx->payload = strdup(IC_STR_NULL);
274 if (OC_OBSERVE_FLAG & flag) {
275 req_ctx->types |= IOTCON_REQUEST_OBSERVE;
276 /* observation info*/
277 req_ctx->observer_id = request->obsInfo.obsId;
278 req_ctx->observe_action = request->obsInfo.action;
282 req_ctx->types = IOTCON_REQUEST_PUT;
283 req_ctx->payload = ic_utils_strdup(request->reqJSONPayload);
286 req_ctx->types = IOTCON_REQUEST_POST;
287 req_ctx->payload = ic_utils_strdup(request->reqJSONPayload);
290 req_ctx->types = IOTCON_REQUEST_DELETE;
291 req_ctx->payload = strdup(IC_STR_NULL);
294 free(req_ctx->bus_name);
301 req_ctx->options = _ocprocess_parse_header_options(
302 request->rcvdVendorSpecificHeaderOptions,
303 request->numRcvdVendorSpecificHeaderOptions);
306 req_ctx->query = g_variant_builder_new(G_VARIANT_TYPE("a(ss)"));
307 query_str = request->query;
308 while ((token = strtok_r(query_str, "&", &save_ptr1))) {
309 while ((query_key = strtok_r(token, "=", &save_ptr2))) {
311 query_value = strtok_r(token, "=", &save_ptr2);
312 if (NULL == query_value)
315 g_variant_builder_add(req_ctx->query, "(ss)", query_key, query_value);
320 ret = _ocprocess_worker_start(_worker_req_handler, req_ctx);
321 if (IOTCON_ERROR_NONE != ret) {
322 ERR("_ocprocess_worker_start() Fail(%d)", ret);
323 free(req_ctx->bus_name);
324 free(req_ctx->payload);
325 g_variant_builder_unref(req_ctx->options);
326 g_variant_builder_unref(req_ctx->query);
331 /* DO NOT FREE req_ctx. It MUST be freed in the _worker_req_handler func */
337 gpointer icd_ioty_ocprocess_thread(gpointer data)
340 OCStackResult result;
343 while (icd_ioty_alive) {
344 icd_ioty_csdk_lock();
345 result = OCProcess();
346 icd_ioty_csdk_unlock();
347 if (OC_STACK_OK != result) {
348 ERR("OCProcess() Fail(%d)", result);
352 /* TODO : SHOULD revise time or usleep */
361 * returned string SHOULD be released by you
363 static inline char* _find_cb_get_address(OCDevAddr *address, int sec_type, int sec_port)
369 char addr[1024] = {0};
371 RETVM_IF(ICD_TRANSPORT_IPV4 != sec_type && ICD_TRANSPORT_IPV4_SECURE != sec_type,
372 NULL, "Invalid secure type(%d)", sec_type);
374 ret = OCDevAddrToIPv4Addr(address, &a, &b, &c, &d);
375 if (OC_STACK_OK != ret) {
376 ERR("OCDevAddrToIPv4Addr() Fail(%d)", ret);
380 if (ICD_TRANSPORT_IPV4_SECURE == sec_type) {
381 if (sec_port <= 0 || 65535 < sec_port) {
382 SECURE_ERR("Invalid secure port(%d)", sec_port);
386 ret = snprintf(addr, sizeof(addr), ICD_IOTY_COAPS"%d.%d.%d.%d:%d", a, b, c, d,
389 ret = OCDevAddrToPort(address, &port);
390 if (OC_STACK_OK != ret) {
391 ERR("OCDevAddrToPort() Fail(%d)", ret);
395 ret = snprintf(addr, sizeof(addr), ICD_IOTY_COAP"%d.%d.%d.%d:%d", a, b, c, d,
399 WARN_IF(ret <= 0 || sizeof(addr) <= ret, "snprintf() Fail(%d)", ret);
401 return ic_utils_strdup(addr);
405 static inline int _find_cb_response(JsonObject *rsrc_obj,
406 struct icd_find_context *ctx)
411 char *host, *json_data;
412 JsonObject *property_obj;
413 int ret, secure, secure_type, secure_port;
415 RETV_IF(NULL == rsrc_obj, IOTCON_ERROR_INVALID_PARAMETER);
416 RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
418 /* parse secure secure_port */
419 property_obj = json_object_get_object_member(rsrc_obj, IC_JSON_KEY_PROPERTY);
420 if (NULL == property_obj) {
421 ERR("json_object_get_object_member() Fail");
422 return IOTCON_ERROR_INVALID_PARAMETER;
425 secure = json_object_get_int_member(property_obj, IC_JSON_KEY_SECURE);
427 secure_type = ICD_TRANSPORT_IPV4;
430 secure_type = ICD_TRANSPORT_IPV4_SECURE;
431 secure_port = json_object_get_int_member(property_obj, IC_JSON_KEY_PORT);
434 host = _find_cb_get_address(ctx->dev_addr, secure_type, secure_port);
436 ERR("_find_cb_get_address() Fail");
437 return IOTCON_ERROR_IOTIVITY;
440 gen = json_generator_new();
441 root_node = json_node_new(JSON_NODE_OBJECT);
442 json_node_set_object(root_node, rsrc_obj);
443 json_generator_set_root(gen, root_node);
445 json_data = json_generator_to_data(gen, NULL);
446 json_node_free(root_node);
449 value = g_variant_new("(ssi)", json_data, host, ctx->conn_type);
453 /* TODO : If one device has multi resources, it comes as bulk data.
454 * To reduce the number of emit_signal, let's send signal only one time for one device.
455 * for ex, client list. */
456 ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_FOUND_RESOURCE,
458 if (IOTCON_ERROR_NONE != ret) {
459 ERR("_ocprocess_response_signal() Fail(%d)", ret);
463 return IOTCON_ERROR_NONE;
467 static inline int _find_cb_handle_context(struct icd_find_context *ctx)
471 GError *error = NULL;
472 JsonObject *root_obj;
473 JsonArray *rsrc_array;
474 unsigned int rsrc_count, rsrc_index;
476 RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
477 RETV_IF(NULL == ctx->payload, IOTCON_ERROR_INVALID_PARAMETER);
479 parser = json_parser_new();
480 ret = json_parser_load_from_data(parser, ctx->payload, strlen(ctx->payload), &error);
482 ERR("json_parser_load_from_data() Fail(%s)", error->message);
484 return IOTCON_ERROR_INVALID_PARAMETER;
487 /* parse 'oc' prefix */
488 root_obj = json_node_get_object(json_parser_get_root(parser));
489 rsrc_array = json_object_get_array_member(root_obj, IC_JSON_KEY_OC);
490 if (NULL == rsrc_array) {
491 ERR("json_object_get_array_member() Fail");
492 g_object_unref(parser);
493 return IOTCON_ERROR_INVALID_PARAMETER;
496 rsrc_count = json_array_get_length(rsrc_array);
497 if (0 == rsrc_count) {
498 ERR("Invalid count(%d)", rsrc_count);
499 g_object_unref(parser);
500 return IOTCON_ERROR_INVALID_PARAMETER;
503 for (rsrc_index = 0; rsrc_index < rsrc_count; rsrc_index++) {
504 JsonObject *rsrc_obj;
506 rsrc_obj = json_array_get_object_element(rsrc_array, rsrc_index);
507 if (0 == json_object_get_size(rsrc_obj)) /* for the case of empty "{}" */
510 ret = _find_cb_response(rsrc_obj, ctx);
511 if (IOTCON_ERROR_NONE != ret) {
512 ERR("_find_cb_response() Fail(%d)", ret);
513 g_object_unref(parser);
518 g_object_unref(parser);
520 return IOTCON_ERROR_NONE;
524 static int _worker_find_cb(void *context)
527 struct icd_find_context *ctx = context;
529 RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
531 ret = _find_cb_handle_context(ctx);
532 if (IOTCON_ERROR_NONE != ret)
533 ERR("_find_cb_handle_context() Fail(%d)", ret);
535 /* ctx was allocated from icd_ioty_ocprocess_find_cb() */
545 OCStackApplicationResult icd_ioty_ocprocess_find_cb(void *ctx, OCDoHandle handle,
546 OCClientResponse *resp)
550 struct icd_find_context *find_ctx;
551 icd_sig_ctx_s *sig_context = ctx;
553 RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
554 RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
555 RETV_IF(NULL == resp->resJSONPayload, OC_STACK_KEEP_TRANSACTION);
557 find_ctx = calloc(1, sizeof(struct icd_find_context));
558 if (NULL == find_ctx) {
559 ERR("calloc() Fail(%d)", errno);
560 return OC_STACK_KEEP_TRANSACTION;
563 dev_addr = calloc(1, sizeof(OCDevAddr));
564 if (NULL == dev_addr) {
565 ERR("calloc() Fail(%d)", errno);
567 return OC_STACK_KEEP_TRANSACTION;
569 memcpy(dev_addr, resp->addr, sizeof(OCDevAddr));
571 find_ctx->signum = sig_context->signum;
572 find_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
573 find_ctx->payload = ic_utils_strdup(resp->resJSONPayload);
574 find_ctx->dev_addr = dev_addr;
575 find_ctx->conn_type = resp->connType;
577 ret = _ocprocess_worker_start(_worker_find_cb, find_ctx);
578 if (IOTCON_ERROR_NONE != ret) {
579 ERR("_ocprocess_worker_start() Fail(%d)", ret);
580 free(find_ctx->bus_name);
581 free(find_ctx->payload);
582 free(find_ctx->dev_addr);
584 return OC_STACK_KEEP_TRANSACTION;
587 /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
588 /* DO NOT FREE find_ctx. It MUST be freed in the _worker_find_cb func */
590 return OC_STACK_KEEP_TRANSACTION;
594 static int _worker_crud_cb(void *context)
597 struct icd_crud_context *ctx = context;
599 RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
601 if (ICD_CRUD_DELETE == ctx->crud_type)
602 value = g_variant_new("(a(qs)i)", ctx->options, ctx->res);
604 value = g_variant_new("(a(qs)si)", ctx->options, ctx->payload, ctx->res);
605 icd_ioty_complete(ctx->crud_type, ctx->invocation, value);
607 /* ctx was allocated from icd_ioty_ocprocess_xxx_cb() */
609 g_variant_builder_unref(ctx->options);
612 return IOTCON_ERROR_NONE;
616 static int _ocprocess_worker(_ocprocess_fn fn, int type, const char *payload, int res,
617 GVariantBuilder *options, void *ctx)
620 struct icd_crud_context *crud_ctx;
622 crud_ctx = calloc(1, sizeof(struct icd_crud_context));
623 if (NULL == crud_ctx) {
624 ERR("calloc() Fail(%d)", errno);
625 return IOTCON_ERROR_OUT_OF_MEMORY;
628 crud_ctx->crud_type = type;
629 crud_ctx->payload = strdup(ic_utils_dbus_encode_str(payload));
631 crud_ctx->options = options;
632 crud_ctx->invocation = ctx;
634 ret = _ocprocess_worker_start(fn, crud_ctx);
635 if (IOTCON_ERROR_NONE != ret) {
636 ERR("_ocprocess_worker_start() Fail(%d)", ret);
637 free(crud_ctx->payload);
638 g_variant_builder_unref(crud_ctx->options);
642 /* DO NOT FREE crud_ctx. It MUST be freed in the _worker_crud_cb func */
648 OCStackApplicationResult icd_ioty_ocprocess_get_cb(void *ctx, OCDoHandle handle,
649 OCClientResponse *resp)
653 OCStackResult result;
654 GVariantBuilder *options;
655 struct icd_crud_context *crud_ctx;
657 RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
659 if (NULL == resp->resJSONPayload || '\0' == resp->resJSONPayload[0]) {
660 ERR("json payload is empty");
661 icd_ioty_complete_error(ICD_CRUD_GET, ctx, IOTCON_ERROR_IOTIVITY);
662 return OC_STACK_DELETE_TRANSACTION;
665 crud_ctx = calloc(1, sizeof(struct icd_crud_context));
666 if (NULL == crud_ctx) {
667 ERR("calloc() Fail(%d)", errno);
668 icd_ioty_complete_error(ICD_CRUD_GET, ctx, IOTCON_ERROR_OUT_OF_MEMORY);
669 return OC_STACK_DELETE_TRANSACTION;
672 result = resp->result;
673 if (OC_STACK_OK == result) {
674 res = IOTCON_RESPONSE_RESULT_OK;
675 options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
676 resp->numRcvdVendorSpecificHeaderOptions);
678 WARN("resp error(%d)", result);
679 res = IOTCON_RESPONSE_RESULT_ERROR;
683 ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_GET, resp->resJSONPayload, res,
685 if (IOTCON_ERROR_NONE != ret) {
686 ERR("_ocprocess_worker() Fail(%d)", ret);
687 icd_ioty_complete_error(ICD_CRUD_GET, ctx, ret);
688 return OC_STACK_DELETE_TRANSACTION;
691 return OC_STACK_DELETE_TRANSACTION;
695 OCStackApplicationResult icd_ioty_ocprocess_put_cb(void *ctx, OCDoHandle handle,
696 OCClientResponse *resp)
700 OCStackResult result;
701 GVariantBuilder *options;
703 RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
705 if (NULL == resp->resJSONPayload || '\0' == resp->resJSONPayload[0]) {
706 ERR("json payload is empty");
707 icd_ioty_complete_error(ICD_CRUD_PUT, ctx, IOTCON_ERROR_IOTIVITY);
708 return OC_STACK_DELETE_TRANSACTION;
711 result = resp->result;
714 res = IOTCON_RESPONSE_RESULT_OK;
716 case OC_STACK_RESOURCE_CREATED:
717 res = IOTCON_RESPONSE_RESULT_RESOURCE_CREATED;
720 WARN("resp error(%d)", result);
721 res = IOTCON_RESPONSE_RESULT_ERROR;
725 if (IOTCON_RESPONSE_RESULT_ERROR != res) {
726 options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
727 resp->numRcvdVendorSpecificHeaderOptions);
730 ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_PUT, resp->resJSONPayload, res,
732 if (IOTCON_ERROR_NONE != ret) {
733 ERR("_ocprocess_worker() Fail(%d)", ret);
734 icd_ioty_complete_error(ICD_CRUD_PUT, ctx, ret);
735 return OC_STACK_DELETE_TRANSACTION;
738 return OC_STACK_DELETE_TRANSACTION;
742 OCStackApplicationResult icd_ioty_ocprocess_post_cb(void *ctx, OCDoHandle handle,
743 OCClientResponse *resp)
747 OCStackResult result;
748 GVariantBuilder *options;
749 struct icd_crud_context *crud_ctx;
751 RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
753 if (NULL == resp->resJSONPayload || '\0' == resp->resJSONPayload[0]) {
754 ERR("json payload is empty");
755 icd_ioty_complete_error(ICD_CRUD_POST, ctx, IOTCON_ERROR_IOTIVITY);
756 return OC_STACK_DELETE_TRANSACTION;
759 crud_ctx = calloc(1, sizeof(struct icd_crud_context));
760 if (NULL == crud_ctx) {
761 ERR("calloc() Fail(%d)", errno);
762 icd_ioty_complete_error(ICD_CRUD_POST, ctx, IOTCON_ERROR_OUT_OF_MEMORY);
763 return OC_STACK_DELETE_TRANSACTION;
766 result = resp->result;
769 res = IOTCON_RESPONSE_RESULT_OK;
771 case OC_STACK_RESOURCE_CREATED:
772 res = IOTCON_RESPONSE_RESULT_RESOURCE_CREATED;
775 WARN("resp error(%d)", result);
776 res = IOTCON_RESPONSE_RESULT_ERROR;
780 if (IOTCON_RESPONSE_RESULT_ERROR != res) {
781 options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
782 resp->numRcvdVendorSpecificHeaderOptions);
785 ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_POST, resp->resJSONPayload, res,
787 if (IOTCON_ERROR_NONE != ret) {
788 ERR("_ocprocess_worker() Fail(%d)", ret);
789 icd_ioty_complete_error(ICD_CRUD_POST, ctx, ret);
790 return OC_STACK_DELETE_TRANSACTION;
793 return OC_STACK_DELETE_TRANSACTION;
797 OCStackApplicationResult icd_ioty_ocprocess_delete_cb(void *ctx, OCDoHandle handle,
798 OCClientResponse *resp)
802 OCStackResult result;
803 GVariantBuilder *options;
804 struct icd_crud_context *crud_ctx;
806 RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
808 if (NULL == resp->resJSONPayload || '\0' == resp->resJSONPayload[0]) {
809 ERR("json payload is empty");
810 icd_ioty_complete_error(ICD_CRUD_DELETE, ctx, IOTCON_ERROR_IOTIVITY);
811 return OC_STACK_DELETE_TRANSACTION;
814 crud_ctx = calloc(1, sizeof(struct icd_crud_context));
815 if (NULL == crud_ctx) {
816 ERR("calloc() Fail(%d)", errno);
817 icd_ioty_complete_error(ICD_CRUD_DELETE, ctx, IOTCON_ERROR_OUT_OF_MEMORY);
818 return OC_STACK_DELETE_TRANSACTION;
821 result = resp->result;
824 res = IOTCON_RESPONSE_RESULT_OK;
826 case OC_STACK_RESOURCE_DELETED:
827 res = IOTCON_RESPONSE_RESULT_RESOURCE_DELETED;
830 WARN("resp error(%d)", result);
831 res = IOTCON_RESPONSE_RESULT_ERROR;
835 if (IOTCON_RESPONSE_RESULT_ERROR != res) {
836 options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
837 resp->numRcvdVendorSpecificHeaderOptions);
840 ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_DELETE, NULL, res, options, ctx);
841 if (IOTCON_ERROR_NONE != ret) {
842 ERR("_ocprocess_worker() Fail(%d)", ret);
843 icd_ioty_complete_error(ICD_CRUD_DELETE, ctx, ret);
844 return OC_STACK_DELETE_TRANSACTION;
847 /* DO NOT FREE crud_ctx. It MUST be freed in the _worker_delete_cb func */
849 return OC_STACK_DELETE_TRANSACTION;
853 static int _worker_observe_cb(void *context)
857 struct icd_observe_context *ctx = context;
859 RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
861 value = g_variant_new("(a(qs)sii)", ctx->options, ctx->payload, ctx->res,
864 ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_OBSERVE, ctx->signum,
866 if (IOTCON_ERROR_NONE != ret)
867 ERR("_ocprocess_response_signal() Fail(%d)", ret);
869 /* ctx was allocated from icd_ioty_ocprocess_observe_cb() */
872 g_variant_builder_unref(ctx->options);
879 static void _observe_cb_response_error(const char *dest, unsigned int signum, int ret_val)
884 value = g_variant_new("(a(qs)sii)", NULL, IC_STR_NULL, ret_val, 0);
886 ret = _ocprocess_response_signal(dest, IC_DBUS_SIGNAL_OBSERVE, signum, value);
887 if (IOTCON_ERROR_NONE != ret)
888 ERR("_ocprocess_response_signal() Fail(%d)", ret);
892 OCStackApplicationResult icd_ioty_ocprocess_observe_cb(void *ctx, OCDoHandle handle,
893 OCClientResponse *resp)
896 OCStackResult result;
897 GVariantBuilder *options;
898 struct icd_observe_context *observe_ctx;
899 icd_sig_ctx_s *sig_context = ctx;
901 RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
903 if (NULL == resp->resJSONPayload || '\0' == resp->resJSONPayload[0]) {
904 ERR("json payload is empty");
905 _observe_cb_response_error(sig_context->bus_name, sig_context->signum,
906 IOTCON_ERROR_IOTIVITY);
907 return OC_STACK_KEEP_TRANSACTION;
910 observe_ctx = calloc(1, sizeof(struct icd_observe_context));
911 if (NULL == observe_ctx) {
912 ERR("calloc() Fail(%d)", errno);
913 _observe_cb_response_error(sig_context->bus_name, sig_context->signum,
914 IOTCON_ERROR_OUT_OF_MEMORY);
915 return OC_STACK_KEEP_TRANSACTION;
918 result = resp->result;
919 if (OC_STACK_OK == result) {
920 res = IOTCON_RESPONSE_RESULT_OK;
921 options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
922 resp->numRcvdVendorSpecificHeaderOptions);
924 WARN("resp error(%d)", result);
925 res = IOTCON_RESPONSE_RESULT_ERROR;
929 observe_ctx->payload = strdup(resp->resJSONPayload);
930 observe_ctx->signum = sig_context->signum;
931 observe_ctx->res = res;
932 observe_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
933 observe_ctx->options = options;
935 ret = _ocprocess_worker_start(_worker_observe_cb, observe_ctx);
936 if (IOTCON_ERROR_NONE != ret) {
937 ERR("_ocprocess_worker_start() Fail(%d)", ret);
938 _observe_cb_response_error(sig_context->bus_name, sig_context->signum, ret);
939 free(observe_ctx->bus_name);
940 free(observe_ctx->payload);
941 g_variant_builder_unref(observe_ctx->options);
943 return OC_STACK_KEEP_TRANSACTION;
946 /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
947 /* DO NOT FREE observe_ctx. It MUST be freed in the _worker_observe_cb func */
949 return OC_STACK_KEEP_TRANSACTION;
954 static int _worker_presence_cb(void *context)
961 char addr[PATH_MAX] = {0};
962 struct icd_presence_context *ctx = context;
964 RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
966 ret = OCDevAddrToIPv4Addr(ctx->dev_addr, &a, &b, &c, &d);
967 if (OC_STACK_OK != ret) {
968 ERR("OCDevAddrToIPv4Addr() Fail(%d)", ret);
975 ret = OCDevAddrToPort(ctx->dev_addr, &port);
976 if (OC_STACK_OK != ret) {
977 ERR("OCDevAddrToPort() Fail(%d)", ret);
985 snprintf(addr, sizeof(addr), ICD_IOTY_COAP"%d.%d.%d.%d:%d", a, b, c, d, port);
987 value = g_variant_new("(ius)", ctx->result, ctx->nonce, addr);
989 ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_PRESENCE, ctx->signum,
991 if (IOTCON_ERROR_NONE != ret)
992 ERR("_ocprocess_response_signal() Fail(%d)", ret);
994 /* ctx was allocated from icd_ioty_ocprocess_presence_cb() */
1003 static void _presence_cb_response_error(const char *dest, unsigned int signum,
1010 value = g_variant_new("(ius)", ret_val, 0, IC_STR_NULL);
1012 ret = _ocprocess_response_signal(dest, IC_DBUS_SIGNAL_PRESENCE, signum, value);
1013 if (IOTCON_ERROR_NONE != ret)
1014 ERR("_ocprocess_response_signal() Fail(%d)", ret);
1018 OCStackApplicationResult icd_ioty_ocprocess_presence_cb(void *ctx, OCDoHandle handle,
1019 OCClientResponse *resp)
1023 OCDevAddr *dev_addr;
1024 icd_sig_ctx_s *sig_context = ctx;
1025 struct icd_presence_context *presence_ctx;
1027 RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
1029 presence_ctx = calloc(1, sizeof(struct icd_presence_context));
1030 if (NULL == presence_ctx) {
1031 ERR("calloc() Fail(%d)", errno);
1032 _presence_cb_response_error(sig_context->bus_name, sig_context->signum,
1033 IOTCON_ERROR_OUT_OF_MEMORY);
1034 return OC_STACK_KEEP_TRANSACTION;
1037 dev_addr = calloc(1, sizeof(OCDevAddr));
1038 if (NULL == dev_addr) {
1039 ERR("calloc() Fail(%d)", errno);
1040 _presence_cb_response_error(sig_context->bus_name, sig_context->signum,
1041 IOTCON_ERROR_OUT_OF_MEMORY);
1043 return OC_STACK_KEEP_TRANSACTION;
1045 memcpy(dev_addr, resp->addr, sizeof(OCDevAddr));
1047 switch (resp->result) {
1049 presence_ctx->result = IOTCON_PRESENCE_OK;
1051 case OC_STACK_PRESENCE_STOPPED:
1052 presence_ctx->result = IOTCON_PRESENCE_STOPPED;
1054 case OC_STACK_PRESENCE_TIMEOUT:
1055 presence_ctx->result = IOTCON_PRESENCE_TIMEOUT;
1057 case OC_STACK_ERROR:
1059 DBG("Presence error(%d)", resp->result);
1060 presence_ctx->result = IOTCON_ERROR_IOTIVITY;
1063 presence_ctx->signum = sig_context->signum;
1064 presence_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
1065 presence_ctx->nonce = resp->sequenceNumber;
1066 presence_ctx->dev_addr = dev_addr;
1068 ret = _ocprocess_worker_start(_worker_presence_cb, presence_ctx);
1069 if (IOTCON_ERROR_NONE != ret) {
1070 ERR("_ocprocess_worker_start() Fail(%d)", ret);
1071 _presence_cb_response_error(sig_context->bus_name, sig_context->signum, ret);
1072 free(presence_ctx->bus_name);
1073 free(presence_ctx->dev_addr);
1075 return OC_STACK_KEEP_TRANSACTION;
1078 /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
1079 /* DO NOT FREE presence_ctx. It MUST be freed in the _worker_presence_cb func */
1081 return OC_STACK_KEEP_TRANSACTION;