pkg-psyc: incomplete packet handling

This commit is contained in:
Gabor Adam Toth 2011-05-09 21:33:45 +02:00
parent 14944d8484
commit a27331f703
6 changed files with 131 additions and 80 deletions

View File

@ -1220,7 +1220,7 @@ lp_cv_has_psyc_lib="no"
AC_CHECK_LIB(psyc,main, lp_cv_has_psyc_lib="yes") AC_CHECK_LIB(psyc,main, lp_cv_has_psyc_lib="yes")
if test $lp_cv_has_psyc_lib = yes; then 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_CACHE_CHECK(for libpsyc usability,lp_cv_has_psyc,
AC_TRY_RUN([ AC_TRY_RUN([
#include <psyc.h> #include <psyc.h>
@ -1237,7 +1237,7 @@ int main(void) {
if test $lp_cv_has_psyc = yes; then if test $lp_cv_has_psyc = yes; then
AC_DEFINE(HAS_PSYC, 1, [Does the machine offer libpsyc?]) 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." echo "Congrats! libpsyc is available on this system."
else else
echo "libpsyc not available on this system yet." echo "libpsyc not available on this system yet."

View File

@ -32,7 +32,7 @@
# include <fcntl.h> # include <fcntl.h>
# include <psyc.h> # include <psyc.h>
# include <psyc/parser.h> # include <psyc/parse.h>
# include <psyc/render.h> # include <psyc/render.h>
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
@ -95,7 +95,7 @@ f_psyc_render(svalue_t *sp) {
meth, mlen, body, blen, meth, mlen, body, blen,
PSYC_PACKET_CHECK_LENGTH); 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 // alloc_mstring creates an *untabled* string suitable for tmp data
memsafe(out = alloc_mstring(packet.length), packet.length, "f_psyc_render"); memsafe(out = alloc_mstring(packet.length), packet.length, "f_psyc_render");
psyc_render(&packet, get_txt(out), packet.length); psyc_render(&packet, get_txt(out), packet.length);
@ -117,15 +117,14 @@ f_psyc_parse (svalue_t *sp) {
mapping_t *map; mapping_t *map;
mp_int i; mp_int i;
char oper = 0; char oper = 0;
psycString name = {0,0}, value = {0,0}, elem = {0,0}; psycString name = {0,0}, value = {0,0}, elem;
psycParseListState listState; psycParseListState listState;
int ret; int ret;
size_t len;
assert_shadow_sent(current_object); 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) { if (!state) {
state = pxalloc(sizeof(psycState)); state = pxalloc(sizeof(psyc_state_t));
if (!state) errorf("Out of memory for psyc state struct.\n"); if (!state) errorf("Out of memory for psyc state struct.\n");
O_GET_PSYC_STATE(current_object) = state; O_GET_PSYC_STATE(current_object) = state;
state->parser = pxalloc(sizeof(psycParseState)); 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); 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 %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), psyc_setParseBuffer(state->parser, psyc_newString(get_txt(sp->u.str),
mstrsize(sp->u.str))); mstrsize(sp->u.str)));
} }
@ -160,21 +159,50 @@ f_psyc_parse (svalue_t *sp) {
svalue_t *sv; svalue_t *sv;
ret = psyc_parse(state->parser, &oper, &name, &value); ret = psyc_parse(state->parser, &oper, &name, &value);
switch (ret) { if (state->remaining) {
case PSYC_PARSE_ENTITY_START: case PSYC_PARSE_BODY_START: pfree(state->remaining);
if ((len = psyc_getParseValueLength(state->parser))) state->remaining_len = 0;
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;
} }
switch (ret) { 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 != ':') { if (oper != ':') {
puts("_failure_unsupported_state"); puts("_failure_unsupported_state");
continue; continue;
} }
sv = pxalloc(sizeof(svalue_t)); sv = pxalloc(sizeof(svalue_t));
// new_n_tabled fetches a reference of a probably existing // 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 // for values of routing variables as they repeat a lot
put_string(sv, new_n_tabled(value.ptr, value.length)); put_string(sv, new_n_tabled(value.ptr, value.length));
break; break;
case PSYC_PARSE_ENTITY_START: case PSYC_PARSE_ENTITY_END:
case PSYC_PARSE_ENTITY_CONT: case PSYC_PARSE_ENTITY:
case PSYC_PARSE_ENTITY_END: if (oper != ':') {
case PSYC_PARSE_ENTITY: puts("_failure_unsupported_state");
if (oper && oper != ':') { continue;
puts("_failure_unsupported_state");
continue;
} }
if (name.length) {
sv = pxalloc(sizeof(svalue_t)); sv = pxalloc(sizeof(svalue_t));
put_string(sv, new_n_tabled(name.ptr, name.length)); put_string(sv, new_n_tabled(name.ptr, name.length));
sv = get_map_lvalue(v->item[PSYC_ENTITY].u.map, sv); sv = get_map_lvalue(v->item[PSYC_ENTITY].u.map, sv);
} else
errorf("sv needs to point to the current map_lvalue .. FIXME!\n");
// is it good to put entity variable values into the // is it good to put entity variable values into the
// shared string table? probably yes.. but it's a guess // 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)); put_string(sv, new_n_tabled(value.ptr, value.length));
// list parsing not supported yet.. TODO // list parsing not supported yet.. TODO
if (name.length >= 5 && memcmp(name.ptr, "_list", 5) == 0) if (psyc_isListVar(&name)) {
{ psyc_initParseListState(&listState);
write(1, ">>> LIST START\n", 15); psyc_setParseListBuffer(&listState, value);
psyc_initParseListState(&listState); elem = (psycString){0, 0};
psyc_setParseListBuffer(&listState, value); while ((ret = psyc_parseList(&listState, &value, &elem))) {
while ((ret = psyc_parseList(&listState, &name, &value, &elem))) switch (ret)
{ {
switch (ret) case PSYC_PARSE_LIST_END:
{ case PSYC_PARSE_LIST_ELEM:
case PSYC_PARSE_LIST_END: // TODO: store elem
case PSYC_PARSE_LIST_ELEM: //write(1, elem.ptr, elem.length);
write(1, "|", 1); break;
write(1, elem.ptr, elem.length); default:
write(1, "\n", 1); errorf("Error while parsing PSYC list: %i\n", ret);
break; /* NOTREACHED */
default: return sp;
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;
}
} }
if (ret == PSYC_PARSE_LIST_END)
break;
}
} }
break; break;
case PSYC_PARSE_BODY_START: case PSYC_PARSE_BODY_END:
case PSYC_PARSE_BODY_CONT: 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"); if (str) errorf("Got two PSYC methods in the same packet!?\n");
// new_n_tabled gets the shared string for the method // new_n_tabled gets the shared string for the method
put_string(&v->item[PSYC_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 // allocate an untabled string for the packet body
put_string(&v->item[PSYC_BODY], put_string(&v->item[PSYC_BODY],
new_n_mstring(value.ptr, value.length)); new_n_mstring(value.ptr, value.length));
break; break;
case PSYC_PARSE_COMPLETE: case PSYC_PARSE_COMPLETE:
ret = 0; ret = 0;
break; break;
case PSYC_PARSE_INSUFFICIENT: case PSYC_PARSE_INSUFFICIENT:
errorf("Insufficient PSYC data.\n"); // insufficient data, save remaining bytes
/* NOTREACHED */ state->remaining_len = psyc_getParseRemainingLength(state->parser);
return sp; if (state->remaining_len) {
default: 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); errorf("Error while parsing PSYC: %i\n", ret);
/* NOTREACHED */ /* NOTREACHED */
return sp; 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); } while (ret);
free_svalue(sp); free_svalue(sp);

View File

@ -11,28 +11,40 @@
# define PSYC_METHOD 2 # define PSYC_METHOD 2
# define PSYC_BODY 3 # define PSYC_BODY 3
# include <psyc/parser.h> # include <psyc/parse.h>
# include "array.h" # include "array.h"
# include "xalloc.h" # include "xalloc.h"
typedef struct { typedef struct psyc_state_s {
psycParseState *parser; psycParseState *parser;
vector_t *packet; vector_t *packet;
char *tmp; // tmp storage for incomplete modifier/body
size_t tmplen; char oper;
} psycState; 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 static inline void
psyc_free_parser (psycState *ps) { psyc_free_state (psyc_state_t *ps) {
if (!ps) if (!ps)
return; return;
if (ps->tmp) if (ps->name)
pfree((void *) ps->tmp); pfree((void *) ps->name);
if (ps->value)
pfree((void *) ps->value);
if (ps->remaining)
pfree((void *) ps->remaining);
if (ps->parser) if (ps->parser)
pfree((void *) ps->parser); pfree((void *) ps->parser);
if (ps->packet) if (ps->packet)
free_array(ps->packet); free_array(ps->packet);
ps->oper = ps->name_len = ps->value_len = ps->remaining_len = 0;
} }
# define PKG_PSYC_H # define PKG_PSYC_H

View File

@ -132,7 +132,7 @@ struct shadow_s
#endif #endif
interactive_t *ip; /* the information for interactive objects */ interactive_t *ip; /* the information for interactive objects */
#ifdef USE_PSYC #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 #endif
}; };

View File

@ -2703,7 +2703,7 @@ destruct (object_t *ob)
#ifdef USE_PSYC #ifdef USE_PSYC
if (shadow_sent->psyc_state) if (shadow_sent->psyc_state)
psyc_free_parser(shadow_sent->psyc_state); psyc_free_state(shadow_sent->psyc_state);
#endif #endif
#ifdef USE_SHADOWING #ifdef USE_SHADOWING

View File

@ -17,7 +17,7 @@ version_longtype="stable"
# A timestamp, to be used by bumpversion and other scripts. # A timestamp, to be used by bumpversion and other scripts.
# It can be used, for example, to 'touch' this file on every build, thus # 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. # 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 # Okay, LDMUD is using 3.x.x so to avoid conflicts let's just use 4.x.x
version_major=4 version_major=4