travis: fix clang
[awesomized/libmemcached] / testing / lib / Server.cpp
index b3d0118baf9a51f14dbab99101e8f85355ef79f5..2ab4d5b70b29b1f4cc675b36a8f105f6c963a98c 100644 (file)
@@ -5,14 +5,17 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-Server::Server(string &&binary_, Server::argv_t &&args_)
-    : binary{forward<string>(binary_)}
-    , args{forward<argv_t>(args_)}
+Server::Server(string binary_, Server::argv_t args_)
+    : binary{move(binary_)}
+    , args{move(args_)}
 {}
 
 Server::~Server() {
   stop();
   wait();
+  if (pipe != -1) {
+    close(pipe);
+  }
   if (holds_alternative<string>(socket_or_port)) {
     unlink(get<string>(socket_or_port).c_str());
   }
@@ -57,7 +60,7 @@ vector<char *> Server::createArgv()  {
   vector<char *> arr;
 
   pushArg(arr, binary);
-  pushArg(arr, "-v");
+  //pushArg(arr, "-v");
 
   for (auto it = args.cbegin(); it != args.cend(); ++it) {
     if (holds_alternative<arg_t>(*it)) {
@@ -87,32 +90,44 @@ vector<char *> Server::createArgv()  {
   return arr;
 }
 
-optional<pid_t> Server::start() {
-  if (pid) {
-    return pid;
-  }
+optional<Server::ChildProc> Server::start() {
+  if (!pid) {
+    auto argv = createArgv();
+    ForkAndExec fork_and_exec{binary.c_str(), argv.data()};
 
-  auto argv = createArgv();
-  auto child = ForkAndExec{binary.c_str(), argv.data()}();
+    pipe = fork_and_exec.createPipe();
+    pid = fork_and_exec();
 
-  for (auto argp : argv) {
-    delete [] argp;
-  }
+    for (auto argp : argv) {
+      delete [] argp;
+    }
 
-  if (child.has_value()) {
-    pid = child.value();
+    if (!pid) {
+      return {};
+    }
   }
-
-  return child;
+  return ChildProc{pid, pipe};
 }
 
 bool Server::isListening() {
-  Connection conn(socket_or_port);
+  MemcachedPtr memc;
+
+  if (holds_alternative<string>(socket_or_port)) {
+    if (memcached_server_add_unix_socket(*memc, get<string>(socket_or_port).c_str())) {
+      return false;
+    }
+  } else {
+    if (memcached_server_add(*memc, "localhost", get<int>(socket_or_port))) {
+      return false;
+    }
+  }
 
-  if (!conn.open()) {
+  Malloced stat(memcached_stat(*memc, nullptr, nullptr));
+  if (!*stat || !stat->pid || stat->pid != pid) {
     return false;
   }
-  return conn.isOpen();
+
+  return true;
 }
 
 bool Server::stop() {
@@ -140,7 +155,15 @@ bool Server::check() {
 
 bool Server::wait(int flags) {
   if (pid && pid == waitpid(pid, &status, flags)) {
+    if (drain().length()) {
+      cerr << "Ouput of " << *this << ":\n" << output << endl;
+      output.clear();
+    }
     pid = 0;
+    if (pipe != -1) {
+      close(pipe);
+      pipe = -1;
+    }
     return true;
   }
   return false;
@@ -179,3 +202,34 @@ const socket_or_port_t &Server::getSocketOrPort() const {
   return socket_or_port;
 }
 
+int Server::getPipe() const {
+  return pipe;
+}
+
+string &Server::drain() {
+  if (pipe != -1) {
+    again:
+    char read_buf[1<<12];
+    auto read_len = read(pipe, read_buf, sizeof(read_buf));
+
+    if (read_len > 0) {
+      output.append(read_buf, read_len);
+      goto again;
+    }
+    if (read_len == -1) {
+      switch (errno) {
+      case EINTR:
+        goto again;
+      default:
+        perror("Server::drain read()");
+        [[fallthrough]];
+      case EAGAIN:
+#if EWOULDBLOCK != EAGAIN
+      case EWOULDBLOCK:
+#endif
+        break;
+      }
+    }
+  }
+  return output;
+}