2727
2828
2929static int ngx_stream_lua_socket_udp (lua_State * L );
30+ static int ngx_stream_lua_socket_udp_bind (lua_State * L );
3031static int ngx_stream_lua_socket_udp_setpeername (lua_State * L );
3132static int ngx_stream_lua_socket_udp_send (lua_State * L );
3233static int ngx_stream_lua_socket_udp_receive (lua_State * L );
@@ -54,7 +55,7 @@ static void ngx_stream_lua_socket_udp_read_handler(ngx_stream_session_t *s,
5455 ngx_stream_lua_socket_udp_upstream_t * u );
5556static void ngx_stream_lua_socket_udp_handle_success (ngx_stream_session_t * s ,
5657 ngx_stream_lua_socket_udp_upstream_t * u );
57- static ngx_int_t ngx_stream_lua_udp_connect (
58+ static ngx_int_t ngx_stream_lua_udp_connect (lua_State * L ,
5859 ngx_stream_lua_udp_connection_t * uc );
5960static int ngx_stream_lua_socket_udp_close (lua_State * L );
6061static ngx_int_t ngx_stream_lua_socket_udp_resume (ngx_stream_session_t * s ,
@@ -65,7 +66,8 @@ static void ngx_stream_lua_udp_socket_cleanup(ngx_stream_lua_co_ctx_t *coctx);
6566
6667enum {
6768 SOCKET_CTX_INDEX = 1 ,
68- SOCKET_TIMEOUT_INDEX = 2
69+ SOCKET_TIMEOUT_INDEX = 2 ,
70+ SOCKET_BIND_INDEX = 3 /* only in upstream cosocket */
6971};
7072
7173
@@ -84,7 +86,10 @@ ngx_stream_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L)
8486
8587 /* udp socket object metatable */
8688 lua_pushlightuserdata (L , & ngx_stream_lua_socket_udp_metatable_key );
87- lua_createtable (L , 0 /* narr */ , 6 /* nrec */ );
89+ lua_createtable (L , 0 /* narr */ , 7 /* nrec */ );
90+
91+ lua_pushcfunction (L , ngx_stream_lua_socket_udp_bind );
92+ lua_setfield (L , -2 , "bind" ); /* ngx socket mt */
8893
8994 lua_pushcfunction (L , ngx_stream_lua_socket_udp_setpeername );
9095 lua_setfield (L , -2 , "setpeername" ); /* ngx socket mt */
@@ -142,7 +147,7 @@ ngx_stream_lua_socket_udp(lua_State *L)
142147 ngx_stream_lua_check_context (L , ctx , NGX_STREAM_LUA_CONTEXT_CONTENT
143148 | NGX_STREAM_LUA_CONTEXT_TIMER );
144149
145- lua_createtable (L , 3 /* narr */ , 1 /* nrec */ );
150+ lua_createtable (L , 4 /* narr */ , 1 /* nrec */ );
146151 lua_pushlightuserdata (L , & ngx_stream_lua_socket_udp_metatable_key );
147152 lua_rawget (L , LUA_REGISTRYINDEX );
148153 lua_setmetatable (L , -2 );
@@ -153,6 +158,54 @@ ngx_stream_lua_socket_udp(lua_State *L)
153158}
154159
155160
161+ static int
162+ ngx_stream_lua_socket_udp_bind (lua_State * L )
163+ {
164+ ngx_stream_session_t * s ;
165+ ngx_stream_lua_ctx_t * ctx ;
166+ int n ;
167+ u_char * text ;
168+ size_t len ;
169+ ngx_addr_t * local ;
170+
171+ n = lua_gettop (L );
172+ if (n != 2 ) {
173+ return luaL_error (L , "expecting 2 arguments, but got %d" ,
174+ lua_gettop (L ));
175+ }
176+
177+ s = ngx_stream_lua_get_session (L );
178+ if (s == NULL ) {
179+ return luaL_error (L , "no request found" );
180+ }
181+
182+ ctx = ngx_stream_get_module_ctx (s , ngx_stream_lua_module );
183+ if (ctx == NULL ) {
184+ return luaL_error (L , "no ctx found" );
185+ }
186+
187+ ngx_stream_lua_check_context (L , ctx , NGX_STREAM_LUA_CONTEXT_CONTENT
188+ | NGX_STREAM_LUA_CONTEXT_TIMER );
189+
190+ luaL_checktype (L , 1 , LUA_TTABLE );
191+
192+ text = (u_char * ) luaL_checklstring (L , 2 , & len );
193+ local = ngx_stream_lua_parse_addr (L , text , len );
194+ if (local == NULL ) {
195+ lua_pushnil (L );
196+ lua_pushfstring (L , "bad address" );
197+ return 2 ;
198+ }
199+
200+ /* TODO: we may reuse the userdata here */
201+ lua_rawseti (L , 1 , SOCKET_BIND_INDEX );
202+ ngx_log_debug1 (NGX_LOG_DEBUG_STREAM , s -> connection -> log , 0 ,
203+ "lua udp socket bind ip: %V" , & local -> name );
204+ lua_pushboolean (L , 1 );
205+ return 1 ;
206+ }
207+
208+
156209static int
157210ngx_stream_lua_socket_udp_setpeername (lua_State * L )
158211{
@@ -652,7 +705,7 @@ ngx_stream_lua_socket_resolve_retval_handler(ngx_stream_session_t *s,
652705 return 2 ;
653706 }
654707
655- rc = ngx_stream_lua_udp_connect (uc );
708+ rc = ngx_stream_lua_udp_connect (L , uc );
656709
657710 if (rc != NGX_OK ) {
658711 u -> socket_errno = ngx_socket_errno ;
@@ -1318,11 +1371,12 @@ ngx_stream_lua_socket_udp_handle_success(ngx_stream_session_t *s,
13181371
13191372
13201373static ngx_int_t
1321- ngx_stream_lua_udp_connect (ngx_stream_lua_udp_connection_t * uc )
1374+ ngx_stream_lua_udp_connect (lua_State * L , ngx_stream_lua_udp_connection_t * uc )
13221375{
13231376 int rc ;
13241377 ngx_int_t event ;
13251378 ngx_event_t * rev , * wev ;
1379+ ngx_addr_t * local ;
13261380 ngx_socket_t s ;
13271381 ngx_connection_t * c ;
13281382
@@ -1393,6 +1447,20 @@ ngx_stream_lua_udp_connect(ngx_stream_lua_udp_connection_t *uc)
13931447 }
13941448#endif
13951449
1450+ lua_rawgeti (L , 1 , SOCKET_BIND_INDEX );
1451+ local = lua_touserdata (L , -1 );
1452+ lua_pop (L , 1 );
1453+
1454+ if (local && (uc -> sockaddr -> sa_family == AF_INET
1455+ || uc -> sockaddr -> sa_family == AF_INET6 )) {
1456+ if (bind (uc -> connection -> fd ,
1457+ local -> sockaddr , local -> socklen ) != 0 ) {
1458+ ngx_log_error (NGX_LOG_CRIT , & uc -> log , ngx_socket_errno ,
1459+ "bind(%V) failed" , & local -> name );
1460+ return NGX_ERROR ;
1461+ }
1462+ }
1463+
13961464 ngx_log_debug3 (NGX_LOG_DEBUG_EVENT , & uc -> log , 0 ,
13971465 "connect to %V, fd:%d #%d" , & uc -> server , s , c -> number );
13981466
0 commit comments