Skip to content

Commit 6525999

Browse files
committed
session UPDATE dynamic capability creation
Refs #608
1 parent 791c6f9 commit 6525999

1 file changed

Lines changed: 89 additions & 61 deletions

File tree

src/session.c

Lines changed: 89 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <netinet/in.h>
2222
#include <netinet/tcp.h>
2323
#include <pthread.h>
24+
#include <stdarg.h>
2425
#include <stdlib.h>
2526
#include <string.h>
2627
#include <sys/socket.h>
@@ -1224,6 +1225,10 @@ nc_add_cpblt(const char *capab, char ***cpblts, uint32_t *count)
12241225
}
12251226

12261227
(*cpblts)[*count] = strdup(capab);
1228+
if (!(*cpblts)[*count]) {
1229+
ERRMEM;
1230+
return -1;
1231+
}
12271232
++(*count);
12281233

12291234
/* terminating NULL */
@@ -1232,6 +1237,46 @@ nc_add_cpblt(const char *capab, char ***cpblts, uint32_t *count)
12321237
return 0;
12331238
}
12341239

1240+
/**
1241+
* @brief Append string to a string buffer.
1242+
*
1243+
* @param[in,out] str String to append to.
1244+
* @param[in,out] used Used bytes of @p str excluding the terminating 0 byte.
1245+
* @param[in,out] size Size of @p str.
1246+
* @param[in] app_format Format string to append.
1247+
* @param[in] ... Format string arguments.
1248+
* @return 0 on success,
1249+
* @return -1 on error.
1250+
*/
1251+
static int
1252+
nc_str_append(char **str, uint32_t *used, uint32_t *size, const char *app_format, ...)
1253+
{
1254+
va_list ap;
1255+
int r;
1256+
1257+
/* try to append */
1258+
va_start(ap, app_format);
1259+
r = vsnprintf(*str + *used, *size - *used, app_format, ap);
1260+
va_end(ap);
1261+
1262+
if (*used + r >= *size) {
1263+
/* enlarge */
1264+
*str = nc_realloc(*str, *used + r + 1);
1265+
NC_CHECK_ERRMEM_RET(!*str, -1);
1266+
1267+
*size = *used + r + 1;
1268+
1269+
/* append */
1270+
va_start(ap, app_format);
1271+
*used += vsnprintf(*str + *used, *size - *used, app_format, ap);
1272+
va_end(ap);
1273+
} else {
1274+
*used += r;
1275+
}
1276+
1277+
return 0;
1278+
}
1279+
12351280
/**
12361281
* @brief Get the server capabilities.
12371282
*
@@ -1245,15 +1290,11 @@ _nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version, int
12451290
{
12461291
char **cpblts;
12471292
const struct lys_module *mod;
1248-
const char *feat;
1249-
int features_count = 0, dev_count = 0, str_len, len;
1250-
uint32_t i, count;
1293+
uint32_t i, count, str_used = 0, str_size = 0;
12511294
LY_ARRAY_COUNT_TYPE v;
12521295
char *yl_content_id = NULL;
12531296
uint32_t wd_also_supported, wd_basic_mode;
1254-
1255-
#define NC_CPBLT_BUF_LEN 4096
1256-
char str[NC_CPBLT_BUF_LEN];
1297+
char *str = NULL;
12571298

12581299
NC_CHECK_ARG_RET(NULL, ctx, NULL);
12591300

@@ -1310,16 +1351,18 @@ _nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version, int
13101351
VRB(NULL, "with-defaults capability will not be advertised even though \"ietf-netconf-with-defaults\" "
13111352
"model is present, unknown basic-mode.");
13121353
} else {
1313-
strcpy(str, "urn:ietf:params:netconf:capability:with-defaults:1.0");
1354+
str_used = 0;
1355+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, "urn:ietf:params:netconf:capability:with-defaults:1.0"),
1356+
unlock_error);
13141357
switch (wd_basic_mode) {
13151358
case NC_WD_ALL:
1316-
strcat(str, "?basic-mode=report-all");
1359+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, "?basic-mode=report-all"), unlock_error);
13171360
break;
13181361
case NC_WD_TRIM:
1319-
strcat(str, "?basic-mode=trim");
1362+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, "?basic-mode=trim"), unlock_error);
13201363
break;
13211364
case NC_WD_EXPLICIT:
1322-
strcat(str, "?basic-mode=explicit");
1365+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, "?basic-mode=explicit"), unlock_error);
13231366
break;
13241367
default:
13251368
ERRINT;
@@ -1328,29 +1371,30 @@ _nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version, int
13281371

13291372
wd_also_supported = server_opts.wd_also_supported;
13301373
if (wd_also_supported) {
1331-
strcat(str, "&also-supported=");
1374+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, "&also-supported="), unlock_error);
13321375
if (wd_also_supported & NC_WD_ALL) {
1333-
strcat(str, "report-all,");
1376+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, "report-all,"), unlock_error);
13341377
}
13351378
if (wd_also_supported & NC_WD_ALL_TAG) {
1336-
strcat(str, "report-all-tagged,");
1379+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, "report-all-tagged,"), unlock_error);
13371380
}
13381381
if (wd_also_supported & NC_WD_TRIM) {
1339-
strcat(str, "trim,");
1382+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, "trim,"), unlock_error);
13401383
}
13411384
if (wd_also_supported & NC_WD_EXPLICIT) {
1342-
strcat(str, "explicit,");
1385+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, "explicit,"), unlock_error);
13431386
}
1344-
str[strlen(str) - 1] = '\0';
1387+
str[str_used] = '\0';
1388+
--str_used;
13451389

1346-
NC_CHECK_GOTO(nc_add_cpblt(str, &cpblts, &count), error);
1390+
NC_CHECK_GOTO(nc_add_cpblt(str, &cpblts, &count), unlock_error);
13471391
}
13481392
}
13491393
}
13501394

13511395
/* other capabilities */
13521396
for (i = 0; i < server_opts.capabilities_count; i++) {
1353-
NC_CHECK_GOTO(nc_add_cpblt(server_opts.capabilities[i], &cpblts, &count), error);
1397+
NC_CHECK_GOTO(nc_add_cpblt(server_opts.capabilities[i], &cpblts, &count), unlock_error);
13541398
}
13551399

13561400
/* models */
@@ -1379,14 +1423,18 @@ _nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version, int
13791423

13801424
if (!strcmp(mod->revision, "2019-01-04")) {
13811425
/* new one (capab defined in RFC 8526 section 2) */
1382-
sprintf(str, "urn:ietf:params:netconf:capability:yang-library:1.1?revision=%s&content-id=%s",
1383-
mod->revision, yl_content_id);
1384-
NC_CHECK_GOTO(nc_add_cpblt(str, &cpblts, &count), error);
1426+
str_used = 0;
1427+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size,
1428+
"urn:ietf:params:netconf:capability:yang-library:1.1?revision=%s&content-id=%s",
1429+
mod->revision, yl_content_id), unlock_error);
1430+
NC_CHECK_GOTO(nc_add_cpblt(str, &cpblts, &count), unlock_error);
13851431
} else {
13861432
/* old one (capab defined in RFC 7950 section 5.6.4) */
1387-
sprintf(str, "urn:ietf:params:netconf:capability:yang-library:1.0?revision=%s&module-set-id=%s",
1388-
mod->revision, yl_content_id);
1389-
NC_CHECK_GOTO(nc_add_cpblt(str, &cpblts, &count), error);
1433+
str_used = 0;
1434+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size,
1435+
"urn:ietf:params:netconf:capability:yang-library:1.0?revision=%s&module-set-id=%s",
1436+
mod->revision, yl_content_id), unlock_error);
1437+
NC_CHECK_GOTO(nc_add_cpblt(str, &cpblts, &count), unlock_error);
13901438
}
13911439
free(yl_content_id);
13921440
yl_content_id = NULL;
@@ -1396,58 +1444,37 @@ _nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version, int
13961444
continue;
13971445
}
13981446

1399-
str_len = sprintf(str, "%s?module=%s%s%s", mod->ns, mod->name, mod->revision ? "&revision=" : "",
1400-
mod->revision ? mod->revision : "");
1447+
str_used = 0;
1448+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, "%s?module=%s%s%s", mod->ns, mod->name,
1449+
mod->revision ? "&revision=" : "", mod->revision ? mod->revision : ""), unlock_error);
14011450

14021451
if (mod->compiled) {
1403-
features_count = 0;
14041452
LY_ARRAY_FOR(mod->compiled->features, v) {
1405-
feat = mod->compiled->features[v];
1406-
if (!features_count) {
1407-
strcat(str, "&features=");
1408-
str_len += 10;
1453+
if (!v) {
1454+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, "&features="), unlock_error);
1455+
} else {
1456+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, ","), unlock_error);
14091457
}
1410-
len = strlen(feat);
1411-
if (str_len + 1 + len >= NC_CPBLT_BUF_LEN) {
1412-
ERRINT;
1413-
break;
1414-
}
1415-
if (features_count) {
1416-
strcat(str, ",");
1417-
++str_len;
1418-
}
1419-
strcat(str, feat);
1420-
str_len += len;
1421-
features_count++;
1458+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, mod->compiled->features[v]), unlock_error);
14221459
}
14231460
}
14241461

1425-
if (mod->deviated_by) {
1426-
strcat(str, "&deviations=");
1427-
str_len += 12;
1428-
dev_count = 0;
1429-
LY_ARRAY_FOR(mod->deviated_by, v) {
1430-
len = strlen(mod->deviated_by[v]->name);
1431-
if (str_len + 1 + len >= NC_CPBLT_BUF_LEN) {
1432-
ERRINT;
1433-
break;
1434-
}
1435-
if (dev_count) {
1436-
strcat(str, ",");
1437-
++str_len;
1438-
}
1439-
strcat(str, mod->deviated_by[v]->name);
1440-
str_len += len;
1441-
dev_count++;
1462+
LY_ARRAY_FOR(mod->deviated_by, v) {
1463+
if (!v) {
1464+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, "&deviations="), unlock_error);
1465+
} else {
1466+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, ","), unlock_error);
14421467
}
1468+
NC_CHECK_GOTO(nc_str_append(&str, &str_used, &str_size, mod->deviated_by[v]->name), unlock_error);
14431469
}
14441470

1445-
NC_CHECK_GOTO(nc_add_cpblt(str, &cpblts, &count), error);
1471+
NC_CHECK_GOTO(nc_add_cpblt(str, &cpblts, &count), unlock_error);
14461472
}
14471473

14481474
/* HELLO UNLOCK */
14491475
nc_rwlock_unlock(&server_opts.hello_lock, __func__);
14501476

1477+
free(str);
14511478
return cpblts;
14521479

14531480
unlock_error:
@@ -1462,6 +1489,7 @@ _nc_server_get_cpblts_version(const struct ly_ctx *ctx, LYS_VERSION version, int
14621489
free(cpblts);
14631490
}
14641491
free(yl_content_id);
1492+
free(str);
14651493
return NULL;
14661494
}
14671495

0 commit comments

Comments
 (0)