blob: a21065dc3472698ed0876c51105c27da4df84e95 [file] [log] [blame]
Thierry Fourniere726b142016-02-11 17:57:57 +01001/*
2 * Lua safe functions
3 *
4 * Copyright 2015-2016 Thierry Fournier <tfournier@arpalert.org>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 *
12 * All the functions in this file runs with a Lua stack, and can
Thierry Fournierfb0b5462016-01-21 09:28:58 +010013 * return with a longjmp. All of these function must be launched
14 * in an environment able to catch a longjmp, otherwise a
15 * critical error can be raised.
16 */
17#include <lauxlib.h>
18#include <lua.h>
19#include <lualib.h>
20
Thierry Fournierb1f46562016-01-21 09:46:15 +010021#include <common/time.h>
Thierry Fournierf61aa632016-02-19 20:56:00 +010022#include <common/uri_auth.h>
Thierry Fournierb1f46562016-01-21 09:46:15 +010023
Thierry Fournier49d48422016-02-19 12:09:29 +010024#include <types/hlua.h>
Thierry Fournierf61aa632016-02-19 20:56:00 +010025#include <types/proxy.h>
Thierry Fournier49d48422016-02-19 12:09:29 +010026
Thierry Fournier8b0d6e12016-03-16 18:29:13 +010027#include <proto/dumpstats.h>
Thierry Fournier94ed1c12016-02-24 08:06:32 +010028#include <proto/proto_http.h>
Thierry Fournierf61aa632016-02-19 20:56:00 +010029#include <proto/proxy.h>
30#include <proto/server.h>
Thierry Fournier94ed1c12016-02-24 08:06:32 +010031
Thierry Fournier1de16592016-01-27 09:49:07 +010032/* Contains the class reference of the concat object. */
33static int class_concat_ref;
Thierry Fournierf61aa632016-02-19 20:56:00 +010034static int class_proxy_ref;
Thierry Fournierf2fdc9d2016-02-22 08:21:39 +010035static int class_server_ref;
Thierry Fournierff480422016-02-25 08:36:46 +010036static int class_listener_ref;
Thierry Fournier1de16592016-01-27 09:49:07 +010037
Thierry Fournierf61aa632016-02-19 20:56:00 +010038#define STATS_LEN (MAX((int)ST_F_TOTAL_FIELDS, (int)INF_TOTAL_FIELDS))
Thierry Fourniereea77c02016-03-18 08:47:13 +010039
40static struct field stats[STATS_LEN];
41
Thierry Fournier8b0d6e12016-03-16 18:29:13 +010042/* This function gets a struct field and convert it in Lua
43 * variable. The variable is pushed at the top of the stak.
44 */
45int hlua_fcn_pushfield(lua_State *L, struct field *field)
46{
47 /* The lua_Integer is always signed. Its length depends on
48 * compilation opions, so the followinfg code is conditionned
49 * by some macros. Windows maros are not supported.
50 * If the number cannot be represented as integer, we try to
51 * convert to float.
52 */
53 switch (field_format(field, 0)) {
54
55 case FF_EMPTY:
56 lua_pushnil(L);
57 return 1;
58
59 case FF_S32:
60 /* S32 is always supported. */
61 lua_pushinteger(L, field->u.s32);
62 return 1;
63
64 case FF_U32:
65#if (LUA_MAXINTEGER == LLONG_MAX || ((LUA_MAXINTEGER == LONG_MAX) && (__WORDSIZE == 64)))
66 /* 64 bits case, U32 is always supported */
67 lua_pushinteger(L, field->u.u32);
68#else
69 /* 32 bits case, U32 is supported until INT_MAX. */
70 if (field->u.u32 > INT_MAX)
71 lua_pushnumber(L, (lua_Number)field->u.u32);
72 else
73 lua_pushinteger(L, field->u.u32);
74#endif
75 return 1;
76
77 case FF_S64:
78#if (LUA_MAXINTEGER == LLONG_MAX || ((LUA_MAXINTEGER == LONG_MAX) && (__WORDSIZE == 64)))
79 /* 64 bits case, S64 is always supported */
80 lua_pushinteger(L, field->u.s64);
81#else
82 /* 64 bits case, S64 is supported beetween INT_MIN and INT_MAX */
83 if (field->u.s64 < INT_MIN || field->u.s64 > INT_MAX)
84 lua_pushnumber(L, (lua_Number)field->u.s64);
85 else
86 lua_pushinteger(L, (int)field->u.s64);
87#endif
88 return 1;
89
90 case FF_U64:
91#if (LUA_MAXINTEGER == LLONG_MAX || ((LUA_MAXINTEGER == LONG_MAX) && (__WORDSIZE == 64)))
92 /* 64 bits case, U64 is supported until LLONG_MAX */
93 if (field->u.u64 > LLONG_MAX)
94 lua_pushnumber(L, (lua_Number)field->u.u64);
95 else
96 lua_pushinteger(L, field->u.u64);
97#else
98 /* 64 bits case, U64 is supported until INT_MAX */
99 if (field->u.u64 > INT_MAX)
100 lua_pushnumber(L, (lua_Number)field->u.u64);
101 else
102 lua_pushinteger(L, (int)field->u.u64);
103#endif
104 return 1;
105
106 case FF_STR:
107 lua_pushstring(L, field->u.str);
108 return 1;
109
110 default:
111 break;
112 }
113
114 /* Default case, never reached. */
115 lua_pushnil(L);
116 return 1;
117}
118
Thierry Fournier94ed1c12016-02-24 08:06:32 +0100119/* Some string are started or terminated by blank chars,
120 * this function removes the spaces, tabs, \r and
121 * \n at the begin and at the end of the string "str", and
122 * push the result in the lua stack.
123 * Returns a pointer to the Lua internal copy of the string.
124 */
125const char *hlua_pushstrippedstring(lua_State *L, const char *str)
126{
127 const char *p;
128 const char *e;
129
130 for (p = str; HTTP_IS_LWS(*p); p++);
131 for (e = p + strlen(p) - 1; e > p && HTTP_IS_LWS(*e); e--);
132
133 return lua_pushlstring(L, p, e - p);
134}
135
Thierry Fournierddd89882016-02-22 19:52:08 +0100136/* The three following functions are useful for adding entries
137 * in a table. These functions takes a string and respectively an
138 * integer, a string or a function and add it to the table in the
139 * top of the stack.
140 *
141 * These functions throws an error if no more stack size is
142 * available.
143 */
144void hlua_class_const_int(lua_State *L, const char *name, int value)
145{
Thierry Fournierddd89882016-02-22 19:52:08 +0100146 lua_pushstring(L, name);
147 lua_pushinteger(L, value);
148 lua_rawset(L, -3);
149}
150void hlua_class_const_str(lua_State *L, const char *name, const char *value)
151{
Thierry Fournierddd89882016-02-22 19:52:08 +0100152 lua_pushstring(L, name);
153 lua_pushstring(L, value);
154 lua_rawset(L, -3);
155}
156void hlua_class_function(lua_State *L, const char *name, int (*function)(lua_State *L))
157{
Thierry Fournierddd89882016-02-22 19:52:08 +0100158 lua_pushstring(L, name);
159 lua_pushcclosure(L, function, 0);
160 lua_rawset(L, -3);
161}
162
163/* This function returns a string containg the HAProxy object name. */
164int hlua_dump_object(struct lua_State *L)
165{
166 const char *name = (const char *)lua_tostring(L, lua_upvalueindex(1));
167 lua_pushfstring(L, "HAProxy class %s", name);
168 return 1;
169}
170
Thierry Fournier45e78d72016-02-19 18:34:46 +0100171/* This function register a table as metatable and. It names
172 * the metatable, and returns the associated reference.
173 * The original table is poped from the top of the stack.
174 * "name" is the referenced class name.
175 */
176int hlua_register_metatable(struct lua_State *L, char *name)
177{
178 /* Check the type of the top element. it must be
179 * a table.
180 */
181 if (lua_type(L, -1) != LUA_TTABLE)
182 luaL_error(L, "hlua_register_metatable() requires a type Table "
183 "in the top of the stack");
184
185 /* Add the __tostring function which identify the
186 * created object.
187 */
188 lua_pushstring(L, "__tostring");
189 lua_pushstring(L, name);
190 lua_pushcclosure(L, hlua_dump_object, 1);
191 lua_rawset(L, -3);
192
193 /* Register a named entry for the table. The table
194 * reference is copyed first because the function
195 * lua_setfield() pop the entry.
196 */
197 lua_pushvalue(L, -1);
198 lua_setfield(L, LUA_REGISTRYINDEX, name);
199
200 /* Creates the reference of the object. The
201 * function luaL_ref pop the top of the stack.
202 */
203 return luaL_ref(L, LUA_REGISTRYINDEX);
204}
205
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +0100206/* Return an object of the expected type, or throws an error. */
207void *hlua_checkudata(lua_State *L, int ud, int class_ref)
208{
209 void *p;
Thierry Fournier53518272016-01-27 10:34:09 +0100210 int ret;
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +0100211
212 /* Check if the stack entry is an array. */
213 if (!lua_istable(L, ud))
Thierry Fournier53518272016-01-27 10:34:09 +0100214 luaL_argerror(L, ud, NULL);
215
216 /* pop the metatable of the referencecd object. */
217 if (!lua_getmetatable(L, ud))
218 luaL_argerror(L, ud, NULL);
219
220 /* pop the expected metatable. */
221 lua_rawgeti(L, LUA_REGISTRYINDEX, class_ref);
222
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +0100223 /* Check if the metadata have the expected type. */
Thierry Fournier53518272016-01-27 10:34:09 +0100224 ret = lua_rawequal(L, -1, -2);
225 lua_pop(L, 2);
226 if (!ret)
227 luaL_argerror(L, ud, NULL);
228
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +0100229 /* Push on the stack at the entry [0] of the table. */
230 lua_rawgeti(L, ud, 0);
Thierry Fournier53518272016-01-27 10:34:09 +0100231
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +0100232 /* Check if this entry is userdata. */
233 p = lua_touserdata(L, -1);
234 if (!p)
Thierry Fournier53518272016-01-27 10:34:09 +0100235 luaL_argerror(L, ud, NULL);
236
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +0100237 /* Remove the entry returned by lua_rawgeti(). */
238 lua_pop(L, 1);
Thierry Fournier53518272016-01-27 10:34:09 +0100239
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +0100240 /* Return the associated struct. */
241 return p;
242}
243
Thierry Fournierb1f46562016-01-21 09:46:15 +0100244/* This function return the current date at epoch format in milliseconds. */
245int hlua_now(lua_State *L)
246{
247 lua_newtable(L);
248 lua_pushstring(L, "sec");
249 lua_pushinteger(L, now.tv_sec);
250 lua_rawset(L, -3);
251 lua_pushstring(L, "usec");
252 lua_pushinteger(L, now.tv_usec);
253 lua_rawset(L, -3);
254 return 1;
255}
256
Thierry Fournier1550d5d2016-01-21 09:35:41 +0100257/* This functions expects a Lua string as HTTP date, parse it and
258 * returns an integer containing the epoch format of the date, or
259 * nil if the parsing fails.
260 */
261static int hlua_parse_date(lua_State *L, int (*fcn)(const char *, int, struct tm*))
262{
263 const char *str;
264 size_t len;
265 struct tm tm;
266 time_t time;
267
268 str = luaL_checklstring(L, 1, &len);
269
270 if (!fcn(str, len, &tm)) {
271 lua_pushnil(L);
272 return 1;
273 }
274
275 /* This function considers the content of the broken-down time
276 * is exprimed in the UTC timezone. timegm don't care about
277 * the gnu variable tm_gmtoff. If gmtoff is set, or if you know
278 * the timezone from the broken-down time, it must be fixed
279 * after the conversion.
280 */
281 time = timegm(&tm);
282 if (time == -1) {
283 lua_pushnil(L);
284 return 1;
285 }
286
287 lua_pushinteger(L, (int)time);
288 return 1;
289}
290static int hlua_http_date(lua_State *L)
291{
292 return hlua_parse_date(L, parse_http_date);
293}
294static int hlua_imf_date(lua_State *L)
295{
296 return hlua_parse_date(L, parse_imf_date);
297}
298static int hlua_rfc850_date(lua_State *L)
299{
300 return hlua_parse_date(L, parse_rfc850_date);
301}
302static int hlua_asctime_date(lua_State *L)
303{
304 return hlua_parse_date(L, parse_asctime_date);
305}
306
Thierry Fourniereea77c02016-03-18 08:47:13 +0100307static int hlua_get_info(lua_State *L)
308{
309 int i;
310
311 stats_fill_info(stats, STATS_LEN);
312
313 lua_newtable(L);
314 for (i=0; i<INF_TOTAL_FIELDS; i++) {
315 lua_pushstring(L, info_field_names[i]);
316 hlua_fcn_pushfield(L, &stats[i]);
317 lua_settable(L, -3);
318 }
319 return 1;
320}
321
Thierry Fournier49d48422016-02-19 12:09:29 +0100322static struct hlua_concat *hlua_check_concat(lua_State *L, int ud)
Thierry Fournier1de16592016-01-27 09:49:07 +0100323{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +0200324 return (hlua_checkudata(L, ud, class_concat_ref));
Thierry Fournier1de16592016-01-27 09:49:07 +0100325}
326
327static int hlua_concat_add(lua_State *L)
328{
Thierry Fournier49d48422016-02-19 12:09:29 +0100329 struct hlua_concat *b;
330 char *buffer;
331 char *new;
Thierry Fournier1de16592016-01-27 09:49:07 +0100332 const char *str;
333 size_t l;
334
335 /* First arg must be a concat object. */
336 b = hlua_check_concat(L, 1);
337
338 /* Second arg must be a string. */
339 str = luaL_checklstring(L, 2, &l);
340
Thierry Fournier49d48422016-02-19 12:09:29 +0100341 /* Get the buffer. */
342 lua_rawgeti(L, 1, 1);
343 buffer = lua_touserdata(L, -1);
344 lua_pop(L, 1);
345
346 /* Update the buffer size if it s required. The old buffer
347 * is crushed by the new in the object array, so it will
348 * be deleted by the GC.
349 * Note that in the first loop, the "new" variable is only
350 * used as a flag.
351 */
352 new = NULL;
353 while (b->size - b->len < l) {
354 b->size += HLUA_CONCAT_BLOCSZ;
355 new = buffer;
356 }
357 if (new) {
358 new = lua_newuserdata(L, b->size);
359 memcpy(new, buffer, b->len);
360 lua_rawseti(L, 1, 1);
361 buffer = new;
362 }
363
364 /* Copy string, and update metadata. */
365 memcpy(buffer + b->len, str, l);
366 b->len += l;
Thierry Fournier1de16592016-01-27 09:49:07 +0100367 return 0;
368}
369
370static int hlua_concat_dump(lua_State *L)
371{
Thierry Fournier49d48422016-02-19 12:09:29 +0100372 struct hlua_concat *b;
373 char *buffer;
Thierry Fournier1de16592016-01-27 09:49:07 +0100374
375 /* First arg must be a concat object. */
376 b = hlua_check_concat(L, 1);
377
Thierry Fournier49d48422016-02-19 12:09:29 +0100378 /* Get the buffer. */
379 lua_rawgeti(L, 1, 1);
380 buffer = lua_touserdata(L, -1);
381 lua_pop(L, 1);
382
Thierry Fournier1de16592016-01-27 09:49:07 +0100383 /* Push the soncatenated strng in the stack. */
Thierry Fournier49d48422016-02-19 12:09:29 +0100384 lua_pushlstring(L, buffer, b->len);
Thierry Fournier1de16592016-01-27 09:49:07 +0100385 return 1;
386}
387
388int hlua_concat_new(lua_State *L)
389{
Thierry Fournier49d48422016-02-19 12:09:29 +0100390 struct hlua_concat *b;
Thierry Fournier1de16592016-01-27 09:49:07 +0100391
392 lua_newtable(L);
Vincent Bernat3c2f2f22016-04-03 13:48:42 +0200393 b = lua_newuserdata(L, sizeof(*b));
Thierry Fournier49d48422016-02-19 12:09:29 +0100394 b->size = HLUA_CONCAT_BLOCSZ;
395 b->len = 0;
Thierry Fournier1de16592016-01-27 09:49:07 +0100396 lua_rawseti(L, -2, 0);
Thierry Fournier49d48422016-02-19 12:09:29 +0100397 lua_newuserdata(L, HLUA_CONCAT_BLOCSZ);
398 lua_rawseti(L, -2, 1);
Thierry Fournier1de16592016-01-27 09:49:07 +0100399
400 lua_rawgeti(L, LUA_REGISTRYINDEX, class_concat_ref);
401 lua_setmetatable(L, -2);
402
Thierry Fournier1de16592016-01-27 09:49:07 +0100403 return 1;
404}
405
406static int concat_tostring(lua_State *L)
407{
408 const void *ptr = lua_topointer(L, 1);
409 lua_pushfstring(L, "Concat object: %p", ptr);
410 return 1;
411}
412
413static int hlua_concat_init(lua_State *L)
414{
415 /* Creates the buffered concat object. */
416 lua_newtable(L);
417
418 lua_pushstring(L, "__tostring");
419 lua_pushcclosure(L, concat_tostring, 0);
420 lua_settable(L, -3);
421
422 lua_pushstring(L, "__index"); /* Creates the index entry. */
423 lua_newtable(L); /* The "__index" content. */
424
425 lua_pushstring(L, "add");
426 lua_pushcclosure(L, hlua_concat_add, 0);
427 lua_settable(L, -3);
428
429 lua_pushstring(L, "dump");
430 lua_pushcclosure(L, hlua_concat_dump, 0);
431 lua_settable(L, -3);
432
433 lua_settable(L, -3); /* Sets the __index entry. */
434 class_concat_ref = luaL_ref(L, LUA_REGISTRYINDEX);
435
436 return 1;
437}
438
Thierry Fournierff480422016-02-25 08:36:46 +0100439int hlua_fcn_new_listener(lua_State *L, struct listener *lst)
440{
441 lua_newtable(L);
442
443 /* Pop a class sesison metatable and affect it to the userdata. */
444 lua_rawgeti(L, LUA_REGISTRYINDEX, class_listener_ref);
445 lua_setmetatable(L, -2);
446
447 lua_pushlightuserdata(L, lst);
448 lua_rawseti(L, -2, 0);
449 return 1;
450}
451
452static struct listener *hlua_check_listener(lua_State *L, int ud)
453{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +0200454 return hlua_checkudata(L, ud, class_listener_ref);
Thierry Fournierff480422016-02-25 08:36:46 +0100455}
456
457int hlua_listener_get_stats(lua_State *L)
458{
459 struct listener *li;
460 int i;
461
462 li = hlua_check_listener(L, 1);
463
464 if (!li->frontend) {
465 lua_pushnil(L);
466 return 1;
467 }
468
469 stats_fill_li_stats(li->frontend, li, ST_SHLGNDS, stats, STATS_LEN);
470
471 lua_newtable(L);
472 for (i=0; i<ST_F_TOTAL_FIELDS; i++) {
473 lua_pushstring(L, stat_field_names[i]);
474 hlua_fcn_pushfield(L, &stats[i]);
475 lua_settable(L, -3);
476 }
477 return 1;
478
479}
480
Thierry Fournierf2fdc9d2016-02-22 08:21:39 +0100481int hlua_fcn_new_server(lua_State *L, struct server *srv)
482{
483 lua_newtable(L);
484
485 /* Pop a class sesison metatable and affect it to the userdata. */
486 lua_rawgeti(L, LUA_REGISTRYINDEX, class_server_ref);
487 lua_setmetatable(L, -2);
488
489 lua_pushlightuserdata(L, srv);
490 lua_rawseti(L, -2, 0);
491 return 1;
492}
493
494static struct server *hlua_check_server(lua_State *L, int ud)
495{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +0200496 return hlua_checkudata(L, ud, class_server_ref);
Thierry Fournierf2fdc9d2016-02-22 08:21:39 +0100497}
498
499int hlua_server_get_stats(lua_State *L)
500{
501 struct server *srv;
502 int i;
503
504 srv = hlua_check_server(L, 1);
505
506 if (!srv->proxy) {
507 lua_pushnil(L);
508 return 1;
509 }
510
511 stats_fill_sv_stats(srv->proxy, srv, ST_SHLGNDS, stats, STATS_LEN);
512
513 lua_newtable(L);
514 for (i=0; i<ST_F_TOTAL_FIELDS; i++) {
515 lua_pushstring(L, stat_field_names[i]);
516 hlua_fcn_pushfield(L, &stats[i]);
517 lua_settable(L, -3);
518 }
519 return 1;
520
521}
522
523int hlua_server_get_addr(lua_State *L)
524{
525 struct server *srv;
526 char addr[INET6_ADDRSTRLEN];
527 luaL_Buffer b;
528
529 srv = hlua_check_server(L, 1);
530
531 luaL_buffinit(L, &b);
532
533 switch (srv->addr.ss_family) {
534 case AF_INET:
535 inet_ntop(AF_INET, &((struct sockaddr_in *)&srv->addr)->sin_addr,
536 addr, INET_ADDRSTRLEN);
537 luaL_addstring(&b, addr);
538 luaL_addstring(&b, ":");
539 snprintf(addr, INET_ADDRSTRLEN, "%d",
540 ntohs(((struct sockaddr_in *)&srv->addr)->sin_port));
541 luaL_addstring(&b, addr);
542 break;
543 case AF_INET6:
544 inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&srv->addr)->sin6_addr,
545 addr, INET_ADDRSTRLEN);
546 luaL_addstring(&b, addr);
547 luaL_addstring(&b, ":");
548 snprintf(addr, INET_ADDRSTRLEN, "%d",
549 ntohs(((struct sockaddr_in6 *)&srv->addr)->sin6_port));
550 luaL_addstring(&b, addr);
551 break;
552 case AF_UNIX:
553 luaL_addstring(&b, (char *)((struct sockaddr_un *)&srv->addr)->sun_path);
554 break;
555 default:
556 luaL_addstring(&b, "<unknown>");
557 break;
558 }
559
560 luaL_pushresult(&b);
561 return 1;
562}
563
564int hlua_server_is_draining(lua_State *L)
565{
566 struct server *srv;
567
568 srv = hlua_check_server(L, 1);
569 lua_pushinteger(L, server_is_draining(srv));
570 return 1;
571}
572
573int hlua_server_set_weight(lua_State *L)
574{
575 struct server *srv;
576 const char *weight;
577 const char *err;
578
579 srv = hlua_check_server(L, 1);
580 weight = luaL_checkstring(L, 2);
581
582 err = server_parse_weight_change_request(srv, weight);
583 if (!err)
584 lua_pushnil(L);
585 else
586 hlua_pushstrippedstring(L, err);
587 return 1;
588}
589
590int hlua_server_get_weight(lua_State *L)
591{
592 struct server *srv;
593
594 srv = hlua_check_server(L, 1);
595 lua_pushinteger(L, srv->uweight);
596 return 1;
597}
598
599int hlua_server_set_addr(lua_State *L)
600{
601 struct server *srv;
602 const char *addr;
603 const char *err;
604
605 srv = hlua_check_server(L, 1);
606 addr = luaL_checkstring(L, 2);
607
608 err = server_parse_addr_change_request(srv, addr, "Lua script");
609 if (!err)
610 lua_pushnil(L);
611 else
612 hlua_pushstrippedstring(L, err);
613 return 1;
614}
615
616int hlua_server_shut_sess(lua_State *L)
617{
618 struct server *srv;
619
620 srv = hlua_check_server(L, 1);
621 srv_shutdown_streams(srv, SF_ERR_KILLED);
622 return 0;
623}
624
625int hlua_server_set_drain(lua_State *L)
626{
627 struct server *srv;
628
629 srv = hlua_check_server(L, 1);
630 srv_adm_set_drain(srv);
631 return 0;
632}
633
634int hlua_server_set_maint(lua_State *L)
635{
636 struct server *srv;
637
638 srv = hlua_check_server(L, 1);
639 srv_adm_set_maint(srv);
640 return 0;
641}
642
643int hlua_server_set_ready(lua_State *L)
644{
645 struct server *srv;
646
647 srv = hlua_check_server(L, 1);
648 srv_adm_set_ready(srv);
649 return 0;
650}
651
652int hlua_server_check_enable(lua_State *L)
653{
654 struct server *sv;
655
656 sv = hlua_check_server(L, 1);
657 if (sv->check.state & CHK_ST_CONFIGURED) {
658 sv->check.state &= ~CHK_ST_ENABLED;
659 }
660 return 0;
661}
662
663int hlua_server_check_disable(lua_State *L)
664{
665 struct server *sv;
666
667 sv = hlua_check_server(L, 1);
668 if (sv->check.state & CHK_ST_CONFIGURED) {
669 sv->check.state |= CHK_ST_ENABLED;
670 }
671 return 0;
672}
673
674int hlua_server_check_force_up(lua_State *L)
675{
676 struct server *sv;
677
678 sv = hlua_check_server(L, 1);
679 if (!(sv->track)) {
680 sv->check.health = sv->check.rise + sv->check.fall - 1;
681 srv_set_running(sv, "changed from Lua script");
682 }
683 return 0;
684}
685
686int hlua_server_check_force_nolb(lua_State *L)
687{
688 struct server *sv;
689
690 sv = hlua_check_server(L, 1);
691 if (!(sv->track)) {
692 sv->check.health = sv->check.rise + sv->check.fall - 1;
693 srv_set_stopping(sv, "changed from Lua script");
694 }
695 return 0;
696}
697
698int hlua_server_check_force_down(lua_State *L)
699{
700 struct server *sv;
701
702 sv = hlua_check_server(L, 1);
703 if (!(sv->track)) {
704 sv->check.health = 0;
705 srv_set_stopped(sv, "changed from Lua script");
706 }
707 return 0;
708}
709
710int hlua_server_agent_enable(lua_State *L)
711{
712 struct server *sv;
713
714 sv = hlua_check_server(L, 1);
715 if (sv->agent.state & CHK_ST_CONFIGURED) {
716 sv->agent.state |= CHK_ST_ENABLED;
717 }
718 return 0;
719}
720
721int hlua_server_agent_disable(lua_State *L)
722{
723 struct server *sv;
724
725 sv = hlua_check_server(L, 1);
726 if (sv->agent.state & CHK_ST_CONFIGURED) {
727 sv->agent.state &= ~CHK_ST_ENABLED;
728 }
729 return 0;
730}
731
732int hlua_server_agent_force_up(lua_State *L)
733{
734 struct server *sv;
735
736 sv = hlua_check_server(L, 1);
737 if (sv->agent.state & CHK_ST_ENABLED) {
738 sv->agent.health = sv->agent.rise + sv->agent.fall - 1;
739 srv_set_running(sv, "changed from Lua script");
740 }
741 return 0;
742}
743
744int hlua_server_agent_force_down(lua_State *L)
745{
746 struct server *sv;
747
748 sv = hlua_check_server(L, 1);
749 if (sv->agent.state & CHK_ST_ENABLED) {
750 sv->agent.health = 0;
751 srv_set_stopped(sv, "changed from Lua script");
752 }
753 return 0;
754}
755
Thierry Fournierf61aa632016-02-19 20:56:00 +0100756int hlua_fcn_new_proxy(lua_State *L, struct proxy *px)
757{
Thierry Fournierf2fdc9d2016-02-22 08:21:39 +0100758 struct server *srv;
Thierry Fournierff480422016-02-25 08:36:46 +0100759 struct listener *lst;
760 int lid;
761 char buffer[10];
Thierry Fournierf2fdc9d2016-02-22 08:21:39 +0100762
Thierry Fournierf61aa632016-02-19 20:56:00 +0100763 lua_newtable(L);
764
765 /* Pop a class sesison metatable and affect it to the userdata. */
766 lua_rawgeti(L, LUA_REGISTRYINDEX, class_proxy_ref);
767 lua_setmetatable(L, -2);
768
769 lua_pushlightuserdata(L, px);
770 lua_rawseti(L, -2, 0);
Thierry Fournierf2fdc9d2016-02-22 08:21:39 +0100771
772 /* Browse and register servers. */
773 lua_pushstring(L, "servers");
774 lua_newtable(L);
775 for (srv = px->srv; srv; srv = srv->next) {
776 lua_pushstring(L, srv->id);
777 hlua_fcn_new_server(L, srv);
778 lua_settable(L, -3);
779 }
780 lua_settable(L, -3);
781
Thierry Fournierff480422016-02-25 08:36:46 +0100782 /* Browse and register listeners. */
783 lua_pushstring(L, "listeners");
784 lua_newtable(L);
785 lid = 1;
786 list_for_each_entry(lst, &px->conf.listeners, by_fe) {
787 if (lst->name)
788 lua_pushstring(L, lst->name);
789 else {
790 snprintf(buffer, 10, "sock-%d", lid);
791 lid++;
792 lua_pushstring(L, buffer);
793 }
794 hlua_fcn_new_listener(L, lst);
795 lua_settable(L, -3);
796 }
797 lua_settable(L, -3);
798
Thierry Fournierf61aa632016-02-19 20:56:00 +0100799 return 1;
800}
801
802static struct proxy *hlua_check_proxy(lua_State *L, int ud)
803{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +0200804 return hlua_checkudata(L, ud, class_proxy_ref);
Thierry Fournierf61aa632016-02-19 20:56:00 +0100805}
806
807int hlua_proxy_pause(lua_State *L)
808{
809 struct proxy *px;
810
811 px = hlua_check_proxy(L, 1);
812 pause_proxy(px);
813 return 0;
814}
815
816int hlua_proxy_resume(lua_State *L)
817{
818 struct proxy *px;
819
820 px = hlua_check_proxy(L, 1);
821 resume_proxy(px);
822 return 0;
823}
824
825int hlua_proxy_stop(lua_State *L)
826{
827 struct proxy *px;
828
829 px = hlua_check_proxy(L, 1);
830 stop_proxy(px);
831 return 0;
832}
833
834int hlua_proxy_get_cap(lua_State *L)
835{
836 struct proxy *px;
837 const char *str;
838
839 px = hlua_check_proxy(L, 1);
840 str = proxy_cap_str(px->cap);
841 lua_pushstring(L, str);
842 return 1;
843}
844
845int hlua_proxy_get_stats(lua_State *L)
846{
847 struct proxy *px;
848 int i;
849
850 px = hlua_check_proxy(L, 1);
851 if (px->cap & PR_CAP_BE)
852 stats_fill_be_stats(px, ST_SHLGNDS, stats, STATS_LEN);
853 else
854 stats_fill_fe_stats(px, stats, STATS_LEN);
855 lua_newtable(L);
856 for (i=0; i<ST_F_TOTAL_FIELDS; i++) {
857 lua_pushstring(L, stat_field_names[i]);
858 hlua_fcn_pushfield(L, &stats[i]);
859 lua_settable(L, -3);
860 }
861 return 1;
862}
863
864int hlua_proxy_get_mode(lua_State *L)
865{
866 struct proxy *px;
867 const char *str;
868
869 px = hlua_check_proxy(L, 1);
870 str = proxy_mode_str(px->mode);
871 lua_pushstring(L, str);
872 return 1;
873}
874
875int hlua_proxy_shut_bcksess(lua_State *L)
876{
877 struct proxy *px;
878
879 px = hlua_check_proxy(L, 1);
880 srv_shutdown_backup_streams(px, SF_ERR_KILLED);
881 return 0;
882}
883
Thierry Fournier3d4a6752016-02-19 20:53:30 +0100884int hlua_fcn_post_init(lua_State *L)
885{
Thierry Fournierf61aa632016-02-19 20:56:00 +0100886 struct proxy *px;
887
888 /* get core array. */
889 if (lua_getglobal(L, "core") != LUA_TTABLE)
890 lua_error(L);
891
892 /* Create proxies entry. */
893 lua_pushstring(L, "proxies");
894 lua_newtable(L);
895
896 /* List all proxies. */
897 for (px = proxy; px; px = px->next) {
898 lua_pushstring(L, px->id);
899 hlua_fcn_new_proxy(L, px);
900 lua_settable(L, -3);
901 }
902
903 /* push "proxies" in "core" */
904 lua_settable(L, -3);
905
Thierry Fournier3d4a6752016-02-19 20:53:30 +0100906 return 1;
907}
908
Thierry FOURNIER / OZON.IO62fec752016-11-10 20:38:11 +0100909int hlua_parse_addr(lua_State *L)
910{
911 struct hlua_addr *addr;
912 const char *str = luaL_checkstring(L, 1);
913 unsigned char mask;
914
915 addr = lua_newuserdata(L, sizeof(struct hlua_addr));
916 if (!addr) {
917 lua_pushnil(L);
918 return 1;
919 }
920
921 if (str2net(str, PAT_MF_NO_DNS, &addr->addr.v4.ip, &addr->addr.v4.mask)) {
922 addr->type = AF_INET;
923 return 1;
924 }
925
926 if (str62net(str, &addr->addr.v6.ip, &mask)) {
927 len2mask6(mask, &addr->addr.v6.mask);
928 addr->type = AF_INET6;
929 return 1;
930 }
931
932 lua_pop(L, 1);
933 lua_pushnil(L);
934 return 1;
935}
936
937int hlua_match_addr(lua_State *L)
938{
939 struct hlua_addr *addr1;
940 struct hlua_addr *addr2;
941
942 if (!lua_isuserdata(L, 1) ||
943 !lua_isuserdata(L, 2)) {
944 lua_pushboolean(L, 0);
945 return 1;
946 }
947
948 addr1 = lua_touserdata(L, 1);
949 addr2 = lua_touserdata(L, 2);
950
951 if (addr1->type != addr2->type) {
952 lua_pushboolean(L, 0);
953 return 1;
954 }
955
956 if (addr1->type == AF_INET) {
957 if ((addr1->addr.v4.ip.s_addr & addr2->addr.v4.mask.s_addr) ==
958 (addr2->addr.v4.ip.s_addr & addr1->addr.v4.mask.s_addr)) {
959 lua_pushboolean(L, 1);
960 return 1;
961 }
962 } else {
963 if (((addr1->addr.v6.ip.s6_addr32[0] & addr2->addr.v6.mask.s6_addr32[0]) ==
964 (addr2->addr.v6.ip.s6_addr32[0] & addr1->addr.v6.mask.s6_addr32[0])) &&
965 ((addr1->addr.v6.ip.s6_addr32[1] & addr2->addr.v6.mask.s6_addr32[1]) ==
966 (addr2->addr.v6.ip.s6_addr32[1] & addr1->addr.v6.mask.s6_addr32[1])) &&
967 ((addr1->addr.v6.ip.s6_addr32[2] & addr2->addr.v6.mask.s6_addr32[2]) ==
968 (addr2->addr.v6.ip.s6_addr32[2] & addr1->addr.v6.mask.s6_addr32[2])) &&
969 ((addr1->addr.v6.ip.s6_addr32[3] & addr2->addr.v6.mask.s6_addr32[3]) ==
970 (addr2->addr.v6.ip.s6_addr32[3] & addr1->addr.v6.mask.s6_addr32[3]))) {
971 lua_pushboolean(L, 1);
972 return 1;
973 }
974 }
975
976 lua_pushboolean(L, 0);
977 return 1;
978}
979
Thierry Fournierfb0b5462016-01-21 09:28:58 +0100980int hlua_fcn_reg_core_fcn(lua_State *L)
981{
Thierry Fournier1de16592016-01-27 09:49:07 +0100982 if (!hlua_concat_init(L))
983 return 0;
984
Thierry Fournier4f99b272016-02-22 08:40:02 +0100985 hlua_class_function(L, "now", hlua_now);
986 hlua_class_function(L, "http_date", hlua_http_date);
987 hlua_class_function(L, "imf_date", hlua_imf_date);
988 hlua_class_function(L, "rfc850_date", hlua_rfc850_date);
989 hlua_class_function(L, "asctime_date", hlua_asctime_date);
990 hlua_class_function(L, "concat", hlua_concat_new);
Thierry Fourniereea77c02016-03-18 08:47:13 +0100991 hlua_class_function(L, "get_info", hlua_get_info);
Thierry FOURNIER / OZON.IO62fec752016-11-10 20:38:11 +0100992 hlua_class_function(L, "parse_addr", hlua_parse_addr);
993 hlua_class_function(L, "match_addr", hlua_match_addr);
Thierry Fournier4f99b272016-02-22 08:40:02 +0100994
Thierry Fournierff480422016-02-25 08:36:46 +0100995 /* Create listener object. */
996 lua_newtable(L);
997 lua_pushstring(L, "__index");
998 lua_newtable(L);
999 hlua_class_function(L, "get_stats", hlua_listener_get_stats);
1000 lua_settable(L, -3); /* -> META["__index"] = TABLE */
1001 class_listener_ref = hlua_register_metatable(L, CLASS_LISTENER);
1002
Thierry Fournierf2fdc9d2016-02-22 08:21:39 +01001003 /* Create server object. */
1004 lua_newtable(L);
1005 lua_pushstring(L, "__index");
1006 lua_newtable(L);
1007 hlua_class_function(L, "is_draining", hlua_server_is_draining);
1008 hlua_class_function(L, "set_weight", hlua_server_set_weight);
1009 hlua_class_function(L, "get_weight", hlua_server_get_weight);
1010 hlua_class_function(L, "set_addr", hlua_server_set_addr);
1011 hlua_class_function(L, "get_addr", hlua_server_get_addr);
1012 hlua_class_function(L, "get_stats", hlua_server_get_stats);
1013 hlua_class_function(L, "shut_sess", hlua_server_shut_sess);
1014 hlua_class_function(L, "set_drain", hlua_server_set_drain);
1015 hlua_class_function(L, "set_maint", hlua_server_set_maint);
1016 hlua_class_function(L, "set_ready", hlua_server_set_ready);
1017 hlua_class_function(L, "check_enable", hlua_server_check_enable);
1018 hlua_class_function(L, "check_disable", hlua_server_check_disable);
1019 hlua_class_function(L, "check_force_up", hlua_server_check_force_up);
1020 hlua_class_function(L, "check_force_nolb", hlua_server_check_force_nolb);
1021 hlua_class_function(L, "check_force_down", hlua_server_check_force_down);
1022 hlua_class_function(L, "agent_enable", hlua_server_agent_enable);
1023 hlua_class_function(L, "agent_disable", hlua_server_agent_disable);
1024 hlua_class_function(L, "agent_force_up", hlua_server_agent_force_up);
1025 hlua_class_function(L, "agent_force_down", hlua_server_agent_force_down);
1026 lua_settable(L, -3); /* -> META["__index"] = TABLE */
1027 class_server_ref = hlua_register_metatable(L, CLASS_SERVER);
1028
Thierry Fournierf61aa632016-02-19 20:56:00 +01001029 /* Create proxy object. */
1030 lua_newtable(L);
1031 lua_pushstring(L, "__index");
1032 lua_newtable(L);
1033 hlua_class_function(L, "pause", hlua_proxy_pause);
1034 hlua_class_function(L, "resume", hlua_proxy_resume);
1035 hlua_class_function(L, "stop", hlua_proxy_stop);
1036 hlua_class_function(L, "shut_bcksess", hlua_proxy_shut_bcksess);
1037 hlua_class_function(L, "get_cap", hlua_proxy_get_cap);
1038 hlua_class_function(L, "get_mode", hlua_proxy_get_mode);
1039 hlua_class_function(L, "get_stats", hlua_proxy_get_stats);
1040 lua_settable(L, -3); /* -> META["__index"] = TABLE */
1041 class_proxy_ref = hlua_register_metatable(L, CLASS_PROXY);
1042
Thierry Fournier1550d5d2016-01-21 09:35:41 +01001043 return 5;
Thierry Fournierfb0b5462016-01-21 09:28:58 +01001044}