fix prevent 482199 ~ 488631
[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_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->bus_name);
333                 free(req_ctx);
334                 return OC_EH_ERROR;
335         }
336         memcpy(dev_addr, &request->devAddr, sizeof(OCDevAddr));
337         req_ctx->dev_addr = dev_addr;
338
339         /* request type */
340         if (OC_REQUEST_FLAG & flag) {
341                 switch (request->method) {
342                 case OC_REST_GET:
343                         req_ctx->request_type = IOTCON_REQUEST_GET;
344                         req_ctx->payload = NULL;
345                         break;
346                 case OC_REST_PUT:
347                         req_ctx->request_type = IOTCON_REQUEST_PUT;
348                         req_ctx->payload = icd_payload_to_gvariant(request->payload);
349                         break;
350                 case OC_REST_POST:
351                         req_ctx->request_type = IOTCON_REQUEST_POST;
352                         req_ctx->payload = icd_payload_to_gvariant(request->payload);
353                         break;
354                 case OC_REST_DELETE:
355                         req_ctx->request_type = IOTCON_REQUEST_DELETE;
356                         req_ctx->payload = NULL;
357                         break;
358                 default:
359                         free(req_ctx->dev_addr);
360                         free(req_ctx->bus_name);
361                         free(req_ctx);
362                         return OC_EH_ERROR;
363                 }
364         }
365
366         if (OC_OBSERVE_FLAG & flag) {
367                 /* observation info*/
368                 req_ctx->observe_id = request->obsInfo.obsId;
369                 req_ctx->observe_type = _ioty_oic_action_to_ioty_action(request->obsInfo.action);
370         } else {
371                 req_ctx->observe_type = IOTCON_OBSERVE_TYPE_NONE;
372         }
373
374         /* header options */
375         req_ctx->options = _ocprocess_parse_header_options(
376                         request->rcvdVendorSpecificHeaderOptions,
377                         request->numRcvdVendorSpecificHeaderOptions);
378
379         /* query */
380         req_ctx->query = g_variant_builder_new(G_VARIANT_TYPE("a(ss)"));
381         query_str = request->query;
382         while ((token = strtok_r(query_str, "&;", &save_ptr1))) {
383                 while ((query_key = strtok_r(token, "=", &save_ptr2))) {
384                         token = NULL;
385                         query_value = strtok_r(token, "=", &save_ptr2);
386                         if (NULL == query_value)
387                                 break;
388
389                         g_variant_builder_add(req_ctx->query, "(ss)", query_key, query_value);
390                 }
391                 query_str = NULL;
392         }
393
394         ret = _ocprocess_worker_start(_worker_req_handler, req_ctx);
395         if (IOTCON_ERROR_NONE != ret) {
396                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
397                 _icd_req_context_free(req_ctx);
398                 return OC_EH_ERROR;
399         }
400
401         /* DO NOT FREE req_ctx. It MUST be freed in the _worker_req_handler func */
402
403         return OC_EH_OK;
404 }
405
406
407 gpointer icd_ioty_ocprocess_thread(gpointer data)
408 {
409         FN_CALL;
410         OCStackResult result;
411         const struct timespec delay = {0, 10 * 1000 * 1000}; /* 10 ms */
412
413         icd_ioty_alive = 1;
414         while (icd_ioty_alive) {
415                 icd_ioty_csdk_lock();
416                 result = OCProcess();
417                 icd_ioty_csdk_unlock();
418                 if (OC_STACK_OK != result) {
419                         ERR("OCProcess() Fail(%d)", result);
420                         break;
421                 }
422
423                 /* TODO : Current '10ms' is not proven sleep time. Revise the time after test.
424                  * Or recommend changes to event driven architecture */
425                 nanosleep(&delay, NULL);
426         }
427
428         return NULL;
429 }
430
431
432 static int _worker_find_cb(void *context)
433 {
434         GVariant *value;
435         int i, ret;
436         struct icd_find_context *ctx = context;
437
438         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
439
440         for (i = 0; ctx->payload[i]; i++) {
441                 value = g_variant_new("(vi)", ctx->payload[i], ctx->conn_type);
442                 /* TODO : If one device has multi resources, it comes as bulk data.
443                  * To reduce the number of emit_signal, let's send signal only one time for one device.
444                  * for ex, client list. */
445                 ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_FOUND_RESOURCE,
446                                 ctx->signal_number, value);
447                 if (IOTCON_ERROR_NONE != ret) {
448                         ERR("_ocprocess_response_signal() Fail(%d)", ret);
449                         g_variant_unref(value);
450                         return ret;
451                 }
452         }
453
454         /* ctx was allocated from icd_ioty_ocprocess_find_cb() */
455         free(ctx->bus_name);
456         free(ctx);
457
458         return ret;
459 }
460
461
462 OCStackApplicationResult icd_ioty_ocprocess_find_cb(void *ctx, OCDoHandle handle,
463                 OCClientResponse *resp)
464 {
465         int ret;
466         struct icd_find_context *find_ctx;
467         icd_sig_ctx_s *sig_context = ctx;
468
469         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
470         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
471         if (NULL == resp->payload)
472                 /* normal case : payload COULD be NULL */
473                 return OC_STACK_KEEP_TRANSACTION;
474         RETVM_IF(PAYLOAD_TYPE_DISCOVERY != resp->payload->type,
475                         OC_STACK_KEEP_TRANSACTION, "Invalid payload type(%d)", resp->payload->type);
476
477         find_ctx = calloc(1, sizeof(struct icd_find_context));
478         if (NULL == find_ctx) {
479                 ERR("calloc() Fail(%d)", errno);
480                 return OC_STACK_KEEP_TRANSACTION;
481         }
482
483         find_ctx->signal_number = sig_context->signal_number;
484         find_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
485         find_ctx->payload = icd_payload_res_to_gvariant(resp->payload, &resp->devAddr);
486         find_ctx->conn_type = icd_ioty_transport_flag_to_conn_type(resp->devAddr.adapter,
487                         resp->devAddr.flags);
488
489         ret = _ocprocess_worker_start(_worker_find_cb, find_ctx);
490         if (IOTCON_ERROR_NONE != ret) {
491                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
492                 free(find_ctx->bus_name);
493                 ic_utils_gvariant_array_free(find_ctx->payload);
494                 free(find_ctx);
495                 return OC_STACK_KEEP_TRANSACTION;
496         }
497
498         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
499         /* DO NOT FREE find_ctx. It MUST be freed in the _worker_find_cb func */
500
501         return OC_STACK_KEEP_TRANSACTION;
502 }
503
504
505 static int _worker_crud_cb(void *context)
506 {
507         GVariant *value;
508         struct icd_crud_context *ctx = context;
509
510         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
511
512         if (ICD_CRUD_DELETE == ctx->crud_type)
513                 value = g_variant_new("(a(qs)i)", ctx->options, ctx->res);
514         else
515                 value = g_variant_new("(a(qs)vi)", ctx->options, ctx->payload, ctx->res);
516         icd_ioty_complete(ctx->crud_type, ctx->invocation, value);
517
518         /* ctx was allocated from icd_ioty_ocprocess_xxx_cb() */
519         g_variant_builder_unref(ctx->options);
520         free(ctx);
521
522         return IOTCON_ERROR_NONE;
523 }
524
525
526 static int _worker_info_cb(void *context)
527 {
528         int ret;
529         const char *signal_prefix = NULL;
530         struct icd_info_context *ctx = context;
531
532         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
533
534         if (ICD_DEVICE_INFO == ctx->info_type)
535                 signal_prefix = IC_DBUS_SIGNAL_DEVICE;
536         else if (ICD_PLATFORM_INFO == ctx->info_type)
537                 signal_prefix = IC_DBUS_SIGNAL_PLATFORM;
538
539         ret = _ocprocess_response_signal(ctx->bus_name, signal_prefix, ctx->signal_number,
540                         ctx->payload);
541         if (IOTCON_ERROR_NONE != ret)
542                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
543
544         /* ctx was allocated from icd_ioty_ocprocess_info_cb() */
545         free(ctx->bus_name);
546         free(ctx);
547
548         return ret;
549 }
550
551
552 static int _ocprocess_worker(_ocprocess_cb cb, int type, OCPayload *payload, int res,
553                 GVariantBuilder *options, void *ctx)
554 {
555         int ret;
556         struct icd_crud_context *crud_ctx;
557
558         crud_ctx = calloc(1, sizeof(struct icd_crud_context));
559         if (NULL == crud_ctx) {
560                 ERR("calloc() Fail(%d)", errno);
561                 return IOTCON_ERROR_OUT_OF_MEMORY;
562         }
563
564         crud_ctx->crud_type = type;
565         crud_ctx->payload = icd_payload_to_gvariant(payload);
566         crud_ctx->res = res;
567         crud_ctx->options = options;
568         crud_ctx->invocation = ctx;
569
570         ret = _ocprocess_worker_start(cb, crud_ctx);
571         if (IOTCON_ERROR_NONE != ret) {
572                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
573                 if (crud_ctx->payload)
574                         g_variant_unref(crud_ctx->payload);
575                 g_variant_builder_unref(crud_ctx->options);
576                 free(crud_ctx);
577         }
578
579         /* DO NOT FREE crud_ctx. It MUST be freed in the _worker_crud_cb func */
580
581         return ret;
582 }
583
584 static int _ocprocess_parse_oic_result(OCStackResult result)
585 {
586         int res;
587
588         switch (result) {
589         case OC_STACK_OK:
590                 res = IOTCON_RESPONSE_RESULT_OK;
591                 break;
592         case OC_STACK_RESOURCE_CREATED:
593                 res = IOTCON_RESPONSE_RESULT_RESOURCE_CREATED;
594                 break;
595         case OC_STACK_RESOURCE_DELETED:
596                 res = IOTCON_RESPONSE_RESULT_RESOURCE_DELETED;
597                 break;
598         case OC_STACK_UNAUTHORIZED_REQ:
599                 res = IOTCON_RESPONSE_RESULT_FORBIDDEN;
600                 break;
601         default:
602                 WARN("response error(%d)", result);
603                 res = IOTCON_RESPONSE_RESULT_ERROR;
604                 break;
605         }
606
607         return res;
608 }
609
610
611 OCStackApplicationResult icd_ioty_ocprocess_get_cb(void *ctx, OCDoHandle handle,
612                 OCClientResponse *resp)
613 {
614         FN_CALL;
615         int ret, res;
616         GVariantBuilder *options;
617
618         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
619
620         if (NULL == resp->payload) {
621                 ERR("payload is empty");
622                 icd_ioty_complete_error(ICD_CRUD_GET, ctx, IOTCON_ERROR_IOTIVITY);
623                 return OC_STACK_DELETE_TRANSACTION;
624         }
625
626         res = _ocprocess_parse_oic_result(resp->result);
627
628         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
629                         resp->numRcvdVendorSpecificHeaderOptions);
630
631         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_GET, resp->payload, res,
632                         options, ctx);
633         if (IOTCON_ERROR_NONE != ret) {
634                 ERR("_ocprocess_worker() Fail(%d)", ret);
635                 icd_ioty_complete_error(ICD_CRUD_GET, ctx, ret);
636                 return OC_STACK_DELETE_TRANSACTION;
637         }
638
639         return OC_STACK_DELETE_TRANSACTION;
640 }
641
642
643 OCStackApplicationResult icd_ioty_ocprocess_put_cb(void *ctx, OCDoHandle handle,
644                 OCClientResponse *resp)
645 {
646         FN_CALL;
647         int ret, res;
648         GVariantBuilder *options;
649
650         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
651
652         if (NULL == resp->payload) {
653                 ERR("payload is empty");
654                 icd_ioty_complete_error(ICD_CRUD_PUT, ctx, IOTCON_ERROR_IOTIVITY);
655                 return OC_STACK_DELETE_TRANSACTION;
656         }
657
658         res = _ocprocess_parse_oic_result(resp->result);
659
660         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
661                         resp->numRcvdVendorSpecificHeaderOptions);
662
663         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_PUT, resp->payload, res,
664                         options, ctx);
665         if (IOTCON_ERROR_NONE != ret) {
666                 ERR("_ocprocess_worker() Fail(%d)", ret);
667                 icd_ioty_complete_error(ICD_CRUD_PUT, ctx, ret);
668                 return OC_STACK_DELETE_TRANSACTION;
669         }
670
671         return OC_STACK_DELETE_TRANSACTION;
672 }
673
674
675 OCStackApplicationResult icd_ioty_ocprocess_post_cb(void *ctx, OCDoHandle handle,
676                 OCClientResponse *resp)
677 {
678         FN_CALL;
679         int ret, res;
680         GVariantBuilder *options;
681
682         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
683
684         if (NULL == resp->payload) {
685                 ERR("payload is empty");
686                 icd_ioty_complete_error(ICD_CRUD_POST, ctx, IOTCON_ERROR_IOTIVITY);
687                 return OC_STACK_DELETE_TRANSACTION;
688         }
689
690         res = _ocprocess_parse_oic_result(resp->result);
691
692         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
693                         resp->numRcvdVendorSpecificHeaderOptions);
694
695         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_POST, resp->payload, res,
696                         options, ctx);
697         if (IOTCON_ERROR_NONE != ret) {
698                 ERR("_ocprocess_worker() Fail(%d)", ret);
699                 icd_ioty_complete_error(ICD_CRUD_POST, ctx, ret);
700                 return OC_STACK_DELETE_TRANSACTION;
701         }
702
703         return OC_STACK_DELETE_TRANSACTION;
704 }
705
706
707 OCStackApplicationResult icd_ioty_ocprocess_delete_cb(void *ctx, OCDoHandle handle,
708                 OCClientResponse *resp)
709 {
710         FN_CALL;
711         int ret, res;
712         GVariantBuilder *options;
713
714         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
715
716         if (NULL == resp->payload) {
717                 ERR("payload is empty");
718                 icd_ioty_complete_error(ICD_CRUD_DELETE, ctx, IOTCON_ERROR_IOTIVITY);
719                 return OC_STACK_DELETE_TRANSACTION;
720         }
721
722         res = _ocprocess_parse_oic_result(resp->result);
723
724         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
725                         resp->numRcvdVendorSpecificHeaderOptions);
726
727         ret = _ocprocess_worker(_worker_crud_cb, ICD_CRUD_DELETE, NULL, res, options, ctx);
728         if (IOTCON_ERROR_NONE != ret) {
729                 ERR("_ocprocess_worker() Fail(%d)", ret);
730                 icd_ioty_complete_error(ICD_CRUD_DELETE, ctx, ret);
731                 return OC_STACK_DELETE_TRANSACTION;
732         }
733
734         return OC_STACK_DELETE_TRANSACTION;
735 }
736
737
738 static int _worker_observe_cb(void *context)
739 {
740         int ret;
741         GVariant *value;
742         struct icd_observe_context *ctx = context;
743
744         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
745
746         value = g_variant_new("(a(qs)vii)", ctx->options, ctx->payload, ctx->res,
747                         ctx->seqnum);
748
749         ret = _ocprocess_response_signal(ctx->bus_name, IC_DBUS_SIGNAL_OBSERVE,
750                         ctx->signal_number, value);
751         if (IOTCON_ERROR_NONE != ret)
752                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
753
754         /* ctx was allocated from icd_ioty_ocprocess_observe_cb() */
755         free(ctx->bus_name);
756         g_variant_builder_unref(ctx->options);
757         free(ctx);
758
759         return ret;
760 }
761
762
763 static void _observe_cb_response_error(const char *dest,
764                 int64_t signal_number, int ret_val)
765 {
766         int ret;
767         GVariant *value;
768         GVariant *payload;
769         GVariantBuilder options;
770
771         g_variant_builder_init(&options, G_VARIANT_TYPE("a(qs)"));
772         payload = icd_payload_representation_empty_gvariant();
773
774         value = g_variant_new("(a(qs)vii)", &options, payload, ret_val, 0);
775
776         ret = _ocprocess_response_signal(dest, IC_DBUS_SIGNAL_OBSERVE, signal_number, value);
777         if (IOTCON_ERROR_NONE != ret)
778                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
779 }
780
781
782 OCStackApplicationResult icd_ioty_ocprocess_observe_cb(void *ctx,
783                 OCDoHandle handle, OCClientResponse *resp)
784 {
785         int ret, res;
786         GVariantBuilder *options;
787         struct icd_observe_context *observe_ctx;
788         icd_sig_ctx_s *sig_context = ctx;
789
790         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
791
792         if (NULL == resp->payload) {
793                 ERR("payload is empty");
794                 _observe_cb_response_error(sig_context->bus_name, sig_context->signal_number,
795                                 IOTCON_ERROR_IOTIVITY);
796                 return OC_STACK_KEEP_TRANSACTION;
797         }
798
799         observe_ctx = calloc(1, sizeof(struct icd_observe_context));
800         if (NULL == observe_ctx) {
801                 ERR("calloc() Fail(%d)", errno);
802                 _observe_cb_response_error(sig_context->bus_name, sig_context->signal_number,
803                                 IOTCON_ERROR_OUT_OF_MEMORY);
804                 return OC_STACK_KEEP_TRANSACTION;
805         }
806
807         res = _ocprocess_parse_oic_result(resp->result);
808
809         options = _ocprocess_parse_header_options(resp->rcvdVendorSpecificHeaderOptions,
810                         resp->numRcvdVendorSpecificHeaderOptions);
811
812         observe_ctx->payload = icd_payload_to_gvariant(resp->payload);
813         observe_ctx->signal_number = sig_context->signal_number;
814         observe_ctx->res = res;
815         observe_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
816         observe_ctx->options = options;
817
818         ret = _ocprocess_worker_start(_worker_observe_cb, observe_ctx);
819         if (IOTCON_ERROR_NONE != ret) {
820                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
821                 _observe_cb_response_error(sig_context->bus_name, sig_context->signal_number, ret);
822                 free(observe_ctx->bus_name);
823                 if (observe_ctx->payload)
824                         g_variant_unref(observe_ctx->payload);
825                 g_variant_builder_unref(observe_ctx->options);
826                 free(observe_ctx);
827                 return OC_STACK_KEEP_TRANSACTION;
828         }
829
830         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
831         /* DO NOT FREE observe_ctx. It MUST be freed in the _worker_observe_cb func */
832
833         return OC_STACK_KEEP_TRANSACTION;
834 }
835
836
837 static int _worker_presence_cb(void *context)
838 {
839         int conn_type;
840         OCDoHandle handle;
841         char *host_address;
842         GVariant *value, *value2;
843         int ret = IOTCON_ERROR_NONE;
844         struct icd_presence_context *ctx = context;
845
846         RETV_IF(NULL == ctx, IOTCON_ERROR_INVALID_PARAMETER);
847
848         ret = icd_ioty_get_host_address(ctx->dev_addr, &host_address, &conn_type);
849         if (IOTCON_ERROR_NONE != ret) {
850                 ERR("icd_ioty_get_host_address() Fail(%d)", ret);
851                 free(ctx->resource_type);
852                 free(ctx->dev_addr);
853                 free(ctx);
854                 return ret;
855         }
856
857         value = g_variant_new("(iusiis)", ctx->result, ctx->nonce, host_address, conn_type,
858                         ctx->trigger, ic_utils_dbus_encode_str(ctx->resource_type));
859         value2 = g_variant_ref(value);
860
861         free(host_address);
862
863         ret = _ocprocess_response_signal(NULL, IC_DBUS_SIGNAL_PRESENCE,
864                         ICD_POINTER_TO_INT64(ctx->handle), value);
865         if (IOTCON_ERROR_NONE != ret)
866                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
867
868         handle = icd_ioty_presence_table_get_handle(ICD_MULTICAST_ADDRESS);
869         if (handle && (handle != ctx->handle)) {
870                 ret = _ocprocess_response_signal(NULL, IC_DBUS_SIGNAL_PRESENCE,
871                                 ICD_POINTER_TO_INT64(handle), value2);
872                 if (IOTCON_ERROR_NONE != ret)
873                         ERR("_ocprocess_response_signal() Fail(%d)", ret);
874         } else {
875                 g_variant_unref(value2);
876         }
877
878         /* ctx was allocated from icd_ioty_ocprocess_presence_cb() */
879         free(ctx->resource_type);
880         free(ctx->dev_addr);
881         free(ctx);
882
883         return ret;
884 }
885
886
887 static void _presence_cb_response_error(OCDoHandle handle, int ret_val)
888 {
889         FN_CALL;
890         int ret;
891         OCDoHandle handle2;
892         GVariant *value, *value2;
893
894         value = g_variant_new("(iusiis)", ret_val, 0, IC_STR_NULL, IOTCON_CONNECTIVITY_ALL,
895                         IOTCON_PRESENCE_TRIGGER_RESOURCE_CREATED, IC_STR_NULL);
896         value2 = g_variant_ref(value);
897
898         ret = _ocprocess_response_signal(NULL, IC_DBUS_SIGNAL_PRESENCE,
899                         ICD_POINTER_TO_INT64(handle), value);
900         if (IOTCON_ERROR_NONE != ret)
901                 ERR("_ocprocess_response_signal() Fail(%d)", ret);
902
903         handle2 = icd_ioty_presence_table_get_handle(ICD_MULTICAST_ADDRESS);
904         if (handle2 && (handle2 != handle)) {
905                 ret = _ocprocess_response_signal(NULL, IC_DBUS_SIGNAL_PRESENCE,
906                                 ICD_POINTER_TO_INT64(handle), value2);
907                 if (IOTCON_ERROR_NONE != ret)
908                         ERR("_ocprocess_response_signal() Fail(%d)", ret);
909         } else {
910                 g_variant_unref(value2);
911         }
912 }
913
914
915 static int _presence_trigger_to_ioty_trigger(OCPresenceTrigger src,
916                 iotcon_presence_trigger_e *dest)
917 {
918         RETV_IF(NULL == dest, IOTCON_ERROR_INVALID_PARAMETER);
919
920         switch (src) {
921         case OC_PRESENCE_TRIGGER_CREATE:
922                 *dest = IOTCON_PRESENCE_TRIGGER_RESOURCE_CREATED;
923                 break;
924         case OC_PRESENCE_TRIGGER_CHANGE:
925                 *dest = IOTCON_PRESENCE_TRIGGER_RESOURCE_UPDATED;
926                 break;
927         case OC_PRESENCE_TRIGGER_DELETE:
928                 *dest = IOTCON_PRESENCE_TRIGGER_RESOURCE_DESTROYED;
929                 break;
930         default:
931                 ERR("Invalid trigger(%d)", src);
932                 return IOTCON_ERROR_INVALID_PARAMETER;
933         }
934
935         return IOTCON_ERROR_NONE;
936 }
937
938
939 OCStackApplicationResult icd_ioty_ocprocess_presence_cb(void *ctx, OCDoHandle handle,
940                 OCClientResponse *resp)
941 {
942         FN_CALL;
943         int ret;
944         OCDevAddr *dev_addr;
945         OCPresencePayload *payload;
946         struct icd_presence_context *presence_ctx;
947
948         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
949
950         presence_ctx = calloc(1, sizeof(struct icd_presence_context));
951         if (NULL == presence_ctx) {
952                 ERR("calloc() Fail(%d)", errno);
953                 _presence_cb_response_error(handle, IOTCON_ERROR_OUT_OF_MEMORY);
954                 return OC_STACK_KEEP_TRANSACTION;
955         }
956
957         dev_addr = calloc(1, sizeof(OCDevAddr));
958         if (NULL == dev_addr) {
959                 ERR("calloc() Fail(%d)", errno);
960                 _presence_cb_response_error(handle, IOTCON_ERROR_OUT_OF_MEMORY);
961                 free(presence_ctx);
962                 return OC_STACK_KEEP_TRANSACTION;
963         }
964         memcpy(dev_addr, &resp->devAddr, sizeof(OCDevAddr));
965
966         payload = (OCPresencePayload*)resp->payload;
967
968         switch (resp->result) {
969         case OC_STACK_OK:
970                 presence_ctx->result = IOTCON_PRESENCE_OK;
971                 ret = _presence_trigger_to_ioty_trigger(payload->trigger, &presence_ctx->trigger);
972                 if (IOTCON_ERROR_NONE != ret) {
973                         ERR("_presence_trigger_to_ioty_trigger() Fail(%d)", ret);
974                         _presence_cb_response_error(handle, ret);
975                         free(presence_ctx);
976                         return OC_STACK_KEEP_TRANSACTION;
977                 }
978                 break;
979         case OC_STACK_PRESENCE_STOPPED:
980                 presence_ctx->result = IOTCON_PRESENCE_STOPPED;
981                 break;
982         case OC_STACK_PRESENCE_TIMEOUT:
983                 presence_ctx->result = IOTCON_PRESENCE_TIMEOUT;
984                 break;
985         case OC_STACK_ERROR:
986         default:
987                 DBG("Presence error(%d)", resp->result);
988                 presence_ctx->result = IOTCON_ERROR_IOTIVITY;
989         }
990
991         presence_ctx->handle = handle;
992         presence_ctx->nonce = resp->sequenceNumber;
993         presence_ctx->dev_addr = dev_addr;
994
995         if (payload->resourceType)
996                 presence_ctx->resource_type = strdup(payload->resourceType);
997
998         ret = _ocprocess_worker_start(_worker_presence_cb, presence_ctx);
999         if (IOTCON_ERROR_NONE != ret) {
1000                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
1001                 _presence_cb_response_error(handle, ret);
1002                 free(presence_ctx->resource_type);
1003                 free(presence_ctx->dev_addr);
1004                 free(presence_ctx);
1005                 return OC_STACK_KEEP_TRANSACTION;
1006         }
1007
1008         /* DO NOT FREE presence_ctx. It MUST be freed in the _worker_presence_cb func */
1009
1010         return OC_STACK_KEEP_TRANSACTION;
1011 }
1012
1013
1014 OCStackApplicationResult icd_ioty_ocprocess_info_cb(void *ctx, OCDoHandle handle,
1015                 OCClientResponse *resp)
1016 {
1017         int ret;
1018         int info_type;
1019         struct icd_info_context *info_ctx;
1020         icd_sig_ctx_s *sig_context = ctx;
1021
1022         RETV_IF(NULL == ctx, OC_STACK_KEEP_TRANSACTION);
1023         RETV_IF(NULL == resp, OC_STACK_KEEP_TRANSACTION);
1024         RETV_IF(NULL == resp->payload, OC_STACK_KEEP_TRANSACTION);
1025
1026         if (PAYLOAD_TYPE_DEVICE == resp->payload->type)
1027                 info_type = ICD_DEVICE_INFO;
1028         else if (PAYLOAD_TYPE_PLATFORM == resp->payload->type)
1029                 info_type = ICD_PLATFORM_INFO;
1030         else
1031                 return OC_STACK_KEEP_TRANSACTION;
1032
1033         info_ctx = calloc(1, sizeof(struct icd_info_context));
1034         if (NULL == info_ctx) {
1035                 ERR("calloc() Fail(%d)", errno);
1036                 return OC_STACK_KEEP_TRANSACTION;
1037         }
1038
1039         info_ctx->info_type = info_type;
1040         info_ctx->payload = icd_payload_to_gvariant(resp->payload);
1041         info_ctx->signal_number = sig_context->signal_number;
1042         info_ctx->bus_name = ic_utils_strdup(sig_context->bus_name);
1043
1044         ret = _ocprocess_worker_start(_worker_info_cb, info_ctx);
1045         if (IOTCON_ERROR_NONE != ret) {
1046                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
1047                 free(info_ctx->bus_name);
1048                 if (info_ctx->payload)
1049                         g_variant_unref(info_ctx->payload);
1050                 free(info_ctx);
1051                 return OC_STACK_KEEP_TRANSACTION;
1052         }
1053
1054         /* DO NOT FREE sig_context. It MUST be freed in the ocstack */
1055         /* DO NOT FREE info_ctx. It MUST be freed in the _worker_info_cb func */
1056
1057         return OC_STACK_KEEP_TRANSACTION;
1058 }
1059
1060
1061 static int _worker_tizen_info_handler(void *context)
1062 {
1063         int ret;
1064         char *device_name;
1065         char *tizen_device_id;
1066         OCStackResult result;
1067         OCRepPayload *payload;
1068         OCEntityHandlerResponse response = {0};
1069         struct icd_tizen_info_context *ctx = context;
1070
1071         response.requestHandle = ctx->request_h;
1072         response.resourceHandle = ctx->resource_h;
1073         response.ehResult = OC_EH_OK;
1074
1075         /* Get Tizen Info */
1076         ret = icd_ioty_tizen_info_get_property(&device_name, &tizen_device_id);
1077         if (IOTCON_ERROR_NONE != ret) {
1078                 ERR("icd_ioty_tizen_info_get_property() Fail(%d)", ret);
1079                 response.ehResult = OC_EH_ERROR;
1080         }
1081
1082         /* payload */
1083         payload = OCRepPayloadCreate();
1084         OCRepPayloadSetUri(payload, ICD_IOTY_TIZEN_INFO_URI);
1085         OCRepPayloadAddResourceType(payload, ICD_IOTY_TIZEN_INFO_TYPE);
1086         OCRepPayloadAddInterface(payload, IC_INTERFACE_DEFAULT);
1087
1088         OCRepPayloadSetPropString(payload, ICD_IOTY_TIZEN_INFO_DEVICE_NAME,
1089                         ic_utils_dbus_encode_str(device_name));
1090         OCRepPayloadSetPropString(payload, ICD_IOTY_TIZEN_INFO_TIZEN_DEVICE_ID,
1091                         ic_utils_dbus_encode_str(tizen_device_id));
1092         response.payload = (OCPayload*)payload;
1093
1094         icd_ioty_csdk_lock();
1095         result = OCDoResponse(&response);
1096         icd_ioty_csdk_unlock();
1097
1098         if (OC_STACK_OK != result) {
1099                 ERR("OCDoResponse() Fail(%d)", result);
1100                 free(ctx);
1101                 return IOTCON_ERROR_IOTIVITY;
1102         }
1103
1104         free(ctx);
1105         return IOTCON_ERROR_NONE;
1106 }
1107
1108
1109 OCEntityHandlerResult icd_ioty_ocprocess_tizen_info_handler(OCEntityHandlerFlag flag,
1110                 OCEntityHandlerRequest *request, void *user_data)
1111 {
1112         int ret;
1113         struct icd_tizen_info_context *tizen_info_ctx;
1114
1115         if ((0 == (OC_REQUEST_FLAG & flag)) || (OC_REST_GET != request->method)) {
1116                 ERR("Prohibited Action");
1117                 return OC_EH_FORBIDDEN;
1118         }
1119
1120         tizen_info_ctx = calloc(1, sizeof(struct icd_tizen_info_context));
1121         if (NULL == tizen_info_ctx) {
1122                 ERR("calloc() Fail(%d)", errno);
1123                 return OC_EH_ERROR;
1124         }
1125
1126         tizen_info_ctx->request_h = request->requestHandle;
1127         tizen_info_ctx->resource_h = request->resource;
1128
1129         ret = _ocprocess_worker_start(_worker_tizen_info_handler, tizen_info_ctx);
1130         if (IOTCON_ERROR_NONE != ret) {
1131                 ERR("_ocprocess_worker_start() Fail(%d)", ret);
1132                 free(tizen_info_ctx);
1133                 return OC_EH_ERROR;
1134         }
1135
1136         return OC_EH_OK;
1137 }
1138
1139
1140 OCStackApplicationResult icd_ioty_ocprocess_get_tizen_info_cb(void *ctx,
1141                 OCDoHandle handle, OCClientResponse *resp)
1142 {
1143         int res;
1144         char *device_name;
1145         char *tizen_device_id;
1146         GVariant *tizen_info;
1147         OCRepPayload *payload;
1148         OCRepPayloadValue *val;
1149
1150         RETV_IF(NULL == ctx, OC_STACK_DELETE_TRANSACTION);
1151
1152         if (NULL == resp->payload) {
1153                 ERR("payload is empty");
1154                 icd_ioty_complete_error(ICD_TIZEN_INFO, ctx, IOTCON_ERROR_IOTIVITY);
1155                 return OC_STACK_DELETE_TRANSACTION;
1156         }
1157
1158         payload = (OCRepPayload*)resp->payload;
1159         val = payload->values;
1160         if (NULL == val) {
1161                 ERR("Invalid payload");
1162                 icd_ioty_complete_error(ICD_TIZEN_INFO, ctx, IOTCON_ERROR_IOTIVITY);
1163                 return OC_STACK_DELETE_TRANSACTION;
1164         }
1165         device_name = val->str;
1166
1167         val = val->next;
1168         if (NULL == val) {
1169                 ERR("Invalid Payload");
1170                 icd_ioty_complete_error(ICD_TIZEN_INFO, ctx, IOTCON_ERROR_IOTIVITY);
1171                 return OC_STACK_DELETE_TRANSACTION;
1172         }
1173
1174         tizen_device_id = val->str;
1175
1176         if (OC_STACK_OK == resp->result)
1177                 res = IOTCON_RESPONSE_RESULT_OK;
1178         else
1179                 res = IOTCON_RESPONSE_RESULT_ERROR;
1180
1181         tizen_info = g_variant_new("(ssi)", device_name, tizen_device_id, res);
1182
1183         icd_ioty_complete(ICD_TIZEN_INFO, ctx, tizen_info);
1184
1185         return OC_STACK_DELETE_TRANSACTION;
1186 }