int output(lua_State* lua) { void* luserdata = lua_touserdata(lua, lua_upvalueindex(1)); if (NULL == luserdata) { lua_pushstring(lua, "output() invalid lightuserdata"); lua_error(lua); } lua_sandbox* lsb = (lua_sandbox*)luserdata; int n = lua_gettop(lua); if (n == 0) { lua_pushstring(lua, "output() must have at least one argument"); lua_error(lua); } int result = 0; void* ud = NULL; for (int i = 1; result == 0 && i <= n; ++i) { switch (lua_type(lua, i)) { case LUA_TNUMBER: if (dynamic_snprintf(&lsb->m_output, "%0.9g", lua_tonumber(lua, i))) { result = 1; } break; case LUA_TSTRING: if (dynamic_snprintf(&lsb->m_output, "%s", lua_tostring(lua, i))) { result = 1; } break; case LUA_TNIL: if (dynamic_snprintf(&lsb->m_output, "nil")) { result = 1; } break; case LUA_TUSERDATA: ud = lua_touserdata(lua, i); if (heka_circular_buffer == userdata_type(lua, ud, i)) { if (output_circular_buffer((circular_buffer*)ud, &lsb->m_output)) { result = 1; } } break; } } lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_CURRENT] = lsb->m_output.m_pos; if (lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_CURRENT] > lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_MAXIMUM]) { lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_MAXIMUM] = lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_CURRENT]; } if (result != 0 || lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_CURRENT] > lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_LIMIT]) { lua_pushstring(lua, "output_limit exceeded"); lua_error(lua); } return 0; }
int ignore_value_type(lua_sandbox* lsb, serialization_data* data, int index) { void* ud = NULL; switch (lua_type(lsb->m_lua, index)) { case LUA_TTABLE: if (lua_getmetatable(lsb->m_lua, index) != 0) { lua_pop(lsb->m_lua, 1); // Remove the metatable. return 1; } if (lua_topointer(lsb->m_lua, index) == data->m_globals) { return 1; } break; case LUA_TUSERDATA: ud = lua_touserdata(lsb->m_lua, index); if ((heka_circular_buffer != userdata_type(lsb->m_lua, ud, index))) { return 1; } break; case LUA_TNONE: case LUA_TFUNCTION: case LUA_TTHREAD: case LUA_TLIGHTUSERDATA: return 1; } return 0; }
int inject_message(lua_State* lua) { static const char* default_type = "txt"; static const char* default_name = ""; void* luserdata = lua_touserdata(lua, lua_upvalueindex(1)); if (NULL == luserdata) { luaL_error(lua, "inject_message() invalid lightuserdata"); } lua_sandbox* lsb = (lua_sandbox*)luserdata; void* ud = NULL; const char* type = default_type; const char* name = default_name; switch (lua_gettop(lua)) { case 0: break; case 2: name = luaL_checkstring(lua, 2); // fallthru case 1: switch (lua_type(lua, 1)) { case LUA_TSTRING: type = lua_tostring(lua, 1); if (strlen(type) == 0) type = default_type; break; case LUA_TTABLE: type = ""; if (serialize_table_as_pb(lsb) != 0) { luaL_error(lua, "inject_message() cound not encode protobuf - %s", lsb->m_error_message); } break; case LUA_TUSERDATA: ud = lua_touserdata(lua, 1); if (heka_circular_buffer == userdata_type(lua, ud, 1)) { circular_buffer* cb = (circular_buffer*)ud; type = get_output_format(cb); lsb->m_output.m_pos = 0; if (output_circular_buffer(lua, cb, &lsb->m_output)) { luaL_error(lua, lsb->m_error_message); } } else { luaL_typerror(lua, 1, "circular_buffer"); } break; default: luaL_typerror(lua, 1, "string, table, or circular_buffer"); break; } break; default: luaL_error(lua, "inject_message() takes a maximum of 2 arguments"); break; } if (lsb->m_output.m_pos != 0) { update_output_stats(lsb); if (lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_CURRENT] > lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_LIMIT]) { if (lsb->m_error_message[0] == 0) { luaL_error(lua, "output_limit exceeded"); } luaL_error(lua, lsb->m_error_message); } int result = go_lua_inject_message(lsb->m_go, lsb->m_output.m_data, (int)(lsb->m_output.m_pos), (char*)type, (char*)name); lsb->m_output.m_pos = 0; if (result != 0) { luaL_error(lua, "inject_message() exceeded MaxMsgLoops"); } } return 0; }
int serialize_kvp(lua_sandbox* lsb, serialization_data* data, size_t parent) { int kindex = -2, vindex = -1; if (ignore_value_type(lsb, data, vindex)) return 0; int result = serialize_data(lsb, kindex, &lsb->m_output); if (result != 0) return result; size_t pos = data->m_keys.m_pos; if (dynamic_snprintf(&data->m_keys, "%s[%s]", data->m_keys.m_data + parent, lsb->m_output.m_data)) { return 1; } if (lua_type(lsb->m_lua, vindex) == LUA_TTABLE) { const void* ptr = lua_topointer(lsb->m_lua, vindex); table_ref* seen = find_table_ref(&data->m_tables, ptr); if (seen == NULL) { seen = add_table_ref(&data->m_tables, ptr, pos); if (seen != NULL) { data->m_keys.m_pos += 1; fprintf(data->m_fh, "%s = {}\n", data->m_keys.m_data + pos); result = serialize_table(lsb, data, pos); } else { snprintf(lsb->m_error_message, ERROR_SIZE, "preserve table out of memory"); return 1; } } else { fprintf(data->m_fh, "%s = ", data->m_keys.m_data + pos); data->m_keys.m_pos = pos; fprintf(data->m_fh, "%s\n", data->m_keys.m_data + seen->m_name_pos); } } else if (lua_type(lsb->m_lua, vindex) == LUA_TUSERDATA) { void* ud = lua_touserdata(lsb->m_lua, vindex); if (heka_circular_buffer == userdata_type(lsb->m_lua, ud, vindex)) { table_ref* seen = find_table_ref(&data->m_tables, ud); if (seen == NULL) { seen = add_table_ref(&data->m_tables, ud, pos); if (seen != NULL) { data->m_keys.m_pos += 1; result = serialize_circular_buffer( data->m_keys.m_data + pos, (circular_buffer*)ud, &lsb->m_output); if (result == 0) { fprintf(data->m_fh, "%s", lsb->m_output.m_data); } } else { snprintf(lsb->m_error_message, ERROR_SIZE, "preserve table out of memory"); result = 1; } } else { fprintf(data->m_fh, "%s = ", data->m_keys.m_data + pos); data->m_keys.m_pos = pos; fprintf(data->m_fh, "%s\n", data->m_keys.m_data + seen->m_name_pos); } } } else { fprintf(data->m_fh, "%s = ", data->m_keys.m_data + pos); data->m_keys.m_pos = pos; result = serialize_data(lsb, vindex, &lsb->m_output); if (result == 0) { fprintf(data->m_fh, "%s\n", lsb->m_output.m_data); } } return result; }
int output(lua_State* lua) { void* luserdata = lua_touserdata(lua, lua_upvalueindex(1)); if (NULL == luserdata) { luaL_error(lua, "output() invalid lightuserdata"); } lua_sandbox* lsb = (lua_sandbox*)luserdata; int n = lua_gettop(lua); if (n == 0) { luaL_error(lua, "output() must have at least one argument"); } int result = 0; void* ud = NULL; for (int i = 1; result == 0 && i <= n; ++i) { switch (lua_type(lua, i)) { case LUA_TNUMBER: if (serialize_double(&lsb->m_output, lua_tonumber(lua, i))) { result = 1; } break; case LUA_TSTRING: if (dynamic_snprintf(&lsb->m_output, "%s", lua_tostring(lua, i))) { result = 1; } break; case LUA_TNIL: if (dynamic_snprintf(&lsb->m_output, "nil")) { result = 1; } break; case LUA_TBOOLEAN: if (dynamic_snprintf(&lsb->m_output, "%s", lua_toboolean(lsb->m_lua, i) ? "true" : "false")) { result = 1; } break; case LUA_TTABLE: if (!dynamic_snprintf(&lsb->m_output, "{")) { serialization_data data; data.m_globals = NULL; data.m_tables.m_size = 64; data.m_tables.m_pos = 0; data.m_tables.m_array = malloc(data.m_tables.m_size * sizeof(table_ref)); if (data.m_tables.m_array == NULL) { snprintf(lsb->m_error_message, ERROR_SIZE, "json table serialization out of memory"); result = 1; } else { lua_checkstack(lsb->m_lua, 2); lua_getfield(lsb->m_lua, i, "_name"); if (lua_type(lsb->m_lua, -1) != LUA_TSTRING) { lua_pop(lsb->m_lua, 1); // remove the failed _name result lua_pushstring(lsb->m_lua, "table"); // add default name } lua_pushvalue(lsb->m_lua, i); result = serialize_kvp_as_json(lsb, &data, 1); if (result == 0) { result = dynamic_snprintf(&lsb->m_output, "}\n"); } lua_pop(lsb->m_lua, 2); // remove the name and copy of the table free(data.m_tables.m_array); } } else { result = 1; } break; case LUA_TUSERDATA: ud = lua_touserdata(lua, i); if (heka_circular_buffer == userdata_type(lua, ud, i)) { if (output_circular_buffer(lua, (circular_buffer*)ud, &lsb->m_output)) { result = 1; } } break; } } update_output_stats(lsb); if (result != 0 || lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_CURRENT] > lsb->m_usage[USAGE_TYPE_OUTPUT][USAGE_STAT_LIMIT]) { if (lsb->m_error_message[0] == 0) { luaL_error(lua, "output_limit exceeded"); } luaL_error(lua, lsb->m_error_message); } return 0; }