diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 5f2255e7eb..30aee760cc 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -843,11 +843,13 @@ ngx_http_lua_socket_tcp_bind(lua_State *L) u_char *text; size_t len; ngx_addr_t *local; + int port; n = lua_gettop(L); - if (n != 2) { - return luaL_error(L, "expecting 2 arguments, but got %d", + /* Correct the parameter check and allow 2 or 3 parameters */ + if (n != 2 && n != 3) { + return luaL_error(L, "expecting 2 or 3 arguments, but got %d", lua_gettop(L)); } @@ -865,6 +867,26 @@ ngx_http_lua_socket_tcp_bind(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); + port = 0; + /* handle case: host:port */ + /* Hit the following parameter combination: + * sock:bind("127.0.0.1", port) */ + if (n == 3) { + if (!lua_isnumber(L, 3)) { + lua_pushnil(L); + lua_pushfstring(L, "expecting port to be a" + "number but got type: %s", luaL_typename(L, 3)); + return 2; + } + + port = (int) lua_tointeger(L, 3); + if (port < 0 || port > 65535) { + lua_pushnil(L); + lua_pushfstring(L, "bad port number: %d", port); + return 2; + } + } + text = (u_char *) luaL_checklstring(L, 2, &len); local = ngx_http_lua_parse_addr(L, text, len); @@ -874,9 +896,11 @@ ngx_http_lua_socket_tcp_bind(lua_State *L) return 2; } + if (port > 0) { + ngx_inet_set_port(local->sockaddr, (in_port_t) port); + } /* 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, "lua tcp socket bind ip: %V", &local->name); @@ -1129,6 +1153,10 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) lua_rawgeti(L, 1, SOCKET_BIND_INDEX); local = lua_touserdata(L, -1); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "lua tcp socket sock:connect ip: %V", &local->name); + lua_pop(L, 1); if (local) { @@ -3419,7 +3447,7 @@ ngx_http_lua_socket_tcp_handler(ngx_event_t *ev) static ngx_int_t ngx_http_lua_socket_tcp_get_peer(ngx_peer_connection_t *pc, void *data) { - /* empty */ + pc->type = SOCK_STREAM; return NGX_OK; } diff --git a/t/168-tcp-socket-bind.t b/t/168-tcp-socket-bind.t index a2aa50b4e7..2fe33faed6 100644 --- a/t/168-tcp-socket-bind.t +++ b/t/168-tcp-socket-bind.t @@ -365,3 +365,64 @@ GET /t connected: 1 --- no_error_log [error] + + +=== TEST 7: upstream sockets bind with ip port +--- config + server_tokens off; + location /t { + set $port $TEST_NGINX_SERVER_PORT; + content_by_lua_block { + local ip = "127.0.0.1" + local port = ngx.var.port + + local sock = ngx.socket.tcp() + + local ok, err = sock:bind(ip, 12345) + 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 + + local ok, err = sock:setoption("reuseaddr", 1) + if not ok then + ngx.say("setoption reuseaddr failed: ", err) + 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 + + 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 + sock:close() + ngx.say(data) + + } + } + + location /foo { + echo bind: $remote_addr:$remote_port; + } +--- request +GET /t +--- response_body eval +qr/bind:\s127\.0\.0\.1:12345|failed\s+to\s+connect:\s+address\s+already\s+in\s+use/ +--- error_log eval +"lua tcp socket bind ip: 127.0.0.1" +