1 #include "mod_magnet_cache.h"
2 #include "stat_cache.h"
3 
4 #include <stdlib.h>
5 #include <time.h>
6 #include <assert.h>
7 
8 #ifdef HAVE_LUA_H
9 #include <lualib.h>
10 #include <lauxlib.h>
11 
script_init()12 static script *script_init() {
13 	script *sc;
14 
15 	sc = calloc(1, sizeof(*sc));
16 	sc->name = buffer_init();
17 	sc->etag = buffer_init();
18 
19 	return sc;
20 }
21 
script_free(script * sc)22 static void script_free(script *sc) {
23 	if (!sc) return;
24 
25 	lua_pop(sc->L, 1); /* the function copy */
26 
27 	buffer_free(sc->name);
28 	buffer_free(sc->etag);
29 
30 	lua_close(sc->L);
31 
32 	free(sc);
33 }
34 
script_cache_init()35 script_cache *script_cache_init() {
36 	script_cache *p;
37 
38 	p = calloc(1, sizeof(*p));
39 
40 	return p;
41 }
42 
script_cache_free(script_cache * p)43 void script_cache_free(script_cache *p) {
44 	size_t i;
45 
46 	if (!p) return;
47 
48 	for (i = 0; i < p->used; i++) {
49 		script_free(p->ptr[i]);
50 	}
51 
52 	free(p->ptr);
53 
54 	free(p);
55 }
56 
script_cache_get_script(server * srv,connection * con,script_cache * cache,buffer * name)57 lua_State *script_cache_get_script(server *srv, connection *con, script_cache *cache, buffer *name) {
58 	size_t i;
59 	script *sc = NULL;
60 	stat_cache_entry *sce;
61 
62 	for (i = 0; i < cache->used; i++) {
63 		sc = cache->ptr[i];
64 
65 		if (buffer_is_equal(name, sc->name)) {
66 			sc->last_used = time(NULL);
67 
68 			/* oops, the script failed last time */
69 
70 			if (lua_gettop(sc->L) == 0) break;
71 
72 			if (HANDLER_ERROR == stat_cache_get_entry(srv, con, sc->name, &sce)) {
73 				lua_pop(sc->L, 1); /* pop the old function */
74 				break;
75 			}
76 
77 			if (!buffer_is_equal(sce->etag, sc->etag)) {
78 				/* the etag is outdated, reload the function */
79 				lua_pop(sc->L, 1);
80 				break;
81 			}
82 
83 			assert(lua_isfunction(sc->L, -1));
84 			lua_pushvalue(sc->L, -1); /* copy the function-reference */
85 
86 			return sc->L;
87 		}
88 
89 		sc = NULL;
90 	}
91 
92 	/* if the script was script already loaded but either got changed or
93 	 * failed to load last time */
94 	if (sc == NULL) {
95 		sc = script_init();
96 
97 		if (cache->size == 0) {
98 			cache->size = 16;
99 			cache->ptr = malloc(cache->size * sizeof(*(cache->ptr)));
100 		} else if (cache->used == cache->size) {
101 			cache->size += 16;
102 			cache->ptr = realloc(cache->ptr, cache->size * sizeof(*(cache->ptr)));
103 		}
104 
105 		cache->ptr[cache->used++] = sc;
106 
107 		buffer_copy_string_buffer(sc->name, name);
108 
109 		sc->L = luaL_newstate();
110 		luaL_openlibs(sc->L);
111 	}
112 
113 	sc->last_used = time(NULL);
114 
115 	if (0 != luaL_loadfile(sc->L, name->ptr)) {
116 		/* oops, an error, return it */
117 
118 		return sc->L;
119 	}
120 
121 	if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, sc->name, &sce)) {
122 		buffer_copy_string_buffer(sc->etag, sce->etag);
123 	}
124 
125 	/**
126 	 * pcall() needs the function on the stack
127 	 *
128 	 * as pcall() will pop the script from the stack when done, we have to
129 	 * duplicate it here
130 	 */
131 	assert(lua_isfunction(sc->L, -1));
132 	lua_pushvalue(sc->L, -1); /* copy the function-reference */
133 
134 	return sc->L;
135 }
136 
137 #endif
138