blob: c939b9600841c70f7f434d23f4685b07a101755a [file]
// Copyright 2023 Google Inc. All Rights Reserved.
//
// 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.
#ifndef NINJA_SRC_IPC_UTILS_H_
#define NINJA_SRC_IPC_UTILS_H_
#include <map>
#include <string>
#include <vector>
#ifndef _WIN32
#include <signal.h>
#endif
#include "scoped_handle.h"
/// Convenience wrapper for an std::vector<std::string> that can save
/// the content of an (argc, argv) list of command-line arguments.
struct RemoteArguments {
RemoteArguments() = default;
RemoteArguments(int argc, char** argv);
void Reset(const std::vector<std::string>& args);
const std::vector<std::string>& args() const { return args_; }
/// Export instance as (argc, argv) pair.
int argc() const { return static_cast<int>(args_.size()); }
char** argv() const;
void InsertAt(size_t pos, std::string arg);
protected:
std::vector<std::string> args_;
mutable std::vector<char*> argv_;
};
/// Helper template to write values through an ScopedHandle.
template <typename T>
bool RemoteWrite(const T& obj, const ScopedHandle& con, std::string* error) {
return con.WriteFull(&obj, sizeof(obj), error);
}
template <>
bool RemoteWrite<std::string>(const std::string& obj, const ScopedHandle& con,
std::string* error);
template <>
bool RemoteWrite<RemoteArguments>(const RemoteArguments& obj,
const ScopedHandle& con, std::string* error);
/// Helper template to read values through an ScopedHandle
template <typename T>
bool RemoteRead(T& obj, const ScopedHandle& con, std::string* error) {
return con.ReadFull(&obj, sizeof(obj), error);
}
template <>
bool RemoteRead<std::string>(std::string& obj, const ScopedHandle& con,
std::string* error);
template <>
bool RemoteRead<RemoteArguments>(RemoteArguments& obj, const ScopedHandle& con,
std::string* error);
/// Send a |native| handle to the peer of |con|. On success return true.
/// On failure, return false and sets |*error_message|.
bool RemoteSendNativeHandle(const ScopedHandle& con,
ScopedHandle::NativeType handle,
std::string* error_message);
/// Receive a |native| handle from the peer of |con|. On success return true
/// and sets |*handle|. On failure, return false and sets |*error_message|.
bool RemoteReceiveNativeHandle(const ScopedHandle& con, ScopedHandle* handle,
std::string* error_message);
/// Simple class to encode values into a byte stream that
/// can be sent through IPC to another process. Usage is:
///
/// 1) Create instance.
/// 2) Call one of the Write() methods any number of times.
/// 3) Call GetResult() to retrieve the result as an std::string.
///
struct WireEncoder {
void Write(const void* buffer, size_t size);
void Write(const std::string& str);
template <typename T>
void Write(const T& v) {
Write(&v, sizeof(v));
}
template <typename T, typename Alloc>
void Write(const std::vector<T, Alloc>& m) {
Write(m.size());
for (const auto& e : m) {
Write(e);
}
}
template <typename K, typename V, typename Less, typename Alloc>
void Write(const std::map<K, V, Less, Alloc>& m) {
Write(m.size());
for (const auto& e : m) {
Write(e.first);
Write(e.second);
}
}
std::string TakeResult() { return std::move(result_); }
std::string result_;
};
/// Decode a string of bytes received through IPC into values.
/// Usage is:
/// 1) Create instance passing the input stream as an std::string
/// 2) Call Read() methods as many times as necessary.
/// 3) Check has_error() after each Read(), or after a series of
/// Read() calls to see if there was any error (i.e. read overflow).
///
struct WireDecoder {
WireDecoder(const void* buffer, size_t size);
explicit WireDecoder(const std::string& str);
void Read(void* buffer, size_t size);
void Read(std::string& str);
template <typename T>
void Read(T& v) {
Read(&v, sizeof(T));
}
template <typename T, typename Alloc>
void Read(std::vector<T, Alloc>& m) {
typename std::vector<T, Alloc>::size_type s;
Read(s);
m.reserve(s);
for (size_t i=0; i<s; ++i) {
T v;
Read(v);
m.push_back(v);
}
}
template <typename K, typename V, typename Less, typename Alloc>
void Read(std::map<K, V, Less, Alloc>& m) {
typename std::map<K, V, Less, Alloc>::size_type s;
Read(s);
for (size_t i=0; i<s; ++i) {
K k;
V v;
Read(k);
Read(v);
m[k] = v;
}
}
bool has_error() const { return has_error_; }
const char* p_ = nullptr;
const char* end_ = nullptr;
bool has_error_ = false;
};
#ifndef _WIN32
/// Convenience class to ignore SIGPIPE signals when
/// doing inter-process writes through a pipe.
class SigPipeBlocker {
public:
SigPipeBlocker();
~SigPipeBlocker();
private:
struct sigaction prev_action_;
};
#endif // !_WIN32
#endif // NINJA_SRC_IPC_UTILS_H_