From: Waldemar Kozaczuk <jwkozac...@gmail.com>
Committer: Waldemar Kozaczuk <jwkozac...@gmail.com>
Branch: master

httpserver: allow compiling out features not needed for monitoring api

This patch modifies httpserver-api source code to add pre-processor
conditionals - "#if !defined(MONITORING)" - to disable fragments of
code that are not needed for monitoring api. More specifically it disables
all non-GET routes (with exception of trace API) and YAML file-based 
configuration.
It also disables SSL. All of which is done to allow creating minimal 
"read-only" version
of httpserver API intended for monitoring purposes only.

Finally it also explicitly makes only certains symbols (like "main") public
by using compiler directives like "__attribute__((visibility("default")))"
and "#pragma GCC visibility push(default)/#pragma GCC visibility pop". The
latter is used to make portion of common code public so that is available to 
modules
like trace API. Hiding most symbols in monitoring module also helps
to reduce its size.

Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>

---
diff --git a/modules/httpserver-api/api/api.cc 
b/modules/httpserver-api/api/api.cc
--- a/modules/httpserver-api/api/api.cc
+++ b/modules/httpserver-api/api/api.cc
@@ -240,19 +240,23 @@ class api_param_handler : public handler_base {
     routes& _routes;
 };
 
+#if !defined(MONITORING)
 extern "C" void httpserver_plugin_register_routes(httpserver::routes* routes) {
     httpserver::api::api::init(*routes);
 }
+#endif
 
 void init(routes& routes)
 {
     api_json_init_path("Advanced API options");
 
     api_batch.set_handler(new api_param_handler(routes));
+#if !defined(MONITORING)
     stop_api.set_handler([](const_req req){
         global_server::stop();
         return "";
     });
+#endif
 
 }
 
diff --git a/modules/httpserver-api/api/env.cc 
b/modules/httpserver-api/api/env.cc
--- a/modules/httpserver-api/api/env.cc
+++ b/modules/httpserver-api/api/env.cc
@@ -20,9 +20,11 @@ using namespace json;
 using namespace std;
 using namespace env_json;
 
+#if !defined(MONITORING)
 extern "C" void httpserver_plugin_register_routes(httpserver::routes* routes) {
     httpserver::api::env::init(*routes);
 }
+#endif
 
 void init(routes& routes)
 {
@@ -46,6 +48,7 @@ void init(routes& routes)
         return res;
     });
 
+#if !defined(MONITORING)
     setEnv.set_handler([](const_req req) {
         string param = req.param.at("var").substr(1);
         if (setenv(param.c_str(),
@@ -62,7 +65,7 @@ void init(routes& routes)
             }
             return "";
         });
-
+#endif
 }
 
 }
diff --git a/modules/httpserver-api/api/file.cc 
b/modules/httpserver-api/api/file.cc
--- a/modules/httpserver-api/api/file.cc
+++ b/modules/httpserver-api/api/file.cc
@@ -98,6 +98,7 @@ static string file_name(const string& path)
     return path.substr(found + 1);
 }
 
+#if !defined(MONITORING)
 /**
  * Generate a temporary file name in a target directory
  * according to a file name
@@ -152,6 +153,7 @@ static void copy(const std::string& from, const 
std::string& to)
             + e.code().message());
     }
 }
+#endif
 
 class get_file_handler : public file_interaction_handler {
     virtual void handle(const std::string& path, parameters* params,
@@ -318,6 +320,7 @@ class get_file_handler : public file_interaction_handler {
     }
 };
 
+#if !defined(MONITORING)
 class del_file_handler : public handler_base {
     virtual void handle(const std::string& path, parameters* params,
                         const http::server::request& req, http::server::reply& 
rep)
@@ -442,18 +445,23 @@ class put_file_handler : public handler_base {
         set_headers(rep, "json");
     }
 };
+#endif
 
+#if !defined(MONITORING)
 extern "C" void httpserver_plugin_register_routes(httpserver::routes* routes) {
     httpserver::api::file::init(*routes);
 }
+#endif
 
 void init(routes& routes)
 {
     file_json_init_path("file API");
     getFile.set_handler(new get_file_handler());
+#if !defined(MONITORING)
     delFile.set_handler(new del_file_handler());
     putFile.set_handler(new put_file_handler());
     upload.set_handler(new post_file_handler());
+#endif
 }
 
 }
diff --git a/modules/httpserver-api/api/fs.cc b/modules/httpserver-api/api/fs.cc
--- a/modules/httpserver-api/api/fs.cc
+++ b/modules/httpserver-api/api/fs.cc
@@ -33,9 +33,11 @@ static void fill_dfstat(DFStat& dfstat, const 
osv::mount_desc& mount, const stru
     dfstat.blocksize = st.f_frsize;
 }
 
+#if !defined(MONITORING)
 extern "C" void httpserver_plugin_register_routes(httpserver::routes* routes) {
     httpserver::api::fs::init(*routes);
 }
+#endif
 
 void init(routes& routes) {
 
diff --git a/modules/httpserver-api/api/hardware.cc 
b/modules/httpserver-api/api/hardware.cc
--- a/modules/httpserver-api/api/hardware.cc
+++ b/modules/httpserver-api/api/hardware.cc
@@ -24,9 +24,11 @@ using namespace std;
 using namespace json;
 using namespace hardware_json;
 
+#if !defined(MONITORING)
 extern "C" void httpserver_plugin_register_routes(httpserver::routes* routes) {
     httpserver::api::hardware::init(*routes);
 }
+#endif
 
 void init(routes& routes)
 {
diff --git a/modules/httpserver-api/api/network.cc 
b/modules/httpserver-api/api/network.cc
--- a/modules/httpserver-api/api/network.cc
+++ b/modules/httpserver-api/api/network.cc
@@ -30,7 +30,6 @@ static Interface get_interface(const string& name, ifnet* 
ifp, long time)
     Interface f;
     interface intf(name);
 
-
     if_data cur_data = { 0 };
     if (!set_interface_info(ifp, cur_data, intf)) {
         throw server_error_exception("Failed getting interface information");
@@ -43,9 +42,11 @@ static Interface get_interface(const string& name, ifnet* 
ifp, long time)
     return f;
 }
 
+#if !defined(MONITORING)
 extern "C" void httpserver_plugin_register_routes(httpserver::routes* routes) {
     httpserver::api::network::init(*routes);
 }
+#endif
 
 /**
  * Initialize the routes object with specific routes mapping
diff --git a/modules/httpserver-api/api/os.cc b/modules/httpserver-api/api/os.cc
--- a/modules/httpserver-api/api/os.cc
+++ b/modules/httpserver-api/api/os.cc
@@ -33,9 +33,11 @@ using namespace std;
 using namespace json;
 using namespace os_json;
 
+#if !defined(MONITORING)
 extern "C" void httpserver_plugin_register_routes(httpserver::routes* routes) {
     httpserver::api::os::init(*routes);
 }
+#endif
 
 void init(routes& routes)
 {
@@ -83,6 +85,7 @@ void init(routes& routes)
         return memory::get_balloon_size();
     });
 
+#if !defined(MONITORING)
     os_shutdown.set_handler([](const_req req) {
         osv::shutdown();
         return "";
@@ -97,6 +100,7 @@ void init(routes& routes)
         osv::reboot();
         return "";
     });
+#endif
 
     os_dmesg.set_handler([](const_req req) {
         return debug_buffer;
@@ -109,11 +113,13 @@ void init(routes& routes)
         return json_return_type(hostname);
     });
 
+#if !defined(MONITORING)
     os_set_hostname.set_handler([](const_req req) {
         string hostname = req.get_query_param("name");
         sethostname(hostname.c_str(), hostname.size());
         return "";
     });
+#endif
 
     os_threads.set_handler([](const_req req) {
         using namespace std::chrono;
@@ -143,6 +149,7 @@ void init(routes& routes)
         return osv::getcmdline();
     });
 
+#if !defined(MONITORING)
     os_set_cmdline.set_handler([](const_req req) {
         string newcmd = req.get_query_param("cmdline");
 
@@ -157,6 +164,7 @@ void init(routes& routes)
         return osv::getcmdline();
 
     });
+#endif
 
 }
 
diff --git a/modules/httpserver-api/api/trace.cc 
b/modules/httpserver-api/api/trace.cc
--- a/modules/httpserver-api/api/trace.cc
+++ b/modules/httpserver-api/api/trace.cc
@@ -25,7 +25,7 @@ using namespace httpserver::json::trace_json;
 static std::unordered_map<tracepoint_base*,
     std::unique_ptr<tracepoint_counter>> counters;
 
-extern "C" void httpserver_plugin_register_routes(httpserver::routes* routes) {
+extern "C" void __attribute__((visibility("default"))) 
httpserver_plugin_register_routes(httpserver::routes* routes) {
     httpserver::api::trace::init(*routes);
 }
 
diff --git a/modules/httpserver-api/global_server.cc 
b/modules/httpserver-api/global_server.cc
--- a/modules/httpserver-api/global_server.cc
+++ b/modules/httpserver-api/global_server.cc
@@ -13,11 +13,21 @@
 #include <dlfcn.h>
 #include <boost/filesystem.hpp>
 #include <boost/foreach.hpp>
-#include "yaml-cpp/yaml.h"
 #include "json/api_docs.hh"
 #include <osv/debug.h>
 #include "transformers.hh"
 #include <osv/options.hh>
+#if !defined(MONITORING)
+#include "yaml-cpp/yaml.h"
+#else
+#include "api/os.hh"
+#include "api/fs.hh"
+#include "api/file.hh"
+#include "api/network.hh"
+#include "api/hardware.hh"
+#include "api/api.hh"
+#include "api/env.hh"
+#endif
 
 namespace httpserver {
 
@@ -36,6 +46,7 @@ bool 
global_server::run(std::map<std::string,std::vector<std::string>>& _config)
     if (get().s != nullptr) {
         return false;
     }
+#if !defined(MONITORING)
     std::string config_file_path = "/tmp/httpserver.conf";
     if (options::option_value_exists(_config, "config-file")) {
         config_file_path = options::extract_option_value(_config, 
"config-file");
@@ -79,16 +90,19 @@ bool 
global_server::run(std::map<std::string,std::vector<std::string>>& _config)
             throw e;
         }
     }
+#endif
 
     set(_config);
     get().set("ipaddress", "0.0.0.0");
     get().set("port", "8000");
 
+#if !defined(MONITORING)
     if (get().config.count("ssl")) {
         get().set("cert", "/etc/pki/server.pem");
         get().set("key", "/etc/pki/private/server.key");
         get().set("cacert", "/etc/pki/CA/cacert.pem");
     }
+#endif
 
     auto port = get().config["port"][0];
     get().s = new http::server::server(get().config, &get()._routes);
@@ -105,6 +119,7 @@ bool 
global_server::run(std::map<std::string,std::vector<std::string>>& _config)
     return true;
 }
 
+#if !defined(MONITORING)
 void global_server::setup_file_mappings(const YAML::Node& file_mappings_node) {
     for (auto node : file_mappings_node) {
         const YAML::Node path = node["path"];
@@ -154,6 +169,7 @@ void global_server::setup_redirects(const YAML::Node& 
redirects_node) {
         }
     }
 }
+#endif
 
 global_server::global_server()
     : s(nullptr)
@@ -182,7 +198,15 @@ void global_server::set_routes()
 {
     path_holder::set_routes(&_routes);
     json::api_doc_init(_routes);
-
+#if defined(MONITORING)
+    httpserver::api::api::init(_routes);
+    httpserver::api::fs::init(_routes);
+    httpserver::api::os::init(_routes);
+    httpserver::api::network::init(_routes);
+    httpserver::api::hardware::init(_routes);
+    httpserver::api::env::init(_routes);
+    httpserver::api::file::init(_routes);
+#endif
     {
         namespace fs = boost::filesystem;
         fs::path plugin_path("/usr/mgmt/plugins/");
diff --git a/modules/httpserver-api/global_server.hh 
b/modules/httpserver-api/global_server.hh
--- a/modules/httpserver-api/global_server.hh
+++ b/modules/httpserver-api/global_server.hh
@@ -12,7 +12,9 @@
 #include <vector>
 #include <mutex>
 #include <condition_variable>
+#if !defined(MONITORING)
 #include <yaml-cpp/node/iterator.h>
+#endif
 
 namespace httpserver {
 /**
@@ -64,8 +66,10 @@ private:
 
     global_server();
     void set_routes();
+#if !defined(MONITORING)
     void setup_redirects(const YAML::Node& node);
     void setup_file_mappings(const YAML::Node& node);
+#endif
     void load_plugin(const std::string& path);
     static global_server* instance;
     routes _routes;
diff --git a/modules/httpserver-api/handlers.cc 
b/modules/httpserver-api/handlers.cc
--- a/modules/httpserver-api/handlers.cc
+++ b/modules/httpserver-api/handlers.cc
@@ -19,6 +19,7 @@ const std::string handler_base::ERROR_500_PAGE("<h1>Something 
went wrong</h1>");
 const std::string handler_base::ERROR_404_PAGE(
     "<h1>We didn't find the page you were looking for</h1>");
 
+#pragma GCC visibility push(default)
 void handler_base::set_headers_explicit(http::server::reply& rep, const 
std::string& mime)
 {
     const int contentLength = rep.content.size();
@@ -53,6 +54,7 @@ void handler_base::reply500(http::server::reply& rep, const 
std::string& alterna
     rep = 
http::server::reply::stock_reply(http::server::reply::internal_server_error,
                                            &alternative_message);
 }
+#pragma GCC visibility pop
 
 directory_handler::directory_handler(const string& doc_root,
                                      file_transformer* transformer)
@@ -76,6 +78,7 @@ void directory_handler::handle(const string& path, 
parameters* parts,
     read(full_path, req, rep);
 }
 
+#pragma GCC visibility push(default)
 file_interaction_handler::~file_interaction_handler()
 {
     delete transformer;
@@ -128,6 +131,7 @@ bool file_interaction_handler::redirect_if_needed(
     }
     return false;
 }
+#pragma GCC visibility pop
 
 void file_handler::handle(const string& path, parameters* parts,
                           const http::server::request& req, 
http::server::reply& rep)
diff --git a/modules/httpserver-api/handlers.hh 
b/modules/httpserver-api/handlers.hh
--- a/modules/httpserver-api/handlers.hh
+++ b/modules/httpserver-api/handlers.hh
@@ -32,6 +32,7 @@ typedef const http::server::request& const_req;
  * file_handler - map a url path to a file
  * function_handler - uses a lambda expression to handle a reqeust
  */
+#pragma GCC visibility push(default)
 class handler_base {
 public:
     /**
@@ -90,7 +91,7 @@ public:
     virtual void reply500(http::server::reply& rep,
                           const std::string& alternative_message = 
ERROR_500_PAGE);
 
-    /**
+        /**
      * Add a mandatory parameter
      * @param param a parameter name
      * @return a reference to the handler
@@ -107,6 +108,7 @@ public:
     std::vector<std::string> mandatory_param;
 
 };
+#pragma GCC visibility pop
 
 /**
  * This is a base class for file transformer.
@@ -132,6 +134,7 @@ public:
     virtual ~file_transformer() = default;
 };
 
+#pragma GCC visibility push(default)
 /**
  * A base class for handlers that interact with files.
  * directory and file handlers both share some common logic
@@ -188,6 +191,7 @@ protected:
               http::server::reply& rep);
     file_transformer* transformer;
 };
+#pragma GCC visibility pop
 
 /**
  * The directory handler get a disk path in the
diff --git a/modules/httpserver-api/json/api_docs.cc 
b/modules/httpserver-api/json/api_docs.cc
--- a/modules/httpserver-api/json/api_docs.cc
+++ b/modules/httpserver-api/json/api_docs.cc
@@ -43,9 +43,11 @@ class api_registry : public handler_base {
 const string api_registry::base_path = "/api-doc";
 static api_registry* registry = nullptr;
 
+#pragma GCC visibility push(default)
 void register_api(const std::string& api, const std::string& description) {
     registry->reg(api, description);
 }
+#pragma GCC visibility pop
 
 void api_doc_init(routes& _routes) {
     registry = new api_registry(_routes);
diff --git a/modules/httpserver-api/json/api_docs.hh 
b/modules/httpserver-api/json/api_docs.hh
--- a/modules/httpserver-api/json/api_docs.hh
+++ b/modules/httpserver-api/json/api_docs.hh
@@ -87,8 +87,10 @@ struct api_docs : public json::json_base {
     }
 };
 
+#pragma GCC visibility push(default)
 void register_api(const std::string& api,
                   const std::string& description);
+#pragma GCC visibility pop
 
 /**
  * Initialize the routes object with specific routes mapping
diff --git a/modules/httpserver-api/json/formatter.cc 
b/modules/httpserver-api/json/formatter.cc
--- a/modules/httpserver-api/json/formatter.cc
+++ b/modules/httpserver-api/json/formatter.cc
@@ -13,6 +13,7 @@
 
 using namespace std;
 
+#pragma GCC visibility push(default)
 namespace httpserver {
 
 namespace json {
@@ -97,3 +98,4 @@ std::string formatter::json_escape_UTF8_string(const 
std::string& utf8_string) {
 
 }
 }
+#pragma GCC visibility pop
diff --git a/modules/httpserver-api/json/formatter.hh 
b/modules/httpserver-api/json/formatter.hh
--- a/modules/httpserver-api/json/formatter.hh
+++ b/modules/httpserver-api/json/formatter.hh
@@ -12,6 +12,7 @@
 #include <time.h>
 #include <sstream>
 
+#pragma GCC visibility push(default)
 namespace httpserver {
 
 namespace json {
@@ -124,4 +125,5 @@ private:
 
 }
 }
+#pragma GCC visibility pop
 #endif /* FORMATTER_HH_ */
diff --git a/modules/httpserver-api/json/json_elements.cc 
b/modules/httpserver-api/json/json_elements.cc
--- a/modules/httpserver-api/json/json_elements.cc
+++ b/modules/httpserver-api/json/json_elements.cc
@@ -13,6 +13,7 @@
 
 using namespace std;
 
+#pragma GCC visibility push(default)
 namespace httpserver {
 
 namespace json {
@@ -107,3 +108,4 @@ bool json_base::is_verify() const
 
 }
 }
+#pragma GCC visibility pop
\ No newline at end of file
diff --git a/modules/httpserver-api/json/json_elements.hh 
b/modules/httpserver-api/json/json_elements.hh
--- a/modules/httpserver-api/json/json_elements.hh
+++ b/modules/httpserver-api/json/json_elements.hh
@@ -14,6 +14,7 @@
 #include <sstream>
 #include "formatter.hh"
 
+#pragma GCC visibility push(default)
 namespace httpserver {
 
 namespace json {
@@ -224,4 +225,5 @@ struct json_return_type {
 }
 
 }
+#pragma GCC visibility pop
 #endif /* JSON_ELEMENTS_HH_ */
diff --git a/modules/httpserver-api/json/json_path.cc 
b/modules/httpserver-api/json/json_path.cc
--- a/modules/httpserver-api/json/json_path.cc
+++ b/modules/httpserver-api/json/json_path.cc
@@ -7,6 +7,7 @@
 
 #include "json_path.hh"
 
+#pragma GCC visibility push(default)
 namespace httpserver {
 
 namespace json {
@@ -36,3 +37,4 @@ path_description* path_description::get(string nickname)
 }
 
 }
+#pragma GCC visibility pop
\ No newline at end of file
diff --git a/modules/httpserver-api/json/json_path.hh 
b/modules/httpserver-api/json/json_path.hh
--- a/modules/httpserver-api/json/json_path.hh
+++ b/modules/httpserver-api/json/json_path.hh
@@ -14,6 +14,7 @@
 #include <tuple>
 #include "common.hh"
 
+#pragma GCC visibility push(default)
 namespace httpserver {
 
 namespace json {
@@ -142,4 +143,5 @@ struct path_description {
 
 }
 }
+#pragma GCC visibility pop
 #endif /* JSON_PATH_HH_ */
diff --git a/modules/httpserver-api/main.cc b/modules/httpserver-api/main.cc
--- a/modules/httpserver-api/main.cc
+++ b/modules/httpserver-api/main.cc
@@ -40,7 +40,7 @@ static void handle_parse_error(const std::string &message)
     exit(1);
 }
 
-int main(int argc, char* argv[])
+int __attribute__((visibility("default"))) main(int argc, char* argv[])
 {
     auto options_values = options::parse_options_values(argc - 1, argv + 1, 
handle_parse_error);
 
diff --git a/modules/httpserver-api/path_holder.cc 
b/modules/httpserver-api/path_holder.cc
--- a/modules/httpserver-api/path_holder.cc
+++ b/modules/httpserver-api/path_holder.cc
@@ -7,6 +7,7 @@
 #include "path_holder.hh"
 #include <assert.h>
 
+#pragma GCC visibility push(default)
 namespace httpserver {
 
 routes* path_holder::_routes = nullptr;
@@ -36,3 +37,4 @@ handler_base& path_holder::set_handler(const 
json_request_function& fun) const
 }
 
 }
+#pragma GCC visibility pop
\ No newline at end of file
diff --git a/modules/httpserver-api/path_holder.hh 
b/modules/httpserver-api/path_holder.hh
--- a/modules/httpserver-api/path_holder.hh
+++ b/modules/httpserver-api/path_holder.hh
@@ -11,6 +11,7 @@
 #include "handlers.hh"
 #include "routes.hh"
 
+#pragma GCC visibility push(default)
 namespace httpserver {
 /**
  * Path holder glues handlers and implementation.
@@ -89,5 +90,5 @@ private:
 };
 
 }
-
+#pragma GCC visibility pop
 #endif /* PATH_HOLDER_HH_ */
diff --git a/modules/httpserver-api/reply.cc b/modules/httpserver-api/reply.cc
--- a/modules/httpserver-api/reply.cc
+++ b/modules/httpserver-api/reply.cc
@@ -11,6 +11,7 @@
 #include "reply.hh"
 #include <string>
 
+#pragma GCC visibility push(default)
 namespace http {
 
 namespace server {
@@ -239,3 +240,4 @@ reply& reply::add_header(const std::string& h, const 
std::string& value) {
 } // namespace server
 
 } // namespace http
+#pragma GCC visibility pop
\ No newline at end of file
diff --git a/modules/httpserver-api/reply.hh b/modules/httpserver-api/reply.hh
--- a/modules/httpserver-api/reply.hh
+++ b/modules/httpserver-api/reply.hh
@@ -17,6 +17,7 @@
 #include <vector>
 #include <boost/asio.hpp>
 
+#pragma GCC visibility push(default)
 namespace http {
 
 namespace server {
@@ -87,4 +88,5 @@ struct reply {
 
 } // namespace http
 
+#pragma GCC visibility pop
 #endif // HTTP_REPLY_HPP
diff --git a/modules/httpserver-api/server.cc b/modules/httpserver-api/server.cc
--- a/modules/httpserver-api/server.cc
+++ b/modules/httpserver-api/server.cc
@@ -11,23 +11,29 @@
 
 #include "server.hh"
 #include "connection.hh"
+#if !defined(MONITORING)
 #include "ssl_server.hh"
 #include "openssl-init.hh"
+#endif
 #include "plain_server.hh"
 
 #include <utility>
+#if !defined(MONITORING)
 #include <openssl/ssl.h>
+#endif
 #include <osv/options.hh>
 
 namespace http {
 
 namespace server {
 
+#if !defined(MONITORING)
 static bool exists(const std::string& path)
 {
     struct stat s;
     return stat(path.c_str(), &s) == 0;
 }
+#endif
 
 server::server(std::map<std::string,std::vector<std::string>> &config,
                httpserver::routes* routes)
@@ -48,6 +54,7 @@ server::server(std::map<std::string,std::vector<std::string>> 
&config,
     tcp_acceptor.bind(endpoint);
     tcp_acceptor.listen();
 
+#if !defined(MONITORING)
     if (options::extract_option_flag(config, "ssl", [](const std::string 
&message) {
             std::cerr << message << std::endl;
             throw std::runtime_error("invalid configuration");
@@ -81,6 +88,7 @@ server::server(std::map<std::string,std::vector<std::string>> 
&config,
         ssl::context ctx = make_ssl_context(ca_cert_path, cert_path, key_path);
         acceptor_.reset(new ssl_acceptor(io_service_, std::move(ctx), 
std::move(tcp_acceptor)));
     } else {
+#endif
         if (!config.empty()) {
             for (auto option : config) {
                 std::cout << "Unrecognized option: " << option.first << 
std::endl;
@@ -89,7 +97,9 @@ server::server(std::map<std::string,std::vector<std::string>> 
&config,
         }
 
         acceptor_.reset(new plain_acceptor(io_service_, 
std::move(tcp_acceptor)));
+#if !defined(MONITORING)
     }
+#endif
 
     acceptor_->do_accept(std::bind(&server::on_connected, this, 
std::placeholders::_1));
 }

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/0000000000000f881905a1d83294%40google.com.

Reply via email to