fakekms/cpp/fakekms_posix.cc (62 lines of code) (raw):
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <csignal>
#include "absl/cleanup/cleanup.h"
#include "absl/strings/str_format.h"
#include "fakekms/cpp/fakekms.h"
namespace fakekms {
namespace {
class PosixServer : public Server {
public:
static absl::StatusOr<std::unique_ptr<PosixServer>> New(
std::string_view flags);
PosixServer(std::string listen_addr, pid_t pid)
: Server(listen_addr), pid_(pid) {}
~PosixServer() { CHECK_EQ(kill(pid_, SIGINT), 0); }
private:
pid_t pid_;
};
absl::Status PosixErrorToStatus(std::string_view prefix) {
return absl::InternalError(
absl::StrFormat("%s: %s", prefix, strerror(errno)));
}
} // namespace
absl::StatusOr<std::unique_ptr<Server>> Server::New() {
int fd[2];
if (pipe(fd) == -1) {
return PosixErrorToStatus("unable to create output pipe");
}
absl::Cleanup c = [&] {
CHECK_EQ(close(fd[0]), 0);
CHECK_EQ(close(fd[1]), 0);
};
pid_t pid = fork();
switch (pid) {
// fork failure
case -1: {
return PosixErrorToStatus("failure forking");
}
// post-fork child
case 0: {
if (dup2(fd[1], STDOUT_FILENO) == -1) {
exit(1);
}
// we'll be replacing the executable, so cleanup must happen manually
c.~Cleanup();
std::string bin_path = BinaryLocation();
execl(bin_path.c_str(), bin_path.c_str(), (char*)0);
// the previous line replaces the executable, so this
// line shouldn't be reached
exit(2);
}
// post-fork parent
default: {
FILE* file = fdopen(fd[0], "r");
if (!file) {
return PosixErrorToStatus("error opening pipe");
}
char* line = nullptr;
size_t len = 0;
if (getline(&line, &len, file) == -1) {
free(line);
return PosixErrorToStatus("failure reading address");
}
std::string address(line, len);
free(line);
return std::make_unique<PosixServer>(address, pid);
}
}
}
} // namespace fakekms