示例#1
0
/**
 * Iterates over the specified Lua table encoding the contents as user defined
 * message fields.
 *
 * @param lsb  Pointer to the sandbox.
 * @param ob  Pointer to the output data buffer.
 * @param tag Field identifier.
 * @param name Key used for the Lua table entry lookup.
 * @param index Lua stack index of the table.
 *
 * @return lsb_err_value NULL on success error message on failure
 */
static lsb_err_value
encode_fields(lsb_lua_sandbox *lsb, lsb_output_buffer *ob, char tag,
              const char *name, int index)
{
  lsb_err_value ret = NULL;
  lua_getfield(lsb->lua, index, name);
  if (!lua_istable(lsb->lua, -1)) {
    return ret;
  }

  lua_rawgeti(lsb->lua, -1, 1); // test for the array notation
  size_t len_pos, len;
  if (lua_istable(lsb->lua, -1)) {
    int i = 1;
    do {
      ret = lsb_pb_write_key(ob, tag, LSB_PB_WT_LENGTH);
      if (ret) return ret;

      len_pos = ob->pos;
      ret = lsb_pb_write_varint(ob, 0);  // length tbd later
      if (ret) return ret;

      lua_getfield(lsb->lua, -1, "name");
      if (lua_isstring(lsb->lua, -1)) {
        const char *s = lua_tolstring(lsb->lua, -1, &len);
        ret = lsb_pb_write_string(ob, LSB_PB_NAME, s, len);
      } else {
        snprintf(lsb->error_message, LSB_ERROR_SIZE,
                 "field name must be a string");
        ret = LSB_ERR_HEKA_INPUT;
      }
      lua_pop(lsb->lua, 1); // remove the name
      if (ret) return ret;

      ret = encode_field_object(lsb, ob);
      if (!ret) ret = lsb_pb_update_field_length(ob, len_pos);
      if (ret) return ret;

      lua_pop(lsb->lua, 1); // remove the current field object
      lua_rawgeti(lsb->lua, -1, ++i); // grab the next field object
    } while (!ret && !lua_isnil(lsb->lua, -1));
  } else {
    lua_pop(lsb->lua, 1); // remove the array test value
    lua_checkstack(lsb->lua, 2);
    lua_pushnil(lsb->lua);
    while (lua_next(lsb->lua, -2) != 0) {
      ret = lsb_pb_write_key(ob, tag, LSB_PB_WT_LENGTH);
      if (ret) return ret;

      len_pos = ob->pos;
      ret = lsb_pb_write_varint(ob, 0);  // length tbd later
      if (ret) return ret;

      if (lua_isstring(lsb->lua, -2)) {
        const char *s = lua_tolstring(lsb->lua, -2, &len);
        ret = lsb_pb_write_string(ob, LSB_PB_NAME, s, len);
      } else {
        snprintf(lsb->error_message, LSB_ERROR_SIZE,
                 "field name must be a string");
        ret = LSB_ERR_HEKA_INPUT;
      }
      if (ret) return ret;

      ret = encode_field_value(lsb, ob, 1, NULL, -1);
      if (!ret) ret = lsb_pb_update_field_length(ob, len_pos);
      if (ret) return ret;

      lua_pop(lsb->lua, 1); // Remove the value leaving the key on top for
                            // the next interation.
    }
  }
  lua_pop(lsb->lua, 1); // remove the fields table
  return ret;
}
int encode_field_value(lua_sandbox* lsb, output_data* d, int first,
                       const char* representation)
{
  int result = 1;
  size_t len;
  const char* s;

  int t = lua_type(lsb->lua, -1);
  switch (t) {
  case LUA_TSTRING:
    if (first && representation) { // this uglyness keeps the protobuf
                                   // fields in order without additional
                                   // lookups
      if (pb_write_string(d, 3, representation, strlen(representation))) {
        return 1;
      }
    }
    s = lua_tolstring(lsb->lua, -1, &len);
    result = pb_write_string(d, 4, s, len);
    break;
  case LUA_TNUMBER:
    if (first) {
      if (pb_write_tag(d, 2, 0)) return 1;
      if (pb_write_varint(d, 3)) return 1;
      if (representation) {
        if (pb_write_string(d, 3, representation,
                            strlen(representation))) {
          return 1;
        }
      }
    }
    result = encode_double(lsb, d, 7);
    break;
  case LUA_TBOOLEAN:
    if (first) {
      if (pb_write_tag(d, 2, 0)) return 1;
      if (pb_write_varint(d, 4)) return 1;
      if (representation) {
        if (pb_write_string(d, 3, representation,
                            strlen(representation))) {
          return 1;
        }
      }
    }
    if (pb_write_tag(d, 8, 0)) return 1;
    result = pb_write_bool(d, lua_toboolean(lsb->lua, -1));
    break;
  case LUA_TTABLE:
    {
      lua_rawgeti(lsb->lua, -1, 1);
      int t = lua_type(lsb->lua, -1);
      lua_pop(lsb->lua, 1); // remove the array test value
      if (LUA_TNIL == t) {
        result = encode_field_object(lsb, d);
      } else {
        result = encode_field_array(lsb, d, t, representation);
      }
    }
    break;
  default:
    snprintf(lsb->error_message, LSB_ERROR_SIZE, "unsupported type %d", t);
    result = 1;
  }
  return result;
}
示例#3
0
static lsb_err_value
encode_field_value(lsb_lua_sandbox *lsb, lsb_output_buffer *ob, int first,
                   const char *representation, int value_type)
{
  lsb_err_value ret = NULL;
  size_t len;
  const char *s;

  int t = lua_type(lsb->lua, -1);
  switch (t) {
  case LUA_TSTRING:
    switch (value_type) {
    case -1: // not specified defaults to string
      value_type = 0;
    case 0:
    case 1:
      break;
    default:
      snprintf(lsb->error_message, LSB_ERROR_SIZE,
               "invalid string value_type: %d", value_type);
      return LSB_ERR_HEKA_INPUT;
    }
    if (first) { // this uglyness keeps the protobuf fields in order without
                 // additional lookups
      if (value_type == LSB_PB_BYTES) {
        ret = lsb_pb_write_key(ob, LSB_PB_VALUE_TYPE, LSB_PB_WT_VARINT);
        if (!ret) ret = lsb_pb_write_varint(ob, value_type);
        if (ret) return ret;
      }
      if (representation) {
        ret = lsb_pb_write_string(ob, LSB_PB_REPRESENTATION, representation,
                                  strlen(representation));
        if (ret) return ret;
      }
    }
    s = lua_tolstring(lsb->lua, -1, &len);
    if (value_type == LSB_PB_BYTES) {
      ret = lsb_pb_write_string(ob, LSB_PB_VALUE_BYTES, s, len);
      if (ret) return ret;
    } else {
      ret = lsb_pb_write_string(ob, LSB_PB_VALUE_STRING, s, len);
      if (ret) return ret;
    }
    break;
  case LUA_TNUMBER:
    switch (value_type) {
    case -1: // not specified defaults to double
      value_type = 3;
    case 2:
    case 3:
      break;
    default:
      snprintf(lsb->error_message, LSB_ERROR_SIZE,
               "invalid numeric value_type: %d", value_type);
      return LSB_ERR_HEKA_INPUT;
    }
    if (first) {
      ret = lsb_pb_write_key(ob, LSB_PB_VALUE_TYPE, LSB_PB_WT_VARINT);
      if (!ret) ret = lsb_pb_write_varint(ob, value_type);
      if (ret) return ret;

      if (representation) {
        ret = lsb_pb_write_string(ob, LSB_PB_REPRESENTATION, representation,
                                  strlen(representation));
        if (ret) return ret;
      }
      if (1 == first) {
        if (value_type == LSB_PB_INTEGER) {
          ret = lsb_pb_write_key(ob, LSB_PB_VALUE_INTEGER, LSB_PB_WT_VARINT);
        } else {
          ret = lsb_pb_write_key(ob, LSB_PB_VALUE_DOUBLE, LSB_PB_WT_FIXED64);
        }
        if (ret) return ret;
      } else { // pack array
        if (value_type == LSB_PB_INTEGER) {
          ret = lsb_pb_write_key(ob, LSB_PB_VALUE_INTEGER, LSB_PB_WT_LENGTH);
          if (!ret) ret = lsb_pb_write_varint(ob, 0); // length tbd later
        } else {
          ret = lsb_pb_write_key(ob, LSB_PB_VALUE_DOUBLE, LSB_PB_WT_LENGTH);
          if (!ret) ret = lsb_pb_write_varint(ob, first * sizeof(double));
        }
        if (ret) return ret;
      }
    }
    if (value_type == LSB_PB_INTEGER) {
      ret = lsb_pb_write_varint(ob, lua_tointeger(lsb->lua, -1));
    } else {
      ret = lsb_pb_write_double(ob, lua_tonumber(lsb->lua, -1));
    }
    if (ret) return ret;
    break;

  case LUA_TBOOLEAN:
    if (value_type != -1 && value_type != LSB_PB_BOOL) {
      snprintf(lsb->error_message, LSB_ERROR_SIZE,
               "invalid boolean value_type: %d", value_type);
      return LSB_ERR_HEKA_INPUT;
    }
    if (first) {
      ret = lsb_pb_write_key(ob, LSB_PB_VALUE_TYPE, LSB_PB_WT_VARINT);
      if (!ret) ret = lsb_pb_write_varint(ob, LSB_PB_BOOL);
      if (ret) return ret;

      if (representation) {
        ret = lsb_pb_write_string(ob, LSB_PB_REPRESENTATION, representation,
                                  strlen(representation));
        if (ret) return ret;
      }
      if (1 == first) {
        ret = lsb_pb_write_key(ob, LSB_PB_VALUE_BOOL, LSB_PB_WT_VARINT);
      } else {
        ret = lsb_pb_write_key(ob, LSB_PB_VALUE_BOOL, LSB_PB_WT_LENGTH);
        if (!ret) ret = lsb_pb_write_varint(ob, first);
      }
      if (ret) return ret;
    }
    ret = lsb_pb_write_bool(ob, lua_toboolean(lsb->lua, -1));
    break;

  case LUA_TTABLE:
    {
      lua_rawgeti(lsb->lua, -1, 1);
      int t = lua_type(lsb->lua, -1);
      lua_pop(lsb->lua, 1); // remove the array test value
      switch (t) {
      case LUA_TNIL:
        ret = encode_field_object(lsb, ob);
        break;
      case LUA_TNUMBER:
      case LUA_TSTRING:
      case LUA_TBOOLEAN:
        ret = encode_field_array(lsb, ob, t, representation, value_type);
        break;
      default:
        snprintf(lsb->error_message, LSB_ERROR_SIZE,
                 "unsupported array type: %s", lua_typename(lsb->lua, t));
        return LSB_ERR_LUA;
      }
    }
    break;

  case LUA_TLIGHTUSERDATA:
    lua_getfield(lsb->lua, -4, "userdata");
    if (lua_type(lsb->lua, -1) != LUA_TUSERDATA) {
      snprintf(lsb->error_message, LSB_ERROR_SIZE,
               "a lightuserdata output must also specify a userdata value");
      return LSB_ERR_LUA;
    }
    // fall thru

  case LUA_TUSERDATA:
    {
      lua_CFunction fp = lsb_get_output_function(lsb->lua, -1);
      size_t len_pos = 0;
      if (!fp) {
        snprintf(lsb->error_message, LSB_ERROR_SIZE,
                 "userdata object does not implement lsb_output");
        return LSB_ERR_LUA;
      }
      if (first) {
        ret = lsb_pb_write_key(ob, LSB_PB_VALUE_TYPE, LSB_PB_WT_VARINT);
        if (ret) return ret;

        // encode userdata as a byte array
        ret = lsb_pb_write_varint(ob, LSB_PB_BYTES);
        if (ret) return ret;

        if (representation) {
          ret = lsb_pb_write_string(ob, LSB_PB_REPRESENTATION, representation,
                                    strlen(representation));
          if (ret) return ret;
        }
      }

      ret = lsb_pb_write_key(ob, LSB_PB_VALUE_BYTES, LSB_PB_WT_LENGTH);
      if (ret) return ret;

      len_pos = ob->pos;
      ret = lsb_pb_write_varint(ob, 0);  // length tbd later
      if (ret) return ret;

      lua_pushlightuserdata(lsb->lua, ob);
      int result = fp(lsb->lua);
      lua_pop(lsb->lua, 1); // remove output function
      if (result) {
        snprintf(lsb->error_message, LSB_ERROR_SIZE,
                 "userdata output callback failed: %d", result);
        return LSB_ERR_LUA;
      }
      ret = lsb_pb_update_field_length(ob, len_pos);
    }
    if (t == LUA_TLIGHTUSERDATA) lua_pop(lsb->lua, 1); // remove the userdata
    break;

  default:
    snprintf(lsb->error_message, LSB_ERROR_SIZE, "unsupported type: %s",
             lua_typename(lsb->lua, t));
    return LSB_ERR_LUA;
  }
  return ret;
}