Line data Source code
1 :
2 : /*
3 : * Copyright (C) Yichun Zhang (agentzh)
4 : */
5 :
6 :
7 : #ifndef DDEBUG
8 : #define DDEBUG 0
9 : #endif
10 : #include "ddebug.h"
11 :
12 :
13 : #include "ngx_http_lua_cache.h"
14 : #include "ngx_http_lua_balancer.h"
15 : #include "ngx_http_lua_util.h"
16 : #include "ngx_http_lua_directive.h"
17 :
18 :
19 : struct ngx_http_lua_balancer_peer_data_s {
20 : /* the round robin data must be first */
21 : ngx_http_upstream_rr_peer_data_t rrp;
22 :
23 : ngx_http_lua_srv_conf_t *conf;
24 : ngx_http_request_t *request;
25 :
26 : ngx_uint_t more_tries;
27 : ngx_uint_t total_tries;
28 :
29 : struct sockaddr *sockaddr;
30 : socklen_t socklen;
31 :
32 : ngx_str_t *host;
33 : in_port_t port;
34 :
35 : int last_peer_state;
36 :
37 : #if !(HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS)
38 : unsigned cloned_upstream_conf; /* :1 */
39 : #endif
40 : };
41 :
42 :
43 : #if (NGX_HTTP_SSL)
44 : static ngx_int_t ngx_http_lua_balancer_set_session(ngx_peer_connection_t *pc,
45 : void *data);
46 : static void ngx_http_lua_balancer_save_session(ngx_peer_connection_t *pc,
47 : void *data);
48 : #endif
49 : static ngx_int_t ngx_http_lua_balancer_init(ngx_conf_t *cf,
50 : ngx_http_upstream_srv_conf_t *us);
51 : static ngx_int_t ngx_http_lua_balancer_init_peer(ngx_http_request_t *r,
52 : ngx_http_upstream_srv_conf_t *us);
53 : static ngx_int_t ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc,
54 : void *data);
55 : static ngx_int_t ngx_http_lua_balancer_by_chunk(lua_State *L,
56 : ngx_http_request_t *r);
57 : void ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data,
58 : ngx_uint_t state);
59 :
60 :
61 : ngx_int_t
62 0 : ngx_http_lua_balancer_handler_file(ngx_http_request_t *r,
63 : ngx_http_lua_srv_conf_t *lscf, lua_State *L)
64 : {
65 : ngx_int_t rc;
66 :
67 0 : rc = ngx_http_lua_cache_loadfile(r->connection->log, L,
68 0 : lscf->balancer.src.data,
69 0 : lscf->balancer.src_key);
70 0 : if (rc != NGX_OK) {
71 0 : return rc;
72 : }
73 :
74 : /* make sure we have a valid code chunk */
75 0 : ngx_http_lua_assert(lua_isfunction(L, -1));
76 :
77 0 : return ngx_http_lua_balancer_by_chunk(L, r);
78 : }
79 :
80 :
81 : ngx_int_t
82 0 : ngx_http_lua_balancer_handler_inline(ngx_http_request_t *r,
83 : ngx_http_lua_srv_conf_t *lscf, lua_State *L)
84 : {
85 : ngx_int_t rc;
86 :
87 0 : rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L,
88 0 : lscf->balancer.src.data,
89 : lscf->balancer.src.len,
90 0 : lscf->balancer.src_key,
91 : "=balancer_by_lua");
92 0 : if (rc != NGX_OK) {
93 0 : return rc;
94 : }
95 :
96 : /* make sure we have a valid code chunk */
97 0 : ngx_http_lua_assert(lua_isfunction(L, -1));
98 :
99 0 : return ngx_http_lua_balancer_by_chunk(L, r);
100 : }
101 :
102 :
103 : char *
104 0 : ngx_http_lua_balancer_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
105 : void *conf)
106 : {
107 : char *rv;
108 : ngx_conf_t save;
109 :
110 0 : save = *cf;
111 0 : cf->handler = ngx_http_lua_balancer_by_lua;
112 0 : cf->handler_conf = conf;
113 :
114 0 : rv = ngx_http_lua_conf_lua_block_parse(cf, cmd);
115 :
116 0 : *cf = save;
117 :
118 0 : return rv;
119 : }
120 :
121 :
122 : char *
123 0 : ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
124 : void *conf)
125 : {
126 : u_char *p;
127 : u_char *name;
128 : ngx_str_t *value;
129 0 : ngx_http_lua_srv_conf_t *lscf = conf;
130 :
131 : ngx_http_upstream_srv_conf_t *uscf;
132 :
133 : dd("enter");
134 :
135 : /* must specify a content handler */
136 0 : if (cmd->post == NULL) {
137 0 : return NGX_CONF_ERROR;
138 : }
139 :
140 0 : if (lscf->balancer.handler) {
141 0 : return "is duplicate";
142 : }
143 :
144 0 : value = cf->args->elts;
145 :
146 0 : lscf->balancer.handler = (ngx_http_lua_srv_conf_handler_pt) cmd->post;
147 :
148 0 : if (cmd->post == ngx_http_lua_balancer_handler_file) {
149 : /* Lua code in an external file */
150 :
151 0 : name = ngx_http_lua_rebase_path(cf->pool, value[1].data,
152 0 : value[1].len);
153 0 : if (name == NULL) {
154 0 : return NGX_CONF_ERROR;
155 : }
156 :
157 0 : lscf->balancer.src.data = name;
158 0 : lscf->balancer.src.len = ngx_strlen(name);
159 :
160 0 : p = ngx_palloc(cf->pool, NGX_HTTP_LUA_FILE_KEY_LEN + 1);
161 0 : if (p == NULL) {
162 0 : return NGX_CONF_ERROR;
163 : }
164 :
165 0 : lscf->balancer.src_key = p;
166 :
167 0 : p = ngx_copy(p, NGX_HTTP_LUA_FILE_TAG, NGX_HTTP_LUA_FILE_TAG_LEN);
168 0 : p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len);
169 0 : *p = '\0';
170 :
171 : } else {
172 : /* inlined Lua code */
173 :
174 0 : lscf->balancer.src = value[1];
175 :
176 0 : p = ngx_palloc(cf->pool, NGX_HTTP_LUA_INLINE_KEY_LEN + 1);
177 0 : if (p == NULL) {
178 0 : return NGX_CONF_ERROR;
179 : }
180 :
181 0 : lscf->balancer.src_key = p;
182 :
183 0 : p = ngx_copy(p, NGX_HTTP_LUA_INLINE_TAG, NGX_HTTP_LUA_INLINE_TAG_LEN);
184 0 : p = ngx_http_lua_digest_hex(p, value[1].data, value[1].len);
185 0 : *p = '\0';
186 : }
187 :
188 0 : uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
189 :
190 0 : if (uscf->peer.init_upstream) {
191 0 : ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
192 : "load balancing method redefined");
193 : }
194 :
195 0 : uscf->peer.init_upstream = ngx_http_lua_balancer_init;
196 :
197 0 : uscf->flags = NGX_HTTP_UPSTREAM_CREATE
198 : |NGX_HTTP_UPSTREAM_WEIGHT
199 : |NGX_HTTP_UPSTREAM_MAX_FAILS
200 : |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
201 : |NGX_HTTP_UPSTREAM_DOWN;
202 :
203 0 : return NGX_CONF_OK;
204 : }
205 :
206 :
207 : static ngx_int_t
208 0 : ngx_http_lua_balancer_init(ngx_conf_t *cf,
209 : ngx_http_upstream_srv_conf_t *us)
210 : {
211 0 : if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) {
212 0 : return NGX_ERROR;
213 : }
214 :
215 : /* this callback is called upon individual requests */
216 0 : us->peer.init = ngx_http_lua_balancer_init_peer;
217 :
218 0 : return NGX_OK;
219 : }
220 :
221 :
222 : static ngx_int_t
223 0 : ngx_http_lua_balancer_init_peer(ngx_http_request_t *r,
224 : ngx_http_upstream_srv_conf_t *us)
225 : {
226 : ngx_http_lua_srv_conf_t *bcf;
227 : ngx_http_lua_balancer_peer_data_t *bp;
228 :
229 0 : bp = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_balancer_peer_data_t));
230 0 : if (bp == NULL) {
231 0 : return NGX_ERROR;
232 : }
233 :
234 0 : r->upstream->peer.data = &bp->rrp;
235 :
236 0 : if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) {
237 0 : return NGX_ERROR;
238 : }
239 :
240 0 : r->upstream->peer.get = ngx_http_lua_balancer_get_peer;
241 0 : r->upstream->peer.free = ngx_http_lua_balancer_free_peer;
242 :
243 : #if (NGX_HTTP_SSL)
244 0 : r->upstream->peer.set_session = ngx_http_lua_balancer_set_session;
245 0 : r->upstream->peer.save_session = ngx_http_lua_balancer_save_session;
246 : #endif
247 :
248 0 : bcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_lua_module);
249 :
250 0 : bp->conf = bcf;
251 0 : bp->request = r;
252 :
253 0 : return NGX_OK;
254 : }
255 :
256 :
257 : static ngx_int_t
258 0 : ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data)
259 : {
260 : lua_State *L;
261 : ngx_int_t rc;
262 : ngx_http_request_t *r;
263 : ngx_http_lua_ctx_t *ctx;
264 : ngx_http_lua_srv_conf_t *lscf;
265 : ngx_http_lua_main_conf_t *lmcf;
266 0 : ngx_http_lua_balancer_peer_data_t *bp = data;
267 :
268 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
269 : "lua balancer peer, tries: %ui", pc->tries);
270 :
271 0 : lscf = bp->conf;
272 :
273 0 : r = bp->request;
274 :
275 0 : ngx_http_lua_assert(lscf->balancer.handler && r);
276 :
277 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
278 :
279 0 : if (ctx == NULL) {
280 0 : ctx = ngx_http_lua_create_ctx(r);
281 0 : if (ctx == NULL) {
282 0 : return NGX_ERROR;
283 : }
284 :
285 0 : L = ngx_http_lua_get_lua_vm(r, ctx);
286 :
287 : } else {
288 0 : L = ngx_http_lua_get_lua_vm(r, ctx);
289 :
290 : dd("reset ctx");
291 0 : ngx_http_lua_reset_ctx(r, L, ctx);
292 : }
293 :
294 0 : ctx->context = NGX_HTTP_LUA_CONTEXT_BALANCER;
295 :
296 0 : bp->sockaddr = NULL;
297 0 : bp->socklen = 0;
298 0 : bp->more_tries = 0;
299 0 : bp->total_tries++;
300 :
301 0 : lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
302 :
303 : /* balancer_by_lua does not support yielding and
304 : * there cannot be any conflicts among concurrent requests,
305 : * thus it is safe to store the peer data in the main conf.
306 : */
307 0 : lmcf->balancer_peer_data = bp;
308 :
309 0 : rc = lscf->balancer.handler(r, lscf, L);
310 :
311 0 : if (rc == NGX_ERROR) {
312 0 : return NGX_ERROR;
313 : }
314 :
315 0 : if (ctx->exited && ctx->exit_code != NGX_OK) {
316 0 : rc = ctx->exit_code;
317 0 : if (rc == NGX_ERROR
318 0 : || rc == NGX_BUSY
319 0 : || rc == NGX_DECLINED
320 : #ifdef HAVE_BALANCER_STATUS_CODE_PATCH
321 0 : || rc >= NGX_HTTP_SPECIAL_RESPONSE
322 : #endif
323 : ) {
324 0 : return rc;
325 : }
326 :
327 0 : if (rc > NGX_OK) {
328 0 : return NGX_ERROR;
329 : }
330 : }
331 :
332 0 : if (bp->sockaddr && bp->socklen) {
333 0 : pc->sockaddr = bp->sockaddr;
334 0 : pc->socklen = bp->socklen;
335 0 : pc->cached = 0;
336 0 : pc->connection = NULL;
337 0 : pc->name = bp->host;
338 :
339 0 : bp->rrp.peers->single = 0;
340 :
341 0 : if (bp->more_tries) {
342 0 : r->upstream->peer.tries += bp->more_tries;
343 : }
344 :
345 : dd("tries: %d", (int) r->upstream->peer.tries);
346 :
347 0 : return NGX_OK;
348 : }
349 :
350 0 : return ngx_http_upstream_get_round_robin_peer(pc, &bp->rrp);
351 : }
352 :
353 :
354 : static ngx_int_t
355 0 : ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r)
356 : {
357 : u_char *err_msg;
358 : size_t len;
359 : ngx_int_t rc;
360 :
361 : /* init nginx context in Lua VM */
362 0 : ngx_http_lua_set_req(L, r);
363 0 : ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */);
364 :
365 : /* {{{ make new env inheriting main thread's globals table */
366 0 : lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new env */
367 0 : ngx_http_lua_get_globals_table(L);
368 0 : lua_setfield(L, -2, "__index");
369 0 : lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */
370 : /* }}} */
371 :
372 0 : lua_setfenv(L, -2); /* set new running env for the code closure */
373 :
374 0 : lua_pushcfunction(L, ngx_http_lua_traceback);
375 0 : lua_insert(L, 1); /* put it under chunk and args */
376 :
377 : /* protected call user code */
378 0 : rc = lua_pcall(L, 0, 1, 1);
379 :
380 0 : lua_remove(L, 1); /* remove traceback function */
381 :
382 : dd("rc == %d", (int) rc);
383 :
384 0 : if (rc != 0) {
385 : /* error occurred when running loaded code */
386 0 : err_msg = (u_char *) lua_tolstring(L, -1, &len);
387 :
388 0 : if (err_msg == NULL) {
389 0 : err_msg = (u_char *) "unknown reason";
390 0 : len = sizeof("unknown reason") - 1;
391 : }
392 :
393 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
394 : "failed to run balancer_by_lua*: %*s", len, err_msg);
395 :
396 0 : lua_settop(L, 0); /* clear remaining elems on stack */
397 :
398 0 : return NGX_ERROR;
399 : }
400 :
401 0 : lua_settop(L, 0); /* clear remaining elems on stack */
402 0 : return rc;
403 : }
404 :
405 :
406 : void
407 0 : ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data,
408 : ngx_uint_t state)
409 : {
410 0 : ngx_http_lua_balancer_peer_data_t *bp = data;
411 :
412 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
413 : "lua balancer free peer, tries: %ui", pc->tries);
414 :
415 0 : if (bp->sockaddr && bp->socklen) {
416 0 : bp->last_peer_state = (int) state;
417 :
418 0 : if (pc->tries) {
419 0 : pc->tries--;
420 : }
421 :
422 0 : return;
423 : }
424 :
425 : /* fallback */
426 :
427 0 : ngx_http_upstream_free_round_robin_peer(pc, data, state);
428 : }
429 :
430 :
431 : #if (NGX_HTTP_SSL)
432 :
433 : static ngx_int_t
434 0 : ngx_http_lua_balancer_set_session(ngx_peer_connection_t *pc, void *data)
435 : {
436 0 : ngx_http_lua_balancer_peer_data_t *bp = data;
437 :
438 0 : if (bp->sockaddr && bp->socklen) {
439 : /* TODO */
440 0 : return NGX_OK;
441 : }
442 :
443 0 : return ngx_http_upstream_set_round_robin_peer_session(pc, &bp->rrp);
444 : }
445 :
446 :
447 : static void
448 0 : ngx_http_lua_balancer_save_session(ngx_peer_connection_t *pc, void *data)
449 : {
450 0 : ngx_http_lua_balancer_peer_data_t *bp = data;
451 :
452 0 : if (bp->sockaddr && bp->socklen) {
453 : /* TODO */
454 0 : return;
455 : }
456 :
457 0 : ngx_http_upstream_save_round_robin_peer_session(pc, &bp->rrp);
458 0 : return;
459 : }
460 :
461 : #endif
462 :
463 :
464 : #ifndef NGX_LUA_NO_FFI_API
465 :
466 : int
467 0 : ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r,
468 : const u_char *addr, size_t addr_len, int port, char **err)
469 : {
470 : ngx_url_t url;
471 : ngx_http_lua_ctx_t *ctx;
472 : ngx_http_upstream_t *u;
473 :
474 : ngx_http_lua_main_conf_t *lmcf;
475 : ngx_http_lua_balancer_peer_data_t *bp;
476 :
477 0 : if (r == NULL) {
478 0 : *err = "no request found";
479 0 : return NGX_ERROR;
480 : }
481 :
482 0 : u = r->upstream;
483 :
484 0 : if (u == NULL) {
485 0 : *err = "no upstream found";
486 0 : return NGX_ERROR;
487 : }
488 :
489 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
490 0 : if (ctx == NULL) {
491 0 : *err = "no ctx found";
492 0 : return NGX_ERROR;
493 : }
494 :
495 0 : if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) {
496 0 : *err = "API disabled in the current context";
497 0 : return NGX_ERROR;
498 : }
499 :
500 0 : lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
501 :
502 : /* we cannot read r->upstream->peer.data here directly because
503 : * it could be overridden by other modules like
504 : * ngx_http_upstream_keepalive_module.
505 : */
506 0 : bp = lmcf->balancer_peer_data;
507 0 : if (bp == NULL) {
508 0 : *err = "no upstream peer data found";
509 0 : return NGX_ERROR;
510 : }
511 :
512 0 : ngx_memzero(&url, sizeof(ngx_url_t));
513 :
514 0 : url.url.data = ngx_palloc(r->pool, addr_len);
515 0 : if (url.url.data == NULL) {
516 0 : *err = "no memory";
517 0 : return NGX_ERROR;
518 : }
519 :
520 0 : ngx_memcpy(url.url.data, addr, addr_len);
521 :
522 0 : url.url.len = addr_len;
523 0 : url.default_port = (in_port_t) port;
524 0 : url.uri_part = 0;
525 0 : url.no_resolve = 1;
526 :
527 0 : if (ngx_parse_url(r->pool, &url) != NGX_OK) {
528 0 : if (url.err) {
529 0 : *err = url.err;
530 : }
531 :
532 0 : return NGX_ERROR;
533 : }
534 :
535 0 : if (url.addrs && url.addrs[0].sockaddr) {
536 0 : bp->sockaddr = url.addrs[0].sockaddr;
537 0 : bp->socklen = url.addrs[0].socklen;
538 0 : bp->host = &url.addrs[0].name;
539 :
540 : } else {
541 0 : *err = "no host allowed";
542 0 : return NGX_ERROR;
543 : }
544 :
545 0 : return NGX_OK;
546 : }
547 :
548 :
549 : int
550 0 : ngx_http_lua_ffi_balancer_set_timeouts(ngx_http_request_t *r,
551 : long connect_timeout, long send_timeout, long read_timeout,
552 : char **err)
553 : {
554 : ngx_http_lua_ctx_t *ctx;
555 : ngx_http_upstream_t *u;
556 :
557 : #if !(HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS)
558 : ngx_http_upstream_conf_t *ucf;
559 : #endif
560 : ngx_http_lua_main_conf_t *lmcf;
561 : ngx_http_lua_balancer_peer_data_t *bp;
562 :
563 0 : if (r == NULL) {
564 0 : *err = "no request found";
565 0 : return NGX_ERROR;
566 : }
567 :
568 0 : u = r->upstream;
569 :
570 0 : if (u == NULL) {
571 0 : *err = "no upstream found";
572 0 : return NGX_ERROR;
573 : }
574 :
575 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
576 0 : if (ctx == NULL) {
577 0 : *err = "no ctx found";
578 0 : return NGX_ERROR;
579 : }
580 :
581 0 : if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) {
582 0 : *err = "API disabled in the current context";
583 0 : return NGX_ERROR;
584 : }
585 :
586 0 : lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
587 :
588 0 : bp = lmcf->balancer_peer_data;
589 0 : if (bp == NULL) {
590 0 : *err = "no upstream peer data found";
591 0 : return NGX_ERROR;
592 : }
593 :
594 : #if !(HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS)
595 : if (!bp->cloned_upstream_conf) {
596 : /* we clone the upstream conf for the current request so that
597 : * we do not affect other requests at all. */
598 :
599 : ucf = ngx_palloc(r->pool, sizeof(ngx_http_upstream_conf_t));
600 :
601 : if (ucf == NULL) {
602 : *err = "no memory";
603 : return NGX_ERROR;
604 : }
605 :
606 : ngx_memcpy(ucf, u->conf, sizeof(ngx_http_upstream_conf_t));
607 :
608 : u->conf = ucf;
609 : bp->cloned_upstream_conf = 1;
610 :
611 : } else {
612 : ucf = u->conf;
613 : }
614 : #endif
615 :
616 0 : if (connect_timeout > 0) {
617 : #if (HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS)
618 0 : u->connect_timeout = (ngx_msec_t) connect_timeout;
619 : #else
620 : ucf->connect_timeout = (ngx_msec_t) connect_timeout;
621 : #endif
622 : }
623 :
624 0 : if (send_timeout > 0) {
625 : #if (HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS)
626 0 : u->send_timeout = (ngx_msec_t) send_timeout;
627 : #else
628 : ucf->send_timeout = (ngx_msec_t) send_timeout;
629 : #endif
630 : }
631 :
632 0 : if (read_timeout > 0) {
633 : #if (HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS)
634 0 : u->read_timeout = (ngx_msec_t) read_timeout;
635 : #else
636 : ucf->read_timeout = (ngx_msec_t) read_timeout;
637 : #endif
638 : }
639 :
640 0 : return NGX_OK;
641 : }
642 :
643 :
644 : int
645 0 : ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r,
646 : int count, char **err)
647 : {
648 : #if (nginx_version >= 1007005)
649 : ngx_uint_t max_tries, total;
650 : #endif
651 : ngx_http_lua_ctx_t *ctx;
652 : ngx_http_upstream_t *u;
653 :
654 : ngx_http_lua_main_conf_t *lmcf;
655 : ngx_http_lua_balancer_peer_data_t *bp;
656 :
657 0 : if (r == NULL) {
658 0 : *err = "no request found";
659 0 : return NGX_ERROR;
660 : }
661 :
662 0 : u = r->upstream;
663 :
664 0 : if (u == NULL) {
665 0 : *err = "no upstream found";
666 0 : return NGX_ERROR;
667 : }
668 :
669 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
670 0 : if (ctx == NULL) {
671 0 : *err = "no ctx found";
672 0 : return NGX_ERROR;
673 : }
674 :
675 0 : if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) {
676 0 : *err = "API disabled in the current context";
677 0 : return NGX_ERROR;
678 : }
679 :
680 0 : lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
681 :
682 0 : bp = lmcf->balancer_peer_data;
683 0 : if (bp == NULL) {
684 0 : *err = "no upstream peer data found";
685 0 : return NGX_ERROR;
686 : }
687 :
688 : #if (nginx_version >= 1007005)
689 0 : max_tries = r->upstream->conf->next_upstream_tries;
690 0 : total = bp->total_tries + r->upstream->peer.tries - 1;
691 :
692 0 : if (max_tries && total + count > max_tries) {
693 0 : count = max_tries - total;
694 0 : *err = "reduced tries due to limit";
695 :
696 : } else {
697 0 : *err = NULL;
698 : }
699 : #else
700 : *err = NULL;
701 : #endif
702 :
703 0 : bp->more_tries = count;
704 0 : return NGX_OK;
705 : }
706 :
707 :
708 : int
709 0 : ngx_http_lua_ffi_balancer_get_last_failure(ngx_http_request_t *r,
710 : int *status, char **err)
711 : {
712 : ngx_http_lua_ctx_t *ctx;
713 : ngx_http_upstream_t *u;
714 : ngx_http_upstream_state_t *state;
715 :
716 : ngx_http_lua_balancer_peer_data_t *bp;
717 : ngx_http_lua_main_conf_t *lmcf;
718 :
719 0 : if (r == NULL) {
720 0 : *err = "no request found";
721 0 : return NGX_ERROR;
722 : }
723 :
724 0 : u = r->upstream;
725 :
726 0 : if (u == NULL) {
727 0 : *err = "no upstream found";
728 0 : return NGX_ERROR;
729 : }
730 :
731 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
732 0 : if (ctx == NULL) {
733 0 : *err = "no ctx found";
734 0 : return NGX_ERROR;
735 : }
736 :
737 0 : if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) {
738 0 : *err = "API disabled in the current context";
739 0 : return NGX_ERROR;
740 : }
741 :
742 0 : lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
743 :
744 0 : bp = lmcf->balancer_peer_data;
745 0 : if (bp == NULL) {
746 0 : *err = "no upstream peer data found";
747 0 : return NGX_ERROR;
748 : }
749 :
750 0 : if (r->upstream_states && r->upstream_states->nelts > 1) {
751 0 : state = r->upstream_states->elts;
752 0 : *status = (int) state[r->upstream_states->nelts - 2].status;
753 :
754 : } else {
755 0 : *status = 0;
756 : }
757 :
758 0 : return bp->last_peer_state;
759 : }
760 :
761 : #endif /* NGX_LUA_NO_FFI_API */
|