This is an automated email from the ASF dual-hosted git repository.

kichan pushed a commit to branch 8.1.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/8.1.x by this push:
     new 32cbd5baad Add support for vconn start handler for lua plugin (#10575)
32cbd5baad is described below

commit 32cbd5baadc946fc87c78b1b3a8b778a081ff3c7
Author: Kit Chan <[email protected]>
AuthorDate: Mon Oct 9 15:43:42 2023 -0300

    Add support for vconn start handler for lua plugin (#10575)
    
    * add support for vconn start for lua plugin
    
    * fix clang format
---
 doc/admin-guide/plugins/lua.en.rst  |  84 +++++++++++++++++++++++
 plugins/lua/Makefile.inc            |   1 +
 plugins/lua/example/test_vconn.lua  |  40 +++++++++++
 plugins/lua/ts_lua.c                |  87 ++++++++++++++++++++++++
 plugins/lua/ts_lua_common.h         |  17 +++++
 plugins/lua/ts_lua_fetch.c          |   4 ++
 plugins/lua/ts_lua_hook.c           |  10 +++
 plugins/lua/ts_lua_http.c           | 131 ++++++++++++++++++++++++++++++++++++
 plugins/lua/ts_lua_http_intercept.c |   2 +
 plugins/lua/ts_lua_misc.c           |   6 ++
 plugins/lua/ts_lua_util.c           |  92 +++++++++++++++++++++++++
 plugins/lua/ts_lua_util.h           |  25 +++++--
 plugins/lua/ts_lua_vconn.c          |  87 ++++++++++++++++++++++++
 plugins/lua/ts_lua_vconn.h          |  21 ++++++
 14 files changed, 602 insertions(+), 5 deletions(-)

diff --git a/doc/admin-guide/plugins/lua.en.rst 
b/doc/admin-guide/plugins/lua.en.rst
index 8cf69b17ba..3e27e1ba44 100644
--- a/doc/admin-guide/plugins/lua.en.rst
+++ b/doc/admin-guide/plugins/lua.en.rst
@@ -96,6 +96,7 @@ script, and we can write this in remap.config:
 This module can also act as a global plugin of Traffic Server. In this case we 
should provide one of these functions in
 each lua script:
 
+- **'do_global_vconn_start'**
 - **'do_global_txn_start'**
 - **'do_global_txn_close'**
 - **'do_global_os_dns'**
@@ -478,6 +479,7 @@ Hook point constants
 
 ::
 
+    TS_LUA_HOOK_VCONN_START
     TS_LUA_HOOK_OS_DNS
     TS_LUA_HOOK_PRE_REMAP
     TS_LUA_HOOK_READ_CACHE_HDR
@@ -501,6 +503,8 @@ Additional Information:
 |                       |                           |   do_remap() via     | 
do_os_response()   |   global context via |
 |                       |                           |   ts.hook()?         | 
via ts.hook()?     |   ts.hook()?         |
 
+=======================+===========================+======================+====================+======================+
+| TS_VCONN_START_HOOK   | TS_LUA_HOOK_VCONN_START   |     NO               |   
 NO              |    YES               |
++-----------------------+---------------------------+----------------------+--------------------+----------------------+
 | TS_HTTP_TXN           | TS_LUA_HOOK               |     NO               |   
 NO              |    YES               |
 | _START_HOOK           | _TXN_START                |                      |   
                 |                      |
 
+-----------------------+---------------------------+----------------------+--------------------+----------------------+
@@ -2745,6 +2749,66 @@ Here is an example
 
 `TOP <#ts-lua-plugin>`_
 
+ts.http.get_ssn_remote_addr
+---------------------------
+**syntax:** *ts.http.get_ssn_remote_addr()*
+
+**context:** after do_global_read_reqest
+
+**description:** This function can be used to get the remote address (IP, 
port, family) of the session.
+
+`TOP <#ts-lua-plugin>`_
+
+ts.http.get_client_received_error
+---------------------------------
+**syntax:** *ts.http.get_client_received_error()*
+
+**context:** after do_global_txn_close
+
+**description:** This function can be used to get the client received error 
from transaction.
+
+Here is an example
+
+::
+
+    function do_global_txn_close()
+        local class, code = ts.http.get_client_received_error()
+        ts.debug('txn_close: '..class)
+        ts.debug('txn_close: '..code)
+    end
+
+`TOP <#ts-lua-plugin>`_
+
+ts.http.get_client_sent_error
+-----------------------------
+**syntax:** *ts.http.get_client_sent_error()*
+
+**context:** after do_global_txn_close
+
+**description:** This function can be used to get the client sent error from 
transaction.
+
+`TOP <#ts-lua-plugin>`_
+
+ts.http.get_server_received_error
+---------------------------------
+**syntax:** *ts.http.get_server_received_error()*
+
+**context:** after do_global_txn_close
+
+**description:** This function can be used to get the server received error 
from transaction.
+
+`TOP <#ts-lua-plugin>`_
+
+ts.http.get_server_sent_error
+-----------------------------
+**syntax:** *ts.http.get_server_sent_error()*
+
+**context:** after do_global_txn_close
+
+**description:** This function can be used to get the server sent error from 
transaction.
+
+`TOP <#ts-lua-plugin>`_
+
 ts.add_package_path
 -------------------
 **syntax:** *ts.add_package_path(lua-style-path-str)*
@@ -3847,6 +3911,26 @@ be returned with 4 functions to increment, decrement, 
get and set the value. Tha
 
 `TOP <#ts-lua-plugin>`_
 
+ts.vconn.get_fd
+---------------
+**syntax:** *ts.vconn.get_fd()*
+
+**context:** do_global_vconn_start
+
+**description:** This function can be used to get the file descriptor of the 
virtual connection.
+
+`TOP <#ts-lua-plugin>`_
+
+ts.vconn.get_remote_addr
+------------------------
+**syntax:** *ts.vconn.get_remote_addr()*
+
+**context:** do_global_vconn_start
+
+**description:** This function can be used to get the remote address (IP, 
port, family) of the virtual connection.
+
+`TOP <#ts-lua-plugin>`_
+
 Todo
 ====
 * ts.cache_xxx
diff --git a/plugins/lua/Makefile.inc b/plugins/lua/Makefile.inc
index adcdde5e87..cfae2e89a4 100644
--- a/plugins/lua/Makefile.inc
+++ b/plugins/lua/Makefile.inc
@@ -26,6 +26,7 @@ lua_tslua_la_SOURCES = \
   lua/ts_lua_client_response.c \
   lua/ts_lua_context.c \
   lua/ts_lua_hook.c \
+  lua/ts_lua_vconn.c \
   lua/ts_lua_http.c \
   lua/ts_lua_http_intercept.c \
   lua/ts_lua_log.c \
diff --git a/plugins/lua/example/test_vconn.lua 
b/plugins/lua/example/test_vconn.lua
new file mode 100644
index 0000000000..70175ef171
--- /dev/null
+++ b/plugins/lua/example/test_vconn.lua
@@ -0,0 +1,40 @@
+--  Licensed to the Apache Software Foundation (ASF) under one
+--  or more contributor license agreements.  See the NOTICE file
+--  distributed with this work for additional information
+--  regarding copyright ownership.  The ASF licenses this file
+--  to you under the Apache License, Version 2.0 (the
+--  "License"); you may not use this file except in compliance
+--  with the License.  You may obtain a copy of the License at
+--
+--  http://www.apache.org/licenses/LICENSE-2.0
+--
+--  Unless required by applicable law or agreed to in writing, software
+--  distributed under the License is distributed on an "AS IS" BASIS,
+--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+--  See the License for the specific language governing permissions and
+--  limitations under the License.
+
+function do_global_vconn_start()
+    ts.debug('vconn_start')
+
+    ip, port, family = ts.vconn.get_remote_addr()
+    ts.debug('vconn: '..ip)               -- 192.168.231.17
+    ts.debug('vconn: '..port)             -- 17786
+    ts.debug('vconn: '..family)           -- 2(AF_INET)
+
+    fd = ts.vconn.get_fd()
+    ts.debug('vconn: '..fd)
+end
+
+function do_global_txn_close()
+    ts.debug('txn_close')
+
+    ip, port, family = ts.http.get_ssn_remote_addr()
+    ts.debug('txn_close: '..ip)               -- 192.168.231.17
+    ts.debug('txn_close: '..port)             -- 17786
+    ts.debug('txn_close: '..family)           -- 2(AF_INET)
+
+    class, code = ts.http.get_client_received_error()
+    ts.debug('txn_close: '..class)
+    ts.debug('txn_close: '..code)
+end
diff --git a/plugins/lua/ts_lua.c b/plugins/lua/ts_lua.c
index 2a4cbc34f3..2e758e55b5 100644
--- a/plugins/lua/ts_lua.c
+++ b/plugins/lua/ts_lua.c
@@ -555,6 +555,73 @@ configHandler(TSCont contp, TSEvent event ATS_UNUSED, void 
*edata ATS_UNUSED)
   return 0;
 }
 
+static int
+vconnHookHandler(TSCont contp, TSEvent event, void *edata)
+{
+  TSVConn vconn = (TSVConn)edata;
+
+  int ret;
+  uint64_t req_id;
+
+  lua_State *l;
+
+  ts_lua_main_ctx *main_ctx;
+  ts_lua_vconn_ctx *vconn_ctx;
+
+  ts_lua_instance_conf *conf = (ts_lua_instance_conf *)TSContDataGet(contp);
+
+  req_id = __sync_fetch_and_add(&ts_lua_g_http_next_id, 1);
+
+  main_ctx = &ts_lua_g_main_ctx_array[req_id % conf->states];
+
+  TSDebug(TS_LUA_DEBUG_TAG, "[%s] req_id: %" PRId64, __FUNCTION__, req_id);
+
+  TSMutexLock(main_ctx->mutexp);
+
+  vconn_ctx        = ts_lua_create_vconn_ctx(main_ctx, conf);
+  vconn_ctx->vconn = vconn;
+  l                = vconn_ctx->lua;
+
+  switch (event) {
+  case TS_EVENT_VCONN_START:
+    lua_getglobal(l, TS_LUA_FUNCTION_G_VCONN_START);
+    break;
+
+  default:
+    ts_lua_destroy_vconn_ctx(vconn_ctx);
+    TSMutexUnlock(main_ctx->mutexp);
+    TSVConnReenable(vconn);
+    return 0;
+  }
+
+  if (lua_type(l, -1) != LUA_TFUNCTION) {
+    lua_pop(l, 1);
+    ts_lua_destroy_vconn_ctx(vconn_ctx);
+    TSMutexUnlock(main_ctx->mutexp);
+
+    TSVConnReenable(vconn);
+    return 0;
+  }
+
+  if (lua_pcall(l, 0, 1, 0) != 0) {
+    TSError("[ts_lua][%s] lua_pcall failed: %s", __FUNCTION__, lua_tostring(l, 
-1));
+  }
+
+  ret = lua_tointeger(l, -1);
+  lua_pop(l, 1);
+
+  ts_lua_destroy_vconn_ctx(vconn_ctx);
+
+  TSMutexUnlock(main_ctx->mutexp);
+  if (ret) {
+    TSError("[ts_lua][%s] error returned", __FUNCTION__);
+  } else {
+    TSDebug(TS_LUA_DEBUG_TAG, "[%s] no error returned", __FUNCTION__);
+  }
+  TSVConnReenable(vconn);
+  return 0;
+}
+
 static int
 globalHookHandler(TSCont contp, TSEvent event ATS_UNUSED, void *edata)
 {
@@ -908,6 +975,26 @@ TSPluginInit(int argc, const char *argv[])
 
   ts_lua_destroy_http_ctx(http_ctx);
 
+  TSCont vconn_contp = TSContCreate(vconnHookHandler, NULL);
+  if (!vconn_contp) {
+    TSError("[ts_lua][%s] could not create vconn continuation", __FUNCTION__);
+    return;
+  }
+  TSContDataSet(vconn_contp, conf);
+
+  // adding hook based on whther the lua global vconn function exists
+  ts_lua_vconn_ctx *vconn_ctx = ts_lua_create_vconn_ctx(main_ctx, conf);
+  lua_State *vl               = vconn_ctx->lua;
+
+  lua_getglobal(vl, TS_LUA_FUNCTION_G_VCONN_START);
+  if (lua_type(vl, -1) == LUA_TFUNCTION) {
+    TSHttpHookAdd(TS_VCONN_START_HOOK, vconn_contp);
+    TSDebug(TS_LUA_DEBUG_TAG, "vconn_start_hook added");
+  }
+  lua_pop(vl, 1);
+
+  ts_lua_destroy_vconn_ctx(vconn_ctx);
+
   // support for reload as global plugin
   if (reload) {
     TSCont config_contp = TSContCreate(configHandler, NULL);
diff --git a/plugins/lua/ts_lua_common.h b/plugins/lua/ts_lua_common.h
index dba8b7d77e..3cec245363 100644
--- a/plugins/lua/ts_lua_common.h
+++ b/plugins/lua/ts_lua_common.h
@@ -58,6 +58,9 @@
 #define TS_LUA_FUNCTION_G_READ_CACHE "do_global_read_cache"
 #define TS_LUA_FUNCTION_G_TXN_CLOSE "do_global_txn_close"
 
+// TLS hooks can only be global
+#define TS_LUA_FUNCTION_G_VCONN_START "do_global_vconn_start"
+
 #define TS_LUA_DEBUG_TAG "ts_lua"
 
 #define TS_LUA_EVENT_COROUTINE_CONT 20000
@@ -100,6 +103,20 @@ typedef struct {
   int init_func;
 } ts_lua_instance_conf;
 
+/* lua state for vconn */
+typedef struct {
+  int ref;
+
+  ts_lua_main_ctx *mctx;
+
+  lua_State *lua;
+
+  TSVConn vconn;
+
+  ts_lua_instance_conf *instance_conf;
+
+} ts_lua_vconn_ctx;
+
 /* lua state for http request */
 typedef struct {
   ts_lua_cont_info cinfo;
diff --git a/plugins/lua/ts_lua_fetch.c b/plugins/lua/ts_lua_fetch.c
index f76e990d06..d27fd66a18 100644
--- a/plugins/lua/ts_lua_fetch.c
+++ b/plugins/lua/ts_lua_fetch.c
@@ -60,6 +60,8 @@ ts_lua_fetch(lua_State *L)
 
   ci = ts_lua_get_cont_info(L);
   if (ci == NULL) {
+    TSError("[ts_lua][%s] no cont info found", __FUNCTION__);
+    TSReleaseAssert(!"Unexpected fetch of cont info");
     return 0;
   }
 
@@ -124,6 +126,8 @@ ts_lua_fetch_multi(lua_State *L)
 
   ci = ts_lua_get_cont_info(L);
   if (ci == NULL) {
+    TSError("[ts_lua][%s] no cont info found", __FUNCTION__);
+    TSReleaseAssert(!"Unexpected fetch of cont info");
     return 0;
   }
 
diff --git a/plugins/lua/ts_lua_hook.c b/plugins/lua/ts_lua_hook.c
index 81e32983ce..227a0f4335 100644
--- a/plugins/lua/ts_lua_hook.c
+++ b/plugins/lua/ts_lua_hook.c
@@ -35,6 +35,7 @@ typedef enum {
   TS_LUA_HOOK_TXN_CLOSE,
   TS_LUA_REQUEST_TRANSFORM,
   TS_LUA_RESPONSE_TRANSFORM,
+  TS_LUA_HOOK_VCONN_START,
   TS_LUA_HOOK_LAST
 } TSLuaHookID;
 
@@ -52,6 +53,7 @@ char *ts_lua_hook_id_string[] = {"TS_LUA_HOOK_DUMMY",
                                  "TS_LUA_HOOK_TXN_CLOSE",
                                  "TS_LUA_REQUEST_TRANSFORM",
                                  "TS_LUA_RESPONSE_TRANSFORM",
+                                 "TS_LUA_HOOK_VCONN_START",
                                  "TS_LUA_HOOK_LAST"};
 
 static int ts_lua_add_hook(lua_State *L);
@@ -240,6 +242,14 @@ ts_lua_add_hook(lua_State *L)
     }
     break;
 
+  case TS_LUA_HOOK_VCONN_START:
+    if (http_ctx) {
+      TSError("[ts_lua][%s] VCONN_START handler can only be global", 
__FUNCTION__);
+    } else {
+      lua_pushvalue(L, 2);
+      lua_setglobal(L, TS_LUA_FUNCTION_G_VCONN_START);
+    }
+
   default:
     break;
   }
diff --git a/plugins/lua/ts_lua_http.c b/plugins/lua/ts_lua_http.c
index b10fefba1c..2e9f7cf674 100644
--- a/plugins/lua/ts_lua_http.c
+++ b/plugins/lua/ts_lua_http.c
@@ -16,6 +16,8 @@
   limitations under the License.
 */
 
+#include <netinet/in.h>
+#include <arpa/inet.h>
 #include "ts_lua_util.h"
 #include "ts_lua_http_intercept.h"
 #include "ts_lua_http_config.h"
@@ -101,6 +103,13 @@ static int ts_lua_http_get_remap_to_url(lua_State *L);
 static int ts_lua_http_get_server_fd(lua_State *L);
 static int ts_lua_http_get_client_fd(lua_State *L);
 
+static int ts_lua_http_get_client_received_error(lua_State *L);
+static int ts_lua_http_get_client_sent_error(lua_State *L);
+static int ts_lua_http_get_server_received_error(lua_State *L);
+static int ts_lua_http_get_server_sent_error(lua_State *L);
+
+static int ts_lua_http_get_ssn_remote_addr(lua_State *L);
+
 static void ts_lua_inject_server_state_variables(lua_State *L);
 
 static void ts_lua_inject_http_resp_transform_api(lua_State *L);
@@ -257,6 +266,21 @@ ts_lua_inject_http_misc_api(lua_State *L)
   lua_pushcfunction(L, ts_lua_http_get_client_fd);
   lua_setfield(L, -2, "get_client_fd");
 
+  lua_pushcfunction(L, ts_lua_http_get_client_received_error);
+  lua_setfield(L, -2, "get_client_received_error");
+
+  lua_pushcfunction(L, ts_lua_http_get_client_sent_error);
+  lua_setfield(L, -2, "get_client_sent_error");
+
+  lua_pushcfunction(L, ts_lua_http_get_server_received_error);
+  lua_setfield(L, -2, "get_server_received_error");
+
+  lua_pushcfunction(L, ts_lua_http_get_server_sent_error);
+  lua_setfield(L, -2, "get_server_sent_error");
+
+  lua_pushcfunction(L, ts_lua_http_get_ssn_remote_addr);
+  lua_setfield(L, -2, "get_ssn_remote_addr");
+
   ts_lua_inject_server_state_variables(L);
 }
 
@@ -876,6 +900,109 @@ ts_lua_http_get_client_fd(lua_State *L)
   return 1;
 }
 
+static int
+ts_lua_http_get_client_received_error(lua_State *L)
+{
+  uint32_t class = 0;
+  uint64_t code  = 0;
+  ts_lua_http_ctx *http_ctx;
+
+  GET_HTTP_CONTEXT(http_ctx, L);
+
+  TSHttpTxnClientReceivedErrorGet(http_ctx->txnp, &class, &code);
+  lua_pushnumber(L, class);
+  lua_pushnumber(L, code);
+
+  return 2;
+}
+
+static int
+ts_lua_http_get_client_sent_error(lua_State *L)
+{
+  uint32_t class = 0;
+  uint64_t code  = 0;
+  ts_lua_http_ctx *http_ctx;
+
+  GET_HTTP_CONTEXT(http_ctx, L);
+
+  TSHttpTxnClientSentErrorGet(http_ctx->txnp, &class, &code);
+  lua_pushnumber(L, class);
+  lua_pushnumber(L, code);
+
+  return 2;
+}
+
+static int
+ts_lua_http_get_server_received_error(lua_State *L)
+{
+  uint32_t class = 0;
+  uint64_t code  = 0;
+  ts_lua_http_ctx *http_ctx;
+
+  GET_HTTP_CONTEXT(http_ctx, L);
+
+  TSHttpTxnServerReceivedErrorGet(http_ctx->txnp, &class, &code);
+  lua_pushnumber(L, class);
+  lua_pushnumber(L, code);
+
+  return 2;
+}
+
+static int
+ts_lua_http_get_server_sent_error(lua_State *L)
+{
+  uint32_t class = 0;
+  uint64_t code  = 0;
+  ts_lua_http_ctx *http_ctx;
+
+  GET_HTTP_CONTEXT(http_ctx, L);
+
+  TSHttpTxnServerSentErrorGet(http_ctx->txnp, &class, &code);
+  lua_pushnumber(L, class);
+  lua_pushnumber(L, code);
+
+  return 2;
+}
+
+static int
+ts_lua_http_get_ssn_remote_addr(lua_State *L)
+{
+  struct sockaddr const *client_ip;
+  ts_lua_http_ctx *http_ctx;
+  int port;
+  int family;
+  char cip[128];
+
+  GET_HTTP_CONTEXT(http_ctx, L);
+
+  TSHttpSsn ssn = TSHttpTxnSsnGet(http_ctx->txnp);
+  TSVConn vconn = TSHttpSsnClientVConnGet(ssn);
+  client_ip     = TSNetVConnRemoteAddrGet(vconn);
+
+  if (client_ip == NULL) {
+    lua_pushnil(L);
+    lua_pushnil(L);
+    lua_pushnil(L);
+
+  } else {
+    if (client_ip->sa_family == AF_INET) {
+      port = ntohs(((struct sockaddr_in *)client_ip)->sin_port);
+      inet_ntop(AF_INET, (const void *)&((struct sockaddr_in 
*)client_ip)->sin_addr, cip, sizeof(cip));
+      family = AF_INET;
+    } else {
+      port = ntohs(((struct sockaddr_in6 *)client_ip)->sin6_port);
+      inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 
*)client_ip)->sin6_addr, cip, sizeof(cip));
+      family = AF_INET6;
+    }
+
+    lua_pushstring(L, cip);
+    lua_pushnumber(L, port);
+    lua_pushnumber(L, family);
+  }
+
+  return 3;
+}
+
 static int
 ts_lua_http_resp_transform_get_upstream_bytes(lua_State *L)
 {
@@ -884,6 +1011,7 @@ ts_lua_http_resp_transform_get_upstream_bytes(lua_State *L)
   transform_ctx = ts_lua_get_http_transform_ctx(L);
   if (transform_ctx == NULL) {
     TSError("[ts_lua] missing transform_ctx");
+    TSReleaseAssert(!"Unexpected fetch of transform_ctx");
     return 0;
   }
 
@@ -900,6 +1028,7 @@ 
ts_lua_http_resp_transform_get_upstream_watermark_bytes(lua_State *L)
   transform_ctx = ts_lua_get_http_transform_ctx(L);
   if (transform_ctx == NULL) {
     TSError("[ts_lua] missing transform_ctx");
+    TSReleaseAssert(!"Unexpected fetch of transform_ctx");
     return 0;
   }
 
@@ -917,6 +1046,7 @@ 
ts_lua_http_resp_transform_set_upstream_watermark_bytes(lua_State *L)
   transform_ctx = ts_lua_get_http_transform_ctx(L);
   if (transform_ctx == NULL) {
     TSError("[ts_lua] missing transform_ctx");
+    TSReleaseAssert(!"Unexpected fetch of transform_ctx");
     return 0;
   }
 
@@ -936,6 +1066,7 @@ ts_lua_http_resp_transform_set_downstream_bytes(lua_State 
*L)
   transform_ctx = ts_lua_get_http_transform_ctx(L);
   if (transform_ctx == NULL) {
     TSError("[ts_lua] missing transform_ctx");
+    TSReleaseAssert(!"Unexpected fetch of transform_ctx");
     return 0;
   }
 
diff --git a/plugins/lua/ts_lua_http_intercept.c 
b/plugins/lua/ts_lua_http_intercept.c
index 048f52d918..deec525266 100644
--- a/plugins/lua/ts_lua_http_intercept.c
+++ b/plugins/lua/ts_lua_http_intercept.c
@@ -358,6 +358,7 @@ ts_lua_say(lua_State *L)
   ictx = ts_lua_get_http_intercept_ctx(L);
   if (ictx == NULL) {
     TSError("[ts_lua] missing ictx");
+    TSReleaseAssert(!"Unexpected fetch of intercept_ctx");
     return 0;
   }
 
@@ -380,6 +381,7 @@ ts_lua_flush(lua_State *L)
   ictx = ts_lua_get_http_intercept_ctx(L);
   if (ictx == NULL) {
     TSError("[ts_lua] missing ictx");
+    TSReleaseAssert(!"Unexpected fetch of intercept_ctx");
     return 0;
   }
 
diff --git a/plugins/lua/ts_lua_misc.c b/plugins/lua/ts_lua_misc.c
index 8da3a160aa..f2800fd050 100644
--- a/plugins/lua/ts_lua_misc.c
+++ b/plugins/lua/ts_lua_misc.c
@@ -180,6 +180,8 @@ ts_lua_schedule(lua_State *L)
 
   ci = ts_lua_get_cont_info(L);
   if (ci == NULL) {
+    TSError("[ts_lua][%s] no cont info found", __FUNCTION__);
+    TSReleaseAssert(!"Unexpected fetch of cont info");
     return 0;
   }
 
@@ -278,6 +280,8 @@ ts_lua_sleep(lua_State *L)
 
   ci = ts_lua_get_cont_info(L);
   if (ci == NULL) {
+    TSError("[ts_lua][%s] no cont info found", __FUNCTION__);
+    TSReleaseAssert(!"Unexpected fetch of cont info");
     return 0;
   }
 
@@ -338,6 +342,8 @@ ts_lua_host_lookup(lua_State *L)
 
   ci = ts_lua_get_cont_info(L);
   if (ci == NULL) {
+    TSError("[ts_lua][%s] no cont info found", __FUNCTION__);
+    TSReleaseAssert(!"Unexpected fetch of cont info");
     return 0;
   }
 
diff --git a/plugins/lua/ts_lua_util.c b/plugins/lua/ts_lua_util.c
index 76d86fd88c..ee08617d38 100644
--- a/plugins/lua/ts_lua_util.c
+++ b/plugins/lua/ts_lua_util.c
@@ -26,6 +26,7 @@
 #include "ts_lua_cached_response.h"
 #include "ts_lua_context.h"
 #include "ts_lua_hook.h"
+#include "ts_lua_vconn.h"
 #include "ts_lua_http.h"
 #include "ts_lua_misc.h"
 #include "ts_lua_log.h"
@@ -454,6 +455,8 @@ ts_lua_inject_ts_api(lua_State *L)
   ts_lua_inject_context_api(L);
   ts_lua_inject_hook_api(L);
 
+  ts_lua_inject_vconn_api(L);
+
   ts_lua_inject_http_api(L);
   ts_lua_inject_intercept_api(L);
   ts_lua_inject_misc_api(L);
@@ -576,6 +579,95 @@ ts_lua_destroy_async_ctx(ts_lua_http_ctx *http_ctx)
   TSfree(http_ctx);
 }
 
+void
+ts_lua_set_vconn_ctx(lua_State *L, ts_lua_vconn_ctx *ctx)
+{
+  lua_pushliteral(L, "__ts_vconn_ctx");
+  lua_pushlightuserdata(L, ctx);
+  lua_rawset(L, LUA_GLOBALSINDEX);
+}
+
+ts_lua_vconn_ctx *
+ts_lua_get_vconn_ctx(lua_State *L)
+{
+  ts_lua_vconn_ctx *ctx;
+
+  lua_pushliteral(L, "__ts_vconn_ctx");
+  lua_rawget(L, LUA_GLOBALSINDEX);
+  ctx = lua_touserdata(L, -1);
+
+  lua_pop(L, 1); // pop the ctx out
+
+  return ctx;
+}
+
+ts_lua_vconn_ctx *
+ts_lua_create_vconn_ctx(ts_lua_main_ctx *main_ctx, ts_lua_instance_conf *conf)
+{
+  ts_lua_vconn_ctx *vconn_ctx;
+
+  vconn_ctx = TSmalloc(sizeof(ts_lua_vconn_ctx));
+  memset(vconn_ctx, 0, sizeof(*vconn_ctx));
+
+  lua_State *L = main_ctx->lua;
+  lua_State *l = lua_newthread(L);
+
+  lua_pushlightuserdata(L, conf);
+  lua_rawget(L, LUA_REGISTRYINDEX);
+
+  /* new globals table for coroutine */
+  lua_newtable(l);
+  lua_pushvalue(l, -1);
+  lua_setfield(l, -2, "_G");
+  lua_newtable(l);
+  lua_xmove(L, l, 1);
+  lua_setfield(l, -2, "__index");
+  lua_setmetatable(l, -2);
+
+  lua_replace(l, LUA_GLOBALSINDEX);
+
+  // init coroutine
+  vconn_ctx->ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+  vconn_ctx->lua  = l;
+  vconn_ctx->mctx = main_ctx;
+
+  // update thread stats
+  ts_lua_ctx_stats *const stats = main_ctx->stats;
+
+  TSMutexLock(stats->mutexp);
+  ++stats->threads;
+  if (stats->threads_max < stats->threads) {
+    stats->threads_max = stats->threads;
+  }
+  TSMutexUnlock(stats->mutexp);
+
+  vconn_ctx->instance_conf = conf;
+
+  ts_lua_set_vconn_ctx(l, vconn_ctx);
+  ts_lua_create_context_table(l);
+
+  return vconn_ctx;
+}
+
+void
+ts_lua_destroy_vconn_ctx(ts_lua_vconn_ctx *vconn_ctx)
+{
+  // update thread stats
+  ts_lua_main_ctx *const main_ctx = vconn_ctx->mctx;
+  ts_lua_ctx_stats *const stats   = main_ctx->stats;
+
+  TSMutexLock(stats->mutexp);
+  --stats->threads;
+  TSMutexUnlock(stats->mutexp);
+
+  if (vconn_ctx->lua) {
+    luaL_unref(vconn_ctx->lua, LUA_REGISTRYINDEX, vconn_ctx->ref);
+  }
+
+  TSfree(vconn_ctx);
+}
+
 void
 ts_lua_set_http_ctx(lua_State *L, ts_lua_http_ctx *ctx)
 {
diff --git a/plugins/lua/ts_lua_util.h b/plugins/lua/ts_lua_util.h
index d75db9f188..b35890db17 100644
--- a/plugins/lua/ts_lua_util.h
+++ b/plugins/lua/ts_lua_util.h
@@ -46,16 +46,31 @@ void ts_lua_destroy_async_ctx(ts_lua_http_ctx *http_ctx);
 void ts_lua_set_http_ctx(lua_State *L, ts_lua_http_ctx *ctx);
 ts_lua_http_ctx *ts_lua_get_http_ctx(lua_State *L);
 
-#define GET_HTTP_CONTEXT(ctx, list)       \
-  ctx = ts_lua_get_http_ctx(list);        \
-  if (ctx == NULL) {                      \
-    TSError("[ts_lua] missing http_ctx"); \
-    return 0;                             \
+#define GET_HTTP_CONTEXT(ctx, list)                   \
+  ctx = ts_lua_get_http_ctx(list);                    \
+  if (ctx == NULL) {                                  \
+    TSError("[ts_lua] missing http_ctx");             \
+    TSReleaseAssert(!"Unexpected fetch of http_ctx"); \
+    return 0;                                         \
+  }
+
+#define GET_VCONN_CONTEXT(ctx, list)                   \
+  ctx = ts_lua_get_vconn_ctx(list);                    \
+  if (ctx == NULL) {                                   \
+    TSError("[ts_lua] missing vconn_ctx");             \
+    TSReleaseAssert(!"Unexpected fetch of vconn_ctx"); \
+    return 0;                                          \
   }
 
 ts_lua_http_ctx *ts_lua_create_http_ctx(ts_lua_main_ctx *mctx, 
ts_lua_instance_conf *conf);
 void ts_lua_destroy_http_ctx(ts_lua_http_ctx *http_ctx);
 
+void ts_lua_set_vconn_ctx(lua_State *L, ts_lua_vconn_ctx *ctx);
+ts_lua_vconn_ctx *ts_lua_get_vconn_ctx(lua_State *L);
+
+ts_lua_vconn_ctx *ts_lua_create_vconn_ctx(ts_lua_main_ctx *mctx, 
ts_lua_instance_conf *conf);
+void ts_lua_destroy_vconn_ctx(ts_lua_vconn_ctx *vconn_ctx);
+
 ts_lua_http_transform_ctx *ts_lua_create_http_transform_ctx(ts_lua_http_ctx 
*http_ctx, TSVConn connp);
 void ts_lua_destroy_http_transform_ctx(ts_lua_http_transform_ctx 
*transform_ctx);
 void ts_lua_set_http_transform_ctx(lua_State *L, ts_lua_http_transform_ctx 
*tctx);
diff --git a/plugins/lua/ts_lua_vconn.c b/plugins/lua/ts_lua_vconn.c
new file mode 100644
index 0000000000..dd1e4b5381
--- /dev/null
+++ b/plugins/lua/ts_lua_vconn.c
@@ -0,0 +1,87 @@
+/*
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  http://www.apache.org/licenses/LICENSE-2.0
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+*/
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "ts_lua_util.h"
+
+static int ts_lua_vconn_get_remote_addr(lua_State *L);
+static int ts_lua_vconn_get_fd(lua_State *L);
+
+void
+ts_lua_inject_vconn_api(lua_State *L)
+{
+  lua_newtable(L);
+
+  lua_pushcfunction(L, ts_lua_vconn_get_remote_addr);
+  lua_setfield(L, -2, "get_remote_addr");
+
+  lua_pushcfunction(L, ts_lua_vconn_get_fd);
+  lua_setfield(L, -2, "get_fd");
+
+  lua_setfield(L, -2, "vconn");
+}
+
+static int
+ts_lua_vconn_get_remote_addr(lua_State *L)
+{
+  ts_lua_vconn_ctx *vconn_ctx;
+  int port;
+  int family;
+  char sip[128];
+
+  GET_VCONN_CONTEXT(vconn_ctx, L);
+
+  struct sockaddr const *addr = TSNetVConnRemoteAddrGet(vconn_ctx->vconn);
+
+  if (addr == NULL) {
+    lua_pushnil(L);
+    lua_pushnil(L);
+    lua_pushnil(L);
+  } else {
+    if (addr->sa_family == AF_INET) {
+      port = ntohs(((struct sockaddr_in *)addr)->sin_port);
+      inet_ntop(AF_INET, (const void *)&((struct sockaddr_in 
*)addr)->sin_addr, sip, sizeof(sip));
+      family = AF_INET;
+    } else {
+      port = ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
+      inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 
*)addr)->sin6_addr, sip, sizeof(sip));
+      family = AF_INET6;
+    }
+
+    lua_pushstring(L, sip);
+    lua_pushnumber(L, port);
+    lua_pushnumber(L, family);
+  }
+
+  return 3;
+}
+
+static int
+ts_lua_vconn_get_fd(lua_State *L)
+{
+  int fd = 0;
+  ts_lua_vconn_ctx *vconn_ctx;
+
+  GET_VCONN_CONTEXT(vconn_ctx, L);
+
+  fd = TSVConnFdGet(vconn_ctx->vconn);
+
+  lua_pushnumber(L, fd);
+
+  return 1;
+}
diff --git a/plugins/lua/ts_lua_vconn.h b/plugins/lua/ts_lua_vconn.h
new file mode 100644
index 0000000000..6239f86435
--- /dev/null
+++ b/plugins/lua/ts_lua_vconn.h
@@ -0,0 +1,21 @@
+/*
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  http://www.apache.org/licenses/LICENSE-2.0
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+*/
+
+#pragma once
+
+#include "ts_lua_common.h"
+
+void ts_lua_inject_vconn_api(lua_State *L);

Reply via email to