libamxs  0.6.0
Data Model Synchronization C API
amxs_util.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 
55 #ifndef _GNU_SOURCE
56 #define _GNU_SOURCE
57 #endif
58 
59 #include <stdlib.h>
60 #include <string.h>
61 
62 #include <amxc/amxc.h>
63 
64 #include <amxp/amxp.h>
65 
66 #include <amxd/amxd_object.h>
67 #include <amxd/amxd_path.h>
68 #include <amxd/amxd_transaction.h>
69 #include <amxd/amxd_dm.h>
70 
71 #include <amxs/amxs_types.h>
72 #include <amxs/amxs_util.h>
73 
74 #include "amxs_priv.h"
75 
77  amxs_sync_direction_t direction,
78  const char* path) {
79  bool ret = false;
80  amxc_var_t* opposite_list = NULL;
81  amxc_var_t* opposite = NULL;
83 
84  when_null(entry, exit);
85  when_null(ctx, exit);
86  when_str_empty(path, exit);
87  when_false(amxs_sync_entry_is_bidirectional(entry), exit);
88 
89  opposite_list = direction == amxs_sync_a_to_b ? &ctx->b_to_a : &ctx->a_to_b;
90  opposite = GET_ARG(opposite_list, path);
91 
92  if(opposite != NULL) {
93  amxc_var_delete(&opposite);
94  ret = true;
95  }
96 
97 exit:
98  return ret;
99 }
100 
102  amxs_sync_direction_t direction,
103  const char* path,
104  const char* opposite_path) {
105  bool ret = false;
106  amxd_path_t check_path;
107  amxc_var_t* opposite_list = NULL;
108  amxc_var_t* current_list = NULL;
109  amxc_var_t* opposite = NULL;
111 
112  amxd_path_init(&check_path, opposite_path);
113 
114  when_null(entry, exit);
115  when_null(ctx, exit);
116  when_str_empty(path, exit);
117  when_str_empty(opposite_path, exit);
118  when_false(amxs_sync_entry_is_bidirectional(entry), exit);
119 
120  opposite_list = direction == amxs_sync_a_to_b ? &ctx->b_to_a : &ctx->a_to_b;
121  current_list = direction == amxs_sync_a_to_b ? &ctx->a_to_b : &ctx->b_to_a;
122  opposite = GET_ARG(opposite_list, path);
123 
124  when_true(amxd_path_is_instance_path(&check_path), exit);
125 
126  if(opposite != NULL) {
127  amxc_var_delete(&opposite);
128  ret = true;
129  } else {
130  amxc_var_add_key(bool, current_list, opposite_path, true);
131  }
132 
133 exit:
134  amxd_path_clean(&check_path);
135  return ret;
136 }
137 
138 static bool amxs_sync_entry_check_bidirectional_param(amxc_var_t* list,
139  amxc_var_t* value) {
140  bool ret = false;
141 
142  when_null(list, exit);
143  when_null(value, exit);
144 
145  amxc_var_for_each(var, list) {
146  int count = 1;
147  int result = 0;
148 
149  if((amxc_var_compare(value, var, &result) == 0) && (result == 0)) {
150  amxc_var_for_each(var_rm, list) {
151  amxc_var_take_it(var_rm);
152  amxc_var_delete(&var_rm);
153  count--;
154  if(count == 0) {
155  break;
156  }
157  }
158  ret = true;
159  goto exit;
160  }
161  count++;
162  }
163 
164 exit:
165  return ret;
166 }
167 
169  amxs_sync_direction_t direction,
170  amxc_var_t* value,
171  const char* path,
172  const char* opposite_path) {
173  bool ret = false;
174  amxc_string_t str;
175  amxc_var_t* current_list = NULL;
176  amxc_var_t* opposite_list = NULL;
177  amxc_var_t* current_table = NULL;
178  amxc_var_t* opposite_table = NULL;
179  amxc_var_t* value_storage = NULL;
181 
182  amxc_string_init(&str, 0);
183 
184  when_null(entry, exit);
185  when_null(ctx, exit);
186  when_null(value, exit);
187  when_str_empty(path, exit);
188  when_str_empty(opposite_path, exit);
189  when_false(amxs_sync_entry_is_bidirectional(entry), exit);
190 
191  opposite_table = direction == amxs_sync_a_to_b ? &ctx->b_to_a : &ctx->a_to_b;
192  current_table = direction == amxs_sync_a_to_b ? &ctx->a_to_b : &ctx->b_to_a;
193 
194  // Find current path in opposite table
195  amxc_string_setf(&str, "%s%s", path, amxs_sync_entry_get_name(entry, direction));
196  opposite_list = GET_ARG(opposite_table, amxc_string_get(&str, 0));
197  if(opposite_list != NULL) {
198  // Entry found, do the regular loop detection for parameters
199  ret = amxs_sync_entry_check_bidirectional_param(opposite_list, value);
200  when_true(ret, exit);
201  }
202 
203  amxc_string_setf(&str, "%s%s", opposite_path, amxs_sync_entry_get_opposite_name(entry, direction));
204  current_list = GET_ARG(current_table, amxc_string_get(&str, 0));
205  if(current_list == NULL) {
206  // Add the opposite path to the current ctx htable
207  current_list = amxc_var_add_key(amxc_llist_t, current_table, amxc_string_get(&str, 0), NULL);
208  }
209 
210  // Add the current value to the current list
211  value_storage = amxc_var_add_new(current_list);
212  amxc_var_copy(value_storage, value);
213 
214 exit:
215  amxc_string_clean(&str);
216  return ret;
217 }
218 
220  bool ret = true;
221 
222  when_null(entry, exit);
223  if((entry->attributes & (AMXS_SYNC_ONLY_B_TO_A | AMXS_SYNC_ONLY_A_TO_B)) != 0) {
224  ret = false;
225  }
226 
227 exit:
228  return ret;
229 }
230 
232  amxs_sync_direction_t direction) {
233  bool ret = true;
234 
235  if((direction == amxs_sync_a_to_b) &&
236  ((entry->attributes & AMXS_SYNC_ONLY_B_TO_A) != 0)) {
237  ret = false;
238  goto exit;
239  }
240 
241  if((direction == amxs_sync_b_to_a) &&
242  ((entry->attributes & AMXS_SYNC_ONLY_A_TO_B) != 0)) {
243  ret = false;
244  goto exit;
245  }
246 
247 exit:
248  return ret;
249 }
250 
252  bool ret = false;
253 
254  when_null(entry, exit);
255  when_false(entry->type == amxs_sync_type_param, exit);
256  when_true((entry->attributes & AMXS_SYNC_PARAM_BATCH) == 0, exit);
257 
258  ret = true;
259 
260 exit:
261  return ret;
262 }
263 
264 const char* amxs_sync_entry_get_name(const amxs_sync_entry_t* const entry,
265  amxs_sync_direction_t direction) {
266  const char* name = NULL;
267  when_null(entry, exit);
268 
269  name = direction == amxs_sync_a_to_b ? entry->a : entry->b;
270 
271 exit:
272  return name;
273 }
274 
276  amxs_sync_direction_t direction) {
277  const char* opposite = NULL;
278  when_null(entry, exit);
279 
280  opposite = direction == amxs_sync_a_to_b ? entry->b : entry->a;
281 
282 exit:
283  return opposite;
284 }
285 
287  amxs_sync_entry_t* parent = NULL;
288  when_null(entry, exit);
289  when_false(amxc_llist_it_is_in_list(&entry->it), exit);
290 
291  parent = amxc_container_of(entry->it.llist, amxs_sync_entry_t, entries);
292 
293 exit:
294  return parent;
295 }
296 
298  amxs_sync_ctx_t* ctx = NULL;
299  amxs_sync_entry_t* tmp = NULL;
300  when_null(entry, exit);
301 
302  when_true_status(entry->type == amxs_sync_type_ctx, exit, ctx = (amxs_sync_ctx_t*) entry);
303 
304  tmp = amxs_sync_entry_get_parent(entry);
305  while(tmp != NULL && tmp->type != amxs_sync_type_ctx) {
306  tmp = amxs_sync_entry_get_parent(tmp);
307  }
308 
309  if((tmp != NULL) && (tmp->type == amxs_sync_type_ctx)) {
310  ctx = tmp;
311  }
312 
313 exit:
314  return ctx;
315 }
316 
317 amxp_signal_mngr_t* amxs_sync_entry_get_signal_manager(const amxs_sync_entry_t* const entry) {
318  amxp_signal_mngr_t* sig_mngr = NULL;
319  amxs_sync_ctx_t* ctx = NULL;
320 
321  ctx = amxs_sync_entry_get_ctx(entry);
322  when_null(ctx, exit);
323 
324  sig_mngr = ctx->sig_mngr;
325 
326 exit:
327  return sig_mngr;
328 }
329 
330 
331 amxb_bus_ctx_t* amxs_sync_ctx_get_opposite_bus_ctx(const amxs_sync_ctx_t* const ctx,
332  amxs_sync_direction_t direction) {
333  amxb_bus_ctx_t* bus_ctx = NULL;
334  when_null(ctx, exit);
335  when_false(ctx->type == amxs_sync_type_ctx, exit);
336 
337  bus_ctx = direction == amxs_sync_a_to_b ? ctx->bus_ctx_b : ctx->bus_ctx_a;
338 
339 exit:
340  return bus_ctx;
341 }
342 
343 amxb_bus_ctx_t* amxs_sync_ctx_get_bus_ctx(const amxs_sync_ctx_t* const ctx,
344  amxs_sync_direction_t direction) {
345  amxb_bus_ctx_t* bus_ctx = NULL;
346  when_null(ctx, exit);
347  when_false(ctx->type == amxs_sync_type_ctx, exit);
348 
349  bus_ctx = direction == amxs_sync_a_to_b ? ctx->bus_ctx_a : ctx->bus_ctx_b;
350 
351 exit:
352  return bus_ctx;
353 }
354 
356  amxs_sync_direction_t direction) {
357  amxd_dm_t* dm = NULL;
358  when_null(ctx, exit);
359  when_false(ctx->type == amxs_sync_type_ctx, exit);
360 
361  dm = direction == amxs_sync_a_to_b ? ctx->local_dm_b : ctx->local_dm_a;
362 
363 exit:
364  return dm;
365 }
366 
367 amxd_dm_t* amxs_sync_ctx_get_dm(const amxs_sync_ctx_t* ctx,
368  amxs_sync_direction_t direction) {
369  amxd_dm_t* dm = NULL;
370  when_null(ctx, exit);
371  when_false(ctx->type == amxs_sync_type_ctx, exit);
372 
373  dm = direction == amxs_sync_a_to_b ? ctx->local_dm_a : ctx->local_dm_b;
374 
375 exit:
376  return dm;
377 }
378 
380  UNUSED amxs_sync_direction_t direction,
381  unsigned int index) {
382  int new_index = 0;
383  when_null(entry, exit);
384 
385  new_index = index;
386 
387 exit:
388  return new_index;
389 }
390 
392  amxs_sync_direction_t direction,
393  amxd_path_t* path,
394  amxc_string_t* path_str) {
395  char* last = amxd_path_get_last(path, true);
396  char* ptr = NULL;
397  unsigned int index = strtoul(last, &ptr, 0);
398  int ret = -1;
399  const char* name = amxs_sync_entry_get_name(entry, direction);
400  amxc_string_t str;
401 
402  amxc_string_init(&str, 0);
403 
404  if(strcmp(name, last) == 0) {
405  amxc_string_prependf(path_str, "%s", amxs_sync_entry_get_opposite_name(entry, direction));
406  } else if(strstr(name, last) != NULL) {
407  amxc_string_set(&str, last);
408  do {
409  free(last);
410  last = amxd_path_get_last(path, true);
411  when_null(last, exit);
412  amxc_string_prependf(&str, "%s", last);
413  } while(strcmp(amxc_string_get(&str, 0), name) != 0);
414  amxc_string_prependf(path_str, "%s", amxs_sync_entry_get_opposite_name(entry, direction));
415  } else if(last != ptr) {
416  index = amxs_sync_entry_get_opposite_index(entry, direction, index);
417  amxc_string_prependf(path_str, "%u.", index);
418  amxs_sync_entry_build_opposite_path_entry(entry, direction, path, path_str);
419  }
420 
421  ret = 0;
422 
423 exit:
424  free(last);
425  amxc_string_clean(&str);
426  return ret;
427 }
428 
430  amxs_sync_direction_t direction,
431  const char* const old_path) {
432  char* new_path = NULL;
433  amxc_string_t path_str;
434  amxd_path_t path;
435  const amxs_sync_entry_t* tmp = entry;
436 
437  when_null(entry, exit);
438  when_str_empty(old_path, exit);
439 
440  amxd_path_init(&path, old_path);
441  amxc_string_init(&path_str, 0);
442 
443  while(amxd_path_get_depth(&path) != 0 && tmp != NULL) {
444  when_false(amxs_sync_entry_build_opposite_path_entry(tmp, direction, &path, &path_str) == 0, exit);
445  tmp = amxs_sync_entry_get_parent(tmp);
446  }
447 
448  new_path = amxc_string_take_buffer(&path_str);
449 
450 exit:
451  amxd_path_clean(&path);
452  amxc_string_clean(&path_str);
453  return new_path;
454 }
455 
457  amxs_sync_direction_t direction,
458  const char* const old_path) {
459  char* new_path = NULL;
461  when_null(parent, exit);
462 
463  new_path = amxs_sync_entry_get_opposite_path(parent, direction, old_path);
464 
465 exit:
466  return new_path;
467 }
468 
470  amxs_sync_direction_t direction) {
471  char* path_str = NULL;
472  const amxs_sync_entry_t* tmp = entry;
473  amxc_string_t str;
474 
475  when_null(entry, exit);
476  amxc_string_init(&str, 0);
477  amxc_string_set(&str, "$");
478 
479  while(tmp != NULL) {
480  amxd_path_t path;
481  const char* name = amxs_sync_entry_get_name(tmp, direction);
482  when_str_empty(name, exit);
483  amxd_path_init(&path, name);
484 
485  if((entry->type == amxs_sync_type_object) && (amxd_path_is_instance_path(&path) == false)) {
486  amxc_string_prependf(&str, "%s([0-9]+\\.)?", name);
487  } else {
488  amxc_string_prependf(&str, "%s", name);
489  }
490  amxd_path_clean(&path);
491  tmp = amxs_sync_entry_get_parent(tmp);
492  }
493  amxc_string_prependf(&str, "%s", "^");
494 
495  path_str = amxc_string_take_buffer(&str);
496 
497 exit:
498  amxc_string_clean(&str);
499  return path_str;
500 }
501 
503  amxs_sync_direction_t direction) {
504  char* path = NULL;
506  when_null(parent, exit);
507 
508  path = amxs_sync_entry_get_regex_path(parent, direction);
509 
510 exit:
511  return path;
512 }
513 
515  amxc_var_t* params,
516  amxs_sync_direction_t direction) {
518 
519  when_null(entry, exit);
520  when_null(params, exit);
521  when_true_status(entry->type == amxs_sync_type_param, exit, status = amxs_status_invalid_type);
522 
523  amxc_llist_iterate(it, &entry->entries) {
524  amxs_sync_entry_t* child = amxc_llist_it_get_data(it, amxs_sync_entry_t, it);
525  if(!amxs_sync_entry_is_batch_param(child)) {
526  continue;
527  }
528 
529  if(!amxs_sync_entry_direction_allowed(child, direction)) {
530  continue;
531  }
532 
533  amxc_var_add(cstring_t, params, direction == amxs_sync_a_to_b ? child->a : child->b);
534  }
535 
536  status = amxs_status_ok;
537 
538 exit:
539  return status;
540 }
541 
543  amxs_sync_direction_t direction,
544  const amxc_var_t* input,
545  amxc_var_t* output,
546  UNUSED void* priv) {
548  amxc_var_t* params = GET_ARG(input, "parameters");
549  amxc_var_t* output_params = NULL;
550  const char* path = GET_CHAR(input, "path");
551  const char* notification = GET_CHAR(input, "notification");
552  const char* entry_name = amxs_sync_entry_get_name(entry, direction);
553  char* opposite_path = NULL;
554  amxs_sync_entry_t* parent_entry = amxs_sync_entry_get_parent(entry);
555 
556  when_null(params, exit);
557  when_str_empty(path, exit);
558  when_str_empty(entry_name, exit);
559  when_str_empty(notification, exit);
560 
561  opposite_path = amxs_sync_entry_get_opposite_parent_path(entry, direction, path);
562  when_str_empty(opposite_path, exit);
563 
564  amxc_var_set_type(output, AMXC_VAR_ID_HTABLE);
565  output_params = amxc_var_add_key(amxc_htable_t, output, "parameters", NULL);
566  amxc_var_add_key(cstring_t, output, "path", opposite_path);
567 
568  // When doing initial sync, protect agains loop-back add-object events
569  if((strcmp(notification, "dm:object-added") == 0) ||
570  (strcmp(notification, "sync:init-param") == 0)) {
571  // This translation callback function is called on parameter entries
572  // Here the object entry is needed, take parent.
573  // Handle loop prevention, returns true if this object-added is to be ignored
574  if(amxs_sync_entry_check_bidrection_object(parent_entry, direction, path, opposite_path)) {
575  status = amxs_status_ok;
576  goto exit;
577  }
578  } else {
579  amxs_sync_entry_remove_bidrection_object(parent_entry, direction, path);
580  if(strcmp(notification, "dm:object-removed") == 0) {
581  status = amxs_status_ok;
582  goto exit;
583  }
584  }
585 
586  amxc_var_for_each(param, params) {
587  if(strcmp(amxc_var_key(param), entry_name) == 0) {
588  amxc_var_t* value = NULL;
589  amxc_var_t* new_param = NULL;
590 
591  if((strcmp(notification, "sync:init-param") == 0) ||
592  (strcmp(notification, "dm:object-added") == 0)) {
593  value = param;
594  } else {
595  value = GET_ARG(param, "to");
596  }
597 
598  // Handle loop prevention, returns true if this parameter is to be ignored
599  if(strcmp(notification, "dm:object-added") != 0) {
600  if(amxs_sync_entry_check_bidirectional_loop(entry, direction, value, path, opposite_path)) {
601  continue;
602  }
603  }
604 
605  new_param = amxc_var_add_new_key(output_params, amxs_sync_entry_get_opposite_name(entry, direction));
606  amxc_var_copy(new_param, value);
607  }
608  }
609 
610  status = amxs_status_ok;
611 
612 exit:
613  free(opposite_path);
614  return status;
615 }
616 
618  amxs_sync_direction_t direction,
619  const amxc_var_t* input,
620  amxc_var_t* output,
621  UNUSED void* priv) {
623  amxc_var_t* params = GET_ARG(input, "parameters");
624  amxc_var_t* output_params = NULL;
625  const char* path = GET_CHAR(input, "path");
626  const char* notification = GET_CHAR(input, "notification");
627  const char* entry_name = amxs_sync_entry_get_name(entry, direction);
628  char* opposite_path = NULL;
629 
630  when_null(params, exit);
631  when_str_empty(path, exit);
632  when_str_empty(entry_name, exit);
633  when_str_empty(notification, exit);
634 
635  opposite_path = amxs_sync_entry_get_opposite_path(entry, direction, path);
636  when_str_empty(opposite_path, exit);
637 
638  amxc_var_set_type(output, AMXC_VAR_ID_HTABLE);
639  output_params = amxc_var_add_key(amxc_htable_t, output, "parameters", NULL);
640  amxc_var_add_key(cstring_t, output, "path", opposite_path);
641 
642  if((strcmp(notification, "dm:object-added") == 0) ||
643  (strcmp(notification, "sync:init-batch-param") == 0)) {
644  // Handle loop prevention, returns true if this object-added is to be ignored
645  if(amxs_sync_entry_check_bidrection_object(entry, direction, path, opposite_path)) {
646  status = amxs_status_ok;
647  goto exit;
648  }
649  } else {
650  amxs_sync_entry_remove_bidrection_object(entry, direction, path);
651  if(strcmp(notification, "dm:object-removed") == 0) {
652  status = amxs_status_ok;
653  goto exit;
654  }
655  }
656 
657 
658  amxc_llist_iterate(it, &entry->entries) {
659  amxs_sync_entry_t* child = amxc_llist_it_get_data(it, amxs_sync_entry_t, it);
660  amxc_var_t* param = NULL;
661  amxc_var_t* new_param = NULL;
662  amxc_var_t* value = NULL;
663 
664  if(!amxs_sync_entry_is_batch_param(child)) {
665  continue;
666  }
667 
668  param = GETP_ARG(params, amxs_sync_entry_get_name(child, direction));
669  if(param == NULL) {
670  continue;
671  }
672 
673  if((strcmp(notification, "sync:init-batch-param") == 0) ||
674  (strcmp(notification, "dm:object-added") == 0)) {
675  value = param;
676  } else {
677  value = GET_ARG(param, "to");
678  }
679 
680  // Handle loop prevention, returns true if this parameter is to be ignored
681  if(strcmp(notification, "dm:object-added") != 0) {
682  if(amxs_sync_entry_check_bidirectional_loop(child, direction, value, path, opposite_path)) {
683  continue;
684  }
685  }
686 
687  new_param = amxc_var_add_new_key(output_params, amxs_sync_entry_get_opposite_name(child, direction));
688  amxc_var_copy(new_param, value);
689  }
690 
691  status = amxs_status_ok;
692 
693 exit:
694  free(opposite_path);
695  return status;
696 }
697 
699  amxs_sync_direction_t direction,
700  amxc_var_t* data,
701  UNUSED void* priv) {
703  const char* path = GET_CHAR(data, "path");
704  amxc_var_t* params = GET_ARG(data, "parameters");
705  amxb_bus_ctx_t* bus_ctx = NULL;
706  amxc_var_t ret;
707  amxd_dm_t* dm = NULL;
708 
709  amxc_var_init(&ret);
710 
711  when_null(path, exit);
712  when_null(params, exit);
713 
715  if(dm != NULL) {
716  amxd_trans_t trans;
717 
718  amxd_trans_init(&trans);
719  amxd_trans_set_attr(&trans, amxd_tattr_change_ro, true);
720  amxd_trans_select_pathf(&trans, "%s", path);
721  amxc_var_for_each(var, params) {
722  amxd_trans_set_param(&trans, amxc_var_key(var), var);
723  }
724 
725  if(amxd_trans_apply(&trans, dm) == 0) {
726  status = amxs_status_ok;
727  }
728  amxd_trans_clean(&trans);
729  } else {
731  when_null(bus_ctx, exit);
732  if(amxb_set(bus_ctx, path, params, &ret, 5) == 0) {
733  status = amxs_status_ok;
734  }
735  }
736 
737 exit:
738  amxc_var_clean(&ret);
739  return status;
740 }
741 
742 static void amxs_notify_instance_added(const amxc_var_t* input, amxs_sync_entry_t* entry, const amxs_sync_direction_t direction) {
743  amxc_var_t* parameters = NULL;
744  amxc_var_t* changed_value = NULL;
745  amxc_var_t event_data;
746  amxc_string_t str_object;
747  amxc_string_t str_path;
748  amxc_string_t str_new_value;
749 
750  amxc_var_init(&event_data);
751  amxc_var_set_type(&event_data, AMXC_VAR_ID_HTABLE);
752  amxc_string_init(&str_object, 0);
753  amxc_string_init(&str_path, 0);
754  amxc_string_init(&str_new_value, 0);
755  amxc_string_setf(&str_object, "%s%d.", GET_CHAR(input, "object"), GET_UINT32(input, "index"));
756  amxc_string_setf(&str_path, "%s%d.", GET_CHAR(input, "path"), GET_UINT32(input, "index"));
757  amxc_string_setf(&str_new_value, "parameters.%s", amxs_sync_entry_get_name(entry, direction));
758 
759  amxc_var_add_key(cstring_t, &event_data, "notification", "dm:object-changed");
760  amxc_var_add_key(cstring_t, &event_data, "object", amxc_string_get(&str_object, 0));
761 
762  parameters = amxc_var_add_key(amxc_htable_t, &event_data, "parameters", NULL);
763  changed_value = amxc_var_add_key(amxc_htable_t, parameters, amxs_sync_entry_get_name(entry, direction), NULL);
764  amxc_var_set_key(changed_value, "from", NULL, AMXC_VAR_FLAG_DEFAULT);
765  amxc_var_set_key(changed_value, "to", GETP_ARG(input, amxc_string_get(&str_new_value, 0)), AMXC_VAR_FLAG_DEFAULT);
766 
767  amxc_var_add_key(cstring_t, &event_data, "path", amxc_string_get(&str_path, 0));
768  amxp_sigmngr_emit_signal(amxs_sync_entry_get_signal_manager(entry), "sync:instance-added", &event_data);
769 
770  amxc_var_clean(&event_data);
771  amxc_string_clean(&str_new_value);
772  amxc_string_clean(&str_path);
773  amxc_string_clean(&str_object);
774 }
775 
777  amxs_sync_direction_t direction,
778  const amxc_var_t* input,
779  amxc_var_t* output,
780  UNUSED void* priv) {
782  const char* path = GET_CHAR(input, "path");
783  char* opposite_path = NULL;
784  const char* notification = GET_CHAR(input, "notification");
785 
786  when_str_empty(path, exit);
787  when_str_empty(notification, exit);
788  opposite_path = amxs_sync_entry_get_opposite_path(entry, direction, path);
789  when_str_empty(opposite_path, exit);
790 
791  amxc_var_set_type(output, AMXC_VAR_ID_HTABLE);
792  amxc_var_add_key(cstring_t, output, "path", opposite_path);
793  amxc_var_add_key(uint32_t, output, "index",
794  amxs_sync_entry_get_opposite_index(entry, direction, GET_UINT32(input, "index")));
795  amxc_var_add_key(cstring_t, output, "notification", notification);
796 
797  if(((strcmp("dm:instance-added", notification) == 0) ||
798  (strcmp("sync:init-object", notification) == 0)) &&
799  (GET_ARG(input, "parameters") != NULL)) {
800  amxc_var_t* params = GET_ARG(input, "parameters");
801  amxc_var_t* output_params = amxc_var_add_new_key(output, "parameters");
802  amxc_var_set_type(output_params, AMXC_VAR_ID_HTABLE);
803 
804  amxc_llist_for_each(it, &entry->entries) {
805  amxs_sync_entry_t* child = amxc_container_of(it, amxs_sync_entry_t, it);
806  if(child->type != amxs_sync_type_param) {
807  continue;
808  }
809  amxc_var_for_each(param, params) {
810  if(strcmp(amxc_var_key(param), amxs_sync_entry_get_name(child, direction)) == 0) {
811  amxc_var_t* new_param = amxc_var_add_new_key(output_params, amxs_sync_entry_get_opposite_name(child, direction));
812  amxc_var_copy(new_param, param);
813  }
814  }
815 
816  /* Emit a sync:instance-added signal for each non batch parameter */
817  if((amxs_sync_entry_is_batch_param(child) == false) &&
818  (GET_CHAR(input, "object") != NULL) &&
819  (GET_CHAR(input, "path") != NULL) &&
820  (strcmp("dm:instance-added", notification) == 0)) {
821  amxs_notify_instance_added(input, child, direction);
822  }
823  }
824  }
825 
826  status = amxs_status_ok;
827 
828 exit:
829  free(opposite_path);
830  return status;
831 }
832 
834  amxs_sync_direction_t direction,
835  amxc_var_t* data,
836  UNUSED void* priv) {
838  const char* path = GET_CHAR(data, "path");
839  const char* notification = GET_CHAR(data, "notification");
840  uint32_t index = GET_UINT32(data, "index");
841  amxb_bus_ctx_t* bus_ctx = NULL;
842  amxc_var_t ret;
843 
844  amxc_var_init(&ret);
845 
846  when_null(path, exit);
847  when_null(notification, exit);
848 
850  when_null(bus_ctx, exit);
851 
852  if((strcmp(notification, "dm:instance-added") == 0) ||
853  (strcmp(notification, "sync:init-object") == 0)) {
854  amxc_var_t* params = GET_ARG(data, "parameters");
855  amxc_string_t str;
856  amxc_string_init(&str, 0);
857  amxc_string_setf(&str, "%s%u.", path, index);
858  if((amxb_get(bus_ctx, amxc_string_get(&str, 0), 0, &ret, 5) == 0) &&
859  (GETP_ARG(&ret, "0.0") != NULL)) {
860  if(amxb_set(bus_ctx, amxc_string_get(&str, 0), params, &ret, 5) == 0) {
861  status = amxs_status_ok;
862  }
863  } else {
864  if(amxb_add(bus_ctx, path, index, NULL, params, &ret, 5) == 0) {
865  status = amxs_status_ok;
866  }
867  }
868  amxc_string_clean(&str);
869  } else {
870  if(amxb_del(bus_ctx, path, index, NULL, &ret, 5) == 0) {
871  status = amxs_status_ok;
872  }
873  }
874 
875 exit:
876  amxc_var_clean(&ret);
877  return status;
878 }
Ambiorix Object Synchronization API header file.
@ amxs_status_ok
Definition: amxs_types.h:86
@ amxs_status_unknown_error
Definition: amxs_types.h:90
@ amxs_status_invalid_type
Definition: amxs_types.h:92
@ amxs_status_invalid_arg
Definition: amxs_types.h:89
enum _amxs_sync_direction amxs_sync_direction_t
@ amxs_sync_a_to_b
Definition: amxs_types.h:80
@ amxs_sync_b_to_a
Definition: amxs_types.h:81
enum _amxs_status amxs_status_t
@ amxs_sync_type_param
Definition: amxs_types.h:102
@ amxs_sync_type_object
Definition: amxs_types.h:101
@ amxs_sync_type_ctx
Definition: amxs_types.h:100
const char * amxs_sync_entry_get_opposite_name(const amxs_sync_entry_t *const entry, amxs_sync_direction_t direction)
Definition: amxs_util.c:275
amxs_status_t amxs_sync_batch_param_copy_trans_cb(const amxs_sync_entry_t *entry, amxs_sync_direction_t direction, const amxc_var_t *input, amxc_var_t *output, UNUSED void *priv)
Definition: amxs_util.c:617
static int amxs_sync_entry_build_opposite_path_entry(const amxs_sync_entry_t *const entry, amxs_sync_direction_t direction, amxd_path_t *path, amxc_string_t *path_str)
Definition: amxs_util.c:391
char * amxs_sync_entry_get_regex_parent_path(const amxs_sync_entry_t *const entry, amxs_sync_direction_t direction)
Definition: amxs_util.c:502
amxs_status_t amxs_sync_entry_get_batch_params(const amxs_sync_entry_t *const entry, amxc_var_t *params, amxs_sync_direction_t direction)
Definition: amxs_util.c:514
char * amxs_sync_entry_get_regex_path(const amxs_sync_entry_t *const entry, amxs_sync_direction_t direction)
Definition: amxs_util.c:469
bool amxs_sync_entry_check_bidirectional_loop(const amxs_sync_entry_t *entry, amxs_sync_direction_t direction, amxc_var_t *value, const char *path, const char *opposite_path)
Definition: amxs_util.c:168
static bool amxs_sync_entry_check_bidirectional_param(amxc_var_t *list, amxc_var_t *value)
Definition: amxs_util.c:138
amxb_bus_ctx_t * amxs_sync_ctx_get_opposite_bus_ctx(const amxs_sync_ctx_t *const ctx, amxs_sync_direction_t direction)
Definition: amxs_util.c:331
bool amxs_sync_entry_remove_bidrection_object(const amxs_sync_entry_t *entry, amxs_sync_direction_t direction, const char *path)
Definition: amxs_util.c:76
amxd_dm_t * amxs_sync_ctx_get_opposite_dm(const amxs_sync_ctx_t *ctx, amxs_sync_direction_t direction)
Definition: amxs_util.c:355
amxs_sync_ctx_t * amxs_sync_entry_get_ctx(const amxs_sync_entry_t *const entry)
Definition: amxs_util.c:297
char * amxs_sync_entry_get_opposite_path(const amxs_sync_entry_t *const entry, amxs_sync_direction_t direction, const char *const old_path)
Definition: amxs_util.c:429
bool amxs_sync_entry_is_batch_param(const amxs_sync_entry_t *const entry)
Definition: amxs_util.c:251
char * amxs_sync_entry_get_opposite_parent_path(const amxs_sync_entry_t *const entry, amxs_sync_direction_t direction, const char *const old_path)
Definition: amxs_util.c:456
bool amxs_sync_entry_check_bidrection_object(const amxs_sync_entry_t *entry, amxs_sync_direction_t direction, const char *path, const char *opposite_path)
Definition: amxs_util.c:101
const char * amxs_sync_entry_get_name(const amxs_sync_entry_t *const entry, amxs_sync_direction_t direction)
Definition: amxs_util.c:264
unsigned int amxs_sync_entry_get_opposite_index(const amxs_sync_entry_t *const entry, UNUSED amxs_sync_direction_t direction, unsigned int index)
Definition: amxs_util.c:379
amxs_status_t amxs_sync_object_copy_action_cb(const amxs_sync_entry_t *entry, amxs_sync_direction_t direction, amxc_var_t *data, UNUSED void *priv)
Definition: amxs_util.c:833
bool amxs_sync_entry_direction_allowed(const amxs_sync_entry_t *const entry, amxs_sync_direction_t direction)
Definition: amxs_util.c:231
amxs_status_t amxs_sync_param_copy_action_cb(const amxs_sync_entry_t *entry, amxs_sync_direction_t direction, amxc_var_t *data, UNUSED void *priv)
Definition: amxs_util.c:698
amxs_status_t amxs_sync_param_copy_trans_cb(const amxs_sync_entry_t *entry, amxs_sync_direction_t direction, const amxc_var_t *input, amxc_var_t *output, UNUSED void *priv)
Definition: amxs_util.c:542
amxb_bus_ctx_t * amxs_sync_ctx_get_bus_ctx(const amxs_sync_ctx_t *const ctx, amxs_sync_direction_t direction)
Definition: amxs_util.c:343
amxs_status_t amxs_sync_object_copy_trans_cb(const amxs_sync_entry_t *entry, amxs_sync_direction_t direction, const amxc_var_t *input, amxc_var_t *output, UNUSED void *priv)
Definition: amxs_util.c:776
static void amxs_notify_instance_added(const amxc_var_t *input, amxs_sync_entry_t *entry, const amxs_sync_direction_t direction)
Definition: amxs_util.c:742
bool amxs_sync_entry_is_bidirectional(const amxs_sync_entry_t *entry)
Definition: amxs_util.c:219
amxp_signal_mngr_t * amxs_sync_entry_get_signal_manager(const amxs_sync_entry_t *const entry)
Definition: amxs_util.c:317
amxs_sync_entry_t * amxs_sync_entry_get_parent(const amxs_sync_entry_t *const entry)
Definition: amxs_util.c:286
amxd_dm_t * amxs_sync_ctx_get_dm(const amxs_sync_ctx_t *ctx, amxs_sync_direction_t direction)
Definition: amxs_util.c:367
#define AMXS_SYNC_ONLY_B_TO_A
Only synchronize from object B to object A.
Definition: amxs_types.h:195
#define AMXS_SYNC_ONLY_A_TO_B
Only synchronize from object A to object B.
Definition: amxs_types.h:200
#define AMXS_SYNC_PARAM_BATCH
Indicate that this parameter may be part of a batch copy operation.
Definition: amxs_types.h:210
Definition: amxs_types.h:161
amxd_dm_t * local_dm_b
Definition: amxs_types.h:178
char * a
Definition: amxs_types.h:163
amxs_sync_entry_type_t type
Definition: amxs_types.h:170
amxc_llist_it_t it
Definition: amxs_types.h:162
amxb_bus_ctx_t * bus_ctx_a
Definition: amxs_types.h:171
amxd_dm_t * local_dm_a
Definition: amxs_types.h:177
amxc_var_t b_to_a
Definition: amxs_types.h:176
amxc_var_t a_to_b
Definition: amxs_types.h:175
int attributes
Definition: amxs_types.h:165
amxp_signal_mngr_t * sig_mngr
Definition: amxs_types.h:174
char * b
Definition: amxs_types.h:164
amxc_llist_t entries
Definition: amxs_types.h:169
amxb_bus_ctx_t * bus_ctx_b
Definition: amxs_types.h:172
static amxb_bus_ctx_t * bus_ctx