blob: 626b40de4690e36000b01cf540b4979373cdab80 [file] [log] [blame]
/** @file
A brief file description
@section license License
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "libts.h"
#include "luaConfig.h"
#include "I_Layout.h"
#include "I_RecDefs.h"
#include "I_RecCore.h"
#include "P_RecCore.h"
#include "UrlRewrite.h"
luaConfig globalLuaConfig("tsconfig");
static int
tsrec_newindex_func(lua_State *L) {
luaL_error(L, "cannot assign to ats.config_t, invoked instead");
return 0;
}
static int
tsrec_index_func(lua_State *L) {
const char *opath = NULL;
char path[1024];
assert(lua_gettop(L) == 2);
if(!strcmp(lua_tostring(L,2),"_path")) return 0;
lua_pushvalue(L,2);
lua_rawget(L,1);
if(lua_istable(L,-1)) return 1;
lua_pop(L,1);
lua_pushstring(L,"_path");
lua_rawget(L,1);
if(lua_isstring(L,-1)) opath = lua_tostring(L,-1);
if(opath == NULL) snprintf(path, sizeof(path), "%s", lua_tostring(L,2));
else snprintf(path, sizeof(path), "%s.%s", opath, lua_tostring(L,2));
lua_newtable(L);
lua_pushstring(L, path);
lua_setfield(L, -2, "_path");
luaL_getmetatable(L, "ats.config_t");
lua_setmetatable(L, -2);
lua_pushvalue(L,2); /* requested name */
lua_pushvalue(L,-2);
lua_rawset(L,1);
return 1;
}
static int
tsrec_next_record(lua_State *L) {
RecRecord *r = NULL;
int *idx, i, num_records, upidx;
upidx = lua_upvalueindex(1);
idx = (int *)lua_touserdata(L,upidx);
i = *idx;
ink_mutex_acquire(&g_rec_config_lock);
num_records = g_num_records;
for (; i < num_records; i++) {
r = &(g_records[i]);
if (REC_TYPE_IS_CONFIG(r->rec_type))
break;
r = NULL;
}
if(r != NULL) rec_mutex_acquire(&(r->lock));
ink_mutex_release(&g_rec_config_lock);
*idx = i+1;
if(r != NULL) {
lua_newtable(L);
lua_pushstring(L, r->name);
lua_setfield(L, -2, "_path");
luaL_getmetatable(L, "ats.config_t");
lua_setmetatable(L, -2);
rec_mutex_release(&(r->lock));
return 1;
}
return 0;
}
static int
tsrec_dispatch_method(lua_State *L, const char *bpath, const char *method) {
if(!strcmp(method, "name")) {
lua_pushstring(L, bpath);
return 1;
}
else if(!strcmp(method, "list")) {
int *idx = (int *)lua_newuserdata(L, sizeof(int));
*idx = 0;
lua_pushcclosure(L, tsrec_next_record, 1);
return 1;
}
luaL_error(L, "unknown method call: %s", method);
return 0;
}
static int
tsrec_call_func(lua_State *L) {
RecT rec_type;
RecDataT data_type;
const char *opath = NULL;
int nargs = lua_gettop(L);
lua_pushstring(L,"_path");
lua_rawget(L,1);
opath = lua_tostring(L,-1);
lua_pop(L,1);
if(lua_istable(L,2)) {
const char *bpath;
lua_pushstring(L,"_path");
lua_rawget(L,2);
bpath = lua_tostring(L,-1);
if(bpath == NULL) return tsrec_dispatch_method(L,"",opath);
int blen = strlen(bpath);
lua_pop(L,1);
if(blen > strlen(opath) ||
strncmp(bpath, opath, blen) ||
opath[blen] != '.') {
luaL_error(L, "impossible method call: %s", opath + blen + 1);
}
return tsrec_dispatch_method(L,bpath,opath + blen + 1);
}
if(RecGetRecordType(opath, &rec_type))
luaL_error(L, "Could not find record type '%s'", opath);
if(RecGetRecordDataType(opath, &data_type))
luaL_error(L, "Could not find record data type '%s'", opath);
if(nargs == 1) {
/* return the value */
switch(data_type) {
case RECD_INT:
RecInt v_int;
RecGetRecordInt(opath, &v_int);
lua_pushinteger(L,v_int);
return 1;
break;
case RECD_FLOAT:
RecFloat v_float;
RecGetRecordFloat(opath, &v_float);
lua_pushnumber(L,v_float);
return 1;
break;
case RECD_STRING:
RecString v_string;
RecGetRecordString_Xmalloc(opath, &v_string);
lua_pushstring(L, v_string);
ats_free(v_string);
return 1;
break;
case RECD_COUNTER:
RecCounter v_counter;
RecGetRecordCounter(opath, &v_counter);
lua_pushinteger(L,v_counter);
return 1;
break;
default:
luaL_error(L, "Unknown type of record: %s", opath);
break;
}
return 0;
}
switch(data_type) {
case RECD_INT:
RecSetRecordInt(opath, (RecInt)luaL_checkint(L,2));
break;
case RECD_FLOAT:
RecSetRecordFloat(opath, (RecFloat)luaL_checknumber(L,2));
break;
case RECD_STRING:
RecSetRecordString(opath, (const RecString)lua_tostring(L,2));
break;
case RECD_COUNTER:
RecSetRecordCounter(opath, (RecCounter)luaL_checklong(L,2));
break;
default:
luaL_error(L, "Unknown type of record: %s", opath);
break;
}
return 0;
}
static int
lua_ats_log(lua_State *L) {
int type = lua_tointeger(L, lua_upvalueindex(1));
switch(type) {
case 0: Error("%s", lua_tostring(L,1)); break;
case 1: Warning("%s", lua_tostring(L,1)); break;
case 2: Note("%s", lua_tostring(L,1)); break;
case 3: Status("%s", lua_tostring(L,1)); break;
case 4: Emergency("%s", lua_tostring(L,1)); break;
case 5: Fatal("%s", lua_tostring(L,1)); break;
case 6: Debug(lua_tostring(L,1), "%s", lua_tostring(L,2)); break;
default:
luaL_error(L, "unknown internal log type");
break;
}
return 0;
}
void luaopen_ats(lua_State *L) {
luaL_newmetatable(L, "ats.config_t");
lua_pushcclosure(L, tsrec_index_func, 0);
lua_setfield(L, -2, "__index");
lua_pushcclosure(L, tsrec_newindex_func, 0);
lua_setfield(L, -2, "__newindex");
lua_pushcclosure(L, tsrec_call_func, 0);
lua_setfield(L, -2, "__call");
lua_newtable(L);
lua_setglobal(L, "ats");
lua_getglobal(L, "ats");
/* config */
lua_newtable(L);
luaL_getmetatable(L, "ats.config_t");
lua_setmetatable(L, -2);
lua_setfield(L, -2, "config");
lua_newtable(L);
#define mkLog(id,name) do { \
lua_pushinteger(L,id); \
lua_pushcclosure(L, lua_ats_log, 1); \
lua_setfield(L, -2, #name); \
} while(0)
mkLog(0,error);
mkLog(1,warning);
mkLog(2,note);
mkLog(3,status);
mkLog(4,emergency);
mkLog(5,fatal);
mkLog(6,debug);
lua_setfield(L, -2, "log");
}
void luaConfig::records() {
int rv;
lua_State *L = getL();
lua_getglobal(L, "tsconfig");
lua_getfield(L, -1, "config");
if(lua_isnil(L,-1)) {
lua_pop(L,1);
return;
}
rv = lua_pcall(L, 0, 1, 0);
if(rv != 0) {
ink_error("tsconfig.config() failed: %s\n", lua_tostring(L,-1));
}
lua_pop(L,1);
}
void drop_lua_state_holder(void *vls) {
struct luaConfigStateHolder *state_holder = (struct luaConfigStateHolder *)vls;
lua_close(state_holder->states[0]);
lua_close(state_holder->states[1]);
}
void luaConfig::boot() {
assert(state_holder.states[0] == NULL);
assert(state_holder.states[1] == NULL);
char system_config_directory[PATH_NAME_MAX + 1]; // Layout->sysconfdir
ink_strlcpy(system_config_directory, Layout::get()->sysconfdir, PATH_NAME_MAX);
char config_file_path[PATH_NAME_MAX];
config_file_path[0] = '\0';
ink_strlcpy(config_file_path, system_config_directory, sizeof(config_file_path));
ink_strlcat(config_file_path, "/?.lua", sizeof(config_file_path));
setL(0, open(config_file_path, config_module));
setL(1, open(config_file_path, config_module));
}
lua_State *luaConfig::open(const char *config_file_path, const char *module) {
lua_State *L = luaL_newstate();
if(L == NULL) {
printf("[TrafficServer] failed to initialized lua.\n");
exit(1);
}
luaL_openlibs(L);
lua_getglobal(L, "package");
lua_pushstring(L, config_file_path);
lua_setfield(L, -2, "path");
lua_pop(L,1);
luaopen_ats(L);
UrlRewrite::luaopen(L);
lua_getglobal(L,"require");
lua_pushstring(L,module);
if(lua_pcall(L,1,1,0) != 0) {
printf("[TrafficServer] failed to run lua config '%s'\n%s", config_file_path,
lua_tostring(L,-1));
exit(1);
}
lua_pop(L, lua_gettop(L));
return L;
}
int
luaConfig::call(lua_State *L, const char *method, int nargs) {
lua_getglobal(L, "tsconfig");
lua_getfield(L, -1, method);
if(lua_isnil(L,-1)) {
lua_pop(L,2);
return -1;
}
lua_remove(L,-2);
lua_insert(L, 0 - (nargs+1));
if(lua_pcall(L, nargs, 0, 0) != 0) {
Error("lua call(%s) failed: %s\n", method, lua_tostring(L,-1));
return -1;
}
return 0;
}
void luaConfigInit() {
globalLuaConfig.boot();
globalLuaConfig.records();
}