int encode_field_array(lua_sandbox* lsb, output_data* d, int t, const char* representation) { int result = 0, first = 1; lua_checkstack(lsb->m_lua, 2); lua_pushnil(lsb->m_lua); while (result == 0 && lua_next(lsb->m_lua, -2) != 0) { // numerics are not packed, the space savings aren't worth the extra // buffer manipulation if (lua_type(lsb->m_lua, -1) != t) { snprintf(lsb->m_error_message, ERROR_SIZE, "array has mixed types"); return 1; } result = encode_field_value(lsb, d, first, representation); first = 0; lua_pop(lsb->m_lua, 1); // Remove the value leaving the key on top for // the next interation. } return result; }
/** * Encodes a field that contains metadata in addition to its value. * * @param lsb Pointer to the sandbox. * @param ob Pointer to the output data buffer. * * @return lsb_err_value NULL on success error message on failure */ static lsb_err_value encode_field_object(lsb_lua_sandbox *lsb, lsb_output_buffer *ob) { const char *representation = NULL; lua_getfield(lsb->lua, -1, "representation"); if (lua_isstring(lsb->lua, -1)) { representation = lua_tostring(lsb->lua, -1); } int value_type = -1; lua_getfield(lsb->lua, -2, "value_type"); if (lua_isnumber(lsb->lua, -1)) { value_type = (int)lua_tointeger(lsb->lua, -1); } lua_getfield(lsb->lua, -3, "value"); lsb_err_value ret = encode_field_value(lsb, ob, 1, representation, value_type); lua_pop(lsb->lua, 3); // remove representation, value_type and value return ret; }
/** * Encodes a field that has an array of values. * * @param lsb Pointer to the sandbox. * @param ob Pointer to the output data buffer. * @param t Lua type of the array values. * @param representation String representation of the field i.e., "ms" * * @return lsb_err_value NULL on success error message on failure */ static lsb_err_value encode_field_array(lsb_lua_sandbox *lsb, lsb_output_buffer *ob, int t, const char *representation, int value_type) { lsb_err_value ret = NULL; int first = (int)lua_objlen(lsb->lua, -1); int multiple = first > 1 ? first : 0; size_t len_pos = 0; lua_checkstack(lsb->lua, 2); lua_pushnil(lsb->lua); while (!ret && lua_next(lsb->lua, -2) != 0) { if (lua_type(lsb->lua, -1) != t) { snprintf(lsb->error_message, LSB_ERROR_SIZE, "array has mixed types"); return LSB_ERR_HEKA_INPUT; } ret = encode_field_value(lsb, ob, first, representation, value_type); if (first) { len_pos = ob->pos; first = 0; } lua_pop(lsb->lua, 1); // Remove the value leaving the key on top for // the next interation. } if (!ret && multiple && value_type == LSB_PB_INTEGER) { // fix up the varint packed length size_t i = len_pos - 2; int y = 0; // find the length byte while (ob->buf[i] != 0 && y < LSB_MAX_VARINT_BYTES) { --i; ++y; } if (y == LSB_MAX_VARINT_BYTES) { snprintf(lsb->error_message, LSB_ERROR_SIZE, "unable set the length of the packed integer array"); return LSB_ERR_LUA; } ret = lsb_pb_update_field_length(ob, i); } return ret; }
/** * 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; }