Advertisement
BigETI

main.cpp - sampshell

Nov 22nd, 2014
433
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.99 KB | None | 0 0
  1. #include "main.h"
  2.  
  3. typedef void(*logprintf_t)(char* format, ...);
  4. logprintf_t logprintf;
  5. extern void *pAMXFunctions;
  6.  
  7. static CTR<CallbackInfo *> callbacks;
  8. static std::mutex mtx;
  9. static std::list<CMDRet *> cmd_rets;
  10. static CTR<ShellThread *> shell_threads;
  11. static std::map<AMX *, CallbackInfo *> cb_map;
  12.  
  13. void command_thread(ShellThread *shell_thread)
  14. {
  15. #ifdef PLUGIN_DEBUG
  16.     logprintf("command_thread() call");
  17. #endif
  18.     shell_thread->ThreadedCall();
  19. #ifdef PLUGIN_DEBUG
  20.     logprintf("command_thread() end");
  21. #endif
  22. }
  23.  
  24. template <class _T> void CTR<_T>::Add(_T ptr)
  25. {
  26. #ifdef PLUGIN_DEBUG
  27.     logprintf("CTR<_T>::Add() call");
  28. #endif
  29.     static typename std::list<_T>::iterator value;
  30.     if (_map.find(ptr) == _map.end())
  31.     {
  32.         try
  33.         {
  34.             _list.push_back(ptr);
  35.         }
  36.         catch (...)
  37.         {
  38.             throw EXCEPTION::OUT_OF_MEMORY;
  39.         }
  40.         value = _list.end();
  41.         try
  42.         {
  43.             _map[ptr] = (--value);
  44.         }
  45.         catch (...)
  46.         {
  47.             _list.pop_back();
  48.             throw EXCEPTION::OUT_OF_MEMORY;
  49.         }
  50.     }
  51. #ifdef PLUGIN_DEBUG
  52.     logprintf("CTR<_T>::Add() end");
  53. #endif
  54. }
  55.  
  56. template <class _T> typename std::list<_T>::iterator CTR<_T>::Delete(_T ptr)
  57. {
  58. #ifdef PLUGIN_DEBUG
  59.     logprintf("CTR<_T>::Delete() call");
  60. #endif
  61.     static typename std::list<_T>::iterator ret = _list.end();
  62.     static typename std::list<_T>::iterator *value;
  63.     try
  64.     {
  65.         ret = _list.erase(*(value = &(_map.at(ptr))));
  66.         (*value) = _list.end();
  67.     }
  68.     catch (...) {}
  69. #ifdef PLUGIN_DEBUG
  70.     logprintf("CTR<_T>::Delete() end");
  71. #endif
  72.     return ret;
  73. }
  74.  
  75. template <class _T> bool CTR<_T>::Exists(_T ptr)
  76. {
  77. #ifdef PLUGIN_DEBUG
  78.     logprintf("CTR<_T>::Exists() call and end");
  79. #endif
  80.     return _map.find(ptr) == _map.end() ? false : (_map[ptr] != _list.end());
  81. }
  82.  
  83. template <class _T> void CTR<_T>::Clear()
  84. {
  85. #ifdef PLUGIN_DEBUG
  86.     logprintf("CTR<_T>::Clear() call");
  87. #endif
  88.     _map.clear();
  89.     _list.clear();
  90. #ifdef PLUGIN_DEBUG
  91.     logprintf("CTR<_T>::Clear() end");
  92. #endif
  93. }
  94.  
  95. template <class _T> void CTR<_T>::CleanUp()
  96. {
  97. #ifdef PLUGIN_DEBUG
  98.     logprintf("CTR<_T>::CleanUp() call");
  99. #endif
  100.     typedef typename std::list<_T>::iterator listit;
  101.     static typename std::map<_T, listit>::iterator _it;
  102.     for (_it = _map.begin(); _it != _map.end(); ++_it)
  103.     {
  104.         map_foreach_begin:
  105.         if (_it->second == _list.end())
  106.         {
  107.             _map.erase(_it);
  108.             if ((_it = _map.begin()) == _map.end()) break;
  109.             goto map_foreach_begin;
  110.         }
  111.     }
  112. #ifdef PLUGIN_DEBUG
  113.     logprintf("CTR<_T>::CleanUp() end");
  114. #endif
  115. }
  116.  
  117. template <class _T> void CTR<_T>::Destruct()
  118. {
  119. #ifdef PLUGIN_DEBUG
  120.     logprintf("CTR<_T>::Destruct() call");
  121. #endif
  122.     static typename std::list<_T>::iterator _it;
  123.     while ((_it = _list.begin()) != _list.end()) delete (*_it);
  124. #ifdef PLUGIN_DEBUG
  125.     logprintf("CTR<_T>::Destruct() end");
  126. #endif
  127. }
  128.  
  129. ShellThread::ShellThread(std::string *exec_str) : joinable(false), quit_it(false)
  130. {
  131. #ifdef PLUGIN_DEBUG
  132.     logprintf("ShellThread::ShellThread() call");
  133. #endif
  134.     if (pipe_handle = ETI_popen((*exec_str).c_str(), "r"))
  135.     {
  136.         try
  137.         {
  138.             thread = new std::thread(command_thread, this);
  139.         }
  140.         catch (...)
  141.         {
  142.             throw EXCEPTION::OUT_OF_MEMORY;
  143.         }
  144.     }
  145.     else
  146.     {
  147.         throw EXCEPTION::PIPE_OPEN_FAILED;
  148.     }
  149. #ifdef PLUGIN_DEBUG
  150.     logprintf("ShellThread::ShellThread() end");
  151. #endif
  152. }
  153.  
  154. ShellThread::~ShellThread()
  155. {
  156. #ifdef PLUGIN_DEBUG
  157.     logprintf("ShellThread::~ShellThread() call");
  158. #endif
  159.     delete thread;
  160.     shell_threads.Delete(this);
  161. #ifdef PLUGIN_DEBUG
  162.     logprintf("ShellThread::~ShellThread() end");
  163. #endif
  164. }
  165.  
  166. void ShellThread::ThreadedCall()
  167. {
  168. #ifdef PLUGIN_DEBUG
  169.     logprintf("ShellThread::ThreadedCall() call");
  170. #endif
  171.     CMDRet *ret = NULL;
  172.     char buf[BUF_LEN];
  173.     if (pipe_handle)
  174.     {
  175.         while (fgets(buf, BUF_LEN * sizeof(char), pipe_handle))
  176.         {
  177.             try
  178.             {
  179.                 ret = new CMDRet;
  180.             }
  181.             catch (...)
  182.             {
  183.                 ret = NULL;
  184.             }
  185.             if (ret)
  186.             {
  187.                 ret->handle = (cell)this;
  188.                 ret->str = buf;
  189.                 mtx.lock();
  190.                 cmd_rets.push_back(ret);
  191.                 mtx.unlock();
  192.             }
  193.             if (quit_it) break;
  194.         }
  195.         ETI_pclose(pipe_handle);
  196.     }
  197.     joinable = true;
  198. #ifdef PLUGIN_DEBUG
  199.     logprintf("ShellThread::ThreadedCall() end");
  200. #endif
  201. }
  202.  
  203. void ShellThread::CloseHandle()
  204. {
  205. #ifdef PLUGIN_DEBUG
  206.     logprintf("ShellThread::CloseHandle() call");
  207. #endif
  208.     mtx.lock();
  209.     quit_it = true;
  210.     mtx.unlock();
  211. #ifdef PLUGIN_DEBUG
  212.     logprintf("ShellThread::CloseHandle() end");
  213. #endif
  214. }
  215.  
  216. std::thread *ShellThread::GetThread()
  217. {
  218. #ifdef PLUGIN_DEBUG
  219.     logprintf("ShellThread::GetThread() call");
  220. #endif
  221.     return thread;
  222. #ifdef PLUGIN_DEBUG
  223.     logprintf("ShellThread::GetThread() end");
  224. #endif
  225. }
  226.  
  227. bool ShellThread::Joinable()
  228. {
  229. #ifdef PLUGIN_DEBUG
  230.     logprintf("ShellThread::Joinable() call");
  231. #endif
  232.     return joinable;
  233. #ifdef PLUGIN_DEBUG
  234.     logprintf("ShellThread::Joinable() end");
  235. #endif
  236. }
  237.  
  238. static ShellThread *CreateShell(AMX *amx, std::string *exec_str)
  239. {
  240. #ifdef PLUGIN_DEBUG
  241.     logprintf("CreateShell() call");
  242. #endif
  243.     ShellThread *ret = NULL;
  244.     try
  245.     {
  246.         ret = new ShellThread(exec_str);
  247.     }
  248.     catch (...)
  249.     {
  250.         ret = NULL;
  251.     }
  252.     if (ret)
  253.     {
  254.         try
  255.         {
  256.             shell_threads.Add(ret);
  257.         }
  258.         catch (...)
  259.         {
  260.             delete ret;
  261.             ret = NULL;
  262.         }
  263.     }
  264. #ifdef PLUGIN_DEBUG
  265.     logprintf("CreateShell() end");
  266. #endif
  267.     return ret;
  268. }
  269.  
  270. // native Shell:SHELL_Execute(const cmd[]);
  271. cell AMX_NATIVE_CALL AMX_SHELL_Execute(AMX *amx, cell *params)
  272. {
  273. #ifdef PLUGIN_DEBUG
  274.     logprintf("AMX_SHELL_Execute() call");
  275. #endif
  276.     ShellThread *ret = NULL;
  277.     cell *addr;
  278.     std::string *exec_str = NULL;
  279.     try
  280.     {
  281.         exec_str = new std::string;
  282.     }
  283.     catch (...)
  284.     {
  285.         exec_str = NULL;
  286.     }
  287.     if (exec_str)
  288.     {
  289.         amx_GetAddr(amx, params[1], &addr);
  290.         for (cell *qs = addr; *qs != 0; qs++) (*exec_str) += ((char)(*qs));
  291.         if ((ret = CreateShell(amx, exec_str)) == NULL) delete exec_str;
  292.     }
  293. #ifdef PLUGIN_DEBUG
  294.     logprintf("AMX_SHELL_Execute() end");
  295. #endif
  296.     return (cell)ret;
  297. }
  298.  
  299. // native SHELL_System(const cmd[]);
  300. cell AMX_NATIVE_CALL AMX_SHELL_System(AMX *amx, cell *params)
  301. {
  302.     std::string exec_str;
  303.     cell *addr;
  304.     amx_GetAddr(amx, params[1], &addr);
  305.     for (cell *qs = addr; *qs != 0; qs++) exec_str += ((char)(*qs));
  306.     return ((cell)(system(exec_str.c_str())));
  307. }
  308.  
  309. // native SHELL_IsActive(Shell:handle);
  310. cell AMX_NATIVE_CALL AMX_SHELL_IsActive(AMX *amx, cell *params)
  311. {
  312. #ifdef PLUGIN_DEBUG
  313.     logprintf("AMX_SHELL_IsActive() call and end");
  314. #endif
  315.     return (cell)(shell_threads.Exists((ShellThread *)(params[1])));
  316. }
  317.  
  318. // native SHELL_Release(Shell:handle);
  319. cell AMX_NATIVE_CALL AMX_SHELL_Release(AMX *amx, cell *params)
  320. {
  321. #ifdef PLUGIN_DEBUG
  322.     logprintf("AMX_SHELL_Release() call");
  323. #endif
  324.     if (shell_threads.Exists((ShellThread *)(params[1]))) ((ShellThread *)(params[1]))->CloseHandle();
  325. #ifdef PLUGIN_DEBUG
  326.     logprintf("AMX_SHELL_Release() end");
  327. #endif
  328.     return 1;
  329. }
  330.  
  331. // native SHELL_ReleaseAll();
  332. cell AMX_NATIVE_CALL AMX_SHELL_ReleaseAll(AMX *amx, cell *params)
  333. {
  334. #ifdef PLUGIN_DEBUG
  335.     logprintf("AMX_SHELL_ReleaseAll() call");
  336. #endif
  337.     list_foreach(ShellThread *, shell_threads._list, shell_threads_it) (*shell_threads_it)->CloseHandle();
  338. #ifdef PLUGIN_DEBUG
  339.     logprintf("AMX_SHELL_ReleaseAll() end");
  340. #endif
  341.     return 1;
  342. }
  343.  
  344. // native SHELL_MEM_CleanUp();
  345. cell AMX_NATIVE_CALL AMX_SHELL_MEM_CleanUp(AMX *amx, cell *params)
  346. {
  347. #ifdef PLUGIN_DEBUG
  348.     logprintf("AMX_SHELL_CleanUp() call");
  349. #endif
  350.     callbacks.CleanUp();
  351.     shell_threads.CleanUp();
  352. #ifdef PLUGIN_DEBUG
  353.     logprintf("AMX_SHELL_CleanUp() end");
  354. #endif
  355.     return 1;
  356. }
  357. PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports()
  358. {
  359.     return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES | SUPPORTS_PROCESS_TICK;
  360. }
  361.  
  362. PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData)
  363. {
  364.     pAMXFunctions = ppData[PLUGIN_DATA_AMX_EXPORTS];
  365.     logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];
  366.     logprintf("/====================\\");
  367.     logprintf("| SA:MP Shell Plugin |");
  368.     logprintf("|     Made by BigETI |");
  369.     logprintf("| Loaded!            |");
  370.     logprintf("\\====================/");
  371.     return true;
  372. }
  373.  
  374. PLUGIN_EXPORT void PLUGIN_CALL Unload()
  375. {
  376.     callbacks.Destruct();
  377.     shell_threads.Destruct();
  378.     logprintf("/====================\\");
  379.     logprintf("| SA:MP Shell Plugin |");
  380.     logprintf("|     Made by BigETI |");
  381.     logprintf("| Unloaded!          |");
  382.     logprintf("\\====================/");
  383. }
  384.  
  385. AMX_NATIVE_INFO PluginNatives[] =
  386. {
  387.     { "SHELL_Execute", AMX_SHELL_Execute },
  388.     { "SHELL_System", AMX_SHELL_System },
  389.     { "SHELL_IsActive", AMX_SHELL_IsActive },
  390.     { "SHELL_Release", AMX_SHELL_Release },
  391.     { "SHELL_ReleaseAll", AMX_SHELL_ReleaseAll },
  392.     { "SHELL_MEM_CleanUp ", AMX_SHELL_MEM_CleanUp },
  393.     { 0, 0 }
  394. };
  395.  
  396. PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx)
  397. {
  398.     int ret = 0;
  399.     CallbackInfo *cb_info = NULL;
  400.     try
  401.     {
  402.         cb_info = new CallbackInfo;
  403.     }
  404.     catch (...)
  405.     {
  406.         cb_info = NULL;
  407.     }
  408.     if (cb_info)
  409.     {
  410.         cb_info->amx = amx;
  411.         if (amx_FindPublic(amx, "OnReceiveShellMessage", &(cb_info->orsm_idx))) cb_info->orsm_idx = -1;
  412.         if (amx_FindPublic(amx, "OnReleaseShell", &(cb_info->ors_idx))) cb_info->ors_idx = -1;
  413.         try
  414.         {
  415.             callbacks.Add(cb_info);
  416.         }
  417.         catch (...)
  418.         {
  419.             delete cb_info;
  420.             cb_info = NULL;
  421.         }
  422.         cb_map[amx] = cb_info;
  423.         if (cb_info) ret = amx_Register(amx, PluginNatives, -1);
  424.     }
  425.     return ret;
  426. }
  427.  
  428. PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx)
  429. {
  430.     CallbackInfo *cb_info = cb_map[amx];
  431.     if (cb_info)
  432.     {
  433.         callbacks.Delete(cb_info);
  434.         delete cb_info;
  435.         cb_map.erase(amx);
  436.     }
  437.     callbacks.CleanUp();
  438.     shell_threads.CleanUp();
  439.     return AMX_ERR_NONE;
  440. }
  441.  
  442. PLUGIN_EXPORT void PLUGIN_CALL ProcessTick()
  443. {
  444. #ifdef PLUGIN_DEBUG
  445.     logprintf("ProcessTick() call");
  446. #endif
  447.     static std::list<CMDRet *>::iterator cmd_rets_it;
  448.     static std::list<CallbackInfo *>::iterator callbacks_it;
  449.     static std::list<ShellThread *>::iterator t_shell_threads_it;
  450.     static cell amx_addr, *phys_addr, retval;
  451.     mtx.lock();
  452.     while ((cmd_rets_it = cmd_rets.begin()) != cmd_rets.end())
  453.     {
  454.         for (callbacks_it = callbacks._list.begin(); callbacks_it != callbacks._list.end(); callbacks_it++)
  455.         {
  456.             if ((*callbacks_it)->orsm_idx != -1)
  457.             {
  458.                 amx_PushString((*callbacks_it)->amx, &amx_addr, &phys_addr, (*cmd_rets_it)->str.c_str(), 0, 0);
  459.                 amx_Push((*callbacks_it)->amx, (*cmd_rets_it)->handle);
  460.                 amx_Exec((*callbacks_it)->amx, &retval, (*callbacks_it)->orsm_idx);
  461.                 amx_Release((*callbacks_it)->amx, amx_addr);
  462.             }
  463.         }
  464.         delete (*cmd_rets_it);
  465.         cmd_rets.pop_front();
  466.     }
  467.     mtx.unlock();
  468.     list_foreach(ShellThread *, shell_threads._list, shell_threads_it)
  469.     {
  470.     shell_threads_begin:
  471.         if ((*shell_threads_it)->Joinable())
  472.         {
  473.             (*shell_threads_it)->GetThread()->join();
  474.             for (callbacks_it = callbacks._list.begin(); callbacks_it != callbacks._list.end(); callbacks_it++)
  475.             {
  476.                 if ((*callbacks_it)->ors_idx != -1)
  477.                 {
  478.                     amx_Push((*callbacks_it)->amx, (cell)(*shell_threads_it));
  479.                     amx_Exec((*callbacks_it)->amx, &retval, (*callbacks_it)->ors_idx);
  480.                 }
  481.             }
  482.             t_shell_threads_it = shell_threads_it;
  483.             t_shell_threads_it++;
  484.             delete (*shell_threads_it);
  485.             shell_threads_it = t_shell_threads_it;
  486.             if (shell_threads_it != shell_threads._list.end()) goto shell_threads_begin;
  487.         }
  488.     }
  489. #ifdef PLUGIN_DEBUG
  490.     logprintf("ProcessTick() end");
  491. #endif
  492. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement