From 53d482d7ea797c5cb2359eb408572b31340f6a9a Mon Sep 17 00:00:00 2001 From: xuhui Date: Thu, 18 Feb 2016 17:48:50 +0800 Subject: [PATCH 1/9] feature: added new API bind. optimize: palloc instead of pcalloc. bugfix: fixed alloc 'ngx_addr_t', not reference it. change: modified some logging code. feature: added test cases for tcp bind. (squash by doujiang24) --- src/ngx_http_lua_socket_tcp.c | 91 +++++++++- src/ngx_http_lua_socket_tcp.h | 1 + src/ngx_http_lua_socket_udp.c | 36 +++- t/141-tcp-socket-bind.t | 302 ++++++++++++++++++++++++++++++++++ 4 files changed, 423 insertions(+), 7 deletions(-) create mode 100644 t/141-tcp-socket-bind.t diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 1a6594d168..1170716bf9 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -19,6 +19,7 @@ static int ngx_http_lua_socket_tcp(lua_State *L); +static int ngx_http_lua_socket_tcp_bind(lua_State *L); static int ngx_http_lua_socket_tcp_connect(lua_State *L); #if (NGX_HTTP_SSL) static int ngx_http_lua_socket_tcp_sslhandshake(lua_State *L); @@ -138,7 +139,8 @@ static void ngx_http_lua_socket_tcp_close_connection(ngx_connection_t *c); enum { SOCKET_CTX_INDEX = 1, SOCKET_TIMEOUT_INDEX = 2, - SOCKET_KEY_INDEX = 3 + SOCKET_KEY_INDEX = 3, + SOCKET_BIND_IP_INDEX = 4 }; @@ -266,7 +268,10 @@ ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* {{{tcp object metatable */ lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); - lua_createtable(L, 0 /* narr */, 11 /* nrec */); + lua_createtable(L, 0 /* narr */, 12 /* nrec */); + + lua_pushcfunction(L, ngx_http_lua_socket_tcp_bind); + lua_setfield(L, -2, "bind"); lua_pushcfunction(L, ngx_http_lua_socket_tcp_connect); lua_setfield(L, -2, "connect"); @@ -399,6 +404,74 @@ ngx_http_lua_socket_tcp(lua_State *L) } +int +ngx_http_lua_socket_bind_ip(lua_State *L, int index) +{ + ngx_http_request_t *r; + int n; + u_char *ip; + size_t len; + + ngx_addr_t *local; + + n = lua_gettop(L); + + if (n != 2) { + return luaL_error(L, "ngx.socket bind: expecting at least 2 " + "arguments (including the object) but seen %d", + lua_gettop(L)); + } + + r = ngx_http_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request found"); + } + + luaL_checktype(L, 1, LUA_TTABLE); + + ip = (u_char *) luaL_checklstring(L, 2, &len); + + lua_rawgeti(L, 1, index); + local = lua_touserdata(L, -1); + lua_pop(L, 1); + + if (local == NULL) { + local = lua_newuserdata(L, sizeof(ngx_addr_t)); + if (local == NULL) { + return luaL_error(L, "no memory"); + } + + lua_rawseti(L, 1, index); + } + + if (ngx_parse_addr(r->pool, local, ip, len) != NGX_OK) { + lua_pushnil(L); + lua_pushfstring(L, "bad ip: %s", ip); + return 2; + } + + local->name.data = ngx_palloc(r->pool, len); + if (local->name.data == NULL) { + return luaL_error(L, "no memory"); + } + + local->name.len = len; + ngx_memcpy(local->name.data, ip, len); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket bind ip: %V", &local->name); + + lua_pushinteger(L, 1); + return 1; +} + + +static int +ngx_http_lua_socket_tcp_bind(lua_State *L) +{ + return ngx_http_lua_socket_bind_ip(L, SOCKET_BIND_IP_INDEX); +} + + static int ngx_http_lua_socket_tcp_connect(lua_State *L) { @@ -416,6 +489,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) ngx_int_t rc; ngx_http_lua_loc_conf_t *llcf; ngx_peer_connection_t *pc; + ngx_addr_t *local; int timeout; unsigned custom_pool; int key_index; @@ -574,6 +648,19 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) dd("lua peer connection log: %p", pc->log); + lua_rawgeti(L, 1, SOCKET_BIND_IP_INDEX); + local = lua_touserdata(L, -1); + lua_pop(L, 1); + + if (local) { + u->peer.local = ngx_palloc(r->pool, sizeof(ngx_addr_t)); + if (u->peer.local == NULL) { + return luaL_error(L, "no memory"); + } + + ngx_memcpy(u->peer.local, local, sizeof(ngx_addr_t)); + } + lua_rawgeti(L, 1, SOCKET_TIMEOUT_INDEX); timeout = (ngx_int_t) lua_tointeger(L, -1); lua_pop(L, 1); diff --git a/src/ngx_http_lua_socket_tcp.h b/src/ngx_http_lua_socket_tcp.h index dbdee41c6e..81275bdd1d 100644 --- a/src/ngx_http_lua_socket_tcp.h +++ b/src/ngx_http_lua_socket_tcp.h @@ -149,6 +149,7 @@ typedef struct { void ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L); void ngx_http_lua_inject_req_socket_api(lua_State *L); void ngx_http_lua_cleanup_conn_pools(lua_State *L); +int ngx_http_lua_socket_bind_ip(lua_State *L, int index); #endif /* _NGX_HTTP_LUA_SOCKET_TCP_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 1ec0c00a0f..697fd83b17 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -28,6 +28,7 @@ static int ngx_http_lua_socket_udp(lua_State *L); +static int ngx_http_lua_socket_udp_bind(lua_State *L); static int ngx_http_lua_socket_udp_setpeername(lua_State *L); static int ngx_http_lua_socket_udp_send(lua_State *L); static int ngx_http_lua_socket_udp_receive(lua_State *L); @@ -54,7 +55,7 @@ static void ngx_http_lua_socket_udp_read_handler(ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); static void ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); -static ngx_int_t ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc); +static ngx_int_t ngx_http_lua_udp_connect(lua_State *L, ngx_udp_connection_t *uc); static int ngx_http_lua_socket_udp_close(lua_State *L); static ngx_int_t ngx_http_lua_socket_udp_resume(ngx_http_request_t *r); static void ngx_http_lua_udp_resolve_cleanup(void *data); @@ -63,7 +64,8 @@ static void ngx_http_lua_udp_socket_cleanup(void *data); enum { SOCKET_CTX_INDEX = 1, - SOCKET_TIMEOUT_INDEX = 2 + SOCKET_TIMEOUT_INDEX = 2, + SOCKET_BIND_IP_INDEX = 3 }; @@ -82,7 +84,10 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) /* udp socket object metatable */ lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); - lua_createtable(L, 0 /* narr */, 6 /* nrec */); + lua_createtable(L, 0 /* narr */, 7 /* nrec */); + + lua_pushcfunction(L, ngx_http_lua_socket_udp_bind); + lua_setfield(L, -2, "bind"); lua_pushcfunction(L, ngx_http_lua_socket_udp_setpeername); lua_setfield(L, -2, "setpeername"); /* ngx socket mt */ @@ -154,6 +159,13 @@ ngx_http_lua_socket_udp(lua_State *L) } +static int +ngx_http_lua_socket_udp_bind(lua_State *L) +{ + return ngx_http_lua_socket_bind_ip(L, SOCKET_BIND_IP_INDEX); +} + + static int ngx_http_lua_socket_udp_setpeername(lua_State *L) { @@ -670,7 +682,7 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, return 2; } - rc = ngx_http_lua_udp_connect(uc); + rc = ngx_http_lua_udp_connect(L, uc); if (rc != NGX_OK) { u->socket_errno = ngx_socket_errno; @@ -1348,11 +1360,12 @@ ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, static ngx_int_t -ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc) +ngx_http_lua_udp_connect(lua_State *L, ngx_udp_connection_t *uc) { int rc; ngx_int_t event; ngx_event_t *rev, *wev; + ngx_addr_t *local; ngx_socket_t s; ngx_connection_t *c; @@ -1422,6 +1435,19 @@ ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc) } } #endif + + lua_rawgeti(L, 1, SOCKET_BIND_IP_INDEX); + local = lua_touserdata(L, -1); + lua_pop(L, 1); + + if (local && (uc->sockaddr->sa_family == AF_INET + || uc->sockaddr->sa_family == AF_INET6)) { + if (bind(uc->connection->fd, local->sockaddr, local->socklen) != 0) { + ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, + "bind (%V) failed", &local->name); + return NGX_ERROR; + } + } ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "connect to %V, fd:%d #%d", &uc->server, s, c->number); diff --git a/t/141-tcp-socket-bind.t b/t/141-tcp-socket-bind.t new file mode 100644 index 0000000000..84e321dbae --- /dev/null +++ b/t/141-tcp-socket-bind.t @@ -0,0 +1,302 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 5 + 7); + +our $HtmlDir = html_dir; + +$ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; +$ENV{TEST_NOT_EXIST_IP} ||= '8.8.8.8'; +$ENV{TEST_INVALID_IP} ||= '127.0.0.1:8899'; + +$ENV{LUA_PATH} ||= + '/usr/local/openresty-debug/lualib/?.lua;/usr/local/openresty/lualib/?.lua;;'; + +no_long_string(); +#no_diff(); + +#log_level 'warn'; +log_level 'debug'; + +no_shuffle(); + +run_tests(); + +__DATA__ + +=== TEST 1: upstream sockets bind 127.0.0.1 +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua ' + local ip = "127.0.0.1" + local port = ngx.var.port + + local sock = ngx.socket.tcp() + local ok, err = sock:bind(ip) + if not ok then + ngx.say("failed to bind", err) + return + end + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local bytes, err = sock:send("GET /foo HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: keepalive\\r\\n\\r\\n") + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + ngx.say("request sent") + + local reader = sock:receiveuntil("\\r\\n0\\r\\n\\r\\n") + local data, err = reader() + + if not data then + ngx.say("failed to receive response body: ", err) + return + end + + ngx.say("received response") + local remote_ip = string.match(data, "(bind: %d+%.%d+%.%d+%.%d+)") + ngx.say(remote_ip) + + ngx.location.capture("/sleep") + + ngx.say("done") + '; + } + + location /foo { + echo bind: $remote_addr + } + + location /sleep { + echo_sleep 1; + } +--- request +GET /t +--- response_body +connected: 1 +request sent +received response +bind: 127.0.0.1 +done +--- no_error_log +["[error]", +"bind(127.0.0.1) failed"] +--- error_log eval +"lua tcp socket bind ip: 127.0.0.1" + + + +=== TEST 2: upstream sockets bind server ip, not 127.0.0.1 +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua ' + local ip = $TEST_NGINX_SERVER_IP + local port = ngx.var.port + + local sock = ngx.socket.tcp() + local ok, err = sock:bind(ip) + if not ok then + ngx.say("failed to bind", err) + return + end + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local bytes, err = sock:send("GET /foo HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: keepalive\\r\\n\\r\\n") + if not bytes then + ngx.say("failed to send request: ", err) + return + end + + ngx.say("request sent") + + local reader = sock:receiveuntil("\\r\\n0\\r\\n\\r\\n") + local data, err = reader() + + if not data then + ngx.say("failed to receive response body: ", err) + return + end + + ngx.say("received response") + local remote_ip = string.match(data, "(bind: %d+%.%d+%.%d+%.%d+)") + ngx.say(remote_ip) + + ngx.location.capture("/sleep") + + ngx.say("done") + '; + } + + location /foo { + echo bind: $remote_addr + } + location /sleep { + echo_sleep 1; + } +--- request +GET /t +--- response_body +connected: 1 +request sent +received response +bind: $ENV{TEST_NGINX_SERVER_IP} +done +--- no_error_log +["[error]", +"bind(127.0.0.1) failed"] +--- error_log eval +"lua tcp socket bind ip: $ENV{TEST_NGINX_SERVER_IP}" + + + +=== TEST 3: add setkeepalive +--- http_config eval + "lua_package_path '$::HtmlDir/?.lua;./?.lua';" +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua ' + local test = require "test" + test.go() + test.go() + '; + } +--- user_files +>>> test.lua +module("test", package.seeall) + +function go() + local ip = "127.0.0.1" + local port = ngx.var.port + + local sock = ngx.socket.tcp() + local ok, err = sock:bind(ip) + if not ok then + ngx.say("failed to bind", err) + return + end + + ngx.say("bind: ", ip) + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) + + local ok, err = sock:setkeepalive() + if not ok then + ngx.say("failed to set reusable: ", err) + end +end +--- request +GET /t +--- response_body +bind: 127.0.0.1 +connected: 1 +bind: 127.0.0.1 +connected: 1 +--- no_error_log +["[error]", +"bind(127.0.0.1) failed"] +--- error_log eval +"lua tcp socket bind ip: 127.0.0.1" + + + +=== TEST 4: upstream sockets bind not exist ip +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua ' + local ip = $TEST_NOT_EXIST_IP + local port = ngx.var.port + + local sock = ngx.socket.tcp() + local ok, err = sock:bind(ip) + if not ok then + ngx.say("failed to bind", err) + return + end + + ngx.say("bind: ", ip) + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + '; + } +--- request +GET /t +--- response_body +bind: 8.8.8.8 +failed to connect: cannot assign requested address +--- error_log +["bind(8.8.8.8) failed", +"lua tcp socket bind ip: 8.8.8.8" + + + +=== TEST 5: upstream sockets bind invalid ip +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua ' + local ip = $TEST_INVALID_IP + local port = ngx.var.port + + local sock = ngx.socket.tcp() + local ok, err = sock:bind(ip) + if not ok then + ngx.say("failed to bind: ", err) + return + end + + ngx.say("bind: ", ip) + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + '; + } +--- request +GET /t +--- response_body +failed to bind: bad ip: "127.0.0.1:8899" + From b10befd9fd4d2e93248eacfea21a4a689dcb84df Mon Sep 17 00:00:00 2001 From: doujiang24 Date: Thu, 17 Mar 2016 16:30:37 +0800 Subject: [PATCH 2/9] make test cases runable --- t/141-tcp-socket-bind.t | 89 +++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/t/141-tcp-socket-bind.t b/t/141-tcp-socket-bind.t index 84e321dbae..961e09c9af 100644 --- a/t/141-tcp-socket-bind.t +++ b/t/141-tcp-socket-bind.t @@ -4,13 +4,14 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 5 + 7); +plan tests => repeat_each() * (blocks() * 3 + 7); our $HtmlDir = html_dir; $ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; -$ENV{TEST_NOT_EXIST_IP} ||= '8.8.8.8'; -$ENV{TEST_INVALID_IP} ||= '127.0.0.1:8899'; +$ENV{TEST_NGINX_NOT_EXIST_IP} ||= '8.8.8.8'; +$ENV{TEST_NGINX_INVALID_IP} ||= '127.0.0.1:8899'; +$ENV{TEST_NGINX_SERVER_IP} = '172.17.11.75'; # need to fix $ENV{LUA_PATH} ||= '/usr/local/openresty-debug/lualib/?.lua;/usr/local/openresty/lualib/?.lua;;'; @@ -32,7 +33,7 @@ __DATA__ server_tokens off; location /t { set $port $TEST_NGINX_SERVER_PORT; - content_by_lua ' + content_by_lua_block { local ip = "127.0.0.1" local port = ngx.var.port @@ -51,7 +52,7 @@ __DATA__ ngx.say("connected: ", ok) - local bytes, err = sock:send("GET /foo HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: keepalive\\r\\n\\r\\n") + local bytes, err = sock:send("GET /foo HTTP/1.1\r\nHost: localhost\r\nConnection: keepalive\r\n\r\n") if not bytes then ngx.say("failed to send request: ", err) return @@ -59,7 +60,7 @@ __DATA__ ngx.say("request sent") - local reader = sock:receiveuntil("\\r\\n0\\r\\n\\r\\n") + local reader = sock:receiveuntil("\r\n0\r\n\r\n") local data, err = reader() if not data then @@ -71,18 +72,12 @@ __DATA__ local remote_ip = string.match(data, "(bind: %d+%.%d+%.%d+%.%d+)") ngx.say(remote_ip) - ngx.location.capture("/sleep") - ngx.say("done") - '; + } } location /foo { - echo bind: $remote_addr - } - - location /sleep { - echo_sleep 1; + echo bind: $remote_addr; } --- request GET /t @@ -105,8 +100,8 @@ done server_tokens off; location /t { set $port $TEST_NGINX_SERVER_PORT; - content_by_lua ' - local ip = $TEST_NGINX_SERVER_IP + content_by_lua_block { + local ip = "$TEST_NGINX_SERVER_IP" local port = ngx.var.port local sock = ngx.socket.tcp() @@ -124,7 +119,7 @@ done ngx.say("connected: ", ok) - local bytes, err = sock:send("GET /foo HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: keepalive\\r\\n\\r\\n") + local bytes, err = sock:send("GET /foo HTTP/1.1\r\nHost: localhost\r\nConnection: keepalive\r\n\r\n") if not bytes then ngx.say("failed to send request: ", err) return @@ -132,7 +127,7 @@ done ngx.say("request sent") - local reader = sock:receiveuntil("\\r\\n0\\r\\n\\r\\n") + local reader = sock:receiveuntil("\r\n0\r\n\r\n") local data, err = reader() if not data then @@ -142,19 +137,16 @@ done ngx.say("received response") local remote_ip = string.match(data, "(bind: %d+%.%d+%.%d+%.%d+)") - ngx.say(remote_ip) - - ngx.location.capture("/sleep") + if remote_ip == "bind: $TEST_NGINX_SERVER_IP" then + ngx.say("ip matched") + end ngx.say("done") - '; + } } location /foo { - echo bind: $remote_addr - } - location /sleep { - echo_sleep 1; + echo bind: $remote_addr; } --- request GET /t @@ -162,7 +154,7 @@ GET /t connected: 1 request sent received response -bind: $ENV{TEST_NGINX_SERVER_IP} +ip matched done --- no_error_log ["[error]", @@ -179,17 +171,18 @@ done server_tokens off; location /t { set $port $TEST_NGINX_SERVER_PORT; - content_by_lua ' + content_by_lua_block { local test = require "test" - test.go() - test.go() - '; + local t1 = test.go() + local t2 = test.go() + ngx.say("t2 - t1: ", t2 - t1) + } } --- user_files >>> test.lua -module("test", package.seeall) +local _M = {} -function go() +function _M.go() local ip = "127.0.0.1" local port = ngx.var.port @@ -208,13 +201,19 @@ function go() return end - ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) + ngx.say("connected: ", ok) + + local reused = sock:getreusedtimes() local ok, err = sock:setkeepalive() if not ok then ngx.say("failed to set reusable: ", err) end + + return reused end + +return _M --- request GET /t --- response_body @@ -222,6 +221,7 @@ bind: 127.0.0.1 connected: 1 bind: 127.0.0.1 connected: 1 +t2 - t1: 1 --- no_error_log ["[error]", "bind(127.0.0.1) failed"] @@ -235,8 +235,8 @@ connected: 1 server_tokens off; location /t { set $port $TEST_NGINX_SERVER_PORT; - content_by_lua ' - local ip = $TEST_NOT_EXIST_IP + content_by_lua_block { + local ip = "$TEST_NGINX_NOT_EXIST_IP" local port = ngx.var.port local sock = ngx.socket.tcp() @@ -255,16 +255,16 @@ connected: 1 end ngx.say("connected: ", ok) - '; + } } --- request GET /t --- response_body bind: 8.8.8.8 failed to connect: cannot assign requested address ---- error_log +--- error_log eval ["bind(8.8.8.8) failed", -"lua tcp socket bind ip: 8.8.8.8" +"lua tcp socket bind ip: 8.8.8.8"] @@ -273,8 +273,8 @@ failed to connect: cannot assign requested address server_tokens off; location /t { set $port $TEST_NGINX_SERVER_PORT; - content_by_lua ' - local ip = $TEST_INVALID_IP + content_by_lua_block { + local ip = "$TEST_NGINX_INVALID_IP" local port = ngx.var.port local sock = ngx.socket.tcp() @@ -293,10 +293,11 @@ failed to connect: cannot assign requested address end ngx.say("connected: ", ok) - '; + } } --- request GET /t --- response_body -failed to bind: bad ip: "127.0.0.1:8899" - +failed to bind: bad ip: 127.0.0.1:8899 +--- no_error_log +[error] From 81398e3e71e0b9eb3fccafa39208c2deef8dd711 Mon Sep 17 00:00:00 2001 From: doujiang24 Date: Thu, 17 Mar 2016 16:37:26 +0800 Subject: [PATCH 3/9] just some style fix --- src/ngx_http_lua_socket_tcp.c | 4 ++-- src/ngx_http_lua_socket_udp.c | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 1170716bf9..1b90b44513 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -434,7 +434,7 @@ ngx_http_lua_socket_bind_ip(lua_State *L, int index) lua_rawgeti(L, 1, index); local = lua_touserdata(L, -1); lua_pop(L, 1); - + if (local == NULL) { local = lua_newuserdata(L, sizeof(ngx_addr_t)); if (local == NULL) { @@ -443,7 +443,7 @@ ngx_http_lua_socket_bind_ip(lua_State *L, int index) lua_rawseti(L, 1, index); } - + if (ngx_parse_addr(r->pool, local, ip, len) != NGX_OK) { lua_pushnil(L); lua_pushfstring(L, "bad ip: %s", ip); diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 697fd83b17..f915926d26 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -55,7 +55,8 @@ static void ngx_http_lua_socket_udp_read_handler(ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); static void ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); -static ngx_int_t ngx_http_lua_udp_connect(lua_State *L, ngx_udp_connection_t *uc); +static ngx_int_t ngx_http_lua_udp_connect(lua_State *L, + ngx_udp_connection_t *uc); static int ngx_http_lua_socket_udp_close(lua_State *L); static ngx_int_t ngx_http_lua_socket_udp_resume(ngx_http_request_t *r); static void ngx_http_lua_udp_resolve_cleanup(void *data); @@ -87,7 +88,7 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) lua_createtable(L, 0 /* narr */, 7 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_udp_bind); - lua_setfield(L, -2, "bind"); + lua_setfield(L, -2, "bind"); lua_pushcfunction(L, ngx_http_lua_socket_udp_setpeername); lua_setfield(L, -2, "setpeername"); /* ngx socket mt */ @@ -1435,13 +1436,14 @@ ngx_http_lua_udp_connect(lua_State *L, ngx_udp_connection_t *uc) } } #endif - + lua_rawgeti(L, 1, SOCKET_BIND_IP_INDEX); local = lua_touserdata(L, -1); lua_pop(L, 1); - if (local && (uc->sockaddr->sa_family == AF_INET - || uc->sockaddr->sa_family == AF_INET6)) { + if (local && (uc->sockaddr->sa_family == AF_INET + || uc->sockaddr->sa_family == AF_INET6)) + { if (bind(uc->connection->fd, local->sockaddr, local->socklen) != 0) { ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, "bind (%V) failed", &local->name); From d4338b7dc2f53868fb8dc0f1801f2d6ddab45529 Mon Sep 17 00:00:00 2001 From: doujiang24 Date: Thu, 17 Mar 2016 17:28:25 +0800 Subject: [PATCH 4/9] some code optimize --- src/ngx_http_lua_socket_tcp.c | 34 ++++++++++++++++++++-------------- src/ngx_http_lua_socket_tcp.h | 2 +- src/ngx_http_lua_socket_udp.c | 10 +++++----- t/141-tcp-socket-bind.t | 2 +- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 1b90b44513..9b181b78be 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -140,7 +140,7 @@ enum { SOCKET_CTX_INDEX = 1, SOCKET_TIMEOUT_INDEX = 2, SOCKET_KEY_INDEX = 3, - SOCKET_BIND_IP_INDEX = 4 + SOCKET_BIND_INDEX = 4 }; @@ -405,20 +405,19 @@ ngx_http_lua_socket_tcp(lua_State *L) int -ngx_http_lua_socket_bind_ip(lua_State *L, int index) +ngx_http_lua_socket_bind(lua_State *L, int index) { ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; int n; u_char *ip; size_t len; - ngx_addr_t *local; n = lua_gettop(L); if (n != 2) { - return luaL_error(L, "ngx.socket bind: expecting at least 2 " - "arguments (including the object) but seen %d", + return luaL_error(L, "expecting 2 arguments, but got %d", lua_gettop(L)); } @@ -427,6 +426,17 @@ ngx_http_lua_socket_bind_ip(lua_State *L, int index) return luaL_error(L, "no request found"); } + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no ctx found"); + } + + ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE + | NGX_HTTP_LUA_CONTEXT_ACCESS + | NGX_HTTP_LUA_CONTEXT_CONTENT + | NGX_HTTP_LUA_CONTEXT_TIMER + | NGX_HTTP_LUA_CONTEXT_SSL_CERT); + luaL_checktype(L, 1, LUA_TTABLE); ip = (u_char *) luaL_checklstring(L, 2, &len); @@ -446,7 +456,7 @@ ngx_http_lua_socket_bind_ip(lua_State *L, int index) if (ngx_parse_addr(r->pool, local, ip, len) != NGX_OK) { lua_pushnil(L); - lua_pushfstring(L, "bad ip: %s", ip); + lua_pushfstring(L, "bad address"); return 2; } @@ -457,6 +467,7 @@ ngx_http_lua_socket_bind_ip(lua_State *L, int index) local->name.len = len; ngx_memcpy(local->name.data, ip, len); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket bind ip: %V", &local->name); @@ -468,7 +479,7 @@ ngx_http_lua_socket_bind_ip(lua_State *L, int index) static int ngx_http_lua_socket_tcp_bind(lua_State *L) { - return ngx_http_lua_socket_bind_ip(L, SOCKET_BIND_IP_INDEX); + return ngx_http_lua_socket_bind(L, SOCKET_BIND_INDEX); } @@ -648,17 +659,12 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) dd("lua peer connection log: %p", pc->log); - lua_rawgeti(L, 1, SOCKET_BIND_IP_INDEX); + lua_rawgeti(L, 1, SOCKET_BIND_INDEX); local = lua_touserdata(L, -1); lua_pop(L, 1); if (local) { - u->peer.local = ngx_palloc(r->pool, sizeof(ngx_addr_t)); - if (u->peer.local == NULL) { - return luaL_error(L, "no memory"); - } - - ngx_memcpy(u->peer.local, local, sizeof(ngx_addr_t)); + u->peer.local = local; } lua_rawgeti(L, 1, SOCKET_TIMEOUT_INDEX); diff --git a/src/ngx_http_lua_socket_tcp.h b/src/ngx_http_lua_socket_tcp.h index 81275bdd1d..3c3483b312 100644 --- a/src/ngx_http_lua_socket_tcp.h +++ b/src/ngx_http_lua_socket_tcp.h @@ -149,7 +149,7 @@ typedef struct { void ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L); void ngx_http_lua_inject_req_socket_api(lua_State *L); void ngx_http_lua_cleanup_conn_pools(lua_State *L); -int ngx_http_lua_socket_bind_ip(lua_State *L, int index); +int ngx_http_lua_socket_bind(lua_State *L, int index); #endif /* _NGX_HTTP_LUA_SOCKET_TCP_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index f915926d26..6752802587 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -56,7 +56,7 @@ static void ngx_http_lua_socket_udp_read_handler(ngx_http_request_t *r, static void ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); static ngx_int_t ngx_http_lua_udp_connect(lua_State *L, - ngx_udp_connection_t *uc); + ngx_http_lua_udp_connection_t *uc); static int ngx_http_lua_socket_udp_close(lua_State *L); static ngx_int_t ngx_http_lua_socket_udp_resume(ngx_http_request_t *r); static void ngx_http_lua_udp_resolve_cleanup(void *data); @@ -66,7 +66,7 @@ static void ngx_http_lua_udp_socket_cleanup(void *data); enum { SOCKET_CTX_INDEX = 1, SOCKET_TIMEOUT_INDEX = 2, - SOCKET_BIND_IP_INDEX = 3 + SOCKET_BIND_INDEX = 3 }; @@ -163,7 +163,7 @@ ngx_http_lua_socket_udp(lua_State *L) static int ngx_http_lua_socket_udp_bind(lua_State *L) { - return ngx_http_lua_socket_bind_ip(L, SOCKET_BIND_IP_INDEX); + return ngx_http_lua_socket_bind(L, SOCKET_BIND_INDEX); } @@ -1361,7 +1361,7 @@ ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, static ngx_int_t -ngx_http_lua_udp_connect(lua_State *L, ngx_udp_connection_t *uc) +ngx_http_lua_udp_connect(lua_State *L, ngx_http_lua_udp_connection_t *uc) { int rc; ngx_int_t event; @@ -1437,7 +1437,7 @@ ngx_http_lua_udp_connect(lua_State *L, ngx_udp_connection_t *uc) } #endif - lua_rawgeti(L, 1, SOCKET_BIND_IP_INDEX); + lua_rawgeti(L, 1, SOCKET_BIND_INDEX); local = lua_touserdata(L, -1); lua_pop(L, 1); diff --git a/t/141-tcp-socket-bind.t b/t/141-tcp-socket-bind.t index 961e09c9af..66a008e024 100644 --- a/t/141-tcp-socket-bind.t +++ b/t/141-tcp-socket-bind.t @@ -298,6 +298,6 @@ failed to connect: cannot assign requested address --- request GET /t --- response_body -failed to bind: bad ip: 127.0.0.1:8899 +failed to bind: bad address --- no_error_log [error] From db0332fcb511be1b0b3ed65736e79bddd76b5379 Mon Sep 17 00:00:00 2001 From: doujiang24 Date: Thu, 17 Mar 2016 20:25:23 +0800 Subject: [PATCH 5/9] bugfix: the local variable may across request, we'd better all alloc in Lua --- src/ngx_http_lua_socket_tcp.c | 27 +++---------- src/ngx_http_lua_util.c | 71 +++++++++++++++++++++++++++++++++++ src/ngx_http_lua_util.h | 2 + t/141-tcp-socket-bind.t | 58 +++++++++++++++++++++++++++- 4 files changed, 135 insertions(+), 23 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 9b181b78be..92ad04e11b 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -410,7 +410,7 @@ ngx_http_lua_socket_bind(lua_State *L, int index) ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; int n; - u_char *ip; + u_char *text; size_t len; ngx_addr_t *local; @@ -439,34 +439,17 @@ ngx_http_lua_socket_bind(lua_State *L, int index) luaL_checktype(L, 1, LUA_TTABLE); - ip = (u_char *) luaL_checklstring(L, 2, &len); - - lua_rawgeti(L, 1, index); - local = lua_touserdata(L, -1); - lua_pop(L, 1); + text = (u_char *) luaL_checklstring(L, 2, &len); + local = ngx_http_lua_parse_addr(L, text, len); if (local == NULL) { - local = lua_newuserdata(L, sizeof(ngx_addr_t)); - if (local == NULL) { - return luaL_error(L, "no memory"); - } - - lua_rawseti(L, 1, index); - } - - if (ngx_parse_addr(r->pool, local, ip, len) != NGX_OK) { lua_pushnil(L); lua_pushfstring(L, "bad address"); return 2; } - local->name.data = ngx_palloc(r->pool, len); - if (local->name.data == NULL) { - return luaL_error(L, "no memory"); - } - - local->name.len = len; - ngx_memcpy(local->name.data, ip, len); + // TODO: we may reuse the userdata here + lua_rawseti(L, 1, index); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket bind ip: %V", &local->name); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 69eccaede4..8330b35357 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -4097,4 +4097,75 @@ ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup) } +ngx_addr_t * +ngx_http_lua_parse_addr(lua_State *L, u_char *text, size_t len) +{ + ngx_addr_t *addr; + size_t socklen; + in_addr_t inaddr; + ngx_uint_t family; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct in6_addr inaddr6; + struct sockaddr_in6 *sin6; + + /* + * prevent MSVC8 warning: + * potentially uninitialized local variable 'inaddr6' used + */ + ngx_memzero(&inaddr6, sizeof(struct in6_addr)); +#endif + + inaddr = ngx_inet_addr(text, len); + + if (inaddr != INADDR_NONE) { + family = AF_INET; + socklen = sizeof(struct sockaddr_in); + +#if (NGX_HAVE_INET6) + } else if (ngx_inet6_addr(text, len, inaddr6.s6_addr) == NGX_OK) { + family = AF_INET6; + socklen = sizeof(struct sockaddr_in6); + +#endif + } else { + return NULL; + } + + addr = lua_newuserdata(L, sizeof(ngx_addr_t) + socklen + len); + if (addr == NULL) { + luaL_error(L, "no memory"); + return NULL; + } + + addr->sockaddr = (struct sockaddr *) ((u_char *) addr + sizeof(ngx_addr_t)); + + ngx_memzero(addr->sockaddr, socklen); + + addr->sockaddr->sa_family = (u_char) family; + addr->socklen = socklen; + + switch (family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) addr->sockaddr; + ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16); + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) addr->sockaddr; + sin->sin_addr.s_addr = inaddr; + break; + } + + addr->name.data = (u_char *) addr->sockaddr + socklen; + addr->name.len = len; + ngx_memcpy(addr->name.data, text, len); + + return addr; +} + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index f0e8923c24..797d2249d0 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -245,6 +245,8 @@ ngx_http_cleanup_t *ngx_http_lua_cleanup_add(ngx_http_request_t *r, void ngx_http_lua_cleanup_free(ngx_http_request_t *r, ngx_http_cleanup_pt *cleanup); +ngx_addr_t *ngx_http_lua_parse_addr(lua_State *L, u_char *text, size_t len); + #define ngx_http_lua_check_if_abortable(L, ctx) \ if ((ctx)->no_abort) { \ diff --git a/t/141-tcp-socket-bind.t b/t/141-tcp-socket-bind.t index 66a008e024..d71b8f8824 100644 --- a/t/141-tcp-socket-bind.t +++ b/t/141-tcp-socket-bind.t @@ -2,7 +2,8 @@ use Test::Nginx::Socket::Lua; -repeat_each(2); +# more times than usual(2) for test case 6 +repeat_each(4); plan tests => repeat_each() * (blocks() * 3 + 7); @@ -301,3 +302,58 @@ GET /t failed to bind: bad address --- no_error_log [error] + + + +=== TEST 6: tcpsock across request after bind +--- http_config + init_worker_by_lua_block { + -- this is not the recommend way, just for test + local function tcp() + local sock = ngx.socket.tcp() + + ---[[ + local ok, err = sock:bind("127.0.0.1") + if not ok then + ngx.log(ngx.ERR, "failed to bind") + end + --]] + + package.loaded.share_sock = sock + end + + local ok, err = ngx.timer.at(0, tcp) + if not ok then + ngx.log(ngx.ERR, "failed to create timer") + end + } +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local port = ngx.var.port + + -- make sure share_sock is created + ngx.sleep(0.002) + + local sock = package.loaded.share_sock + + local ok, err = sock:connect("127.0.0.1", port) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + sock:close() + collectgarbage("collect") + } + } +--- request +GET /t +--- response_body +connected: 1 +--- no_error_log +[error] From 5e65af7a43fdc7785149211512c2d125ba7cd1fc Mon Sep 17 00:00:00 2001 From: doujiang24 Date: Fri, 18 Mar 2016 11:27:46 +0800 Subject: [PATCH 6/9] remove udp bind --- src/ngx_http_lua_socket_tcp.c | 19 ++++++------------ src/ngx_http_lua_socket_tcp.h | 1 - src/ngx_http_lua_socket_udp.c | 38 +++++------------------------------ 3 files changed, 11 insertions(+), 47 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 92ad04e11b..586c65e462 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -140,7 +140,7 @@ enum { SOCKET_CTX_INDEX = 1, SOCKET_TIMEOUT_INDEX = 2, SOCKET_KEY_INDEX = 3, - SOCKET_BIND_INDEX = 4 + SOCKET_BIND_INDEX = 4 // only in upstream cosocket }; @@ -393,7 +393,7 @@ ngx_http_lua_socket_tcp(lua_State *L) | NGX_HTTP_LUA_CONTEXT_TIMER | NGX_HTTP_LUA_CONTEXT_SSL_CERT); - lua_createtable(L, 3 /* narr */, 1 /* nrec */); + lua_createtable(L, 4 /* narr */, 1 /* nrec */); lua_pushlightuserdata(L, &ngx_http_lua_tcp_socket_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -404,8 +404,8 @@ ngx_http_lua_socket_tcp(lua_State *L) } -int -ngx_http_lua_socket_bind(lua_State *L, int index) +static int +ngx_http_lua_socket_tcp_bind(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; @@ -449,23 +449,16 @@ ngx_http_lua_socket_bind(lua_State *L, int index) } // TODO: we may reuse the userdata here - lua_rawseti(L, 1, index); + lua_rawseti(L, 1, SOCKET_BIND_INDEX); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua tcp socket bind ip: %V", &local->name); - lua_pushinteger(L, 1); + lua_pushboolean(L, 1); return 1; } -static int -ngx_http_lua_socket_tcp_bind(lua_State *L) -{ - return ngx_http_lua_socket_bind(L, SOCKET_BIND_INDEX); -} - - static int ngx_http_lua_socket_tcp_connect(lua_State *L) { diff --git a/src/ngx_http_lua_socket_tcp.h b/src/ngx_http_lua_socket_tcp.h index 3c3483b312..dbdee41c6e 100644 --- a/src/ngx_http_lua_socket_tcp.h +++ b/src/ngx_http_lua_socket_tcp.h @@ -149,7 +149,6 @@ typedef struct { void ngx_http_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L); void ngx_http_lua_inject_req_socket_api(lua_State *L); void ngx_http_lua_cleanup_conn_pools(lua_State *L); -int ngx_http_lua_socket_bind(lua_State *L, int index); #endif /* _NGX_HTTP_LUA_SOCKET_TCP_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_socket_udp.c b/src/ngx_http_lua_socket_udp.c index 6752802587..1ec0c00a0f 100644 --- a/src/ngx_http_lua_socket_udp.c +++ b/src/ngx_http_lua_socket_udp.c @@ -28,7 +28,6 @@ static int ngx_http_lua_socket_udp(lua_State *L); -static int ngx_http_lua_socket_udp_bind(lua_State *L); static int ngx_http_lua_socket_udp_setpeername(lua_State *L); static int ngx_http_lua_socket_udp_send(lua_State *L); static int ngx_http_lua_socket_udp_receive(lua_State *L); @@ -55,8 +54,7 @@ static void ngx_http_lua_socket_udp_read_handler(ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); static void ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); -static ngx_int_t ngx_http_lua_udp_connect(lua_State *L, - ngx_http_lua_udp_connection_t *uc); +static ngx_int_t ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc); static int ngx_http_lua_socket_udp_close(lua_State *L); static ngx_int_t ngx_http_lua_socket_udp_resume(ngx_http_request_t *r); static void ngx_http_lua_udp_resolve_cleanup(void *data); @@ -65,8 +63,7 @@ static void ngx_http_lua_udp_socket_cleanup(void *data); enum { SOCKET_CTX_INDEX = 1, - SOCKET_TIMEOUT_INDEX = 2, - SOCKET_BIND_INDEX = 3 + SOCKET_TIMEOUT_INDEX = 2 }; @@ -85,10 +82,7 @@ ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) /* udp socket object metatable */ lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); - lua_createtable(L, 0 /* narr */, 7 /* nrec */); - - lua_pushcfunction(L, ngx_http_lua_socket_udp_bind); - lua_setfield(L, -2, "bind"); + lua_createtable(L, 0 /* narr */, 6 /* nrec */); lua_pushcfunction(L, ngx_http_lua_socket_udp_setpeername); lua_setfield(L, -2, "setpeername"); /* ngx socket mt */ @@ -160,13 +154,6 @@ ngx_http_lua_socket_udp(lua_State *L) } -static int -ngx_http_lua_socket_udp_bind(lua_State *L) -{ - return ngx_http_lua_socket_bind(L, SOCKET_BIND_INDEX); -} - - static int ngx_http_lua_socket_udp_setpeername(lua_State *L) { @@ -683,7 +670,7 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, return 2; } - rc = ngx_http_lua_udp_connect(L, uc); + rc = ngx_http_lua_udp_connect(uc); if (rc != NGX_OK) { u->socket_errno = ngx_socket_errno; @@ -1361,12 +1348,11 @@ ngx_http_lua_socket_udp_handle_success(ngx_http_request_t *r, static ngx_int_t -ngx_http_lua_udp_connect(lua_State *L, ngx_http_lua_udp_connection_t *uc) +ngx_http_lua_udp_connect(ngx_http_lua_udp_connection_t *uc) { int rc; ngx_int_t event; ngx_event_t *rev, *wev; - ngx_addr_t *local; ngx_socket_t s; ngx_connection_t *c; @@ -1437,20 +1423,6 @@ ngx_http_lua_udp_connect(lua_State *L, ngx_http_lua_udp_connection_t *uc) } #endif - lua_rawgeti(L, 1, SOCKET_BIND_INDEX); - local = lua_touserdata(L, -1); - lua_pop(L, 1); - - if (local && (uc->sockaddr->sa_family == AF_INET - || uc->sockaddr->sa_family == AF_INET6)) - { - if (bind(uc->connection->fd, local->sockaddr, local->socklen) != 0) { - ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, - "bind (%V) failed", &local->name); - return NGX_ERROR; - } - } - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "connect to %V, fd:%d #%d", &uc->server, s, c->number); From e57079d046aa3080fa75595378d077c22047569c Mon Sep 17 00:00:00 2001 From: doujiang24 Date: Fri, 18 Mar 2016 11:57:01 +0800 Subject: [PATCH 7/9] add doc for tcpsock:bind --- README.markdown | 37 +++++++++++++++++++++++++++++++++++ doc/HttpLuaModule.wiki | 32 ++++++++++++++++++++++++++++++ src/ngx_http_lua_socket_tcp.c | 4 ++-- 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index 4e8f9bd3cf..105fdff2cf 100644 --- a/README.markdown +++ b/README.markdown @@ -2926,6 +2926,7 @@ Nginx API for Lua * [udpsock:settimeout](#udpsocksettimeout) * [ngx.socket.stream](#ngxsocketstream) * [ngx.socket.tcp](#ngxsockettcp) +* [tcpsock:bind](#tcpsockbind) * [tcpsock:connect](#tcpsockconnect) * [tcpsock:sslhandshake](#tcpsocksslhandshake) * [tcpsock:send](#tcpsocksend) @@ -6383,6 +6384,7 @@ ngx.socket.tcp Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: +* [bind](#tcpsockbind) * [connect](#tcpsockconnect) * [sslhandshake](#tcpsocksslhandshake) * [send](#tcpsocksend) @@ -6419,6 +6421,41 @@ See also [ngx.socket.udp](#ngxsocketudp). [Back to TOC](#nginx-api-for-lua) +tcpsock:bind +------------ +**syntax:** *ok, err = tcpsock:bind(address)* + +**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua** + +Just like the standard [proxy_bind](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_bind) directive, this api makes the outgoing connection to a upstream server originate from the specified local IP address. + +Only IP addresses can be specified as the `address` argument. + +Here is an example for connecting to a TCP server from the specified local IP address: + +```nginx + + location /test { + content_by_lua_block { + local sock = ngx.socket.tcp() + local ok, err = sock:bind("192.168.1.10") + if not ok then + ngx.say("failed to bind") + return + end + local ok, err = sock:connect("192.168.1.67", 80) + if not ok then + ngx.say("failed to connect server: ", err) + return + end + ngx.say("successfully connected!") + sock:close() + } + } +``` + +[Back to TOC](#nginx-api-for-lua) + tcpsock:connect --------------- **syntax:** *ok, err = tcpsock:connect(host, port, options_table?)* diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index f6824ef12b..f279a00088 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -5347,6 +5347,7 @@ This API function was first added to the v0.10.1 release. Creates and returns a TCP or stream-oriented unix domain socket object (also known as one type of the "cosocket" objects). The following methods are supported on this object: +* [[#tcpsock:bind|bind]] * [[#tcpsock:connect|connect]] * [[#tcpsock:sslhandshake|sslhandshake]] * [[#tcpsock:send|send]] @@ -5381,6 +5382,37 @@ This feature was first introduced in the v0.5.0rc1 release. See also [[#ngx.socket.udp|ngx.socket.udp]]. +== tcpsock:bind == +'''syntax:''' ''ok, err = tcpsock:bind(address)'' + +'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*'' + +Just like the standard [[HttpProxyModule#proxy_bind|proxy_bind]] directive, this api makes the outgoing connection to a upstream server originate from the specified local IP address. + +Only IP addresses can be specified as the address argument. + +Here is an example for connecting to a TCP server from the specified local IP address: + + + location /test { + content_by_lua_block { + local sock = ngx.socket.tcp() + local ok, err = sock:bind("192.168.1.10") + if not ok then + ngx.say("failed to bind") + return + end + local ok, err = sock:connect("192.168.1.67", 80) + if not ok then + ngx.say("failed to connect server: ", err) + return + end + ngx.say("successfully connected!") + sock:close() + } + } + + == tcpsock:connect == '''syntax:''' ''ok, err = tcpsock:connect(host, port, options_table?)'' diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 586c65e462..dbbc1d8df9 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -140,7 +140,7 @@ enum { SOCKET_CTX_INDEX = 1, SOCKET_TIMEOUT_INDEX = 2, SOCKET_KEY_INDEX = 3, - SOCKET_BIND_INDEX = 4 // only in upstream cosocket + SOCKET_BIND_INDEX = 4 /* only in upstream cosocket */ }; @@ -448,7 +448,7 @@ ngx_http_lua_socket_tcp_bind(lua_State *L) return 2; } - // TODO: we may reuse the userdata here + /* TODO: we may reuse the userdata here */ lua_rawseti(L, 1, SOCKET_BIND_INDEX); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, From 1149ab8dbedbf5aa5f1ca97b8fd60361db86c56c Mon Sep 17 00:00:00 2001 From: doujiang24 Date: Fri, 18 Mar 2016 12:30:26 +0800 Subject: [PATCH 8/9] get local ip in by perl script and shell command --- t/141-tcp-socket-bind.t | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/t/141-tcp-socket-bind.t b/t/141-tcp-socket-bind.t index d71b8f8824..7a615e5430 100644 --- a/t/141-tcp-socket-bind.t +++ b/t/141-tcp-socket-bind.t @@ -9,13 +9,14 @@ plan tests => repeat_each() * (blocks() * 3 + 7); our $HtmlDir = html_dir; +# we'd better find a better way to get local ip +my $local_ip = `ifconfig | grep -oE '([0-9]{1,3}\\.?){4}' | grep '\\.' | grep -v '127.0.0.1' | head -n 1`; +chomp $local_ip; + $ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; $ENV{TEST_NGINX_NOT_EXIST_IP} ||= '8.8.8.8'; $ENV{TEST_NGINX_INVALID_IP} ||= '127.0.0.1:8899'; -$ENV{TEST_NGINX_SERVER_IP} = '172.17.11.75'; # need to fix - -$ENV{LUA_PATH} ||= - '/usr/local/openresty-debug/lualib/?.lua;/usr/local/openresty/lualib/?.lua;;'; +$ENV{TEST_NGINX_SERVER_IP} ||= $local_ip; no_long_string(); #no_diff(); @@ -157,9 +158,9 @@ request sent received response ip matched done ---- no_error_log +--- no_error_log eval ["[error]", -"bind(127.0.0.1) failed"] +"bind($ENV{TEST_NGINX_SERVER_IP}) failed"] --- error_log eval "lua tcp socket bind ip: $ENV{TEST_NGINX_SERVER_IP}" From dc8aebc6e5e6b8c07fe5b54cf604cc63214e2d59 Mon Sep 17 00:00:00 2001 From: doujiang24 Date: Fri, 18 Mar 2016 14:17:37 +0800 Subject: [PATCH 9/9] some doc --- README.markdown | 1 + doc/HttpLuaModule.wiki | 1 + 2 files changed, 2 insertions(+) diff --git a/README.markdown b/README.markdown index 105fdff2cf..937ff1ce31 100644 --- a/README.markdown +++ b/README.markdown @@ -6438,6 +6438,7 @@ Here is an example for connecting to a TCP server from the specified local IP ad location /test { content_by_lua_block { local sock = ngx.socket.tcp() + -- assume "192.168.1.10" is the local ip address local ok, err = sock:bind("192.168.1.10") if not ok then ngx.say("failed to bind") diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index f279a00088..79a110d9d5 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -5397,6 +5397,7 @@ Here is an example for connecting to a TCP server from the specified local IP ad location /test { content_by_lua_block { local sock = ngx.socket.tcp() + -- assume "192.168.1.10" is the local ip address local ok, err = sock:bind("192.168.1.10") if not ok then ngx.say("failed to bind")