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_socket_udp.h"
14 : #include "ngx_http_lua_socket_tcp.h"
15 : #include "ngx_http_lua_util.h"
16 : #include "ngx_http_lua_contentby.h"
17 : #include "ngx_http_lua_output.h"
18 : #include "ngx_http_lua_probe.h"
19 :
20 :
21 : #if 1
22 : #undef ngx_http_lua_probe_info
23 : #define ngx_http_lua_probe_info(msg)
24 : #endif
25 :
26 :
27 : #define UDP_MAX_DATAGRAM_SIZE 8192
28 :
29 :
30 : static int ngx_http_lua_socket_udp(lua_State *L);
31 : static int ngx_http_lua_socket_udp_setpeername(lua_State *L);
32 : static int ngx_http_lua_socket_udp_send(lua_State *L);
33 : static int ngx_http_lua_socket_udp_receive(lua_State *L);
34 : static int ngx_http_lua_socket_udp_settimeout(lua_State *L);
35 : static void ngx_http_lua_socket_udp_finalize(ngx_http_request_t *r,
36 : ngx_http_lua_socket_udp_upstream_t *u);
37 : static int ngx_http_lua_socket_udp_upstream_destroy(lua_State *L);
38 : static int ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r,
39 : ngx_http_lua_socket_udp_upstream_t *u, lua_State *L);
40 : static void ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx);
41 : static int ngx_http_lua_socket_error_retval_handler(ngx_http_request_t *r,
42 : ngx_http_lua_socket_udp_upstream_t *u, lua_State *L);
43 : static void ngx_http_lua_socket_udp_handle_error(ngx_http_request_t *r,
44 : ngx_http_lua_socket_udp_upstream_t *u, ngx_uint_t ft_type);
45 : static void ngx_http_lua_socket_udp_cleanup(void *data);
46 : static void ngx_http_lua_socket_udp_handler(ngx_event_t *ev);
47 : static void ngx_http_lua_socket_dummy_handler(ngx_http_request_t *r,
48 : ngx_http_lua_socket_udp_upstream_t *u);
49 : static int ngx_http_lua_socket_udp_receive_retval_handler(ngx_http_request_t *r,
50 : ngx_http_lua_socket_udp_upstream_t *u, lua_State *L);
51 : static ngx_int_t ngx_http_lua_socket_udp_read(ngx_http_request_t *r,
52 : ngx_http_lua_socket_udp_upstream_t *u);
53 : static void ngx_http_lua_socket_udp_read_handler(ngx_http_request_t *r,
54 : ngx_http_lua_socket_udp_upstream_t *u);
55 : static void ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r,
56 : ngx_http_lua_socket_udp_upstream_t *u);
57 : static ngx_int_t ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc);
58 : static int ngx_http_lua_socket_udp_close(lua_State *L);
59 : static ngx_int_t ngx_http_lua_socket_udp_resume(ngx_http_request_t *r);
60 : static void ngx_http_lua_udp_resolve_cleanup(void *data);
61 : static void ngx_http_lua_udp_socket_cleanup(void *data);
62 :
63 :
64 : enum {
65 : SOCKET_CTX_INDEX = 1,
66 : SOCKET_TIMEOUT_INDEX = 2
67 : };
68 :
69 :
70 : static char ngx_http_lua_socket_udp_metatable_key;
71 : static char ngx_http_lua_udp_udata_metatable_key;
72 : static u_char ngx_http_lua_socket_udp_buffer[UDP_MAX_DATAGRAM_SIZE];
73 :
74 :
75 : void
76 18 : ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L)
77 : {
78 18 : lua_getfield(L, -1, "socket"); /* ngx socket */
79 :
80 18 : lua_pushcfunction(L, ngx_http_lua_socket_udp);
81 18 : lua_setfield(L, -2, "udp"); /* ngx socket */
82 :
83 : /* udp socket object metatable */
84 18 : lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key);
85 18 : lua_createtable(L, 0 /* narr */, 6 /* nrec */);
86 :
87 18 : lua_pushcfunction(L, ngx_http_lua_socket_udp_setpeername);
88 18 : lua_setfield(L, -2, "setpeername"); /* ngx socket mt */
89 :
90 18 : lua_pushcfunction(L, ngx_http_lua_socket_udp_send);
91 18 : lua_setfield(L, -2, "send");
92 :
93 18 : lua_pushcfunction(L, ngx_http_lua_socket_udp_receive);
94 18 : lua_setfield(L, -2, "receive");
95 :
96 18 : lua_pushcfunction(L, ngx_http_lua_socket_udp_settimeout);
97 18 : lua_setfield(L, -2, "settimeout"); /* ngx socket mt */
98 :
99 18 : lua_pushcfunction(L, ngx_http_lua_socket_udp_close);
100 18 : lua_setfield(L, -2, "close"); /* ngx socket mt */
101 :
102 18 : lua_pushvalue(L, -1);
103 18 : lua_setfield(L, -2, "__index");
104 18 : lua_rawset(L, LUA_REGISTRYINDEX);
105 : /* }}} */
106 :
107 : /* udp socket object metatable */
108 18 : lua_pushlightuserdata(L, &ngx_http_lua_udp_udata_metatable_key);
109 18 : lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */
110 18 : lua_pushcfunction(L, ngx_http_lua_socket_udp_upstream_destroy);
111 18 : lua_setfield(L, -2, "__gc");
112 18 : lua_rawset(L, LUA_REGISTRYINDEX);
113 : /* }}} */
114 :
115 18 : lua_pop(L, 1);
116 18 : }
117 :
118 :
119 : static int
120 0 : ngx_http_lua_socket_udp(lua_State *L)
121 : {
122 : ngx_http_request_t *r;
123 : ngx_http_lua_ctx_t *ctx;
124 :
125 0 : if (lua_gettop(L) != 0) {
126 0 : return luaL_error(L, "expecting zero arguments, but got %d",
127 : lua_gettop(L));
128 : }
129 :
130 0 : r = ngx_http_lua_get_req(L);
131 0 : if (r == NULL) {
132 0 : return luaL_error(L, "no request found");
133 : }
134 :
135 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
136 0 : if (ctx == NULL) {
137 0 : return luaL_error(L, "no ctx found");
138 : }
139 :
140 0 : ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
141 : | NGX_HTTP_LUA_CONTEXT_ACCESS
142 : | NGX_HTTP_LUA_CONTEXT_CONTENT
143 : | NGX_HTTP_LUA_CONTEXT_TIMER
144 : | NGX_HTTP_LUA_CONTEXT_SSL_CERT);
145 :
146 0 : lua_createtable(L, 3 /* narr */, 1 /* nrec */);
147 0 : lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key);
148 0 : lua_rawget(L, LUA_REGISTRYINDEX);
149 0 : lua_setmetatable(L, -2);
150 :
151 : dd("top: %d", lua_gettop(L));
152 :
153 0 : return 1;
154 : }
155 :
156 :
157 : static int
158 0 : ngx_http_lua_socket_udp_setpeername(lua_State *L)
159 : {
160 : ngx_http_request_t *r;
161 : ngx_http_lua_ctx_t *ctx;
162 : ngx_str_t host;
163 : int port;
164 : ngx_resolver_ctx_t *rctx, temp;
165 : ngx_http_core_loc_conf_t *clcf;
166 : int saved_top;
167 : int n;
168 : u_char *p;
169 : size_t len;
170 : ngx_url_t url;
171 : ngx_int_t rc;
172 : ngx_http_lua_loc_conf_t *llcf;
173 : int timeout;
174 : ngx_http_lua_co_ctx_t *coctx;
175 :
176 : ngx_http_lua_udp_connection_t *uc;
177 : ngx_http_lua_socket_udp_upstream_t *u;
178 :
179 : /*
180 : * TODO: we should probably accept an extra argument to setpeername()
181 : * to allow the user bind the datagram unix domain socket himself,
182 : * which is necessary for systems without autobind support.
183 : */
184 :
185 0 : n = lua_gettop(L);
186 0 : if (n != 2 && n != 3) {
187 0 : return luaL_error(L, "ngx.socket.udp setpeername: expecting 2 or 3 "
188 : "arguments (including the object), but seen %d", n);
189 : }
190 :
191 0 : r = ngx_http_lua_get_req(L);
192 0 : if (r == NULL) {
193 0 : return luaL_error(L, "no request found");
194 : }
195 :
196 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
197 0 : if (ctx == NULL) {
198 0 : return luaL_error(L, "no ctx found");
199 : }
200 :
201 0 : ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
202 : | NGX_HTTP_LUA_CONTEXT_ACCESS
203 : | NGX_HTTP_LUA_CONTEXT_CONTENT
204 : | NGX_HTTP_LUA_CONTEXT_TIMER
205 : | NGX_HTTP_LUA_CONTEXT_SSL_CERT);
206 :
207 0 : luaL_checktype(L, 1, LUA_TTABLE);
208 :
209 0 : p = (u_char *) luaL_checklstring(L, 2, &len);
210 :
211 0 : host.data = ngx_palloc(r->pool, len + 1);
212 0 : if (host.data == NULL) {
213 0 : return luaL_error(L, "no memory");
214 : }
215 :
216 0 : host.len = len;
217 :
218 0 : ngx_memcpy(host.data, p, len);
219 0 : host.data[len] = '\0';
220 :
221 0 : if (n == 3) {
222 0 : port = luaL_checkinteger(L, 3);
223 :
224 0 : if (port < 0 || port > 65536) {
225 0 : lua_pushnil(L);
226 0 : lua_pushfstring(L, "bad port number: %d", port);
227 0 : return 2;
228 : }
229 :
230 : } else { /* n == 2 */
231 0 : port = 0;
232 : }
233 :
234 0 : lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
235 0 : u = lua_touserdata(L, -1);
236 0 : lua_pop(L, 1);
237 :
238 0 : if (u) {
239 0 : if (u->request && u->request != r) {
240 0 : return luaL_error(L, "bad request");
241 : }
242 :
243 0 : if (u->waiting) {
244 0 : lua_pushnil(L);
245 0 : lua_pushliteral(L, "socket busy");
246 0 : return 2;
247 : }
248 :
249 0 : if (u->udp_connection.connection) {
250 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
251 : "lua udp socket reconnect without shutting down");
252 :
253 0 : ngx_http_lua_socket_udp_finalize(r, u);
254 : }
255 :
256 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
257 : "lua reuse socket upstream ctx");
258 :
259 : } else {
260 0 : u = lua_newuserdata(L, sizeof(ngx_http_lua_socket_udp_upstream_t));
261 0 : if (u == NULL) {
262 0 : return luaL_error(L, "no memory");
263 : }
264 :
265 : #if 1
266 0 : lua_pushlightuserdata(L, &ngx_http_lua_udp_udata_metatable_key);
267 0 : lua_rawget(L, LUA_REGISTRYINDEX);
268 0 : lua_setmetatable(L, -2);
269 : #endif
270 :
271 0 : lua_rawseti(L, 1, SOCKET_CTX_INDEX);
272 : }
273 :
274 0 : ngx_memzero(u, sizeof(ngx_http_lua_socket_udp_upstream_t));
275 :
276 0 : u->request = r; /* set the controlling request */
277 0 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
278 :
279 0 : u->conf = llcf;
280 :
281 0 : uc = &u->udp_connection;
282 :
283 0 : uc->log = *r->connection->log;
284 :
285 : dd("lua peer connection log: %p", &uc->log);
286 :
287 0 : lua_rawgeti(L, 1, SOCKET_TIMEOUT_INDEX);
288 0 : timeout = (ngx_int_t) lua_tointeger(L, -1);
289 0 : lua_pop(L, 1);
290 :
291 0 : if (timeout > 0) {
292 0 : u->read_timeout = (ngx_msec_t) timeout;
293 :
294 : } else {
295 0 : u->read_timeout = u->conf->read_timeout;
296 : }
297 :
298 0 : ngx_memzero(&url, sizeof(ngx_url_t));
299 :
300 0 : url.url.len = host.len;
301 0 : url.url.data = host.data;
302 0 : url.default_port = (in_port_t) port;
303 0 : url.no_resolve = 1;
304 :
305 0 : if (ngx_parse_url(r->pool, &url) != NGX_OK) {
306 0 : lua_pushnil(L);
307 :
308 0 : if (url.err) {
309 0 : lua_pushfstring(L, "failed to parse host name \"%s\": %s",
310 : host.data, url.err);
311 :
312 : } else {
313 0 : lua_pushfstring(L, "failed to parse host name \"%s\"", host.data);
314 : }
315 :
316 0 : return 2;
317 : }
318 :
319 0 : u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
320 0 : if (u->resolved == NULL) {
321 0 : return luaL_error(L, "no memory");
322 : }
323 :
324 0 : if (url.addrs && url.addrs[0].sockaddr) {
325 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
326 : "lua udp socket network address given directly");
327 :
328 0 : u->resolved->sockaddr = url.addrs[0].sockaddr;
329 0 : u->resolved->socklen = url.addrs[0].socklen;
330 0 : u->resolved->naddrs = 1;
331 0 : u->resolved->host = url.addrs[0].name;
332 :
333 : } else {
334 0 : u->resolved->host = host;
335 0 : u->resolved->port = (in_port_t) port;
336 : }
337 :
338 0 : if (u->resolved->sockaddr) {
339 0 : rc = ngx_http_lua_socket_resolve_retval_handler(r, u, L);
340 0 : if (rc == NGX_AGAIN) {
341 0 : return lua_yield(L, 0);
342 : }
343 :
344 0 : return rc;
345 : }
346 :
347 0 : clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
348 :
349 0 : temp.name = host;
350 0 : rctx = ngx_resolve_start(clcf->resolver, &temp);
351 0 : if (rctx == NULL) {
352 0 : u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER;
353 0 : lua_pushnil(L);
354 0 : lua_pushliteral(L, "failed to start the resolver");
355 0 : return 2;
356 : }
357 :
358 0 : if (rctx == NGX_NO_RESOLVER) {
359 0 : u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER;
360 0 : lua_pushnil(L);
361 0 : lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data);
362 0 : return 2;
363 : }
364 :
365 0 : rctx->name = host;
366 : #if !defined(nginx_version) || nginx_version < 1005008
367 : rctx->type = NGX_RESOLVE_A;
368 : #endif
369 0 : rctx->handler = ngx_http_lua_socket_resolve_handler;
370 0 : rctx->data = u;
371 0 : rctx->timeout = clcf->resolver_timeout;
372 :
373 0 : u->co_ctx = ctx->cur_co_ctx;
374 0 : u->resolved->ctx = rctx;
375 :
376 0 : saved_top = lua_gettop(L);
377 :
378 0 : coctx = ctx->cur_co_ctx;
379 0 : ngx_http_lua_cleanup_pending_operation(coctx);
380 0 : coctx->cleanup = ngx_http_lua_udp_resolve_cleanup;
381 :
382 0 : if (ngx_resolve_name(rctx) != NGX_OK) {
383 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
384 : "lua udp socket fail to run resolver immediately");
385 :
386 0 : u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER;
387 :
388 0 : u->resolved->ctx = NULL;
389 0 : lua_pushnil(L);
390 0 : lua_pushfstring(L, "%s could not be resolved", host.data);
391 :
392 0 : return 2;
393 : }
394 :
395 0 : if (u->waiting == 1) {
396 : /* resolved and already connecting */
397 0 : return lua_yield(L, 0);
398 : }
399 :
400 0 : n = lua_gettop(L) - saved_top;
401 0 : if (n) {
402 : /* errors occurred during resolving or connecting
403 : * or already connected */
404 0 : return n;
405 : }
406 :
407 : /* still resolving */
408 :
409 0 : u->waiting = 1;
410 0 : u->prepare_retvals = ngx_http_lua_socket_resolve_retval_handler;
411 :
412 0 : coctx->data = u;
413 :
414 0 : if (ctx->entered_content_phase) {
415 0 : r->write_event_handler = ngx_http_lua_content_wev_handler;
416 :
417 : } else {
418 0 : r->write_event_handler = ngx_http_core_run_phases;
419 : }
420 :
421 0 : return lua_yield(L, 0);
422 : }
423 :
424 :
425 : static void
426 0 : ngx_http_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx)
427 : {
428 : ngx_http_request_t *r;
429 : ngx_connection_t *c;
430 : ngx_http_upstream_resolved_t *ur;
431 : ngx_http_lua_ctx_t *lctx;
432 : lua_State *L;
433 : ngx_http_lua_socket_udp_upstream_t *u;
434 : u_char *p;
435 : size_t len;
436 : #if defined(nginx_version) && nginx_version >= 1005008
437 : socklen_t socklen;
438 : struct sockaddr *sockaddr;
439 : #else
440 : struct sockaddr_in *sin;
441 : #endif
442 : ngx_uint_t i;
443 : unsigned waiting;
444 :
445 0 : u = ctx->data;
446 0 : r = u->request;
447 0 : c = r->connection;
448 0 : ur = u->resolved;
449 :
450 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
451 : "lua udp socket resolve handler");
452 :
453 0 : lctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
454 0 : if (lctx == NULL) {
455 0 : return;
456 : }
457 :
458 0 : lctx->cur_co_ctx = u->co_ctx;
459 :
460 0 : u->co_ctx->cleanup = NULL;
461 :
462 0 : L = lctx->cur_co_ctx->co;
463 :
464 : dd("setting socket_ready to 1");
465 :
466 0 : waiting = u->waiting;
467 :
468 0 : if (ctx->state) {
469 0 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
470 : "lua udp socket resolver error: %s (waiting: %d)",
471 : ngx_resolver_strerror(ctx->state), (int) u->waiting);
472 :
473 0 : lua_pushnil(L);
474 0 : lua_pushlstring(L, (char *) ctx->name.data, ctx->name.len);
475 0 : lua_pushfstring(L, " could not be resolved (%d: %s)",
476 0 : (int) ctx->state,
477 : ngx_resolver_strerror(ctx->state));
478 0 : lua_concat(L, 2);
479 :
480 : #if 1
481 0 : ngx_resolve_name_done(ctx);
482 0 : ur->ctx = NULL;
483 : #endif
484 :
485 0 : u->prepare_retvals = ngx_http_lua_socket_error_retval_handler;
486 0 : ngx_http_lua_socket_udp_handle_error(r, u,
487 : NGX_HTTP_LUA_SOCKET_FT_RESOLVER);
488 :
489 0 : if (waiting) {
490 0 : ngx_http_run_posted_requests(c);
491 : }
492 :
493 0 : return;
494 : }
495 :
496 0 : ur->naddrs = ctx->naddrs;
497 0 : ur->addrs = ctx->addrs;
498 :
499 : #if (NGX_DEBUG)
500 : {
501 : # if defined(nginx_version) && nginx_version >= 1005008
502 : u_char text[NGX_SOCKADDR_STRLEN];
503 : ngx_str_t addr;
504 : # else
505 : in_addr_t addr;
506 : # endif
507 : ngx_uint_t i;
508 :
509 : # if defined(nginx_version) && nginx_version >= 1005008
510 0 : addr.data = text;
511 :
512 0 : for (i = 0; i < ctx->naddrs; i++) {
513 0 : addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen,
514 : text, NGX_SOCKADDR_STRLEN, 0);
515 :
516 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
517 : "name was resolved to %V", &addr);
518 : }
519 : # else
520 : for (i = 0; i < ctx->naddrs; i++) {
521 : dd("addr i: %d %p", (int) i, &ctx->addrs[i]);
522 :
523 : addr = ntohl(ctx->addrs[i]);
524 :
525 : ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
526 : "name was resolved to %ud.%ud.%ud.%ud",
527 : (addr >> 24) & 0xff, (addr >> 16) & 0xff,
528 : (addr >> 8) & 0xff, addr & 0xff);
529 : }
530 : # endif
531 : }
532 : #endif
533 :
534 0 : ngx_http_lua_assert(ur->naddrs > 0);
535 :
536 0 : if (ur->naddrs == 1) {
537 0 : i = 0;
538 :
539 : } else {
540 0 : i = ngx_random() % ur->naddrs;
541 : }
542 :
543 : dd("selected addr index: %d", (int) i);
544 :
545 : #if defined(nginx_version) && nginx_version >= 1005008
546 0 : socklen = ur->addrs[i].socklen;
547 :
548 0 : sockaddr = ngx_palloc(r->pool, socklen);
549 0 : if (sockaddr == NULL) {
550 0 : goto nomem;
551 : }
552 :
553 0 : ngx_memcpy(sockaddr, ur->addrs[i].sockaddr, socklen);
554 :
555 0 : switch (sockaddr->sa_family) {
556 : #if (NGX_HAVE_INET6)
557 0 : case AF_INET6:
558 0 : ((struct sockaddr_in6 *) sockaddr)->sin6_port = htons(ur->port);
559 0 : break;
560 : #endif
561 0 : default: /* AF_INET */
562 0 : ((struct sockaddr_in *) sockaddr)->sin_port = htons(ur->port);
563 : }
564 :
565 0 : p = ngx_pnalloc(r->pool, NGX_SOCKADDR_STRLEN);
566 0 : if (p == NULL) {
567 0 : goto nomem;
568 : }
569 :
570 0 : len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1);
571 0 : ur->sockaddr = sockaddr;
572 0 : ur->socklen = socklen;
573 :
574 : #else
575 : /* for nginx older than 1.5.8 */
576 :
577 : len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;
578 :
579 : p = ngx_pnalloc(r->pool, len + sizeof(struct sockaddr_in));
580 : if (p == NULL) {
581 : goto nomem;
582 : }
583 :
584 : sin = (struct sockaddr_in *) &p[len];
585 : ngx_memzero(sin, sizeof(struct sockaddr_in));
586 :
587 : len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, NGX_INET_ADDRSTRLEN);
588 : len = ngx_sprintf(&p[len], ":%d", ur->port) - p;
589 :
590 : sin->sin_family = AF_INET;
591 : sin->sin_port = htons(ur->port);
592 : sin->sin_addr.s_addr = ur->addrs[i];
593 :
594 : ur->sockaddr = (struct sockaddr *) sin;
595 : ur->socklen = sizeof(struct sockaddr_in);
596 : #endif
597 :
598 0 : ur->host.data = p;
599 0 : ur->host.len = len;
600 0 : ur->naddrs = 1;
601 :
602 0 : ngx_resolve_name_done(ctx);
603 0 : ur->ctx = NULL;
604 :
605 0 : u->waiting = 0;
606 :
607 0 : if (waiting) {
608 0 : lctx->resume_handler = ngx_http_lua_socket_udp_resume;
609 0 : r->write_event_handler(r);
610 0 : ngx_http_run_posted_requests(c);
611 :
612 : } else {
613 0 : (void) ngx_http_lua_socket_resolve_retval_handler(r, u, L);
614 : }
615 :
616 0 : return;
617 :
618 0 : nomem:
619 :
620 0 : if (ur->ctx) {
621 0 : ngx_resolve_name_done(ctx);
622 0 : ur->ctx = NULL;
623 : }
624 :
625 0 : u->prepare_retvals = ngx_http_lua_socket_error_retval_handler;
626 0 : ngx_http_lua_socket_udp_handle_error(r, u,
627 : NGX_HTTP_LUA_SOCKET_FT_NOMEM);
628 :
629 0 : if (waiting) {
630 0 : ngx_http_run_posted_requests(c);
631 :
632 : } else {
633 0 : lua_pushnil(L);
634 0 : lua_pushliteral(L, "no memory");
635 : }
636 : }
637 :
638 :
639 : static int
640 0 : ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r,
641 : ngx_http_lua_socket_udp_upstream_t *u, lua_State *L)
642 : {
643 : ngx_http_lua_ctx_t *ctx;
644 : ngx_http_lua_co_ctx_t *coctx;
645 : ngx_connection_t *c;
646 : ngx_http_cleanup_t *cln;
647 : ngx_http_upstream_resolved_t *ur;
648 : ngx_int_t rc;
649 : ngx_http_lua_udp_connection_t *uc;
650 :
651 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
652 : "lua udp socket resolve retval handler");
653 :
654 0 : if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_RESOLVER) {
655 0 : return 2;
656 : }
657 :
658 0 : uc = &u->udp_connection;
659 :
660 0 : ur = u->resolved;
661 :
662 0 : if (ur->sockaddr) {
663 0 : uc->sockaddr = ur->sockaddr;
664 0 : uc->socklen = ur->socklen;
665 0 : uc->server = ur->host;
666 :
667 : } else {
668 0 : lua_pushnil(L);
669 0 : lua_pushliteral(L, "resolver not working");
670 0 : return 2;
671 : }
672 :
673 0 : rc = ngx_http_lua_udp_connect(uc);
674 :
675 0 : if (rc != NGX_OK) {
676 0 : u->socket_errno = ngx_socket_errno;
677 : }
678 :
679 0 : if (u->cleanup == NULL) {
680 0 : cln = ngx_http_cleanup_add(r, 0);
681 0 : if (cln == NULL) {
682 0 : u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_ERROR;
683 0 : lua_pushnil(L);
684 0 : lua_pushliteral(L, "no memory");
685 0 : return 2;
686 : }
687 :
688 0 : cln->handler = ngx_http_lua_socket_udp_cleanup;
689 0 : cln->data = u;
690 0 : u->cleanup = &cln->handler;
691 : }
692 :
693 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
694 : "lua udp socket connect: %i", rc);
695 :
696 0 : if (rc != NGX_OK) {
697 0 : return ngx_http_lua_socket_error_retval_handler(r, u, L);
698 : }
699 :
700 : /* rc == NGX_OK */
701 :
702 0 : c = uc->connection;
703 :
704 0 : c->data = u;
705 :
706 0 : c->write->handler = NULL;
707 0 : c->read->handler = ngx_http_lua_socket_udp_handler;
708 0 : c->read->resolver = 0;
709 :
710 0 : c->pool = r->pool;
711 0 : c->log = r->connection->log;
712 0 : c->read->log = c->log;
713 0 : c->write->log = c->log;
714 :
715 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
716 :
717 0 : coctx = ctx->cur_co_ctx;
718 :
719 0 : coctx->data = u;
720 :
721 0 : u->read_event_handler = ngx_http_lua_socket_dummy_handler;
722 :
723 0 : lua_pushinteger(L, 1);
724 0 : return 1;
725 : }
726 :
727 :
728 : static int
729 0 : ngx_http_lua_socket_error_retval_handler(ngx_http_request_t *r,
730 : ngx_http_lua_socket_udp_upstream_t *u, lua_State *L)
731 : {
732 : u_char errstr[NGX_MAX_ERROR_STR];
733 : u_char *p;
734 :
735 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
736 : "lua udp socket error retval handler");
737 :
738 0 : if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_RESOLVER) {
739 0 : return 2;
740 : }
741 :
742 0 : lua_pushnil(L);
743 :
744 0 : if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_PARTIALWRITE) {
745 0 : lua_pushliteral(L, "partial write");
746 :
747 0 : } else if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_TIMEOUT) {
748 0 : lua_pushliteral(L, "timeout");
749 :
750 0 : } else if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_CLOSED) {
751 0 : lua_pushliteral(L, "closed");
752 :
753 0 : } else if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_BUFTOOSMALL) {
754 0 : lua_pushliteral(L, "buffer too small");
755 :
756 0 : } else if (u->ft_type & NGX_HTTP_LUA_SOCKET_FT_NOMEM) {
757 0 : lua_pushliteral(L, "no memory");
758 :
759 : } else {
760 :
761 0 : if (u->socket_errno) {
762 : #if defined(nginx_version) && nginx_version >= 9000
763 0 : p = ngx_strerror(u->socket_errno, errstr, sizeof(errstr));
764 : #else
765 : p = ngx_strerror_r(u->socket_errno, errstr, sizeof(errstr));
766 : #endif
767 : /* for compatibility with LuaSocket */
768 0 : ngx_strlow(errstr, errstr, p - errstr);
769 0 : lua_pushlstring(L, (char *) errstr, p - errstr);
770 :
771 : } else {
772 0 : lua_pushliteral(L, "error");
773 : }
774 : }
775 :
776 0 : return 2;
777 : }
778 :
779 :
780 : static int
781 0 : ngx_http_lua_socket_udp_send(lua_State *L)
782 : {
783 : ssize_t n;
784 : ngx_http_request_t *r;
785 : u_char *p;
786 : size_t len;
787 : ngx_http_lua_socket_udp_upstream_t *u;
788 : int type;
789 : const char *msg;
790 : ngx_str_t query;
791 : ngx_http_lua_loc_conf_t *llcf;
792 :
793 0 : if (lua_gettop(L) != 2) {
794 0 : return luaL_error(L, "expecting 2 arguments (including the object), "
795 : "but got %d", lua_gettop(L));
796 : }
797 :
798 0 : r = ngx_http_lua_get_req(L);
799 0 : if (r == NULL) {
800 0 : return luaL_error(L, "request object not found");
801 : }
802 :
803 0 : luaL_checktype(L, 1, LUA_TTABLE);
804 :
805 0 : lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
806 0 : u = lua_touserdata(L, -1);
807 0 : lua_pop(L, 1);
808 :
809 0 : if (u == NULL || u->udp_connection.connection == NULL) {
810 0 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
811 :
812 0 : if (llcf->log_socket_errors) {
813 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
814 : "attempt to send data on a closed socket: u:%p, c:%p",
815 : u, u ? u->udp_connection.connection : NULL);
816 : }
817 :
818 0 : lua_pushnil(L);
819 0 : lua_pushliteral(L, "closed");
820 0 : return 2;
821 : }
822 :
823 0 : if (u->request != r) {
824 0 : return luaL_error(L, "bad request");
825 : }
826 :
827 0 : if (u->ft_type) {
828 0 : u->ft_type = 0;
829 : }
830 :
831 0 : if (u->waiting) {
832 0 : lua_pushnil(L);
833 0 : lua_pushliteral(L, "socket busy");
834 0 : return 2;
835 : }
836 :
837 0 : type = lua_type(L, 2);
838 0 : switch (type) {
839 0 : case LUA_TNUMBER:
840 : case LUA_TSTRING:
841 0 : lua_tolstring(L, 2, &len);
842 0 : break;
843 :
844 0 : case LUA_TTABLE:
845 0 : len = ngx_http_lua_calc_strlen_in_table(L, 2, 2, 1 /* strict */);
846 0 : break;
847 :
848 0 : default:
849 0 : msg = lua_pushfstring(L, "string, number, boolean, nil, "
850 : "or array table expected, got %s",
851 : lua_typename(L, type));
852 :
853 0 : return luaL_argerror(L, 2, msg);
854 : }
855 :
856 0 : query.data = lua_newuserdata(L, len);
857 0 : query.len = len;
858 :
859 0 : switch (type) {
860 0 : case LUA_TNUMBER:
861 : case LUA_TSTRING:
862 0 : p = (u_char *) lua_tolstring(L, 2, &len);
863 0 : ngx_memcpy(query.data, (u_char *) p, len);
864 0 : break;
865 :
866 0 : case LUA_TTABLE:
867 0 : (void) ngx_http_lua_copy_str_in_table(L, 2, query.data);
868 0 : break;
869 :
870 0 : default:
871 0 : return luaL_error(L, "impossible to reach here");
872 : }
873 :
874 0 : u->ft_type = 0;
875 :
876 : /* mimic ngx_http_upstream_init_request here */
877 :
878 : #if 1
879 0 : u->waiting = 0;
880 : #endif
881 :
882 : dd("sending query %.*s", (int) query.len, query.data);
883 :
884 0 : n = ngx_send(u->udp_connection.connection, query.data, query.len);
885 :
886 : dd("ngx_send returns %d (query len %d)", (int) n, (int) query.len);
887 :
888 0 : if (n == NGX_ERROR || n == NGX_AGAIN) {
889 0 : u->socket_errno = ngx_socket_errno;
890 :
891 0 : return ngx_http_lua_socket_error_retval_handler(r, u, L);
892 : }
893 :
894 0 : if (n != (ssize_t) query.len) {
895 : dd("not the while query was sent");
896 :
897 0 : u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_PARTIALWRITE;
898 0 : return ngx_http_lua_socket_error_retval_handler(r, u, L);
899 : }
900 :
901 : dd("n == len");
902 :
903 0 : lua_pushinteger(L, 1);
904 0 : return 1;
905 : }
906 :
907 :
908 : static int
909 0 : ngx_http_lua_socket_udp_receive(lua_State *L)
910 : {
911 : ngx_http_request_t *r;
912 : ngx_http_lua_socket_udp_upstream_t *u;
913 : ngx_int_t rc;
914 : ngx_http_lua_ctx_t *ctx;
915 : ngx_http_lua_co_ctx_t *coctx;
916 : size_t size;
917 : int nargs;
918 : ngx_http_lua_loc_conf_t *llcf;
919 :
920 0 : nargs = lua_gettop(L);
921 0 : if (nargs != 1 && nargs != 2) {
922 0 : return luaL_error(L, "expecting 1 or 2 arguments "
923 : "(including the object), but got %d", nargs);
924 : }
925 :
926 0 : r = ngx_http_lua_get_req(L);
927 0 : if (r == NULL) {
928 0 : return luaL_error(L, "no request found");
929 : }
930 :
931 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
932 : "lua udp socket calling receive() method");
933 :
934 0 : luaL_checktype(L, 1, LUA_TTABLE);
935 :
936 0 : lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
937 0 : u = lua_touserdata(L, -1);
938 0 : lua_pop(L, 1);
939 :
940 0 : if (u == NULL || u->udp_connection.connection == NULL) {
941 0 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
942 :
943 0 : if (llcf->log_socket_errors) {
944 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
945 : "attempt to receive data on a closed socket: u:%p, "
946 : "c:%p", u, u ? u->udp_connection.connection : NULL);
947 : }
948 :
949 0 : lua_pushnil(L);
950 0 : lua_pushliteral(L, "closed");
951 0 : return 2;
952 : }
953 :
954 0 : if (u->request != r) {
955 0 : return luaL_error(L, "bad request");
956 : }
957 :
958 0 : if (u->ft_type) {
959 0 : u->ft_type = 0;
960 : }
961 :
962 : #if 1
963 0 : if (u->waiting) {
964 0 : lua_pushnil(L);
965 0 : lua_pushliteral(L, "socket busy");
966 0 : return 2;
967 : }
968 : #endif
969 :
970 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
971 : "lua udp socket read timeout: %M", u->read_timeout);
972 :
973 0 : size = (size_t) luaL_optnumber(L, 2, UDP_MAX_DATAGRAM_SIZE);
974 0 : size = ngx_min(size, UDP_MAX_DATAGRAM_SIZE);
975 :
976 0 : u->recv_buf_size = size;
977 :
978 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
979 : "lua udp socket receive buffer size: %uz", u->recv_buf_size);
980 :
981 0 : rc = ngx_http_lua_socket_udp_read(r, u);
982 :
983 0 : if (rc == NGX_ERROR) {
984 : dd("read failed: %d", (int) u->ft_type);
985 0 : rc = ngx_http_lua_socket_udp_receive_retval_handler(r, u, L);
986 : dd("udp receive retval returned: %d", (int) rc);
987 0 : return rc;
988 : }
989 :
990 0 : if (rc == NGX_OK) {
991 :
992 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
993 : "lua udp socket receive done in a single run");
994 :
995 0 : return ngx_http_lua_socket_udp_receive_retval_handler(r, u, L);
996 : }
997 :
998 : /* n == NGX_AGAIN */
999 :
1000 0 : u->read_event_handler = ngx_http_lua_socket_udp_read_handler;
1001 :
1002 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
1003 0 : if (ctx == NULL) {
1004 0 : return luaL_error(L, "no request ctx found");
1005 : }
1006 :
1007 0 : coctx = ctx->cur_co_ctx;
1008 :
1009 0 : ngx_http_lua_cleanup_pending_operation(coctx);
1010 0 : coctx->cleanup = ngx_http_lua_udp_socket_cleanup;
1011 0 : coctx->data = u;
1012 :
1013 0 : if (ctx->entered_content_phase) {
1014 0 : r->write_event_handler = ngx_http_lua_content_wev_handler;
1015 :
1016 : } else {
1017 0 : r->write_event_handler = ngx_http_core_run_phases;
1018 : }
1019 :
1020 0 : u->co_ctx = coctx;
1021 0 : u->waiting = 1;
1022 0 : u->prepare_retvals = ngx_http_lua_socket_udp_receive_retval_handler;
1023 :
1024 0 : return lua_yield(L, 0);
1025 : }
1026 :
1027 :
1028 : static int
1029 0 : ngx_http_lua_socket_udp_receive_retval_handler(ngx_http_request_t *r,
1030 : ngx_http_lua_socket_udp_upstream_t *u, lua_State *L)
1031 : {
1032 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1033 : "lua udp socket receive return value handler");
1034 :
1035 0 : if (u->ft_type) {
1036 0 : return ngx_http_lua_socket_error_retval_handler(r, u, L);
1037 : }
1038 :
1039 0 : lua_pushlstring(L, (char *) ngx_http_lua_socket_udp_buffer, u->received);
1040 0 : return 1;
1041 : }
1042 :
1043 :
1044 : static int
1045 0 : ngx_http_lua_socket_udp_settimeout(lua_State *L)
1046 : {
1047 : int n;
1048 : ngx_int_t timeout;
1049 :
1050 : ngx_http_lua_socket_udp_upstream_t *u;
1051 :
1052 0 : n = lua_gettop(L);
1053 :
1054 0 : if (n != 2) {
1055 0 : return luaL_error(L, "ngx.socket settimout: expecting at least 2 "
1056 : "arguments (including the object) but seen %d",
1057 : lua_gettop(L));
1058 : }
1059 :
1060 0 : timeout = (ngx_int_t) lua_tonumber(L, 2);
1061 :
1062 0 : lua_rawseti(L, 1, SOCKET_TIMEOUT_INDEX);
1063 :
1064 0 : lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
1065 0 : u = lua_touserdata(L, -1);
1066 :
1067 0 : if (u) {
1068 0 : if (timeout > 0) {
1069 0 : u->read_timeout = (ngx_msec_t) timeout;
1070 :
1071 : } else {
1072 0 : u->read_timeout = u->conf->read_timeout;
1073 : }
1074 : }
1075 :
1076 0 : return 0;
1077 : }
1078 :
1079 :
1080 : static void
1081 0 : ngx_http_lua_socket_udp_finalize(ngx_http_request_t *r,
1082 : ngx_http_lua_socket_udp_upstream_t *u)
1083 : {
1084 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1085 : "lua finalize socket");
1086 :
1087 0 : if (u->cleanup) {
1088 0 : *u->cleanup = NULL;
1089 0 : u->cleanup = NULL;
1090 : }
1091 :
1092 0 : if (u->resolved && u->resolved->ctx) {
1093 0 : ngx_resolve_name_done(u->resolved->ctx);
1094 0 : u->resolved->ctx = NULL;
1095 : }
1096 :
1097 0 : if (u->udp_connection.connection) {
1098 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1099 : "lua close socket connection");
1100 :
1101 0 : ngx_close_connection(u->udp_connection.connection);
1102 0 : u->udp_connection.connection = NULL;
1103 : }
1104 :
1105 0 : if (u->waiting) {
1106 0 : u->waiting = 0;
1107 : }
1108 0 : }
1109 :
1110 :
1111 : static int
1112 0 : ngx_http_lua_socket_udp_upstream_destroy(lua_State *L)
1113 : {
1114 : ngx_http_lua_socket_udp_upstream_t *u;
1115 :
1116 : dd("upstream destroy triggered by Lua GC");
1117 :
1118 0 : u = lua_touserdata(L, 1);
1119 0 : if (u == NULL) {
1120 0 : return 0;
1121 : }
1122 :
1123 0 : if (u->cleanup) {
1124 0 : ngx_http_lua_socket_udp_cleanup(u); /* it will clear u->cleanup */
1125 : }
1126 :
1127 0 : return 0;
1128 : }
1129 :
1130 :
1131 : static void
1132 0 : ngx_http_lua_socket_dummy_handler(ngx_http_request_t *r,
1133 : ngx_http_lua_socket_udp_upstream_t *u)
1134 : {
1135 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1136 : "lua udp socket dummy handler");
1137 0 : }
1138 :
1139 :
1140 : static ngx_int_t
1141 0 : ngx_http_lua_socket_udp_read(ngx_http_request_t *r,
1142 : ngx_http_lua_socket_udp_upstream_t *u)
1143 : {
1144 : ngx_connection_t *c;
1145 : ngx_event_t *rev;
1146 : ssize_t n;
1147 :
1148 0 : c = u->udp_connection.connection;
1149 0 : rev = c->read;
1150 :
1151 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
1152 : "lua udp socket read data: waiting: %d", (int) u->waiting);
1153 :
1154 0 : n = ngx_udp_recv(u->udp_connection.connection,
1155 : ngx_http_lua_socket_udp_buffer, u->recv_buf_size);
1156 :
1157 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
1158 : "lua udp recv returned %z", n);
1159 :
1160 0 : if (n >= 0) {
1161 0 : u->received = n;
1162 0 : ngx_http_lua_socket_udp_handle_success(r, u);
1163 0 : return NGX_OK;
1164 : }
1165 :
1166 0 : if (n == NGX_ERROR) {
1167 0 : u->socket_errno = ngx_socket_errno;
1168 0 : ngx_http_lua_socket_udp_handle_error(r, u,
1169 : NGX_HTTP_LUA_SOCKET_FT_ERROR);
1170 0 : return NGX_ERROR;
1171 : }
1172 :
1173 : /* n == NGX_AGAIN */
1174 :
1175 : #if 1
1176 0 : if (ngx_handle_read_event(rev, 0) != NGX_OK) {
1177 0 : ngx_http_lua_socket_udp_handle_error(r, u,
1178 : NGX_HTTP_LUA_SOCKET_FT_ERROR);
1179 0 : return NGX_ERROR;
1180 : }
1181 : #endif
1182 :
1183 0 : if (rev->active) {
1184 0 : ngx_add_timer(rev, u->read_timeout);
1185 :
1186 0 : } else if (rev->timer_set) {
1187 0 : ngx_del_timer(rev);
1188 : }
1189 :
1190 0 : return NGX_AGAIN;
1191 : }
1192 :
1193 :
1194 : static void
1195 0 : ngx_http_lua_socket_udp_read_handler(ngx_http_request_t *r,
1196 : ngx_http_lua_socket_udp_upstream_t *u)
1197 : {
1198 : ngx_connection_t *c;
1199 : ngx_http_lua_loc_conf_t *llcf;
1200 :
1201 0 : c = u->udp_connection.connection;
1202 :
1203 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1204 : "lua udp socket read handler");
1205 :
1206 0 : if (c->read->timedout) {
1207 0 : c->read->timedout = 0;
1208 :
1209 0 : llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
1210 :
1211 0 : if (llcf->log_socket_errors) {
1212 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1213 : "lua udp socket read timed out");
1214 : }
1215 :
1216 0 : ngx_http_lua_socket_udp_handle_error(r, u,
1217 : NGX_HTTP_LUA_SOCKET_FT_TIMEOUT);
1218 0 : return;
1219 : }
1220 :
1221 : #if 1
1222 0 : if (c->read->timer_set) {
1223 0 : ngx_del_timer(c->read);
1224 : }
1225 : #endif
1226 :
1227 0 : (void) ngx_http_lua_socket_udp_read(r, u);
1228 : }
1229 :
1230 :
1231 : static void
1232 0 : ngx_http_lua_socket_udp_handle_error(ngx_http_request_t *r,
1233 : ngx_http_lua_socket_udp_upstream_t *u, ngx_uint_t ft_type)
1234 : {
1235 : ngx_http_lua_ctx_t *ctx;
1236 : ngx_http_lua_co_ctx_t *coctx;
1237 :
1238 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1239 : "lua udp socket handle error");
1240 :
1241 0 : u->ft_type |= ft_type;
1242 :
1243 : #if 0
1244 : ngx_http_lua_socket_udp_finalize(r, u);
1245 : #endif
1246 :
1247 0 : u->read_event_handler = ngx_http_lua_socket_dummy_handler;
1248 :
1249 0 : coctx = u->co_ctx;
1250 :
1251 0 : if (coctx) {
1252 0 : coctx->cleanup = NULL;
1253 : }
1254 :
1255 0 : if (u->waiting) {
1256 0 : u->waiting = 0;
1257 :
1258 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
1259 0 : if (ctx == NULL) {
1260 0 : return;
1261 : }
1262 :
1263 0 : ctx->resume_handler = ngx_http_lua_socket_udp_resume;
1264 0 : ctx->cur_co_ctx = coctx;
1265 :
1266 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1267 : "lua udp socket waking up the current request");
1268 :
1269 0 : r->write_event_handler(r);
1270 : }
1271 : }
1272 :
1273 :
1274 : static void
1275 0 : ngx_http_lua_socket_udp_cleanup(void *data)
1276 : {
1277 0 : ngx_http_lua_socket_udp_upstream_t *u = data;
1278 :
1279 : ngx_http_request_t *r;
1280 :
1281 0 : r = u->request;
1282 :
1283 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1284 : "cleanup lua udp socket upstream request: \"%V\"", &r->uri);
1285 :
1286 0 : ngx_http_lua_socket_udp_finalize(r, u);
1287 0 : }
1288 :
1289 :
1290 : static void
1291 0 : ngx_http_lua_socket_udp_handler(ngx_event_t *ev)
1292 : {
1293 : ngx_connection_t *c;
1294 : ngx_http_request_t *r;
1295 : ngx_http_log_ctx_t *ctx;
1296 :
1297 : ngx_http_lua_socket_udp_upstream_t *u;
1298 :
1299 0 : c = ev->data;
1300 0 : u = c->data;
1301 0 : r = u->request;
1302 0 : c = r->connection;
1303 :
1304 0 : if (c->fd != (ngx_socket_t) -1) { /* not a fake connection */
1305 0 : ctx = c->log->data;
1306 0 : ctx->current_request = r;
1307 : }
1308 :
1309 0 : ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
1310 : "lua udp socket handler for \"%V?%V\", wev %d", &r->uri,
1311 : &r->args, (int) ev->write);
1312 :
1313 0 : u->read_event_handler(r, u);
1314 :
1315 0 : ngx_http_run_posted_requests(c);
1316 0 : }
1317 :
1318 :
1319 : static void
1320 0 : ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r,
1321 : ngx_http_lua_socket_udp_upstream_t *u)
1322 : {
1323 : ngx_http_lua_ctx_t *ctx;
1324 :
1325 0 : u->read_event_handler = ngx_http_lua_socket_dummy_handler;
1326 :
1327 0 : if (u->co_ctx) {
1328 0 : u->co_ctx->cleanup = NULL;
1329 : }
1330 :
1331 0 : if (u->waiting) {
1332 0 : u->waiting = 0;
1333 :
1334 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
1335 0 : if (ctx == NULL) {
1336 0 : return;
1337 : }
1338 :
1339 0 : ctx->resume_handler = ngx_http_lua_socket_udp_resume;
1340 0 : ctx->cur_co_ctx = u->co_ctx;
1341 :
1342 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1343 : "lua udp socket waking up the current request");
1344 :
1345 0 : r->write_event_handler(r);
1346 : }
1347 : }
1348 :
1349 :
1350 : static ngx_int_t
1351 0 : ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc)
1352 : {
1353 : int rc;
1354 : ngx_int_t event;
1355 : ngx_event_t *rev, *wev;
1356 : ngx_socket_t s;
1357 : ngx_connection_t *c;
1358 :
1359 0 : s = ngx_socket(uc->sockaddr->sa_family, SOCK_DGRAM, 0);
1360 :
1361 0 : ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "UDP socket %d", s);
1362 :
1363 0 : if (s == (ngx_socket_t) -1) {
1364 0 : ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
1365 : ngx_socket_n " failed");
1366 :
1367 0 : return NGX_ERROR;
1368 : }
1369 :
1370 0 : c = ngx_get_connection(s, &uc->log);
1371 :
1372 0 : if (c == NULL) {
1373 0 : if (ngx_close_socket(s) == -1) {
1374 0 : ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
1375 : ngx_close_socket_n "failed");
1376 : }
1377 :
1378 0 : return NGX_ERROR;
1379 : }
1380 :
1381 0 : if (ngx_nonblocking(s) == -1) {
1382 0 : ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
1383 : ngx_nonblocking_n " failed");
1384 :
1385 0 : ngx_free_connection(c);
1386 :
1387 0 : if (ngx_close_socket(s) == -1) {
1388 0 : ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
1389 : ngx_close_socket_n " failed");
1390 : }
1391 :
1392 0 : return NGX_ERROR;
1393 : }
1394 :
1395 0 : rev = c->read;
1396 0 : wev = c->write;
1397 :
1398 0 : rev->log = &uc->log;
1399 0 : wev->log = &uc->log;
1400 :
1401 0 : uc->connection = c;
1402 :
1403 0 : c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
1404 :
1405 : #if (NGX_HTTP_LUA_HAVE_SO_PASSCRED)
1406 0 : if (uc->sockaddr->sa_family == AF_UNIX) {
1407 : struct sockaddr addr;
1408 :
1409 0 : addr.sa_family = AF_UNIX;
1410 :
1411 : /* just to make valgrind happy */
1412 0 : ngx_memzero(addr.sa_data, sizeof(addr.sa_data));
1413 :
1414 0 : ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "datagram unix "
1415 : "domain socket autobind");
1416 :
1417 0 : if (bind(uc->connection->fd, &addr, sizeof(sa_family_t)) != 0) {
1418 0 : ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno,
1419 : "bind() failed");
1420 :
1421 0 : return NGX_ERROR;
1422 : }
1423 : }
1424 : #endif
1425 :
1426 0 : ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0,
1427 : "connect to %V, fd:%d #%d", &uc->server, s, c->number);
1428 :
1429 0 : rc = connect(s, uc->sockaddr, uc->socklen);
1430 :
1431 : /* TODO: aio, iocp */
1432 :
1433 0 : if (rc == -1) {
1434 0 : ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno,
1435 : "connect() failed");
1436 :
1437 0 : return NGX_ERROR;
1438 : }
1439 :
1440 : /* UDP sockets are always ready to write */
1441 0 : wev->ready = 1;
1442 :
1443 0 : if (ngx_add_event) {
1444 :
1445 0 : event = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ?
1446 0 : /* kqueue, epoll */ NGX_CLEAR_EVENT:
1447 : /* select, poll, /dev/poll */ NGX_LEVEL_EVENT;
1448 : /* eventport event type has no meaning: oneshot only */
1449 :
1450 0 : if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
1451 0 : return NGX_ERROR;
1452 : }
1453 :
1454 : } else {
1455 : /* rtsig */
1456 :
1457 0 : if (ngx_add_conn(c) == NGX_ERROR) {
1458 0 : return NGX_ERROR;
1459 : }
1460 : }
1461 :
1462 0 : return NGX_OK;
1463 : }
1464 :
1465 :
1466 : static int
1467 0 : ngx_http_lua_socket_udp_close(lua_State *L)
1468 : {
1469 : ngx_http_request_t *r;
1470 : ngx_http_lua_socket_udp_upstream_t *u;
1471 :
1472 0 : if (lua_gettop(L) != 1) {
1473 0 : return luaL_error(L, "expecting 1 argument "
1474 : "(including the object) but seen %d", lua_gettop(L));
1475 : }
1476 :
1477 0 : r = ngx_http_lua_get_req(L);
1478 0 : if (r == NULL) {
1479 0 : return luaL_error(L, "no request found");
1480 : }
1481 :
1482 0 : luaL_checktype(L, 1, LUA_TTABLE);
1483 :
1484 0 : lua_rawgeti(L, 1, SOCKET_CTX_INDEX);
1485 0 : u = lua_touserdata(L, -1);
1486 0 : lua_pop(L, 1);
1487 :
1488 0 : if (u == NULL || u->udp_connection.connection == NULL) {
1489 0 : lua_pushnil(L);
1490 0 : lua_pushliteral(L, "closed");
1491 0 : return 2;
1492 : }
1493 :
1494 0 : if (u->request != r) {
1495 0 : return luaL_error(L, "bad request");
1496 : }
1497 :
1498 0 : if (u->waiting) {
1499 0 : lua_pushnil(L);
1500 0 : lua_pushliteral(L, "socket busy");
1501 0 : return 2;
1502 : }
1503 :
1504 0 : ngx_http_lua_socket_udp_finalize(r, u);
1505 :
1506 0 : lua_pushinteger(L, 1);
1507 0 : return 1;
1508 : }
1509 :
1510 :
1511 : static ngx_int_t
1512 0 : ngx_http_lua_socket_udp_resume(ngx_http_request_t *r)
1513 : {
1514 : int nret;
1515 : lua_State *vm;
1516 : ngx_int_t rc;
1517 : ngx_uint_t nreqs;
1518 : ngx_connection_t *c;
1519 : ngx_http_lua_ctx_t *ctx;
1520 : ngx_http_lua_co_ctx_t *coctx;
1521 :
1522 : ngx_http_lua_socket_udp_upstream_t *u;
1523 :
1524 0 : ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
1525 0 : if (ctx == NULL) {
1526 0 : return NGX_ERROR;
1527 : }
1528 :
1529 0 : ctx->resume_handler = ngx_http_lua_wev_handler;
1530 :
1531 0 : ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1532 : "lua udp operation done, resuming lua thread");
1533 :
1534 0 : coctx = ctx->cur_co_ctx;
1535 :
1536 : #if 0
1537 : ngx_http_lua_probe_info("udp resume");
1538 : #endif
1539 :
1540 0 : u = coctx->data;
1541 :
1542 0 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1543 : "lua udp socket calling prepare retvals handler %p, "
1544 : "u:%p", u->prepare_retvals, u);
1545 :
1546 0 : nret = u->prepare_retvals(r, u, ctx->cur_co_ctx->co);
1547 0 : if (nret == NGX_AGAIN) {
1548 0 : return NGX_DONE;
1549 : }
1550 :
1551 0 : c = r->connection;
1552 0 : vm = ngx_http_lua_get_lua_vm(r, ctx);
1553 0 : nreqs = c->requests;
1554 :
1555 0 : rc = ngx_http_lua_run_thread(vm, r, ctx, nret);
1556 :
1557 0 : ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1558 : "lua run thread returned %d", rc);
1559 :
1560 0 : if (rc == NGX_AGAIN) {
1561 0 : return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
1562 : }
1563 :
1564 0 : if (rc == NGX_DONE) {
1565 0 : ngx_http_lua_finalize_request(r, NGX_DONE);
1566 0 : return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
1567 : }
1568 :
1569 0 : if (ctx->entered_content_phase) {
1570 0 : ngx_http_lua_finalize_request(r, rc);
1571 0 : return NGX_DONE;
1572 : }
1573 :
1574 0 : return rc;
1575 : }
1576 :
1577 :
1578 : static void
1579 0 : ngx_http_lua_udp_resolve_cleanup(void *data)
1580 : {
1581 : ngx_resolver_ctx_t *rctx;
1582 : ngx_http_lua_socket_udp_upstream_t *u;
1583 0 : ngx_http_lua_co_ctx_t *coctx = data;
1584 :
1585 0 : u = coctx->data;
1586 0 : if (u == NULL) {
1587 0 : return;
1588 : }
1589 :
1590 0 : rctx = u->resolved->ctx;
1591 0 : if (rctx == NULL) {
1592 0 : return;
1593 : }
1594 :
1595 0 : ngx_resolve_name_done(rctx);
1596 : }
1597 :
1598 :
1599 : static void
1600 0 : ngx_http_lua_udp_socket_cleanup(void *data)
1601 : {
1602 : ngx_http_lua_socket_udp_upstream_t *u;
1603 0 : ngx_http_lua_co_ctx_t *coctx = data;
1604 :
1605 0 : u = coctx->data;
1606 0 : if (u == NULL) {
1607 0 : return;
1608 : }
1609 :
1610 0 : if (u->request == NULL) {
1611 0 : return;
1612 : }
1613 :
1614 0 : ngx_http_lua_socket_udp_finalize(u->request, u);
1615 : }
1616 :
1617 : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|