modify "is_observable->properties", & remove tizen_info
[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 <stdint.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <glib.h>
21
22 #include <ocstack.h>
23 #include <octypes.h>
24 #include <ocpayload.h>
25
26 #include "iotcon.h"
27 #include "ic-utils.h"
28 #include "icd.h"
29 #include "icd-payload.h"
30 #include "icd-dbus.h"
31 #include "icd-ioty.h"
32 #include "icd-ioty-type.h"
33 #include "icd-ioty-ocprocess.h"
34
35 static int icd_ioty_alive;
36
37 typedef int (*_ocprocess_cb)(void *user_data);
38
39 struct icd_ioty_worker
40 {
41         void *ctx;
42         _ocprocess_cb cb;
43 };
44
45
46 struct icd_req_context {
47         int64_t signal_number;
48         char *bus_name;
49         int request_type;
50         int observe_id;
51         int observe_type;
52         OCRequestHandle request_h;
53         OCResourceHandle resource_h;
54         GVariant *payload;
55         GVariantBuilder *options;
56         GVariantBuilder *query;
57         OCDevAddr *dev_addr;
58 };
59
60
61 struct icd_find_context {
62         int64_t signal_number;
63         char *bus_name;
64         int conn_type;
65         GVariant **payload;
66 };
67
68
69 struct icd_crud_context {
70         int res;
71         int crud_type;
72         GVariant *payload;
73         GVariantBuilder *options;
74         GDBusMethodInvocation *invocation;
75 };
76
77
78 struct icd_info_context {
79         int64_t signal_number;
80         int info_type;
81         char *bus_name;
82         GVariant *payload;
83 };
84
85
86 struct icd_observe_context {
87         int64_t signal_number;
88         int res;
89         int seqnum;
90         char *bus_name;
91         GVariant *payload;
92         GVariantBuilder *options;
93 };
94
95
96 struct icd_presence_context {
97         OCDoHandle handle;
98         int result;
99         unsigned int nonce;
100         OCDevAddr *dev_addr;
101         iotcon_presence_trigger_e trigger;
102         char *resource_type;
103 };
104
105
106 struct icd_encap_context {
107         int64_t signal_number;
108         OCRepPayload *oic_payload;
109         OCStackResult ret;
110         icd_encap_info_s *encap_info;
111 };
112
113
114 void icd_ioty_ocprocess_stop()
115 {
116         icd_ioty_alive = 0;
117 }
118
119
120 static void* _ocprocess_worker_thread(void *data)
121 {
122         int ret;
123         struct icd_ioty_worker *worker = data;
124
125         if (NULL == data) {
126                 ERR("worker is NULL");
127                 return NULL;
128         }
129
130         ret = worker->cb(worker->ctx);
131         if (IOTCON_ERROR_NONE != ret)
132                 ERR("cb() Fail(%d)", ret);
133
134         /* worker was allocated from _ocprocess_worker_start() */
135         free(worker);
136
137         /* GCC warning happen if use g_thread_exit() */
138         return NULL;
139 }
140
141
142 static int _ocprocess_worker_start(_ocprocess_cb cb, void *ctx)
143 {
144         GError *error;
145         GThread *thread;
146         struct icd_ioty_worker *worker;
147
148         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
149
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;
154         }
155
156         worker->cb = cb;
157         worker->ctx = ctx;
158
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);
163                 g_error_free(error);
164                 free(worker);
165                 return IOTCON_ERROR_SYSTEM;
166         }
167
168         /* DO NOT join thread. It was already detached by calling g_thread_unref() */
169         g_thread_unref(thread);
170
171         /* DO NOT FREE worker. It MUST be freed in the _ocprocess_worker_thread() */
172
173         return IOTCON_ERROR_NONE;
174 }
175
176
177 static int _ocprocess_response_signal(const char *dest, const char *signal_prefix,
178                 int64_t signal_number, GVariant *value)
179 {
180         int ret;
181         char signal_name[IC_DBUS_SIGNAL_LENGTH] = {0};
182
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;
187         }
188
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);
192                 return ret;
193         }
194
195         return IOTCON_ERROR_NONE;
196 }
197
198
199 static inline GVariantBuilder* _ocprocess_parse_header_options(
200                 OCHeaderOption *oic_option, int option_size)
201 {
202         int i;
203         GVariantBuilder *options;
204
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);
209         }
210
211         return options;
212 }
213
214 static int _ioty_oic_action_to_ioty_action(int oic_action)
215 {
216         int action;
217
218         switch (oic_action) {
219         case OC_OBSERVE_REGISTER:
220                 action = IOTCON_OBSERVE_REGISTER;
221                 break;
222         case OC_OBSERVE_DEREGISTER:
223                 action = IOTCON_OBSERVE_DEREGISTER;
224                 break;
225         case OC_OBSERVE_NO_OPTION:
226         default:
227                 ERR("Invalid action (%d)", oic_action);
228                 action = IOTCON_OBSERVE_NO_TYPE;
229         }
230         return action;
231 }
232
233
234 static void _icd_req_context_free(struct icd_req_context *ctx)
235 {
236         free(ctx->bus_name);
237         if (ctx->payload)
238                 g_variant_unref(ctx->payload);
239         g_variant_builder_unref(ctx->options);
240         g_variant_builder_unref(ctx->query);
241         free(ctx->dev_addr);
242         free(ctx);
243 }
244
245
246 static int _worker_req_handler(void *context)
247 {
248         GVariant *value;
249         char *host_address;
250         int ret, conn_type;
251         GVariantBuilder payload_builder;
252         struct icd_req_context *ctx = context;
253
254         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
255
256         g_variant_builder_init(&payload_builder, G_VARIANT_TYPE("av"));
257         if (ctx->payload) {
258                 g_variant_builder_add(&payload_builder, "v", ctx->payload);
259                 ctx->payload = NULL;
260         }
261
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);
267                 return ret;
268         }
269
270         value = g_variant_new("(siia(qs)a(ss)iiavxx)",
271                         host_address,
272                         conn_type,
273                         ctx->request_type,
274                         ctx->options,
275                         ctx->query,
276                         ctx->observe_type,
277                         ctx->observe_id,
278                         &payload_builder,
279                         ICD_POINTER_TO_INT64(ctx->request_h),
280                         ICD_POINTER_TO_INT64(ctx->resource_h));
281
282         free(host_address);
283
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);
288
289         _icd_req_context_free(ctx);
290
291         return ret;
292 }
293
294
295 OCEntityHandlerResult icd_ioty_ocprocess_req_handler(OCEntityHandlerFlag flag,
296                 OCEntityHandlerRequest *request, void *user_data)
297 {
298         FN_CALL;
299         int ret;
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;
305         OCDevAddr *dev_addr;
306
307         RETV_IF(NULL == request, OC_EH_ERROR);
308
309         req_ctx = calloc(1, sizeof(struct icd_req_context));
310         if (NULL == req_ctx) {
311                 ERR("calloc() Fail(%d)", errno);
312                 return OC_EH_ERROR;
313         }
314
315         /* handle */
316         req_ctx->request_h = request->requestHandle;
317         req_ctx->resource_h = request->resource;
318
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);
322                 free(req_ctx);
323                 return OC_EH_ERROR;
324         }
325
326         /* signal number & bus_name */
327         req_ctx->signal_number = signal_number;
328         req_ctx->bus_name = bus_name;
329
330         dev_addr = calloc(1, sizeof(OCDevAddr));
331         if (NULL == dev_addr) {
332                 ERR("calloc() Fail(%d)", errno);
333                 free(req_ctx->bus_name);
334                 free(req_ctx);
335                 return OC_EH_ERROR;
336         }
337         memcpy(dev_addr, &request->devAddr, sizeof(OCDevAddr));
338         req_ctx->dev_addr = dev_addr;
339
340         /* request type */
341         if (OC_REQUEST_FLAG & flag) {
342                 switch (request->method) {
343                 case OC_REST_GET:
344                         req_ctx->request_type = IOTCON_REQUEST_GET;
345                         req_ctx->payload = NULL;
346                         break;
347                 case OC_REST_PUT:
348                         req_ctx->request_type = IOTCON_REQUEST_PUT;
349                         req_ctx->payload = icd_payload_to_gvariant(request->payload);
350                         break;
351                 case OC_REST_POST:
352                         req_ctx->request_type = IOTCON_REQUEST_POST;
353                         req_ctx->payload = icd_payload_to_gvariant(request->payload);
354                         break;
355                 case OC_REST_DELETE:
356                         req_ctx->request_type = IOTCON_REQUEST_DELETE;
357                         req_ctx->payload = NULL;
358                         break;
359                 default:
360                         free(req_ctx->dev_addr);
361                         free(req_ctx->bus_name);
362                         free(req_ctx);
363                         return OC_EH_ERROR;
364                 }
365         }
366
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);
371         } else {
372                 req_ctx->observe_type = IOTCON_OBSERVE_NO_TYPE;
373         }
374
375         /* header options */
376         req_ctx->options = _ocprocess_parse_header_options(
377                         request->rcvdVendorSpecificHeaderOptions,
378                         request->numRcvdVendorSpecificHeaderOptions);
379
380         /* query */
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))) {
385                         token = NULL;
386                         query_value = strtok_r(token, "=", &save_ptr2);
387                         if (NULL == query_value)
388                                 break;
389
390                         g_variant_builder_add(req_ctx->query, "(ss)", query_key, query_value);
391                 }
392                 query_str = NULL;
393         }
394
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);
399                 return OC_EH_ERROR;
400         }
401
402         /* DO NOT FREE req_ctx. It MUST be freed in the _worker_req_handler func */
403
404         return OC_EH_OK;
405 }
406
407
408 gpointer icd_ioty_ocprocess_thread(gpointer data)
409 {
410         FN_CALL;
411         OCStackResult result;
412         const struct timespec delay = {0, 10 * 1000 * 1000}; /* 10 ms */
413
414         icd_ioty_alive = 1;
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);
421                         break;
422                 }
423
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);
427         }
428
429         return NULL;
430 }
431
432
433 static int _worker_find_cb(void *context)
434 {
435         GVariant *value;
436         int i, ret;
437         struct icd_find_context *ctx = context;
438
439         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
440
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);
451                         return ret;
452                 }
453         }
454
455         /* ctx was allocated from icd_ioty_ocprocess_find_cb() */
456         free(ctx->bus_name);
457         free(ctx);
458
459         return ret;
460 }
461
462
463 OCStackApplicationResult icd_ioty_ocprocess_find_cb(void *ctx, OCDoHandle handle,
464                 OCClientResponse *resp)
465 {
466         int ret;
467         struct icd_find_context *find_ctx;
468         icd_sig_ctx_s *sig_context = ctx;
469
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);
477
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;
482         }
483
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);
489
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);
495                 free(find_ctx);
496                 return OC_STACK_KEEP_TRANSACTION;
497         }
498
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 */
501
502         return OC_STACK_KEEP_TRANSACTION;
503 }
504
505
506 static int _worker_crud_cb(void *context)
507 {
508         GVariant *value;
509         struct icd_crud_context *ctx = context;
510
511         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
512
513         if (ICD_CRUD_DELETE == ctx->crud_type)
514                 value = g_variant_new("(a(qs)i)", ctx->options, ctx->res);
515         else
516                 value = g_variant_new("(a(qs)vi)", ctx->options, ctx->payload, ctx->res);
517         icd_ioty_complete(ctx->crud_type, ctx->invocation, value);
518
519         /* ctx was allocated from icd_ioty_ocprocess_xxx_cb() */
520         g_variant_builder_unref(ctx->options);
521         free(ctx);
522
523         return IOTCON_ERROR_NONE;
524 }
525
526
527 static int _worker_info_cb(void *context)
528 {
529         int ret;
530         const char *signal_prefix = NULL;
531         struct icd_info_context *ctx = context;
532
533         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
534
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;
539
540         ret = _ocprocess_response_signal(ctx->bus_name, signal_prefix, ctx->signal_number,
541                         ctx->payload);
542         if (IOTCON_ERROR_NONE != ret)
543                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
544
545         /* ctx was allocated from icd_ioty_ocprocess_info_cb() */
546         free(ctx->bus_name);
547         free(ctx);
548
549         return ret;
550 }
551
552
553 static int _ocprocess_worker(_ocprocess_cb cb, int type, OCPayload *payload, int res,
554                 GVariantBuilder *options, void *ctx)
555 {
556         int ret;
557         struct icd_crud_context *crud_ctx;
558
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;
563         }
564
565         crud_ctx->crud_type = type;
566         crud_ctx->payload = icd_payload_to_gvariant(payload);
567         crud_ctx->res = res;
568         crud_ctx->options = options;
569         crud_ctx->invocation = ctx;
570
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);
577                 free(crud_ctx);
578         }
579
580         /* DO NOT FREE crud_ctx. It MUST be freed in the _worker_crud_cb func */
581
582         return ret;
583 }
584
585 static int _ocprocess_parse_oic_result(OCStackResult result)
586 {
587         int res;
588
589         switch (result) {
590         case OC_STACK_OK:
591                 res = IOTCON_RESPONSE_OK;
592                 break;
593         case OC_STACK_RESOURCE_CREATED:
594                 res = IOTCON_RESPONSE_RESOURCE_CREATED;
595                 break;
596         case OC_STACK_RESOURCE_DELETED:
597                 res = IOTCON_RESPONSE_RESULT_DELETED;
598                 break;
599         case OC_STACK_UNAUTHORIZED_REQ:
600                 res = IOTCON_RESPONSE_FORBIDDEN;
601                 break;
602         default:
603                 WARN("response error(%d)", result);
604                 res = IOTCON_RESPONSE_ERROR;
605                 break;
606         }
607
608         return res;
609 }
610
611
612 OCStackApplicationResult icd_ioty_ocprocess_get_cb(void *ctx, OCDoHandle handle,
613                 OCClientResponse *resp)
614 {
615         FN_CALL;
616         int ret, res;
617         GVariantBuilder *options;
618
619         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
620
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;
625         }
626
627         res = _ocprocess_parse_oic_result(resp->result);
628
629         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
630                         resp->numRcvdVendorSpecificHeaderOptions);
631
632         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_GET, resp->payload, res,
633                         options, ctx);
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;
638         }
639
640         return OC_STACK_DELETE_TRANSACTION;
641 }
642
643
644 OCStackApplicationResult icd_ioty_ocprocess_put_cb(void *ctx, OCDoHandle handle,
645                 OCClientResponse *resp)
646 {
647         FN_CALL;
648         int ret, res;
649         GVariantBuilder *options;
650
651         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
652
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;
657         }
658
659         res = _ocprocess_parse_oic_result(resp->result);
660
661         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
662                         resp->numRcvdVendorSpecificHeaderOptions);
663
664         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_PUT, resp->payload, res,
665                         options, ctx);
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;
670         }
671
672         return OC_STACK_DELETE_TRANSACTION;
673 }
674
675
676 OCStackApplicationResult icd_ioty_ocprocess_post_cb(void *ctx, OCDoHandle handle,
677                 OCClientResponse *resp)
678 {
679         FN_CALL;
680         int ret, res;
681         GVariantBuilder *options;
682
683         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
684
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;
689         }
690
691         res = _ocprocess_parse_oic_result(resp->result);
692
693         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
694                         resp->numRcvdVendorSpecificHeaderOptions);
695
696         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_POST, resp->payload, res,
697                         options, ctx);
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;
702         }
703
704         return OC_STACK_DELETE_TRANSACTION;
705 }
706
707
708 OCStackApplicationResult icd_ioty_ocprocess_delete_cb(void *ctx, OCDoHandle handle,
709                 OCClientResponse *resp)
710 {
711         FN_CALL;
712         int ret, res;
713         GVariantBuilder *options;
714
715         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
716
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;
721         }
722
723         res = _ocprocess_parse_oic_result(resp->result);
724
725         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
726                         resp->numRcvdVendorSpecificHeaderOptions);
727
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;
733         }
734
735         return OC_STACK_DELETE_TRANSACTION;
736 }
737
738
739 static int _worker_observe_cb(void *context)
740 {
741         int ret;
742         GVariant *value;
743         struct icd_observe_context *ctx = context;
744
745         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
746
747         value = g_variant_new("(a(qs)vii)", ctx->options, ctx->payload, ctx->res,
748                         ctx->seqnum);
749
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);
754
755         /* ctx was allocated from icd_ioty_ocprocess_observe_cb() */
756         free(ctx->bus_name);
757         g_variant_builder_unref(ctx->options);
758         free(ctx);
759
760         return ret;
761 }
762
763
764 static void _observe_cb_response_error(const char *dest,
765                 int64_t signal_number, int ret_val)
766 {
767         int ret;
768         GVariant *value;
769         GVariant *payload;
770         GVariantBuilder options;
771
772         g_variant_builder_init(&options, G_VARIANT_TYPE("a(qs)"));
773         payload = icd_payload_representation_empty_gvariant();
774
775         value = g_variant_new("(a(qs)vii)", &options, payload, ret_val, 0);
776
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);
780 }
781
782
783 OCStackApplicationResult icd_ioty_ocprocess_observe_cb(void *ctx,
784                 OCDoHandle handle, OCClientResponse *resp)
785 {
786         int ret, res;
787         GVariantBuilder *options;
788         struct icd_observe_context *observe_ctx;
789         icd_sig_ctx_s *sig_context = ctx;
790
791         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
792
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;
798         }
799
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;
806         }
807
808         res = _ocprocess_parse_oic_result(resp->result);
809
810         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
811                         resp->numRcvdVendorSpecificHeaderOptions);
812
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;
818
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);
827                 free(observe_ctx);
828                 return OC_STACK_KEEP_TRANSACTION;
829         }
830
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 */
833
834         return OC_STACK_KEEP_TRANSACTION;
835 }
836
837
838 static int _worker_presence_cb(void *context)
839 {
840         int conn_type;
841         OCDoHandle handle;
842         char *host_address;
843         GVariant *value, *value2;
844         int ret = IOTCON_ERROR_NONE;
845         struct icd_presence_context *ctx = context;
846
847         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
848
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);
853                 free(ctx->dev_addr);
854                 free(ctx);
855                 return ret;
856         }
857
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);
861
862         free(host_address);
863
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);
868
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);
875         } else {
876                 g_variant_unref(value2);
877         }
878
879         /* ctx was allocated from icd_ioty_ocprocess_presence_cb() */
880         free(ctx->resource_type);
881         free(ctx->dev_addr);
882         free(ctx);
883
884         return ret;
885 }
886
887
888 static void _presence_cb_response_error(OCDoHandle handle, int ret_val)
889 {
890         FN_CALL;
891         int ret;
892         OCDoHandle handle2;
893         GVariant *value, *value2;
894
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);
898
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);
903
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);
910         } else {
911                 g_variant_unref(value2);
912         }
913 }
914
915
916 static int _presence_trigger_to_ioty_trigger(OCPresenceTrigger src,
917                 iotcon_presence_trigger_e *dest)
918 {
919         RETV_IF(NULL == dest, IOTCON_ERROR_INVALID_PARAMETER);
920
921         switch (src) {
922         case OC_PRESENCE_TRIGGER_CREATE:
923                 *dest = IOTCON_PRESENCE_RESOURCE_CREATED;
924                 break;
925         case OC_PRESENCE_TRIGGER_CHANGE:
926                 *dest = IOTCON_PRESENCE_RESOURCE_UPDATED;
927                 break;
928         case OC_PRESENCE_TRIGGER_DELETE:
929                 *dest = IOTCON_PRESENCE_RESOURCE_DESTROYED;
930                 break;
931         default:
932                 ERR("Invalid trigger(%d)", src);
933                 return IOTCON_ERROR_INVALID_PARAMETER;
934         }
935
936         return IOTCON_ERROR_NONE;
937 }
938
939
940 OCStackApplicationResult icd_ioty_ocprocess_presence_cb(void *ctx, OCDoHandle handle,
941                 OCClientResponse *resp)
942 {
943         FN_CALL;
944         int ret;
945         OCDevAddr *dev_addr;
946         OCPresencePayload *payload;
947         struct icd_presence_context *presence_ctx;
948
949         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
950
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;
956         }
957
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);
962                 free(presence_ctx);
963                 return OC_STACK_KEEP_TRANSACTION;
964         }
965         memcpy(dev_addr, &resp->devAddr, sizeof(OCDevAddr));
966
967         payload = (OCPresencePayload*)resp->payload;
968
969         switch (resp->result) {
970         case OC_STACK_OK:
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);
976                         free(presence_ctx);
977                         return OC_STACK_KEEP_TRANSACTION;
978                 }
979                 break;
980         case OC_STACK_PRESENCE_STOPPED:
981                 presence_ctx->result = IOTCON_PRESENCE_STOPPED;
982                 break;
983         case OC_STACK_PRESENCE_TIMEOUT:
984                 presence_ctx->result = IOTCON_PRESENCE_TIMEOUT;
985                 break;
986         case OC_STACK_ERROR:
987         default:
988                 DBG("Presence error(%d)", resp->result);
989                 presence_ctx->result = IOTCON_ERROR_IOTIVITY;
990         }
991
992         presence_ctx->handle = handle;
993         presence_ctx->nonce = resp->sequenceNumber;
994         presence_ctx->dev_addr = dev_addr;
995
996         if (payload->resourceType)
997                 presence_ctx->resource_type = strdup(payload->resourceType);
998
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);
1005                 free(presence_ctx);
1006                 return OC_STACK_KEEP_TRANSACTION;
1007         }
1008
1009         /* DO NOT FREE presence_ctx. It MUST be freed in the _worker_presence_cb func */
1010
1011         return OC_STACK_KEEP_TRANSACTION;
1012 }
1013
1014
1015 OCStackApplicationResult icd_ioty_ocprocess_info_cb(void *ctx, OCDoHandle handle,
1016                 OCClientResponse *resp)
1017 {
1018         int ret;
1019         int info_type;
1020         struct icd_info_context *info_ctx;
1021         icd_sig_ctx_s *sig_context = ctx;
1022
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);
1026
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;
1031         else
1032                 return OC_STACK_KEEP_TRANSACTION;
1033
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;
1038         }
1039
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);
1044
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);
1051                 free(info_ctx);
1052                 return OC_STACK_KEEP_TRANSACTION;
1053         }
1054
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 */
1057
1058         return OC_STACK_KEEP_TRANSACTION;
1059 }
1060
1061
1062 static int _worker_encap_get_cb(void *context)
1063 {
1064         int ret;
1065         struct icd_encap_context *ctx = context;
1066         iotcon_remote_resource_state_e resource_state;
1067         GVariant *monitoring_value, *caching_value;
1068
1069         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
1070
1071         /* MONITORING */
1072         if (0 < ctx->encap_info->monitoring_count) {
1073                 switch (ctx->ret) {
1074                 case OC_STACK_OK:
1075                         resource_state = IOTCON_REMOTE_RESOURCE_ALIVE;
1076                         break;
1077                 case OC_STACK_ERROR:
1078                 default:
1079                         resource_state = IOTCON_REMOTE_RESOURCE_LOST_SIGNAL;
1080                 }
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);
1089                                 free(ctx);
1090                                 return ret;
1091                         }
1092                 }
1093         }
1094
1095         /* CACHING */
1096         if (0 < ctx->encap_info->caching_count) {
1097                 if (OC_STACK_OK != ctx->ret) {
1098                         OCRepPayloadDestroy(ctx->oic_payload);
1099                         free(ctx);
1100                         return IOTCON_ERROR_NONE;
1101                 }
1102
1103                 ret = icd_payload_representation_compare(ctx->encap_info->oic_payload,
1104                                 ctx->oic_payload);
1105                 if (IC_EQUAL == ret) {
1106                         OCRepPayloadDestroy(ctx->oic_payload);
1107                         free(ctx);
1108                         return IOTCON_ERROR_NONE;
1109                 }
1110
1111                 ctx->encap_info->oic_payload = ctx->oic_payload;
1112                 caching_value = icd_payload_to_gvariant((OCPayload*)ctx->oic_payload);
1113
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);
1119                         free(ctx);
1120                         return ret;
1121                 }
1122         }
1123
1124         OCRepPayloadDestroy(ctx->oic_payload);
1125         free(ctx);
1126
1127         return IOTCON_ERROR_NONE;
1128 }
1129
1130
1131 OCStackApplicationResult icd_ioty_ocprocess_encap_get_cb(void *ctx, OCDoHandle handle,
1132                 OCClientResponse *resp)
1133 {
1134         FN_CALL;
1135         int ret;
1136         icd_encap_info_s *encap_info = ctx;
1137         struct icd_encap_context *encap_ctx;
1138
1139         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
1140
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;
1145         }
1146
1147         encap_ctx->ret = resp->result;
1148         encap_ctx->oic_payload = OCRepPayloadClone((OCRepPayload*)resp->payload);
1149         encap_ctx->encap_info = encap_info;
1150
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);
1155                 free(encap_ctx);
1156                 return OC_STACK_DELETE_TRANSACTION;
1157         }
1158
1159         return OC_STACK_DELETE_TRANSACTION;
1160 }
1161
1162
1163 static int _worker_encap_get(void *context)
1164 {
1165         icd_encap_info_s *encap_info = context;
1166
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);
1171
1172         return IOTCON_ERROR_NONE;
1173 }
1174
1175
1176 OCStackApplicationResult icd_ioty_ocprocess_encap_observe_cb(void *ctx, OCDoHandle handle,
1177                 OCClientResponse *resp)
1178 {
1179         FN_CALL;
1180         int ret;
1181
1182         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
1183
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;
1188         }
1189
1190         return OC_STACK_KEEP_TRANSACTION;
1191 }
1192
1193
1194 OCStackApplicationResult icd_ioty_ocprocess_encap_presence_cb(void *ctx,
1195                 OCDoHandle handle, OCClientResponse *resp)
1196 {
1197         FN_CALL;
1198         int ret;
1199         OCPresencePayload *payload = (OCPresencePayload*)resp->payload;
1200
1201         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
1202
1203         if ((OC_STACK_OK == resp->result) && (OC_PRESENCE_TRIGGER_DELETE != payload->trigger))
1204                 return OC_STACK_KEEP_TRANSACTION;
1205
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;
1210         }
1211
1212         return OC_STACK_KEEP_TRANSACTION;
1213 }