blob: f12ad3459746850ea16c14e2465a01e5a8a31101 [file]
// 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 __PROCESS_PID_HPP__
#define __PROCESS_PID_HPP__
#include <stdint.h>
#include <iosfwd>
#include <string>
#include <boost/functional/hash.hpp>
#include <process/address.hpp>
#include <stout/ip.hpp>
namespace process {
// Forward declaration to break cyclic dependencies.
class ProcessBase;
/**
* An "untyped" `PID`, used to encapsulate the process ID for
* lower-layer abstractions (eg, when receiving incoming requests)
* in the dispatching mechanism.
*
* @see process::PID
*/
struct UPID
{
UPID() = default;
UPID(const UPID& that) = default;
UPID(UPID&& that) = default;
UPID(const char* id_, const net::IP& ip_, uint16_t port_)
: id(id_), address(ip_, port_) { resolve(); }
UPID(const char* id_, const network::inet::Address& address_)
: id(id_), address(address_) { resolve(); }
UPID(const std::string& id_, const net::IP& ip_, uint16_t port_)
: id(id_), address(ip_, port_) { resolve(); }
UPID(const std::string& id_, const network::inet::Address& address_)
: id(id_), address(address_) { resolve(); }
/*implicit*/ UPID(const char* s);
/*implicit*/ UPID(const std::string& s);
/*implicit*/ UPID(const ProcessBase& process);
UPID& operator=(const UPID& that) = default;
UPID& operator=(UPID&& that) = default;
operator std::string() const;
operator bool() const
{
return id != "" && !address.ip.isAny() && address.port != 0;
}
bool operator!() const // NOLINT(whitespace/operators)
{
return id == "" && address.ip.isAny() && address.port == 0;
}
bool operator<(const UPID& that) const
{
if (address == that.address) {
return id < that.id;
} else {
return address < that.address;
}
}
bool operator==(const UPID& that) const
{
return (id == that.id && address == that.address);
}
bool operator!=(const UPID& that) const
{
return !(*this == that);
}
// Attempts to resolve and cache a weak pointer to the ProcessBase
// to which this UPID refers.
void resolve();
// TODO(benh): store all of the members of UPID behind a
// copy-on-write implementation because UPID is often copied but
// rarely written which means we could optimize performance by not
// making so many copies.
// A copy-on-write string for performance.
//
// TODO(benh): Factor this out into a generic copy-on-write string.
struct ID
{
static const std::string EMPTY;
ID() = default;
ID(const std::string& s)
: id(std::make_shared<std::string>(s)) {}
ID(std::string&& s)
: id(std::make_shared<std::string>(std::move(s))) {}
ID& operator=(std::string&& that)
{
id = std::make_shared<std::string>(std::move(that));
return *this;
}
bool operator==(const std::string& that) const
{
if (!id) {
return EMPTY == that;
}
return *id == that;
}
bool operator==(const char* that) const
{
if (!id) {
return EMPTY == that;
}
return *id == that;
}
bool operator!=(const std::string& that) const
{
return !(*this == that);
}
bool operator<(const std::string& that) const
{
if (!id) {
return EMPTY < that;
}
return *id < that;
}
operator const std::string&() const
{
if (!id) {
return EMPTY;
}
return *id;
}
private:
std::shared_ptr<std::string> id;
} id;
// TODO(asridharan): Ideally, the following `address` field should be of
// type `network::Address` so that the default address of the PID
// could be a unix domain socket or an IPv4/v6 address. This change
// however is disruptive at this point and should be done after we have
// introduced support for unix domain and IPv6 sockets into
// `libprocess`.
network::inet::Address address = network::inet4::Address::ANY_ANY();
// TODO(asridharan): Currently we are introducing only an `Optional`
// IPv6 address in the following `addresses` structure. This will
// help us initiate some basic IPv6 support for the
// `DockerContainerizer`. However, going forward, once we start
// supporting unix domain sockets and IPv4/IPv6 socket in
// `libprocess` we will add the following fields to this structure.
//
// Option<network::unix::Address> unix;
// Option<network::inet4::Address> v4;
//
// With the introduction of the above fields `libprocess` PID will
// be able to support unix, IPv4 and IPv6 sockets simultaneously.
struct
{
Option<network::inet6::Address> v6;
} addresses = {None()};
// The hostname that was used to create this UPID, if any. This is useful
// both for display purposes and when making outgoing connections on a TLS
// socket, where the name recorded here can be used for hostname validation
// checks against the X509 certificate presented by the server.
//
// NOTE: In the context of TLS hostname validation, this can also be set
// manually to override the result of DNS resolution before trying to
// `connect()` to this UPID, similar to `curl --resolve`.
Option<std::string> host;
protected:
friend class ProcessBase;
friend class ProcessManager;
// A weak pointer to the actual process used to optimize enqueuing
// events without having to go through a shared lock in the
// `ProcessManager`. This is `None` if someone creates a UPID and
// doesn't call `resolve()` or if `resolve()` doesn't find a valid
// process (i.e., the process hasn't started or has terminated).
Option<std::weak_ptr<ProcessBase*>> reference = None();
};
inline std::ostream& operator<<(std::ostream& stream, const UPID::ID& id)
{
const std::string& s = id;
return stream << s;
}
inline bool operator==(const std::string& s, const UPID::ID& id)
{
return id == s;
}
inline bool operator!=(const std::string& s, const UPID::ID& id)
{
return !(s == id);
}
inline std::string operator+(const UPID::ID& id, const std::string& s)
{
return (const std::string&) id + s;
}
inline std::string operator+(const UPID::ID& id, std::string&& s)
{
return (const std::string&) id + std::move(s);
}
inline std::string operator+(const std::string& s, const UPID::ID& id)
{
return s + (const std::string&) id;
}
inline std::string operator+(std::string&& s, const UPID::ID& id)
{
return std::move(s) + (const std::string&) id;
}
/**
* A "process identifier" used to uniquely identify a process when
* dispatching messages.
*
* Typed with the actual process class's type, which must be
* derived from `process::ProcessBase`.
*
* Use it like this:
*
* using namespace process;
*
* class SimpleProcess : public Process<SimpleProcess>
* {
* // ...
* };
*
*
* SimpleProcess process;
* PID<SimpleProcess> pid = spawn(process);
*
* // ...
*
* dispatchpid, &SimpleProcess::method, "argument");
*
* @see process::ProcessBase
*/
template <typename T = ProcessBase>
struct PID : UPID
{
// Need to declare PID<U> as a friend in order to write `reference`.
template <typename U>
friend struct PID;
PID() : UPID() {}
/*implicit*/ PID(const T* t) : UPID(static_cast<const ProcessBase&>(*t)) {}
/*implicit*/ PID(const T& t) : UPID(static_cast<const ProcessBase&>(t)) {}
template <typename Base>
operator PID<Base>() const
{
// Only allow upcasts!
T* t = nullptr;
Base* base = t;
(void)base; // Eliminate unused base warning.
PID<Base> pid;
pid.id = id;
pid.address = address;
pid.addresses = addresses;
pid.reference = reference;
return pid;
}
};
// Outputing UPIDs and generating UPIDs using streams.
std::ostream& operator<<(std::ostream&, const UPID&);
std::istream& operator>>(std::istream&, UPID&);
} // namespace process {
namespace std {
template <>
struct hash<process::UPID>
{
typedef size_t result_type;
typedef process::UPID argument_type;
result_type operator()(const argument_type& upid) const
{
size_t seed = 0;
boost::hash_combine(seed, (const std::string&) upid.id);
boost::hash_combine(seed, std::hash<net::IP>()(upid.address.ip));
boost::hash_combine(seed, upid.address.port);
return seed;
}
};
} // namespace std {
#endif // __PROCESS_PID_HPP__