From f6ef7ddacbf12672c6230b19257f848c02d2c40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateo=20Cindri=C4=87?= Date: Mon, 26 Sep 2022 17:35:15 +0200 Subject: [PATCH] interfaces-plugin: switch to C11 instead of C99 --- CompileOptions.cmake | 36 +-- .../src/plugin/api/interfaces/change.c | 1 + .../plugin/api/interfaces/interface/change.c | 1 + .../src/plugin/api/interfaces/load.c | 258 +++++++++--------- .../src/plugin/data/interfaces/interface.c | 4 + .../data/interfaces/interface/ipv4/address.c | 2 + .../data/interfaces/interface/linked_list.h | 26 +- .../plugin/data/interfaces/interface_state.c | 1 + .../src/plugin/subscription/change.c | 1 + .../src/plugin/subscription/operational.c | 2 + 10 files changed, 174 insertions(+), 158 deletions(-) diff --git a/CompileOptions.cmake b/CompileOptions.cmake index 00bf1a93..fbe23896 100644 --- a/CompileOptions.cmake +++ b/CompileOptions.cmake @@ -1,20 +1,24 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic") -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra") -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion") -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-align") -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-prototypes") -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wuninitialized") -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow") -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat=2") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-align") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-prototypes") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wuninitialized") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat=2") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE") + if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=incompatible-pointer-types") -endif () -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-parameter") -if (CMAKE_C_COMPILER_ID MATCHES "Clang") - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-newline-eof") - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-gnu-zero-variadic-macro-arguments") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=incompatible-pointer-types") +endif() + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-parameter") + +if(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-newline-eof") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-gnu-zero-variadic-macro-arguments") endif() diff --git a/src/interfaces/src/plugin/api/interfaces/change.c b/src/interfaces/src/plugin/api/interfaces/change.c index a159e7f8..896699bd 100644 --- a/src/interfaces/src/plugin/api/interfaces/change.c +++ b/src/interfaces/src/plugin/api/interfaces/change.c @@ -4,6 +4,7 @@ #include "interface/change.h" +#include #include #include diff --git a/src/interfaces/src/plugin/api/interfaces/interface/change.c b/src/interfaces/src/plugin/api/interfaces/interface/change.c index 69541ff3..6cbd5c04 100644 --- a/src/interfaces/src/plugin/api/interfaces/interface/change.c +++ b/src/interfaces/src/plugin/api/interfaces/interface/change.c @@ -6,6 +6,7 @@ #include "sysrepo/xpath.h" #include +#include #include #include #include diff --git a/src/interfaces/src/plugin/api/interfaces/load.c b/src/interfaces/src/plugin/api/interfaces/load.c index 464e8ac6..0c874fb6 100644 --- a/src/interfaces/src/plugin/api/interfaces/load.c +++ b/src/interfaces/src/plugin/api/interfaces/load.c @@ -1,9 +1,10 @@ #include "load.h" -#include "utlist.h" #include "plugin/common.h" #include "utils/memory.h" +#include "utlist.h" #include +#include #include @@ -14,90 +15,90 @@ enum interfaces_load_exit_status { interfaces_load_failure = -1, - interfaces_load_success = 0, + interfaces_load_success = 0, interfaces_load_continue = 1, }; -static char *interfaces_get_interface_name(struct rtnl_link *link) +static char* interfaces_get_interface_name(struct rtnl_link* link) { - char *name = NULL; + char* name = NULL; - name = rtnl_link_get_name(link); - if (name == NULL) { - SRPLG_LOG_ERR(PLUGIN_NAME, "rtnl_link_get_name error"); - } + name = rtnl_link_get_name(link); + if (name == NULL) { + SRPLG_LOG_ERR(PLUGIN_NAME, "rtnl_link_get_name error"); + } - return xstrdup(name); + return xstrdup(name); } -static char *interfaces_get_interface_description(interfaces_ctx_t *ctx, char *name) +static char* interfaces_get_interface_description(interfaces_ctx_t* ctx, char* name) { - int error = SR_ERR_OK; - char path_buffer[PATH_MAX] = {0}; - sr_val_t *val = {0}; - char *description = NULL; - - /* conjure description path for this interface: /ietf-interfaces:interfaces/interface[name='test_interface']/description */ - error = snprintf(path_buffer, sizeof(path_buffer) / sizeof(char), "%s[name=\"%s\"]/description", INTERFACES_INTERFACES_LIST_YANG_PATH, name); - if (error < 0) { - SRPLG_LOG_ERR(PLUGIN_NAME, "snprintf error"); - goto error_out; - } - - // get the interface description value - error = sr_get_item(ctx->startup_session, path_buffer, 0, &val); - if (error != SR_ERR_OK) { - SRPLG_LOG_ERR(PLUGIN_NAME, "sr_get_item error (%d): %s", error, sr_strerror(error)); - goto error_out; - } - - if (strlen(val->data.string_val) > 0) { - description = xstrdup(val->data.string_val); - } - + int error = SR_ERR_OK; + char path_buffer[PATH_MAX] = { 0 }; + sr_val_t* val = { 0 }; + char* description = NULL; + + /* conjure description path for this interface: /ietf-interfaces:interfaces/interface[name='test_interface']/description */ + error = snprintf(path_buffer, sizeof(path_buffer) / sizeof(char), "%s[name=\"%s\"]/description", INTERFACES_INTERFACES_LIST_YANG_PATH, name); + if (error < 0) { + SRPLG_LOG_ERR(PLUGIN_NAME, "snprintf error"); + goto error_out; + } + + // get the interface description value + error = sr_get_item(ctx->startup_session, path_buffer, 0, &val); + if (error != SR_ERR_OK) { + SRPLG_LOG_ERR(PLUGIN_NAME, "sr_get_item error (%d): %s", error, sr_strerror(error)); + goto error_out; + } + + if (strlen(val->data.string_val) > 0) { + description = xstrdup(val->data.string_val); + } + error_out: - return description; + return description; } -static int read_from_sys_file(const char *dir_path, char *interface, int *val) +static int read_from_sys_file(const char* dir_path, char* interface, int* val) { - int error = 0; - char tmp_buffer[PATH_MAX]; - FILE *fptr = NULL; - char tmp_val[4] = {0}; - - error = snprintf(tmp_buffer, sizeof(tmp_buffer), "%s/%s/type", dir_path, interface); - if (error < 0) { - // snprintf error - SRPLG_LOG_ERR(PLUGIN_NAME, "%s: snprintf failed", __func__); - goto out; - } + int error = 0; + char tmp_buffer[PATH_MAX]; + FILE* fptr = NULL; + char tmp_val[4] = { 0 }; + + error = snprintf(tmp_buffer, sizeof(tmp_buffer), "%s/%s/type", dir_path, interface); + if (error < 0) { + // snprintf error + SRPLG_LOG_ERR(PLUGIN_NAME, "%s: snprintf failed", __func__); + goto out; + } - /* snprintf returns return the number of bytes that are written - reset error to 0 */ - error = 0; + /* snprintf returns return the number of bytes that are written - reset error to 0 */ + error = 0; - fptr = fopen((const char *) tmp_buffer, "r"); + fptr = fopen((const char*)tmp_buffer, "r"); - if (fptr != NULL) { - fgets(tmp_val, sizeof(tmp_val), fptr); + if (fptr != NULL) { + fgets(tmp_val, sizeof(tmp_val), fptr); - *val = atoi(tmp_val); + *val = atoi(tmp_val); - fclose(fptr); - } else { - SRPLG_LOG_ERR(PLUGIN_NAME, "%s: failed to open %s: %s", __func__, tmp_buffer, strerror(errno)); - error = -1; - goto out; - } + fclose(fptr); + } else { + SRPLG_LOG_ERR(PLUGIN_NAME, "%s: failed to open %s: %s", __func__, tmp_buffer, strerror(errno)); + error = -1; + goto out; + } out: - return error; + return error; } -static char *interfaces_get_interface_type(struct rtnl_link *link, char *name) +static char* interfaces_get_interface_type(struct rtnl_link* link, char* name) { int error = 0; - char *type = NULL; + char* type = NULL; type = rtnl_link_get_type(link); if (type == NULL) { @@ -106,28 +107,28 @@ static char *interfaces_get_interface_type(struct rtnl_link *link, char *name) * * get the type from: /sys/class/net//type */ - const char *path_to_sys = "/sys/class/net/"; + const char* path_to_sys = "/sys/class/net/"; int type_id = 0; SRPC_SAFE_CALL(read_from_sys_file(path_to_sys, name, &type_id), error_out); switch (type_id) { - case ARPHRD_ETHER: - type = "eth"; - break; - case ARPHRD_LOOPBACK: - type = "lo"; - break; - default: - SRPLG_LOG_ERR(PLUGIN_NAME, "%s: unkown type_id: %d", __func__, type_id); + case ARPHRD_ETHER: + type = "eth"; + break; + case ARPHRD_LOOPBACK: + type = "lo"; + break; + default: + SRPLG_LOG_ERR(PLUGIN_NAME, "%s: unkown type_id: %d", __func__, type_id); } } - + error_out: - return xstrdup(type); + return xstrdup(type); } -static uint8_t interfaces_get_interface_enabled(struct rtnl_link *link) +static uint8_t interfaces_get_interface_enabled(struct rtnl_link* link) { uint8_t enabled = rtnl_link_get_operstate(link); @@ -137,18 +138,18 @@ static uint8_t interfaces_get_interface_enabled(struct rtnl_link *link) */ if (IF_OPER_UP == enabled || IF_OPER_UNKNOWN == enabled) { enabled = interfaces_interface_enable_enabled; - } else if (IF_OPER_DOWN == enabled ) { + } else if (IF_OPER_DOWN == enabled) { enabled = interfaces_interface_enable_disabled; } - return enabled; + return enabled; } -static char *interfaces_get_interface_parent_interface(struct nl_cache *cache, struct rtnl_link *link) +static char* interfaces_get_interface_parent_interface(struct nl_cache* cache, struct rtnl_link* link) { int parent_index = 0; - char parent_buffer[IFNAMSIZ] = {0}; - char *parent_interface = NULL; + char parent_buffer[IFNAMSIZ] = { 0 }; + char* parent_interface = NULL; if (rtnl_link_is_vlan(link)) { parent_index = rtnl_link_get_link(link); @@ -159,14 +160,14 @@ static char *interfaces_get_interface_parent_interface(struct nl_cache *cache, s } /* TODO: outer tag, second id, tag - maybe refactor all to pass by reference, return error */ -static int interfaces_get_interface_vlan_id(struct rtnl_link *link, interfaces_interface_t *interface) +static int interfaces_get_interface_vlan_id(struct rtnl_link* link, interfaces_interface_t* interface) { - uint16_t *outer_vlan_id = &interface->encapsulation.dot1q_vlan.outer_tag.vlan_id; - char *first = NULL; - char *second = NULL; - + uint16_t* outer_vlan_id = &interface->encapsulation.dot1q_vlan.outer_tag.vlan_id; + char* first = NULL; + char* second = NULL; + if (rtnl_link_is_vlan(link)) { - *outer_vlan_id = (uint16_t) rtnl_link_vlan_get_id(link); + *outer_vlan_id = (uint16_t)rtnl_link_vlan_get_id(link); if (*outer_vlan_id <= 0) { SRPLG_LOG_ERR(PLUGIN_NAME, "%s: couldn't get vlan ID", __func__); return interfaces_load_failure; @@ -174,7 +175,7 @@ static int interfaces_get_interface_vlan_id(struct rtnl_link *link, interfaces_i /* check if vlan_id in name, if it is this is the QinQ interface, skip it */ first = strchr(interface->name, '.'); - second = strchr(first+1, '.'); + second = strchr(first + 1, '.'); if (second != 0) { return interfaces_load_continue; @@ -184,22 +185,22 @@ static int interfaces_get_interface_vlan_id(struct rtnl_link *link, interfaces_i return interfaces_load_success; } -static int interfaces_parse_link(interfaces_ctx_t *ctx, struct nl_sock *socket, struct nl_cache *cache, struct rtnl_link *link, interfaces_interface_t *interface) +static int interfaces_parse_link(interfaces_ctx_t* ctx, struct nl_sock* socket, struct nl_cache* cache, struct rtnl_link* link, interfaces_interface_t* interface) { int error = interfaces_load_success; - *interface = (interfaces_interface_t) {0}; + *interface = (interfaces_interface_t) { 0 }; SRPC_SAFE_CALL_PTR(interface->name, interfaces_get_interface_name(link), error_out); - + SRPC_SAFE_CALL_PTR(interface->description, interfaces_get_interface_description(ctx, interface->name), error_out); - + SRPC_SAFE_CALL_PTR(interface->type, interfaces_get_interface_type(link, interface->name), error_out); SRPC_SAFE_CALL_PTR(interface->parent_interface, interfaces_get_interface_parent_interface(cache, link), error_out); error = interfaces_get_interface_vlan_id(link, interface); if (error != interfaces_load_success) { - SRPLG_LOG_ERR(PLUGIN_NAME, "%s: vlan id error", __func__); + SRPLG_LOG_ERR(PLUGIN_NAME, "%s: vlan id error", __func__); goto out; // error_out would possibly change the error } @@ -225,11 +226,11 @@ static int interfaces_parse_link(interfaces_ctx_t *ctx, struct nl_sock *socket, return error; } -static int interfaces_add_link(interfaces_interface_hash_element_t **if_hash, interfaces_interface_t *interface) +static int interfaces_add_link(interfaces_interface_hash_element_t** if_hash, interfaces_interface_t* interface) { int error = 0; - - interfaces_interface_hash_element_t *new_if_hash_elem = interfaces_interface_hash_element_new(); + + interfaces_interface_hash_element_t* new_if_hash_elem = interfaces_interface_hash_element_new(); interfaces_interface_hash_element_set_name(&new_if_hash_elem, interface->name); SRPC_SAFE_CALL(interfaces_interface_hash_add_element(if_hash, new_if_hash_elem), error_out); @@ -251,81 +252,80 @@ static int interfaces_add_link(interfaces_interface_hash_element_t **if_hash, in goto out; error_out: out: - return error; + return error; } -static struct rtnl_link *interfaces_get_next_link(struct rtnl_link *link) +static struct rtnl_link* interfaces_get_next_link(struct rtnl_link* link) { - return (struct rtnl_link *) nl_cache_get_next((struct nl_object *) link); + return (struct rtnl_link*)nl_cache_get_next((struct nl_object*)link); } -static int interfaces_interfaces_worker(interfaces_ctx_t *ctx, struct nl_sock *socket, struct nl_cache *cache, interfaces_interface_hash_element_t **if_hash) +static int interfaces_interfaces_worker(interfaces_ctx_t* ctx, struct nl_sock* socket, struct nl_cache* cache, interfaces_interface_hash_element_t** if_hash) { int error = 0; - struct rtnl_link *link = NULL; - interfaces_interface_t interface = {0}; + struct rtnl_link* link = NULL; + interfaces_interface_t interface = { 0 }; - link = (struct rtnl_link *) nl_cache_get_first(cache); + link = (struct rtnl_link*)nl_cache_get_first(cache); while (link != NULL) { error = interfaces_parse_link(ctx, socket, cache, link, &interface); switch (error) { - case interfaces_load_success: - SRPC_SAFE_CALL(interfaces_add_link(if_hash, &interface), error_out); - break; - case interfaces_load_continue: - break; - default: - SRPLG_LOG_ERR(PLUGIN_NAME, "%s: error parsing link (%d)", __func__, error); - goto error_out; + case interfaces_load_success: + SRPC_SAFE_CALL(interfaces_add_link(if_hash, &interface), error_out); + break; + case interfaces_load_continue: + break; + default: + SRPLG_LOG_ERR(PLUGIN_NAME, "%s: error parsing link (%d)", __func__, error); + goto error_out; } - link = interfaces_get_next_link(link); - } + link = interfaces_get_next_link(link); + } goto out; error_out: error = -1; out: if (link != NULL) { - rtnl_link_put(link); - } + rtnl_link_put(link); + } return error; } -int interfaces_load_interface(interfaces_ctx_t* ctx, interfaces_interface_hash_element_t **if_hash) +int interfaces_load_interface(interfaces_ctx_t* ctx, interfaces_interface_hash_element_t** if_hash) { int error = 0; - struct nl_sock *socket = NULL; - struct nl_cache *cache = NULL; + struct nl_sock* socket = NULL; + struct nl_cache* cache = NULL; *if_hash = interfaces_interface_hash_new(); - socket = nl_socket_alloc(); - if (socket == NULL) { - SRPLG_LOG_ERR(PLUGIN_NAME, "nl_socket_alloc error: invalid socket"); - goto error_out; - } - + socket = nl_socket_alloc(); + if (socket == NULL) { + SRPLG_LOG_ERR(PLUGIN_NAME, "nl_socket_alloc error: invalid socket"); + goto error_out; + } + SRPC_SAFE_CALL(nl_connect(socket, NETLINK_ROUTE), error_out); SRPC_SAFE_CALL(rtnl_link_alloc_cache(socket, AF_UNSPEC, &cache), error_out); SRPC_SAFE_CALL(interfaces_interfaces_worker(ctx, socket, cache, if_hash), error_out); - - goto out; + + goto out; error_out: - error = -1; + error = -1; out: - if (socket != NULL) { - nl_socket_free(socket); - } + if (socket != NULL) { + nl_socket_free(socket); + } if (cache != NULL) { - nl_cache_free(cache); + nl_cache_free(cache); } return error; } - diff --git a/src/interfaces/src/plugin/data/interfaces/interface.c b/src/interfaces/src/plugin/data/interfaces/interface.c index 1491d701..e4425349 100644 --- a/src/interfaces/src/plugin/data/interfaces/interface.c +++ b/src/interfaces/src/plugin/data/interfaces/interface.c @@ -56,6 +56,10 @@ void interfaces_interface_hash_element_free(interfaces_interface_hash_element_t* free((*el)->interface.parent_interface); } + if ((*el)->interface.ipv4.address) { + INTERFACES_INTERFACE_LIST_FREE((*el)->interface.ipv4.address); + } + // element data free(*el); *el = NULL; diff --git a/src/interfaces/src/plugin/data/interfaces/interface/ipv4/address.c b/src/interfaces/src/plugin/data/interfaces/interface/ipv4/address.c index 82a1b0f7..210dd74b 100644 --- a/src/interfaces/src/plugin/data/interfaces/interface/ipv4/address.c +++ b/src/interfaces/src/plugin/data/interfaces/interface/ipv4/address.c @@ -1,7 +1,9 @@ #include "address.h" #include "plugin/types.h" #include "src/utlist.h" +#include #include +#include interfaces_interface_ipv4_address_element_t* interfaces_interface_ipv4_address_new(void) { diff --git a/src/interfaces/src/plugin/data/interfaces/interface/linked_list.h b/src/interfaces/src/plugin/data/interfaces/interface/linked_list.h index 28f1c92a..853345f0 100644 --- a/src/interfaces/src/plugin/data/interfaces/interface/linked_list.h +++ b/src/interfaces/src/plugin/data/interfaces/interface/linked_list.h @@ -19,19 +19,19 @@ (ll_ptr) = NULL; \ } while (0) -#define INTERFACES_INTERFACE_LIST_FREE(ll_ptr) \ - _Generic((ll_ptr), \ - interfaces_interfaces_interface_ipv4_address_element_t * \ - : interfaces_interface_ipv4_address_free \ - interfaces_interfaces_interface_ipv4_neighbor_element_t \ - * \ - : interfaces_interface_ipv4_neighbor_free \ - interfaces_interfaces_interface_ipv6_address_element_t \ - * \ - : interfaces_interface_ipv6_address_free \ - interfaces_interfaces_interface_ipv6_neighbor_element_t \ - * \ - : interfaces_interface_ipv6_neighbor_free)(&(ll_ptr)) +#define INTERFACES_INTERFACE_LIST_FREE(ll_ptr) \ + _Generic((ll_ptr), \ + interfaces_interface_ipv4_address_element_t * \ + : interfaces_interface_ipv4_address_free, \ + interfaces_interface_ipv4_neighbor_element_t \ + * \ + : interfaces_interface_ipv4_neighbor_free, \ + interfaces_interface_ipv6_address_element_t \ + * \ + : interfaces_interface_ipv6_address_free, \ + interfaces_interface_ipv6_neighbor_element_t \ + * \ + : interfaces_interface_ipv6_neighbor_free)(&ll_ptr) /* prepend since ordering doesn't matter - O(1) */ #define INTERFACES_INTERFACE_LIST_ADD_ELEMENT(ll_ptr, new_element_ptr) \ diff --git a/src/interfaces/src/plugin/data/interfaces/interface_state.c b/src/interfaces/src/plugin/data/interfaces/interface_state.c index cfacc597..426dff94 100644 --- a/src/interfaces/src/plugin/data/interfaces/interface_state.c +++ b/src/interfaces/src/plugin/data/interfaces/interface_state.c @@ -1,5 +1,6 @@ #include "interface_state.h" #include "src/uthash.h" +#include interfaces_interface_state_hash_element_t* interfaces_interface_state_hash_new(void) { diff --git a/src/interfaces/src/plugin/subscription/change.c b/src/interfaces/src/plugin/subscription/change.c index 8f2150ea..9872cf7d 100644 --- a/src/interfaces/src/plugin/subscription/change.c +++ b/src/interfaces/src/plugin/subscription/change.c @@ -3,6 +3,7 @@ #include "plugin/context.h" #include +#include #include #include diff --git a/src/interfaces/src/plugin/subscription/operational.c b/src/interfaces/src/plugin/subscription/operational.c index 9b76027e..9001b349 100644 --- a/src/interfaces/src/plugin/subscription/operational.c +++ b/src/interfaces/src/plugin/subscription/operational.c @@ -29,6 +29,8 @@ #include #include +#include + static struct rtnl_link* interfaces_get_current_link(interfaces_ctx_t* ctx, sr_session_ctx_t* session, const char* xpath); static int interfaces_extract_interface_name(sr_session_ctx_t* session, const char* xpath, char* buffer, size_t buffer_size); static int interfaces_extract_interface_address_ip(sr_session_ctx_t* session, const char* xpath, char* buffer, size_t buffer_size);