Allow multiple presence
[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> /* for usleep() */
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_tizen_info_context {
87         OCRequestHandle request_h;
88         OCResourceHandle resource_h;
89         GDBusMethodInvocation *invocation;
90 };
91
92
93 struct icd_observe_context {
94         int64_t signal_number;
95         int res;
96         int seqnum;
97         char *bus_name;
98         GVariant *payload;
99         GVariantBuilder *options;
100 };
101
102
103 struct icd_presence_context {
104         OCDoHandle handle;
105         int result;
106         unsigned int nonce;
107         OCDevAddr *dev_addr;
108         iotcon_presence_trigger_e trigger;
109         char *resource_type;
110 };
111
112
113 void icd_ioty_ocprocess_stop()
114 {
115         icd_ioty_alive = 0;
116 }
117
118
119 static void* _ocprocess_worker_thread(void *data)
120 {
121         int ret;
122         struct icd_ioty_worker *worker = data;
123
124         if (NULL == data) {
125                 ERR("worker is NULL");
126                 return NULL;
127         }
128
129         ret = worker->cb(worker->ctx);
130         if (IOTCON_ERROR_NONE != ret)
131                 ERR("cb() Fail(%d)", ret);
132
133         /* worker was allocated from _ocprocess_worker_start() */
134         free(worker);
135
136         /* GCC warning happen if use g_thread_exit() */
137         return NULL;
138 }
139
140
141 static int _ocprocess_worker_start(_ocprocess_cb cb, void *ctx)
142 {
143         GError *error;
144         GThread *thread;
145         struct icd_ioty_worker *worker;
146
147         RETV_IF(NULL == cb, IOTCON_ERROR_INVALID_PARAMETER);
148
149         worker = calloc(1, sizeof(struct icd_ioty_worker));
150         if (NULL == worker) {
151                 ERR("calloc() Fail(%d)", errno);
152                 return IOTCON_ERROR_OUT_OF_MEMORY;
153         }
154
155         worker->cb = cb;
156         worker->ctx = ctx;
157
158         /* TODO : consider thread pool mechanism */
159         thread = g_thread_try_new("worker_thread", _ocprocess_worker_thread, worker, &error);
160         if (NULL == thread) {
161                 ERR("g_thread_try_new() Fail(%s)", error->message);
162                 g_error_free(error);
163                 free(worker);
164                 return IOTCON_ERROR_SYSTEM;
165         }
166
167         /* DO NOT join thread. It was already detached by calling g_thread_unref() */
168         g_thread_unref(thread);
169
170         /* DO NOT FREE worker. It MUST be freed in the _ocprocess_worker_thread() */
171
172         return IOTCON_ERROR_NONE;
173 }
174
175
176 static int _ocprocess_response_signal(const char *dest, const char *signal_prefix,
177                 int64_t signal_number, GVariant *value)
178 {
179         int ret;
180         char signal_name[IC_DBUS_SIGNAL_LENGTH] = {0};
181
182         ret = snprintf(signal_name, sizeof(signal_name), "%s_%llx", signal_prefix, signal_number);
183         if (ret <= 0 || sizeof(signal_name) <= ret) {
184                 ERR("snprintf() Fail(%d)", ret);
185                 return IOTCON_ERROR_IO_ERROR;
186         }
187
188         ret = icd_dbus_emit_signal(dest, signal_name, value);
189         if (IOTCON_ERROR_NONE != ret) {
190                 ERR("icd_dbus_emit_signal() Fail(%d)", ret);
191                 return ret;
192         }
193
194         return IOTCON_ERROR_NONE;
195 }
196
197
198 static inline GVariantBuilder* _ocprocess_parse_header_options(
199                 OCHeaderOption *oic_option, int option_size)
200 {
201         int i;
202         GVariantBuilder *options;
203
204         options = g_variant_builder_new(G_VARIANT_TYPE("a(qs)"));
205         for (i = 0; i < option_size; i++) {
206                 g_variant_builder_add(options, "(qs)", oic_option[i].optionID,
207                                 oic_option[i].optionData);
208         }
209
210         return options;
211 }
212
213 static int _ioty_oic_action_to_ioty_action(int oic_action)
214 {
215         int action;
216
217         switch (oic_action) {
218         case OC_OBSERVE_REGISTER:
219                 action = IOTCON_OBSERVE_REGISTER;
220                 break;
221         case OC_OBSERVE_DEREGISTER:
222                 action = IOTCON_OBSERVE_DEREGISTER;
223                 break;
224         case OC_OBSERVE_NO_OPTION:
225         default:
226                 ERR("Invalid action (%d)", oic_action);
227                 action = IOTCON_OBSERVE_TYPE_NONE;
228         }
229         return action;
230 }
231
232
233 static void _icd_req_context_free(struct icd_req_context *ctx)
234 {
235         free(ctx->bus_name);
236         if (ctx->payload)
237                 g_variant_unref(ctx->payload);
238         g_variant_builder_unref(ctx->options);
239         g_variant_builder_unref(ctx->query);
240         free(ctx->dev_addr);
241         free(ctx);
242 }
243
244
245 static int _worker_req_handler(void *context)
246 {
247         GVariant *value;
248         char *host_address;
249         int ret, conn_type;
250         GVariantBuilder payload_builder;
251         struct icd_req_context *ctx = context;
252
253         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
254
255         g_variant_builder_init(&payload_builder, G_VARIANT_TYPE("av"));
256         if (ctx->payload) {
257                 g_variant_builder_add(&payload_builder, "v", ctx->payload);
258                 ctx->payload = NULL;
259         }
260
261         ret = icd_ioty_get_host_address(ctx->dev_addr, &host_address, &conn_type);
262         if (IOTCON_ERROR_NONE != ret) {
263                 ERR("icd_ioty_get_host_address() Fail(%d)", ret);
264                 g_variant_builder_clear(&payload_builder);
265                 _icd_req_context_free(ctx);
266                 return ret;
267         }
268
269         value = g_variant_new("(siia(qs)a(ss)iiavxx)",
270                         host_address,
271                         conn_type,
272                         ctx->request_type,
273                         ctx->options,
274                         ctx->query,
275                         ctx->observe_type,
276                         ctx->observe_id,
277                         &payload_builder,
278                         ICD_POINTER_TO_INT64(ctx->request_h),
279                         ICD_POINTER_TO_INT64(ctx->resource_h));
280
281         free(host_address);
282
283         ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_REQUEST_HANDLER,
284                         ctx->signal_number, value);
285         if (IOTCON_ERROR_NONE != ret)
286                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
287
288         _icd_req_context_free(ctx);
289
290         return ret;
291 }
292
293
294 OCEntityHandlerResult icd_ioty_ocprocess_req_handler(OCEntityHandlerFlag flag,
295                 OCEntityHandlerRequest *request, void *user_data)
296 {
297         FN_CALL;
298         int ret;
299         int64_t signal_number;
300         char *query_str, *query_key, *query_value;
301         char *token, *save_ptr1, *save_ptr2;
302         char *bus_name = NULL;
303         struct icd_req_context *req_ctx;
304         OCDevAddr *dev_addr;
305
306         RETV_IF(NULL == request, OC_EH_ERROR);
307
308         req_ctx = calloc(1, sizeof(struct icd_req_context));
309         if (NULL == req_ctx) {
310                 ERR("calloc() Fail(%d)", errno);
311                 return OC_EH_ERROR;
312         }
313
314         /* handle */
315         req_ctx->request_h = request->requestHandle;
316         req_ctx->resource_h = request->resource;
317
318         ret = icd_dbus_client_list_get_info(req_ctx->resource_h, &signal_number, &bus_name);
319         if (IOTCON_ERROR_NONE != ret) {
320                 ERR("icd_dbus_client_list_get_info() Fail(%d)", ret);
321                 free(req_ctx);
322                 return OC_EH_ERROR;
323         }
324
325         /* signal number & bus_name */
326         req_ctx->signal_number = signal_number;
327         req_ctx->bus_name = bus_name;
328
329         dev_addr = calloc(1, sizeof(OCDevAddr));
330         if (NULL == dev_addr) {
331                 ERR("calloc() Fail(%d)", errno);
332                 free(req_ctx);
333                 return OC_EH_ERROR;
334         }
335         memcpy(dev_addr, &request->devAddr, sizeof(OCDevAddr));
336         req_ctx->dev_addr = dev_addr;
337
338         /* request type */
339         if (OC_REQUEST_FLAG & flag) {
340                 switch (request->method) {
341                 case OC_REST_GET:
342                         req_ctx->request_type = IOTCON_REQUEST_GET;
343                         req_ctx->payload = NULL;
344                         break;
345                 case OC_REST_PUT:
346                         req_ctx->request_type = IOTCON_REQUEST_PUT;
347                         req_ctx->payload = icd_payload_to_gvariant(request->payload);
348                         break;
349                 case OC_REST_POST:
350                         req_ctx->request_type = IOTCON_REQUEST_POST;
351                         req_ctx->payload = icd_payload_to_gvariant(request->payload);
352                         break;
353                 case OC_REST_DELETE:
354                         req_ctx->request_type = IOTCON_REQUEST_DELETE;
355                         req_ctx->payload = NULL;
356                         break;
357                 default:
358                         free(req_ctx->bus_name);
359                         free(req_ctx);
360                         return OC_EH_ERROR;
361                 }
362         }
363
364         if (OC_OBSERVE_FLAG & flag) {
365                 /* observation info*/
366                 req_ctx->observe_id = request->obsInfo.obsId;
367                 req_ctx->observe_type = _ioty_oic_action_to_ioty_action(request->obsInfo.action);
368         } else {
369                 req_ctx->observe_type = IOTCON_OBSERVE_TYPE_NONE;
370         }
371
372         /* header options */
373         req_ctx->options = _ocprocess_parse_header_options(
374                         request->rcvdVendorSpecificHeaderOptions,
375                         request->numRcvdVendorSpecificHeaderOptions);
376
377         /* query */
378         req_ctx->query = g_variant_builder_new(G_VARIANT_TYPE("a(ss)"));
379         query_str = request->query;
380         while ((token = strtok_r(query_str, "&;", &save_ptr1))) {
381                 while ((query_key = strtok_r(token, "=", &save_ptr2))) {
382                         token = NULL;
383                         query_value = strtok_r(token, "=", &save_ptr2);
384                         if (NULL == query_value)
385                                 break;
386
387                         g_variant_builder_add(req_ctx->query, "(ss)", query_key, query_value);
388                 }
389                 query_str = NULL;
390         }
391
392         ret = _ocprocess_worker_start(_worker_req_handler, req_ctx);
393         if (IOTCON_ERROR_NONE != ret) {
394                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
395                 _icd_req_context_free(req_ctx);
396                 return OC_EH_ERROR;
397         }
398
399         /* DO NOT FREE req_ctx. It MUST be freed in the _worker_req_handler func */
400
401         return OC_EH_OK;
402 }
403
404
405 gpointer icd_ioty_ocprocess_thread(gpointer data)
406 {
407         FN_CALL;
408         OCStackResult result;
409
410         icd_ioty_alive = 1;
411         while (icd_ioty_alive) {
412                 icd_ioty_csdk_lock();
413                 result = OCProcess();
414                 icd_ioty_csdk_unlock();
415                 if (OC_STACK_OK != result) {
416                         ERR("OCProcess() Fail(%d)", result);
417                         break;
418                 }
419
420                 /* TODO : SHOULD revise time or usleep */
421                 usleep(10);
422         }
423
424         return NULL;
425 }
426
427
428 static int _worker_find_cb(void *context)
429 {
430         GVariant *value;
431         int i, ret;
432         struct icd_find_context *ctx = context;
433
434         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
435
436         for (i = 0; ctx->payload[i]; i++) {
437                 value = g_variant_new("(vi)", ctx->payload[i], ctx->conn_type);
438                 /* TODO : If one device has multi resources, it comes as bulk data.
439                  * To reduce the number of emit_signal, let's send signal only one time for one device.
440                  * for ex, client list. */
441                 ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_FOUND_RESOURCE,
442                                 ctx->signal_number, value);
443                 if (IOTCON_ERROR_NONE != ret) {
444                         ERR("_ocprocess_response_signal() Fail(%d)", ret);
445                         g_variant_unref(value);
446                         return ret;
447                 }
448         }
449
450         /* ctx was allocated from icd_ioty_ocprocess_find_cb() */
451         free(ctx->bus_name);
452         free(ctx);
453
454         return ret;
455 }
456
457
458 OCStackApplicationResult icd_ioty_ocprocess_find_cb(void *ctx, OCDoHandle handle,
459                 OCClientResponse *resp)
460 {
461         int ret;
462         struct icd_find_context *find_ctx;
463         icd_sig_ctx_s *sig_context = ctx;
464
465         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
466         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
467         if (NULL == resp->payload)
468                 /* normal case : payload COULD be NULL */
469                 return OC_STACK_KEEP_TRANSACTION;
470         RETVM_IF(PAYLOAD_TYPE_DISCOVERY != resp->payload->type,
471                         OC_STACK_KEEP_TRANSACTION, "Invalid payload type(%d)", resp->payload->type);
472
473         find_ctx = calloc(1, sizeof(struct icd_find_context));
474         if (NULL == find_ctx) {
475                 ERR("calloc() Fail(%d)", errno);
476                 return OC_STACK_KEEP_TRANSACTION;
477         }
478
479         find_ctx->signal_number = sig_context->signal_number;
480         find_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
481         find_ctx->payload = icd_payload_res_to_gvariant(resp->payload, &resp->devAddr);
482         find_ctx->conn_type = icd_ioty_transport_flag_to_conn_type(resp->devAddr.adapter,
483                         resp->devAddr.flags);
484
485         ret = _ocprocess_worker_start(_worker_find_cb, find_ctx);
486         if (IOTCON_ERROR_NONE != ret) {
487                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
488                 free(find_ctx->bus_name);
489                 ic_utils_gvariant_array_free(find_ctx->payload);
490                 free(find_ctx);
491                 return OC_STACK_KEEP_TRANSACTION;
492         }
493
494         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
495         /* DO NOT FREE find_ctx. It MUST be freed in the _worker_find_cb func */
496
497         return OC_STACK_KEEP_TRANSACTION;
498 }
499
500
501 static int _worker_crud_cb(void *context)
502 {
503         GVariant *value;
504         struct icd_crud_context *ctx = context;
505
506         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
507
508         if (ICD_CRUD_DELETE == ctx->crud_type)
509                 value = g_variant_new("(a(qs)i)", ctx->options, ctx->res);
510         else
511                 value = g_variant_new("(a(qs)vi)", ctx->options, ctx->payload, ctx->res);
512         icd_ioty_complete(ctx->crud_type, ctx->invocation, value);
513
514         /* ctx was allocated from icd_ioty_ocprocess_xxx_cb() */
515         g_variant_builder_unref(ctx->options);
516         free(ctx);
517
518         return IOTCON_ERROR_NONE;
519 }
520
521
522 static int _worker_info_cb(void *context)
523 {
524         int ret;
525         const char *signal_prefix = NULL;
526         struct icd_info_context *ctx = context;
527
528         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
529
530         if (ICD_DEVICE_INFO == ctx->info_type)
531                 signal_prefix = IC_DBUS_SIGNAL_DEVICE;
532         else if (ICD_PLATFORM_INFO == ctx->info_type)
533                 signal_prefix = IC_DBUS_SIGNAL_PLATFORM;
534
535         ret = _ocprocess_response_signal(ctx->bus_name, signal_prefix, ctx->signal_number,
536                         ctx->payload);
537         if (IOTCON_ERROR_NONE != ret)
538                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
539
540         /* ctx was allocated from icd_ioty_ocprocess_info_cb() */
541         free(ctx->bus_name);
542         free(ctx);
543
544         return ret;
545 }
546
547
548 static int _ocprocess_worker(_ocprocess_cb cb, int type, OCPayload *payload, int res,
549                 GVariantBuilder *options, void *ctx)
550 {
551         int ret;
552         struct icd_crud_context *crud_ctx;
553
554         crud_ctx = calloc(1, sizeof(struct icd_crud_context));
555         if (NULL == crud_ctx) {
556                 ERR("calloc() Fail(%d)", errno);
557                 return IOTCON_ERROR_OUT_OF_MEMORY;
558         }
559
560         crud_ctx->crud_type = type;
561         crud_ctx->payload = icd_payload_to_gvariant(payload);
562         crud_ctx->res = res;
563         crud_ctx->options = options;
564         crud_ctx->invocation = ctx;
565
566         ret = _ocprocess_worker_start(cb, crud_ctx);
567         if (IOTCON_ERROR_NONE != ret) {
568                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
569                 if (crud_ctx->payload)
570                         g_variant_unref(crud_ctx->payload);
571                 g_variant_builder_unref(crud_ctx->options);
572                 free(crud_ctx);
573         }
574
575         /* DO NOT FREE crud_ctx. It MUST be freed in the _worker_crud_cb func */
576
577         return ret;
578 }
579
580 static int _ocprocess_parse_oic_result(OCStackResult result)
581 {
582         int res;
583
584         switch (result) {
585         case OC_STACK_OK:
586                 res = IOTCON_RESPONSE_RESULT_OK;
587                 break;
588         case OC_STACK_RESOURCE_CREATED:
589                 res = IOTCON_RESPONSE_RESULT_RESOURCE_CREATED;
590                 break;
591         case OC_STACK_RESOURCE_DELETED:
592                 res = IOTCON_RESPONSE_RESULT_RESOURCE_DELETED;
593                 break;
594         case OC_STACK_UNAUTHORIZED_REQ:
595                 res = IOTCON_RESPONSE_RESULT_FORBIDDEN;
596                 break;
597         default:
598                 WARN("response error(%d)", result);
599                 res = IOTCON_RESPONSE_RESULT_ERROR;
600                 break;
601         }
602
603         return res;
604 }
605
606
607 OCStackApplicationResult icd_ioty_ocprocess_get_cb(void *ctx, OCDoHandle handle,
608                 OCClientResponse *resp)
609 {
610         FN_CALL;
611         int ret, res;
612         GVariantBuilder *options;
613
614         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
615
616         if (NULL == resp->payload) {
617                 ERR("payload is empty");
618                 icd_ioty_complete_error(ICD_CRUD_GET, ctx, IOTCON_ERROR_IOTIVITY);
619                 return OC_STACK_DELETE_TRANSACTION;
620         }
621
622         res = _ocprocess_parse_oic_result(resp->result);
623
624         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
625                         resp->numRcvdVendorSpecificHeaderOptions);
626
627         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_GET, resp->payload, res,
628                         options, ctx);
629         if (IOTCON_ERROR_NONE != ret) {
630                 ERR("_ocprocess_worker() Fail(%d)", ret);
631                 icd_ioty_complete_error(ICD_CRUD_GET, ctx, ret);
632                 return OC_STACK_DELETE_TRANSACTION;
633         }
634
635         return OC_STACK_DELETE_TRANSACTION;
636 }
637
638
639 OCStackApplicationResult icd_ioty_ocprocess_put_cb(void *ctx, OCDoHandle handle,
640                 OCClientResponse *resp)
641 {
642         FN_CALL;
643         int ret, res;
644         GVariantBuilder *options;
645
646         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
647
648         if (NULL == resp->payload) {
649                 ERR("payload is empty");
650                 icd_ioty_complete_error(ICD_CRUD_PUT, ctx, IOTCON_ERROR_IOTIVITY);
651                 return OC_STACK_DELETE_TRANSACTION;
652         }
653
654         res = _ocprocess_parse_oic_result(resp->result);
655
656         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
657                         resp->numRcvdVendorSpecificHeaderOptions);
658
659         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_PUT, resp->payload, res,
660                         options, ctx);
661         if (IOTCON_ERROR_NONE != ret) {
662                 ERR("_ocprocess_worker() Fail(%d)", ret);
663                 icd_ioty_complete_error(ICD_CRUD_PUT, ctx, ret);
664                 return OC_STACK_DELETE_TRANSACTION;
665         }
666
667         return OC_STACK_DELETE_TRANSACTION;
668 }
669
670
671 OCStackApplicationResult icd_ioty_ocprocess_post_cb(void *ctx, OCDoHandle handle,
672                 OCClientResponse *resp)
673 {
674         FN_CALL;
675         int ret, res;
676         GVariantBuilder *options;
677
678         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
679
680         if (NULL == resp->payload) {
681                 ERR("payload is empty");
682                 icd_ioty_complete_error(ICD_CRUD_POST, ctx, IOTCON_ERROR_IOTIVITY);
683                 return OC_STACK_DELETE_TRANSACTION;
684         }
685
686         res = _ocprocess_parse_oic_result(resp->result);
687
688         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
689                         resp->numRcvdVendorSpecificHeaderOptions);
690
691         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_POST, resp->payload, res,
692                         options, ctx);
693         if (IOTCON_ERROR_NONE != ret) {
694                 ERR("_ocprocess_worker() Fail(%d)", ret);
695                 icd_ioty_complete_error(ICD_CRUD_POST, ctx, ret);
696                 return OC_STACK_DELETE_TRANSACTION;
697         }
698
699         return OC_STACK_DELETE_TRANSACTION;
700 }
701
702
703 OCStackApplicationResult icd_ioty_ocprocess_delete_cb(void *ctx, OCDoHandle handle,
704                 OCClientResponse *resp)
705 {
706         FN_CALL;
707         int ret, res;
708         GVariantBuilder *options;
709
710         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
711
712         if (NULL == resp->payload) {
713                 ERR("payload is empty");
714                 icd_ioty_complete_error(ICD_CRUD_DELETE, ctx, IOTCON_ERROR_IOTIVITY);
715                 return OC_STACK_DELETE_TRANSACTION;
716         }
717
718         res = _ocprocess_parse_oic_result(resp->result);
719
720         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
721                         resp->numRcvdVendorSpecificHeaderOptions);
722
723         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_DELETE, NULL, res, options, ctx);
724         if (IOTCON_ERROR_NONE != ret) {
725                 ERR("_ocprocess_worker() Fail(%d)", ret);
726                 icd_ioty_complete_error(ICD_CRUD_DELETE, ctx, ret);
727                 return OC_STACK_DELETE_TRANSACTION;
728         }
729
730         return OC_STACK_DELETE_TRANSACTION;
731 }
732
733
734 static int _worker_observe_cb(void *context)
735 {
736         int ret;
737         GVariant *value;
738         struct icd_observe_context *ctx = context;
739
740         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
741
742         value = g_variant_new("(a(qs)vii)", ctx->options, ctx->payload, ctx->res,
743                         ctx->seqnum);
744
745         ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_OBSERVE,
746                         ctx->signal_number, value);
747         if (IOTCON_ERROR_NONE != ret)
748                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
749
750         /* ctx was allocated from icd_ioty_ocprocess_observe_cb() */
751         free(ctx->bus_name);
752         g_variant_builder_unref(ctx->options);
753         free(ctx);
754
755         return ret;
756 }
757
758
759 static void _observe_cb_response_error(const char *dest,
760                 int64_t signal_number, int ret_val)
761 {
762         int ret;
763         GVariant *value;
764         GVariant *payload;
765         GVariantBuilder options;
766
767         g_variant_builder_init(&options, G_VARIANT_TYPE("a(qs)"));
768         payload = icd_payload_representation_empty_gvariant();
769
770         value = g_variant_new("(a(qs)vii)", &options, payload, ret_val, 0);
771
772         ret = _ocprocess_response_signal(dest, IC_DBUS_SIGNAL_OBSERVE, signal_number, value);
773         if (IOTCON_ERROR_NONE != ret)
774                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
775 }
776
777
778 OCStackApplicationResult icd_ioty_ocprocess_observe_cb(void *ctx,
779                 OCDoHandle handle, OCClientResponse *resp)
780 {
781         int ret, res;
782         GVariantBuilder *options;
783         struct icd_observe_context *observe_ctx;
784         icd_sig_ctx_s *sig_context = ctx;
785
786         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
787
788         if (NULL == resp->payload) {
789                 ERR("payload is empty");
790                 _observe_cb_response_error(sig_context->bus_name, sig_context->signal_number,
791                                 IOTCON_ERROR_IOTIVITY);
792                 return OC_STACK_KEEP_TRANSACTION;
793         }
794
795         observe_ctx = calloc(1, sizeof(struct icd_observe_context));
796         if (NULL == observe_ctx) {
797                 ERR("calloc() Fail(%d)", errno);
798                 _observe_cb_response_error(sig_context->bus_name, sig_context->signal_number,
799                                 IOTCON_ERROR_OUT_OF_MEMORY);
800                 return OC_STACK_KEEP_TRANSACTION;
801         }
802
803         res = _ocprocess_parse_oic_result(resp->result);
804
805         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
806                         resp->numRcvdVendorSpecificHeaderOptions);
807
808         observe_ctx->payload = icd_payload_to_gvariant(resp->payload);
809         observe_ctx->signal_number = sig_context->signal_number;
810         observe_ctx->res = res;
811         observe_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
812         observe_ctx->options = options;
813
814         ret = _ocprocess_worker_start(_worker_observe_cb, observe_ctx);
815         if (IOTCON_ERROR_NONE != ret) {
816                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
817                 _observe_cb_response_error(sig_context->bus_name, sig_context->signal_number, ret);
818                 free(observe_ctx->bus_name);
819                 if (observe_ctx->payload)
820                         g_variant_unref(observe_ctx->payload);
821                 g_variant_builder_unref(observe_ctx->options);
822                 free(observe_ctx);
823                 return OC_STACK_KEEP_TRANSACTION;
824         }
825
826         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
827         /* DO NOT FREE observe_ctx. It MUST be freed in the _worker_observe_cb func */
828
829         return OC_STACK_KEEP_TRANSACTION;
830 }
831
832
833 static int _worker_presence_cb(void *context)
834 {
835         int conn_type;
836         OCDoHandle handle;
837         char *host_address;
838         GVariant *value, *value2;
839         int ret = IOTCON_ERROR_NONE;
840         struct icd_presence_context *ctx = context;
841
842         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
843
844         ret = icd_ioty_get_host_address(ctx->dev_addr, &host_address, &conn_type);
845         if (IOTCON_ERROR_NONE != ret) {
846                 ERR("icd_ioty_get_host_address() Fail(%d)", ret);
847                 free(ctx->resource_type);
848                 free(ctx->dev_addr);
849                 free(ctx);
850                 return ret;
851         }
852
853         value = g_variant_new("(iusiis)", ctx->result, ctx->nonce, host_address, conn_type,
854                         ctx->trigger, ic_utils_dbus_encode_str(ctx->resource_type));
855         value2 = g_variant_ref(value);
856
857         free(host_address);
858
859         ret = _ocprocess_response_signal(NULL, IC_DBUS_SIGNAL_PRESENCE,
860                         ICD_POINTER_TO_INT64(ctx->handle), value);
861         if (IOTCON_ERROR_NONE != ret)
862                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
863
864         handle = icd_ioty_presence_table_get_handle(ICD_MULTICAST_ADDRESS);
865         if (handle && (handle != ctx->handle)) {
866                 ret = _ocprocess_response_signal(NULL, IC_DBUS_SIGNAL_PRESENCE,
867                                 ICD_POINTER_TO_INT64(handle), value2);
868                 if (IOTCON_ERROR_NONE != ret)
869                         ERR("_ocprocess_response_signal() Fail(%d)", ret);
870         } else {
871                 g_variant_unref(value2);
872         }
873
874         /* ctx was allocated from icd_ioty_ocprocess_presence_cb() */
875         free(ctx->resource_type);
876         free(ctx->dev_addr);
877         free(ctx);
878
879         return ret;
880 }
881
882
883 static void _presence_cb_response_error(OCDoHandle handle, int ret_val)
884 {
885         FN_CALL;
886         int ret;
887         OCDoHandle handle2;
888         GVariant *value, *value2;
889
890         value = g_variant_new("(iusiis)", ret_val, 0, IC_STR_NULL, IOTCON_CONNECTIVITY_ALL,
891                         IOTCON_PRESENCE_TRIGGER_RESOURCE_CREATED, IC_STR_NULL);
892         value2 = g_variant_ref(value);
893
894         ret = _ocprocess_response_signal(NULL, IC_DBUS_SIGNAL_PRESENCE,
895                         ICD_POINTER_TO_INT64(handle), value);
896         if (IOTCON_ERROR_NONE != ret)
897                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
898
899         handle2 = icd_ioty_presence_table_get_handle(ICD_MULTICAST_ADDRESS);
900         if (handle2 && (handle2 != handle)) {
901                 ret = _ocprocess_response_signal(NULL, IC_DBUS_SIGNAL_PRESENCE,
902                                 ICD_POINTER_TO_INT64(handle), value2);
903                 if (IOTCON_ERROR_NONE != ret)
904                         ERR("_ocprocess_response_signal() Fail(%d)", ret);
905         } else {
906                 g_variant_unref(value2);
907         }
908 }
909
910
911 static int _presence_trigger_to_ioty_trigger(OCPresenceTrigger src,
912                 iotcon_presence_trigger_e *dest)
913 {
914         RETV_IF(NULL == dest, IOTCON_ERROR_INVALID_PARAMETER);
915
916         switch (src) {
917         case OC_PRESENCE_TRIGGER_CREATE:
918                 *dest = IOTCON_PRESENCE_TRIGGER_RESOURCE_CREATED;
919                 break;
920         case OC_PRESENCE_TRIGGER_CHANGE:
921                 *dest = IOTCON_PRESENCE_TRIGGER_RESOURCE_UPDATED;
922                 break;
923         case OC_PRESENCE_TRIGGER_DELETE:
924                 *dest = IOTCON_PRESENCE_TRIGGER_RESOURCE_DESTROYED;
925                 break;
926         default:
927                 ERR("Invalid trigger(%d)", src);
928                 return IOTCON_ERROR_INVALID_PARAMETER;
929         }
930
931         return IOTCON_ERROR_NONE;
932 }
933
934
935 OCStackApplicationResult icd_ioty_ocprocess_presence_cb(void *ctx, OCDoHandle handle,
936                 OCClientResponse *resp)
937 {
938         FN_CALL;
939         int ret;
940         OCDevAddr *dev_addr;
941         OCPresencePayload *payload;
942         struct icd_presence_context *presence_ctx;
943
944         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
945
946         presence_ctx = calloc(1, sizeof(struct icd_presence_context));
947         if (NULL == presence_ctx) {
948                 ERR("calloc() Fail(%d)", errno);
949                 _presence_cb_response_error(handle, IOTCON_ERROR_OUT_OF_MEMORY);
950                 return OC_STACK_KEEP_TRANSACTION;
951         }
952
953         dev_addr = calloc(1, sizeof(OCDevAddr));
954         if (NULL == dev_addr) {
955                 ERR("calloc() Fail(%d)", errno);
956                 _presence_cb_response_error(handle, IOTCON_ERROR_OUT_OF_MEMORY);
957                 free(presence_ctx);
958                 return OC_STACK_KEEP_TRANSACTION;
959         }
960         memcpy(dev_addr, &resp->devAddr, sizeof(OCDevAddr));
961
962         payload = (OCPresencePayload*)resp->payload;
963
964         switch (resp->result) {
965         case OC_STACK_OK:
966                 presence_ctx->result = IOTCON_PRESENCE_OK;
967                 ret = _presence_trigger_to_ioty_trigger(payload->trigger, &presence_ctx->trigger);
968                 if (IOTCON_ERROR_NONE != ret) {
969                         ERR("_presence_trigger_to_ioty_trigger() Fail(%d)", ret);
970                         _presence_cb_response_error(handle, ret);
971                         free(presence_ctx);
972                         return OC_STACK_KEEP_TRANSACTION;
973                 }
974                 break;
975         case OC_STACK_PRESENCE_STOPPED:
976                 presence_ctx->result = IOTCON_PRESENCE_STOPPED;
977                 break;
978         case OC_STACK_PRESENCE_TIMEOUT:
979                 presence_ctx->result = IOTCON_PRESENCE_TIMEOUT;
980                 break;
981         case OC_STACK_ERROR:
982         default:
983                 DBG("Presence error(%d)", resp->result);
984                 presence_ctx->result = IOTCON_ERROR_IOTIVITY;
985         }
986
987         presence_ctx->handle = handle;
988         presence_ctx->nonce = resp->sequenceNumber;
989         presence_ctx->dev_addr = dev_addr;
990
991         if (payload->resourceType)
992                 presence_ctx->resource_type = strdup(payload->resourceType);
993
994         ret = _ocprocess_worker_start(_worker_presence_cb, presence_ctx);
995         if (IOTCON_ERROR_NONE != ret) {
996                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
997                 _presence_cb_response_error(handle, ret);
998                 free(presence_ctx->resource_type);
999                 free(presence_ctx->dev_addr);
1000                 free(presence_ctx);
1001                 return OC_STACK_KEEP_TRANSACTION;
1002         }
1003
1004         /* DO NOT FREE presence_ctx. It MUST be freed in the _worker_presence_cb func */
1005
1006         return OC_STACK_KEEP_TRANSACTION;
1007 }
1008
1009
1010 OCStackApplicationResult icd_ioty_ocprocess_info_cb(void *ctx, OCDoHandle handle,
1011                 OCClientResponse *resp)
1012 {
1013         int ret;
1014         int info_type;
1015         struct icd_info_context *info_ctx;
1016         icd_sig_ctx_s *sig_context = ctx;
1017
1018         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
1019         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
1020         RETV_IF(NULL == resp->payload, OC_STACK_KEEP_TRANSACTION);
1021
1022         if (PAYLOAD_TYPE_DEVICE == resp->payload->type)
1023                 info_type = ICD_DEVICE_INFO;
1024         else if (PAYLOAD_TYPE_PLATFORM == resp->payload->type)
1025                 info_type = ICD_PLATFORM_INFO;
1026         else
1027                 return OC_STACK_KEEP_TRANSACTION;
1028
1029         info_ctx = calloc(1, sizeof(struct icd_info_context));
1030         if (NULL == info_ctx) {
1031                 ERR("calloc() Fail(%d)", errno);
1032                 return OC_STACK_KEEP_TRANSACTION;
1033         }
1034
1035         info_ctx->info_type = info_type;
1036         info_ctx->payload = icd_payload_to_gvariant(resp->payload);
1037         info_ctx->signal_number = sig_context->signal_number;
1038         info_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
1039
1040         ret = _ocprocess_worker_start(_worker_info_cb, info_ctx);
1041         if (IOTCON_ERROR_NONE != ret) {
1042                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
1043                 free(info_ctx->bus_name);
1044                 if (info_ctx->payload)
1045                         g_variant_unref(info_ctx->payload);
1046                 free(info_ctx);
1047                 return OC_STACK_KEEP_TRANSACTION;
1048         }
1049
1050         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
1051         /* DO NOT FREE info_ctx. It MUST be freed in the _worker_info_cb func */
1052
1053         return OC_STACK_KEEP_TRANSACTION;
1054 }
1055
1056
1057 static int _worker_tizen_info_handler(void *context)
1058 {
1059         int ret;
1060         char *device_name;
1061         char *tizen_device_id;
1062         OCStackResult result;
1063         OCRepPayload *payload;
1064         OCEntityHandlerResponse response = {0};
1065         struct icd_tizen_info_context *ctx = context;
1066
1067         response.requestHandle = ctx->request_h;
1068         response.resourceHandle = ctx->resource_h;
1069         response.ehResult = OC_EH_OK;
1070
1071         /* Get Tizen Info */
1072         ret = icd_ioty_tizen_info_get_property(&device_name, &tizen_device_id);
1073         if (IOTCON_ERROR_NONE != ret) {
1074                 ERR("icd_ioty_tizen_info_get_property() Fail(%d)", ret);
1075                 response.ehResult = OC_EH_ERROR;
1076         }
1077
1078         /* payload */
1079         payload = OCRepPayloadCreate();
1080         OCRepPayloadSetUri(payload, ICD_IOTY_TIZEN_INFO_URI);
1081         OCRepPayloadAddResourceType(payload, ICD_IOTY_TIZEN_INFO_TYPE);
1082         OCRepPayloadAddInterface(payload, IC_INTERFACE_DEFAULT);
1083
1084         OCRepPayloadSetPropString(payload, ICD_IOTY_TIZEN_INFO_DEVICE_NAME,
1085                         ic_utils_dbus_encode_str(device_name));
1086         OCRepPayloadSetPropString(payload, ICD_IOTY_TIZEN_INFO_TIZEN_DEVICE_ID,
1087                         ic_utils_dbus_encode_str(tizen_device_id));
1088         response.payload = (OCPayload*)payload;
1089
1090         icd_ioty_csdk_lock();
1091         result = OCDoResponse(&response);
1092         icd_ioty_csdk_unlock();
1093
1094         if (OC_STACK_OK != result) {
1095                 ERR("OCDoResponse() Fail(%d)", result);
1096                 free(ctx);
1097                 return IOTCON_ERROR_IOTIVITY;
1098         }
1099
1100         free(ctx);
1101         return IOTCON_ERROR_NONE;
1102 }
1103
1104
1105 OCEntityHandlerResult icd_ioty_ocprocess_tizen_info_handler(OCEntityHandlerFlag flag,
1106                 OCEntityHandlerRequest *request, void *user_data)
1107 {
1108         int ret;
1109         struct icd_tizen_info_context *tizen_info_ctx;
1110
1111         if ((0 == (OC_REQUEST_FLAG & flag)) || (OC_REST_GET != request->method)) {
1112                 ERR("Prohibited Action");
1113                 return OC_EH_FORBIDDEN;
1114         }
1115
1116         tizen_info_ctx = calloc(1, sizeof(struct icd_tizen_info_context));
1117         if (NULL == tizen_info_ctx) {
1118                 ERR("calloc() Fail(%d)", errno);
1119                 return OC_EH_ERROR;
1120         }
1121
1122         tizen_info_ctx->request_h = request->requestHandle;
1123         tizen_info_ctx->resource_h = request->resource;
1124
1125         ret = _ocprocess_worker_start(_worker_tizen_info_handler, tizen_info_ctx);
1126         if (IOTCON_ERROR_NONE != ret) {
1127                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
1128                 free(tizen_info_ctx);
1129                 return OC_EH_ERROR;
1130         }
1131
1132         return OC_EH_OK;
1133 }
1134
1135
1136 OCStackApplicationResult icd_ioty_ocprocess_get_tizen_info_cb(void *ctx,
1137                 OCDoHandle handle, OCClientResponse *resp)
1138 {
1139         int res;
1140         char *device_name;
1141         char *tizen_device_id;
1142         GVariant *tizen_info;
1143         OCRepPayload *payload;
1144         OCRepPayloadValue *val;
1145
1146         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
1147
1148         if (NULL == resp->payload) {
1149                 ERR("payload is empty");
1150                 icd_ioty_complete_error(ICD_TIZEN_INFO, ctx, IOTCON_ERROR_IOTIVITY);
1151                 return OC_STACK_DELETE_TRANSACTION;
1152         }
1153
1154         payload = (OCRepPayload*)resp->payload;
1155         val = payload->values;
1156         if (NULL == val) {
1157                 ERR("Invalid payload");
1158                 icd_ioty_complete_error(ICD_TIZEN_INFO, ctx, IOTCON_ERROR_IOTIVITY);
1159                 return OC_STACK_DELETE_TRANSACTION;
1160         }
1161         device_name = val->str;
1162
1163         val = val->next;
1164         if (NULL == val) {
1165                 ERR("Invalid Payload");
1166                 icd_ioty_complete_error(ICD_TIZEN_INFO, ctx, IOTCON_ERROR_IOTIVITY);
1167                 return OC_STACK_DELETE_TRANSACTION;
1168         }
1169
1170         tizen_device_id = val->str;
1171
1172         if (OC_STACK_OK == resp->result)
1173                 res = IOTCON_RESPONSE_RESULT_OK;
1174         else
1175                 res = IOTCON_RESPONSE_RESULT_ERROR;
1176
1177         tizen_info = g_variant_new("(ssi)", device_name, tizen_device_id, res);
1178
1179         icd_ioty_complete(ICD_TIZEN_INFO, ctx, tizen_info);
1180
1181         return OC_STACK_DELETE_TRANSACTION;
1182 }