LCOV - code coverage report
Current view: top level - home/build/openresty-1.13.6.1/build/ngx_lua-0.10.11/src - ngx_http_lua_socket_udp.c (source / functions) Hit Total Coverage
Test: coverage ngix Lines: 26 659 3.9 %
Date: 2020-03-03 04:25:50 Functions: 1 24 4.2 %
Legend: Lines: hit not hit

          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: */

Generated by: LCOV version 1.13