1
0
Fork 0
mirror of git://git.psyc.eu/libpsyc synced 2024-08-15 03:19:02 +00:00

fixes for parsing partial packets

This commit is contained in:
tg(x) 2011-04-27 18:37:03 +02:00
parent d18187229a
commit 2d8eb96f0d
2 changed files with 89 additions and 36 deletions

View file

@ -30,11 +30,13 @@ typedef enum
*/ */
typedef enum typedef enum
{ {
PSYC_PARSE_ERROR_END = -7, PSYC_PARSE_ERROR_END = -9,
PSYC_PARSE_ERROR_METHOD = -6, PSYC_PARSE_ERROR_BODY = -8,
PSYC_PARSE_ERROR_VAR_LEN = -5, PSYC_PARSE_ERROR_METHOD = -7,
PSYC_PARSE_ERROR_VAR_TAB = -4, PSYC_PARSE_ERROR_MOD_NL = -6,
PSYC_PARSE_ERROR_VAR_NAME = -3, PSYC_PARSE_ERROR_MOD_LEN = -5,
PSYC_PARSE_ERROR_MOD_TAB = -4,
PSYC_PARSE_ERROR_MOD_NAME = -3,
PSYC_PARSE_ERROR_LENGTH = -2, PSYC_PARSE_ERROR_LENGTH = -2,
PSYC_PARSE_ERROR = -1, PSYC_PARSE_ERROR = -1,
PSYC_PARSE_SUCCESS = 0, PSYC_PARSE_SUCCESS = 0,
@ -42,13 +44,13 @@ typedef enum
/// Fill another buffer and concatenate it with the end of the current buffer, /// Fill another buffer and concatenate it with the end of the current buffer,
/// from the cursor position to the end. /// from the cursor position to the end.
PSYC_PARSE_INSUFFICIENT = 1, PSYC_PARSE_INSUFFICIENT = 1,
/// Routing variable parsing done. /// Routing modifier parsing done.
/// Operator, name & value contains the respective parts. /// Operator, name & value contains the respective parts.
PSYC_PARSE_ROUTING = 2, PSYC_PARSE_ROUTING = 2,
/// Entity variable parsing done. /// Entity modifier parsing done.
/// Operator, name & value contains the respective parts. /// Operator, name & value contains the respective parts.
PSYC_PARSE_ENTITY = 3, PSYC_PARSE_ENTITY = 3,
/// Entity variable parsing is incomplete. /// Entity modifier parsing is incomplete.
/// Operator & name are complete, value is incomplete. /// Operator & name are complete, value is incomplete.
PSYC_PARSE_ENTITY_INCOMPLETE = 4, PSYC_PARSE_ENTITY_INCOMPLETE = 4,
/// Body parsing done, name contains method, value contains body. /// Body parsing done, name contains method, value contains body.
@ -91,6 +93,7 @@ typedef struct
uint8_t flags; ///< flags for the parser, see psycParseFlag uint8_t flags; ///< flags for the parser, see psycParseFlag
psycPart part; ///< part of the packet being parsed currently psycPart part; ///< part of the packet being parsed currently
size_t routingLength; ///< length of routing part parsed so far
size_t contentParsed; ///< number of bytes parsed from the content so far size_t contentParsed; ///< number of bytes parsed from the content so far
size_t contentLength; ///< expected length of the content size_t contentLength; ///< expected length of the content
psycBool contentLengthFound; ///< is there a length given for this packet? psycBool contentLengthFound; ///< is there a length given for this packet?

View file

@ -133,13 +133,15 @@ inline psycParseRC psyc_parseBinaryValue(psycParseState* state, psycString* valu
if (state->cursor + remaining > state->buffer.length) // is the length larger than this buffer? if (state->cursor + remaining > state->buffer.length) // is the length larger than this buffer?
{ {
value->length = state->buffer.length - state->cursor; value->length = state->buffer.length - state->cursor;
state->cursor += value->length;
*parsed += value->length; *parsed += value->length;
return PSYC_PARSE_INCOMPLETE; return PSYC_PARSE_INCOMPLETE;
} }
value->length += remaining; value->length = remaining;
state->cursor += remaining; state->cursor += remaining;
*parsed += value->length; *parsed += remaining;
assert(*parsed == *length);
return PSYC_PARSE_COMPLETE; return PSYC_PARSE_COMPLETE;
} }
@ -153,9 +155,13 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
*oper = *(state->buffer.ptr + state->cursor); *oper = *(state->buffer.ptr + state->cursor);
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT); ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
if (psyc_parseName(state, name) != PSYC_PARSE_SUCCESS) psycParseRC ret = psyc_parseName(state, name);
return PSYC_PARSE_ERROR_VAR_NAME; if (ret == PSYC_PARSE_ERROR)
return PSYC_PARSE_ERROR_MOD_NAME;
else if (ret != PSYC_PARSE_SUCCESS)
return ret;
size_t length = 0;
value->length = 0; value->length = 0;
state->valueLength = 0; state->valueLength = 0;
state->valueParsed = 0; state->valueParsed = 0;
@ -170,25 +176,25 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
{ {
do do
{ {
state->valueLength = 10 * state->valueLength + state->buffer.ptr[state->cursor] - '0'; length = 10 * length + state->buffer.ptr[state->cursor] - '0';
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT); ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
} }
while (isNumeric(state->buffer.ptr[state->cursor])); while (isNumeric(state->buffer.ptr[state->cursor]));
state->valueLength = length;
} }
else else
return PSYC_PARSE_ERROR_VAR_LEN; return PSYC_PARSE_ERROR_MOD_LEN;
// After the length a TAB follows. // After the length a TAB follows.
if (state->buffer.ptr[state->cursor] != '\t') if (state->buffer.ptr[state->cursor] != '\t')
return PSYC_PARSE_ERROR_VAR_TAB; return PSYC_PARSE_ERROR_MOD_TAB;
if (state->buffer.length <= ++(state->cursor)) // Incremented cursor inside length? ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INCOMPLETE);
return PSYC_PARSE_ENTITY_INCOMPLETE;
if (psyc_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed)) == PSYC_PARSE_INCOMPLETE) ret = psyc_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed));
return PSYC_PARSE_ENTITY_INCOMPLETE; if (ret == PSYC_PARSE_INCOMPLETE)
return ret;
state->cursor++;
return PSYC_PARSE_SUCCESS; return PSYC_PARSE_SUCCESS;
} }
else if (state->buffer.ptr[state->cursor] == '\t') // simple arg else if (state->buffer.ptr[state->cursor] == '\t') // simple arg
@ -201,11 +207,11 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
value->length++; value->length++;
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT); ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
} }
state->cursor++;
return PSYC_PARSE_SUCCESS; return PSYC_PARSE_SUCCESS;
} }
else else
return PSYC_PARSE_ERROR_VAR_TAB; return PSYC_PARSE_ERROR_MOD_TAB;
} }
/** /**
@ -214,7 +220,7 @@ inline psycParseRC psyc_parseModifier(psycParseState* state, char* oper, psycStr
*/ */
psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psycString* value) psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psycString* value)
{ {
int ret; // a return value psycParseRC ret; // a return value
size_t pos; // a cursor position size_t pos; // a cursor position
// Start position of the current line in the buffer // Start position of the current line in the buffer
@ -230,6 +236,7 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
case PSYC_PART_RESET: // New packet starts here, reset state. case PSYC_PART_RESET: // New packet starts here, reset state.
state->valueParsed = 0; state->valueParsed = 0;
state->valueLength = 0; state->valueLength = 0;
state->routingLength = 0;
state->contentParsed = 0; state->contentParsed = 0;
state->contentLength = 0; state->contentLength = 0;
state->contentLengthFound = 0; state->contentLengthFound = 0;
@ -237,12 +244,21 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
// fall thru // fall thru
case PSYC_PART_ROUTING: case PSYC_PART_ROUTING:
pos = state->cursor;
if (state->routingLength > 0)
{
if (state->buffer.ptr[state->cursor] != '\n')
return PSYC_PARSE_ERROR_MOD_NL;
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
}
// Each line of the header starts with a glyph, // Each line of the header starts with a glyph,
// i.e. :_name, -_name +_name etc, // i.e. :_name, -_name +_name etc,
// so just test if the first char is a glyph. // so just test if the first char is a glyph.
if (isGlyph(state->buffer.ptr[state->cursor])) // is the first char a glyph? if (isGlyph(state->buffer.ptr[state->cursor])) // is the first char a glyph?
{ // it is a glyph, so a variable starts here { // it is a glyph, so a variable starts here
ret = psyc_parseModifier(state, oper, name, value); ret = psyc_parseModifier(state, oper, name, value);
state->routingLength += state->cursor - pos;
return ret == PSYC_PARSE_SUCCESS ? PSYC_PARSE_ROUTING : ret; return ret == PSYC_PARSE_SUCCESS ? PSYC_PARSE_ROUTING : ret;
} }
else // not a glyph else // not a glyph
@ -293,7 +309,20 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
if (state->valueParsed < state->valueLength) { if (state->valueParsed < state->valueLength) {
ret = psyc_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed)); ret = psyc_parseBinaryValue(state, value, &(state->valueLength), &(state->valueParsed));
state->contentParsed += value->length; state->contentParsed += value->length;
return ret == PSYC_PARSE_COMPLETE ? PSYC_PARSE_ENTITY : PSYC_PARSE_ENTITY_INCOMPLETE;
if (ret == PSYC_PARSE_INCOMPLETE)
return PSYC_PARSE_ENTITY_INCOMPLETE;
return PSYC_PARSE_ENTITY;
}
pos = state->cursor;
if (state->contentParsed > 0)
{
if (state->buffer.ptr[state->cursor] != '\n')
return PSYC_PARSE_ERROR_MOD_NL;
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
} }
// Each line of the header starts with a glyph, // Each line of the header starts with a glyph,
@ -303,31 +332,45 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
// method does not start with a glyph. // method does not start with a glyph.
if (isGlyph(state->buffer.ptr[state->cursor])) if (isGlyph(state->buffer.ptr[state->cursor]))
{ {
pos = state->cursor;
ret = psyc_parseModifier(state, oper, name, value); ret = psyc_parseModifier(state, oper, name, value);
state->contentParsed += state->cursor - pos; state->contentParsed += state->cursor - pos;
return ret == PSYC_PARSE_SUCCESS ? PSYC_PARSE_ENTITY : ret;
if (ret == PSYC_PARSE_INCOMPLETE)
return PSYC_PARSE_ENTITY_INCOMPLETE;
else if (ret == PSYC_PARSE_SUCCESS)
return PSYC_PARSE_ENTITY;
return ret;
} }
else else
{ {
state->part = PSYC_PART_METHOD; state->contentParsed += state->cursor - pos;
state->startc = state->cursor; state->startc = state->cursor;
state->part = PSYC_PART_METHOD;
// fall thru // fall thru
} }
case PSYC_PART_METHOD: case PSYC_PART_METHOD:
pos = state->cursor; pos = state->cursor;
if (psyc_parseName(state, name) == PSYC_PARSE_SUCCESS) ret = psyc_parseName(state, name);
if (ret == PSYC_PARSE_INSUFFICIENT)
return ret;
else if (ret == PSYC_PARSE_SUCCESS)
{ // the method ends with a \n then the data follows { // the method ends with a \n then the data follows
if (state->buffer.ptr[state->cursor] != '\n') if (state->buffer.ptr[state->cursor] != '\n')
return PSYC_PARSE_ERROR_METHOD; return PSYC_PARSE_ERROR_METHOD;
state->cursor++; if (state->contentLengthFound)
state->startc = state->cursor; { // if length was found set start position to the beginning of data
state->cursor++;
state->startc = state->cursor;
state->part = PSYC_PART_DATA;
}
else // otherwise keep it at the beginning of method
ADVANCE_CURSOR_OR_RETURN(PSYC_PARSE_INSUFFICIENT);
state->contentParsed += state->cursor - pos; state->contentParsed += state->cursor - pos;
state->part = PSYC_PART_DATA;
if (state->cursor >= state->buffer.length)
return PSYC_PARSE_INSUFFICIENT;
// fall thru // fall thru
} }
else // No method, which means the packet should end now. else // No method, which means the packet should end now.
@ -343,9 +386,16 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
if (state->contentLengthFound) // We know the length of the packet. if (state->contentLengthFound) // We know the length of the packet.
{ {
if (psyc_parseBinaryValue(state, value, &(state->contentLength), &(state->contentParsed)) == PSYC_PARSE_INCOMPLETE) if (state->contentParsed < state->contentLength &&
psyc_parseBinaryValue(state, value, &(state->contentLength), &(state->contentParsed)) == PSYC_PARSE_INCOMPLETE)
return PSYC_PARSE_BODY_INCOMPLETE; return PSYC_PARSE_BODY_INCOMPLETE;
if (state->cursor >= state->buffer.length)
return PSYC_PARSE_BODY;
if (state->buffer.ptr[state->cursor] != '\n')
return PSYC_PARSE_ERROR_BODY;
state->cursor++; state->cursor++;
state->part = PSYC_PART_END; state->part = PSYC_PART_END;
return PSYC_PARSE_BODY; return PSYC_PARSE_BODY;
@ -385,7 +435,7 @@ psycParseRC psyc_parse(psycParseState* state, char* oper, psycString* name, psyc
return PSYC_PARSE_INSUFFICIENT; return PSYC_PARSE_INSUFFICIENT;
if (state->buffer.ptr[state->cursor] == '|' && if (state->buffer.ptr[state->cursor] == '|' &&
state->buffer.ptr[state->cursor+1] == '\n') // packet ends here state->buffer.ptr[state->cursor+1] == '\n') // packet ends here
{ {
state->cursor += 2; state->cursor += 2;
state->part = PSYC_PART_RESET; state->part = PSYC_PART_RESET;
@ -414,7 +464,7 @@ psycParseListRC psyc_parseList(psycParseListState* state, psycString *name, psyc
if (!state->type) // If type is not set we're at the start if (!state->type) // If type is not set we're at the start
{ {
if (name->length < 5 || memcmp(name->ptr, "_list", 5) != 0 || if (name->length < 5 || memcmp(name->ptr, "_list", 5) != 0 ||
(name->length > 5 && name->ptr[5] != '_')) // name should be _list or should start with _list_ (name->length > 5 && name->ptr[5] != '_')) // name should be _list or should start with _list_
return PSYC_PARSE_LIST_ERROR_NAME; return PSYC_PARSE_LIST_ERROR_NAME;
// First character is either | for text lists, or a number for binary lists // First character is either | for text lists, or a number for binary lists