Support 64-bit architectures
[platform/core/iot/iotcon.git] / daemon / icd-ioty-ocprocess.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 <stdlib.h>
18 #include <unistd.h> /* for usleep() */
19 #include <glib.h>
20
21 #include <ocstack.h>
22 #include <octypes.h>
23 #include <ocpayload.h>
24
25 #include "iotcon.h"
26 #include "ic-utils.h"
27 #include "icd.h"
28 #include "icd-payload.h"
29 #include "icd-dbus.h"
30 #include "icd-ioty.h"
31 #include "icd-ioty-type.h"
32 #include "icd-ioty-ocprocess.h"
33
34 static int icd_ioty_alive;
35
36 typedef int (*_ocprocess_fn)(void *user_data);
37
38 struct icd_ioty_worker
39 {
40         void *ctx;
41         _ocprocess_fn fn;
42 };
43
44
45 struct icd_req_context {
46         unsigned int signum;
47         char *bus_name;
48         int types;
49         int observer_id;
50         int observe_action;
51         OCRequestHandle request_h;
52         OCResourceHandle resource_h;
53         GVariant *payload;
54         GVariantBuilder *options;
55         GVariantBuilder *query;
56 };
57
58
59 struct icd_find_context {
60         unsigned int signum;
61         char *bus_name;
62         int conn_type;
63         GVariant **payload;
64 };
65
66
67 struct icd_crud_context {
68         int res;
69         int crud_type;
70         GVariant *payload;
71         GVariantBuilder *options;
72         GDBusMethodInvocation *invocation;
73 };
74
75
76 struct icd_info_context {
77         unsigned int signum;
78         int info_type;
79         char *bus_name;
80         GVariant *payload;
81 };
82
83
84 struct icd_observe_context {
85         unsigned int signum;
86         int res;
87         int seqnum;
88         char *bus_name;
89         GVariant *payload;
90         GVariantBuilder *options;
91 };
92
93
94 struct icd_presence_context {
95         unsigned int signum;
96         char *bus_name;
97         int result;
98         unsigned int nonce;
99         OCDevAddr *dev_addr;
100 };
101
102
103 void icd_ioty_ocprocess_stop()
104 {
105         icd_ioty_alive = 0;
106 }
107
108
109 static void* _ocprocess_worker_thread(void *data)
110 {
111         int ret;
112         struct icd_ioty_worker *worker = data;
113
114         if (NULL == data) {
115                 ERR("worker is NULL");
116                 return NULL;
117         }
118
119         ret = worker->fn(worker->ctx);
120         if (IOTCON_ERROR_NONE != ret)
121                 ERR("fn() Fail(%d)", ret);
122
123         /* worker was allocated from _ocprocess_worker_start() */
124         free(worker);
125
126         /* GCC warning happen if use g_thread_exit() */
127         return NULL;
128 }
129
130
131 static int _ocprocess_worker_start(_ocprocess_fn fn, void *ctx)
132 {
133         GError *error;
134         GThread *thread;
135         struct icd_ioty_worker *worker;
136
137         RETV_IF(NULL == fn, IOTCON_ERROR_INVALID_PARAMETER);
138
139         worker = calloc(1, sizeof(struct icd_ioty_worker));
140         if (NULL == worker) {
141                 ERR("calloc() Fail(%d)", errno);
142                 return IOTCON_ERROR_OUT_OF_MEMORY;
143         }
144
145         worker->fn = fn;
146         worker->ctx = ctx;
147
148         /* TODO : consider thread pool mechanism */
149         thread = g_thread_try_new("worker_thread", _ocprocess_worker_thread, worker, &error);
150         if (NULL == thread) {
151                 ERR("g_thread_try_new() Fail(%s)", error->message);
152                 g_error_free(error);
153                 free(worker);
154                 return IOTCON_ERROR_SYSTEM;
155         }
156
157         /* DO NOT join thread. It was already detached by calling g_thread_unref() */
158         g_thread_unref(thread);
159
160         /* DO NOT FREE worker. It MUST be freed in the _ocprocess_worker_thread() */
161
162         return IOTCON_ERROR_NONE;
163 }
164
165
166 static int _ocprocess_response_signal(const char *dest, const char *signal,
167                 unsigned int signum, GVariant *value)
168 {
169         int ret;
170         char sig_name[IC_DBUS_SIGNAL_LENGTH] = {0};
171
172         ret = snprintf(sig_name, sizeof(sig_name), "%s_%u", signal, signum);
173         if (ret <= 0 || sizeof(sig_name) <= ret) {
174                 ERR("snprintf() Fail(%d)", ret);
175                 return IOTCON_ERROR_UNKNOWN;
176         }
177
178         ret = icd_dbus_emit_signal(dest, sig_name, value);
179         if (IOTCON_ERROR_NONE != ret) {
180                 ERR("icd_dbus_emit_signal() Fail(%d)", ret);
181                 return ret;
182         }
183
184         return IOTCON_ERROR_NONE;
185 }
186
187
188 static inline GVariantBuilder* _ocprocess_parse_header_options(
189                 OCHeaderOption *oic_option, int option_size)
190 {
191         int i;
192         GVariantBuilder *options;
193
194         options = g_variant_builder_new(G_VARIANT_TYPE("a(qs)"));
195         for (i = 0; i < option_size; i++) {
196                 g_variant_builder_add(options, "(qs)", oic_option[i].optionID,
197                                 oic_option[i].optionData);
198         }
199
200         return options;
201 }
202
203
204 static int _worker_req_handler(void *context)
205 {
206         int ret;
207         GVariant *value;
208         struct icd_req_context *ctx = context;
209         GVariantBuilder payload_builder;
210
211         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
212
213         g_variant_builder_init(&payload_builder, G_VARIANT_TYPE("av"));
214         if (ctx->payload)
215                 g_variant_builder_add(&payload_builder, "v", ctx->payload);
216
217         value = g_variant_new("(ia(qs)a(ss)iiavxx)",
218                         ctx->types,
219                         ctx->options,
220                         ctx->query,
221                         ctx->observe_action,
222                         ctx->observer_id,
223                         &payload_builder,
224                         ICD_POINTER_TO_INT64(ctx->request_h),
225                         ICD_POINTER_TO_INT64(ctx->resource_h));
226
227         ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_REQUEST_HANDLER,
228                         ctx->signum, value);
229         if (IOTCON_ERROR_NONE != ret)
230                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
231
232         free(ctx->bus_name);
233         g_variant_builder_unref(ctx->options);
234         g_variant_builder_unref(ctx->query);
235         free(ctx);
236
237         return ret;
238 }
239
240
241 OCEntityHandlerResult icd_ioty_ocprocess_req_handler(OCEntityHandlerFlag flag,
242                 OCEntityHandlerRequest *request, void *user_data)
243 {
244         FN_CALL;
245         int ret;
246         unsigned int signal_number;
247         char *query_str, *query_key, *query_value;
248         char *token, *save_ptr1, *save_ptr2;
249         char *bus_name = NULL;
250         struct icd_req_context *req_ctx;
251
252         RETV_IF(NULL == request, OC_EH_ERROR);
253
254         req_ctx = calloc(1, sizeof(struct icd_req_context));
255         if (NULL == req_ctx) {
256                 ERR("calloc() Fail(%d)", errno);
257                 return OC_EH_ERROR;
258         }
259
260         /* handle */
261         req_ctx->request_h = request->requestHandle;
262         req_ctx->resource_h = request->resource;
263
264         ret = icd_dbus_client_list_get_info(req_ctx->resource_h, &signal_number, &bus_name);
265         if (IOTCON_ERROR_NONE != ret) {
266                 ERR("icd_dbus_client_list_get_info() Fail(%d)", ret);
267                 free(req_ctx);
268                 return OC_EH_ERROR;
269         }
270
271         /* signal number & bus_name */
272         req_ctx->signum = signal_number;
273         req_ctx->bus_name = bus_name;
274
275         /* request type */
276         if (OC_REQUEST_FLAG & flag) {
277                 switch (request->method) {
278                 case OC_REST_GET:
279                         req_ctx->types = IOTCON_REQUEST_GET;
280                         req_ctx->payload = NULL;
281
282                         if (OC_OBSERVE_FLAG & flag) {
283                                 req_ctx->types |= IOTCON_REQUEST_OBSERVE;
284                                 /* observation info*/
285                                 req_ctx->observer_id = request->obsInfo.obsId;
286                                 req_ctx->observe_action = request->obsInfo.action;
287                         }
288                         break;
289                 case OC_REST_PUT:
290                         req_ctx->types = IOTCON_REQUEST_PUT;
291                         req_ctx->payload = icd_payload_to_gvariant(request->payload);
292                         break;
293                 case OC_REST_POST:
294                         req_ctx->types = IOTCON_REQUEST_POST;
295                         req_ctx->payload = icd_payload_to_gvariant(request->payload);
296                         break;
297                 case OC_REST_DELETE:
298                         req_ctx->types = IOTCON_REQUEST_DELETE;
299                         req_ctx->payload = NULL;
300                         break;
301                 default:
302                         free(req_ctx->bus_name);
303                         free(req_ctx);
304                         return OC_EH_ERROR;
305                 }
306         }
307
308         /* header options */
309         req_ctx->options = _ocprocess_parse_header_options(
310                         request->rcvdVendorSpecificHeaderOptions,
311                         request->numRcvdVendorSpecificHeaderOptions);
312
313         /* query */
314         req_ctx->query = g_variant_builder_new(G_VARIANT_TYPE("a(ss)"));
315         query_str = request->query;
316         while ((token = strtok_r(query_str, "&;", &save_ptr1))) {
317                 while ((query_key = strtok_r(token, "=", &save_ptr2))) {
318                         token = NULL;
319                         query_value = strtok_r(token, "=", &save_ptr2);
320                         if (NULL == query_value)
321                                 break;
322
323                         g_variant_builder_add(req_ctx->query, "(ss)", query_key, query_value);
324                 }
325                 query_str = NULL;
326         }
327
328         ret = _ocprocess_worker_start(_worker_req_handler, req_ctx);
329         if (IOTCON_ERROR_NONE != ret) {
330                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
331                 free(req_ctx->bus_name);
332                 if (req_ctx->payload)
333                         g_variant_unref(req_ctx->payload);
334                 g_variant_builder_unref(req_ctx->options);
335                 g_variant_builder_unref(req_ctx->query);
336                 free(req_ctx);
337                 return OC_EH_ERROR;
338         }
339
340         /* DO NOT FREE req_ctx. It MUST be freed in the _worker_req_handler func */
341
342         return OC_EH_OK;
343 }
344
345
346 gpointer icd_ioty_ocprocess_thread(gpointer data)
347 {
348         FN_CALL;
349         OCStackResult result;
350
351         icd_ioty_alive = 1;
352         while (icd_ioty_alive) {
353                 icd_ioty_csdk_lock();
354                 result = OCProcess();
355                 icd_ioty_csdk_unlock();
356                 if (OC_STACK_OK != result) {
357                         ERR("OCProcess() Fail(%d)", result);
358                         break;
359                 }
360
361                 /* TODO : SHOULD revise time or usleep */
362                 usleep(10);
363         }
364
365         return NULL;
366 }
367
368
369 static int _worker_find_cb(void *context)
370 {
371         GVariant *value;
372         int i, ret;
373         struct icd_find_context *ctx = context;
374
375         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
376
377         for (i = 0; ctx->payload[i]; i++) {
378                 value = g_variant_new("(vi)", ctx->payload[i], ctx->conn_type);
379                 /* TODO : If one device has multi resources, it comes as bulk data.
380                  * To reduce the number of emit_signal, let's send signal only one time for one device.
381                  * for ex, client list. */
382                 ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_FOUND_RESOURCE,
383                                 ctx->signum, value);
384                 if (IOTCON_ERROR_NONE != ret) {
385                         ERR("_ocprocess_response_signal() Fail(%d)", ret);
386                         g_variant_unref(value);
387                         return ret;
388                 }
389         }
390
391         /* ctx was allocated from icd_ioty_ocprocess_find_cb() */
392         free(ctx->bus_name);
393         free(ctx);
394
395         return ret;
396 }
397
398
399 OCStackApplicationResult icd_ioty_ocprocess_find_cb(void *ctx, OCDoHandle handle,
400                 OCClientResponse *resp)
401 {
402         int ret;
403         struct icd_find_context *find_ctx;
404         icd_sig_ctx_s *sig_context = ctx;
405
406         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
407         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
408         if (NULL == resp->payload)
409                 /* normal case : payload COULD be NULL */
410                 return OC_STACK_KEEP_TRANSACTION;
411         RETV_IF(PAYLOAD_TYPE_DISCOVERY != resp->payload->type,
412                         OC_STACK_KEEP_TRANSACTION);
413
414         find_ctx = calloc(1, sizeof(struct icd_find_context));
415         if (NULL == find_ctx) {
416                 ERR("calloc() Fail(%d)", errno);
417                 return OC_STACK_KEEP_TRANSACTION;
418         }
419
420         find_ctx->signum = sig_context->signum;
421         find_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
422         find_ctx->payload = icd_payload_res_to_gvariant(resp->payload, &resp->devAddr);
423         find_ctx->conn_type = icd_ioty_transport_flag_to_conn_type(resp->devAddr.adapter,
424                         resp->devAddr.flags);
425
426         ret = _ocprocess_worker_start(_worker_find_cb, find_ctx);
427         if (IOTCON_ERROR_NONE != ret) {
428                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
429                 free(find_ctx->bus_name);
430                 ic_utils_gvariant_array_free(find_ctx->payload);
431                 free(find_ctx);
432                 return OC_STACK_KEEP_TRANSACTION;
433         }
434
435         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
436         /* DO NOT FREE find_ctx. It MUST be freed in the _worker_find_cb func */
437
438         return OC_STACK_KEEP_TRANSACTION;
439 }
440
441
442 static int _worker_crud_cb(void *context)
443 {
444         GVariant *value;
445         struct icd_crud_context *ctx = context;
446
447         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
448
449         if (ICD_CRUD_DELETE == ctx->crud_type)
450                 value = g_variant_new("(a(qs)i)", ctx->options, ctx->res);
451         else
452                 value = g_variant_new("(a(qs)vi)", ctx->options, ctx->payload, ctx->res);
453         icd_ioty_complete(ctx->crud_type, ctx->invocation, value);
454
455         /* ctx was allocated from icd_ioty_ocprocess_xxx_cb() */
456         g_variant_builder_unref(ctx->options);
457         free(ctx);
458
459         return IOTCON_ERROR_NONE;
460 }
461
462
463 static int _worker_info_cb(void *context)
464 {
465         int ret;
466         const char *sig_name = NULL;
467         struct icd_info_context *ctx = context;
468
469         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
470
471         if (ICD_DEVICE_INFO == ctx->info_type)
472                 sig_name = IC_DBUS_SIGNAL_DEVICE;
473         else if (ICD_PLATFORM_INFO == ctx->info_type)
474                 sig_name = IC_DBUS_SIGNAL_PLATFORM;
475
476         ret = _ocprocess_response_signal(ctx->bus_name, sig_name, ctx->signum, ctx->payload);
477         if (IOTCON_ERROR_NONE != ret)
478                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
479
480         /* ctx was allocated from icd_ioty_ocprocess_info_cb() */
481         free(ctx->bus_name);
482         free(ctx);
483
484         return ret;
485 }
486
487
488 static int _ocprocess_worker(_ocprocess_fn fn, int type, OCPayload *payload, int res,
489                 GVariantBuilder *options, void *ctx)
490 {
491         int ret;
492         struct icd_crud_context *crud_ctx;
493
494         crud_ctx = calloc(1, sizeof(struct icd_crud_context));
495         if (NULL == crud_ctx) {
496                 ERR("calloc() Fail(%d)", errno);
497                 return IOTCON_ERROR_OUT_OF_MEMORY;
498         }
499
500         crud_ctx->crud_type = type;
501         crud_ctx->payload = icd_payload_to_gvariant(payload);
502         crud_ctx->res = res;
503         crud_ctx->options = options;
504         crud_ctx->invocation = ctx;
505
506         ret = _ocprocess_worker_start(fn, crud_ctx);
507         if (IOTCON_ERROR_NONE != ret) {
508                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
509                 if (crud_ctx->payload)
510                         g_variant_unref(crud_ctx->payload);
511                 g_variant_builder_unref(crud_ctx->options);
512                 free(crud_ctx);
513         }
514
515         /* DO NOT FREE crud_ctx. It MUST be freed in the _worker_crud_cb func */
516
517         return ret;
518 }
519
520
521 OCStackApplicationResult icd_ioty_ocprocess_get_cb(void *ctx, OCDoHandle handle,
522                 OCClientResponse *resp)
523 {
524         FN_CALL;
525         int ret, res;
526         OCStackResult result;
527         GVariantBuilder *options;
528
529         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
530
531         if (NULL == resp->payload) {
532                 ERR("payload is empty");
533                 icd_ioty_complete_error(ICD_CRUD_GET, ctx, IOTCON_ERROR_IOTIVITY);
534                 return OC_STACK_DELETE_TRANSACTION;
535         }
536
537         result = resp->result;
538         if (OC_STACK_OK == result) {
539                 res = IOTCON_RESPONSE_RESULT_OK;
540                 options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
541                                 resp->numRcvdVendorSpecificHeaderOptions);
542         } else {
543                 WARN("resp error(%d)", result);
544                 res = IOTCON_RESPONSE_RESULT_ERROR;
545                 options = NULL;
546         }
547
548         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_GET, resp->payload, res,
549                         options, ctx);
550         if (IOTCON_ERROR_NONE != ret) {
551                 ERR("_ocprocess_worker() Fail(%d)", ret);
552                 icd_ioty_complete_error(ICD_CRUD_GET, ctx, ret);
553                 return OC_STACK_DELETE_TRANSACTION;
554         }
555
556         return OC_STACK_DELETE_TRANSACTION;
557 }
558
559
560 OCStackApplicationResult icd_ioty_ocprocess_put_cb(void *ctx, OCDoHandle handle,
561                 OCClientResponse *resp)
562 {
563         FN_CALL;
564         int ret, res;
565         OCStackResult result;
566         GVariantBuilder *options;
567
568         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
569
570         if (NULL == resp->payload) {
571                 ERR("payload is empty");
572                 icd_ioty_complete_error(ICD_CRUD_PUT, ctx, IOTCON_ERROR_IOTIVITY);
573                 return OC_STACK_DELETE_TRANSACTION;
574         }
575
576         result = resp->result;
577         switch (result) {
578         case OC_STACK_OK:
579                 res = IOTCON_RESPONSE_RESULT_OK;
580                 break;
581         case OC_STACK_RESOURCE_CREATED:
582                 res = IOTCON_RESPONSE_RESULT_RESOURCE_CREATED;
583                 break;
584         default:
585                 WARN("resp error(%d)", result);
586                 res = IOTCON_RESPONSE_RESULT_ERROR;
587                 options = NULL;
588         }
589
590         if (IOTCON_RESPONSE_RESULT_ERROR != res) {
591                 options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
592                                 resp->numRcvdVendorSpecificHeaderOptions);
593         }
594
595         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_PUT, resp->payload, res,
596                         options, ctx);
597         if (IOTCON_ERROR_NONE != ret) {
598                 ERR("_ocprocess_worker() Fail(%d)", ret);
599                 icd_ioty_complete_error(ICD_CRUD_PUT, ctx, ret);
600                 return OC_STACK_DELETE_TRANSACTION;
601         }
602
603         return OC_STACK_DELETE_TRANSACTION;
604 }
605
606
607 OCStackApplicationResult icd_ioty_ocprocess_post_cb(void *ctx, OCDoHandle handle,
608                 OCClientResponse *resp)
609 {
610         FN_CALL;
611         int ret, res;
612         OCStackResult result;
613         GVariantBuilder *options;
614
615         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
616
617         if (NULL == resp->payload) {
618                 ERR("payload is empty");
619                 icd_ioty_complete_error(ICD_CRUD_POST, ctx, IOTCON_ERROR_IOTIVITY);
620                 return OC_STACK_DELETE_TRANSACTION;
621         }
622
623         result = resp->result;
624         switch (result) {
625         case OC_STACK_OK:
626                 res = IOTCON_RESPONSE_RESULT_OK;
627                 break;
628         case OC_STACK_RESOURCE_CREATED:
629                 res = IOTCON_RESPONSE_RESULT_RESOURCE_CREATED;
630                 break;
631         default:
632                 WARN("resp error(%d)", result);
633                 res = IOTCON_RESPONSE_RESULT_ERROR;
634                 options = NULL;
635         }
636
637         if (IOTCON_RESPONSE_RESULT_ERROR != res) {
638                 options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
639                                 resp->numRcvdVendorSpecificHeaderOptions);
640         }
641
642         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_POST, resp->payload, res,
643                         options, ctx);
644         if (IOTCON_ERROR_NONE != ret) {
645                 ERR("_ocprocess_worker() Fail(%d)", ret);
646                 icd_ioty_complete_error(ICD_CRUD_POST, ctx, ret);
647                 return OC_STACK_DELETE_TRANSACTION;
648         }
649
650         return OC_STACK_DELETE_TRANSACTION;
651 }
652
653
654 OCStackApplicationResult icd_ioty_ocprocess_delete_cb(void *ctx, OCDoHandle handle,
655                 OCClientResponse *resp)
656 {
657         FN_CALL;
658         int ret, res;
659         OCStackResult result;
660         GVariantBuilder *options;
661
662         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
663
664         if (NULL == resp->payload) {
665                 ERR("payload is empty");
666                 icd_ioty_complete_error(ICD_CRUD_DELETE, ctx, IOTCON_ERROR_IOTIVITY);
667                 return OC_STACK_DELETE_TRANSACTION;
668         }
669
670         result = resp->result;
671         switch (result) {
672         case OC_STACK_OK:
673                 res = IOTCON_RESPONSE_RESULT_OK;
674                 break;
675         case OC_STACK_RESOURCE_DELETED:
676                 res = IOTCON_RESPONSE_RESULT_RESOURCE_DELETED;
677                 break;
678         default:
679                 WARN("resp error(%d)", result);
680                 res = IOTCON_RESPONSE_RESULT_ERROR;
681                 options = NULL;
682         }
683
684         if (IOTCON_RESPONSE_RESULT_ERROR != res) {
685                 options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
686                                 resp->numRcvdVendorSpecificHeaderOptions);
687         }
688
689         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_DELETE, NULL, res, options, ctx);
690         if (IOTCON_ERROR_NONE != ret) {
691                 ERR("_ocprocess_worker() Fail(%d)", ret);
692                 icd_ioty_complete_error(ICD_CRUD_DELETE, ctx, ret);
693                 return OC_STACK_DELETE_TRANSACTION;
694         }
695
696         return OC_STACK_DELETE_TRANSACTION;
697 }
698
699
700 static int _worker_observe_cb(void *context)
701 {
702         int ret;
703         GVariant *value;
704         struct icd_observe_context *ctx = context;
705
706         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
707
708         value = g_variant_new("(a(qs)vii)", ctx->options, ctx->payload, ctx->res,
709                         ctx->seqnum);
710
711         ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_OBSERVE, ctx->signum,
712                         value);
713         if (IOTCON_ERROR_NONE != ret)
714                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
715
716         /* ctx was allocated from icd_ioty_ocprocess_observe_cb() */
717         free(ctx->bus_name);
718         g_variant_builder_unref(ctx->options);
719         free(ctx);
720
721         return ret;
722 }
723
724
725 static void _observe_cb_response_error(const char *dest, unsigned int signum, int ret_val)
726 {
727         int ret;
728         GVariant *value;
729
730         value = g_variant_new("(a(qs)vii)", NULL, NULL, ret_val, 0);
731
732         ret = _ocprocess_response_signal(dest, IC_DBUS_SIGNAL_OBSERVE, signum, value);
733         if (IOTCON_ERROR_NONE != ret)
734                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
735 }
736
737
738 OCStackApplicationResult icd_ioty_ocprocess_observe_cb(void *ctx, OCDoHandle handle,
739                 OCClientResponse *resp)
740 {
741         int ret, res;
742         OCStackResult result;
743         GVariantBuilder *options;
744         struct icd_observe_context *observe_ctx;
745         icd_sig_ctx_s *sig_context = ctx;
746
747         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
748
749         if (NULL == resp->payload) {
750                 ERR("payload is empty");
751                 _observe_cb_response_error(sig_context->bus_name, sig_context->signum,
752                                 IOTCON_ERROR_IOTIVITY);
753                 return OC_STACK_KEEP_TRANSACTION;
754         }
755
756         observe_ctx = calloc(1, sizeof(struct icd_observe_context));
757         if (NULL == observe_ctx) {
758                 ERR("calloc() Fail(%d)", errno);
759                 _observe_cb_response_error(sig_context->bus_name, sig_context->signum,
760                                 IOTCON_ERROR_OUT_OF_MEMORY);
761                 return OC_STACK_KEEP_TRANSACTION;
762         }
763
764         result = resp->result;
765         if (OC_STACK_OK == result) {
766                 res = IOTCON_RESPONSE_RESULT_OK;
767                 options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
768                                 resp->numRcvdVendorSpecificHeaderOptions);
769         } else {
770                 WARN("resp error(%d)", result);
771                 res = IOTCON_RESPONSE_RESULT_ERROR;
772                 options = NULL;
773         }
774
775         observe_ctx->payload = icd_payload_to_gvariant(resp->payload);
776         observe_ctx->signum = sig_context->signum;
777         observe_ctx->res = res;
778         observe_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
779         observe_ctx->options = options;
780
781         ret = _ocprocess_worker_start(_worker_observe_cb, observe_ctx);
782         if (IOTCON_ERROR_NONE != ret) {
783                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
784                 _observe_cb_response_error(sig_context->bus_name, sig_context->signum, ret);
785                 free(observe_ctx->bus_name);
786                 if (observe_ctx->payload)
787                         g_variant_unref(observe_ctx->payload);
788                 g_variant_builder_unref(observe_ctx->options);
789                 free(observe_ctx);
790                 return OC_STACK_KEEP_TRANSACTION;
791         }
792
793         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
794         /* DO NOT FREE observe_ctx. It MUST be freed in the _worker_observe_cb func */
795
796         return OC_STACK_KEEP_TRANSACTION;
797 }
798
799
800 static int _worker_presence_cb(void *context)
801 {
802         FN_CALL;
803         int ret;
804         GVariant *value;
805         char addr[PATH_MAX] = {0};
806         struct icd_presence_context *ctx = context;
807
808         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
809
810         snprintf(addr, sizeof(addr), "%s:%d", ctx->dev_addr->addr, ctx->dev_addr->port);
811
812         value = g_variant_new("(ius)", ctx->result, ctx->nonce, addr);
813
814         ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_PRESENCE, ctx->signum,
815                         value);
816         if (IOTCON_ERROR_NONE != ret)
817                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
818
819         /* ctx was allocated from icd_ioty_ocprocess_presence_cb() */
820         free(ctx->bus_name);
821         free(ctx->dev_addr);
822         free(ctx);
823
824         return ret;
825 }
826
827
828 static void _presence_cb_response_error(const char *dest, unsigned int signum,
829                 int ret_val)
830 {
831         FN_CALL;
832         int ret;
833         GVariant *value;
834
835         value = g_variant_new("(ius)", ret_val, 0, IC_STR_NULL);
836
837         ret = _ocprocess_response_signal(dest, IC_DBUS_SIGNAL_PRESENCE, signum, value);
838         if (IOTCON_ERROR_NONE != ret)
839                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
840 }
841
842
843 OCStackApplicationResult icd_ioty_ocprocess_presence_cb(void *ctx, OCDoHandle handle,
844                 OCClientResponse *resp)
845 {
846         FN_CALL;
847         int ret;
848         OCDevAddr *dev_addr;
849         icd_sig_ctx_s *sig_context = ctx;
850         struct icd_presence_context *presence_ctx;
851
852         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
853         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
854
855         presence_ctx = calloc(1, sizeof(struct icd_presence_context));
856         if (NULL == presence_ctx) {
857                 ERR("calloc() Fail(%d)", errno);
858                 _presence_cb_response_error(sig_context->bus_name, sig_context->signum,
859                                 IOTCON_ERROR_OUT_OF_MEMORY);
860                 return OC_STACK_KEEP_TRANSACTION;
861         }
862
863         dev_addr = calloc(1, sizeof(OCDevAddr));
864         if (NULL == dev_addr) {
865                 ERR("calloc() Fail(%d)", errno);
866                 _presence_cb_response_error(sig_context->bus_name, sig_context->signum,
867                                 IOTCON_ERROR_OUT_OF_MEMORY);
868                 free(presence_ctx);
869                 return OC_STACK_KEEP_TRANSACTION;
870         }
871         memcpy(dev_addr, &resp->devAddr, sizeof(OCDevAddr));
872
873         switch (resp->result) {
874         case OC_STACK_OK:
875                 presence_ctx->result = IOTCON_PRESENCE_OK;
876                 break;
877         case OC_STACK_PRESENCE_STOPPED:
878                 presence_ctx->result = IOTCON_PRESENCE_STOPPED;
879                 break;
880         case OC_STACK_PRESENCE_TIMEOUT:
881                 presence_ctx->result = IOTCON_PRESENCE_TIMEOUT;
882                 break;
883         case OC_STACK_ERROR:
884         default:
885                 DBG("Presence error(%d)", resp->result);
886                 presence_ctx->result = IOTCON_ERROR_IOTIVITY;
887         }
888
889         presence_ctx->signum = sig_context->signum;
890         presence_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
891         presence_ctx->nonce = resp->sequenceNumber;
892         presence_ctx->dev_addr = dev_addr;
893
894         ret = _ocprocess_worker_start(_worker_presence_cb, presence_ctx);
895         if (IOTCON_ERROR_NONE != ret) {
896                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
897                 _presence_cb_response_error(sig_context->bus_name, sig_context->signum, ret);
898                 free(presence_ctx->bus_name);
899                 free(presence_ctx->dev_addr);
900                 free(presence_ctx);
901                 return OC_STACK_KEEP_TRANSACTION;
902         }
903
904         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
905         /* DO NOT FREE presence_ctx. It MUST be freed in the _worker_presence_cb func */
906
907         return OC_STACK_KEEP_TRANSACTION;
908 }
909
910
911 OCStackApplicationResult icd_ioty_ocprocess_info_cb(void *ctx, OCDoHandle handle,
912                 OCClientResponse *resp)
913 {
914         int ret;
915         int info_type;
916         struct icd_info_context *info_ctx;
917         icd_sig_ctx_s *sig_context = ctx;
918
919         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
920         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
921         RETV_IF(NULL == resp->payload, OC_STACK_KEEP_TRANSACTION);
922
923         if (PAYLOAD_TYPE_DEVICE == resp->payload->type)
924                 info_type = ICD_DEVICE_INFO;
925         else if (PAYLOAD_TYPE_PLATFORM == resp->payload->type)
926                 info_type = ICD_PLATFORM_INFO;
927         else
928                 return OC_STACK_KEEP_TRANSACTION;
929
930         info_ctx = calloc(1, sizeof(struct icd_info_context));
931         if (NULL == info_ctx) {
932                 ERR("calloc() Fail(%d)", errno);
933                 return OC_STACK_KEEP_TRANSACTION;
934         }
935
936         info_ctx->info_type = info_type;
937         info_ctx->payload = icd_payload_to_gvariant(resp->payload);
938         info_ctx->signum = sig_context->signum;
939         info_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
940
941         ret = _ocprocess_worker_start(_worker_info_cb, info_ctx);
942         if (IOTCON_ERROR_NONE != ret) {
943                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
944                 free(info_ctx->bus_name);
945                 if (info_ctx->payload)
946                         g_variant_unref(info_ctx->payload);
947                 free(info_ctx);
948                 return OC_STACK_KEEP_TRANSACTION;
949         }
950
951         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
952         /* DO NOT FREE info_ctx. It MUST be freed in the _worker_info_cb func */
953
954         return OC_STACK_KEEP_TRANSACTION;
955 }
956
957