Skip to content

Commit ab7f37f

Browse files
lePicimichalvasko
authored andcommitted
session server BUGFIX more accurate description of NETCONF-error
1 parent 762e3be commit ab7f37f

File tree

1 file changed

+158
-12
lines changed

1 file changed

+158
-12
lines changed

src/session_server.c

Lines changed: 158 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,6 +1400,96 @@ recv_rpc_check_msgid(struct nc_session *session, const struct lyd_node *envp)
14001400
return NC_MSG_RPC;
14011401
}
14021402

1403+
/**
1404+
* @brief Find lysc node mentioned in schema_path.
1405+
*
1406+
* @param[in] ctx libyang context.
1407+
* @param[in] ly_err last libyang error.
1408+
* @return lysc node.
1409+
*/
1410+
static const struct lysc_node *
1411+
nc_rpc_err_find_lysc_node(const struct ly_ctx *ctx, const struct ly_err_item *ly_err)
1412+
{
1413+
char *str, *last;
1414+
const struct lysc_node *cn;
1415+
1416+
if (!ly_err->schema_path) {
1417+
return NULL;
1418+
}
1419+
1420+
str = strdup(ly_err->schema_path);
1421+
if (!str) {
1422+
return NULL;
1423+
}
1424+
last = strrchr(str, '/');
1425+
if (strchr(last, '@')) {
1426+
/* ignore attribute part */
1427+
*last = '\0';
1428+
}
1429+
cn = lys_find_path(ctx, NULL, str, 0);
1430+
free(str);
1431+
1432+
return cn;
1433+
}
1434+
1435+
/**
1436+
* @brief Find the nth substring delimited by quotes.
1437+
*
1438+
* For example: abcd"ef"ghij"kl"mn -> index 0 is "ef", index 1 is "kl".
1439+
*
1440+
* @param[in] msg Input string with quoted substring.
1441+
* @param[in] index Number starting from 0 specifying the nth substring.
1442+
* @return Copied nth substring without quotes.
1443+
*/
1444+
static char *
1445+
nc_rpc_err_get_quoted_string(const char *msg, uint32_t index)
1446+
{
1447+
char *ret;
1448+
const char *start = NULL, *end = NULL, *iter, *tmp;
1449+
uint32_t quote_cnt = 0, last_quote;
1450+
1451+
assert(msg);
1452+
1453+
last_quote = (index + 1) * 2;
1454+
for (iter = msg; *iter; ++iter) {
1455+
if (*iter != '\"') {
1456+
continue;
1457+
}
1458+
/* updating the start and end pointers - swap */
1459+
tmp = end;
1460+
end = iter;
1461+
start = tmp;
1462+
if (++quote_cnt == last_quote) {
1463+
/* nth substring found */
1464+
break;
1465+
}
1466+
}
1467+
1468+
if (!start) {
1469+
return NULL;
1470+
}
1471+
1472+
/* Skip first quote */
1473+
++start;
1474+
/* Copy substring */
1475+
ret = strndup(start, end - start);
1476+
1477+
return ret;
1478+
}
1479+
1480+
/**
1481+
* @brief Check that the @p str starts with the @p prefix.
1482+
*
1483+
* @param[in] prefix Required prefix.
1484+
* @param[in] str Input string to check.
1485+
* @return True if @p str start with @p prefix otherwise False.
1486+
*/
1487+
static ly_bool
1488+
nc_strstarts(const char *prefix, const char *str)
1489+
{
1490+
return strncmp(str, prefix, strlen(prefix)) == 0;
1491+
}
1492+
14031493
/**
14041494
* @brief Prepare reply for rpc error.
14051495
*
@@ -1410,28 +1500,84 @@ recv_rpc_check_msgid(struct nc_session *session, const struct lyd_node *envp)
14101500
static struct nc_server_reply *
14111501
nc_server_prepare_rpc_err(struct nc_session *session, struct lyd_node *envp)
14121502
{
1413-
struct lyd_node *node;
1503+
struct lyd_node *reply = NULL;
1504+
const struct lysc_node *cn;
14141505
const struct ly_err_item *ly_err;
1506+
NC_ERR_TYPE errtype;
1507+
const char *attr;
1508+
char *str = NULL, *errmsg = NULL, *schema_path = NULL;
1509+
LY_ERR errcode;
14151510

1511+
/* envelope was not parsed */
14161512
if (!envp && (session->version != NC_VERSION_11)) {
14171513
return NULL;
14181514
}
1419-
14201515
ly_err = ly_err_last(session->ctx);
1421-
if (envp) {
1422-
/* at least the envelopes were parsed */
1423-
node = nc_err(session->ctx, NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
1424-
nc_err_set_msg(node, ly_err->msg, "en");
1425-
} else if (!strcmp("Missing XML namespace.", ly_err->msg)) {
1426-
node = nc_err(session->ctx, NC_ERR_MISSING_ATTR, NC_ERR_TYPE_RPC, "xmlns", "rpc");
1427-
nc_err_set_msg(node, ly_err->msg, "en");
1428-
} else {
1516+
if (!envp && !strcmp("Missing XML namespace.", ly_err->msg)) {
1517+
reply = nc_err(session->ctx, NC_ERR_MISSING_ATTR, NC_ERR_TYPE_RPC, "xmlns", "rpc");
1518+
goto cleanup;
1519+
} else if (!envp) {
14291520
/* completely malformed message, NETCONF version 1.1 defines sending error reply from
14301521
* the server (RFC 6241 sec. 3) */
1431-
node = nc_err(session->ctx, NC_ERR_MALFORMED_MSG);
1522+
reply = nc_err(session->ctx, NC_ERR_MALFORMED_MSG);
1523+
return nc_server_reply_err(reply);
14321524
}
1525+
/* at least the envelopes were parsed */
1526+
assert(envp);
1527+
1528+
/* store strings, to avoid overwriting ly_err */
1529+
errmsg = strdup(ly_err->msg);
1530+
if (!errmsg) {
1531+
reply = nc_err(session->ctx, NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
1532+
goto cleanup;
1533+
}
1534+
if (ly_err->schema_path) {
1535+
schema_path = strdup(ly_err->schema_path);
1536+
if (!schema_path) {
1537+
reply = nc_err(session->ctx, NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
1538+
goto cleanup;
1539+
}
1540+
}
1541+
errcode = ly_err->err;
1542+
1543+
/* find out in which layer the error occurred */
1544+
cn = nc_rpc_err_find_lysc_node(session->ctx, ly_err);
1545+
if (cn && ((cn->nodetype & LYS_RPC) || (cn->nodetype & LYS_INPUT))) {
1546+
errtype = NC_ERR_TYPE_PROT;
1547+
} else {
1548+
errtype = NC_ERR_TYPE_APP;
1549+
}
1550+
1551+
/* deciding which error to prepare */
1552+
if (cn && (nc_strstarts("Missing mandatory prefix", errmsg) ||
1553+
nc_strstarts("Unknown XML prefix", errmsg))) {
1554+
str = nc_rpc_err_get_quoted_string(errmsg, 1);
1555+
reply = str ? nc_err(session->ctx, NC_ERR_UNKNOWN_ATTR, errtype, str, cn->name) :
1556+
nc_err(session->ctx, NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
1557+
} else if (cn && nc_strstarts("Annotation definition for attribute", errmsg)) {
1558+
attr = strrchr(schema_path, ':') + 1;
1559+
reply = nc_err(session->ctx, NC_ERR_UNKNOWN_ATTR, errtype, attr, cn->name);
1560+
} else if (nc_strstarts("Invalid character sequence", errmsg)) {
1561+
reply = nc_err(session->ctx, NC_ERR_MALFORMED_MSG);
1562+
} else if (errcode == LY_EMEM) {
1563+
/* <error-tag>resource-denied</error-tag> */
1564+
reply = nc_err(session->ctx, NC_ERR_RES_DENIED, errtype);
1565+
} else {
1566+
/* prepare some generic error */
1567+
reply = nc_err(session->ctx, NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
1568+
}
1569+
1570+
cleanup:
1571+
nc_err_set_msg(reply, errmsg, "en");
1572+
1573+
/* clear for other errors */
1574+
ly_err_clean(session->ctx, NULL);
1575+
1576+
free(errmsg);
1577+
free(schema_path);
1578+
free(str);
14331579

1434-
return nc_server_reply_err(node);
1580+
return nc_server_reply_err(reply);
14351581
}
14361582

14371583
/* should be called holding the session RPC lock! IO lock will be acquired as needed

0 commit comments

Comments
 (0)