Fix observe API (set_notify_cb -> observe_register)
[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_cb)(void *user_data);
37
38 struct icd_ioty_worker
39 {
40         void *ctx;
41         _ocprocess_cb cb;
42 };
43
44
45 struct icd_req_context {
46         unsigned int signal_number;
47         char *bus_name;
48         int request_type;
49         int observe_id;
50         int observe_type;
51         OCRequestHandle request_h;
52         OCResourceHandle resource_h;
53         GVariant *payload;
54         GVariantBuilder *options;
55         GVariantBuilder *query;
56         OCDevAddr *dev_addr;
57 };
58
59
60 struct icd_find_context {
61         unsigned int signal_number;
62         char *bus_name;
63         int conn_type;
64         GVariant **payload;
65 };
66
67
68 struct icd_crud_context {
69         int res;
70         int crud_type;
71         GVariant *payload;
72         GVariantBuilder *options;
73         GDBusMethodInvocation *invocation;
74 };
75
76
77 struct icd_info_context {
78         unsigned int signal_number;
79         int info_type;
80         char *bus_name;
81         GVariant *payload;
82 };
83
84
85 struct icd_tizen_info_context {
86         OCRequestHandle request_h;
87         OCResourceHandle resource_h;
88         GDBusMethodInvocation *invocation;
89 };
90
91
92 struct icd_observe_context {
93         unsigned int signal_number;
94         int res;
95         int seqnum;
96         char *bus_name;
97         GVariant *payload;
98         GVariantBuilder *options;
99 };
100
101
102 struct icd_presence_context {
103         unsigned int signal_number;
104         char *bus_name;
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                 unsigned int 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_%u", 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         unsigned int 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                 unsigned int 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         GVariant *value;
836         int ret, conn_type;
837         char *host_address;
838         struct icd_presence_context *ctx = context;
839
840         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
841
842         ret = icd_ioty_get_host_address(ctx->dev_addr, &host_address, &conn_type);
843         if (IOTCON_ERROR_NONE != ret) {
844                 ERR("icd_ioty_get_host_address() Fail(%d)", ret);
845                 free(ctx->resource_type);
846                 free(ctx->bus_name);
847                 free(ctx->dev_addr);
848                 free(ctx);
849                 return ret;
850         }
851
852         value = g_variant_new("(iusiis)", ctx->result, ctx->nonce, host_address, conn_type,
853                         ctx->trigger, ic_utils_dbus_encode_str(ctx->resource_type));
854
855         free(host_address);
856
857         ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_PRESENCE,
858                         ctx->signal_number, value);
859         if (IOTCON_ERROR_NONE != ret)
860                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
861
862         /* ctx was allocated from icd_ioty_ocprocess_presence_cb() */
863         free(ctx->resource_type);
864         free(ctx->bus_name);
865         free(ctx->dev_addr);
866         free(ctx);
867
868         return ret;
869 }
870
871
872 static void _presence_cb_response_error(const char *dest, unsigned int signal_number,
873                 int ret_val)
874 {
875         FN_CALL;
876         int ret;
877         GVariant *value;
878
879         value = g_variant_new("(iusiis)", ret_val, 0, IC_STR_NULL, IOTCON_CONNECTIVITY_ALL,
880                         IOTCON_PRESENCE_TRIGGER_RESOURCE_CREATED, IC_STR_NULL);
881
882         ret = _ocprocess_response_signal(dest, IC_DBUS_SIGNAL_PRESENCE, signal_number, value);
883         if (IOTCON_ERROR_NONE != ret)
884                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
885 }
886
887
888 static int _presence_trigger_to_ioty_trigger(OCPresenceTrigger src,
889                 iotcon_presence_trigger_e *dest)
890 {
891         RETV_IF(NULL == dest, IOTCON_ERROR_INVALID_PARAMETER);
892
893         switch (src) {
894         case OC_PRESENCE_TRIGGER_CREATE:
895                 *dest = IOTCON_PRESENCE_TRIGGER_RESOURCE_CREATED;
896                 break;
897         case OC_PRESENCE_TRIGGER_CHANGE:
898                 *dest = IOTCON_PRESENCE_TRIGGER_RESOURCE_UPDATED;
899                 break;
900         case OC_PRESENCE_TRIGGER_DELETE:
901                 *dest = IOTCON_PRESENCE_TRIGGER_RESOURCE_DESTROYED;
902                 break;
903         default:
904                 ERR("Invalid trigger(%d)", src);
905                 return IOTCON_ERROR_INVALID_PARAMETER;
906         }
907
908         return IOTCON_ERROR_NONE;
909 }
910
911
912 OCStackApplicationResult icd_ioty_ocprocess_presence_cb(void *ctx, OCDoHandle handle,
913                 OCClientResponse *resp)
914 {
915         FN_CALL;
916         int ret;
917         OCDevAddr *dev_addr;
918         OCPresencePayload *payload;
919         icd_sig_ctx_s *sig_context = ctx;
920         struct icd_presence_context *presence_ctx;
921
922         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
923         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
924
925         presence_ctx = calloc(1, sizeof(struct icd_presence_context));
926         if (NULL == presence_ctx) {
927                 ERR("calloc() Fail(%d)", errno);
928                 _presence_cb_response_error(sig_context->bus_name, sig_context->signal_number,
929                                 IOTCON_ERROR_OUT_OF_MEMORY);
930                 return OC_STACK_KEEP_TRANSACTION;
931         }
932
933         dev_addr = calloc(1, sizeof(OCDevAddr));
934         if (NULL == dev_addr) {
935                 ERR("calloc() Fail(%d)", errno);
936                 _presence_cb_response_error(sig_context->bus_name, sig_context->signal_number,
937                                 IOTCON_ERROR_OUT_OF_MEMORY);
938                 free(presence_ctx);
939                 return OC_STACK_KEEP_TRANSACTION;
940         }
941         memcpy(dev_addr, &resp->devAddr, sizeof(OCDevAddr));
942
943         payload = (OCPresencePayload*)resp->payload;
944
945         switch (resp->result) {
946         case OC_STACK_OK:
947                 presence_ctx->result = IOTCON_PRESENCE_OK;
948                 ret = _presence_trigger_to_ioty_trigger(payload->trigger, &presence_ctx->trigger);
949                 if (IOTCON_ERROR_NONE != ret) {
950                         ERR("_presence_trigger_to_ioty_trigger() Fail(%d)", ret);
951                         _presence_cb_response_error(sig_context->bus_name, sig_context->signal_number,
952                                         ret);
953                         free(presence_ctx);
954                         return OC_STACK_KEEP_TRANSACTION;
955                 }
956                 break;
957         case OC_STACK_PRESENCE_STOPPED:
958                 presence_ctx->result = IOTCON_PRESENCE_STOPPED;
959                 break;
960         case OC_STACK_PRESENCE_TIMEOUT:
961                 presence_ctx->result = IOTCON_PRESENCE_TIMEOUT;
962                 break;
963         case OC_STACK_ERROR:
964         default:
965                 DBG("Presence error(%d)", resp->result);
966                 presence_ctx->result = IOTCON_ERROR_IOTIVITY;
967         }
968
969         presence_ctx->signal_number = sig_context->signal_number;
970         presence_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
971         presence_ctx->nonce = resp->sequenceNumber;
972         presence_ctx->dev_addr = dev_addr;
973
974         if (payload->resourceType)
975                 presence_ctx->resource_type = strdup(payload->resourceType);
976
977         ret = _ocprocess_worker_start(_worker_presence_cb, presence_ctx);
978         if (IOTCON_ERROR_NONE != ret) {
979                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
980                 _presence_cb_response_error(sig_context->bus_name, sig_context->signal_number, ret);
981                 free(presence_ctx->resource_type);
982                 free(presence_ctx->bus_name);
983                 free(presence_ctx->dev_addr);
984                 free(presence_ctx);
985                 return OC_STACK_KEEP_TRANSACTION;
986         }
987
988         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
989         /* DO NOT FREE presence_ctx. It MUST be freed in the _worker_presence_cb func */
990
991         return OC_STACK_KEEP_TRANSACTION;
992 }
993
994
995 OCStackApplicationResult icd_ioty_ocprocess_info_cb(void *ctx, OCDoHandle handle,
996                 OCClientResponse *resp)
997 {
998         int ret;
999         int info_type;
1000         struct icd_info_context *info_ctx;
1001         icd_sig_ctx_s *sig_context = ctx;
1002
1003         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
1004         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
1005         RETV_IF(NULL == resp->payload, OC_STACK_KEEP_TRANSACTION);
1006
1007         if (PAYLOAD_TYPE_DEVICE == resp->payload->type)
1008                 info_type = ICD_DEVICE_INFO;
1009         else if (PAYLOAD_TYPE_PLATFORM == resp->payload->type)
1010                 info_type = ICD_PLATFORM_INFO;
1011         else
1012                 return OC_STACK_KEEP_TRANSACTION;
1013
1014         info_ctx = calloc(1, sizeof(struct icd_info_context));
1015         if (NULL == info_ctx) {
1016                 ERR("calloc() Fail(%d)", errno);
1017                 return OC_STACK_KEEP_TRANSACTION;
1018         }
1019
1020         info_ctx->info_type = info_type;
1021         info_ctx->payload = icd_payload_to_gvariant(resp->payload);
1022         info_ctx->signal_number = sig_context->signal_number;
1023         info_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
1024
1025         ret = _ocprocess_worker_start(_worker_info_cb, info_ctx);
1026         if (IOTCON_ERROR_NONE != ret) {
1027                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
1028                 free(info_ctx->bus_name);
1029                 if (info_ctx->payload)
1030                         g_variant_unref(info_ctx->payload);
1031                 free(info_ctx);
1032                 return OC_STACK_KEEP_TRANSACTION;
1033         }
1034
1035         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
1036         /* DO NOT FREE info_ctx. It MUST be freed in the _worker_info_cb func */
1037
1038         return OC_STACK_KEEP_TRANSACTION;
1039 }
1040
1041
1042 static int _worker_tizen_info_handler(void *context)
1043 {
1044         int ret;
1045         char *device_name;
1046         char *tizen_device_id;
1047         OCStackResult result;
1048         OCRepPayload *payload;
1049         OCEntityHandlerResponse response = {0};
1050         struct icd_tizen_info_context *ctx = context;
1051
1052         response.requestHandle = ctx->request_h;
1053         response.resourceHandle = ctx->resource_h;
1054         response.ehResult = OC_EH_OK;
1055
1056         /* Get Tizen Info */
1057         ret = icd_ioty_tizen_info_get_property(&device_name, &tizen_device_id);
1058         if (IOTCON_ERROR_NONE != ret) {
1059                 ERR("icd_ioty_tizen_info_get_property() Fail(%d)", ret);
1060                 response.ehResult = OC_EH_ERROR;
1061         }
1062
1063         /* payload */
1064         payload = OCRepPayloadCreate();
1065         OCRepPayloadSetUri(payload, ICD_IOTY_TIZEN_INFO_URI);
1066         OCRepPayloadAddResourceType(payload, ICD_IOTY_TIZEN_INFO_TYPE);
1067         OCRepPayloadAddInterface(payload, IC_INTERFACE_DEFAULT);
1068
1069         OCRepPayloadSetPropString(payload, ICD_IOTY_TIZEN_INFO_DEVICE_NAME,
1070                         ic_utils_dbus_encode_str(device_name));
1071         OCRepPayloadSetPropString(payload, ICD_IOTY_TIZEN_INFO_TIZEN_DEVICE_ID,
1072                         ic_utils_dbus_encode_str(tizen_device_id));
1073         response.payload = (OCPayload*)payload;
1074
1075         icd_ioty_csdk_lock();
1076         result = OCDoResponse(&response);
1077         icd_ioty_csdk_unlock();
1078
1079         if (OC_STACK_OK != result) {
1080                 ERR("OCDoResponse() Fail(%d)", result);
1081                 free(ctx);
1082                 return IOTCON_ERROR_IOTIVITY;
1083         }
1084
1085         free(ctx);
1086         return IOTCON_ERROR_NONE;
1087 }
1088
1089
1090 OCEntityHandlerResult icd_ioty_ocprocess_tizen_info_handler(OCEntityHandlerFlag flag,
1091                 OCEntityHandlerRequest *request, void *user_data)
1092 {
1093         int ret;
1094         struct icd_tizen_info_context *tizen_info_ctx;
1095
1096         if ((0 == (OC_REQUEST_FLAG & flag)) || (OC_REST_GET != request->method)) {
1097                 ERR("Prohibited Action");
1098                 return OC_EH_FORBIDDEN;
1099         }
1100
1101         tizen_info_ctx = calloc(1, sizeof(struct icd_tizen_info_context));
1102         if (NULL == tizen_info_ctx) {
1103                 ERR("calloc() Fail(%d)", errno);
1104                 return OC_EH_ERROR;
1105         }
1106
1107         tizen_info_ctx->request_h = request->requestHandle;
1108         tizen_info_ctx->resource_h = request->resource;
1109
1110         ret = _ocprocess_worker_start(_worker_tizen_info_handler, tizen_info_ctx);
1111         if (IOTCON_ERROR_NONE != ret) {
1112                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
1113                 free(tizen_info_ctx);
1114                 return OC_EH_ERROR;
1115         }
1116
1117         return OC_EH_OK;
1118 }
1119
1120
1121 OCStackApplicationResult icd_ioty_ocprocess_get_tizen_info_cb(void *ctx,
1122                 OCDoHandle handle, OCClientResponse *resp)
1123 {
1124         int res;
1125         char *device_name;
1126         char *tizen_device_id;
1127         GVariant *tizen_info;
1128         OCRepPayload *payload;
1129         OCRepPayloadValue *val;
1130
1131         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
1132
1133         if (NULL == resp->payload) {
1134                 ERR("payload is empty");
1135                 icd_ioty_complete_error(ICD_TIZEN_INFO, ctx, IOTCON_ERROR_IOTIVITY);
1136                 return OC_STACK_DELETE_TRANSACTION;
1137         }
1138
1139         payload = (OCRepPayload*)resp->payload;
1140         val = payload->values;
1141         if (NULL == val) {
1142                 ERR("Invalid payload");
1143                 icd_ioty_complete_error(ICD_TIZEN_INFO, ctx, IOTCON_ERROR_IOTIVITY);
1144                 return OC_STACK_DELETE_TRANSACTION;
1145         }
1146         device_name = val->str;
1147
1148         val = val->next;
1149         if (NULL == val) {
1150                 ERR("Invalid Payload");
1151                 icd_ioty_complete_error(ICD_TIZEN_INFO, ctx, IOTCON_ERROR_IOTIVITY);
1152                 return OC_STACK_DELETE_TRANSACTION;
1153         }
1154
1155         tizen_device_id = val->str;
1156
1157         if (OC_STACK_OK == resp->result)
1158                 res = IOTCON_RESPONSE_RESULT_OK;
1159         else
1160                 res = IOTCON_RESPONSE_RESULT_ERROR;
1161
1162         tizen_info = g_variant_new("(ssi)", device_name, tizen_device_id, res);
1163
1164         icd_ioty_complete(ICD_TIZEN_INFO, ctx, tizen_info);
1165
1166         return OC_STACK_DELETE_TRANSACTION;
1167 }