From 39b7facd1994296855b86bdb03e3b3ab8458fd14 Mon Sep 17 00:00:00 2001 From: Gabor Adam Toth Date: Wed, 11 May 2011 17:09:22 +0200 Subject: [PATCH] pkg-psyc: parsing incomplete packets --- src/pkg-psyc.c | 196 +++++++++++++++++++++++++++++-------------------- src/pkg-psyc.h | 17 +++-- src/version.sh | 2 +- 3 files changed, 128 insertions(+), 87 deletions(-) diff --git a/src/pkg-psyc.c b/src/pkg-psyc.c index 9529ef8..7731426 100644 --- a/src/pkg-psyc.c +++ b/src/pkg-psyc.c @@ -4,14 +4,23 @@ * test LPC code: * // doesn't work with (int *) yet - mixed* x = psyc_parse(":_context\ttest\n\n:_topic\ttesting\n_notice_test_libpsyc\nJust [_topic] libpsyc.\n|\n"); - mixed y = psyc_render(x); - mixed z = ({ ([ "_context": "test" ]), ([ "_topic": "testing" ]), "_notice_test_libpsyc", "Just [_topic] libpsyc." }); - z = psyc_render(z); - // psyc_render currently having some memory corruption problems - debug_message(sprintf("libpsyc returned %O, %O and %O (%s)\n", x, y, z, - y == z? "success": "FAIL!")); - * + mixed *f = psyc_parse(":_context\ttest\n\n:_topic\ttesting\n_notice_test_libpsyc\nJust [_topic] libpsyc.\n|\n"); + mixed fr = psyc_render(f); + mixed r = ({ ([ "_context": "test" ]), ([ "_topic": "testing" ]), + "_notice_test_libpsyc", "Just [_topic] libpsyc." }); + mixed rr = psyc_render(r); + + debug_message(sprintf("libpsyc returned %O, %O and %O (%s)\n", f, fr, rr, + fr == rr ? "success": "FAIL!")); + mixed *p1 = psyc_parse(":_context\ttest\n\n:_topic\ttest"); + debug_message(sprintf("p1: libpsyc returned %O\n", p1)); + mixed *p2 = psyc_parse("ing\n_notice_test_libpsyc\nJust [_topic] libpsyc.\n|\n"); + debug_message(sprintf("p2: libpsyc returned %O\n", p2)); + mixed *p = ({ p1[0]+p2[0], p1[1]+p2[1], + (p1[2]||"") + p2[2], (p1[3]||"") + p2[3] }); + mixed pr = psyc_render(p); + debug_message(sprintf("libpsyc returned %O (%s)\n", p, + pr == rr ? "success": "FAIL!")); */ #include "array.h" @@ -113,6 +122,7 @@ f_psyc_render(svalue_t *sp) { svalue_t * f_psyc_parse (svalue_t *sp) { string_t *str = NULL; + char *buffer = NULL; vector_t *v; mapping_t *map; mp_int i; @@ -137,10 +147,25 @@ f_psyc_parse (svalue_t *sp) { i = 0; if (sp->type == T_POINTER) { errorf("\npsyc_parse got %ld int* bytes... not supported yet\n", i); - } - else if (sp->type == T_STRING) { + } else if (sp->type == T_STRING) { printf("\npsyc_parse got a %ld bytes long string...\n", mstrsize(sp->u.str)); - psyc_setParseBuffer2(state->parser, get_txt(sp->u.str), mstrsize(sp->u.str)); + + if (state->remaining) { + // there are remaining bytes from the previous call to psyc_parse, + // copy them together with the newly arrived data + buffer = pxalloc(state->remaining_len + mstrsize(sp->u.str)); + if (!buffer) errorf("Out of memory for psyc_parse buffer.\n"); + memcpy(buffer, state->remaining, state->remaining_len); + memcpy(buffer + state->remaining_len, get_txt(sp->u.str), mstrsize(sp->u.str)); + psyc_setParseBuffer2(state->parser, buffer, state->remaining_len + mstrsize(sp->u.str)); + pfree(state->remaining); + state->remaining = NULL; + state->remaining_len = 0; + } else { + psyc_setParseBuffer2(state->parser, get_txt(sp->u.str), mstrsize(sp->u.str)); + } + } else { + errorf("\npsyc_parse got type %d, not supported\n", sp->type); } if (!state->packet) { @@ -160,26 +185,20 @@ f_psyc_parse (svalue_t *sp) { svalue_t *sv; ret = psyc_parse(state->parser, &oper, &name, &value); - if (state->remaining) { - pfree(state->remaining); - state->remaining = NULL; - state->remaining_len = 0; - } + printf("#%2d %c%.*s = %.*s\n", ret, oper ? oper : ' ', name.length, name.ptr, value.length, value.ptr); switch (ret) { case PSYC_PARSE_ENTITY_START: case PSYC_PARSE_BODY_START: // save oper, name & value in state at the start of incomplete entity or body state->oper = oper; - - state->name_len = name.length; - state->name = pxalloc(name.length); - memcpy(state->name, name.ptr, name.length); + state->name = mstring_alloc_string(name.length); + memcpy(get_txt(state->name), name.ptr, name.length); if (!state->name) errorf("Out of memory for name.\n"); - state->value_len = 0; // allocate memory for the total length of the value - state->value = pxalloc(psyc_getParseValueLength(state->parser)); + state->value_len = 0; + state->value = mstring_alloc_string(psyc_getParseValueLength(state->parser)); if (!state->value) errorf("Out of memory for value.\n"); @@ -187,17 +206,17 @@ f_psyc_parse (svalue_t *sp) { case PSYC_PARSE_ENTITY_CONT: case PSYC_PARSE_BODY_CONT: case PSYC_PARSE_ENTITY_END: case PSYC_PARSE_BODY_END: // append value to tmp buffer in state - memcpy(state->value + state->value_len, value.ptr, value.length); + memcpy(get_txt(state->value) + state->value_len, value.ptr, value.length); state->value_len += value.length; } if (ret == PSYC_PARSE_ENTITY_END || ret == PSYC_PARSE_BODY_END) { // incomplete entity or body parsing done, set oper/name/value to the ones saved in state oper = state->oper; - name.ptr = state->name; - name.length = state->name_len; - value.ptr = state->value; - value.length = state->value_len; + name.ptr = get_txt(state->name); + name.length = mstrsize(state->name); + value.ptr = get_txt(state->value); + value.length = mstrsize(state->value); } switch (ret) { @@ -216,10 +235,23 @@ f_psyc_parse (svalue_t *sp) { // for values of routing variables as they repeat a lot put_string(sv, new_n_tabled(value.ptr, value.length)); break; + case PSYC_PARSE_ENTITY_START: case PSYC_PARSE_ENTITY_CONT: break; + case PSYC_PARSE_ENTITY_END: + if (oper != ':') { + puts("_failure_unsupported_state"); + continue; + } + + sv = pxalloc(sizeof(svalue_t)); + put_string(sv, make_tabled(state->name)); + sv = get_map_lvalue(v->item[PSYC_ENTITY].u.map, sv); + put_string(sv, state->value); + break; + case PSYC_PARSE_ENTITY: if (oper != ':') { puts("_failure_unsupported_state"); @@ -234,7 +266,63 @@ f_psyc_parse (svalue_t *sp) { // shared string table? probably yes.. but it's a guess //t_string(sv, new_n_mstring(value.ptr, value.length)); put_string(sv, new_n_tabled(value.ptr, value.length)); + break; + case PSYC_PARSE_BODY_START: + case PSYC_PARSE_BODY_CONT: + break; + + case PSYC_PARSE_BODY_END: + put_string(&v->item[PSYC_METHOD], make_tabled(state->name)); + put_string(&v->item[PSYC_BODY], state->value); + break; + + case PSYC_PARSE_BODY: + if (str) errorf("Got two PSYC methods in the same packet!?\n"); + // new_n_tabled gets the shared string for the method + put_string(&v->item[PSYC_METHOD], + new_n_tabled(name.ptr, name.length)); + + // allocate an untabled string for the packet body + put_string(&v->item[PSYC_BODY], + new_n_mstring(value.ptr, value.length)); + break; + + case PSYC_PARSE_COMPLETE: + state->packet = NULL; + ret = 0; + break; + + case PSYC_PARSE_INSUFFICIENT: + // insufficient data, save remaining bytes + state->remaining_len = psyc_getParseRemainingLength(state->parser); + if (state->remaining_len) { + state->remaining = pxalloc(state->remaining_len); + memcpy(state->remaining, + psyc_getParseRemainingBuffer(state->parser), + state->remaining_len); + } else + state->remaining = NULL; + + ret = 0; + break; + + default: + errorf("Error while parsing PSYC: %i\n", ret); + /* NOTREACHED */ + return sp; + } + + switch (ret) { + case PSYC_PARSE_BODY_END: + case PSYC_PARSE_ENTITY_END: + // reset tmp buffers in state when incomplete entity or body parsing is done + state->oper = 0; + state->name = NULL; + state->value = NULL; + if (ret == PSYC_PARSE_BODY_END) + break; + case PSYC_PARSE_ENTITY: // list parsing not supported yet.. TODO if (psyc_isListVar(&name)) { psyc_initParseListState(&listState); @@ -258,60 +346,12 @@ f_psyc_parse (svalue_t *sp) { break; } } - break; - case PSYC_PARSE_BODY_START: - case PSYC_PARSE_BODY_CONT: - break; - case PSYC_PARSE_BODY_END: - case PSYC_PARSE_BODY: - if (str) errorf("Got two PSYC methods in the same packet!?\n"); - // new_n_tabled gets the shared string for the method - put_string(&v->item[PSYC_METHOD], - new_n_tabled(name.ptr, name.length)); - - // allocate an untabled string for the packet body - put_string(&v->item[PSYC_BODY], - new_n_mstring(value.ptr, value.length)); - - break; - case PSYC_PARSE_COMPLETE: - state->packet = NULL; - ret = 0; - break; - case PSYC_PARSE_INSUFFICIENT: - // insufficient data, save remaining bytes - state->remaining_len = psyc_getParseRemainingLength(state->parser); - if (state->remaining_len) { - state->remaining = pxalloc(state->remaining_len); - memcpy(state->remaining, - psyc_getParseRemainingBuffer(state->parser), - state->remaining_len); - } else - state->remaining = NULL; - //TODO: psyc_setRemainingBuffer2(state->parser, state->remaining, state->remaining_len); - break; - default: - errorf("Error while parsing PSYC: %i\n", ret); - /* NOTREACHED */ - return sp; - } - - // free tmp buffers in state when incomplete entity or body parsing is done - if (ret == PSYC_PARSE_ENTITY_END || ret == PSYC_PARSE_BODY_END) { - oper = 0; - - if (state->name) - pfree(state->name); - state->name = NULL; - state->name_len = 0; - - if (value.ptr) - pfree((void*)value.ptr); - state->value = NULL; - state->value_len = 0; } } while (ret); + if (buffer) + pfree(buffer); + free_svalue(sp); put_array(sp, v); state->packet = 0; diff --git a/src/pkg-psyc.h b/src/pkg-psyc.h index 923b8b6..b32d25f 100644 --- a/src/pkg-psyc.h +++ b/src/pkg-psyc.h @@ -6,24 +6,25 @@ * or int* where necessary. */ -# define PSYC_ROUTING 0 -# define PSYC_ENTITY 1 -# define PSYC_METHOD 2 -# define PSYC_BODY 3 - # include # include "array.h" # include "xalloc.h" +enum { + PSYC_ROUTING = 0, + PSYC_ENTITY = 1, + PSYC_METHOD = 2, + PSYC_BODY = 3, +}; + typedef struct psyc_state_s { psycParseState *parser; vector_t *packet; // tmp storage for incomplete modifier/body char oper; - char *name; - size_t name_len; - char *value; + string_t *name; + string_t *value; size_t value_len; // tmp storage for remaining unparsed bytes at the end of the buffer char *remaining; diff --git a/src/version.sh b/src/version.sh index 51f47c9..92f29c0 100644 --- a/src/version.sh +++ b/src/version.sh @@ -17,7 +17,7 @@ version_longtype="stable" # A timestamp, to be used by bumpversion and other scripts. # It can be used, for example, to 'touch' this file on every build, thus # forcing revision control systems to add it on every checkin automatically. -version_stamp="Tue May 10 14:07:26 CEST 2011" +version_stamp="Wed May 11 16:44:23 CEST 2011" # Okay, LDMUD is using 3.x.x so to avoid conflicts let's just use 4.x.x version_major=4