diff --git a/extensions/curl/FileDownloader.cpp b/extensions/curl/FileDownloader.cpp new file mode 100644 index 000000000..f087f7fed --- /dev/null +++ b/extensions/curl/FileDownloader.cpp @@ -0,0 +1,81 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Webternet Extension + * Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#include "FileDownloader.h" + +using namespace SourceMod; + +FileDownloader::FileDownloader( const char *file ) +{ + fpLocal = fopen(file, "wb"); +} + +FileDownloader::~FileDownloader(void) +{ + if(this->fpLocal != NULL) + { + fclose(this->fpLocal); + } +} + +DownloadWriteStatus FileDownloader::OnDownloadWrite(IWebTransfer *session, + void *userdata, + void *ptr, + size_t size, + size_t nmemb) +{ + size_t total = size * nmemb; + + if (this->fpLocal == NULL) + { + return DownloadWrite_Error; + } + + if (fwrite(ptr, size, nmemb, this->fpLocal) == total) + { + return DownloadWrite_Okay; + } + else + { + return DownloadWrite_Error; + } +} + +size_t FileDownloader::GetSize() +{ + return ftell(this->fpLocal); +} + +char *SourceMod::FileDownloader::GetBuffer() +{ + // TODO: implement this! + return NULL; +} diff --git a/extensions/curl/FileDownloader.h b/extensions/curl/FileDownloader.h new file mode 100644 index 000000000..f181b45c1 --- /dev/null +++ b/extensions/curl/FileDownloader.h @@ -0,0 +1,61 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Webternet Extension + * Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_CURLEXT_FILE_DOWNLOADER_IMPL_H_ +#define _INCLUDE_SOURCEMOD_CURLEXT_FILE_DOWNLOADER_IMPL_H_ + +#include + +namespace SourceMod +{ + class FileDownloader : public IBaseDownloader + { + public: + FileDownloader(const char *file); + ~FileDownloader(void); + + virtual DownloadWriteStatus OnDownloadWrite(IWebTransfer *session, + void *userdata, + void *ptr, + size_t size, + size_t nmemb); + + virtual size_t GetSize(); + + virtual char * GetBuffer(); + + + private: + FILE *fpLocal; + }; +} + +#endif diff --git a/extensions/curl/MemoryDownloader.cpp b/extensions/curl/MemoryDownloader.cpp new file mode 100644 index 000000000..73ed3a893 --- /dev/null +++ b/extensions/curl/MemoryDownloader.cpp @@ -0,0 +1,85 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Updater Extension + * Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#include +#include +#include +#include "MemoryDownloader.h" + +using namespace SourceMod; + +MemoryDownloader::MemoryDownloader() : buffer(NULL), bufsize(0), bufpos(0) +{ +} + +MemoryDownloader::~MemoryDownloader() +{ + free(buffer); +} + +DownloadWriteStatus MemoryDownloader::OnDownloadWrite(IWebTransfer *session, + void *userdata, + void *ptr, + size_t size, + size_t nmemb) +{ + size_t total = size * nmemb; + + if (bufpos + total > bufsize) + { + size_t rem = (bufpos + total) - bufsize; + bufsize += rem + (rem / 2); + buffer = (char *)realloc(buffer, bufsize); + } + + assert(bufpos + total <= bufsize); + + memcpy(&buffer[bufpos], ptr, total); + bufpos += total; + + return DownloadWrite_Okay; +} + +void MemoryDownloader::Reset() +{ + bufpos = 0; +} + +char *MemoryDownloader::GetBuffer() +{ + return buffer; +} + +size_t MemoryDownloader::GetSize() +{ + return bufpos; +} + diff --git a/extensions/curl/MemoryDownloader.h b/extensions/curl/MemoryDownloader.h new file mode 100644 index 000000000..9cb189005 --- /dev/null +++ b/extensions/curl/MemoryDownloader.h @@ -0,0 +1,62 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Webternet Extension + * Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEMOD_UPDATER_MEMORY_DOWNLOADER_H_ +#define _INCLUDE_SOURCEMOD_UPDATER_MEMORY_DOWNLOADER_H_ + +#include + +namespace SourceMod +{ + class MemoryDownloader : public IBaseDownloader + { + public: + MemoryDownloader(); + ~MemoryDownloader(); + public: + DownloadWriteStatus OnDownloadWrite(IWebTransfer *session, + void *userdata, + void *ptr, + size_t size, + size_t nmemb); + public: + void Reset(); + char *GetBuffer(); + size_t GetSize(); + private: + char *buffer; + size_t bufsize; + size_t bufpos; + }; +} + +#endif /* _INCLUDE_SOURCEMOD_UPDATER_MEMORY_DOWNLOADER_H_ */ + diff --git a/extensions/curl/extension.cpp b/extensions/curl/extension.cpp index b7c29bc5c..e9a9bb236 100644 --- a/extensions/curl/extension.cpp +++ b/extensions/curl/extension.cpp @@ -35,6 +35,9 @@ #include #include #include "curlapi.h" +#include "FileDownloader.h" +#include "MemoryDownloader.h" + /** * @file extension.cpp @@ -45,6 +48,17 @@ CurlExt curl_ext; /**< Global singleton for extension's main interface */ SMEXT_LINK(&curl_ext); +SessionHandler g_SessionHandler; +HandleType_t g_SessionHandle = 0; +FormHandler g_FormHandler; +HandleType_t g_FormHandle = 0; +DownloadHandler g_DownloadHandler; +HandleType_t g_DownloadHandle = 0; +/************************************************************************/ +/* NEW CODE */ +/************************************************************************/ +HTTPSessionManager& g_SessionManager = HTTPSessionManager::instance(); + bool CurlExt::SDK_OnLoad(char *error, size_t maxlength, bool late) { long flags; @@ -68,11 +82,35 @@ bool CurlExt::SDK_OnLoad(char *error, size_t maxlength, bool late) return false; } + // Register natives + g_pShareSys->AddNatives(myself, curlext_natives); + // Register session handle handler + g_SessionHandle = g_pHandleSys->CreateType("HTTPSession", + &g_SessionHandler, 0, 0, NULL, myself->GetIdentity(), NULL); + // Register web form handle handler + g_FormHandle = g_pHandleSys->CreateType("HTTPWebForm", + &g_FormHandler, 0, 0, NULL, myself->GetIdentity(), NULL); + // Register web form handle handler + g_DownloadHandle = g_pHandleSys->CreateType("HTTPDownloader", + &g_DownloadHandler, 0, 0, NULL, myself->GetIdentity(), NULL); + plsys->AddPluginsListener(this); + smutils->AddGameFrameHook(&OnGameFrame); + /************************************************************************/ + /* NEW CODE */ + /************************************************************************/ + g_SessionManager.Initialize(); + return true; } void CurlExt::SDK_OnUnload() { + g_pHandleSys->RemoveType(g_SessionHandle, myself->GetIdentity()); + g_pHandleSys->RemoveType(g_FormHandle, myself->GetIdentity()); + g_pHandleSys->RemoveType(g_DownloadHandle, myself->GetIdentity()); + plsys->RemovePluginsListener(this); + smutils->RemoveGameFrameHook(&OnGameFrame); + g_SessionManager.Cleanup(); curl_global_cleanup(); } @@ -86,3 +124,754 @@ const char *CurlExt::GetExtensionDateString() return SOURCEMOD_BUILD_TIME; } +void OnGameFrame(bool simulating) +{ + /************************************************************************/ + /* NEW CODE */ + /************************************************************************/ + g_SessionManager.RunFrame(); +} + +void CurlExt::OnPluginUnloaded( IPlugin *plugin ) +{ + g_SessionManager.PluginUnloaded(plugin); +} + +static cell_t HTTP_CreateFileDownloader(IPluginContext *pCtx, const cell_t *params) +{ + char *file; + // 1st param: file name + pCtx->LocalToString(params[1], &file); + + char localPath[PLATFORM_MAX_PATH]; + // Build absolute path for fopen() + smutils->BuildPath(Path_Game, localPath, PLATFORM_MAX_PATH, file); + + // Use file-based download handler + FileDownloader *downloader = new FileDownloader(localPath); + + // This should never happen but, oh well... + if (!downloader) + { + return pCtx->ThrowNativeError("Could not create downloader"); + } + + return g_pHandleSys->CreateHandle(g_DownloadHandle, + (void*)downloader, + pCtx->GetIdentity(), + myself->GetIdentity(), + NULL); +} + +static cell_t HTTP_CreateMemoryDownloader(IPluginContext *pCtx, const cell_t *params) +{ + MemoryDownloader *downloader = new MemoryDownloader(); + + if (!downloader) + { + return pCtx->ThrowNativeError("Could not create downloader"); + } + + return g_pHandleSys->CreateHandle(g_DownloadHandle, + (void*)downloader, + pCtx->GetIdentity(), + myself->GetIdentity(), + NULL); +} + +static cell_t HTTP_CreateWebForm(IPluginContext *pCtx, const cell_t *params) +{ + IWebForm *form = g_webternet.CreateForm(); + + if (!form) + { + return pCtx->ThrowNativeError("Could not create web form"); + } + + return g_pHandleSys->CreateHandle(g_FormHandle, + (void*)form, + pCtx->GetIdentity(), + myself->GetIdentity(), + NULL); +} + +static cell_t HTTP_AddStringToWebForm(IPluginContext *pCtx, const cell_t *params) +{ + // 1st param: web form handle + Handle_t hndl = static_cast(params[1]); + HandleError err; + HandleSecurity sec; + sec.pOwner = pCtx->GetIdentity(); + sec.pIdentity = myself->GetIdentity(); + + IWebForm *form; + + // Validate handle data + if ((err = g_pHandleSys->ReadHandle(hndl, g_FormHandle, &sec, (void **)&form)) != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid web form handle %x (error %d)", hndl, err); + } + + if (!form) + { + return pCtx->ThrowNativeError("HTTP Web Form data not found\n"); + } + + char *name, *data; + // 2nd param: name of the POST variable + pCtx->LocalToString(params[2], &name); + // 3rd param: value of the POST variable + pCtx->LocalToString(params[3], &data); + + return form->AddString(name, data); +} + +static cell_t HTTP_AddFileToWebForm(IPluginContext *pCtx, const cell_t *params) +{ + // 1st param: web form handle + Handle_t hndl = static_cast(params[1]); + HandleError err; + HandleSecurity sec; + sec.pOwner = pCtx->GetIdentity(); + sec.pIdentity = myself->GetIdentity(); + + IWebForm *form; + + // Validate handle data + if ((err = g_pHandleSys->ReadHandle(hndl, g_FormHandle, &sec, (void **)&form)) != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid web form handle %x (error %d)", hndl, err); + } + + if (!form) + { + return pCtx->ThrowNativeError("HTTP Web Form data not found\n"); + } + + char *name, *path; + // 2nd param: name of the POST variable + pCtx->LocalToString(params[2], &name); + // 3rd param: value of the POST variable + pCtx->LocalToString(params[3], &path); + + return form->AddFile(name, path); +} + +static cell_t HTTP_CreateSession(IPluginContext *pCtx, const cell_t *params) +{ + IWebTransfer *x = g_webternet.CreateSession(); + + if (!x) + { + return pCtx->ThrowNativeError("Could not create session"); + } + + return g_pHandleSys->CreateHandle(g_SessionHandle, + (void*)x, + pCtx->GetIdentity(), + myself->GetIdentity(), + NULL); +} + +static cell_t HTTP_GetLastError(IPluginContext *pCtx, const cell_t *params) +{ + // 1st param: session handle + Handle_t hndl = static_cast(params[1]); + HandleError err; + HandleSecurity sec; + sec.pOwner = pCtx->GetIdentity(); + sec.pIdentity = myself->GetIdentity(); + + IWebTransfer *x; + + // Validate handle data + if ((err = g_pHandleSys->ReadHandle(hndl, g_SessionHandle, &sec, (void **)&x)) != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid session handle %x (error %d)", hndl, err); + } + + if (!x) + { + pCtx->ThrowNativeError("HTTP Session data not found\n"); + + return false; + } + + // Copy error message in output string + pCtx->StringToLocalUTF8(params[2], params[3], x->LastErrorMessage(), NULL); + + return true; +} + +static cell_t HTTP_PostAndDownload(IPluginContext *pCtx, const cell_t *params) +{ + /************************************************************************/ + /* NEW CODE */ + /************************************************************************/ + HTTPRequestHandleSet handles; + // 1st param: session handle + handles.hndlSession = static_cast(params[1]); + + HandleError err; + HandleSecurity sec; + sec.pOwner = pCtx->GetIdentity(); + sec.pIdentity = myself->GetIdentity(); + + IWebTransfer *x; + + if ((err = g_pHandleSys->ReadHandle(handles.hndlSession, + g_SessionHandle, &sec, (void **)&x)) != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid session handle %x (error %d)", + handles.hndlSession, err); + } + + if (!x) + { + return pCtx->ThrowNativeError("HTTP Session data not found\n"); + } + + // 2nd param: downloader handle + handles.hndlDownloader = static_cast(params[2]); + IBaseDownloader *downloader; + + if ((err = g_pHandleSys->ReadHandle(handles.hndlDownloader, + g_DownloadHandle, &sec, (void **)&downloader)) != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid downloader handle %x (error %d)", + handles.hndlDownloader, err); + } + + if (!downloader) + { + return pCtx->ThrowNativeError("HTTP Downloader data not found\n"); + } + + // 3rd param: web form handle + handles.hndlForm = static_cast(params[3]);; + IWebForm *form; + + if ((err = g_pHandleSys->ReadHandle(handles.hndlForm, + g_FormHandle, &sec, (void **)&form)) != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid web form handle %x (error %d)", + handles.hndlForm, err); + } + + if (!form) + { + return pCtx->ThrowNativeError("HTTP Web Form data not found\n"); + } + + char *url; + // 4th param: target URL + pCtx->LocalToString(params[4], &url); + + /************************************************************************/ + /* NEW CODE */ + /************************************************************************/ + HTTPRequestCompletedContextPack contextPack; + contextPack.pCallbackFunction = new HTTPRequestCompletedContextFunction; + + contextPack.pCallbackFunction->pContext = pCtx; + // 5th param: callback function + contextPack.pCallbackFunction->uPluginFunction = params[5]; + + // 6th param: custom user data + if (params[0] >= 6) + { + contextPack.pCallbackFunction->bHasContext = true; + contextPack.iPluginContextValue = params[6]; + } + + // Queue request for asynchronous execution + g_SessionManager.PostAndDownload(pCtx, handles, url, contextPack); + + return true; +} + +static cell_t HTTP_Download(IPluginContext *pCtx, const cell_t *params) +{ + /************************************************************************/ + /* NEW CODE */ + /************************************************************************/ + HTTPRequestHandleSet handles; + // 1st param: session handle + handles.hndlSession = static_cast(params[1]); + HandleError err; + HandleSecurity sec; + sec.pOwner = pCtx->GetIdentity(); + sec.pIdentity = myself->GetIdentity(); + + IWebTransfer *x; + + // Validate handle data + if ((err = g_pHandleSys->ReadHandle(handles.hndlSession, + g_SessionHandle, &sec, (void **)&x)) != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid session handle %x (error %d)", + handles.hndlSession, err); + } + + if (!x) + { + return pCtx->ThrowNativeError("HTTP Session data not found\n"); + } + + // 2nd param: downloader handle + handles.hndlDownloader = static_cast(params[2]); + IBaseDownloader *downloader; + + if ((err = g_pHandleSys->ReadHandle(handles.hndlDownloader, + g_DownloadHandle, &sec, (void **)&downloader)) != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid downloader handle %x (error %d)", + handles.hndlDownloader, err); + } + + if (!downloader) + { + return pCtx->ThrowNativeError("HTTP Downloader data not found\n"); + } + + char *url; + // 3rd param: target URL + pCtx->LocalToString(params[3], &url); + + /************************************************************************/ + /* NEW CODE */ + /************************************************************************/ + HTTPRequestCompletedContextPack contextPack; + contextPack.pCallbackFunction = new HTTPRequestCompletedContextFunction; + + contextPack.pCallbackFunction->pContext = pCtx; + // 4th param: callback function + contextPack.pCallbackFunction->uPluginFunction = params[4]; + + // 5th param: custom user data + if (params[0] >= 5) + { + contextPack.pCallbackFunction->bHasContext = true; + contextPack.iPluginContextValue = params[5]; + } + + // Queue request for asynchronous execution + g_SessionManager.Download(pCtx, handles, url, contextPack); + + return true; +} + +static cell_t HTTP_GetBodySize(IPluginContext *pCtx, const cell_t *params) +{ + // 1st param: session handle + Handle_t hndl = static_cast(params[1]); + HandleError err; + HandleSecurity sec; + sec.pOwner = pCtx->GetIdentity(); + sec.pIdentity = myself->GetIdentity(); + + IBaseDownloader *dldr = NULL; + + // Validate handle data + if ((err = g_pHandleSys->ReadHandle(hndl, + g_DownloadHandle, &sec, (void **)&dldr)) != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid downloader handle %x (error %d)", hndl, err); + } + + if (!dldr) + { + return pCtx->ThrowNativeError("HTTP Downloader data not found\n"); + } + + return dldr->GetSize(); +} + +static cell_t HTTP_GetBodyContent(IPluginContext *pCtx, const cell_t *params) +{ + // 1st param: session handle + Handle_t hndl = static_cast(params[1]); + HandleError err; + HandleSecurity sec; + sec.pOwner = pCtx->GetIdentity(); + sec.pIdentity = myself->GetIdentity(); + + IBaseDownloader *dldr = NULL; + + // Validate handle data + if ((err = g_pHandleSys->ReadHandle(hndl, + g_DownloadHandle, &sec, (void **)&dldr)) != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid downloader handle %x (error %d)", hndl, err); + } + + if (!dldr) + { + return pCtx->ThrowNativeError("HTTP Downloader data not found\n"); + } + + char *body; + // 2nd param: receiving buffer + pCtx->LocalToString(params[2], &body); + // 3rd param: max buffer length + uint32_t bodySize = params[3]; + + // NOTE: we need one additional byte for the null terminator + if (bodySize < (dldr->GetSize() + 1)) + { + return pCtx->ThrowNativeError("Buffer too small\n"); + } + + memcpy(body, dldr->GetBuffer(), params[3]); + body[dldr->GetSize()] = '\0'; + + return pCtx->StringToLocal(params[2], params[3], body); +} + +static cell_t HTTP_SetFailOnHTTPError(IPluginContext *pCtx, const cell_t *params) +{ + // 1st param: session handle + Handle_t hndl = static_cast(params[1]); + HandleError err; + HandleSecurity sec; + sec.pOwner = pCtx->GetIdentity(); + sec.pIdentity = myself->GetIdentity(); + + IWebTransfer *xfer; + + // Validate handle data + if ((err = g_pHandleSys->ReadHandle(hndl, + g_SessionHandle, &sec, (void **)&xfer)) != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid session handle %x (error %d)", hndl, err); + } + + if (!xfer) + { + return pCtx->ThrowNativeError("HTTP Session data not found\n"); + } + + return xfer->SetFailOnHTTPError(static_cast(params[2])); +} + +const sp_nativeinfo_t curlext_natives[] = +{ + {"HTTP_CreateFileDownloader", HTTP_CreateFileDownloader}, + {"HTTP_CreateMemoryDownloader", HTTP_CreateMemoryDownloader}, + {"HTTP_CreateSession", HTTP_CreateSession}, + {"HTTP_SetFailOnHTTPError", HTTP_SetFailOnHTTPError}, + {"HTTP_GetLastError", HTTP_GetLastError}, + {"HTTP_Download", HTTP_Download}, + {"HTTP_PostAndDownload", HTTP_PostAndDownload}, + {"HTTP_CreateWebForm", HTTP_CreateWebForm}, + {"HTTP_AddStringToWebForm", HTTP_AddStringToWebForm}, + {"HTTP_AddFileToWebForm", HTTP_AddFileToWebForm}, + {"HTTP_GetBodySize", HTTP_GetBodySize}, + {"HTTP_GetBodyContent", HTTP_GetBodyContent}, + {NULL, NULL}, +}; + +/************************************************************************/ +/* NEW CODE */ +/************************************************************************/ +void HTTPSessionManager::PluginUnloaded( IPlugin *plugin ) +{ + /************************************************************************/ + /* NEW CODE */ + /************************************************************************/ + // Check for pending requests and cancel them + { + pRequestsLock->Lock(); + + if (!requests.empty()) + { + // Run through requests queue + for (std::deque::iterator i(requests.begin()), end(requests.end()); i != end; ++i) + { + // Identify requests associated to (nearly) unmapped plugin context + if (i->pCtx == plugin->GetBaseContext()) + { + // All context related data and callbacks are marked invalid + i->pCtx = NULL; + i->contextPack.pCallbackFunction = NULL; + } + } + } + + pRequestsLock->Unlock(); + } + + // Wait for running requests to finish + if (!threads.empty()) + { + for (std::list::iterator i(threads.begin()), end(threads.end()); i != end; ++i) + { + if ((*i) != NULL) + { + (*i)->WaitForThread(); + // NOTE: do not remove handles here as it would break + // the iteration. Dead thread handles are destroyed + // on the next available game frame in the main thread + + // Check for pending callbacks and cancel them + { + pCallbacksLock->Lock(); + + if (!callbacks.empty()) + { + // Run through callback queue + for (std::deque::iterator i(callbacks.begin()), end(callbacks.end()); i != end; ++i) + { + // Identify callbacks associated to (nearly) unmapped plugin context + if (i->pCtx == plugin->GetBaseContext()) + { + // All context related data and callbacks are marked invalid + i->pCtx = NULL; + i->contextPack.pCallbackFunction = NULL; + } + } + } + + pCallbacksLock->Unlock(); + } + } + } + } +} + +/************************************************************************/ +/* NEW CODE */ +/************************************************************************/ +void HTTPSessionManager::PostAndDownload( IPluginContext *pCtx, + HTTPRequestHandleSet handles, const char *url, + HTTPRequestCompletedContextPack contextPack ) +{ + HTTPRequest request; + BurnSessionHandle(pCtx, handles); + + request.pCtx = pCtx; + request.handles = handles; + request.method = HTTP_POST; + request.url = url; + request.contextPack = contextPack; + + pRequestsLock->Lock(); + this->requests.push_front(request); + pRequestsLock->Unlock(); +} + +/************************************************************************/ +/* NEW CODE */ +/************************************************************************/ +void HTTPSessionManager::Download( IPluginContext *pCtx, + HTTPRequestHandleSet handles, const char *url, + HTTPRequestCompletedContextPack contextPack ) +{ + HTTPRequest request; + BurnSessionHandle(pCtx, handles); + + request.pCtx = pCtx; + request.handles = handles; + request.method = HTTP_GET; + request.url = url; + request.contextPack = contextPack; + + pRequestsLock->Lock(); + this->requests.push_front(request); + pRequestsLock->Unlock(); +} + +/************************************************************************/ +/* NEW CODE */ +/************************************************************************/ +void HTTPSessionManager::BurnSessionHandle( IPluginContext * pCtx, HTTPRequestHandleSet &handles ) +{ + HandleSecurity sec; + sec.pOwner = pCtx->GetIdentity(); + sec.pIdentity = myself->GetIdentity(); + + // TODO: maybe better way to do this? + // Make session handle inaccessible to the user + Handle_t hndlNew = g_pHandleSys->FastCloneHandle(handles.hndlSession); + if (g_pHandleSys->FreeHandle(handles.hndlSession, &sec) != + HandleError_None) + { + pCtx->ThrowNativeError("Couldn't free HTTP session handle"); + return; + } + + handles.hndlSession = hndlNew; +} + +/************************************************************************/ +/* NEW CODE */ +/************************************************************************/ +void HTTPSessionManager::RunFrame() +{ + // Try to execute pending callbacks + if (this->pCallbacksLock->TryLock()) + { + if (!this->callbacks.empty()) + { + HTTPRequest request = this->callbacks.front(); + IPluginContext *pCtx = request.pCtx; + + // Is the requesting plugin still alive? + if (pCtx != NULL) + { + // TODO: this may be unnecessary + if (plsys->FindPluginByContext(request.pCtx->GetContext())) + { + funcid_t id = request.contextPack.pCallbackFunction->uPluginFunction; + IPluginFunction *pFunction = NULL; + pFunction = pCtx->GetFunctionById(id); + + if (pFunction != NULL) + { + // Push data and execute callback + pFunction->PushCell(request.handles.hndlSession); + pFunction->PushCell(request.result); + pFunction->PushCell(request.handles.hndlDownloader); + if (request.contextPack.pCallbackFunction->bHasContext) + { + pFunction->PushCell(request.contextPack.iPluginContextValue); + } + pFunction->Execute(NULL); + } + } + } + + this->callbacks.pop_front(); + } + + this->pCallbacksLock->Unlock(); + } + + // Try to fire up some new asynchronous requests + if (pRequestsLock->TryLock()) + { + if (!this->requests.empty()) + { + // NOTE: this is my "burst thread creation" solution + // Using a thread pool is slow as it executes the threads + // sequentially and not parallel. + // Not using a thread pool might cause SRCDS to crash, so + // we are spawning just a few threads every frame to not + // affect performance too much and still having the advantage + // of parallel execution. + for (unsigned int i = 0; i < iMaxRequestsPerFrame; i++) + { + // Create new thread object + HTTPAsyncRequestHandler *async = + new HTTPAsyncRequestHandler(this->requests.front()); + // Skip requests with unloaded parent plugin + if (this->requests.front().pCtx != NULL) + { + // Create new thread + IThreadHandle *pThread = + threader->MakeThread(async, Thread_Default); + // Save thread handle + this->threads.push_front(pThread); + } + // Remove request as it's being handled now + this->requests.pop_front(); + } + } + + pRequestsLock->Unlock(); + } + + // Do some quick "garbage collection" on finished threads + if (!this->threads.empty()) + { + for (std::list::iterator i(threads.begin()), end(threads.end()); i != end; ++i) + { + if ((*i) != NULL) + { + if ((*i)->GetState() == Thread_Done) + { + (*i)->DestroyThis(); + this->threads.remove((*i)); + // NOTE: this action breaks the iteration so we have + // to leave the loop and start over on next frame + break; + } + } + } + } +} + +/************************************************************************/ +/* NEW CODE */ +/************************************************************************/ +void HTTPSessionManager::Initialize() +{ + pRequestsLock = threader->MakeMutex(); + pCallbacksLock = threader->MakeMutex(); +} + +/************************************************************************/ +/* NEW CODE */ +/************************************************************************/ +void HTTPSessionManager::Cleanup() +{ + if (pRequestsLock != NULL) + { + pRequestsLock->DestroyThis(); + } + + if (pCallbacksLock != NULL) + { + pCallbacksLock->DestroyThis(); + } +} + +/************************************************************************/ +/* NEW CODE */ +/************************************************************************/ +void HTTPSessionManager::AddCallback( HTTPRequest request ) +{ + this->pCallbacksLock->Lock(); + this->callbacks.push_front(request); + this->pCallbacksLock->Unlock(); +} + +/************************************************************************/ +/* NEW CODE */ +/************************************************************************/ +void HTTPSessionManager::HTTPAsyncRequestHandler::RunThread( IThreadHandle *pHandle ) +{ + HandleError err; + HandleSecurity sec; + sec.pOwner = this->request.pCtx->GetIdentity(); + sec.pIdentity = myself->GetIdentity(); + + IWebTransfer *xfer = NULL; + g_pHandleSys->ReadHandle(this->request.handles.hndlSession, + g_SessionHandle, &sec, (void **)&xfer); + + IBaseDownloader *downldr = NULL; + g_pHandleSys->ReadHandle(this->request.handles.hndlDownloader, + g_DownloadHandle, &sec, (void **)&downldr); + + switch (this->request.method) + { + case HTTP_GET: + this->request.result = + xfer->Download(this->request.url, downldr, NULL); + break; + case HTTP_POST: + IWebForm *form = NULL; + g_pHandleSys->ReadHandle(this->request.handles.hndlForm, + g_FormHandle, &sec, (void **)&form); + + this->request.result = + xfer->PostAndDownload(this->request.url, form, downldr, NULL); + break; + } + + // DEBUG + //g_pHandleSys->FreeHandle(this->request.handles.hndlDownloader, &sec); + //smutils->AddFrameAction(ExecuteCallback, new HTTPRequest(this->request)); + g_SessionManager.AddCallback(request); +} diff --git a/extensions/curl/extension.h b/extensions/curl/extension.h index 9241961b8..7efea50cf 100644 --- a/extensions/curl/extension.h +++ b/extensions/curl/extension.h @@ -38,13 +38,17 @@ */ #include "smsdk_ext.h" +#include "IWebternet.h" +#include "IBaseDownloader.h" +#include +#include /** * @brief Sample implementation of the SDK Extension. * Note: Uncomment one of the pre-defined virtual functions in order to use it. */ -class CurlExt : public SDKExtension +class CurlExt : public SDKExtension, IPluginsListener { public: /** @@ -83,6 +87,9 @@ public: //virtual bool QueryRunning(char *error, size_t maxlength); const char *GetExtensionVerString(); const char *GetExtensionDateString(); + + virtual void OnPluginUnloaded( IPlugin *plugin ); + public: #if defined SMEXT_CONF_METAMOD /** @@ -121,4 +128,146 @@ public: size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap); +// Handle helper class +class SessionHandler : public IHandleTypeDispatch +{ +public: + virtual void OnHandleDestroy( HandleType_t type, void *object ) + { + delete ((IWebTransfer *)object); + } +}; + +extern SessionHandler g_SessionHandler; +extern HandleType_t g_SessionHandle; + +class FormHandler : public IHandleTypeDispatch +{ + virtual void OnHandleDestroy( HandleType_t type, void *object ) + { + delete ((IWebForm *)object); + } +}; + +extern FormHandler g_FormHandler; +extern HandleType_t g_FormHandle; + +class DownloadHandler : public IHandleTypeDispatch +{ + virtual void OnHandleDestroy( HandleType_t type, void *object ) + { + delete ((IBaseDownloader *)object); + } +}; + +extern DownloadHandler g_DownloadHandler; +extern HandleType_t g_DownloadHandle; + +struct HTTPRequestCompletedContextFunction { + // NOTE: deprecated! + IPluginContext *pContext; + funcid_t uPluginFunction; + bool bHasContext; +}; + +union HTTPRequestCompletedContextPack { + uint64_t ulContextValue; + struct { + HTTPRequestCompletedContextFunction *pCallbackFunction; + cell_t iPluginContextValue; + }; +}; + + +/************************************************************************/ +/* NEW CODE */ +/************************************************************************/ +struct HTTPRequestHandleSet +{ + Handle_t hndlSession; + Handle_t hndlDownloader; + Handle_t hndlForm; +}; + +class HTTPSessionManager +{ +public: + static HTTPSessionManager& instance() + { + static HTTPSessionManager _instance; + return _instance; + } + ~HTTPSessionManager() {} + + void Initialize(); + void Cleanup(); + void PluginUnloaded(IPlugin *plugin); + void RunFrame(); + void BurnSessionHandle(IPluginContext * pCtx, HTTPRequestHandleSet &handles); + void PostAndDownload(IPluginContext *pCtx, + HTTPRequestHandleSet handles, + const char *url, + HTTPRequestCompletedContextPack contextPack); + void Download(IPluginContext *pCtx, + HTTPRequestHandleSet handles, + const char *url, + HTTPRequestCompletedContextPack contextPack); +protected: + +private: + HTTPSessionManager() {} + HTTPSessionManager(const HTTPSessionManager&); + HTTPSessionManager & operator = (const HTTPSessionManager &); + + enum HTTPRequestMethod + { + HTTP_GET, + HTTP_POST + }; + + struct HTTPRequest + { + IPluginContext *pCtx; + HTTPRequestMethod method; + HTTPRequestHandleSet handles; + const char *url; + HTTPRequestCompletedContextPack contextPack; + cell_t result; + }; + + static const unsigned int iMaxRequestsPerFrame = 20; + IMutex *pRequestsLock; + std::deque requests; + // NOTE: this needs no lock since it's only accessed from main thread + std::list threads; + IMutex *pCallbacksLock; + std::deque callbacks; + + class HTTPAsyncRequestHandler : public IThread + { + public: + HTTPAsyncRequestHandler(HTTPRequest request) + { + this->request = request; + } + ~HTTPAsyncRequestHandler() {} + protected: + private: + HTTPRequest request; + virtual void RunThread( IThreadHandle *pHandle ); + virtual void OnTerminate( IThreadHandle *pHandle, bool cancel ) + { + delete this; + } + static void ExecuteCallback(void *data); + }; + + void AddCallback(HTTPRequest request); +}; + +void OnGameFrame(bool simulating); + +// Natives +extern const sp_nativeinfo_t curlext_natives[]; + #endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/curl/msvc10/curl.sln b/extensions/curl/msvc10/curl.sln new file mode 100644 index 000000000..9e47eaab9 --- /dev/null +++ b/extensions/curl/msvc10/curl.sln @@ -0,0 +1,98 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curl", "curl.vcxproj", "{B3E797CF-4E77-4C9D-B8A8-7589B6902206}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curllib", "..\curl-src\lib\curllib.vcxproj", "{32E22C76-2FE8-2308-E702-DB81C76357DB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "curlsrc", "..\curl-src\src\curlsrc.vcxproj", "{1E99F660-6BDD-C14B-4931-6D6FCFB83177}" + ProjectSection(ProjectDependencies) = postProject + {32E22C76-2FE8-2308-E702-DB81C76357DB} = {32E22C76-2FE8-2308-E702-DB81C76357DB} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + DLL Debug|Win32 = DLL Debug|Win32 + DLL Release|Win32 = DLL Release|Win32 + LIB Debug|Win32 = LIB Debug|Win32 + LIB Release|Win32 = LIB Release|Win32 + Release|Win32 = Release|Win32 + Template|Win32 = Template|Win32 + using libcurl DLL Debug|Win32 = using libcurl DLL Debug|Win32 + using libcurl DLL Release|Win32 = using libcurl DLL Release|Win32 + using libcurl LIB Debug|Win32 = using libcurl LIB Debug|Win32 + using libcurl LIB Release|Win32 = using libcurl LIB Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.ActiveCfg = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.Build.0 = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.DLL Debug|Win32.Build.0 = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.DLL Release|Win32.ActiveCfg = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.DLL Release|Win32.Build.0 = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.LIB Debug|Win32.ActiveCfg = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.LIB Debug|Win32.Build.0 = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.LIB Release|Win32.ActiveCfg = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.LIB Release|Win32.Build.0 = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.ActiveCfg = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.Build.0 = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Template|Win32.ActiveCfg = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Template|Win32.Build.0 = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.using libcurl DLL Debug|Win32.ActiveCfg = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.using libcurl DLL Debug|Win32.Build.0 = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.using libcurl DLL Release|Win32.ActiveCfg = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.using libcurl DLL Release|Win32.Build.0 = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.using libcurl LIB Debug|Win32.ActiveCfg = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.using libcurl LIB Debug|Win32.Build.0 = Debug|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.using libcurl LIB Release|Win32.ActiveCfg = Release|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.using libcurl LIB Release|Win32.Build.0 = Release|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.Debug|Win32.ActiveCfg = LIB Debug|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.Debug|Win32.Build.0 = LIB Debug|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.DLL Release|Win32.Build.0 = DLL Release|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.LIB Release|Win32.Build.0 = LIB Release|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.Release|Win32.ActiveCfg = LIB Release|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.Release|Win32.Build.0 = LIB Release|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.Template|Win32.ActiveCfg = LIB Release|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.Template|Win32.Build.0 = LIB Release|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.using libcurl DLL Debug|Win32.ActiveCfg = DLL Debug|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.using libcurl DLL Debug|Win32.Build.0 = DLL Debug|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.using libcurl DLL Release|Win32.ActiveCfg = DLL Release|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.using libcurl DLL Release|Win32.Build.0 = DLL Release|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.using libcurl LIB Debug|Win32.ActiveCfg = LIB Debug|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.using libcurl LIB Debug|Win32.Build.0 = LIB Debug|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.using libcurl LIB Release|Win32.ActiveCfg = LIB Release|Win32 + {32E22C76-2FE8-2308-E702-DB81C76357DB}.using libcurl LIB Release|Win32.Build.0 = LIB Release|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.Debug|Win32.ActiveCfg = using libcurl LIB Debug|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.Debug|Win32.Build.0 = using libcurl LIB Debug|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.DLL Debug|Win32.ActiveCfg = using libcurl DLL Debug|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.DLL Debug|Win32.Build.0 = using libcurl DLL Debug|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.DLL Release|Win32.ActiveCfg = using libcurl DLL Release|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.DLL Release|Win32.Build.0 = using libcurl DLL Release|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.LIB Debug|Win32.ActiveCfg = using libcurl LIB Debug|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.LIB Debug|Win32.Build.0 = using libcurl LIB Debug|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.LIB Release|Win32.ActiveCfg = using libcurl LIB Release|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.LIB Release|Win32.Build.0 = using libcurl LIB Release|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.Release|Win32.ActiveCfg = using libcurl LIB Release|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.Release|Win32.Build.0 = using libcurl LIB Release|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.Template|Win32.ActiveCfg = Template|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.Template|Win32.Build.0 = Template|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.using libcurl DLL Debug|Win32.ActiveCfg = using libcurl DLL Debug|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.using libcurl DLL Debug|Win32.Build.0 = using libcurl DLL Debug|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.using libcurl DLL Release|Win32.ActiveCfg = using libcurl DLL Release|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.using libcurl DLL Release|Win32.Build.0 = using libcurl DLL Release|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.using libcurl LIB Debug|Win32.ActiveCfg = using libcurl LIB Debug|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.using libcurl LIB Debug|Win32.Build.0 = using libcurl LIB Debug|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.using libcurl LIB Release|Win32.ActiveCfg = using libcurl LIB Release|Win32 + {1E99F660-6BDD-C14B-4931-6D6FCFB83177}.using libcurl LIB Release|Win32.Build.0 = using libcurl LIB Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/curl/smsdk_config.h b/extensions/curl/smsdk_config.h index ee2fbdf2e..ed6ba9ba6 100644 --- a/extensions/curl/smsdk_config.h +++ b/extensions/curl/smsdk_config.h @@ -60,18 +60,18 @@ /** Enable interfaces you want to use here by uncommenting lines */ //#define SMEXT_ENABLE_FORWARDSYS -//#define SMEXT_ENABLE_HANDLESYS +#define SMEXT_ENABLE_HANDLESYS //#define SMEXT_ENABLE_PLAYERHELPERS //#define SMEXT_ENABLE_DBMANAGER //#define SMEXT_ENABLE_GAMECONF //#define SMEXT_ENABLE_MEMUTILS //#define SMEXT_ENABLE_GAMEHELPERS //#define SMEXT_ENABLE_TIMERSYS -//#define SMEXT_ENABLE_THREADER +#define SMEXT_ENABLE_THREADER //#define SMEXT_ENABLE_LIBSYS //#define SMEXT_ENABLE_MENUS //#define SMEXT_ENABLE_ADTFACTORY -//#define SMEXT_ENABLE_PLUGINSYS +#define SMEXT_ENABLE_PLUGINSYS //#define SMEXT_ENABLE_ADMINSYS //#define SMEXT_ENABLE_TEXTPARSERS //#define SMEXT_ENABLE_USERMSGS diff --git a/extensions/curl/version.rc b/extensions/curl/version.rc index e62259257..ee3baa3f6 100644 --- a/extensions/curl/version.rc +++ b/extensions/curl/version.rc @@ -50,7 +50,7 @@ BEGIN VALUE "FileVersion", SM_VERSION_STRING VALUE "InternalName", "SourceMod Webternet Extension" VALUE "LegalCopyright", "Copyright (c) 2004-2009, AlliedModders LLC" - VALUE "OriginalFilename", BINARY_NAME + VALUE "OriginalFilename", "webternet.ext.dll" VALUE "ProductName", "SourceMod Webternet Extension" VALUE "ProductVersion", SM_VERSION_STRING END diff --git a/plugins/include/webternet.inc b/plugins/include/webternet.inc new file mode 100644 index 000000000..7ff458468 --- /dev/null +++ b/plugins/include/webternet.inc @@ -0,0 +1,58 @@ +#if defined _webternet_included + #endinput +#endif + +#define _webternet_included + +#define HTTP_OK 1 +#define HTTP_ERROR 0 + +funcenum HTTP_SessionCallback { + public(Handle:session, result), + public(Handle:session, result, Handle:downloader), + public(Handle:session, result, Handle:downloader, any:data), +}; + +native Handle:HTTP_CreateSession(); + +native HTTP_SetFailOnHTTPError(Handle:session, bool:fail); + +native HTTP_GetLastError(Handle:session, String:error[], maxlen); + +native Handle:HTTP_CreateFileDownloader(const String:file[]); + +native Handle:HTTP_CreateMemoryDownloader(); + +native HTTP_Download(Handle:session, Handle:downloader, const String:url[], HTTP_SessionCallback:callback, any:data = INVALID_HANDLE); + +native HTTP_PostAndDownload(Handle:session, Handle:downloader, Handle:form, const String:url[], HTTP_SessionCallback:callback, any:data = INVALID_HANDLE); + +native Handle:HTTP_CreateWebForm(); + +native HTTP_AddStringToWebForm(Handle:form, const String:name[], const String:data[]); + +native HTTP_AddFileToWebForm(Handle:form, const String:name[], const String:path[]); + +native HTTP_GetBodySize(Handle:downloader); + +native HTTP_GetBodyContent(Handle:downloader, String:body[], maxlen); + + +/** + * Do not edit below this line! + */ +public Extension:__ext_webternet = +{ + name = "webternet", + file = "webternet.ext", +#if defined AUTOLOAD_EXTENSIONS + autoload = 1, +#else + autoload = 0, +#endif +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; diff --git a/tools/gamedata_md5/msvc9/gamedatamd5.sln b/tools/gamedata_md5/msvc9/gamedatamd5.sln deleted file mode 100644 index 3f7872324..000000000 --- a/tools/gamedata_md5/msvc9/gamedatamd5.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gamedatamd5", "gamedatamd5.vcproj", "{E1C96598-E1AC-4928-8930-F8B6CD245B12}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E1C96598-E1AC-4928-8930-F8B6CD245B12}.Debug|Win32.ActiveCfg = Debug|Win32 - {E1C96598-E1AC-4928-8930-F8B6CD245B12}.Debug|Win32.Build.0 = Debug|Win32 - {E1C96598-E1AC-4928-8930-F8B6CD245B12}.Release|Win32.ActiveCfg = Release|Win32 - {E1C96598-E1AC-4928-8930-F8B6CD245B12}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/tools/gamedata_md5/msvc9/gamedatamd5.vcproj b/tools/gamedata_md5/msvc9/gamedatamd5.vcproj deleted file mode 100644 index 835ebf848..000000000 --- a/tools/gamedata_md5/msvc9/gamedatamd5.vcproj +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -