From: Vincent Bernat Date: Sat, 21 Jan 2012 20:56:20 +0000 (+0100) Subject: marshal: allow to specify null-terminated strings X-Git-Tag: 0.6.0~67 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=da781141251683440ac809b5f16ec69ceda2396c;p=thirdparty%2Flldpd.git marshal: allow to specify null-terminated strings --- diff --git a/src/marshal.c b/src/marshal.c index fa62abd4..6dabdcba 100644 --- a/src/marshal.c +++ b/src/marshal.c @@ -23,6 +23,12 @@ struct marshal_serialized { unsigned char object[0]; }; +struct marshal_info marshal_info__string = { + .name = "null string", + .size = 0, + .pointers = {{ .mi = NULL }}, +}; + /* List of already seen pointers */ struct ref { TAILQ_ENTRY(ref) next; @@ -51,7 +57,13 @@ _marshal_serialize(struct marshal_info *mi, void *unserialized, void **input, return 0; } - size_t len = sizeof(struct marshal_serialized) + (skip?0:mi->size); + /* Handle special cases. */ + int size = mi->size; + if (!strcmp(mi->name, "null string")) + size = strlen((char *)unserialized) + 1; + + /* Allocate serialized structure */ + size_t len = sizeof(struct marshal_serialized) + (skip?0:size); struct marshal_serialized *serialized = calloc(1, len); if (!serialized) { LLOG_WARNX("unable to allocate memory to serialize structure %s", @@ -73,7 +85,7 @@ _marshal_serialize(struct marshal_info *mi, void *unserialized, void **input, /* First, serialize the main structure */ if (!skip) - memcpy(serialized->object, unserialized, mi->size); + memcpy(serialized->object, unserialized, size); /* Then, serialize inner structures */ struct marshal_subinfo *current; @@ -193,15 +205,28 @@ _marshal_unserialize(struct marshal_info *mi, void *buffer, size_t len, void **o TAILQ_INIT(pointers); } + /* Special cases */ + int size = mi->size; + if (!strcmp(mi->name, "null string")) { + size = strnlen((char *)serialized->object, + len - sizeof(struct marshal_serialized)) + 1; + if (size == len - sizeof(struct marshal_serialized) + 1) { + LLOG_WARNX("data to deserialize contains a string too long"); + total_len = 0; + goto unmarshal_error; + } + total_len += size; + } + /* First, the main structure */ if (!skip) { - if ((*output = marshal_alloc(pointers, mi->size, serialized->orig)) == NULL) { + if ((*output = marshal_alloc(pointers, size, serialized->orig)) == NULL) { LLOG_WARNX("unable to allocate memory to unserialize structure %s", mi->name); total_len = 0; goto unmarshal_error; } - memcpy(*output, serialized->object, mi->size); + memcpy(*output, serialized->object, size); } /* Then, each substructure */ diff --git a/src/marshal.h b/src/marshal.h index 55e0a095..20086039 100644 --- a/src/marshal.h +++ b/src/marshal.h @@ -21,6 +21,7 @@ struct marshal_info; enum marshal_subinfo_kind { pointer, substruct, + string, }; #define MARSHAL_INFO_POINTER 1 #define MARSHAL_INFO_SUB 2 @@ -34,6 +35,8 @@ struct marshal_info { size_t size; /* Size of the structure */ struct marshal_subinfo pointers[]; /* Pointer to other structures */ }; +/* Special case for strings */ +extern struct marshal_info marshal_info__string; /* Declare a new marshal_info struct named after the type we want to marshal. The marshalled type has to be a structure. */ @@ -48,6 +51,7 @@ struct marshal_info { .mi = &marshal_info_##subtype }, #define MARSHAL_POINTER(...) MARSHAL_ADD(pointer, ##__VA_ARGS__) #define MARSHAL_SUBSTRUCT(...) MARSHAL_ADD(substruct, ##__VA_ARGS__) +#define MARSHAL_STR(type, member) MARSHAL_ADD(pointer, type, _string, member) #define MARSHAL_TQE(type, field) \ MARSHAL_POINTER(type, type, field.tqe_next) \ MARSHAL_POINTER(type, type, field.tqe_prev) diff --git a/tests/check_marshal.c b/tests/check_marshal.c index 49e322f8..f4fe6637 100644 --- a/tests/check_marshal.c +++ b/tests/check_marshal.c @@ -577,6 +577,41 @@ START_TEST(test_embedded_list) { } END_TEST +struct struct_string { + int s1; + char *s2; + char *s3; +}; +MARSHAL_BEGIN(struct_string) +MARSHAL_STR(struct_string, s2) +MARSHAL_STR(struct_string, s3) +MARSHAL_END; + +START_TEST(test_string) { + struct struct_string source = { + .s1 = 44444, + .s2 = "String 2", + .s3 = "String 3", + }; + struct struct_string *destination; + void *buffer; + size_t len, len2; + + len = marshal_serialize(struct_string, &source, &buffer); + fail_unless(len > 0, "Unable to serialize"); + memset(&source, 0, sizeof(struct struct_string)); + len2 = marshal_unserialize(struct_string, buffer, len, &destination); + fail_unless(len2 > 0, "Unable to deserialize"); + free(buffer); + ck_assert_int_eq(len, len2); + ck_assert_int_eq(destination->s1, 44444); + ck_assert_str_eq(destination->s2, "String 2"); + ck_assert_str_eq(destination->s3, "String 3"); + free(destination->s2); free(destination->s3); + free(destination); +} +END_TEST + Suite * marshal_suite(void) { @@ -593,6 +628,7 @@ marshal_suite(void) tcase_add_test(tc_marshal, test_too_small_unmarshal); tcase_add_test(tc_marshal, test_simple_list); tcase_add_test(tc_marshal, test_embedded_list); + tcase_add_test(tc_marshal, test_string); suite_add_tcase(s, tc_marshal); return s;