]> jfr.im git - irc/quakenet/newserv.git/blame - lua/lua.c
Merge pull request #132 from retropc/lua_country
[irc/quakenet/newserv.git] / lua / lua.c
CommitLineData
2da56f0d
CP
1/* Lua bindings for Newserv */
2
3/* Copyright (C) Chris Porter 2005 */
4/* ALL RIGHTS RESERVED. */
5/* Don't put this into the SVN repo. */
6
d324e17b 7#define _POSIX_C_SOURCE 200112L
b034e086 8#define _DEFAULT_SOURCE
d324e17b
CP
9#include <stdlib.h>
10
2da56f0d
CP
11#include "../core/config.h"
12#include "../core/error.h"
13#include "../core/hooks.h"
14#include "../lib/array.h"
15#include "../lib/irc_string.h"
16#include "../core/schedule.h"
87698d77 17#include "../lib/version.h"
d324e17b 18#include "../lib/strlfunc.h"
2da56f0d
CP
19#include "lua.h"
20
c3c955ee 21MODULE_VERSION(LUA_SMALLVERSION);
87698d77 22
9887536a
CP
23#ifdef LUA_DEBUGSOCKET
24
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <netinet/in.h>
28#include <arpa/inet.h>
29#include <netdb.h>
30#include <unistd.h>
31#include <stdarg.h>
32
33#endif
34
2da56f0d
CP
35void lua_startup(void *arg);
36void lua_loadscripts(void);
2da56f0d 37void lua_registercommands(lua_State *l);
30a59b87 38void lua_initnickpusher(void);
ec91b2e4 39void lua_initchanpusher(void);
c673fb9b 40void lua_loadlibs(lua_State *l);
6269435f 41void lua_require(lua_State *l, char *module);
2da56f0d
CP
42
43void lua_startbot(void *arg);
44void lua_destroybot(void);
45void lua_startcontrol(void);
46void lua_destroycontrol(void);
47
48void lua_onunload(lua_State *l);
49void lua_onload(lua_State *l);
50
d324e17b 51void lua_setpath(void);
2da56f0d 52
9887536a
CP
53void lua_setupdebugsocket(void);
54void lua_freedebugsocket(void);
55
0225bed3
CP
56void lua_deregisternicks(lua_list *l);
57void lua_registerlocalcommands(lua_State *ps);
f9f8ee13 58void lua_registerdebug(lua_State *ps);
065c0091 59void lua_socket_closeall(lua_list *l);
72054e5b 60void lua_scheduler_freeall(lua_list *l);
065c0091 61void lua_registersocketcommands(lua_State *ps);
3cf6947a 62void lua_registercryptocommands(lua_State *ps);
72054e5b 63void lua_registerschedulercommands(lua_State *ps);
0225bed3 64
7697f3b1
CP
65void lua_registerdbcommands(lua_list *l);
66void lua_destroydb(lua_list *l);
67
9887536a
CP
68#ifdef LUA_DEBUGSOCKET
69
70struct sockaddr_in debugsocketdest;
71int debugsocket = -1;
72
73#endif
74
2da56f0d
CP
75lua_list *lua_head = NULL, *lua_tail = NULL;
76
a25981bf 77sstring *cpath = NULL, *suffix = NULL;
2da56f0d
CP
78
79void *startsched = NULL;
80
a25981bf
CP
81int loaded = 0;
82
fe0f6b25
CP
83struct rusage r_usages;
84struct rusage r_usagee;
85
c673fb9b
CP
86static const luaL_Reg ourlibs[] = {
87 {"", luaopen_base},
88 {LUA_LOADLIBNAME, luaopen_package},
89 {LUA_TABLIBNAME, luaopen_table},
90 {LUA_IOLIBNAME, luaopen_io},
91 {LUA_OSLIBNAME, luaopen_os},
92 {LUA_STRLIBNAME, luaopen_string},
93 {LUA_MATHLIBNAME, luaopen_math},
9887536a 94#ifdef LUA_USEJIT
6269435f
CP
95 {LUA_JITLIBNAME, luaopen_jit},
96#endif
c673fb9b
CP
97 {NULL, NULL}
98};
d0d1e2a3
CP
99
100lua_list dummy;
c673fb9b 101
2da56f0d 102void _init() {
9887536a 103 lua_setupdebugsocket();
30a59b87 104 lua_initnickpusher();
ec91b2e4 105 lua_initchanpusher();
9887536a 106
d0d1e2a3
CP
107 dummy.name = getsstring("???", 10);
108 if(!dummy.name) {
109 Error("lua", ERR_ERROR, "Cannot set dummy name.");
110 return;
111 }
112
a25981bf
CP
113 cpath = getcopyconfigitem("lua", "scriptdir", "", 500);
114
115 if(!cpath || !cpath->content || !cpath->content[0]) {
116 Error("lua", ERR_ERROR, "Error loading path.");
117 return;
118 }
119
120 suffix = getcopyconfigitem("lua", "scriptsuffix", ".lua", 10);
121 if(!suffix) {
122 Error("lua", ERR_ERROR, "Error loading suffix.");
123 return;
124 }
125
d324e17b
CP
126 lua_setpath();
127
a25981bf
CP
128 loaded = 1;
129
2da56f0d
CP
130 startsched = scheduleoneshot(time(NULL) + 1, &lua_startup, NULL);
131}
132
133void lua_startup(void *arg) {
2da56f0d
CP
134 startsched = NULL;
135
2da56f0d
CP
136 lua_startcontrol();
137 lua_startbot(NULL);
138
a25981bf 139 lua_loadscripts();
2da56f0d
CP
140}
141
142#ifdef BROKEN_DLCLOSE
143void __fini() {
144#else
145void _fini() {
146#endif
2da56f0d 147
a25981bf
CP
148 if(loaded) {
149 if(startsched)
150 deleteschedule(startsched, &lua_startup, NULL);
2da56f0d 151
a25981bf
CP
152 while(lua_head)
153 lua_unloadscript(lua_head);
2da56f0d 154
a25981bf
CP
155 lua_destroybot();
156 lua_destroycontrol();
2da56f0d
CP
157 }
158
a25981bf
CP
159 freesstring(cpath);
160 freesstring(suffix);
d0d1e2a3 161 freesstring(dummy.name);
9887536a
CP
162
163 lua_freedebugsocket();
f8d5cfcf 164 nscheckfreeall(POOL_LUA);
2da56f0d
CP
165}
166
167void lua_loadscripts(void) {
168 array *ls;
169
170 ls = getconfigitems("lua", "script");
171 if(!ls) {
172 Error("lua", ERR_INFO, "No scripts loaded.");
173 } else {
174 sstring **scripts = (sstring **)(ls->content);
175 int i;
176 for(i=0;i<ls->cursi;i++)
177 lua_loadscript(scripts[i]->content);
178 }
179}
180
93917ccd
CP
181/* taken from the lua manual, modified to use nsmalloc */
182static void *lua_nsmalloc(void *ud, void *ptr, size_t osize, size_t nsize) {
183 if(nsize == 0) {
184 if(ptr != NULL)
185 luafree(ptr);
186 return NULL;
187 }
188
189 return luarealloc(ptr, nsize);
190}
191
2da56f0d
CP
192lua_State *lua_loadscript(char *file) {
193 char fullpath[LUA_PATHLEN];
194 int top;
195 lua_State *l;
196 lua_list *n;
d324e17b 197 char buf[1024];
41bfdb81 198 void *args[2];
2da56f0d
CP
199
200 if(!cpath || !suffix)
201 return NULL;
202
d324e17b 203 strlcpy(buf, file, sizeof(buf));
2da56f0d 204
d324e17b
CP
205 delchars(buf, "./\\;");
206
207 if(lua_scriptloaded(buf))
2da56f0d
CP
208 return NULL;
209
93917ccd 210 l = lua_newstate(lua_nsmalloc, NULL);
2da56f0d
CP
211 if(!l)
212 return NULL;
213
d0e17ef9 214 n = (lua_list *)luamalloc(sizeof(lua_list));;
2da56f0d 215 if(!n) {
d324e17b 216 Error("lua", ERR_ERROR, "Error allocing list for %s.", buf);
2da56f0d
CP
217 return NULL;
218 }
219
d324e17b 220 n->name = getsstring(buf, LUA_PATHLEN);
2da56f0d 221 if(!n->name) {
d324e17b 222 Error("lua", ERR_ERROR, "Error allocing name item for %s.", buf);
d0e17ef9 223 luafree(n);
2da56f0d
CP
224 return NULL;
225 }
d0d1e2a3 226 n->calls = 0;
2da56f0d 227
fe0f6b25
CP
228 timerclear(&n->ru_utime);
229 timerclear(&n->ru_stime);
230
7697f3b1
CP
231 n->l = l;
232
c673fb9b 233 lua_loadlibs(l);
f9f8ee13 234 lua_registerdebug(l);
2da56f0d 235 lua_registercommands(l);
0225bed3 236 lua_registerlocalcommands(l);
7697f3b1 237 lua_registerdbcommands(n);
c7ec7d64 238 lua_registersocketcommands(l);
3cf6947a 239 lua_registercryptocommands(l);
72054e5b 240 lua_registerschedulercommands(l);
0225bed3 241
41bfdb81
GB
242 args[0] = file;
243 args[1] = l;
244 triggerhook(HOOK_LUA_LOADSCRIPT, args);
245
9887536a 246#ifdef LUA_USEJIT
6269435f
CP
247 lua_require(l, "lib/jit");
248#endif
249
250 lua_require(l, "lib/bootstrap");
251
2da56f0d
CP
252 snprintf(fullpath, sizeof(fullpath), "%s/%s%s", cpath->content, file, suffix->content);
253 if(luaL_loadfile(l, fullpath)) {
254 Error("lua", ERR_ERROR, "Error loading %s.", file);
255 lua_close(l);
256 freesstring(n->name);
d0e17ef9 257 luafree(n);
2da56f0d
CP
258 return NULL;
259 }
260
2da56f0d
CP
261 n->next = NULL;
262 n->prev = lua_tail;
0225bed3 263 n->nicks = NULL;
065c0091 264 n->sockets = NULL;
72054e5b 265 n->schedulers = NULL;
2da56f0d
CP
266
267 if(!lua_head) {
268 lua_head = n;
269 } else {
270 lua_tail->next = n;
271 }
272
273 lua_tail = n;
274
55cee062
CP
275 top = lua_gettop(l);
276
277 if(lua_pcall(l, 0, 0, 0)) {
278 Error("lua", ERR_ERROR, "Error pcalling: %s.", file);
279 lua_close(l);
280 freesstring(n->name);
c07dd8fd
CP
281
282 if(lua_head == n)
283 lua_head = NULL;
284
285 lua_tail = n->prev;
286 if(lua_tail)
287 lua_tail->next = NULL;
288
d0e17ef9 289 luafree(n);
55cee062
CP
290 return NULL;
291 }
292
293 lua_settop(l, top);
294
295 Error("lua", ERR_INFO, "Loaded %s.", file);
2da56f0d
CP
296 lua_onload(l);
297
298 return l;
299}
300
301void lua_unloadscript(lua_list *l) {
6e1aa3b3
GB
302 triggerhook(HOOK_LUA_UNLOADSCRIPT, l->l);
303
2da56f0d 304 lua_onunload(l->l);
0225bed3 305 lua_deregisternicks(l);
065c0091 306 lua_socket_closeall(l);
72054e5b 307 lua_scheduler_freeall(l);
7697f3b1 308 lua_destroydb(l);
2da56f0d
CP
309 lua_close(l->l);
310 freesstring(l->name);
311
312 /* well, at least it's O(1) */
313
314 if(!l->prev) { /* head */
315 lua_head = l->next;
316 if(!lua_head) {
317 lua_tail = NULL;
318 } else {
319 lua_head->prev = NULL;
320 }
321 } else {
322 if(!l->next) { /* tail */
323 lua_tail = lua_tail->prev;
324 if(!lua_tail) {
325 lua_head = NULL;
326 } else {
327 lua_tail->next = NULL;
328 }
329 } else {
330 l->prev->next = l->next;
331 l->next->prev = l->prev;
332 }
333 }
334
d0e17ef9 335 luafree(l);
2da56f0d
CP
336}
337
d324e17b
CP
338void lua_setpath(void) {
339 char fullpath[LUA_PATHLEN];
a25981bf 340
d324e17b
CP
341 snprintf(fullpath, sizeof(fullpath), "%s/?%s", cpath->content, suffix->content);
342 setenv("LUA_PATH", fullpath, 1);
2da56f0d
CP
343}
344
345lua_list *lua_scriptloaded(char *name) {
346 lua_list *l;
347
348 for(l=lua_head;l;l=l->next)
349 if(!strcmp(l->name->content, name))
350 return l;
351
352 return NULL;
353}
354
c673fb9b
CP
355void lua_loadlibs(lua_State *l) {
356 const luaL_Reg *lib = ourlibs;
357
358 for (;lib->func;lib++) {
359 lua_pushcfunction(l, lib->func);
360 lua_pushstring(l, lib->name);
361 lua_call(l, 1, 0);
362 }
363}
6269435f
CP
364
365void lua_require(lua_State *l, char *module) {
366 int top = lua_gettop(l);
367
368 lua_getglobal(l, "require");
369 lua_pushstring(l, module);
370
371 if(lua_pcall(l, 1, 1, 0))
372 Error("lua", ERR_ERROR, "Error requiring %s: %s", module, lua_tostring(l, -1));
373
374 lua_settop(l, top);
375}
376
9887536a
CP
377void lua_setupdebugsocket(void) {
378#ifdef LUA_DEBUGSOCKET
379
380 debugsocket = socket(AF_INET, SOCK_DGRAM, 0);
381 if(debugsocket < 0) {
382 debugsocket = -1;
383 Error("lua", ERR_ERROR, "Cannot create debug socket.");
384
385 return;
386 }
387
388 memset(&debugsocketdest, 0, sizeof(debugsocketdest));
389
390 debugsocketdest.sin_family = AF_INET;
391 debugsocketdest.sin_port = htons(LUA_DEBUGSOCKET_PORT);
392 debugsocketdest.sin_addr.s_addr = inet_addr(LUA_DEBUGSOCKET_ADDRESS);
393
394#endif
395}
396
397void lua_freedebugsocket(void) {
398#ifdef LUA_DEBUGSOCKET
399
400 if(debugsocket == -1)
401 return;
402
403 close(debugsocket);
404
405
406 debugsocket = -1;
407
408#endif
409}
410
411#ifdef LUA_DEBUGSOCKET
412void lua_debugoutput(char *format, ...) {
413 char buf[1024];
414 va_list va;
415 int size;
416
417 if(debugsocket == -1)
418 return;
419
420 va_start(va, format);
421 size = vsnprintf(buf, sizeof(buf), format, va);
422 va_end(va);
423
424 if(size >= sizeof(buf))
425 size = sizeof(buf) - 1;
426
427 if(size > 0)
428 sendto(debugsocket, buf, size, 0, (struct sockaddr *)&debugsocketdest, sizeof(debugsocketdest));
429}
430#endif
431
d0d1e2a3 432lua_list *lua_listfromstate(lua_State *l) {
9887536a
CP
433 lua_list *i = lua_head;
434 for(;i;i=i->next)
435 if(i->l == l)
d0d1e2a3 436 return i;
9887536a 437
d0d1e2a3 438 return &dummy;
9887536a 439}
6269435f 440
55cee062
CP
441int lua_listexists(lua_list *l) {
442 lua_list *i;
443
444 for(i=lua_head;i;i=i->next)
445 if(i == l)
446 return 1;
447
448 return 0;
449}
450
0225bed3
CP
451int lua_lineok(const char *data) {
452 if(strchr(data, '\r') || strchr(data, '\n'))
453 return 0;
454 return 1;
455}
456
4f556cb0 457int lua_debugpcall(lua_State *l, char *message, int a, int b, int c) {
ea15be33
CP
458 lua_list *l2 = lua_listfromstate(l);
459 int ret;
460
461#ifdef LUA_DEBUGSOCKET
462 DEBUGOUT("%s: %s\n", l2->name->content, message);
463#endif
464
465#ifdef LUA_PROFILE
466 ACCOUNTING_START(l2);
467#endif
468
469 ret = lua_pcall(l, a, b, c);
470
471#ifdef LUA_PROFILE
472 ACCOUNTING_STOP(l2);
473#endif
474
475 return ret;
476}
0225bed3 477