IPCWindows.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #ifdef ATOMIC_PLATFORM_WINDOWS
  2. #include <Windows.h>
  3. #include <Sddl.h>
  4. #include <AccCtrl.h>
  5. #include <Aclapi.h>
  6. #include <string>
  7. #include "IPCWindows.h"
  8. typedef std::wstring IPCWString;
  9. namespace Atomic
  10. {
  11. static const wchar_t kPipePrefix[] = L"\\\\.\\pipe\\";
  12. static const int kPipeBufferSz = 4 * 1024;
  13. static LONG g_pipe_seq = 0;
  14. bool checkIntegritySupport()
  15. {
  16. OSVERSIONINFO osvi;
  17. ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
  18. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  19. GetVersionEx(&osvi);
  20. return osvi.dwMajorVersion > 5;
  21. }
  22. HANDLE PipePair::OpenPipeServer(const wchar_t* name, bool low_integrity) {
  23. SECURITY_ATTRIBUTES sa = { 0 };
  24. SECURITY_ATTRIBUTES *psa = 0;
  25. static const bool is_integrity_supported = false;// checkIntegritySupport();
  26. if (is_integrity_supported && low_integrity) {
  27. psa = &sa;
  28. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  29. sa.bInheritHandle = TRUE;
  30. if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
  31. TEXT("S:(ML;;NWNR;;;LW)"), SDDL_REVISION_1, &sa.lpSecurityDescriptor, NULL))
  32. return INVALID_HANDLE_VALUE;
  33. }
  34. IPCWString pipename(kPipePrefix);
  35. pipename.append(name);
  36. return ::CreateNamedPipeW(pipename.c_str(), PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE,
  37. PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
  38. 1, kPipeBufferSz, kPipeBufferSz, 200, psa);
  39. }
  40. HANDLE PipePair::OpenPipeClient(const wchar_t* name, bool inherit, bool impersonate) {
  41. IPCWString pipename(kPipePrefix);
  42. pipename.append(name);
  43. SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, inherit ? TRUE : FALSE };
  44. for (;;) {
  45. DWORD attributes = impersonate ? 0 : SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION;
  46. HANDLE pipe = ::CreateFileW(pipename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, &sa,
  47. OPEN_EXISTING, attributes, NULL);
  48. if (INVALID_HANDLE_VALUE == pipe) {
  49. if (ERROR_PIPE_BUSY != ::GetLastError()) {
  50. return pipe;
  51. }
  52. // wait and retry.
  53. ::Sleep(25);
  54. }
  55. else {
  56. // success.
  57. return pipe;
  58. }
  59. }
  60. }
  61. PipePair::PipePair(bool inherit_fd2) :
  62. srv_(INVALID_IPCHANDLE_VALUE),
  63. cln_(INVALID_IPCHANDLE_VALUE)
  64. {
  65. // Come up with a reasonable unique name.
  66. const wchar_t kPipePattern[] = L"ko.%x.%x.%x";
  67. wchar_t name[8 * 3 + sizeof(kPipePattern)];
  68. ::wsprintfW(name, kPipePattern, ::GetCurrentProcessId(), ::GetTickCount(),
  69. ::InterlockedIncrement(&g_pipe_seq));
  70. HANDLE server = OpenPipeServer(name);
  71. if (INVALID_HANDLE_VALUE == server)
  72. {
  73. return;
  74. }
  75. // Don't allow client impersonation.
  76. HANDLE client = OpenPipeClient(name, inherit_fd2, false);
  77. if (INVALID_HANDLE_VALUE == client)
  78. {
  79. ::CloseHandle(server);
  80. return;
  81. }
  82. if (!::ConnectNamedPipe(server, NULL))
  83. {
  84. if (ERROR_PIPE_CONNECTED != ::GetLastError())
  85. {
  86. ::CloseHandle(server);
  87. ::CloseHandle(client);
  88. return;
  89. }
  90. }
  91. srv_ = server;
  92. cln_ = client;
  93. }
  94. PipeWin::PipeWin() : pipe_(INVALID_IPCHANDLE_VALUE)
  95. {
  96. }
  97. PipeWin::~PipeWin()
  98. {
  99. if (pipe_ != INVALID_HANDLE_VALUE)
  100. {
  101. ::DisconnectNamedPipe(pipe_); // $$$ disconect is valid on the server side.
  102. ::CloseHandle(pipe_);
  103. }
  104. }
  105. bool PipeWin::OpenClient(IPCHandle pipe)
  106. {
  107. pipe_ = pipe;
  108. return true;
  109. }
  110. bool PipeWin::OpenServer(IPCHandle pipe, bool connect)
  111. {
  112. pipe_ = pipe;
  113. if (connect)
  114. {
  115. if (!::ConnectNamedPipe(pipe, NULL))
  116. {
  117. if (ERROR_PIPE_CONNECTED != ::GetLastError())
  118. {
  119. return false;
  120. }
  121. }
  122. }
  123. return true;
  124. }
  125. bool PipeWin::Write(const void* buf, size_t sz)
  126. {
  127. DWORD written = 0;
  128. if (TRUE == ::WriteFile(pipe_, buf, sz, &written, NULL))
  129. return true;
  130. return false;
  131. }
  132. bool PipeWin::Read(void* buf, size_t* sz)
  133. {
  134. if (TRUE == ::ReadFile(pipe_, buf, *sz, reinterpret_cast<DWORD*>(sz), NULL))
  135. {
  136. return true;
  137. }
  138. return false;
  139. }
  140. char* PipeTransport::Receive(size_t* size)
  141. {
  142. if (buf_.Size() < kBufferSz)
  143. {
  144. buf_.Resize(kBufferSz);
  145. }
  146. *size = kBufferSz;
  147. if (!Read(&buf_[0], size))
  148. {
  149. return NULL;
  150. }
  151. return &buf_[0];
  152. }
  153. IPCProcess::IPCProcess(Context* context, IPCHandle fd1, IPCHandle fd2, IPCHandle pid) : Object(context),
  154. pid_(pid),
  155. fd1_(fd1),
  156. fd2_(fd2)
  157. {
  158. }
  159. IPCProcess::~IPCProcess()
  160. {
  161. }
  162. bool IPCProcess::IsRunning()
  163. {
  164. return true;
  165. }
  166. bool IPCProcess::Launch(const String& command, const Vector<String>& args, const String& initialDirectory)
  167. {
  168. STARTUPINFOW si = { sizeof(si) };
  169. PROCESS_INFORMATION pi = { 0 };
  170. // CreateProcess wants a single string
  171. String sargs;
  172. sargs.Join(args, " ");
  173. // convert to wide
  174. WString wcommand(command);
  175. // prepend the command and convert to wide
  176. WString wargs("\"" + command + "\" " + sargs);
  177. // The child process inherits the pipe handle.
  178. if (!::CreateProcessW(wcommand.CString(), (LPWSTR) wargs.CString(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
  179. return false;
  180. }
  181. pid_ = pi.hProcess;
  182. ::CloseHandle(pi.hThread);
  183. // The client side of the pipe has been already duplicated into the worker process.
  184. ::CloseHandle(fd2_);
  185. return true;
  186. }
  187. }
  188. #endif