static bool
read_string_value(const char *p, const char *e, int ai, lsb_read_value *val)
{
  int acnt = 0;
  int tag = 0;
  int wiretype = 0;
  while (p && p < e) {
    val->type = LSB_READ_NIL;
    p = lsb_pb_read_key(p, &tag, &wiretype);
    p = read_string(wiretype, p, e, &val->u.s);
    if (p) {
      if (ai == acnt++) {
        val->type = LSB_READ_STRING;
        return true;
      }
    }
  }
  return false;
}
bool lsb_decode_heka_message(lsb_heka_message *m,
                             const char *buf,
                             size_t len,
                             lsb_logger *logger)
{
  if (!m || !buf || len == 0) {
    if (logger && logger->cb) {
      logger->cb(logger->context, __func__, 4, LSB_ERR_UTIL_NULL);
    }
    return false;
  }

  const char *cp  = buf;       // current position
  const char *lp  = buf;       // last position
  const char *ep  = buf + len; // end position
  int wiretype    = 0;
  int tag         = 0;
  long long val   = 0;
  bool timestamp  = false;

  lsb_clear_heka_message(m);

  do {
    cp = lsb_pb_read_key(cp, &tag, &wiretype);

    switch (tag) {
    case LSB_PB_UUID:
      cp = read_string(wiretype, cp, ep, &m->uuid);
      if (m->uuid.len != LSB_UUID_SIZE) cp = NULL;
      break;

    case LSB_PB_TIMESTAMP:
      cp = process_varint(wiretype, cp, ep, &m->timestamp);
      if (cp) timestamp = true;
      break;

    case LSB_PB_TYPE:
      cp = read_string(wiretype, cp, ep, &m->type);
      break;

    case LSB_PB_LOGGER:
      cp = read_string(wiretype, cp, ep, &m->logger);
      break;

    case LSB_PB_SEVERITY:
      cp = process_varint(wiretype, cp, ep, &val);
      if (cp) m->severity = (int)val;
      break;

    case LSB_PB_PAYLOAD:
      cp = read_string(wiretype, cp, ep, &m->payload);
      break;

    case LSB_PB_ENV_VERSION:
      cp = read_string(wiretype, cp, ep, &m->env_version);
      break;

    case LSB_PB_PID:
      cp = process_varint(wiretype, cp, ep, &val);
      if (cp) m->pid = (int)val;
      break;

    case LSB_PB_HOSTNAME:
      cp = read_string(wiretype, cp, ep, &m->hostname);
      break;

    case LSB_PB_FIELDS:
      if (wiretype != 2) {
        cp = NULL;
        break;
      }
      if (m->fields_len == m->fields_size) {
        int step = 8;
        m->fields_size += step;
        lsb_heka_field *tmp = realloc(m->fields,
                                      m->fields_size * sizeof(lsb_heka_field));
        if (!tmp) {
          if (logger && logger->cb) {
            logger->cb(logger->context, __func__, 0, "fields reallocation failed");
          }
          return false;
        }
        m->fields = tmp;
        memset(&m->fields[m->fields_len], 0, step * sizeof(lsb_heka_field));
      }
      cp = process_fields(&m->fields[m->fields_len], cp, ep);
      ++m->fields_len;
      break;

    default:
      cp = NULL;
      break;
    }
    if (cp) lp = cp;
  } while (cp && cp < ep);

  if (!cp) {
    if (logger && logger->cb) {
      logger->cb(logger->context, __func__, 4, "tag:%d wiretype:%d position:%d",
                 tag, wiretype, lp - buf);
    }
    return false;
  }

  if (!m->uuid.s) {
    if (logger && logger->cb) {
      logger->cb(logger->context, __func__, 4, "missing " LSB_UUID);
    }
    return false;
  }

  if (!timestamp) {
    if (logger && logger->cb) {
      logger->cb(logger->context, __func__, 4, "missing " LSB_TIMESTAMP);
    }
    return false;
  }

  m->raw.s = buf;
  m->raw.len = len;
  return true;
}
static const char*
process_fields(lsb_heka_field *f, const char *p, const char *e)
{
  int tag       = 0;
  int wiretype  = 0;
  long long vi  = 0;

  p = lsb_pb_read_varint(p, e, &vi);
  if (!p || vi < 0 || p + vi > e) {
    return NULL;
  }
  e = p + vi; // only process to the end of the current field record

  do {
    p = lsb_pb_read_key(p, &tag, &wiretype);

    switch (tag) {
    case LSB_PB_NAME:
      p = read_string(wiretype, p, e, &f->name);
      break;

    case LSB_PB_VALUE_TYPE:
      p = process_varint(wiretype, p, e, &vi);
      if (p) {
        f->value_type = (int)vi;
      }
      break;

    case LSB_PB_REPRESENTATION:
      p = read_string(wiretype, p, e, &f->representation);
      break;

      // don't bother with the value(s) until we actually need them
      // since this stream is created by Hindsight
      // - tags are guaranteed to be properly ordered (values at the end)
      // - there won't be repeated tags for packed values
    case LSB_PB_VALUE_STRING:
    case LSB_PB_VALUE_BYTES:
      if (wiretype != 2) {
        p = NULL;
        break;
      }
      f->value.s = p - 1;
      f->value.len = e - f->value.s;
      p = e;
      break;

    case LSB_PB_VALUE_INTEGER:
    case LSB_PB_VALUE_BOOL:
      if (wiretype != 0 && wiretype != 2) {
        p = NULL;
        break;
      }
      // fall thru
    case LSB_PB_VALUE_DOUBLE:
      if (tag == 7 && wiretype != 1 && wiretype != 2) {
        p = NULL;
        break;
      }
      if (wiretype == 2) {
        p = lsb_pb_read_varint(p, e, &vi);
        if (!p || vi < 0 || p + vi > e) {
          p = NULL;
          break;
        }
      }
      f->value.s = p;
      f->value.len = e - f->value.s;
      p = e;
      break;

    default:
      p = NULL; // don't allow unknown tags
      break;
    }
  } while (p && p < e);

  return p && f->name.s ? p : NULL;
}
static void output_text(lsb_heka_message *msg)
{
  static char tstr[64];
  if (!msg->raw.s) return;

  fprintf(stdout, ":Uuid: %02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx"
          "-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n",
          msg->uuid.s[0], msg->uuid.s[1], msg->uuid.s[2], msg->uuid.s[3],
          msg->uuid.s[4], msg->uuid.s[5], msg->uuid.s[6], msg->uuid.s[7],
          msg->uuid.s[8], msg->uuid.s[9], msg->uuid.s[10], msg->uuid.s[11],
          msg->uuid.s[12], msg->uuid.s[13], msg->uuid.s[14], msg->uuid.s[15]);
  fprintf(stdout, ":Timestamp: ");

  time_t t = floor(msg->timestamp / 1e9);
  double frac = msg->timestamp - t * 1e9;
  struct tm *tms = gmtime(&t);
  strftime(tstr, sizeof(tstr) - 1, "%Y-%m-%dT%H:%M:%S", tms);
  fprintf(stdout, "%s.%09lldZ\n", tstr, (long long)frac);
  output_cs(":Type", &msg->type, true);
  output_cs(":Logger", &msg->logger, true);
  fprintf(stdout, ":Severity: %d\n", msg->severity);
  output_cs(":Payload", &msg->payload, true);
  output_cs(":EnvVersion", &msg->env_version, true);
  if (msg->pid == INT_MIN) {
    fprintf(stdout, ":Pid: <nil>\n");
  } else {
    fprintf(stdout, ":Pid: %d\n", msg->pid);
  }
  output_cs(":Hostname", &msg->hostname, true);
  fprintf(stdout, ":Fields:\n");
  for (int i = 0; i < msg->fields_len; ++i) {
    fprintf(stdout, "    | name: %.*s type: %d ", (int)msg->fields[i].name.len,
            msg->fields[i].name.s, msg->fields[i].value_type);
    output_cs("representation", &msg->fields[i].representation, false);
    fprintf(stdout, " value: ");
    const char *p = msg->fields[i].value.s;
    const char *e = msg->fields[i].value.s + msg->fields[i].value.len;
    switch (msg->fields[i].value_type) {
    case LSB_PB_STRING:
      {
        lsb_const_string cs;
        int tag = 0;
        int wiretype = 0;
        while (p && p < e) {
          p = lsb_pb_read_key(p, &tag, &wiretype);
          p = read_string(wiretype, p, e, &cs);
          if (p) {
            fprintf(stdout, "%.*s", (int)cs.len, cs.s);
          }
        }
      }
      break;
    case LSB_PB_BYTES:
      {
        lsb_const_string cs;
        int tag = 0;
        int wiretype = 0;
        while (p && p < e) {
          p = lsb_pb_read_key(p, &tag, &wiretype);
          p = read_string(wiretype, p, e, &cs);
          if (p) {
            for (size_t i = 0; i < cs.len; ++i) {
              if (isprint(cs.s[i])) {
                if (cs.s[i] == '\\') {
                  fwrite("\\\\", 2, 1, stdout);
                } else {
                  putchar(cs.s[i]);
                }
              } else {
                fprintf(stdout, "\\x%02hhx", (unsigned char)cs.s[i]);
              }
            }
          }
        }
      }
      break;
    case LSB_PB_INTEGER:
      {
        long long ll = 0;
        while (p && p < e) {
          p = lsb_pb_read_varint(p, e, &ll);
          if (p) {
            fprintf(stdout, "%lld", ll);
          }
        }
      }
      break;
    case LSB_PB_DOUBLE:
      {
        double d;
        for (int i = 0; p <= (e - sizeof(double)); p += sizeof(double), ++i) {
          memcpy(&d, p, sizeof(double));
          if (i > 0) {
            fprintf(stdout, ",");
          }
          fprintf(stdout, "%.17g", d);
        }
      }
      break;
    case LSB_PB_BOOL:
      {
        long long ll = 0;
        while (p && p < e) {
          p = lsb_pb_read_varint(p, e, &ll);
          if (p) {
            fprintf(stdout, "%s", ll == 0 ? "false" : "true");
          }
        }
      }
      break;
    }
    fprintf(stdout, "\n");
  }
  fprintf(stdout, "\n");
  return;
}
Exemple #5
0
static const char* process_fields(lua_State *lua, const char *p, const char *e)
{
  int tag = 0;
  int wiretype = 0;
  int has_name = 0;
  int value_count = 0;
  long long len = 0;

  p = lsb_pb_read_varint(p, e, &len);
  if (!p || len < 0 || p + len > e) {
    return NULL;
  }
  e = p + len; // only process to the end of the current field record

  lua_newtable(lua); // Table to be added to the Fields array index 4
  lua_newtable(lua); // Table to hold the value(s) index 5
  do {
    p = lsb_pb_read_key(p, &tag, &wiretype);

    switch (tag) {
    case 1:
      p = read_string(lua, wiretype, p, e);
      if (p) {
        lua_setfield(lua, 4, "name");
        has_name = 1;
      }
      break;

    case 2:
      p = process_varint(lua, "value_type", wiretype, 4, p, e);
      break;

    case 3:
      p = read_string(lua, wiretype, p, e);
      if (p) {
        lua_setfield(lua, 4, "representation");
      }
      break;

    case 4: // value_string
    case 5: // value_bytes
      p = read_string(lua, wiretype, p, e);
      if (p) {
        lua_rawseti(lua, 5, ++value_count);
      }
      break;

    case 6: // value_integer
      {
        long long val = 0;
        switch (wiretype) {
        case 0:
          p = lsb_pb_read_varint(p, p + len, &val);
          if (!p) break;
          lua_pushnumber(lua, (lua_Number)val);
          lua_rawseti(lua, 5, ++value_count);
          break;
        case 2:
          p = lsb_pb_read_varint(p, e, &len);
          if (!p || len < 0 || p + len > e) {
            p = NULL;
            break;
          }
          do {
            p = lsb_pb_read_varint(p, p + len, &val);
            if (!p) break;
            lua_pushnumber(lua, (lua_Number)val);
            lua_rawseti(lua, 5, ++value_count);
          } while (p < e);
          break;
        default:
          p = NULL;
          break;
        }
      }
      break;

    case 7: // value_double
      {
        double val = 0;
        switch (wiretype) {
        case 1:
          if (p + sizeof(double) > e) {
            p = NULL;
            break;
          }
          memcpy(&val, p, sizeof(double));
          p += sizeof(double);
          lua_pushnumber(lua, val);
          lua_rawseti(lua, 5, ++value_count);
          break;
        case 2:
          p = lsb_pb_read_varint(p, e, &len);
          if (!p || len < 0 || p + len > e || len % sizeof(double) != 0) {
            p = NULL;
            break;
          }
          do {
            memcpy(&val, p, sizeof(double));
            p += sizeof(double);
            lua_pushnumber(lua, val);
            lua_rawseti(lua, 5, ++value_count);
          } while (p < e);
          break;
        default:
          p = NULL;
          break;
        }
      }
      break;

    case 8: // value_bool
      {
        long long val = 0;
        switch (wiretype) {
        case 0:
          p = lsb_pb_read_varint(p, p + len, &val);
          if (!p) break;
          lua_pushboolean(lua, (int)val);
          lua_rawseti(lua, 5, ++value_count);
          break;
        case 2:
          p = lsb_pb_read_varint(p, e, &len);
          if (!p || len < 0 || p + len > e) {
            p = NULL;
            break;
          }
          do {
            p = lsb_pb_read_varint(p, p + len, &val);
            if (!p) break;
            lua_pushboolean(lua, (int)val);
            lua_rawseti(lua, 5, ++value_count);
          } while (p < e);
          break;
        default:
          p = NULL;
          break;
        }
      }
      break;
    default:
      p = NULL; // don't allow unknown tags
      break;
    }
  } while (p && p < e);

  lua_setfield(lua, 4, "value");

  return has_name ? p : NULL;
}
Exemple #6
0
int heka_decode_message(lua_State *lua)
{
  int n = lua_gettop(lua);
  if (n != 1 || lua_type(lua, 1) != LUA_TSTRING) {
    return luaL_argerror(lua, 0, "must have one string argument");
  }

  size_t len;
  const char *pbstr = lua_tolstring(lua, 1, &len);
  if (len < 20) {
    return luaL_error(lua, "invalid message, too short");
  }

  const char *p = pbstr;
  const char *lp = p;
  const char *e = pbstr + len;
  int wiretype = 0;
  int tag = 0;
  int has_uuid = 0;
  int has_timestamp = 0;
  int field_count = 0;

  lua_newtable(lua); // message table index 2
  do {
    p = lsb_pb_read_key(p, &tag, &wiretype);

    switch (tag) {
    case 1:
      p = read_string(lua, wiretype, p, e);
      if (p && p - lp == 18) {
        lua_setfield(lua, 2, "Uuid");
        has_uuid = 1;
      } else {
        p = NULL;
      }
      break;

    case 2:
      p = process_varint(lua, "Timestamp", wiretype, 2, p, e);
      if (p) {
        has_timestamp = 1;
      }
      break;

    case 3:
      p = read_string(lua, wiretype, p, e);
      if (p) {
        lua_setfield(lua, 2, "Type");
      }
      break;

    case 4:
      p = read_string(lua, wiretype, p, e);
      if (p) {
        lua_setfield(lua, 2, "Logger");
      }
      break;

    case 5:
      p = process_varint(lua, "Severity", wiretype, 2, p, e);
      break;

    case 6:
      p = read_string(lua, wiretype, p, e);
      if (p) {
        lua_setfield(lua, 2, "Payload");
      }
      break;

    case 7:
      p = read_string(lua, wiretype, p, e);
      if (p) {
        lua_setfield(lua, 2, "EnvVersion");
      }
      break;

    case 8:
      p = process_varint(lua, "Pid", wiretype, 2, p, e);
      break;

    case 9:
      p = read_string(lua, wiretype, p, e);
      if (p) {
        lua_setfield(lua, 2, "Hostname");
      }
      break;

    case 10:
      if (wiretype != 2) {
        p = NULL;
        break;
      }
      if (field_count == 0) {
        lua_newtable(lua); // Fields table index 3
      }
      p = process_fields(lua, p, e);
      if (p) {
        lua_rawseti(lua, 3, ++field_count);
      }
      break;

    default:
      p = NULL; // don't allow unknown tags
      break;
    }
    if (p) lp = p;
  } while (p && p < e);

  if (!p) {
    return luaL_error(lua, "error in tag: %d wiretype: %d offset: %d", tag,
                      wiretype, (const char *)lp - pbstr);
  }

  if (!has_uuid || !has_timestamp) {
    return luaL_error(lua, "missing required field uuid: %s timestamp: %s",
                      has_uuid ? "found" : "not found",
                      has_timestamp ? "found" : "not found");
  }

  if (field_count) {
    lua_setfield(lua, 2, "Fields");
  }

  return 1;
}