You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1030 lines
34 KiB

  1. Index: libyang-0.16-r3/CMakeLists.txt
  2. ===================================================================
  3. --- libyang-0.16-r3.orig/CMakeLists.txt
  4. +++ libyang-0.16-r3/CMakeLists.txt
  5. @@ -351,8 +351,8 @@ else()
  6. add_subdirectory(src/extensions)
  7. endif(ENABLE_STATIC)
  8. -# YANG user types plugins ("user_ipv4" is just an example, not installed by default)
  9. -set(USER_TYPE_LIST "user_date_and_time")
  10. +# YANG user types plugins
  11. +set(USER_TYPE_LIST "user_yang_types" "user_inet_types")
  12. if(ENABLE_STATIC)
  13. set(USER_TYPE_LIST_SIZE " 0 ")
  14. foreach(USER_TYPE ${USER_TYPE_LIST})
  15. Index: libyang-0.16-r3/src/parser.c
  16. ===================================================================
  17. --- libyang-0.16-r3.orig/src/parser.c
  18. +++ libyang-0.16-r3/src/parser.c
  19. @@ -1936,7 +1936,7 @@ lyp_parse_value(struct lys_type *type, c
  20. /* search user types in case this value is supposed to be stored in a custom way */
  21. if (store && type->der && type->der->module) {
  22. - c = lytype_store(type->der->module, type->der->name, *value_, val);
  23. + c = lytype_store(type->der->module, type->der->name, value_, val);
  24. if (c == -1) {
  25. goto error;
  26. } else if (!c) {
  27. Index: libyang-0.16-r3/src/parser.h
  28. ===================================================================
  29. --- libyang-0.16-r3.orig/src/parser.h
  30. +++ libyang-0.16-r3/src/parser.h
  31. @@ -258,11 +258,11 @@ struct lyext_plugin *ext_get_plugin(cons
  32. *
  33. * @param[in] mod Module of the type.
  34. * @param[in] type_name Type (typedef) name.
  35. - * @param[in] value_str Value to store as a string.
  36. + * @param[in,out] value_str Stored string value, can be overwritten by the user store callback.
  37. * @param[in,out] value Filled value to be overwritten by the user store callback.
  38. * @return 0 on successful storing, 1 if the type is not a user type, -1 on error.
  39. */
  40. -int lytype_store(const struct lys_module *mod, const char *type_name, const char *value_str, lyd_val *value);
  41. +int lytype_store(const struct lys_module *mod, const char *type_name, const char **value_str, lyd_val *value);
  42. /**
  43. * @brief Free a user type stored value.
  44. Index: libyang-0.16-r3/src/plugins.c
  45. ===================================================================
  46. --- libyang-0.16-r3.orig/src/plugins.c
  47. +++ libyang-0.16-r3/src/plugins.c
  48. @@ -574,7 +574,7 @@ lytype_find(const char *module, const ch
  49. }
  50. int
  51. -lytype_store(const struct lys_module *mod, const char *type_name, const char *value_str, lyd_val *value)
  52. +lytype_store(const struct lys_module *mod, const char *type_name, const char **value_str, lyd_val *value)
  53. {
  54. struct lytype_plugin_list *p;
  55. char *err_msg = NULL;
  56. @@ -583,9 +583,9 @@ lytype_store(const struct lys_module *mo
  57. p = lytype_find(mod->name, mod->rev_size ? mod->rev[0].date : NULL, type_name);
  58. if (p) {
  59. - if (p->store_clb(type_name, value_str, value, &err_msg)) {
  60. + if (p->store_clb(mod->ctx, type_name, value_str, value, &err_msg)) {
  61. if (!err_msg) {
  62. - if (asprintf(&err_msg, "Failed to store value \"%s\" of user type \"%s\".", value_str, type_name) == -1) {
  63. + if (asprintf(&err_msg, "Failed to store value \"%s\" of user type \"%s\".", *value_str, type_name) == -1) {
  64. LOGMEM(mod->ctx);
  65. return -1;
  66. }
  67. Index: libyang-0.16-r3/src/tree_data.c
  68. ===================================================================
  69. --- libyang-0.16-r3.orig/src/tree_data.c
  70. +++ libyang-0.16-r3/src/tree_data.c
  71. @@ -5476,7 +5476,7 @@ _lyd_dup_node(const struct lyd_node *nod
  72. }
  73. if (sleaf->type.der && sleaf->type.der->module) {
  74. - r = lytype_store(sleaf->type.der->module, sleaf->type.der->name, new_leaf->value_str, &new_leaf->value);
  75. + r = lytype_store(sleaf->type.der->module, sleaf->type.der->name, &new_leaf->value_str, &new_leaf->value);
  76. if (r == -1) {
  77. goto error;
  78. } else if (!r) {
  79. Index: libyang-0.16-r3/src/user_types.h
  80. ===================================================================
  81. --- libyang-0.16-r3.orig/src/user_types.h
  82. +++ libyang-0.16-r3/src/user_types.h
  83. @@ -33,13 +33,15 @@ extern "C" {
  84. * This callback should overwrite the value stored in \p value using some custom encoding. Be careful,
  85. * if the type is #LY_TYPE_BITS, the bits must be freed before overwritting the union value.
  86. *
  87. + * @param[in] ctx libyang ctx to enable correct manipulation with values that are in the dictionary.
  88. * @param[in] type_name Name of the type being stored.
  89. - * @param[in] value_str String value to be stored.
  90. + * @param[in,out] value_str String value to be stored.
  91. * @param[in,out] value Value union for the value to be stored in (already is but in the standard way).
  92. * @param[out] err_msg Can be filled on error. If not, a generic error message will be printed.
  93. * @return 0 on success, non-zero if an error occured and the value could not be stored for any reason.
  94. */
  95. -typedef int (*lytype_store_clb)(const char *type_name, const char *value_str, lyd_val *value, char **err_msg);
  96. +typedef int (*lytype_store_clb)(struct ly_ctx *ctx, const char *type_name, const char **value_str, lyd_val *value,
  97. + char **err_msg);
  98. struct lytype_plugin_list {
  99. const char *module; /**< Name of the module where the type is defined. */
  100. Index: libyang-0.16-r3/src/user_types/user_inet_types.c
  101. ===================================================================
  102. --- /dev/null
  103. +++ libyang-0.16-r3/src/user_types/user_inet_types.c
  104. @@ -0,0 +1,235 @@
  105. +/**
  106. + * @file user_inet_types.c
  107. + * @author Michal Vasko <mvasko@cesnet.cz>
  108. + * @brief ietf-inet-types typedef conversion to canonical format
  109. + *
  110. + * Copyright (c) 2018 CESNET, z.s.p.o.
  111. + *
  112. + * This source code is licensed under BSD 3-Clause License (the "License").
  113. + * You may not use this file except in compliance with the License.
  114. + * You may obtain a copy of the License at
  115. + *
  116. + * https://opensource.org/licenses/BSD-3-Clause
  117. + */
  118. +
  119. +#define _GNU_SOURCE
  120. +
  121. +#include <stdlib.h>
  122. +#include <string.h>
  123. +#include <errno.h>
  124. +#include <arpa/inet.h>
  125. +
  126. +#include "../user_types.h"
  127. +
  128. +#ifdef __GNUC__
  129. +# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
  130. +#else
  131. +# define UNUSED(x) UNUSED_ ## x
  132. +#endif
  133. +
  134. +static char *
  135. +convert_ipv6_addr(const char *ipv6_addr, char **err_msg)
  136. +{
  137. + char buf[sizeof(struct in6_addr)], *str;
  138. +
  139. + str = malloc(INET6_ADDRSTRLEN);
  140. + if (!str) {
  141. + *err_msg = NULL;
  142. + return NULL;
  143. + }
  144. +
  145. + if (!inet_pton(AF_INET6, ipv6_addr, buf)) {
  146. + asprintf(err_msg, "Failed to convert IPv6 address \"%s\".", ipv6_addr);
  147. + free(str);
  148. + return NULL;
  149. + }
  150. +
  151. + if (!inet_ntop(AF_INET6, buf, str, INET6_ADDRSTRLEN)) {
  152. + asprintf(err_msg, "Failed to convert IPv6 address (%s).", strerror(errno));
  153. + free(str);
  154. + return NULL;
  155. + }
  156. +
  157. + return str;
  158. +}
  159. +
  160. +static int
  161. +ip_store_clb(struct ly_ctx *ctx, const char *UNUSED(type_name), const char **value_str, lyd_val *value, char **err_msg)
  162. +{
  163. + char *ptr, *ipv6_addr, *result, *tmp;
  164. +
  165. + if (!strchr(*value_str, ':')) {
  166. + /* not an IPv6 address */
  167. + return 0;
  168. + }
  169. +
  170. + if ((ptr = strchr(*value_str, '%'))) {
  171. + /* there is a zone index */
  172. + ipv6_addr = strndup(*value_str, ptr - *value_str);
  173. + } else {
  174. + ipv6_addr = (char *)*value_str;
  175. + }
  176. +
  177. + /* convert to canonical format */
  178. + result = convert_ipv6_addr(ipv6_addr, err_msg);
  179. + if (ptr) {
  180. + free(ipv6_addr);
  181. + }
  182. +
  183. + /* failure */
  184. + if (!result) {
  185. + return 1;
  186. + }
  187. +
  188. + if (strncmp(*value_str, result, strlen(result))) {
  189. + /* some conversion took place, update the value */
  190. + if (ptr) {
  191. + tmp = result;
  192. + if (asprintf(&result, "%s%s", tmp, ptr) == -1) {
  193. + free(tmp);
  194. + *err_msg = NULL;
  195. + return 1;
  196. + }
  197. + free(tmp);
  198. + }
  199. +
  200. + lydict_remove(ctx, *value_str);
  201. + *value_str = lydict_insert_zc(ctx, result);
  202. + value->string = *value_str;
  203. + } else {
  204. + free(result);
  205. + }
  206. +
  207. + return 0;
  208. +}
  209. +
  210. +static int
  211. +ipv4_prefix_store_clb(struct ly_ctx *ctx, const char *UNUSED(type_name), const char **value_str, lyd_val *value, char **err_msg)
  212. +{
  213. + char *pref_str, *ptr, *result;
  214. + int result_len, i, j, num;
  215. + unsigned long int pref;
  216. +
  217. + pref_str = strchr(*value_str, '/');
  218. + if (!pref_str) {
  219. + asprintf(err_msg, "Invalid IPv4 prefix \"%s\".", *value_str);
  220. + return 1;
  221. + }
  222. +
  223. + pref = strtoul(pref_str + 1, &ptr, 10);
  224. + if (ptr[0]) {
  225. + asprintf(err_msg, "Invalid IPv4 prefix \"%s\".", *value_str);
  226. + return 1;
  227. + }
  228. +
  229. + result = malloc(INET_ADDRSTRLEN + 3);
  230. + if (!result) {
  231. + *err_msg = NULL;
  232. + return 1;
  233. + }
  234. +
  235. + /* generate ip prefix mask */
  236. + result_len = 0;
  237. + for (i = 0; i < 4; ++i) {
  238. + num = 0;
  239. + for (j = 0; (j < 8) && pref; ++j) {
  240. + num += (1 << j);
  241. + --pref;
  242. + }
  243. +
  244. + result_len += sprintf(result + result_len, "%s%d", i ? "." : "", num);
  245. + }
  246. +
  247. + /* add the prefix */
  248. + result_len += sprintf(result + result_len, "%s", pref_str);
  249. +
  250. + if (strcmp(result, *value_str)) {
  251. + /* some conversion took place, update the value */
  252. + lydict_remove(ctx, *value_str);
  253. + *value_str = lydict_insert_zc(ctx, result);
  254. + value->string = *value_str;
  255. + } else {
  256. + free(result);
  257. + }
  258. +
  259. + return 0;
  260. +}
  261. +
  262. +static int
  263. +ipv6_prefix_store_clb(struct ly_ctx *ctx, const char *UNUSED(type_name), const char **value_str, lyd_val *value, char **err_msg)
  264. +{
  265. + char *pref_str, *ptr, *result;
  266. + int result_len, i, j, num;
  267. + unsigned long int pref;
  268. +
  269. + pref_str = strchr(*value_str, '/');
  270. + if (!pref_str) {
  271. + asprintf(err_msg, "Invalid IPv6 prefix \"%s\".", *value_str);
  272. + return 1;
  273. + }
  274. +
  275. + pref = strtoul(pref_str + 1, &ptr, 10);
  276. + if (ptr[0]) {
  277. + asprintf(err_msg, "Invalid IPv6 prefix \"%s\".", *value_str);
  278. + return 1;
  279. + }
  280. +
  281. + result = malloc(INET6_ADDRSTRLEN + 4);
  282. + if (!result) {
  283. + *err_msg = NULL;
  284. + return 1;
  285. + }
  286. +
  287. + /* generate ipv6 prefix mask */
  288. + result_len = 0;
  289. + for (i = 0; i < 8; ++i) {
  290. + num = 0;
  291. + for (j = 0; (j < 16) && pref; ++j) {
  292. + num += (1 << j);
  293. + --pref;
  294. + }
  295. +
  296. + result_len += sprintf(result + result_len, "%s%x", i ? ":" : "", num);
  297. +
  298. + if (!pref && (i < 6)) {
  299. + /* shorten ending zeros */
  300. + result_len += sprintf(result + result_len, "::");
  301. + break;
  302. + }
  303. + }
  304. +
  305. + /* add the prefix */
  306. + result_len += sprintf(result + result_len, "%s", pref_str);
  307. +
  308. + if (strcmp(result, *value_str)) {
  309. + /* some conversion took place, update the value */
  310. + lydict_remove(ctx, *value_str);
  311. + *value_str = lydict_insert_zc(ctx, result);
  312. + value->string = *value_str;
  313. + } else {
  314. + free(result);
  315. + }
  316. +
  317. + return 0;
  318. +}
  319. +
  320. +static int
  321. +ip_prefix_store_clb(struct ly_ctx *ctx, const char *type_name, const char **value_str, lyd_val *value, char **err_msg)
  322. +{
  323. + if (strchr(*value_str, ':')) {
  324. + return ipv6_prefix_store_clb(ctx, type_name, value_str, value, err_msg);
  325. + }
  326. + return ipv4_prefix_store_clb(ctx, type_name, value_str, value, err_msg);
  327. +}
  328. +
  329. +/* Name of this array must match the file name! */
  330. +struct lytype_plugin_list user_inet_types[] = {
  331. + {"ietf-inet-types", "2013-07-15", "ip-address", ip_store_clb, NULL},
  332. + {"ietf-inet-types", "2013-07-15", "ipv6-address", ip_store_clb, NULL},
  333. + {"ietf-inet-types", "2013-07-15", "ip-address-no-zone", ip_store_clb, NULL},
  334. + {"ietf-inet-types", "2013-07-15", "ipv6-address-no-zone", ip_store_clb, NULL},
  335. + {"ietf-inet-types", "2013-07-15", "ip-prefix", ip_prefix_store_clb, NULL},
  336. + {"ietf-inet-types", "2013-07-15", "ipv4-prefix", ipv4_prefix_store_clb, NULL},
  337. + {"ietf-inet-types", "2013-07-15", "ipv6-prefix", ipv6_prefix_store_clb, NULL},
  338. + {NULL, NULL, NULL, NULL, NULL} /* terminating item */
  339. +};
  340. Index: libyang-0.16-r3/src/user_types/user_ipv4.c
  341. ===================================================================
  342. --- libyang-0.16-r3.orig/src/user_types/user_ipv4.c
  343. +++ /dev/null
  344. @@ -1,42 +0,0 @@
  345. -/**
  346. - * @file user_ipv4.c
  347. - * @author Michal Vasko <mvasko@cesnet.cz>
  348. - * @brief Example implementation of an ipv4-address as a user type
  349. - *
  350. - * Copyright (c) 2018 CESNET, z.s.p.o.
  351. - *
  352. - * This source code is licensed under BSD 3-Clause License (the "License").
  353. - * You may not use this file except in compliance with the License.
  354. - * You may obtain a copy of the License at
  355. - *
  356. - * https://opensource.org/licenses/BSD-3-Clause
  357. - */
  358. -
  359. -#include <stdlib.h>
  360. -#include <string.h>
  361. -#include <arpa/inet.h>
  362. -#include <sys/socket.h>
  363. -
  364. -#include "../user_types.h"
  365. -
  366. -static int
  367. -ipv4_store_clb(const char *type_name, const char *value_str, lyd_val *value, char **err_msg)
  368. -{
  369. - value->ptr = malloc(sizeof(struct in_addr));
  370. - if (!value->ptr) {
  371. - return 1;
  372. - }
  373. -
  374. - if (inet_pton(AF_INET, value_str, value->ptr) != 1) {
  375. - free(value->ptr);
  376. - return 1;
  377. - }
  378. - return 0;
  379. -}
  380. -
  381. -/* Name of this array must match the file name! */
  382. -struct lytype_plugin_list user_ipv4[] = {
  383. - {"ietf-inet-types", "2013-07-15", "ipv4-address", ipv4_store_clb, free},
  384. - {"ietf-inet-types", "2013-07-15", "ipv4-address-no-zone", ipv4_store_clb, free},
  385. - {NULL, NULL, NULL, NULL, NULL} /* terminating item */
  386. -};
  387. Index: libyang-0.16-r3/src/user_types/user_yang_types.c
  388. ===================================================================
  389. --- /dev/null
  390. +++ libyang-0.16-r3/src/user_types/user_yang_types.c
  391. @@ -0,0 +1,303 @@
  392. +/**
  393. + * @file user_yang_types.c
  394. + * @author Michal Vasko <mvasko@cesnet.cz>
  395. + * @brief ietf-yang-types typedef validation and conversion to canonical format
  396. + *
  397. + * Copyright (c) 2018 CESNET, z.s.p.o.
  398. + *
  399. + * This source code is licensed under BSD 3-Clause License (the "License").
  400. + * You may not use this file except in compliance with the License.
  401. + * You may obtain a copy of the License at
  402. + *
  403. + * https://opensource.org/licenses/BSD-3-Clause
  404. + */
  405. +#define _GNU_SOURCE
  406. +
  407. +#include <stdlib.h>
  408. +#include <string.h>
  409. +#include <stdint.h>
  410. +#include <errno.h>
  411. +#include <time.h>
  412. +#include <ctype.h>
  413. +
  414. +#include "../user_types.h"
  415. +
  416. +#ifdef __GNUC__
  417. +# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
  418. +#else
  419. +# define UNUSED(x) UNUSED_ ## x
  420. +#endif
  421. +
  422. +static const char *gmt_offsets[] = {
  423. + "+00:00",
  424. + "+00:20",
  425. + "+00:30",
  426. + "+01:00",
  427. + "+01:24",
  428. + "+01:30",
  429. + "+02:00",
  430. + "+02:30",
  431. + "+03:00",
  432. + "+03:30",
  433. + "+04:00",
  434. + "+04:30",
  435. + "+04:51",
  436. + "+05:00",
  437. + "+05:30",
  438. + "+05:40",
  439. + "+05:45",
  440. + "+06:00",
  441. + "+06:30",
  442. + "+07:00",
  443. + "+07:20",
  444. + "+07:30",
  445. + "+08:00",
  446. + "+08:30",
  447. + "+08:45",
  448. + "+09:00",
  449. + "+09:30",
  450. + "+09:45",
  451. + "+10:00",
  452. + "+10:30",
  453. + "+11:00",
  454. + "+11:30",
  455. + "+12:00",
  456. + "+12:45",
  457. + "+13:00",
  458. + "+13:45",
  459. + "+14:00",
  460. + "-00:00",
  461. + "-00:44",
  462. + "-01:00",
  463. + "-02:00",
  464. + "-02:30",
  465. + "-03:00",
  466. + "-03:30",
  467. + "-04:00",
  468. + "-04:30",
  469. + "-05:00",
  470. + "-06:00",
  471. + "-07:00",
  472. + "-08:00",
  473. + "-08:30",
  474. + "-09:00",
  475. + "-09:30",
  476. + "-10:00",
  477. + "-10:30",
  478. + "-11:00",
  479. + "-12:00",
  480. +};
  481. +
  482. +static int
  483. +date_and_time_store_clb(struct ly_ctx *UNUSED(ctx), const char *UNUSED(type_name), const char **value_str,
  484. + lyd_val *UNUSED(value), char **err_msg)
  485. +{
  486. + struct tm tm, tm2;
  487. + uint32_t i, j, k;
  488. + const char *val_str = *value_str;
  489. + int ret;
  490. +
  491. + /* \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[\+\-]\d{2}:\d{2})
  492. + * 2018-03-21T09:11:05(.55785...)(Z|+02:00) */
  493. + memset(&tm, 0, sizeof tm);
  494. + i = 0;
  495. +
  496. + /* year */
  497. + tm.tm_year = atoi(val_str + i);
  498. + /* if there was some invalid number, it will either be discovered in the loop below or by mktime() */
  499. + tm.tm_year -= 1900;
  500. + for (j = i + 4; i < j; ++i) {
  501. + if (!isdigit(val_str[i])) {
  502. + ret = asprintf(err_msg, "Invalid character '%c'[%d] in date-and-time value \"%s\", a digit expected.", val_str[i], i, val_str);
  503. + goto error;
  504. + }
  505. + }
  506. + if (val_str[i] != '-') {
  507. + ret = asprintf(err_msg, "Invalid character '%c'[%d] in date-and-time value \"%s\", '-' expected.", val_str[i], i, val_str);
  508. + goto error;
  509. + }
  510. + ++i;
  511. +
  512. + /* month */
  513. + tm.tm_mon = atoi(val_str + i);
  514. + tm.tm_mon -= 1;
  515. + for (j = i + 2; i < j; ++i) {
  516. + if (!isdigit(val_str[i])) {
  517. + ret = asprintf(err_msg, "Invalid character '%c'[%d] in date-and-time value \"%s\", a digit expected.", val_str[i], i, val_str);
  518. + goto error;
  519. + }
  520. + }
  521. + if (val_str[i] != '-') {
  522. + ret = asprintf(err_msg, "Invalid character '%c'[%d] in date-and-time value \"%s\", '-' expected.", val_str[i], i, val_str);
  523. + goto error;
  524. + }
  525. + ++i;
  526. +
  527. + /* day */
  528. + tm.tm_mday = atoi(val_str + i);
  529. + for (j = i + 2; i < j; ++i) {
  530. + if (!isdigit(val_str[i])) {
  531. + ret = asprintf(err_msg, "Invalid character '%c'[%d] in date-and-time value \"%s\", a digit expected.", val_str[i], i, val_str);
  532. + goto error;
  533. + }
  534. + }
  535. + if (val_str[i] != 'T') {
  536. + ret = asprintf(err_msg, "Invalid character '%c'[%d] in date-and-time value \"%s\", 'T' expected.", val_str[i], i, val_str);
  537. + goto error;
  538. + }
  539. + ++i;
  540. +
  541. + /* hours */
  542. + tm.tm_hour = atoi(val_str + i);
  543. + for (j = i + 2; i < j; ++i) {
  544. + if (!isdigit(val_str[i])) {
  545. + ret = asprintf(err_msg, "Invalid character '%c'[%d] in date-and-time value \"%s\", a digit expected.", val_str[i], i, val_str);
  546. + goto error;
  547. + }
  548. + }
  549. + if (val_str[i] != ':') {
  550. + ret = asprintf(err_msg, "Invalid character '%c'[%d] in date-and-time value \"%s\", ':' expected.", val_str[i], i, val_str);
  551. + goto error;
  552. + }
  553. + ++i;
  554. +
  555. + /* minutes */
  556. + tm.tm_min = atoi(val_str + i);
  557. + for (j = i + 2; i < j; ++i) {
  558. + if (!isdigit(val_str[i])) {
  559. + ret = asprintf(err_msg, "Invalid character '%c'[%d] in date-and-time value \"%s\", a digit expected.", val_str[i], i, val_str);
  560. + goto error;
  561. + }
  562. + }
  563. + if (val_str[i] != ':') {
  564. + ret = asprintf(err_msg, "Invalid character '%c'[%d] in date-and-time value \"%s\", ':' expected.", val_str[i], i, val_str);
  565. + goto error;
  566. + }
  567. + ++i;
  568. +
  569. + /* seconds */
  570. + tm.tm_sec = atoi(val_str + i);
  571. + for (j = i + 2; i < j; ++i) {
  572. + if (!isdigit(val_str[i])) {
  573. + ret = asprintf(err_msg, "Invalid character '%c'[%d] in date-and-time value \"%s\", a digit expected.", val_str[i], i, val_str);
  574. + goto error;
  575. + }
  576. + }
  577. + if ((val_str[i] != '.') && (val_str[i] != 'Z') && (val_str[i] != '+') && (val_str[i] != '-')) {
  578. + ret = asprintf(err_msg, "Invalid character '%c'[%d] in date-and-time value \"%s\", '.', 'Z', '+', or '-' expected.",
  579. + val_str[i], i, val_str);
  580. + goto error;
  581. + }
  582. +
  583. + /* validate using mktime() */
  584. + tm2 = tm;
  585. + if (mktime(&tm) == -1) {
  586. + ret = asprintf(err_msg, "Checking date-and-time value \"%s\" failed (%s).", val_str, strerror(errno));
  587. + goto error;
  588. + }
  589. + /* we now have correctly filled the remaining values, use them */
  590. + memcpy(((char *)&tm2) + (6 * sizeof(int)), ((char *)&tm) + (6 * sizeof(int)), sizeof(struct tm) - (6 * sizeof(int)));
  591. + /* back it up again */
  592. + tm = tm2;
  593. + /* let mktime() correct date & time with having the other values correct now */
  594. + if (mktime(&tm) == -1) {
  595. + ret = asprintf(err_msg, "Checking date-and-time value \"%s\" failed (%s).", val_str, strerror(errno));
  596. + goto error;
  597. + }
  598. + /* detect changes in the filled values */
  599. + if (memcmp(&tm, &tm2, 6 * sizeof(int))) {
  600. + ret = asprintf(err_msg, "Checking date-and-time value \"%s\" failed, canonical date and time is \"%04d-%02d-%02dT%02d:%02d:%02d\".",
  601. + val_str, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
  602. + goto error;
  603. + }
  604. +
  605. + /* tenth of a second */
  606. + if (val_str[i] == '.') {
  607. + ++i;
  608. + if (!isdigit(val_str[i])) {
  609. + ret = asprintf(err_msg, "Invalid character '%c'[%d] in date-and-time value \"%s\", a digit expected.", val_str[i], i, val_str);
  610. + goto error;
  611. + }
  612. + do {
  613. + ++i;
  614. + } while (isdigit(val_str[i]));
  615. + }
  616. +
  617. + switch (val_str[i]) {
  618. + case 'Z':
  619. + /* done */
  620. + break;
  621. + case '+':
  622. + case '-':
  623. + /* timezone shift */
  624. + k = sizeof gmt_offsets / sizeof *gmt_offsets;
  625. + for (j = 0; j < k ; ++j) {
  626. + if (!strncmp(val_str + i, gmt_offsets[j], 6)) {
  627. + break;
  628. + }
  629. + }
  630. + if (j == k) {
  631. + ret = asprintf(err_msg, "Invalid timezone \"%.6s\" in date-and-time value \"%s\".", val_str + i, val_str);
  632. + goto error;
  633. + }
  634. + i += 5;
  635. + break;
  636. + default:
  637. + ret = asprintf(err_msg, "Invalid character '%c'[%d] in date-and-time value \"%s\", 'Z', '+', or '-' expected.", val_str[i], i, val_str);
  638. + goto error;
  639. + }
  640. +
  641. + /* no other characters expected */
  642. + ++i;
  643. + if (val_str[i]) {
  644. + ret = asprintf(err_msg, "Invalid character '%c'[%d] in date-and-time value \"%s\", no characters expected.", val_str[i], i, val_str);
  645. + goto error;
  646. + }
  647. +
  648. + /* validation succeeded and we do not want to change how it is stored */
  649. + return 0;
  650. +
  651. +error:
  652. + if (ret == -1) {
  653. + err_msg = NULL;
  654. + }
  655. + return 1;
  656. +}
  657. +
  658. +static int
  659. +hex_string_store_clb(struct ly_ctx *ctx, const char *UNUSED(type_name), const char **value_str, lyd_val *value, char **err_msg)
  660. +{
  661. + char *str;
  662. + uint32_t i, len;
  663. +
  664. + str = strdup(*value_str);
  665. + if (!str) {
  666. + /* we can hardly allocate an error message */
  667. + *err_msg = NULL;
  668. + return 1;
  669. + }
  670. +
  671. + len = strlen(str);
  672. + for (i = 0; i < len; ++i) {
  673. + if ((str[i] >= 'A') && (str[i] <= 'Z')) {
  674. + /* make it lowercase (canonical format) */
  675. + str[i] += 32;
  676. + }
  677. + }
  678. +
  679. + /* update the value correctly */
  680. + lydict_remove(ctx, *value_str);
  681. + *value_str = lydict_insert_zc(ctx, str);
  682. + value->string = *value_str;
  683. + return 0;
  684. +}
  685. +
  686. +/* Name of this array must match the file name! */
  687. +struct lytype_plugin_list user_yang_types[] = {
  688. + {"ietf-yang-types", "2013-07-15", "date-and-time", date_and_time_store_clb, NULL},
  689. + {"ietf-yang-types", "2013-07-15", "phys-address", hex_string_store_clb, NULL},
  690. + {"ietf-yang-types", "2013-07-15", "mac-address", hex_string_store_clb, NULL},
  691. + {"ietf-yang-types", "2013-07-15", "hex-string", hex_string_store_clb, NULL},
  692. + {"ietf-yang-types", "2013-07-15", "uuid", hex_string_store_clb, NULL},
  693. + {NULL, NULL, NULL, NULL, NULL} /* terminating item */
  694. +};
  695. Index: libyang-0.16-r3/tests/CMakeLists.txt
  696. ===================================================================
  697. --- libyang-0.16-r3.orig/tests/CMakeLists.txt
  698. +++ libyang-0.16-r3/tests/CMakeLists.txt
  699. @@ -7,7 +7,7 @@ set(CMAKE_MACOSX_RPATH TRUE)
  700. get_filename_component(TESTS_DIR "${CMAKE_SOURCE_DIR}/tests" REALPATH)
  701. set(api_tests test_libyang test_tree_schema test_xml test_dict test_tree_data test_tree_data_dup test_tree_data_merge test_xpath test_xpath_1.1 test_diff)
  702. -set(data_tests test_data_initialization test_leafref_remove test_instid_remove test_keys test_autodel test_when test_when_1.1 test_must_1.1 test_defaults test_emptycont test_unique test_mandatory test_json test_parse_print test_values test_metadata test_yangtypes_xpath test_yang_data test_unknown_element)
  703. +set(data_tests test_data_initialization test_leafref_remove test_instid_remove test_keys test_autodel test_when test_when_1.1 test_must_1.1 test_defaults test_emptycont test_unique test_mandatory test_json test_parse_print test_values test_metadata test_yangtypes_xpath test_yang_data test_unknown_element test_user_types)
  704. set(schema_yin_tests test_print_transform)
  705. set(schema_tests test_ietf test_augment test_deviation test_refine test_typedef test_import test_include test_feature test_conformance test_leaflist test_status test_printer test_invalid)
  706. if(CMAKE_BUILD_TYPE MATCHES debug)
  707. Index: libyang-0.16-r3/tests/api/test_libyang.c
  708. ===================================================================
  709. --- libyang-0.16-r3.orig/tests/api/test_libyang.c
  710. +++ libyang-0.16-r3/tests/api/test_libyang.c
  711. @@ -1245,7 +1245,13 @@ test_ly_get_loaded_plugins(void **state)
  712. }
  713. assert_non_null(plugins[i]);
  714. for (i = 0; plugins[i]; ++i) {
  715. - if (!strcmp(plugins[i], "user_date_and_time")) {
  716. + if (!strcmp(plugins[i], "user_yang_types")) {
  717. + break;
  718. + }
  719. + }
  720. + assert_non_null(plugins[i]);
  721. + for (i = 0; plugins[i]; ++i) {
  722. + if (!strcmp(plugins[i], "user_inet_types")) {
  723. break;
  724. }
  725. }
  726. Index: libyang-0.16-r3/tests/data/files/user-types.yang
  727. ===================================================================
  728. --- /dev/null
  729. +++ libyang-0.16-r3/tests/data/files/user-types.yang
  730. @@ -0,0 +1,61 @@
  731. +module user-types {
  732. + namespace "urn:user-types";
  733. + prefix ut;
  734. +
  735. + import ietf-yang-types {
  736. + prefix yang;
  737. + }
  738. +
  739. + import ietf-inet-types {
  740. + prefix inet;
  741. + }
  742. +
  743. +
  744. + leaf yang1 {
  745. + type yang:date-and-time;
  746. + }
  747. +
  748. + leaf yang2 {
  749. + type yang:phys-address;
  750. + }
  751. +
  752. + leaf yang3 {
  753. + type yang:mac-address;
  754. + }
  755. +
  756. + leaf yang4 {
  757. + type yang:hex-string;
  758. + }
  759. +
  760. + leaf yang5 {
  761. + type yang:uuid;
  762. + }
  763. +
  764. + leaf inet1 {
  765. + type inet:ip-address;
  766. + }
  767. +
  768. + leaf inet2 {
  769. + type inet:ipv6-address;
  770. + }
  771. +
  772. + leaf inet3 {
  773. + type inet:ip-address-no-zone;
  774. + }
  775. +
  776. + leaf inet4 {
  777. + type inet:ipv6-address-no-zone;
  778. + }
  779. +
  780. + leaf inet5 {
  781. + type inet:ip-prefix;
  782. + }
  783. +
  784. + leaf inet6 {
  785. + type inet:ipv4-prefix;
  786. + }
  787. +
  788. + leaf inet7 {
  789. + type inet:ipv6-prefix;
  790. + }
  791. +}
  792. Index: libyang-0.16-r3/tests/data/test_user_types.c
  793. ===================================================================
  794. --- /dev/null
  795. +++ libyang-0.16-r3/tests/data/test_user_types.c
  796. @@ -0,0 +1,226 @@
  797. +/**
  798. + * @file test_user_types.c
  799. + * @author Michal Vasko <mvasko@cesnet.cz>
  800. + * @brief Cmocka tests for libyang internal user types.
  801. + *
  802. + * Copyright (c) 2018 CESNET, z.s.p.o.
  803. + *
  804. + * This source code is licensed under BSD 3-Clause License (the "License").
  805. + * You may not use this file except in compliance with the License.
  806. + * You may obtain a copy of the License at
  807. + *
  808. + * https://opensource.org/licenses/BSD-3-Clause
  809. + */
  810. +
  811. +#include <stdio.h>
  812. +#include <stdlib.h>
  813. +#include <setjmp.h>
  814. +#include <stdarg.h>
  815. +#include <cmocka.h>
  816. +
  817. +#include "tests/config.h"
  818. +#include "libyang.h"
  819. +
  820. +struct state {
  821. + struct ly_ctx *ctx;
  822. + const struct lys_module *mod;
  823. + struct lyd_node *dt;
  824. +};
  825. +
  826. +static int
  827. +setup_f(void **state)
  828. +{
  829. + struct state *st;
  830. +
  831. + (*state) = st = calloc(1, sizeof *st);
  832. + if (!st) {
  833. + fprintf(stderr, "Memory allocation error");
  834. + return -1;
  835. + }
  836. +
  837. + /* libyang context */
  838. + st->ctx = ly_ctx_new(TESTS_DIR"/data/files", 0);
  839. + if (!st->ctx) {
  840. + fprintf(stderr, "Failed to create context.\n");
  841. + goto error;
  842. + }
  843. +
  844. + st->mod = ly_ctx_load_module(st->ctx, "user-types", NULL);
  845. + if (!st->mod) {
  846. + fprintf(stderr, "Failed to load schema.\n");
  847. + goto error;
  848. + }
  849. +
  850. + return 0;
  851. +
  852. +error:
  853. + ly_ctx_destroy(st->ctx, NULL);
  854. + free(st);
  855. + (*state) = NULL;
  856. +
  857. + return -1;
  858. +}
  859. +
  860. +static int
  861. +teardown_f(void **state)
  862. +{
  863. + struct state *st = (*state);
  864. +
  865. + lyd_free_withsiblings(st->dt);
  866. + ly_ctx_destroy(st->ctx, NULL);
  867. + free(st);
  868. + (*state) = NULL;
  869. +
  870. + return 0;
  871. +}
  872. +
  873. +static void
  874. +test_yang_types(void **state)
  875. +{
  876. + struct state *st = (struct state *)*state;
  877. +
  878. + /* date-and-time */
  879. + st->dt = lyd_new_leaf(NULL, st->mod, "yang1", "2005-05-25T23:15:15.88888Z");
  880. + assert_non_null(st->dt);
  881. + lyd_free_withsiblings(st->dt);
  882. +
  883. + st->dt = lyd_new_leaf(NULL, st->mod, "yang1", "2005-05-31T23:15:15-08:00");
  884. + assert_non_null(st->dt);
  885. + lyd_free_withsiblings(st->dt);
  886. +
  887. + st->dt = lyd_new_leaf(NULL, st->mod, "yang1", "2005-05-31T23:15:15.-08:00");
  888. + assert_null(st->dt);
  889. +
  890. + st->dt = lyd_new_leaf(NULL, st->mod, "yang1", "2005-02-29T23:15:15-08:00");
  891. + assert_null(st->dt);
  892. +
  893. + /* phys-address */
  894. + st->dt = lyd_new_leaf(NULL, st->mod, "yang2", "aa:bb:cc:dd");
  895. + assert_non_null(st->dt);
  896. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "aa:bb:cc:dd");
  897. + lyd_free_withsiblings(st->dt);
  898. +
  899. + st->dt = lyd_new_leaf(NULL, st->mod, "yang2", "AA:BB:1D:2F:CA:52");
  900. + assert_non_null(st->dt);
  901. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "aa:bb:1d:2f:ca:52");
  902. + lyd_free_withsiblings(st->dt);
  903. +
  904. + /* mac-address */
  905. + st->dt = lyd_new_leaf(NULL, st->mod, "yang3", "12:34:56:78:9A:BC");
  906. + assert_non_null(st->dt);
  907. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "12:34:56:78:9a:bc");
  908. + lyd_free_withsiblings(st->dt);
  909. +
  910. + /* hex-string */
  911. + st->dt = lyd_new_leaf(NULL, st->mod, "yang4", "AB:CD:eF:fE:dc:Ba:Ab");
  912. + assert_non_null(st->dt);
  913. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "ab:cd:ef:fe:dc:ba:ab");
  914. + lyd_free_withsiblings(st->dt);
  915. +
  916. + /* uuid */
  917. + st->dt = lyd_new_leaf(NULL, st->mod, "yang5", "12AbCDef-3456-58cd-9ABC-8796cdACdfEE");
  918. + assert_non_null(st->dt);
  919. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "12abcdef-3456-58cd-9abc-8796cdacdfee");
  920. +}
  921. +
  922. +static void
  923. +test_inet_types(void **state)
  924. +{
  925. + struct state *st = (struct state *)*state;
  926. +
  927. + /* ip-address */
  928. + st->dt = lyd_new_leaf(NULL, st->mod, "inet1", "192.168.0.1");
  929. + assert_non_null(st->dt);
  930. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "192.168.0.1");
  931. + lyd_free_withsiblings(st->dt);
  932. +
  933. + st->dt = lyd_new_leaf(NULL, st->mod, "inet1", "192.168.0.1%12");
  934. + assert_non_null(st->dt);
  935. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "192.168.0.1%12");
  936. + lyd_free_withsiblings(st->dt);
  937. +
  938. + st->dt = lyd_new_leaf(NULL, st->mod, "inet1", "2008:15:0:0:0:0:feAC:1");
  939. + assert_non_null(st->dt);
  940. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "2008:15::feac:1");
  941. + lyd_free_withsiblings(st->dt);
  942. +
  943. + /* ipv6-address */
  944. + st->dt = lyd_new_leaf(NULL, st->mod, "inet2", "FAAC:21:011:Da85::87:daaF%1");
  945. + assert_non_null(st->dt);
  946. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "faac:21:11:da85::87:daaf%1");
  947. + lyd_free_withsiblings(st->dt);
  948. +
  949. + /* ip-address-no-zone */
  950. + st->dt = lyd_new_leaf(NULL, st->mod, "inet3", "127.0.0.1");
  951. + assert_non_null(st->dt);
  952. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "127.0.0.1");
  953. + lyd_free_withsiblings(st->dt);
  954. +
  955. + st->dt = lyd_new_leaf(NULL, st->mod, "inet3", "0:00:000:0000:000:00:0:1");
  956. + assert_non_null(st->dt);
  957. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "::1");
  958. + lyd_free_withsiblings(st->dt);
  959. +
  960. + /* ipv6-address-no-zone */
  961. + st->dt = lyd_new_leaf(NULL, st->mod, "inet4", "A:B:c:D:e:f:1:0");
  962. + assert_non_null(st->dt);
  963. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "a:b:c:d:e:f:1:0");
  964. + lyd_free_withsiblings(st->dt);
  965. +
  966. + /* ip-prefix */
  967. + st->dt = lyd_new_leaf(NULL, st->mod, "inet5", "12.1.58.4/1");
  968. + assert_non_null(st->dt);
  969. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "1.0.0.0/1");
  970. + lyd_free_withsiblings(st->dt);
  971. +
  972. + st->dt = lyd_new_leaf(NULL, st->mod, "inet5", "12.1.58.4/24");
  973. + assert_non_null(st->dt);
  974. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "255.255.255.0/24");
  975. + lyd_free_withsiblings(st->dt);
  976. +
  977. + st->dt = lyd_new_leaf(NULL, st->mod, "inet5", "2000:A:B:C:D:E:f:a/16");
  978. + assert_non_null(st->dt);
  979. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "ffff::/16");
  980. + lyd_free_withsiblings(st->dt);
  981. +
  982. + /* ipv4-prefix */
  983. + st->dt = lyd_new_leaf(NULL, st->mod, "inet6", "0.1.58.4/32");
  984. + assert_non_null(st->dt);
  985. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "255.255.255.255/32");
  986. + lyd_free_withsiblings(st->dt);
  987. +
  988. + st->dt = lyd_new_leaf(NULL, st->mod, "inet6", "12.1.58.4/8");
  989. + assert_non_null(st->dt);
  990. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "255.0.0.0/8");
  991. + lyd_free_withsiblings(st->dt);
  992. +
  993. + /* ipv6-prefix */
  994. + st->dt = lyd_new_leaf(NULL, st->mod, "inet7", "::C:D:E:f:a/112");
  995. + assert_non_null(st->dt);
  996. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0/112");
  997. + lyd_free_withsiblings(st->dt);
  998. +
  999. + st->dt = lyd_new_leaf(NULL, st->mod, "inet7", "::C:D:E:f:a/110");
  1000. + assert_non_null(st->dt);
  1001. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "ffff:ffff:ffff:ffff:ffff:ffff:3fff:0/110");
  1002. + lyd_free_withsiblings(st->dt);
  1003. +
  1004. + st->dt = lyd_new_leaf(NULL, st->mod, "inet7", "::C:D:E:f:a/96");
  1005. + assert_non_null(st->dt);
  1006. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "ffff:ffff:ffff:ffff:ffff:ffff::/96");
  1007. + lyd_free_withsiblings(st->dt);
  1008. +
  1009. + st->dt = lyd_new_leaf(NULL, st->mod, "inet7", "::C:D:E:f:a/55");
  1010. + assert_non_null(st->dt);
  1011. + assert_string_equal(((struct lyd_node_leaf_list *)st->dt)->value_str, "ffff:ffff:ffff:7f::/55");
  1012. +}
  1013. +
  1014. +int main(void)
  1015. +{
  1016. + const struct CMUnitTest tests[] = {
  1017. + cmocka_unit_test_setup_teardown(test_yang_types, setup_f, teardown_f),
  1018. + cmocka_unit_test_setup_teardown(test_inet_types, setup_f, teardown_f),
  1019. + };
  1020. +
  1021. + return cmocka_run_group_tests(tests, NULL, NULL);
  1022. +}