From a27331f7036ddc306ef95a0631fac541933082f6 Mon Sep 17 00:00:00 2001 From: Gabor Adam Toth Date: Mon, 9 May 2011 21:33:45 +0200 Subject: [PATCH] pkg-psyc: incomplete packet handling --- src/autoconf/configure.in | 4 +- src/pkg-psyc.c | 173 +++++++++++++++++++++++--------------- src/pkg-psyc.h | 28 ++++-- src/sent.h | 2 +- src/simulate.c | 2 +- src/version.sh | 2 +- 6 files changed, 131 insertions(+), 80 deletions(-) diff --git a/src/autoconf/configure.in b/src/autoconf/configure.in index 3f075de..015a4f4 100644 --- a/src/autoconf/configure.in +++ b/src/autoconf/configure.in @@ -1220,7 +1220,7 @@ lp_cv_has_psyc_lib="no" AC_CHECK_LIB(psyc,main, lp_cv_has_psyc_lib="yes") if test $lp_cv_has_psyc_lib = yes; then - LIBS="-lpsyc" + LIBS="-lpsyc -lm" AC_CACHE_CHECK(for libpsyc usability,lp_cv_has_psyc, AC_TRY_RUN([ #include @@ -1237,7 +1237,7 @@ int main(void) { if test $lp_cv_has_psyc = yes; then AC_DEFINE(HAS_PSYC, 1, [Does the machine offer libpsyc?]) - PKGLIBS="$PKGLIBS -lpsyc" + PKGLIBS="$PKGLIBS -lpsyc -lm" echo "Congrats! libpsyc is available on this system." else echo "libpsyc not available on this system yet." diff --git a/src/pkg-psyc.c b/src/pkg-psyc.c index 874aa04..85a993d 100644 --- a/src/pkg-psyc.c +++ b/src/pkg-psyc.c @@ -32,7 +32,7 @@ # include # include -# include +# include # include /*-------------------------------------------------------------------------*/ @@ -95,7 +95,7 @@ f_psyc_render(svalue_t *sp) { meth, mlen, body, blen, PSYC_PACKET_CHECK_LENGTH); - printf("rendering... packet.length = %d\n", packet.length); + printf("rendering... packet.length = %ld\n", packet.length); // alloc_mstring creates an *untabled* string suitable for tmp data memsafe(out = alloc_mstring(packet.length), packet.length, "f_psyc_render"); psyc_render(&packet, get_txt(out), packet.length); @@ -117,15 +117,14 @@ f_psyc_parse (svalue_t *sp) { mapping_t *map; mp_int i; char oper = 0; - psycString name = {0,0}, value = {0,0}, elem = {0,0}; + psycString name = {0,0}, value = {0,0}, elem; psycParseListState listState; int ret; - size_t len; assert_shadow_sent(current_object); - psycState *state = O_GET_PSYC_STATE(current_object); + psyc_state_t *state = O_GET_PSYC_STATE(current_object); if (!state) { - state = pxalloc(sizeof(psycState)); + state = pxalloc(sizeof(psyc_state_t)); if (!state) errorf("Out of memory for psyc state struct.\n"); O_GET_PSYC_STATE(current_object) = state; state->parser = pxalloc(sizeof(psycParseState)); @@ -138,7 +137,7 @@ f_psyc_parse (svalue_t *sp) { errorf("\npsyc_parse got %ld int* bytes... not supported yet\n", i); } else if (sp->type == T_STRING) { - printf("\npsyc_parse got a %d bytes long string...\n", mstrsize(sp->u.str)); + printf("\npsyc_parse got a %ld bytes long string...\n", mstrsize(sp->u.str)); psyc_setParseBuffer(state->parser, psyc_newString(get_txt(sp->u.str), mstrsize(sp->u.str))); } @@ -160,21 +159,50 @@ f_psyc_parse (svalue_t *sp) { svalue_t *sv; ret = psyc_parse(state->parser, &oper, &name, &value); - switch (ret) { - case PSYC_PARSE_ENTITY_START: case PSYC_PARSE_BODY_START: - if ((len = psyc_getParseValueLength(state->parser))) - state->tmp = pxalloc(len); - case PSYC_PARSE_ENTITY_CONT: case PSYC_PARSE_BODY_CONT: - case PSYC_PARSE_ENTITY_END: case PSYC_PARSE_BODY_END: - memcpy(state->tmp + state->tmplen, value.ptr, value.length); - state->tmplen += value.length; + if (state->remaining) { + pfree(state->remaining); + state->remaining_len = 0; } switch (ret) { - case PSYC_PARSE_ROUTING: + 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); + 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)); + if (!state->value) + errorf("Out of memory for value.\n"); + + // fall thru + 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); + 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; + } + + switch (ret) { + case PSYC_PARSE_ROUTING: if (oper != ':') { - puts("_failure_unsupported_state"); - continue; + puts("_failure_unsupported_state"); + continue; } sv = pxalloc(sizeof(svalue_t)); // new_n_tabled fetches a reference of a probably existing @@ -186,20 +214,16 @@ 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: - case PSYC_PARSE_ENTITY_END: - case PSYC_PARSE_ENTITY: - if (oper && oper != ':') { - puts("_failure_unsupported_state"); - continue; + case PSYC_PARSE_ENTITY_END: + case PSYC_PARSE_ENTITY: + if (oper != ':') { + puts("_failure_unsupported_state"); + continue; } - if (name.length) { - sv = pxalloc(sizeof(svalue_t)); - put_string(sv, new_n_tabled(name.ptr, name.length)); - sv = get_map_lvalue(v->item[PSYC_ENTITY].u.map, sv); - } else - errorf("sv needs to point to the current map_lvalue .. FIXME!\n"); + + sv = pxalloc(sizeof(svalue_t)); + put_string(sv, new_n_tabled(name.ptr, name.length)); + sv = get_map_lvalue(v->item[PSYC_ENTITY].u.map, sv); // is it good to put entity variable values into the // shared string table? probably yes.. but it's a guess @@ -207,61 +231,76 @@ f_psyc_parse (svalue_t *sp) { put_string(sv, new_n_tabled(value.ptr, value.length)); // list parsing not supported yet.. TODO - if (name.length >= 5 && memcmp(name.ptr, "_list", 5) == 0) - { - write(1, ">>> LIST START\n", 15); - psyc_initParseListState(&listState); - psyc_setParseListBuffer(&listState, value); - while ((ret = psyc_parseList(&listState, &name, &value, &elem))) + if (psyc_isListVar(&name)) { + psyc_initParseListState(&listState); + psyc_setParseListBuffer(&listState, value); + elem = (psycString){0, 0}; + while ((ret = psyc_parseList(&listState, &value, &elem))) { + switch (ret) { - switch (ret) - { - case PSYC_PARSE_LIST_END: - case PSYC_PARSE_LIST_ELEM: - write(1, "|", 1); - write(1, elem.ptr, elem.length); - write(1, "\n", 1); - break; - default: - errorf("Error while parsing PSYC list: %i\n", ret); - /* NOTREACHED */ - return sp; - } - - if (ret == PSYC_PARSE_LIST_END) - { - write(1, ">>> LIST END\n", 13); - break; - } + case PSYC_PARSE_LIST_END: + case PSYC_PARSE_LIST_ELEM: + // TODO: store elem + //write(1, elem.ptr, elem.length); + break; + default: + errorf("Error while parsing PSYC list: %i\n", ret); + /* NOTREACHED */ + return sp; } + + if (ret == PSYC_PARSE_LIST_END) + break; + } } break; - case PSYC_PARSE_BODY_START: - case PSYC_PARSE_BODY_CONT: - case PSYC_PARSE_BODY_END: - case PSYC_PARSE_BODY: + 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)); + 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: + case PSYC_PARSE_COMPLETE: ret = 0; break; - case PSYC_PARSE_INSUFFICIENT: - errorf("Insufficient PSYC data.\n"); - /* NOTREACHED */ - return sp; - default: + 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); free_svalue(sp); diff --git a/src/pkg-psyc.h b/src/pkg-psyc.h index d905ef1..caccc21 100644 --- a/src/pkg-psyc.h +++ b/src/pkg-psyc.h @@ -11,28 +11,40 @@ # define PSYC_METHOD 2 # define PSYC_BODY 3 -# include +# include # include "array.h" # include "xalloc.h" -typedef struct { +typedef struct psyc_state_s { psycParseState *parser; vector_t *packet; - char *tmp; - size_t tmplen; -} psycState; + // tmp storage for incomplete modifier/body + char oper; + char *name; + size_t name_len; + char *value; + size_t value_len; + // tmp storage for remaining unparsed bytes at the end of the buffer + char *remaining; + size_t remaining_len; +} psyc_state_t; static inline void -psyc_free_parser (psycState *ps) { +psyc_free_state (psyc_state_t *ps) { if (!ps) return; - if (ps->tmp) - pfree((void *) ps->tmp); + if (ps->name) + pfree((void *) ps->name); + if (ps->value) + pfree((void *) ps->value); + if (ps->remaining) + pfree((void *) ps->remaining); if (ps->parser) pfree((void *) ps->parser); if (ps->packet) free_array(ps->packet); + ps->oper = ps->name_len = ps->value_len = ps->remaining_len = 0; } # define PKG_PSYC_H diff --git a/src/sent.h b/src/sent.h index 8eb9507..794683b 100644 --- a/src/sent.h +++ b/src/sent.h @@ -132,7 +132,7 @@ struct shadow_s #endif interactive_t *ip; /* the information for interactive objects */ #ifdef USE_PSYC - psycState *psyc_state; /* in case this objects parses PSYC data */ + psyc_state_t *psyc_state; /* in case this objects parses PSYC data */ #endif }; diff --git a/src/simulate.c b/src/simulate.c index 64cb924..ecc3354 100644 --- a/src/simulate.c +++ b/src/simulate.c @@ -2703,7 +2703,7 @@ destruct (object_t *ob) #ifdef USE_PSYC if (shadow_sent->psyc_state) - psyc_free_parser(shadow_sent->psyc_state); + psyc_free_state(shadow_sent->psyc_state); #endif #ifdef USE_SHADOWING diff --git a/src/version.sh b/src/version.sh index d7b0ab8..6577aa5 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="Sun May 8 22:11:18 CEST 2011" +version_stamp="Mon May 9 21:22:33 CEST 2011" # Okay, LDMUD is using 3.x.x so to avoid conflicts let's just use 4.x.x version_major=4