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