From: Vincent Bernat Date: Sat, 21 Jan 2012 21:42:44 +0000 (+0100) Subject: marshal: handle fixed-size strings X-Git-Tag: 0.6.0~66 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ca4ed9da47205117b8f5e480924953993bbbf37a;p=thirdparty%2Flldpd.git marshal: handle fixed-size strings --- diff --git a/src/marshal.c b/src/marshal.c index 6dabdcba..8a7131fa 100644 --- a/src/marshal.c +++ b/src/marshal.c @@ -28,6 +28,11 @@ struct marshal_info marshal_info__string = { .size = 0, .pointers = {{ .mi = NULL }}, }; +struct marshal_info marshal_info__fstring = { + .name = "fixed string", + .size = 0, + .pointers = {{ .mi = NULL }}, +}; /* List of already seen pointers */ struct ref { @@ -39,7 +44,7 @@ TAILQ_HEAD(ref_l, ref); /* Serialize the given object. */ size_t _marshal_serialize(struct marshal_info *mi, void *unserialized, void **input, - int skip, void *_refs) + int skip, void *_refs, int osize) { /* Check if we have already serialized this one. */ struct ref_l *refs = _refs; @@ -61,6 +66,8 @@ _marshal_serialize(struct marshal_info *mi, void *unserialized, void **input, int size = mi->size; if (!strcmp(mi->name, "null string")) size = strlen((char *)unserialized) + 1; + else if (!strcmp(mi->name, "fixed string")) + size = osize; /* Allocate serialized structure */ size_t len = sizeof(struct marshal_serialized) + (skip?0:size); @@ -98,9 +105,10 @@ _marshal_serialize(struct marshal_info *mi, void *unserialized, void **input, if (source == NULL) continue; } else source = (void *)((unsigned char *)unserialized + current->offset); + memcpy(&osize, (unsigned char*)unserialized + current->offset2, sizeof(int)); sublen = _marshal_serialize(current->mi, source, &target, - current->kind == substruct, refs); + current->kind == substruct, refs, osize); if (sublen == -1) { LLOG_WARNX("unable to serialize substructure %s for %s", current->mi->name, mi->name); @@ -184,7 +192,7 @@ marshal_free(struct gc_l *pointers, int gconly) /* Unserialize the given object. */ size_t _marshal_unserialize(struct marshal_info *mi, void *buffer, size_t len, void **output, - void *_pointers, int skip) + void *_pointers, int skip, int osize) { int total_len = sizeof(struct marshal_serialized) + (skip?0:mi->size); struct marshal_serialized *serialized = buffer; @@ -207,10 +215,13 @@ _marshal_unserialize(struct marshal_info *mi, void *buffer, size_t len, void **o /* 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) { + if (!strcmp(mi->name, "null string") || !strcmp(mi->name, "fixed string")) { + switch (mi->name[0]) { + case 'n': size = strnlen((char *)serialized->object, + len - sizeof(struct marshal_serialized)) + 1; break; + case 'f': size = osize; break; + } + if (size > len - sizeof(struct marshal_serialized)) { LLOG_WARNX("data to deserialize contains a string too long"); total_len = 0; goto unmarshal_error; @@ -250,9 +261,10 @@ _marshal_unserialize(struct marshal_info *mi, void *buffer, size_t len, void **o if (already) continue; } /* Deserialize */ + memcpy(&osize, (unsigned char *)*output + current->offset2, sizeof(int)); sublen = _marshal_unserialize(current->mi, (unsigned char *)buffer + total_len, len - total_len, &new, pointers, - current->kind == substruct); + current->kind == substruct, osize); if (sublen == 0) { LLOG_WARNX("unable to serialize substructure %s for %s", current->mi->name, mi->name); diff --git a/src/marshal.h b/src/marshal.h index 20086039..cac9e682 100644 --- a/src/marshal.h +++ b/src/marshal.h @@ -21,12 +21,12 @@ struct marshal_info; enum marshal_subinfo_kind { pointer, substruct, - string, }; #define MARSHAL_INFO_POINTER 1 #define MARSHAL_INFO_SUB 2 struct marshal_subinfo { size_t offset; /* Offset compared to parent structure */ + size_t offset2; /* Ancillary offset (for related data) */ enum marshal_subinfo_kind kind; /* Kind of substructure */ struct marshal_info *mi; }; @@ -37,6 +37,7 @@ struct marshal_info { }; /* Special case for strings */ extern struct marshal_info marshal_info__string; +extern struct marshal_info marshal_info__fstring; /* Declare a new marshal_info struct named after the type we want to marshal. The marshalled type has to be a structure. */ @@ -45,13 +46,18 @@ extern struct marshal_info marshal_info__string; .name = #type, \ .size = sizeof(struct type), \ .pointers = { -#define MARSHAL_ADD(_kind, type, subtype, member) \ - { .offset = offsetof(struct type, member), \ - .kind = _kind, \ +#define MARSHAL_ADD(_kind, type, subtype, member) \ + { .offset = offsetof(struct type, member), \ + .kind = _kind, \ .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_FSTR(type, member, len) \ + { .offset = offsetof(struct type, member), \ + .offset2 = offsetof(struct type, len), \ + .kind = pointer, \ + .mi = &marshal_info__fstring }, #define MARSHAL_TQE(type, field) \ MARSHAL_POINTER(type, type, field.tqe_next) \ MARSHAL_POINTER(type, type, field.tqe_prev) @@ -72,12 +78,12 @@ extern struct marshal_info marshal_info__string; MARSHAL_END /* Serialization */ -size_t _marshal_serialize(struct marshal_info *, void *, void **, int, void *); -#define marshal_serialize(type, o, output) _marshal_serialize(&marshal_info_##type, o, output, 0, NULL) +size_t _marshal_serialize(struct marshal_info *, void *, void **, int, void *, int); +#define marshal_serialize(type, o, output) _marshal_serialize(&marshal_info_##type, o, output, 0, NULL, 0) /* Unserialization */ -size_t _marshal_unserialize(struct marshal_info *, void *, size_t, void **, void*, int); +size_t _marshal_unserialize(struct marshal_info *, void *, size_t, void **, void*, int, int); #define marshal_unserialize(type, o, l, input) \ - _marshal_unserialize(&marshal_info_##type, o, l, (void **)input, NULL, 0) + _marshal_unserialize(&marshal_info_##type, o, l, (void **)input, NULL, 0, 0) #endif diff --git a/tests/check_marshal.c b/tests/check_marshal.c index f4fe6637..5d4102c3 100644 --- a/tests/check_marshal.c +++ b/tests/check_marshal.c @@ -611,6 +611,48 @@ START_TEST(test_string) { free(destination); } END_TEST +struct struct_fixedstring { + int s1; + char *s2; + int s2_len; + char *s3; +}; +MARSHAL_BEGIN(struct_fixedstring) +MARSHAL_FSTR(struct_fixedstring, s2, s2_len) +MARSHAL_STR(struct_fixedstring, s3) +MARSHAL_END; + +START_TEST(test_fixed_string) { + struct struct_fixedstring source = { + .s1 = 44444, + .s2 = "String 2 Bla", + .s2_len = 8, + .s3 = "String 3", + }; + struct struct_fixedstring *destination; + void *buffer; + size_t len, len2; + + len = marshal_serialize(struct_fixedstring, &source, &buffer); + fail_unless(len > 0, "Unable to serialize"); + memset(&source, 0, sizeof(struct struct_string)); + len2 = marshal_unserialize(struct_fixedstring, 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_int_eq(destination->s2_len, 8); + ck_assert_int_eq(destination->s2[0], 'S'); + ck_assert_int_eq(destination->s2[2], 'r'); + ck_assert_int_eq(destination->s2[4], 'n'); + ck_assert_int_eq(destination->s2[5], 'g'); + ck_assert_int_eq(destination->s2[6], ' '); + ck_assert_int_eq(destination->s2[7], '2'); + ck_assert_str_eq(destination->s3, "String 3"); + free(destination->s2); free(destination->s3); + free(destination); +} +END_TEST Suite * marshal_suite(void) @@ -629,6 +671,7 @@ marshal_suite(void) tcase_add_test(tc_marshal, test_simple_list); tcase_add_test(tc_marshal, test_embedded_list); tcase_add_test(tc_marshal, test_string); + tcase_add_test(tc_marshal, test_fixed_string); suite_add_tcase(s, tc_marshal); return s;