/** * 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; }
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; }