IPCUnix.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #ifndef ATOMIC_PLATFORM_WINDOWS
  2. #include "IPCUnix.h"
  3. namespace Atomic
  4. {
  5. #include <unistd.h>
  6. #include <signal.h>
  7. #include <sys/socket.h>
  8. #include <errno.h>
  9. #ifdef ATOMIC_PLATFORM_OSX
  10. #include <libproc.h>
  11. #endif
  12. #define HANDLE_EINTR(x) ({ \
  13. typeof(x) __eintr_result__; \
  14. do { \
  15. __eintr_result__ = x; \
  16. } while (__eintr_result__ == -1 && errno == EINTR); \
  17. __eintr_result__;\
  18. })
  19. bool SilenceSocket(int fd) {
  20. #ifdef ATOMIC_PLATFORM_OSX
  21. int nosigpipe = 1;
  22. // On OSX an attempt to read or write to a closed socket may generate a
  23. // SIGPIPE rather than returning -1. setsockopt will shut this off.
  24. if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE,
  25. &nosigpipe, sizeof nosigpipe)) {
  26. return false;
  27. }
  28. #endif
  29. return true;
  30. }
  31. size_t ReadFromFD(int fd, char* buffer, size_t bytes) {
  32. fd_set set;
  33. struct timeval timeout;
  34. FD_ZERO(&set);
  35. FD_SET(fd, &set);
  36. timeout.tv_sec = 0;
  37. // 100ms
  38. timeout.tv_usec = 100000;
  39. // check if there is anything to read
  40. int rv = select(fd + 1, &set, NULL, NULL, &timeout);
  41. if (rv < 0)
  42. return -1;
  43. if (!rv)
  44. return 0;
  45. ssize_t bytes_read =
  46. HANDLE_EINTR(read(fd, buffer, bytes));
  47. if (bytes_read < 0) {
  48. return -1;
  49. }
  50. return bytes_read;
  51. }
  52. size_t WriteToFD(int fd, const char* data, size_t size) {
  53. // Allow for partial writes.
  54. ssize_t written_total = 0;
  55. for (ssize_t written_partial = 0; written_total < size; written_total += written_partial) {
  56. written_partial =
  57. HANDLE_EINTR(write(fd, data + written_total, size - written_total));
  58. if (written_partial < 0) {
  59. return -1;
  60. }
  61. }
  62. return written_total;
  63. }
  64. PipePair::PipePair() {
  65. fd_[0] = -1;
  66. fd_[1] = -1;
  67. if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd_) !=0) {
  68. return;
  69. }
  70. };
  71. PipeUnix::PipeUnix() : fd_(-1) {
  72. }
  73. bool PipeUnix::OpenClient(int fd) {
  74. if (!SilenceSocket(fd)) {
  75. return false;
  76. }
  77. fd_ = fd;
  78. return true;
  79. }
  80. bool PipeUnix::OpenServer(int fd) {
  81. if (!SilenceSocket(fd)) {
  82. return false;
  83. }
  84. fd_ = fd;
  85. return true;
  86. }
  87. bool PipeUnix::Write(const void* buf, size_t sz) {
  88. if (sz == -1) {
  89. return false;
  90. }
  91. size_t written = WriteToFD(fd_, static_cast<const char*> (buf), sz);
  92. return (sz == written);
  93. }
  94. bool PipeUnix::Read(void* buf, size_t* sz) {
  95. size_t read = ReadFromFD(fd_, static_cast<char*> (buf), *sz);
  96. if (read == -1) {
  97. return false;
  98. }
  99. *sz = read;
  100. return true;
  101. }
  102. char* PipeTransport::Receive(size_t* size) {
  103. if (buf_.Size() < kBufferSz) {
  104. buf_.Resize(kBufferSz);
  105. }
  106. *size = kBufferSz;
  107. if (!Read(&buf_[0], size)) {
  108. return NULL;
  109. }
  110. return &buf_[0];
  111. }
  112. IPCProcess::IPCProcess(Context* context, int fd1, int fd2, int pid) : Object(context),
  113. pid_(pid),
  114. fd1_(fd1),
  115. fd2_(fd2)
  116. {
  117. }
  118. IPCProcess::~IPCProcess()
  119. {
  120. }
  121. bool IPCProcess::IsRunning()
  122. {
  123. if (pid_ == -1)
  124. return false;
  125. #ifdef __APPLE__
  126. char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
  127. int ret = proc_pidpath (pid_, pathbuf, sizeof(pathbuf));
  128. if ( ret > 0 )
  129. {
  130. return true;
  131. }
  132. #else
  133. // this doesn't seem to work on OSX?
  134. if (kill(pid_, 0) == 0)
  135. return true;
  136. #endif
  137. return false;
  138. }
  139. bool IPCProcess::Launch(const String& command, const Vector<String>& args, const String& initialDirectory)
  140. {
  141. assert(pid_ == -1);
  142. // We must not allocated memory after fork(),
  143. // therefore allocate all required buffers first.
  144. PODVector<char*> argv;
  145. argv.Resize(args.Size() + 2);
  146. int i = 0;
  147. argv[i++] = const_cast<char*>(command.CString());
  148. for (unsigned j = 0; j < args.Size(); j++)
  149. {
  150. argv[i++] = const_cast<char*>(args[j].CString());
  151. }
  152. argv[i] = NULL;
  153. const char* pInitialDirectory = initialDirectory.Empty() ? 0 : initialDirectory.CString();
  154. int pid = fork();
  155. if (pid < 0)
  156. {
  157. // error forking
  158. return false;
  159. }
  160. else if (pid == 0)
  161. {
  162. // child process
  163. if (pInitialDirectory)
  164. {
  165. if (chdir(pInitialDirectory) != 0)
  166. {
  167. _exit(72);
  168. }
  169. }
  170. // close all open file descriptors other than stdin, stdout, stderr
  171. // and the IPC child fd
  172. for (int i = 3; i < getdtablesize(); ++i)
  173. {
  174. if (i != fd2())
  175. close(i);
  176. }
  177. execvp(argv[0], &argv[0]);
  178. _exit(72);
  179. }
  180. else
  181. {
  182. // parent process
  183. pid_ = pid;
  184. }
  185. return true;
  186. }
  187. }
  188. #endif