Esempio n. 1
0
// Parses trailing NUL character. Returns true iff progress was made.
bool frameparser_parse_end(frameparser *fp, buffer *b)
{
  // Valid input in this state is simply a single NUL character
  log_printf(LOG_LEVEL_DEBUG, "frameparser_parse_end\n");

  // If there is already a parsed frame that hasn't been picked up yet, we
  //  don't want to overwrite it, so refrain from finishing this frame.
  if (fp->fin_frame)
    return false;  // No progress

  // Check for the NUL
  uint8_t byte = buffer_get_byte(b, 0);
  if (byte != '\x00')
  {
    frameparser_set_error(fp, "Expected trailing NUL at end of frame");
    return false;
  }

  // Consume it
  buffer_consume(b, 1);

  // All done with the current frame
  fp->fin_frame = fp->cur_frame;
  fp->cur_frame = NULL;
  fp->state = FP_STATE_IDLE;

  return true;
}
Esempio n. 2
0
// Parses a frame's command. Returns true iff progress was made.
bool frameparser_parse_command(frameparser *fp, buffer *b)
{
  log_printf(LOG_LEVEL_DEBUG, "frameparser_parse_command\n");
  // Valid input in this state is a string followed by CR/LF or LF, which matches a known frame command

  // Try to find LF line terminator
  int lfpos = buffer_find_byte(b, '\x0A');
  if (lfpos < 0)  // No LF yet?
  {
    if (buffer_get_length(b) > LIMIT_FRAME_CMD_LINE_LEN)
      frameparser_set_error(fp, "Line length limit exceeded waiting for command");

    return false;  // No progress
  }
  else if (lfpos == 0)
    abort();  // Should never happen in this state

  // Figure out number of bytes in command string
  int len = lfpos;
  if (buffer_get_byte(b, len - 1) == '\x0D')
    len--;

  // Extract the command into a new bytestring
  bytestring *bs = bytestring_new(len);
  buffer_append_bytestring(b, bs, 0, len);
  bytestring_dump(bs);

  // Consume the current line
  buffer_consume(b, lfpos + 1);

  // Find the command code for this command
  frame_command cmd = frame_command_code(bytestring_get_bytes(bs), bytestring_get_length(bs));

  // Clean up the bytestring
  bytestring_free(bs);

  // Make sure command is valid
  if (cmd == CMD_NONE)
  {
    frameparser_set_error(fp, "Unknown command");
    return false;
  }

  // Set up a new frame structure to hold parsed data
  if (!fp->cur_frame)
    fp->cur_frame = frame_new();

  // Store parsed data
  frame_set_command(fp->cur_frame, cmd);

  // Got a valid command, so headers should be next
  fp->state = FP_STATE_HEADER;
  return true;
}
Esempio n. 3
0
// Parses keepalive linefeeds. Returns true iff progress was made.
bool frameparser_parse_idle(frameparser *fp, buffer *b)
{
  log_printf(LOG_LEVEL_DEBUG, "frameparser_parse_idle\n");
  // Valid input in this state is a CR/LF pair, or bare LF

  uint8_t byte = buffer_get_byte(b, 0);
  if (byte == '\x0D')
  {
    // Should be CR/LF pair. Make sure we have at least two bytes
    size_t len = buffer_get_length(b);
    if (len < 2)
      return false;  // No progress

    // Make sure second byte is LF
    byte = buffer_get_byte(b, 1);
    if (byte != '\x0A')
    {
      frameparser_set_error(fp, "Expected 0x0A after 0x0D, got 0x%02X", byte);
      return false;  // No progress
    }

    // Eat the CR/LF pair
    buffer_consume(b, 2);
    return true;
  }
  else if (byte == '\x0A')
  {
    // Bare LF
    buffer_consume(b, 1);
    return true;
  }

  // Something else? Must be the start of a frame
  fp->state = FP_STATE_COMMAND;
  return true;
}
Esempio n. 4
0
packet_t* packet_decode(buffer_t* buffer)
{
	int error = buffer_ok;
	uint16_t length;
	uint8_t id;

	buffer->position = 0;

	error |= buffer_get_short(buffer, &length);
	error |= buffer_get_byte(buffer, &id);
	error |= buffer_available(buffer) == length;

	if (error || length > 5000 || length == 0)
		return NULL;

	uint8_t payload[length];
	memcpy(payload, buffer->payload + buffer->position, length);

	packet_t* packet = safe_alloc(sizeof(packet_t));
	packet->id = id;
	packet->buffer = buffer_wrap(payload, length);
	packet->buffer->position = 0;
	return packet;
}
Esempio n. 5
0
// Parses a header line. Returns true iff progress was made.
bool frameparser_parse_header(frameparser *fp, buffer *b)
{
  log_printf(LOG_LEVEL_DEBUG, "frameparser_parse_header\n");
  // Valid input in this state is either:
  // 1. CR/LF or LF alone, denoting the end of headers
  // 2. A key name, followed by a colon, followed by a value name, terminated with CR/LF or LF

  // Try to find LF line terminator
  int lfpos = buffer_find_byte(b, '\x0A');
  if (lfpos < 0)  // No LF yet?
  {
    if (buffer_get_length(b) > LIMIT_FRAME_HEADER_LINE_LEN)
      frameparser_set_error(fp, "Line length limit exceeded waiting for header");

    return false;  // No progress
  }
  else if (lfpos == 0)  // LF alone
  {
    buffer_consume(b, 1);
    frameparser_parse_headers_complete(fp);
    return true;
  }
  else if ((lfpos == 1) && (buffer_get_byte(b, 0) == '\x0D'))  // CR/LF alone
  {
    buffer_consume(b, 2);
    frameparser_parse_headers_complete(fp);
    return true;
  }

  // Figure out number of bytes in the line
  int len = lfpos;
  if (buffer_get_byte(b, len - 1) == '\x0D')
    len--;

  // Find the colon delimiter
  int colonpos = buffer_find_byte_within(b, ':', 0, len);
  if (colonpos < 0)  // No colon?
  {
    frameparser_set_error(fp, "Expected colon delimiter on header line");
    return false;
  }
  else if (colonpos == 0)  // Starts with colon?
  {
    frameparser_set_error(fp, "Header name has zero length");
    return false;
  }

  // Extract the key
  bytestring *key = bytestring_new(colonpos);
  buffer_append_bytestring(b, key, 0, colonpos);

  // Extract the value
  bytestring *val = bytestring_new(len - colonpos - 1);
  buffer_append_bytestring(b, val, colonpos + 1, len - colonpos - 1);

  // Consume the current line
  buffer_consume(b, lfpos + 1);

  // Unescape the key and value if needed
  frame_command cmd = frame_get_command(fp->cur_frame);
  if ((cmd != CMD_CONNECT) && (cmd != CMD_CONNECTED))
  {
    key = unescape_header_bytestring(key);
    val = unescape_header_bytestring(val);
  }

  bytestring_dump(key);
  bytestring_dump(val);

  headerbundle *hb = frame_get_headerbundle(fp->cur_frame);
  headerbundle_append_header(hb, key, val);  // The bundle takes ownership of key and val

  return true;
}