Imported Upstream version 0.3.3
[anytun.git] / src / win32 / sysExec.hpp
1 /*\r
2  *  anytun\r
3  *\r
4  *  The secure anycast tunneling protocol (satp) defines a protocol used\r
5  *  for communication between any combination of unicast and anycast\r
6  *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel\r
7  *  mode and allows tunneling of every ETHER TYPE protocol (e.g.\r
8  *  ethernet, ip, arp ...). satp directly includes cryptography and\r
9  *  message authentication based on the methodes used by SRTP.  It is\r
10  *  intended to deliver a generic, scaleable and secure solution for\r
11  *  tunneling and relaying of packets of any protocol.\r
12  *\r
13  *\r
14  *  Copyright (C) 2007-2009 Othmar Gsenger, Erwin Nindl, \r
15  *                          Christian Pointner <satp@wirdorange.org>\r
16  *\r
17  *  This file is part of Anytun.\r
18  *\r
19  *  Anytun is free software: you can redistribute it and/or modify\r
20  *  it under the terms of the GNU General Public License as published by\r
21  *  the Free Software Foundation, either version 3 of the License, or\r
22  *  any later version.\r
23  *\r
24  *  Anytun is distributed in the hope that it will be useful,\r
25  *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
26  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
27  *  GNU General Public License for more details.\r
28  *\r
29  *  You should have received a copy of the GNU General Public License\r
30  *  along with anytun.  If not, see <http://www.gnu.org/licenses/>.\r
31  */\r
32 #pragma once\r
33 #ifndef ANYTUN_sysexec_hpp_INCLUDED\r
34 #define ANYTUN_sysexec_hpp_INCLUDED\r
35 \r
36 #include <algorithm>\r
37 #include <iostream> // todo remove\r
38 #include <windows.h>\r
39 \r
40 SysExec::~SysExec()\r
41 {\r
42   if(!closed_) {\r
43     CloseHandle(process_info_.hProcess);\r
44     CloseHandle(process_info_.hThread);\r
45   }\r
46 }\r
47 \r
48 STARTUPINFOA getStartupInfo() {\r
49   STARTUPINFOA startup_info;\r
50   startup_info.cb = sizeof(STARTUPINFOA);\r
51   GetStartupInfoA(&startup_info);\r
52 \r
53   //startup_info.dwFlags = STARTF_USESTDHANDLES;\r
54   //startup_info.hStdInput = CreateFile("NUL", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 0, 0, 0); // INVALID_HANDLE_VALUE;\r
55   //startup_info.hStdOutput = CreateFile("NUL", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 0, 0, 0); // INVALID_HANDLE_VALUE;\r
56   //startup_info.hStdError = CreateFile("NUL", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 0, 0, 0); // INVALID_HANDLE_VALUE;\r
57   startup_info.dwFlags |= STARTF_USESHOWWINDOW;\r
58   startup_info.wShowWindow = SW_HIDE;\r
59   \r
60   return startup_info;\r
61 }\r
62 \r
63 char const * const BATCH_FILE_EXTS[] = { ".bat", ".cmd" };\r
64 int const BATCH_FILE_EXTS_COUNT = sizeof(BATCH_FILE_EXTS) / sizeof(BATCH_FILE_EXTS[0]);\r
65 \r
66 bool endsWith(std::string const& string, std::string const& suffix) {\r
67   return string.find(suffix, string.size() - suffix.size()) != std::string::npos;\r
68 }\r
69 \r
70 void SysExec::doExec(StringVector args, StringList env)\r
71 {\r
72   std::vector<char> arguments;\r
73   \r
74   bool isBatchFile = false;\r
75   for(int i = 0; i < BATCH_FILE_EXTS_COUNT; ++i) {\r
76     if(endsWith(script_, BATCH_FILE_EXTS[i])) {\r
77       isBatchFile = true;\r
78       break;\r
79     }\r
80   }\r
81 \r
82   if(isBatchFile) {\r
83     std::string const BATCH_INTERPRETER = "cmd /c \"";\r
84     arguments.insert(arguments.end(), BATCH_INTERPRETER.begin(), BATCH_INTERPRETER.end());\r
85   }\r
86   arguments.push_back('\"');\r
87   arguments.insert(arguments.end(), script_.begin(), script_.end());\r
88   arguments.push_back('\"');\r
89   arguments.push_back(' ');\r
90   \r
91   for(StringVector::const_iterator it = args.begin(); it != args.end(); ++it) {\r
92     arguments.push_back('\"');\r
93     arguments.insert(arguments.end(), it->begin(), it->end());\r
94     arguments.push_back('\"');\r
95     arguments.push_back(' ');\r
96   }\r
97 \r
98   if(isBatchFile) {\r
99     arguments.push_back('\"');\r
100   }\r
101   arguments.push_back(0);\r
102   \r
103   STARTUPINFOA startup_info = getStartupInfo();\r
104 \r
105   std::map<std::string, std::string> envDict;\r
106   for(StringList::const_iterator it = env.begin(); it != env.begin(); ++it) {\r
107     size_t delimiter_pos = it->find('=');\r
108     envDict.insert(std::make_pair(it->substr(0, delimiter_pos), it->substr(delimiter_pos + 1)));\r
109   }\r
110   std::vector<char> env;\r
111   for(std::map<std::string, std::string>::iterator it = envDict.begin(); it != envDict.end(); ++it) {\r
112     env.insert(env.end(), it->first.begin(), it->first.end());\r
113     env.push_back(0);\r
114   }\r
115   env.push_back(0);\r
116 \r
117   if(!CreateProcessA(NULL,\r
118                    &arguments[0],\r
119                    NULL,\r
120                    NULL,\r
121                    false,\r
122                    NULL,\r
123                    &env[0],\r
124                    NULL,\r
125                    &startup_info,\r
126                    &process_info_\r
127                    ))\r
128   {\r
129     cLog.msg(Log::PRIO_ERROR) << "executing script '" << script_ << "' CreateProcess() error: " << GetLastError();\r
130     return;\r
131   }\r
132 }\r
133 \r
134 int SysExec::waitForScript()\r
135 {\r
136   DWORD result = WaitForSingleObject(process_info_.hProcess, INFINITE);\r
137   assert(WAIT_OBJECT_0 == result); // WAIT_FAILED, WAIT_TIMEOUT ... ???\r
138   bool success = GetExitCodeProcess(process_info_.hProcess, &return_code_) != 0;\r
139   assert(true == success); // false -> HU?\r
140 \r
141   CloseHandle(process_info_.hProcess);\r
142   CloseHandle(process_info_.hThread);\r
143   closed_ = true;\r
144 \r
145   return static_cast<int>(return_code_);\r
146 }\r
147 \r
148 void SysExec::waitAndDestroy(SysExec*& s)\r
149 {\r
150   if(!s)\r
151     return;\r
152 \r
153   s->waitForScript();\r
154   cLog.msg(Log::PRIO_NOTICE) << "script '" << s->script_ << "' returned " << s->return_code_;\r
155 \r
156   delete(s);\r
157   s = NULL;\r
158 }\r
159 \r
160 #endif // ANYTUN_sysexec_hpp_INCLUDED\r