]> git.sesse.net Git - casparcg/commitdiff
3568865: CLK server component can't handle more than one connection
authorhellgore <hellgore@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 19 Sep 2012 14:19:28 +0000 (14:19 +0000)
committerhellgore <hellgore@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 19 Sep 2012 14:19:28 +0000 (14:19 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/trunk@3320 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

protocol/clk/CLKProtocolStrategy.cpp
protocol/clk/CLKProtocolStrategy.h
protocol/protocol.vcxproj
protocol/protocol.vcxproj.filters
protocol/util/stateful_protocol_strategy_wrapper.cpp [new file with mode: 0644]
protocol/util/stateful_protocol_strategy_wrapper.h [new file with mode: 0644]
shell/server.cpp

index 4ce1a23e6133e8348a313c511785a541188186a7..dda74314bd6cb872062f261fbf47b95799174dad 100644 (file)
@@ -110,7 +110,9 @@ void CLKProtocolStrategy::Parse(const TCHAR* pData, int charCount, IO::ClientInf
                                }\r
                                else\r
                                {\r
-                                       CASPAR_LOG(debug) << L"CLK: Executed valid command: " \r                                         << currentCommandString_.str();\r                                }\r
+                                       CASPAR_LOG(debug) << L"CLK: Executed valid command: " \r
+                                               << currentCommandString_.str();\r
+                               }\r
                        } \r
                        catch (...)\r
                        {\r
index 89af7872aca1ec877c4def59af99941059924147..a2b8ab5dc717e8c43f3da2409237b16e8e22ac74 100644 (file)
 namespace caspar { namespace protocol { namespace CLK {\r
 \r
 /**\r
- * TODO:\r
- * Can only handle one connection at a time safely. Works with multiple if\r
- * every Parse call contains a complete command, but this will not happen if\r
- * the client sends one command in multiple chunks, then partial commands can\r
- * be interlieved with each other from different clients, causing the parser\r
- * to be confused.\r
+ * Can only handle one connection at a time safely, therefore it should be\r
+ * wrapped in a stateful_protocol_strategy_wrapper.\r
  */\r
 class CLKProtocolStrategy : public IO::IProtocolStrategy\r
 {\r
index cc0041a3dc12f3b5e9fd4336671495bdbd25333e..67fb832e686c3d72f2ba1813886af4c58718d4df 100644 (file)
@@ -48,6 +48,7 @@
     <ClInclude Include="util\ClientInfo.h" />\r
     <ClInclude Include="util\ProtocolStrategy.h" />\r
     <ClInclude Include="util\SocketInfo.h" />\r
+    <ClInclude Include="util\stateful_protocol_strategy_wrapper.h" />\r
     <ClInclude Include="util\Thread.h" />\r
   </ItemGroup>\r
   <ItemGroup>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
     </ClCompile>\r
+    <ClCompile Include="util\stateful_protocol_strategy_wrapper.cpp">\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+    </ClCompile>\r
     <ClCompile Include="util\Thread.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
index 6e323a49153340d08fecccf20546cfd9ae15e667..9f2e7d2fa6460335e705ba67b659ced4aa34ab2d 100644 (file)
@@ -64,6 +64,9 @@
     <ClInclude Include="clk\clk_commands.h">\r
       <Filter>source\clk</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="util\stateful_protocol_strategy_wrapper.h">\r
+      <Filter>source\util</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClCompile Include="amcp\AMCPCommandQueue.cpp">\r
     <ClCompile Include="clk\clk_commands.cpp">\r
       <Filter>source\clk</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="util\stateful_protocol_strategy_wrapper.cpp">\r
+      <Filter>source\util</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
diff --git a/protocol/util/stateful_protocol_strategy_wrapper.cpp b/protocol/util/stateful_protocol_strategy_wrapper.cpp
new file mode 100644 (file)
index 0000000..7c23e00
--- /dev/null
@@ -0,0 +1,75 @@
+/*\r
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
+*\r
+* This file is part of CasparCG (www.casparcg.com).\r
+*\r
+* CasparCG is free software: you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation, either version 3 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* CasparCG is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+* GNU General Public License for more details.\r
+*\r
+* You should have received a copy of the GNU General Public License\r
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
+*\r
+* Author: Helge Norberg, helge.norberg@svt.se\r
+*/\r
+\r
+#include "../StdAfx.h"\r
+\r
+#include "stateful_protocol_strategy_wrapper.h"\r
+\r
+namespace caspar { namespace IO {\r
+\r
+stateful_protocol_strategy_wrapper::stateful_protocol_strategy_wrapper(\r
+       const std::function<ProtocolStrategyPtr ()>& factory)\r
+       : factory_(factory)\r
+       , codepage_(factory()->GetCodepage())\r
+{\r
+}\r
+\r
+void stateful_protocol_strategy_wrapper::purge_dead_clients()\r
+{\r
+       for (auto it = strategies_.begin(); it != strategies_.end();)\r
+       {\r
+               auto strong = it->first.lock();\r
+\r
+               if (strong)\r
+                       ++it;\r
+               else\r
+                       it = strategies_.erase(it);\r
+       }\r
+}\r
+\r
+void stateful_protocol_strategy_wrapper::Parse(\r
+       const wchar_t* pData, int charCount, ClientInfoPtr pClientInfo)\r
+{\r
+       purge_dead_clients();\r
+\r
+       std::weak_ptr<ClientInfo> weak(pClientInfo);\r
+       ProtocolStrategyPtr strategy;\r
+       auto strategy_iter = strategies_.find(weak);\r
+\r
+       if (strategy_iter == strategies_.end())\r
+       {\r
+               strategy = factory_();\r
+               strategies_.insert(std::make_pair(weak, strategy));\r
+       }\r
+       else\r
+       {\r
+               strategy = strategy_iter->second;\r
+       }\r
+\r
+       strategy->Parse(pData, charCount, pClientInfo);\r
+}\r
+\r
+unsigned int stateful_protocol_strategy_wrapper::GetCodepage()\r
+{\r
+       return codepage_;\r
+}\r
+\r
+}}\r
diff --git a/protocol/util/stateful_protocol_strategy_wrapper.h b/protocol/util/stateful_protocol_strategy_wrapper.h
new file mode 100644 (file)
index 0000000..e6a66d3
--- /dev/null
@@ -0,0 +1,59 @@
+/*\r
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
+*\r
+* This file is part of CasparCG (www.casparcg.com).\r
+*\r
+* CasparCG is free software: you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation, either version 3 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* CasparCG is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+* GNU General Public License for more details.\r
+*\r
+* You should have received a copy of the GNU General Public License\r
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
+*\r
+* Author: Helge Norberg, helge.norberg@svt.se\r
+*/\r
+\r
+#pragma once\r
+\r
+#include "ProtocolStrategy.h"\r
+\r
+#include <functional>\r
+#include <map>\r
+#include <memory>\r
+\r
+namespace caspar { namespace IO {\r
+\r
+/**\r
+ * A protocol strategy which creates unique protocol strategy instances per\r
+ * client connection, using a supplied factory.\r
+ *\r
+ * This allows for the strategy implementation to only concern about one\r
+ * client.\r
+ */\r
+class stateful_protocol_strategy_wrapper : public IProtocolStrategy\r
+{\r
+       std::function<ProtocolStrategyPtr ()> factory_;\r
+       std::map<\r
+               std::weak_ptr<ClientInfo>, \r
+               ProtocolStrategyPtr, \r
+               std::owner_less<std::weak_ptr<ClientInfo>>> strategies_;\r
+       unsigned int codepage_;\r
+public:\r
+       stateful_protocol_strategy_wrapper(\r
+               const std::function<ProtocolStrategyPtr ()>& factory);\r
+\r
+       virtual void Parse(\r
+               const wchar_t* pData, int charCount, ClientInfoPtr pClientInfo);\r
+\r
+       virtual unsigned int GetCodepage();\r
+private:\r
+       void purge_dead_clients();\r
+};\r
+\r
+}}\r
index 4a3b06f49e23cde3744f211f84a3ad407c638ec2..bd3b5677d4d22f2e55557f2dc460af5f7590a708 100644 (file)
@@ -50,7 +50,7 @@
 #include <protocol/cii/CIIProtocolStrategy.h>\r
 #include <protocol/CLK/CLKProtocolStrategy.h>\r
 #include <protocol/util/AsyncEventServer.h>\r
-\r
+#include <protocol/util/stateful_protocol_strategy_wrapper.h>\r\r
 #include <boost/algorithm/string.hpp>\r
 #include <boost/lexical_cast.hpp>\r
 #include <boost/foreach.hpp>\r
@@ -182,7 +182,11 @@ struct server::implementation : boost::noncopyable
                else if(boost::iequals(name, L"CII"))\r
                        return make_safe<cii::CIIProtocolStrategy>(channels_);\r
                else if(boost::iequals(name, L"CLOCK"))\r
-                       return make_safe<CLK::CLKProtocolStrategy>(channels_);\r
+                       //return make_safe<CLK::CLKProtocolStrategy>(channels_);\r
+                       return make_safe<IO::stateful_protocol_strategy_wrapper>([=]\r
+                       {\r
+                               return std::make_shared<CLK::CLKProtocolStrategy>(channels_);\r
+                       });\r
                \r
                BOOST_THROW_EXCEPTION(caspar_exception() << arg_name_info("name") << arg_value_info(narrow(name)) << msg_info("Invalid protocol"));\r
        }\r