libamxs  0.6.0
Data Model Synchronization C API
amxs_sync_ctx.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_signal.h>
65 #include <amxp/amxp_slot.h>
66 #include <amxp/amxp_expression.h>
67 
68 #include <amxd/amxd_types.h>
69 #include <amxd/amxd_object.h>
70 #include <amxd/amxd_path.h>
71 #include <amxd/amxd_dm.h>
72 
73 #include <amxb/amxb.h>
74 
75 #include <amxs/amxs_sync_ctx.h>
76 #include <amxs/amxs_util.h>
77 #include <amxs/amxs_sync_object.h>
78 #include <amxs/amxs_sync_param.h>
79 
80 #include "amxs_priv.h"
81 #include "amxs_sync_entry.h"
82 
83 static void amxs_callback(amxs_sync_direction_t direction,
84  const amxc_var_t* const data,
85  void* const priv,
86  bool batch) {
88  amxs_sync_entry_t* entry = (amxs_sync_entry_t*) priv;
89  amxc_var_t trans_data;
91  amxs_action_cb_t action_cb = batch ? amxs_sync_param_copy_action_cb : entry->action_cb;
92 
93  amxc_var_init(&trans_data);
94 
95  if(trans_cb != NULL) {
96  status = trans_cb(entry, direction, data, &trans_data, entry->priv);
97  when_failed(status, exit);
98  } else {
99  amxc_var_copy(&trans_data, data);
100  }
101 
102  if(action_cb != NULL) {
103  status = action_cb(entry, direction, &trans_data, entry->priv);
104  when_failed(status, exit);
105  }
106 
107 exit:
108  amxc_var_clean(&trans_data);
109 }
110 
111 static void amxs_callback_a(UNUSED const char* const sig_name,
112  const amxc_var_t* const data,
113  void* const priv) {
114  amxs_callback(amxs_sync_a_to_b, data, priv, false);
115 }
116 
117 static void amxs_callback_b(UNUSED const char* const sig_name,
118  const amxc_var_t* const data,
119  void* const priv) {
120  amxs_callback(amxs_sync_b_to_a, data, priv, false);
121 }
122 
123 static void amxs_batch_callback_a(UNUSED const char* const sig_name,
124  const amxc_var_t* const data,
125  void* const priv) {
126  amxs_callback(amxs_sync_a_to_b, data, priv, true);
127 }
128 
129 static void amxs_batch_callback_b(UNUSED const char* const sig_name,
130  const amxc_var_t* const data,
131  void* const priv) {
132  amxs_callback(amxs_sync_b_to_a, data, priv, true);
133 }
134 
136  amxs_sync_entry_t* entry,
137  amxs_sync_direction_t direction);
138 
140  amxs_sync_entry_t* entry,
141  amxs_sync_direction_t direction) {
143  const char* object = amxs_sync_entry_get_name(ctx, direction);
144  amxb_bus_ctx_t* bus_ctx = amxs_sync_ctx_get_bus_ctx(ctx, direction);
145  amxp_slot_fn_t fn = direction == amxs_sync_a_to_b ? amxs_batch_callback_a : amxs_batch_callback_b;
146  amxc_var_t params;
147  amxb_subscription_t* sub = NULL;
148  char* path = NULL;
149  amxc_string_t str;
150  int ret = -1;
151 
152  amxc_var_init(&params);
153  amxc_var_set_type(&params, AMXC_VAR_ID_LIST);
154  amxc_string_init(&str, 0);
155 
156  status = amxs_sync_entry_get_batch_params(entry, &params, direction);
157  when_failed(status, exit);
158  when_null_status(amxc_var_get_first(&params), exit, status = amxs_status_ok);
159 
160  path = amxs_sync_entry_get_regex_path(entry, direction);
161  when_str_empty(path, exit);
162 
163  amxc_string_setf(&str, "notification matches 'dm:object-(changed|added|removed)' && path matches '%s' && (", path);
164  amxc_var_for_each(var, &params) {
165  amxc_string_appendf(&str, " contains('parameters.%s') ||", GET_CHAR(var, NULL));
166  }
167  amxc_string_remove_at(&str, amxc_string_text_length(&str) - 3, 3);
168  amxc_string_append(&str, ")", 1);
169 
170  ret = amxb_subscription_new(&sub, bus_ctx, object, amxc_string_get(&str, 0), fn, entry);
171  when_failed(ret, exit);
172  amxc_llist_append(&ctx->subscriptions, &sub->it);
173 
174 exit:
175  amxc_var_clean(&params);
176  free(path);
177  amxc_string_clean(&str);
178  return status;
179 }
180 
182  amxs_sync_entry_t* entry,
183  amxs_sync_direction_t direction) {
185  amxb_subscription_t* sub = NULL;
186  amxc_string_t str;
187  char* path = NULL;
188  int ret = -1;
189  amxb_bus_ctx_t* bus_ctx = amxs_sync_ctx_get_bus_ctx(ctx, direction);
190  const char* object = amxs_sync_entry_get_name(ctx, direction);
191  const char* name = amxs_sync_entry_get_name(entry, direction);
192  amxp_slot_fn_t fn = direction == amxs_sync_a_to_b ? amxs_callback_a : amxs_callback_b;
193  amxd_path_t p;
194 
195  amxd_path_init(&p, name);
196  amxc_string_init(&str, 0);
197 
198  switch(entry->type) {
200  if(amxs_sync_entry_is_batch_param(entry)) {
201  break;
202  }
203  amxc_string_setf(&str, "notification matches 'dm:object-(changed|added|removed)' && contains('parameters.%s')", name);
204  path = amxs_sync_entry_get_regex_parent_path(entry, direction);
205  when_str_empty(path, exit);
206  amxc_string_appendf(&str, " && path matches '%s'", path);
207  ret = amxb_subscription_new(&sub, bus_ctx, object, amxc_string_get(&str, 0), fn, entry);
208  amxp_slot_connect(amxs_sync_entry_get_signal_manager(entry), "sync:instance-added", amxc_string_get(&str, 0), fn, entry);
209  when_failed(ret, exit);
210  amxc_llist_append(&ctx->subscriptions, &sub->it);
211  break;
213  if(amxd_path_is_instance_path(&p)) {
214  amxs_subscribe_batch_params(ctx, entry, direction);
215  amxs_subscribe_child_entries(ctx, entry, direction);
216  break;
217  }
218  path = amxs_sync_entry_get_regex_path(entry, direction);
219  when_str_empty(path, exit);
220  amxc_string_setf(&str, "notification matches 'dm:instance-*' && path matches '%s'", path);
221  ret = amxb_subscription_new(&sub, bus_ctx, object, amxc_string_get(&str, 0), fn, entry);
222  when_failed(ret, exit);
223  amxc_llist_append(&ctx->subscriptions, &sub->it);
224  amxs_subscribe_batch_params(ctx, entry, direction);
225  amxs_subscribe_child_entries(ctx, entry, direction);
226  break;
227  case amxs_sync_type_ctx:
228  amxs_subscribe_batch_params(ctx, entry, direction);
229  amxs_subscribe_child_entries(ctx, entry, direction);
230  break;
231  default:
232  break;
233  }
234 
235  status = amxs_status_ok;
236 
237 exit:
238  amxd_path_clean(&p);
239  free(path);
240  amxc_string_clean(&str);
241  return status;
242 }
243 
245  amxs_sync_entry_t* entry,
246  amxs_sync_direction_t direction) {
248 
249  amxc_llist_for_each(it, &entry->entries) {
250  amxs_sync_entry_t* child = amxc_container_of(it, amxs_sync_entry_t, it);
251  if(amxs_sync_entry_direction_allowed(child, direction)) {
252  status = amxs_subscribe(ctx, child, direction);
253  when_failed(status, exit);
254  }
255  }
256 
257  status = amxs_status_ok;
258 
259 exit:
260  return status;
261 }
262 
263 static int amxs_var_find_keys_regex(const amxc_var_t* var,
264  amxc_llist_t* paths,
265  const char* expr_str) {
266  amxc_string_t str;
267  int ret = -1;
268 
269  amxc_string_init(&str, 0);
270 
271  amxc_var_for_each(variant, var) {
272  amxp_expr_t expr;
273  amxp_expr_status_t status;
274 
275  amxc_string_setf(&str, "'%s' matches '%s'", amxc_var_key(variant), expr_str);
276  status = amxp_expr_init(&expr, amxc_string_get(&str, 0));
277  when_failed(status, exit);
278  if(amxp_expr_eval(&expr, &status)) {
279  amxc_llist_add_string(paths, amxc_var_key(variant));
280  }
281  amxp_expr_clean(&expr);
282  }
283 
284  ret = 0;
285 
286 exit:
287  amxc_string_clean(&str);
288  return ret;
289 }
290 
291 static void amxs_var_fill_initial_instance_data(const char* object,
292  const char* instance,
293  amxc_var_t* init_data,
294  const amxc_var_t* data) {
295  unsigned int index = strtoul(instance + strlen(object), NULL, 0);
296  amxc_var_t* tmp = NULL;
297 
298  amxc_var_set_type(init_data, AMXC_VAR_ID_HTABLE);
299  amxc_var_add_key(cstring_t, init_data, "path", object);
300  amxc_var_add_key(cstring_t, init_data, "notification", "sync:init-object");
301  amxc_var_add_key(uint32_t, init_data, "index", index);
302  tmp = amxc_var_add_new_key(init_data, "parameters");
303  amxc_var_copy(tmp, GET_ARG(data, instance));
304 }
305 
306 static void amxs_var_fill_initial_param_data(const char* object,
307  const char* name,
308  amxc_var_t* init_data,
309  const amxc_var_t* data) {
310  amxc_var_t* params = NULL;
311  amxc_var_t* param = NULL;
312 
313  amxc_var_set_type(init_data, AMXC_VAR_ID_HTABLE);
314  amxc_var_add_key(cstring_t, init_data, "path", object);
315  amxc_var_add_key(cstring_t, init_data, "notification", "sync:init-param");
316  params = amxc_var_add_new_key(init_data, "parameters");
317  amxc_var_set_type(params, AMXC_VAR_ID_HTABLE);
318  param = amxc_var_add_new_key(params, name);
319  amxc_var_copy(param, data);
320 }
321 
323  const char* const parent_path,
324  amxs_sync_direction_t parent_direction,
325  const amxc_var_t* const data_a,
326  const amxc_var_t* const data_b);
327 
328 static void amxs_var_fill_initial_batch_param_data(const char* object,
329  amxc_var_t* init_data,
330  const amxc_var_t* data) {
331  amxc_var_t* params = NULL;
332 
333  amxc_var_set_type(init_data, AMXC_VAR_ID_HTABLE);
334  amxc_var_add_key(cstring_t, init_data, "path", object);
335  amxc_var_add_key(cstring_t, init_data, "notification", "sync:init-batch-param");
336  params = amxc_var_add_new_key(init_data, "parameters");
337  amxc_var_set_type(params, AMXC_VAR_ID_HTABLE);
338  amxc_var_copy(params, data);
339 }
340 
342  UNUSED const char* const object,
343  UNUSED amxs_sync_direction_t direction,
344  UNUSED const amxc_var_t* const data) {
346  amxc_var_t init_data;
347  amxc_var_t* var = GET_ARG(data, object);
348 
349  amxc_var_init(&init_data);
350 
351  when_null_status(var, exit, status = amxs_status_object_not_found);
352 
353  amxs_var_fill_initial_batch_param_data(object, &init_data, var);
354  amxs_callback(direction, &init_data, entry, true);
355 
356  status = amxs_status_ok;
357 
358 exit:
359  amxc_var_clean(&init_data);
360  return status;
361 }
362 
364  const char* const object,
365  amxs_sync_direction_t direction,
366  const amxc_var_t* const data_a,
367  const amxc_var_t* const data_b) {
369  const amxc_var_t* data = direction == amxs_sync_a_to_b ? data_a : data_b;
370  amxc_string_t str;
371  amxc_llist_t list;
372  amxc_var_t init_data;
373 
374  amxc_string_init(&str, 0);
375  amxc_llist_init(&list);
376  amxc_var_init(&init_data);
377 
378  amxc_string_setf(&str, "%s[0-9]+\\.$", object);
379  when_failed(amxs_var_find_keys_regex(data, &list, amxc_string_get(&str, 0)), exit);
380 
381  // This only lists instance objects
382  amxc_llist_for_each(it, &list) {
383  const char* instance = amxc_string_get(amxc_llist_it_get_data(it, amxc_string_t, it), 0);
384 
385  amxs_var_fill_initial_instance_data(object, instance, &init_data, data);
386  amxs_callback(direction, &init_data, entry, false);
387 
388  status = amxs_initial_sync_child_entries(entry, instance, direction, data_a, data_b);
389  when_failed(status, exit);
390  }
391 
392  // find variant with the exact object name
393  // this will match in case the object is an instance or a non template object
394  if(amxc_var_get_pathf(data, AMXC_VAR_FLAG_DEFAULT, "'%s'", object) != NULL) {
395  status = amxs_initial_sync_batch_params(entry, object, direction, data);
396  when_failed(status, exit);
397  }
398 
399  if(GET_ARG(data, object) != NULL) {
400  status = amxs_initial_sync_child_entries(entry, object, direction, data_a, data_b);
401  when_failed(status, exit);
402  }
403 
404  status = amxs_status_ok;
405 
406 exit:
407  amxc_string_clean(&str);
408  amxc_llist_clean(&list, amxc_string_list_it_free);
409  amxc_var_clean(&init_data);
410  return status;
411 }
412 
414  const char* const object,
415  const char* const param,
416  amxs_sync_direction_t direction,
417  const amxc_var_t* const data) {
419  amxc_var_t init_data;
420  amxc_var_t* var = GET_ARG(data, object);
421 
422  amxc_var_init(&init_data);
423 
424  when_true_status(amxs_sync_entry_is_batch_param(entry), exit, status = amxs_status_ok);
425  when_null_status(var, exit, status = amxs_status_object_not_found);
426 
427  var = GET_ARG(var, param);
428  when_null_status(var, exit, status = amxs_status_ok);
429 
430  amxs_var_fill_initial_param_data(object, param, &init_data, var);
431  amxs_callback(direction, &init_data, entry, false);
432 
433  status = amxs_status_ok;
434 
435 exit:
436  amxc_var_clean(&init_data);
437  return status;
438 }
439 
441  const char* const parent_path,
442  amxs_sync_direction_t parent_direction,
443  const amxc_var_t* const data_a,
444  const amxc_var_t* const data_b) {
447  const amxc_var_t* data = direction == amxs_sync_a_to_b ? data_a : data_b;
448  const char* name = NULL;
449  amxc_string_t object;
450 
451  when_null(data, exit);
452 
453  amxc_string_init(&object, 0);
454 
455  name = amxs_sync_entry_get_name(entry, direction);
456  if(direction != parent_direction) {
457  char* opposite_parent_path = amxs_sync_entry_get_opposite_parent_path(entry, parent_direction, parent_path);
458  amxc_string_set(&object, opposite_parent_path);
459  free(opposite_parent_path);
460  } else {
461  amxc_string_set(&object, parent_path);
462  }
463 
464  switch(entry->type) {
465  case amxs_sync_type_ctx:
466  status = amxs_initial_sync_object(entry, name, direction, data_a, data_b);
467  when_failed(status, exit);
468  break;
470  amxc_string_appendf(&object, "%s", name);
471  status = amxs_initial_sync_object(entry, amxc_string_get(&object, 0), direction, data_a, data_b);
472  break;
474  status = amxs_initial_sync_param(entry, amxc_string_get(&object, 0), name, direction, data);
475  break;
476  default:
477  break;
478  }
479 
480 exit:
481  amxc_string_clean(&object);
482  return status;
483 }
484 
486  const char* const parent_path,
487  amxs_sync_direction_t parent_direction,
488  const amxc_var_t* const data_a,
489  const amxc_var_t* const data_b) {
491 
492  amxc_llist_for_each(it, &entry->entries) {
493  amxs_sync_entry_t* child = amxc_container_of(it, amxs_sync_entry_t, it);
494  status = amxs_initial_sync_entry(child, parent_path, parent_direction, data_a, data_b);
495  when_failed(status, exit);
496  }
497 
498  status = amxs_status_ok;
499 
500 exit:
501  return status;
502 }
503 
504 static amxd_object_type_t amxb_get_object_type(amxb_bus_ctx_t* ctx, const char* path) {
505  amxd_object_type_t rv = amxd_object_singleton;
506  amxc_var_t ret;
507 
508  amxc_var_init(&ret);
509  if(amxb_describe(ctx, path, 0, &ret, 5) == 0) {
510  rv = (amxd_object_type_t) GETP_UINT32(&ret, "0.type_id");
511  }
512  amxc_var_clean(&ret);
513 
514  return rv;
515 }
516 
517 static uint32_t amxs_sync_depth(amxs_sync_ctx_t* sync_ctx,
518  amxs_sync_entry_t* sync_entry,
519  amxs_sync_direction_t direction,
520  amxc_string_t* path,
521  uint32_t start) {
522  uint32_t depth = start;
523  uint32_t path_pos = amxc_string_text_length(path);
524  const char* sync_path = NULL;
525  amxb_bus_ctx_t* ctx = NULL;
526  amxd_path_t rel_path;
527  char* part = NULL;
528  char* endptr = NULL;
529  amxd_object_type_t type = amxd_object_singleton;
530 
531  sync_entry = sync_entry == NULL? sync_ctx:sync_entry;
532  ctx = (direction == amxs_sync_a_to_b)? sync_ctx->bus_ctx_a:sync_ctx->bus_ctx_b;
533  sync_path = (direction == amxs_sync_a_to_b)? sync_entry->a: sync_entry->b;
534 
535  when_null(sync_path, exit);
536 
537  amxd_path_init(&rel_path, sync_path);
538  amxc_string_appendf(path, "%s", sync_path);
539  start += (sync_entry == sync_ctx)? 0:amxd_path_get_depth(&rel_path);
540 
541  part = amxd_path_get_first(&rel_path, true);
542  if(strtoull(part, &endptr, 10) != 0) {
543  // if the relative path starts with a number then it is an instance
544  // decrease by 1 as the parent sync entry already added 1 for a template
545  start -= 1;
546  }
547  free(part);
548  amxd_path_clean(&rel_path);
549 
550  depth = start;
551  amxc_llist_iterate(it, &sync_entry->entries) {
552  uint32_t tree_depth = 0;
553  amxs_sync_entry_t* entry = amxc_container_of(it, amxs_sync_entry_t, it);
554  if(entry->type == amxs_sync_type_object) {
555  tree_depth = amxs_sync_depth(sync_ctx, entry, direction, path, start);
556  if(tree_depth > depth) {
557  depth = tree_depth;
558  }
559  }
560  }
561 
562  // If the current entry in the sync hierarchy is a template object the instances must be
563  // monitored as well, so add 1 in the depth
564  type = amxb_get_object_type(ctx, amxc_string_get(path, 0));
565  if(type == amxd_object_template) {
566  depth++;
567  }
568 
569  amxc_string_remove_at(path, path_pos, strlen(sync_path));
570 
571 exit:
572  return depth;
573 }
574 
577  int ret = -1;
578  amxc_var_t data_a;
579  amxc_var_t data_b;
580  uint32_t orig_access = AMXB_PROTECTED;
581  uint32_t depth = 0;
582  amxc_string_t path;
584  bool bidirectional = amxs_sync_entry_is_bidirectional(ctx);
585 
586  amxc_var_init(&data_a);
587  amxc_var_init(&data_b);
588  amxc_string_init(&path, 64);
589 
590  if((direction == amxs_sync_a_to_b) || bidirectional) {
591  if((ctx->bus_ctx_a != NULL) && (ctx->bus_ctx_a->access != AMXB_PROTECTED)) {
592  orig_access = ctx->bus_ctx_a->access;
593  amxb_set_access(ctx->bus_ctx_a, AMXB_PROTECTED);
594  }
595  depth = amxs_sync_depth(ctx, NULL, amxs_sync_a_to_b, &path, 0);
596  ret = amxb_get(ctx->bus_ctx_a, ctx->a, depth, &data_a, 5);
597  amxb_set_access(ctx->bus_ctx_a, orig_access);
598  if((ctx->attributes & AMXS_SYNC_ONLY_B_TO_A) == 0) {
599  when_failed(ret, exit);
600  }
601  }
602 
603  if((direction == amxs_sync_b_to_a) || bidirectional) {
604  if((ctx->bus_ctx_b != NULL) && (ctx->bus_ctx_b->access != AMXB_PROTECTED)) {
605  orig_access = ctx->bus_ctx_b->access;
606  amxb_set_access(ctx->bus_ctx_b, AMXB_PROTECTED);
607  }
608  depth = amxs_sync_depth(ctx, NULL, amxs_sync_b_to_a, &path, 0);
609  ret = amxb_get(ctx->bus_ctx_b, ctx->b, depth, &data_b, 5);
610  amxb_set_access(ctx->bus_ctx_b, orig_access);
611  if((ctx->attributes & AMXS_SYNC_ONLY_A_TO_B) == 0) {
612  when_failed(ret, exit);
613  }
614  }
615 
616  status = amxs_initial_sync_entry(ctx, NULL, amxs_sync_invalid, GETI_ARG(&data_a, 0), GETI_ARG(&data_b, 0));
617 
618 exit:
619  amxc_string_clean(&path);
620  amxc_var_clean(&data_a);
621  amxc_var_clean(&data_b);
622  return status;
623 }
624 
626  amxc_var_t data;
627  amxb_bus_ctx_t* bus_ctx = NULL;
628  char** path = NULL;
629  const char* new_path = NULL;
631  int ret = -1;
632  amxc_llist_it_t* it = NULL;
633  amxd_path_t p;
634 
635  amxc_var_init(&data);
636  amxd_path_init(&p, NULL);
637  when_null(ctx, exit);
638 
639  bus_ctx = direction == amxs_sync_a_to_b ? ctx->bus_ctx_a : ctx->bus_ctx_b;
640  path = direction == amxs_sync_a_to_b ? &ctx->a : &ctx->b;
641 
642  when_null(bus_ctx, exit);
643  when_str_empty(*path, exit);
644 
645  amxd_path_setf(&p, true, "%s", *path);
646  ret = amxb_resolve(bus_ctx, &p, &data);
647  when_failed(ret, exit);
648 
649  it = amxc_llist_get_first(amxc_var_constcast(amxc_llist_t, &data));
650  if((it == NULL) || (amxc_llist_it_get_next(it) != NULL)) {
651  goto exit;
652  }
653 
654  new_path = GET_CHAR(amxc_llist_it_get_data(it, amxc_var_t, lit), NULL);
655  when_str_empty(new_path, exit);
656  free(*path);
657  *path = strdup(new_path);
658 
659  stat = amxs_status_ok;
660 
661 exit:
662  amxd_path_clean(&p);
663  amxc_var_clean(&data);
664  return stat;
665 }
666 
668  amxs_sync_direction_t direction) {
670  amxd_dm_t* dm = NULL;
671  const char* path = NULL;
672 
673  when_null(ctx, exit);
674 
675  dm = direction == amxs_sync_a_to_b ? ctx->local_dm_b : ctx->local_dm_a;
676  path = direction == amxs_sync_a_to_b ? ctx->b : ctx->a;
677  when_null_status(dm, exit, status = amxs_status_ok);
678 
679  when_null_status(amxd_dm_findf(dm, "%s", path), exit, status = amxs_status_object_not_found);
680 
681  status = amxs_status_ok;
682 
683 exit:
684  return status;
685 }
686 
687 static bool amxs_sync_ctx_paths_match(const char* new_path, const char* old_path) {
688  bool retval = false;
689  amxd_path_t old_p;
690  amxd_path_t new_p;
691  char* supported_old = NULL;
692  char* supported_new = NULL;
693 
694  amxd_path_init(&old_p, NULL);
695  amxd_path_init(&new_p, NULL);
696 
697  amxd_path_setf(&old_p, false, "%s", new_path);
698  amxd_path_setf(&new_p, false, "%s", old_path);
699 
700  supported_old = amxd_path_get_supported_path(&old_p);
701  supported_new = amxd_path_get_supported_path(&new_p);
702 
703  retval = strcmp(supported_old, supported_new) == 0;
704 
705  free(supported_old);
706  free(supported_new);
707  amxd_path_clean(&old_p);
708  amxd_path_clean(&new_p);
709 
710  return retval;
711 }
712 
714  const char* object_a,
715  const char* object_b,
716  int attributes) {
717  return amxs_sync_entry_new(ctx,
718  object_a,
719  object_b,
720  attributes,
721  NULL,
722  NULL,
724  NULL);
725 }
726 
728  when_null(ctx, exit);
729  when_null(*ctx, exit);
730  when_false((*ctx)->type == amxs_sync_type_ctx, exit);
731 
733 
734 exit:
735  return;
736 }
737 
739  const char* object_a,
740  const char* object_b,
741  int attributes) {
742  return amxs_sync_entry_init(ctx,
743  object_a,
744  object_b,
745  attributes,
746  NULL,
747  NULL,
749  NULL);
750 }
751 
753  when_null(ctx, exit);
754  when_false(ctx->type == amxs_sync_type_ctx, exit);
755 
757 
758 exit:
759  return;
760 }
761 
763  return amxs_sync_entry_copy(dest, src, priv);
764 }
765 
768  when_null(ctx, exit);
769 
770  when_false_status(ctx->type == amxs_sync_type_ctx, exit, status = amxs_status_invalid_type);
771  when_true_status(amxc_llist_is_empty(&ctx->entries), exit, status = amxs_status_empty_context);
772 
773  if(ctx->bus_ctx_a == NULL) {
774  ctx->bus_ctx_a = amxb_be_who_has(ctx->a);
775  }
776  if(ctx->bus_ctx_b == NULL) {
777  ctx->bus_ctx_b = amxb_be_who_has(ctx->b);
778  }
779 
780  if((ctx->attributes & AMXS_SYNC_ONLY_B_TO_A) == 0) {
781  when_null_status(ctx->bus_ctx_a, exit, status = amxs_status_object_not_found);
782  when_failed_status(amxs_sync_ctx_validate_path(ctx, amxs_sync_a_to_b), exit,
784  when_failed_status(amxs_sync_ctx_verify_local_dm(ctx, amxs_sync_b_to_a), exit,
786  }
787 
788  if((ctx->attributes & AMXS_SYNC_ONLY_A_TO_B) == 0) {
789  when_null_status(ctx->bus_ctx_b, exit, status = amxs_status_object_not_found);
790  when_failed_status(amxs_sync_ctx_validate_path(ctx, amxs_sync_b_to_a), exit,
792  when_failed_status(amxs_sync_ctx_verify_local_dm(ctx, amxs_sync_a_to_b), exit,
794  }
795 
796  if((ctx->attributes & AMXS_SYNC_ONLY_B_TO_A) == 0) {
797  status = amxs_subscribe(ctx, ctx, amxs_sync_a_to_b);
798  when_failed(status, cleanup_subs);
799  }
800 
801  if((ctx->attributes & AMXS_SYNC_ONLY_A_TO_B) == 0) {
802  status = amxs_subscribe(ctx, ctx, amxs_sync_b_to_a);
803  when_failed(status, cleanup_subs);
804  }
805 
806  status = amxs_do_initial_sync(ctx);
807  when_failed(status, cleanup_subs);
808 
809 cleanup_subs:
810  if(status != amxs_status_ok) {
811  amxc_llist_clean(&ctx->subscriptions, amxs_llist_it_delete_subscription);
812  }
813 
814 exit:
815  return status;
816 }
817 
819  when_null(ctx, exit);
820  when_false(ctx->type == amxs_sync_type_ctx, exit);
821 
822  amxc_llist_clean(&ctx->subscriptions, amxs_llist_it_delete_subscription);
823 
824 exit:
825  return;
826 }
827 
829  const char* object_a,
830  const char* object_b) {
832  char* supported_a = NULL;
833  char* supported_b = NULL;
834 
835  when_null(ctx, exit);
836  when_str_empty_status(object_a, exit, status = amxs_status_invalid_arg);
837  when_str_empty_status(object_b, exit, status = amxs_status_invalid_arg);
838 
839  supported_a = ctx->a;
840  supported_b = ctx->b;
841 
842  ctx->a = strdup(object_a);
843  ctx->b = strdup(object_b);
844 
845  if(ctx->bus_ctx_a == NULL) {
846  ctx->bus_ctx_a = amxb_be_who_has(ctx->a);
847  }
848  if(ctx->bus_ctx_b == NULL) {
849  ctx->bus_ctx_b = amxb_be_who_has(ctx->b);
850  }
851 
852  when_failed_status(amxs_sync_ctx_validate_path(ctx, amxs_sync_a_to_b), exit,
854  when_failed_status(amxs_sync_ctx_validate_path(ctx, amxs_sync_b_to_a), exit,
856 
857  when_false_status(amxs_sync_ctx_paths_match(ctx->a, supported_a), exit, status = amxs_status_invalid_arg);
858  when_false_status(amxs_sync_ctx_paths_match(ctx->b, supported_b), exit, status = amxs_status_invalid_arg);
859 
860  status = amxs_status_ok;
861 
862 exit:
863  free(supported_a);
864  free(supported_b);
865  return status;
866 }
867 
870  when_null(ctx, exit);
871  when_null(param, exit);
872  when_false_status(ctx->type == amxs_sync_type_ctx, exit, status = amxs_status_invalid_type);
873  when_false_status(param->type == amxs_sync_type_param, exit, status = amxs_status_invalid_type);
874 
875  status = amxs_sync_entry_add_entry(ctx, param);
876 
877 exit:
878  return status;
879 }
880 
882  const char* param_a,
883  const char* param_b,
884  int attributes,
885  amxs_translation_cb_t translation_cb,
886  amxs_action_cb_t action_cb,
887  void* priv) {
889  amxs_sync_param_t* param = NULL;
890 
891  status = amxs_sync_param_new(&param, param_a, param_b, attributes, translation_cb, action_cb, priv);
892  when_failed(status, exit);
893 
894  status = amxs_sync_ctx_add_param(ctx, param);
895  if(status != amxs_status_ok) {
896  amxs_sync_param_delete(&param);
897  }
898 
899 exit:
900  return status;
901 }
902 
904  const char* param_a,
905  const char* param_b,
906  int attributes) {
907  return amxs_sync_ctx_add_new_param(ctx,
908  param_a,
909  param_b,
910  attributes | AMXS_SYNC_PARAM_BATCH,
911  NULL,
912  NULL,
913  NULL);
914 }
915 
918  when_null(ctx, exit);
919  when_null(object, exit);
920  when_false_status(ctx->type == amxs_sync_type_ctx, exit, status = amxs_status_invalid_type);
921  when_false_status(object->type == amxs_sync_type_object, exit, status = amxs_status_invalid_type);
922 
923  status = amxs_sync_entry_add_entry(ctx, object);
924 
925 exit:
926  return status;
927 }
928 
930  const char* object_a,
931  const char* object_b,
932  int attributes,
933  amxs_translation_cb_t translation_cb,
934  amxs_action_cb_t action_cb,
935  void* priv) {
937  amxs_sync_object_t* object = NULL;
938 
939  status = amxs_sync_object_new(&object, object_a, object_b, attributes, translation_cb, action_cb, priv);
940  when_failed(status, exit);
941 
942  status = amxs_sync_ctx_add_object(ctx, object);
943  if(status != amxs_status_ok) {
944  amxs_sync_object_delete(&object);
945  }
946 
947 exit:
948  return status;
949 }
950 
952  const char* object_a,
953  const char* object_b,
954  int attributes) {
955  return amxs_sync_ctx_add_new_object(ctx,
956  object_a,
957  object_b,
958  attributes,
961  NULL);
962 }
963 
965  amxd_dm_t* dm_a,
966  amxd_dm_t* dm_b) {
968  when_null(ctx, exit);
969  when_false_status(ctx->type == amxs_sync_type_ctx, exit, status = amxs_status_invalid_type);
970 
971  if(((ctx->attributes & AMXS_SYNC_ONLY_B_TO_A) != 0) && (dm_b != NULL)) {
972  status = amxs_status_invalid_arg;
973  goto exit;
974  }
975 
976  if(((ctx->attributes & AMXS_SYNC_ONLY_A_TO_B) != 0) && (dm_a != NULL)) {
977  status = amxs_status_invalid_arg;
978  goto exit;
979  }
980 
981  ctx->local_dm_a = dm_a;
982  ctx->local_dm_b = dm_b;
983 
984  status = amxs_status_ok;
985 
986 exit:
987  return status;
988 }
void amxs_llist_it_delete_subscription(amxc_llist_it_t *it)
Definition: amxs_common.c:140
static amxs_status_t amxs_sync_ctx_verify_local_dm(amxs_sync_ctx_t *ctx, amxs_sync_direction_t direction)
static amxs_status_t amxs_initial_sync_child_entries(amxs_sync_entry_t *entry, const char *const parent_path, amxs_sync_direction_t parent_direction, const amxc_var_t *const data_a, const amxc_var_t *const data_b)
static amxs_status_t amxs_subscribe_batch_params(amxs_sync_ctx_t *ctx, amxs_sync_entry_t *entry, amxs_sync_direction_t direction)
static amxs_status_t amxs_subscribe(amxs_sync_ctx_t *ctx, amxs_sync_entry_t *entry, amxs_sync_direction_t direction)
static void amxs_callback_a(UNUSED const char *const sig_name, const amxc_var_t *const data, void *const priv)
amxs_status_t amxs_sync_ctx_set_local_dm(amxs_sync_ctx_t *ctx, amxd_dm_t *dm_a, amxd_dm_t *dm_b)
Set the local datamodel pointer for the sync root objects.
static int amxs_var_find_keys_regex(const amxc_var_t *var, amxc_llist_t *paths, const char *expr_str)
static void amxs_batch_callback_b(UNUSED const char *const sig_name, const amxc_var_t *const data, void *const priv)
static void amxs_callback(amxs_sync_direction_t direction, const amxc_var_t *const data, void *const priv, bool batch)
Definition: amxs_sync_ctx.c:83
static amxs_status_t amxs_initial_sync_param(amxs_sync_entry_t *entry, const char *const object, const char *const param, amxs_sync_direction_t direction, const amxc_var_t *const data)
static amxd_object_type_t amxb_get_object_type(amxb_bus_ctx_t *ctx, const char *path)
static amxs_status_t amxs_sync_ctx_validate_path(amxs_sync_ctx_t *ctx, amxs_sync_direction_t direction)
static void amxs_var_fill_initial_param_data(const char *object, const char *name, amxc_var_t *init_data, const amxc_var_t *data)
static void amxs_var_fill_initial_instance_data(const char *object, const char *instance, amxc_var_t *init_data, const amxc_var_t *data)
static void amxs_var_fill_initial_batch_param_data(const char *object, amxc_var_t *init_data, const amxc_var_t *data)
static uint32_t amxs_sync_depth(amxs_sync_ctx_t *sync_ctx, amxs_sync_entry_t *sync_entry, amxs_sync_direction_t direction, amxc_string_t *path, uint32_t start)
static amxs_status_t amxs_initial_sync_batch_params(UNUSED amxs_sync_entry_t *entry, UNUSED const char *const object, UNUSED amxs_sync_direction_t direction, UNUSED const amxc_var_t *const data)
static amxs_status_t amxs_subscribe_child_entries(amxs_sync_ctx_t *ctx, amxs_sync_entry_t *entry, amxs_sync_direction_t direction)
amxs_status_t amxs_sync_ctx_add_new_copy_object(amxs_sync_ctx_t *ctx, const char *object_a, const char *object_b, int attributes)
Creates and adds a synchronization object to a synchronization context.
static amxs_status_t amxs_initial_sync_object(amxs_sync_entry_t *entry, const char *const object, amxs_sync_direction_t direction, const amxc_var_t *const data_a, const amxc_var_t *const data_b)
static void amxs_callback_b(UNUSED const char *const sig_name, const amxc_var_t *const data, void *const priv)
static bool amxs_sync_ctx_paths_match(const char *new_path, const char *old_path)
static amxs_status_t amxs_do_initial_sync(amxs_sync_ctx_t *ctx)
static void amxs_batch_callback_a(UNUSED const char *const sig_name, const amxc_var_t *const data, void *const priv)
static amxs_status_t amxs_initial_sync_entry(amxs_sync_entry_t *entry, const char *const parent_path, amxs_sync_direction_t parent_direction, const amxc_var_t *const data_a, const amxc_var_t *const data_b)
Ambiorix Object Synchronization API header file.
amxs_status_t amxs_sync_entry_add_entry(amxs_sync_entry_t *parent, amxs_sync_entry_t *child)
amxs_status_t amxs_sync_entry_new(amxs_sync_entry_t **entry, const char *a, const char *b, int attributes, amxs_translation_cb_t translation_cb, amxs_action_cb_t action_cb, amxs_sync_entry_type_t type, void *priv)
amxs_sync_direction_t amxs_sync_entry_get_initial_direction(const amxs_sync_entry_t *entry)
amxs_status_t amxs_sync_entry_init(amxs_sync_entry_t *entry, const char *a, const char *b, int attributes, amxs_translation_cb_t translation_cb, amxs_action_cb_t action_cb, amxs_sync_entry_type_t type, void *priv)
amxs_status_t amxs_sync_entry_copy(amxs_sync_entry_t **dest, amxs_sync_entry_t *src, void *priv)
void amxs_sync_entry_delete(amxs_sync_entry_t **entry)
void amxs_sync_entry_clean(amxs_sync_entry_t *entry)
Ambiorix Object Synchronization API header file.
Ambiorix Object Synchronization API header file.
@ amxs_status_ok
Definition: amxs_types.h:86
@ amxs_status_object_not_found
Definition: amxs_types.h:93
@ 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
@ amxs_status_empty_context
Definition: amxs_types.h:91
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
@ amxs_sync_invalid
Definition: amxs_types.h:82
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
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_opposite_parent_path(const amxs_sync_entry_t *entry, amxs_sync_direction_t direction, const char *old_path)
Definition: amxs_util.c:456
bool amxs_sync_entry_direction_allowed(const amxs_sync_entry_t *entry, amxs_sync_direction_t direction)
Definition: amxs_util.c:231
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_is_batch_param(const amxs_sync_entry_t *const entry)
Definition: amxs_util.c:251
const char * amxs_sync_entry_get_name(const amxs_sync_entry_t *entry, amxs_sync_direction_t direction)
Definition: amxs_util.c:264
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
amxb_bus_ctx_t * amxs_sync_ctx_get_bus_ctx(const amxs_sync_ctx_t *ctx, amxs_sync_direction_t direction)
Definition: amxs_util.c:343
amxs_status_t amxs_sync_object_new(amxs_sync_object_t **object, const char *object_a, const char *object_b, int attributes, amxs_translation_cb_t translation_cb, amxs_action_cb_t action_cb, void *priv)
Synchronization object constructor function.
void amxs_sync_object_delete(amxs_sync_object_t **object)
Synchronization object destructor function.
void amxs_sync_param_delete(amxs_sync_param_t **param)
Synchronization parameter destructor function.
amxs_status_t amxs_sync_param_new(amxs_sync_param_t **param, const char *param_a, const char *param_b, int attributes, amxs_translation_cb_t translation_cb, amxs_action_cb_t action_cb, void *priv)
Synchronization parameter constructor function.
#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
amxs_status_t(* amxs_action_cb_t)(const amxs_sync_entry_t *entry, amxs_sync_direction_t direction, amxc_var_t *data, void *priv)
Definition of the action callback function.
Definition: amxs_types.h:156
amxs_status_t(* amxs_translation_cb_t)(const amxs_sync_entry_t *entry, amxs_sync_direction_t direction, const amxc_var_t *input, amxc_var_t *output, void *priv)
Definition of the translation callback function.
Definition: amxs_types.h:131
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, void *priv)
Translates data from a dm:object-changed event to data suited for an amxb_set call for all parameters...
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, void *priv)
Translates data from a dm:instance-added or dm:instance-removed event to data suited for an amxb call...
amxs_status_t amxs_sync_param_copy_action_cb(const amxs_sync_entry_t *entry, amxs_sync_direction_t direction, amxc_var_t *data, void *priv)
Sets the new parameter value.
amxs_status_t amxs_sync_object_copy_action_cb(const amxs_sync_entry_t *entry, amxs_sync_direction_t direction, amxc_var_t *data, void *priv)
Adds, removes or updates an object with the given data using an amxb call.
amxs_status_t amxs_sync_ctx_new(amxs_sync_ctx_t **ctx, const char *object_a, const char *object_b, int attributes)
Synchronization context constructor function.
amxs_status_t amxs_sync_ctx_copy(amxs_sync_ctx_t **dest, amxs_sync_ctx_t *src, void *priv)
Copies an existing synchronization context to a new synchronization context.
amxs_status_t amxs_sync_ctx_add_new_param(amxs_sync_ctx_t *ctx, const char *param_a, const char *param_b, int attributes, amxs_translation_cb_t translation_cb, amxs_action_cb_t action_cb, void *priv)
Creates and adds a synchronization parameter to a synchronization context.
amxs_status_t amxs_sync_ctx_add_param(amxs_sync_ctx_t *ctx, amxs_sync_param_t *param)
Adds a synchronization parameter to a synchronization context.
amxs_status_t amxs_sync_ctx_start_sync(amxs_sync_ctx_t *ctx)
Starts the object synchronization.
amxs_status_t amxs_sync_ctx_add_new_copy_param(amxs_sync_ctx_t *ctx, const char *param_a, const char *param_b, int attributes)
Creates and adds a synchronization parameter to a synchronization context.
void amxs_sync_ctx_delete(amxs_sync_ctx_t **ctx)
Synchronization context destructor function.
amxs_status_t amxs_sync_ctx_add_new_object(amxs_sync_ctx_t *ctx, const char *object_a, const char *object_b, int attributes, amxs_translation_cb_t translation_cb, amxs_action_cb_t action_cb, void *priv)
Creates and adds a synchronization object to a synchronization context.
amxs_status_t amxs_sync_ctx_init(amxs_sync_ctx_t *ctx, const char *object_a, const char *object_b, int attributes)
Synchronization context initialization function.
amxs_status_t amxs_sync_ctx_add_object(amxs_sync_ctx_t *ctx, amxs_sync_object_t *object)
Adds a synchronization object to a synchronization context.
void amxs_sync_ctx_stop_sync(amxs_sync_ctx_t *ctx)
Stops the object synchronization.
void amxs_sync_ctx_clean(amxs_sync_ctx_t *ctx)
Synchronization context cleanup function.
amxs_status_t amxs_sync_ctx_set_paths(amxs_sync_ctx_t *const ctx, const char *object_a, const char *object_b)
Updates the object paths of the synchronization context.
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
void * priv
Definition: amxs_types.h:168
amxb_bus_ctx_t * bus_ctx_a
Definition: amxs_types.h:171
amxd_dm_t * local_dm_a
Definition: amxs_types.h:177
amxs_translation_cb_t translation_cb
Definition: amxs_types.h:167
amxc_llist_t subscriptions
Definition: amxs_types.h:173
amxs_action_cb_t action_cb
Definition: amxs_types.h:166
int attributes
Definition: amxs_types.h:165
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