From 5984a056de1bdb5ac5b5aee632d14822ae758fa3 Mon Sep 17 00:00:00 2001 From: Dolly <109222243+Dolly132@users.noreply.github.com> Date: Sat, 1 Aug 2026 09:43:02 +0300 Subject: [PATCH] feat(api): add GetClientIP to track connected clients (#4) --- .../scripting/include/AsyncSocket.inc | 3 + src/context.cpp | 5 ++ src/context.h | 2 + src/extension.cpp | 62 +++++++++++++++++++ src/extension.h | 1 + 5 files changed, 73 insertions(+) diff --git a/package/addons/sourcemod/scripting/include/AsyncSocket.inc b/package/addons/sourcemod/scripting/include/AsyncSocket.inc index a662238..a05a8df 100644 --- a/package/addons/sourcemod/scripting/include/AsyncSocket.inc +++ b/package/addons/sourcemod/scripting/include/AsyncSocket.inc @@ -28,6 +28,8 @@ methodmap AsyncSocket < Handle { public native bool SetErrorCallback(AsyncSocketErrorCallback callback); public native bool SetDataCallback(AsyncSocketDataCallback callback); + + public native void GetClientIP(char[] buffer, int length); } /** @@ -59,5 +61,6 @@ public __ext_AsyncSocket_SetNTVOptional() MarkNativeAsOptional("AsyncSocket.SetConnectCallback"); MarkNativeAsOptional("AsyncSocket.SetErrorCallback"); MarkNativeAsOptional("AsyncSocket.SetDataCallback"); + MarkNativeAsOptional("AsyncSocket.GetClientIP"); } #endif diff --git a/src/context.cpp b/src/context.cpp index edd8042..5b07496 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -8,6 +8,8 @@ CAsyncSocketContext::CAsyncSocketContext(IPluginContext *pContext) m_pHost = NULL; m_Port = -1; + m_pClientIP = NULL; + m_Deleted = false; m_PendingCallback = false; m_Pending = false; @@ -26,6 +28,9 @@ CAsyncSocketContext::~CAsyncSocketContext() if(m_pHost) free(m_pHost); + if(m_pClientIP) + free(m_pClientIP); + if(m_pConnectCallback) forwards->ReleaseForward(m_pConnectCallback); diff --git a/src/context.h b/src/context.h index 30369b5..3627cb0 100644 --- a/src/context.h +++ b/src/context.h @@ -20,6 +20,8 @@ public: char *m_pHost; int m_Port; + char *m_pClientIP; + IChangeableForward *m_pConnectCallback; IChangeableForward *m_pErrorCallback; IChangeableForward *m_pDataCallback; diff --git a/src/extension.cpp b/src/extension.cpp index ec372d3..7cee0fe 100644 --- a/src/extension.cpp +++ b/src/extension.cpp @@ -39,6 +39,8 @@ * @brief Implement extension code here. */ +#define MAX_IP_BUFFER_LENGTH 64 + moodycamel::ReaderWriterQueue g_ConnectQueue; moodycamel::ReaderWriterQueue g_ErrorQueue; moodycamel::ReaderWriterQueue g_DataQueue; @@ -105,6 +107,19 @@ void OnGameFrame(bool simulating) pSocketContext->m_pStream = pConnect->pClientSocket; pSocketContext->m_pStream->data = pSocketContext; + if (pConnect->pClientIP) + { + pSocketContext->m_pClientIP = pConnect->pClientIP; + } + else + { + pSocketContext->m_pClientIP = (char *)malloc(MAX_IP_BUFFER_LENGTH); + if (pSocketContext->m_pClientIP) + { + pSocketContext->m_pClientIP[0] = '\0'; + } + } + pConnect->pSocketContext->OnConnect(pSocketContext); if(!pSocketContext->m_Deleted) @@ -119,6 +134,10 @@ void OnGameFrame(bool simulating) } else { + if (pConnect->pClientIP) + { + pConnect->pSocketContext->m_pClientIP = pConnect->pClientIP; + } pConnect->pSocketContext->Connected(); } @@ -200,6 +219,12 @@ void UV_DeleteAsyncContext(uv_async_t *pHandle) pSocketContext->m_pSocket = NULL; } + if (pSocketContext->m_pClientIP) + { + free(pSocketContext->m_pClientIP); + pSocketContext->m_pClientIP = NULL; + } + delete pSocketContext; } @@ -280,6 +305,7 @@ void UV_OnConnect(uv_connect_t *req, int status) CSocketConnect *pConnect = (CSocketConnect *)malloc(sizeof(CSocketConnect)); pConnect->pSocketContext = pSocketContext; pConnect->pClientSocket = pSocketContext->m_pStream; + pConnect->pClientIP = NULL; g_ConnectQueue.enqueue(pConnect); uv_read_start(pSocketContext->m_pStream, UV_AllocBuffer, UV_OnRead); @@ -324,6 +350,26 @@ void UV_OnNewConnection(uv_stream_t *server, int status) CSocketConnect *pConnect = (CSocketConnect *)malloc(sizeof(CSocketConnect)); pConnect->pSocketContext = pSocketContext; pConnect->pClientSocket = (uv_stream_t *)pClientSocket; + + pConnect->pClientIP = (char *)malloc(MAX_IP_BUFFER_LENGTH); + if (pConnect->pClientIP) + { + pConnect->pClientIP[0] = '\0'; + struct sockaddr_storage name; + int namelen = sizeof(name); + if (uv_tcp_getpeername(pClientSocket, (struct sockaddr *)&name, &namelen) == 0) + { + if (name.ss_family == AF_INET) + { + uv_ip4_name((const struct sockaddr_in *)&name, pConnect->pClientIP, MAX_IP_BUFFER_LENGTH); + } + else if (name.ss_family == AF_INET6) + { + uv_ip6_name((const struct sockaddr_in6 *)&name, pConnect->pClientIP, MAX_IP_BUFFER_LENGTH); + } + } + } + g_ConnectQueue.enqueue(pConnect); } else @@ -599,6 +645,21 @@ cell_t Native_AsyncSocket_SetDataCallback(IPluginContext *pContext, const cell_t return true; } +cell_t Native_AsyncSocket_GetClientIP(IPluginContext *pContext, const cell_t *params) +{ + CAsyncSocketContext *pSocketContext = g_AsyncSocket.GetSocketInstanceByHandle(params[1]); + + if (pSocketContext == NULL) + { + return pContext->ThrowNativeError("Invalid socket handle"); + } + + const char *ip = (pSocketContext->m_pClientIP != NULL) ? pSocketContext->m_pClientIP : ""; + pContext->StringToLocal(params[2], params[3], ip); + + return 1; +} + // Sourcemod Plugin Events bool AsyncSocket::SDK_OnLoad(char *error, size_t maxlength, bool late) { @@ -656,5 +717,6 @@ const sp_nativeinfo_t AsyncSocketNatives[] = { {"AsyncSocket.SetConnectCallback", Native_AsyncSocket_SetConnectCallback}, {"AsyncSocket.SetErrorCallback", Native_AsyncSocket_SetErrorCallback}, {"AsyncSocket.SetDataCallback", Native_AsyncSocket_SetDataCallback}, + {"AsyncSocket.GetClientIP", Native_AsyncSocket_GetClientIP}, {NULL, NULL} }; diff --git a/src/extension.h b/src/extension.h index 237d64e..1bc1fb5 100644 --- a/src/extension.h +++ b/src/extension.h @@ -58,6 +58,7 @@ struct CSocketConnect { CAsyncSocketContext *pSocketContext; uv_stream_t *pClientSocket; + char *pClientIP; }; struct CSocketData