Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions apps/cli/cli_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,59 @@ dbxml_body(cxobj *xbot,
return retval;
}

/*! Special handling of identityref:s whose body may be: <namespace prefix>:<id>
*
* Ensure the namespace is declared if it exists in YANG
* @param[in] x
* @param[in] arg
* @retval 0 OK
* @retval -1 Error
*/
int
identityref_add_ns(cxobj *x,
void *arg)
{
int retval = -1;
yang_stmt *yspec = (yang_stmt *)arg;
yang_stmt *y;
yang_stmt *yrestype; /* resolved type */
char *restype; /* resolved type */
char *origtype = NULL; /* original type */
char *pf = NULL;
yang_stmt *yns;
char *ns = NULL;

if ((y = xml_spec(x)) != NULL &&
(yang_keyword_get(y) == Y_LEAF ||
yang_keyword_get(y) == Y_LEAF_LIST)){
if (yang_type_get(y, &origtype, &yrestype, NULL, NULL, NULL, NULL, NULL) < 0)
goto done;
restype = yrestype?yang_argument_get(yrestype):NULL;
if (strcmp(restype, "identityref") == 0){
if (nodeid_split(xml_body(x), &pf, NULL) < 0)
goto done;
// search if already defined
if (pf != NULL){
if (xml2ns(x, pf, &ns) < 0)
goto done;
if (ns == NULL &&
(yns = yang_find_module_by_prefix_yspec(yspec, pf)) != NULL){
if ((ns = yang_find_mynamespace(yns)) != NULL)
if (xmlns_set(x, pf, ns) < 0)
goto done;
}
}
}
}
retval = 0;
done:
if (origtype)
free(origtype);
if (pf)
free(pf);
return retval;
}

/*! Given a top-level yspec and mountpoint xpath compute api-path
*
* Manipulate top-level and a mountpoint:
Expand Down
2 changes: 1 addition & 1 deletion apps/cli/cli_generate.c
Original file line number Diff line number Diff line change
Expand Up @@ -750,4 +750,4 @@ yang2cli_init(clixon_handle h)
retval = 0;
done:
return retval;
}
}
29 changes: 27 additions & 2 deletions apps/restconf/restconf_err.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,15 +364,40 @@ api_return_err0(clixon_handle h,
{
int retval = -1;
cxobj *xe;
int created_err = 0;
cxobj *xnew = NULL;
cbuf *cb = NULL;

clixon_debug(CLIXON_DBG_RESTCONF, "");
if ((xe = xml_find_type(xerr, NULL, "rpc-error", CX_ELMNT)) == NULL){
clixon_err(OE_XML, EINVAL, "Expected xml on the form <rpc-error>..");
goto done;
/* Log what we actually got to ease debugging */
if (xerr && (cb = cbuf_new()) != NULL){
/* Best effort dump of unexpected error payload */
clixon_xml2cbuf(cb, xerr, 0, pretty, NULL, -1, 0);
clixon_err(OE_XML, EINVAL, "Expected xml on the form <rpc-error>.. Payload:\"%s\"",
cbuf_get(cb));
}
else
clixon_err(OE_XML, EINVAL, "Expected xml on the form <rpc-error>..");
/* Fall back to a generic operation-failed rpc-error so we can return
* a proper RESTCONF error instead of aborting the connection.
*/
if (netconf_operation_failed_xml(xerr ? &xerr : &xnew,
"application",
"restconf internal error: missing rpc-error") < 0)
goto done;
created_err = 1;
if ((xe = xml_find_type(xerr ? xerr : xnew, NULL, "rpc-error", CX_ELMNT)) == NULL)
goto done;
}
if (api_return_err(h, req, xe, pretty, media, code) < 0)
goto done;
retval = 0;
done:
if (cb)
cbuf_free(cb);
/* Free synthesized container if caller did not supply one */
if (created_err && xerr == NULL && xnew)
xml_free(xnew);
return retval;
}
27 changes: 21 additions & 6 deletions apps/restconf/restconf_methods_get.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,17 +146,32 @@ api_data_get2(clixon_handle h,
restconf_apipath_mount_cb, h, NULL, &y, &xerr)) < 0)
goto done;
if (ret == 0){ /* validation failed */
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
clixon_err(OE_RESTCONF, EINVAL,
"api_data_get2: api_path2xml_mnt validation failed pi=%d path:%s xerr:%s",
pi, api_path, xerr ? "set" : "NULL");
/* If no rpc-error was provided, continue and let the xpath translation
* try to handle the path instead of aborting the request.
*/
if (xerr == NULL)
ret = 1;
else {
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
}
}
/* Translate api-path to xpath: xpath (cbpath) and namespace context (nsc) */
if ((ret = api_path2xpath(api_path, yspec, &xpath, &nsc, &xerr)) < 0)
goto done;
if (ret == 0){ /* validation failed */
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
clixon_err(OE_RESTCONF, EINVAL, "api_data_get2: api_path2xpath validation failed pi=%d path:%s xerr:%s", pi, api_path, xerr ? "set" : "NULL");
if (xerr == NULL)
ret = 1;
else {
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
goto done;
goto ok;
}
}

/* Ad-hoc method to determine json pagination request:
Expand Down
15 changes: 12 additions & 3 deletions apps/restconf/restconf_native.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ restconf_stream_data_new(restconf_conn *rc,
memset(sd, 0, sizeof(restconf_stream_data));
sd->sd_stream_id = stream_id;
sd->sd_fd = -1;
sd->sd_freed = 0;
if ((sd->sd_inbuf = cbuf_new()) == NULL){
clixon_err(OE_UNIX, errno, "cbuf_new");
goto done;
Expand Down Expand Up @@ -153,6 +154,9 @@ restconf_stream_find(restconf_conn *rc,
int
restconf_stream_free(restconf_stream_data *sd)
{
if (sd->sd_freed)
return 0;
sd->sd_freed = 1;
if (sd->sd_fd != -1) {
close(sd->sd_fd);
}
Expand Down Expand Up @@ -197,6 +201,7 @@ restconf_conn_new(clixon_handle h,
memset(rc, 0, sizeof(restconf_conn));
rc->rc_h = h;
rc->rc_s = s;
rc->rc_closed = 0;
rc->rc_callhome = rsock->rs_callhome;
rc->rc_socket = rsock;
INSQ(rc, rsock->rs_conns);
Expand All @@ -208,7 +213,7 @@ restconf_conn_new(clixon_handle h,
*
* @param[in] rc restconf connection
*/
static int
static int __attribute__((unused))
restconf_conn_free(restconf_conn *rc)
{
int retval = -1;
Expand Down Expand Up @@ -1109,6 +1114,12 @@ restconf_close_ssl_socket(restconf_conn *rc,
int ret;

clixon_debug(CLIXON_DBG_RESTCONF, "%s", callfn);
/* restconf_close_ssl_socket can be invoked along multiple error/close paths.
* If a connection is already being torn down, bail out to avoid double free.
*/
if (rc->rc_closed)
return 0;
rc->rc_closed = 1;
if (rc->rc_ssl != NULL){
if (!dontshutdown &&
(ret = SSL_shutdown(rc->rc_ssl)) < 0){
Expand Down Expand Up @@ -1138,8 +1149,6 @@ restconf_close_ssl_socket(restconf_conn *rc,
}
if (restconf_connection_close1(rc) < 0)
goto done;
if (restconf_conn_free(rc) < 0)
goto done;
retval = 0;
done:
clixon_debug(CLIXON_DBG_RESTCONF, "retval:%d", retval);
Expand Down
2 changes: 2 additions & 0 deletions apps/restconf/restconf_native.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ typedef struct {
void *sd_req; /* Lib-specific request */
int sd_upgrade2; /* Upgrade to http/2 */
uint8_t *sd_settings2; /* Settings for upgrade to http/2 request */
int sd_freed; /* Guard against double free */
} restconf_stream_data;

typedef struct restconf_socket restconf_socket;
Expand All @@ -109,6 +110,7 @@ typedef struct restconf_conn {
int rc_proto_d1; /* parsed version digit 1 */
int rc_proto_d2; /* parsed version digit 2 */
int rc_s; /* Connection socket */
int rc_closed; /* Set after close to avoid double free */
clixon_handle rc_h; /* Clixon handle */
SSL *rc_ssl; /* Structure for SSL connection */
restconf_stream_data *rc_streams; /* List of http/2 session streams */
Expand Down
11 changes: 10 additions & 1 deletion lib/src/clixon_autocli_generate.c
Original file line number Diff line number Diff line change
Expand Up @@ -1495,7 +1495,16 @@ yang2cli_uses(clixon_handle h,
if (ys_grouping_resolve(ys, prefix, argument, &ygrouping) < 0)
goto done;
if (ygrouping == NULL){
clixon_err(OE_YANG, 0, "grouping %s not found in \n", yang_argument_get(ys));
yang_stmt *yerrmod = ys_module(ys);
const char *modname = NULL;

if (yerrmod == NULL)
yerrmod = yang_mymodule_get(ys);
if (yerrmod)
modname = yang_argument_get(yerrmod);
clixon_err(OE_YANG, 0, "grouping %s not found in %s",
yang_argument_get(ys),
modname?modname:"<unknown>");
goto done;
}
if ((cbtree = cbuf_new()) == NULL){
Expand Down
17 changes: 17 additions & 0 deletions lib/src/clixon_xml_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -1507,6 +1507,23 @@ yang_check_when_xpath(cxobj *xn,
if (x && xpath){
if ((nr = xpath_vec_bool(x, nsc, "%s", xpath)) < 0)
goto done;
if (nr == 0){
char *xpath_raw = NULL;
cvec *nsc_raw = NULL;
cxobj *xraw = NULL;

if (yang_when_xpath_get(yn, &xpath_raw, &nsc_raw) < 0)
goto done;
if (xpath_raw && nsc_raw){
xraw = xn ? xn : x;
if ((nr = xpath_vec_bool(xraw, nsc_raw, "%s", xpath_raw)) < 0){
xml_nsctx_free(nsc_raw);
goto done;
}
}
if (nsc_raw)
xml_nsctx_free(nsc_raw);
}
}
if (nrp)
*nrp = nr;
Expand Down
43 changes: 41 additions & 2 deletions lib/src/clixon_xpath_eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,22 @@ xp_eval_step(xp_ctx *xc0,
case A_ATTRIBUTE: /* principal node type is attribute */
break;
case A_CHILD:
if (nodetest &&
nodetest->xs_type == XP_NODE_FN &&
nodetest->xs_int == XPATHFN_TEXT){
/* Clixon stores leaf text content directly on the parent node.
* When text() is requested, return the parent nodes that have body
* content so downstream functions operate on their string values.
*/
for (i=0; i<xc->xc_size; i++){
xv = xc->xc_nodeset[i];
if (xml_body(xv) == NULL)
continue;
if (cxvec_append(xv, &vec, &veclen) < 0)
goto done;
}
break;
}
if (xc->xc_descendant){
for (i=0; i<xc->xc_size; i++){
xv = xc->xc_nodeset[i];
Expand Down Expand Up @@ -1009,7 +1025,30 @@ xp_relop(xp_ctx *xc1,
}
break;
case XT_STRING:
xr->xc_bool = (strcmp(xc1->xc_string, xc2->xc_string)==0);
switch (op){
case XO_EQ:
xr->xc_bool = (strcmp(xc1->xc_string, xc2->xc_string)==0);
break;
case XO_NE:
xr->xc_bool = (strcmp(xc1->xc_string, xc2->xc_string)!=0);
break;
case XO_GE:
xr->xc_bool = (strcmp(xc1->xc_string, xc2->xc_string)>=0);
break;
case XO_LE:
xr->xc_bool = (strcmp(xc1->xc_string, xc2->xc_string)<=0);
break;
case XO_LT:
xr->xc_bool = (strcmp(xc1->xc_string, xc2->xc_string)<0);
break;
case XO_GT:
xr->xc_bool = (strcmp(xc1->xc_string, xc2->xc_string)>0);
break;
default:
clixon_err(OE_XML, 0, "Operator %s not supported for string/string comparison", clicon_int2str(xpopmap,op));
goto done;
break;
}
break;
} /* switch xc1 */
}
Expand Down Expand Up @@ -1382,8 +1421,8 @@ xp_eval(xp_ctx *xc,
clixon_err(OE_XML, EFAULT, "XPath function not implemented: %s", xs->xs_s0);
goto done;
break;
}
}
}
break;
default:
break;
Expand Down
6 changes: 4 additions & 2 deletions lib/src/clixon_xpath_parse.l
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ ncname {namestart}{namechar}*
<TOKEN0>".." { return DOUBLEDOT; }
<TOKEN0>:: { BEGIN(TOKEN2); return DOUBLECOLON; /* axisname */ }
<TOKEN0>[(\[] { BEGIN(TOKEN2); return *yytext; }
<TOKEN0>[)\]\.,/:|] { return *yytext; }
<TOKEN0>\/ { BEGIN(TOKEN2); return *yytext; }
<TOKEN0>[)\]\.,:|] { return *yytext; }
<TOKEN0>and { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
<TOKEN0>or { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
<TOKEN0>div { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
Expand Down Expand Up @@ -158,7 +159,8 @@ ncname {namestart}{namechar}*
<TOKEN2><<EOF>> { return X_EOF; }
<TOKEN2>".." { BEGIN(TOKEN0); return DOUBLEDOT; }
<TOKEN2>:: { BEGIN(TOKEN0); return DOUBLECOLON; /* axisname */ }
<TOKEN2>[()\[\]\.,/:|] { BEGIN(TOKEN0); return *yytext; }
<TOKEN2>\/ { BEGIN(TOKEN2); return *yytext; }
<TOKEN2>[()\[\]\.,:|] { BEGIN(TOKEN0); return *yytext; }
<TOKEN2>and { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
<TOKEN2>or { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
<TOKEN2>div { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
Expand Down
6 changes: 5 additions & 1 deletion lib/src/clixon_xpath_parse.y
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,11 @@ xp_primary_function(clixon_xpath_yacc *xpy,
}
fn = ret;
switch (fn){
case XPATHFN_TRANSLATE:
/* Always treat translate() as implemented so the parser never
* downgrades it when optional NYI fallbacks are disabled.
*/
break;
case XPATHFN_ENUM_VALUE: /* Group of NOT IMPLEMENTED xpath functions */
case XPATHFN_LAST:
case XPATHFN_ID:
Expand Down Expand Up @@ -291,7 +296,6 @@ xp_primary_function(clixon_xpath_yacc *xpy,
case XPATHFN_SUBSTRING_AFTER:
case XPATHFN_SUBSTRING:
case XPATHFN_STRING_LENGTH:
case XPATHFN_TRANSLATE:
case XPATHFN_BOOLEAN:
case XPATHFN_NOT:
case XPATHFN_TRUE:
Expand Down
5 changes: 5 additions & 0 deletions lib/src/clixon_xpath_yang.c
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,11 @@ xp_yang_eval(xp_yang_ctx *xy,
(*xyr)->xy_node = (*xyr)->xy_initial;
goto ok;
break;
case XPATHFN_TRANSLATE:
if ((*xyr = xy_dup(xy)) == NULL)
goto done;
goto ok;
break;
default:
clixon_err(OE_XML, 0, "Function %s invalid for path-arg", xptree->xs_s0);
goto done;
Expand Down
Loading