Merge remote-tracking branch 'weave/master' into dev_review

* weave/master:
  Revert "Make internal googletest optional."
  Fix incorrect weave setting file path
  Make internal googletest optional.
  Make internal libevhtp optional.
  Periodicly clean up command queue and remove old processed commands
  Changed meaning of some SSID flags
  Rename CommandQueue::DelayedRemove into RemoveLater()
  Fix memory leak when removing CommandInstance from CommandQueue
  Add a unit tests for deleting CloudCommandProxy along with CommandInstance
  Add libevent-dev to README.
  Make default Makefile target "all".
  Replace bleeding-edge libevent with libevhtp.
  Remove crypto type "None"
  Merge: Add write callback into SaveSettings function
  Merge: Add |name| into LoadSettings/SaveSettings

Change-Id: Ia20fbfd59ee3b6287380b6e674b03f038d1b88b3
diff --git a/.gitignore b/.gitignore
index a256906..86c649b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,6 @@
 /out/
 /third_party/include
 /third_party/lib
+/third_party/libevhtp
+/third_party/googletest
 gomacc.lock
diff --git a/Makefile b/Makefile
index de69f40..9810dd0 100644
--- a/Makefile
+++ b/Makefile
@@ -37,7 +37,7 @@
 	-Wwrite-strings
 
 CFLAGS_Debug := \
-	-O0   \
+	-O0 \
 	-g3
 
 CFLAGS_Release := \
@@ -88,7 +88,6 @@
 
 weave_obj_files := $(WEAVE_SRC_FILES:%.cc=out/$(BUILD_MODE)/%.o)
 
-# TODO(jacobmarble): There are too many gtest/gmock deps in non-test targets. Fix.
 $(weave_obj_files) : out/$(BUILD_MODE)/%.o : %.cc
 	mkdir -p $(dir $@)
 	$(CXX) $(DEFS_$(BUILD_MODE)) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
@@ -102,7 +101,8 @@
 clean :
 	rm -rf out
 
-cleanall : clean clean-gtest clean-libevent
+cleanall : clean clean-gtest clean-libevhtp
 
 .PHONY : clean cleanall all
+.DEFAULT_GOAL := all
 
diff --git a/README.md b/README.md
index fc042b7..211033c 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,20 @@
 
 ```
 sudo apt-get update
-sudo apt-get install autoconf automake binutils g++ hostapd libavahi-client-dev libcurl4-openssl-dev libexpat1-dev libnl-3-dev libnl-route-3-dev libssl-dev libtool
+sudo apt-get install \
+  autoconf \
+  automake \
+  binutils \
+  g++ \
+  hostapd \
+  libavahi-client-dev \
+  libcurl4-openssl-dev \
+  libevent-dev \
+  libexpat1-dev \
+  libnl-3-dev \
+  libnl-route-3-dev \
+  libssl-dev \
+  libtool
 ```
 
 # Prerequisites
@@ -72,7 +85,8 @@
   - hostapd
   - libavahi-client-dev
   - libcurl4-openssl-dev
-  - libevent 2.1.x-alpha (included; see third_party/get_libevent.sh)
+  - libevent 2.0.x
+  - libevhtp (included; see third_party/get_libevhtp.sh)
 
 
 # Compiling
@@ -80,19 +94,18 @@
 The `make --jobs/-j` flag is encouraged, to speed up build time. For example
 
 ```
-make all -j
+make -j
 ```
 
+which happens to be the same as
+
+```
+make all -j
+````
+
 ### Build library
 
 ```
-make
-
-```
-
-or
-
-```
 make out/Debug/libweave.so
 ```
 
diff --git a/examples/examples.mk b/examples/examples.mk
index 06266a3..af15d5c 100644
--- a/examples/examples.mk
+++ b/examples/examples.mk
@@ -7,7 +7,13 @@
 
 examples_provider_obj_files := $(EXAMPLES_PROVIDER_SRC_FILES:%.cc=out/$(BUILD_MODE)/%.o)
 
-$(examples_provider_obj_files) : out/$(BUILD_MODE)/%.o : %.cc third_party/include/event2/event.h
+USE_INTERNAL_LIBEVHTP ?= 1
+
+ifeq (1, $(USE_INTERNAL_LIBEVHTP))
+$(examples_provider_obj_files) : third_party/include/evhtp.h
+endif
+
+$(examples_provider_obj_files) : out/$(BUILD_MODE)/%.o : %.cc
 	mkdir -p $(dir $@)
 	$(CXX) $(DEFS_$(BUILD_MODE)) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
 
@@ -15,7 +21,21 @@
 	rm -f $@
 	$(AR) crsT $@ $^
 
-out/$(BUILD_MODE)/examples/daemon/%.o : examples/daemon/%.cc third_party/include/event2/event.h
+EXAMPLES_DAEMON_SRC_FILES := \
+	examples/daemon/ledflasher/ledflasher.cc \
+	examples/daemon/light/light.cc \
+	examples/daemon/lock/lock.cc \
+	examples/daemon/oven/oven.cc \
+	examples/daemon/sample/sample.cc \
+	examples/daemon/speaker/speaker.cc
+
+examples_daemon_obj_files := $(EXAMPLES_DAEMON_SRC_FILES:%.cc=out/$(BUILD_MODE)/%.o)
+
+ifeq (1, $(USE_INTERNAL_LIBEVHTP))
+$(examples_daemon_obj_files) : third_party/include/evhtp.h
+endif
+
+$(examples_daemon_obj_files) : out/$(BUILD_MODE)/%.o : %.cc
 	mkdir -p $(dir $@)
 	$(CXX) $(DEFS_$(BUILD_MODE)) $(INCLUDES) $(CFLAGS) $(CFLAGS_$(BUILD_MODE)) $(CFLAGS_CC) -c -o $@ $<
 
@@ -32,22 +52,30 @@
 	-lssl \
 	-lcrypto
 
-out/$(BUILD_MODE)/weave_daemon_ledflasher : out/$(BUILD_MODE)/examples/daemon/ledflasher/ledflasher.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
+daemon_deps := out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
+
+ifeq (1, $(USE_INTERNAL_LIBEVHTP))
+daemon_deps += third_party/lib/libevhtp.a
+else
+daemon_common_flags += -levhtp
+endif
+
+out/$(BUILD_MODE)/weave_daemon_ledflasher : out/$(BUILD_MODE)/examples/daemon/ledflasher/ledflasher.o $(daemon_deps)
 	$(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
 
-out/$(BUILD_MODE)/weave_daemon_light : out/$(BUILD_MODE)/examples/daemon/light/light.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
+out/$(BUILD_MODE)/weave_daemon_light : out/$(BUILD_MODE)/examples/daemon/light/light.o $(daemon_deps)
 	$(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
 
-out/$(BUILD_MODE)/weave_daemon_lock : out/$(BUILD_MODE)/examples/daemon/lock/lock.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
+out/$(BUILD_MODE)/weave_daemon_lock : out/$(BUILD_MODE)/examples/daemon/lock/lock.o $(daemon_deps)
 	$(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
 
-out/$(BUILD_MODE)/weave_daemon_oven : out/$(BUILD_MODE)/examples/daemon/oven/oven.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
+out/$(BUILD_MODE)/weave_daemon_oven : out/$(BUILD_MODE)/examples/daemon/oven/oven.o $(daemon_deps)
 	$(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
 
-out/$(BUILD_MODE)/weave_daemon_sample : out/$(BUILD_MODE)/examples/daemon/sample/sample.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
+out/$(BUILD_MODE)/weave_daemon_sample : out/$(BUILD_MODE)/examples/daemon/sample/sample.o $(daemon_deps)
 	$(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
 
-out/$(BUILD_MODE)/weave_daemon_speaker : out/$(BUILD_MODE)/examples/daemon/speaker/speaker.o out/$(BUILD_MODE)/examples_provider.a out/$(BUILD_MODE)/libweave.so
+out/$(BUILD_MODE)/weave_daemon_speaker : out/$(BUILD_MODE)/examples/daemon/speaker/speaker.o $(daemon_deps)
 	$(CXX) -o $@ $^ $(CFLAGS) $(daemon_common_flags)
 
 all-examples : out/$(BUILD_MODE)/weave_daemon_ledflasher out/$(BUILD_MODE)/weave_daemon_light out/$(BUILD_MODE)/weave_daemon_lock out/$(BUILD_MODE)/weave_daemon_oven out/$(BUILD_MODE)/weave_daemon_sample out/$(BUILD_MODE)/weave_daemon_speaker
diff --git a/examples/provider/event_deleter.h b/examples/provider/event_deleter.h
index 078c326..9bb53f4 100644
--- a/examples/provider/event_deleter.h
+++ b/examples/provider/event_deleter.h
@@ -7,9 +7,10 @@
 
 #include <memory>
 
-#include <third_party/include/event2/event.h>
-#include <third_party/include/event2/event_struct.h>
-#include <third_party/include/event2/http.h>
+#include <evhtp.h>
+#include <event2/event.h>
+#include <event2/event_struct.h>
+#include <openssl/ssl.h>
 
 namespace weave {
 namespace examples {
@@ -18,9 +19,19 @@
 // so we can use one unique_ptr definition for all of them
 class EventDeleter {
  public:
-  void operator()(evhttp_uri* http_uri) { evhttp_uri_free(http_uri); }
-  void operator()(evhttp_connection* conn) { evhttp_connection_free(conn); }
-  void operator()(evhttp_request* req) { evhttp_request_free(req); }
+  void operator()(evbuffer* buf) { evbuffer_free(buf); }
+  void operator()(evhtp_t* evhtp) {
+    if (evhtp->ssl_ctx) {
+      // Work around a double-free bug in recent versions of libevhtp.
+      // https://github.com/ellzey/libevhtp/pull/208
+      SSL_CTX_free(evhtp->ssl_ctx);
+      evhtp->ssl_ctx = nullptr;
+    }
+    evhtp_unbind_socket(evhtp);
+    evhtp_free(evhtp);
+  }
+  void operator()(evhtp_connection_t* conn) { evhtp_connection_free(conn); }
+  void operator()(evhtp_request_t* req) { evhtp_request_free(req); }
   void operator()(event_base* base) { event_base_free(base); }
   void operator()(event* ev) {
     event_del(ev);
diff --git a/examples/provider/event_http_server.cc b/examples/provider/event_http_server.cc
index ae9833e..1bf58f6 100644
--- a/examples/provider/event_http_server.cc
+++ b/examples/provider/event_http_server.cc
@@ -9,6 +9,7 @@
 #include <base/bind.h>
 #include <base/time/time.h>
 #include <event2/bufferevent_ssl.h>
+#include <evhtp.h>
 #include <openssl/err.h>
 
 #include "examples/provider/event_task_runner.h"
@@ -24,53 +25,45 @@
   return error;
 }
 
-bufferevent* BuffetEventCallback(event_base* base, void* arg) {
-  SSL_CTX* ctx = static_cast<SSL_CTX*>(arg);
-  return bufferevent_openssl_socket_new(
-      base, -1, SSL_new(ctx), BUFFEREVENT_SSL_ACCEPTING, BEV_OPT_CLOSE_ON_FREE);
-}
-
 }  // namespace
 
 class HttpServerImpl::RequestImpl : public Request {
  public:
-  RequestImpl(evhttp_request* req) {
-    req_.reset(req);
-    uri_ = evhttp_request_get_evhttp_uri(req_.get());
-
-    data_.resize(evbuffer_get_length(req_->input_buffer));
-    evbuffer_remove(req_->input_buffer, &data_[0], data_.size());
+  RequestImpl(EventPtr<evhtp_request_t> req) : req_(std::move(req)) {
+    evbuf_t* input_buffer =
+        bufferevent_get_input(evhtp_request_get_bev(req_.get()));
+    data_.resize(evbuffer_get_length(input_buffer));
+    evbuffer_remove(input_buffer, &data_[0], data_.size());
   }
 
   ~RequestImpl() {}
 
-  std::string GetPath() const override {
-    const char* path = evhttp_uri_get_path(uri_);
-    return path ? path : "";
-  }
+  std::string GetPath() const override { return req_->uri->path->path; }
+
   std::string GetFirstHeader(const std::string& name) const override {
-    const char* header = evhttp_find_header(req_->input_headers, name.c_str());
+    const char* header = evhtp_header_find(req_->headers_in, name.c_str());
     if (!header)
       return {};
     return header;
   }
+
   std::string GetData() { return data_; }
 
   void SendReply(int status_code,
                  const std::string& data,
                  const std::string& mime_type) override {
-    std::unique_ptr<evbuffer, decltype(&evbuffer_free)> buf{evbuffer_new(),
-                                                            &evbuffer_free};
+    EventPtr<evbuffer> buf{evbuffer_new()};
     evbuffer_add(buf.get(), data.data(), data.size());
-    evhttp_add_header(req_->output_headers, "Content-Type", mime_type.c_str());
-    evhttp_send_reply(req_.release(), status_code, "None", buf.get());
+    evhtp_header_key_add(req_->headers_out, "Content-Type", 0);
+    evhtp_header_val_add(req_->headers_out, mime_type.c_str(), 1);
+    evhtp_send_reply_start(req_.get(), status_code);
+    evhtp_send_reply_body(req_.get(), buf.get());
+    evhtp_send_reply_end(req_.get());
   }
 
  private:
-  std::unique_ptr<evhttp_request, decltype(&evhttp_cancel_request)> req_{
-      nullptr, &evhttp_cancel_request};
+  EventPtr<evhtp_request_t> req_;
   std::string data_;
-  const evhttp_uri* uri_{nullptr};
 };
 
 HttpServerImpl::HttpServerImpl(EventTaskRunner* task_runner)
@@ -78,74 +71,75 @@
   SSL_load_error_strings();
   SSL_library_init();
 
-  ctx_.reset(SSL_CTX_new(TLSv1_2_server_method()));
-  SSL_CTX_set_options(ctx_.get(), SSL_OP_SINGLE_DH_USE |
-                                      SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_SSLv2);
+  std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)> ctx{
+      SSL_CTX_new(TLSv1_2_server_method()), &SSL_CTX_free};
+  CHECK(ctx);
+  SSL_CTX_set_options(ctx.get(), SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE |
+                                     SSL_OP_NO_SSLv2);
 
-  ec_key_.reset(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
-  CHECK(ec_key_) << GetSslError();
-  CHECK_EQ(1, SSL_CTX_set_tmp_ecdh(ctx_.get(), ec_key_.get())) << GetSslError();
+  std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)> ec_key{
+      EC_KEY_new_by_curve_name(NID_X9_62_prime256v1), &EC_KEY_free};
+  CHECK(ec_key) << GetSslError();
+  CHECK_EQ(1, SSL_CTX_set_tmp_ecdh(ctx.get(), ec_key.get())) << GetSslError();
 
-  GenerateX509();
-  CHECK_EQ(1, SSL_CTX_use_PrivateKey(ctx_.get(), pkey_.get())) << GetSslError();
-  CHECK_EQ(1, SSL_CTX_use_certificate(ctx_.get(), x509_.get()))
-      << GetSslError();
+  std::unique_ptr<X509, decltype(&X509_free)> x509{X509_new(), &X509_free};
+  CHECK(x509);
+  std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> pkey{EVP_PKEY_new(),
+                                                           &EVP_PKEY_free};
+  CHECK(pkey);
+  GenerateX509(x509.get(), pkey.get());
+  CHECK_EQ(1, SSL_CTX_use_PrivateKey(ctx.get(), pkey.get())) << GetSslError();
+  CHECK_EQ(1, SSL_CTX_use_certificate(ctx.get(), x509.get())) << GetSslError();
 
-  CHECK_EQ(1, SSL_CTX_check_private_key(ctx_.get())) << GetSslError();
+  CHECK_EQ(1, SSL_CTX_check_private_key(ctx.get())) << GetSslError();
 
-  httpd_.reset(evhttp_new(task_runner_->GetEventBase()));
+  httpd_.reset(evhtp_new(task_runner_->GetEventBase(), nullptr));
   CHECK(httpd_);
-  httpsd_.reset(evhttp_new(task_runner_->GetEventBase()));
+  httpsd_.reset(evhtp_new(task_runner_->GetEventBase(), nullptr));
   CHECK(httpsd_);
 
-  evhttp_set_bevcb(httpsd_.get(), BuffetEventCallback, ctx_.get());
+  httpsd_.get()->ssl_ctx = ctx.release();
 
-  CHECK_EQ(0, evhttp_bind_socket(httpd_.get(), "0.0.0.0", GetHttpPort()));
-  CHECK_EQ(0, evhttp_bind_socket(httpsd_.get(), "0.0.0.0", GetHttpsPort()));
+  CHECK_EQ(0, evhtp_bind_socket(httpd_.get(), "0.0.0.0", GetHttpPort(), -1));
+  CHECK_EQ(0, evhtp_bind_socket(httpsd_.get(), "0.0.0.0", GetHttpsPort(), -1));
 }
 
-void HttpServerImpl::GenerateX509() {
-  x509_.reset(X509_new());
-  CHECK(x509_) << GetSslError();
+void HttpServerImpl::GenerateX509(X509* x509, EVP_PKEY* pkey) {
+  CHECK(x509) << GetSslError();
 
-  X509_set_version(x509_.get(), 2);
+  X509_set_version(x509, 2);
 
-  X509_gmtime_adj(X509_get_notBefore(x509_.get()), 0);
-  X509_gmtime_adj(X509_get_notAfter(x509_.get()),
+  X509_gmtime_adj(X509_get_notBefore(x509), 0);
+  X509_gmtime_adj(X509_get_notAfter(x509),
                   base::TimeDelta::FromDays(365).InSeconds());
 
-  pkey_.reset(EVP_PKEY_new());
-  CHECK(pkey_) << GetSslError();
+  CHECK(pkey) << GetSslError();
   std::unique_ptr<BIGNUM, decltype(&BN_free)> big_num(BN_new(), &BN_free);
   CHECK(BN_set_word(big_num.get(), 65537)) << GetSslError();
   auto rsa = RSA_new();
   RSA_generate_key_ex(rsa, 2048, big_num.get(), nullptr);
-  CHECK(EVP_PKEY_assign_RSA(pkey_.get(), rsa)) << GetSslError();
+  CHECK(EVP_PKEY_assign_RSA(pkey, rsa)) << GetSslError();
 
-  X509_set_pubkey(x509_.get(), pkey_.get());
+  X509_set_pubkey(x509, pkey);
 
-  CHECK(X509_sign(x509_.get(), pkey_.get(), EVP_sha256())) << GetSslError();
+  CHECK(X509_sign(x509, pkey, EVP_sha256())) << GetSslError();
 
   cert_fingerprint_.resize(EVP_MD_size(EVP_sha256()));
   uint32_t len = 0;
-  CHECK(X509_digest(x509_.get(), EVP_sha256(), cert_fingerprint_.data(), &len));
+  CHECK(X509_digest(x509, EVP_sha256(), cert_fingerprint_.data(), &len));
   CHECK_EQ(len, cert_fingerprint_.size());
 }
 
-void HttpServerImpl::ProcessRequestCallback(evhttp_request* req, void* arg) {
-  static_cast<HttpServerImpl*>(arg)->ProcessRequest(req);
+void HttpServerImpl::NotFound(evhtp_request_t* req) {
+  EventPtr<evbuffer> buf{evbuffer_new()};
+  evbuffer_add_printf(buf.get(), "404 Not Found: %s\n", req->uri->path->path);
+  evhtp_send_reply_start(req, 404);
+  evhtp_send_reply_body(req, buf.get());
+  evhtp_send_reply_end(req);
 }
 
-void HttpServerImpl::NotFound(evhttp_request* req) {
-  std::unique_ptr<evbuffer, decltype(&evbuffer_free)> buf{evbuffer_new(),
-                                                          &evbuffer_free};
-  evbuffer_add_printf(buf.get(), "404 Not Found: %s\n",
-                      evhttp_request_uri(req));
-  evhttp_send_reply(req, 404, "Not Found", buf.get());
-}
-
-void HttpServerImpl::ProcessRequest(evhttp_request* req) {
-  std::unique_ptr<RequestImpl> request{new RequestImpl{req}};
+void HttpServerImpl::ProcessRequest(evhtp_request_t* req) {
+  std::unique_ptr<RequestImpl> request{new RequestImpl{EventPtr<evhtp_request_t>{req}}};
   std::string path = request->GetPath();
   auto it = handlers_.find(path);
   if (it != handlers_.end()) {
@@ -154,25 +148,29 @@
   NotFound(req);
 }
 
-void HttpServerImpl::ProcessReply(std::shared_ptr<RequestImpl> request,
-                                  int status_code,
-                                  const std::string& data,
-                                  const std::string& mime_type) {}
+void HttpServerImpl::ProcessRequestCallback(evhtp_request_t* req, void* arg) {
+  static_cast<HttpServerImpl*>(arg)->ProcessRequest(req);
+}
 
 void HttpServerImpl::AddHttpRequestHandler(
     const std::string& path,
     const RequestHandlerCallback& callback) {
   handlers_.insert(std::make_pair(path, callback));
-  evhttp_set_cb(httpd_.get(), path.c_str(), &ProcessRequestCallback, this);
+  evhtp_set_cb(httpd_.get(), path.c_str(), &ProcessRequestCallback, this);
 }
 
 void HttpServerImpl::AddHttpsRequestHandler(
     const std::string& path,
     const RequestHandlerCallback& callback) {
   handlers_.insert(std::make_pair(path, callback));
-  evhttp_set_cb(httpsd_.get(), path.c_str(), &ProcessRequestCallback, this);
+  evhtp_set_cb(httpsd_.get(), path.c_str(), &ProcessRequestCallback, this);
 }
 
+void HttpServerImpl::ProcessReply(std::shared_ptr<RequestImpl> request,
+                                  int status_code,
+                                  const std::string& data,
+                                  const std::string& mime_type) {}
+
 uint16_t HttpServerImpl::GetHttpPort() const {
   return 7780;
 }
diff --git a/examples/provider/event_http_server.h b/examples/provider/event_http_server.h
index 950e536..8bb5dd9 100644
--- a/examples/provider/event_http_server.h
+++ b/examples/provider/event_http_server.h
@@ -5,8 +5,7 @@
 #ifndef LIBWEAVE_EXAMPLES_PROVIDER_EVENT_HTTP_SERVER_H_
 #define LIBWEAVE_EXAMPLES_PROVIDER_EVENT_HTTP_SERVER_H_
 
-#include <event2/http.h>
-#include <evhttp.h>
+#include <evhtp.h>
 #include <openssl/ssl.h>
 
 #include <map>
@@ -16,12 +15,14 @@
 #include <base/memory/weak_ptr.h>
 #include <weave/provider/http_server.h>
 
+#include "examples/provider/event_deleter.h"
+
 namespace weave {
 namespace examples {
 
 class EventTaskRunner;
 
-// HTTP/HTTPS server implemented with libevent.
+// HTTP/HTTPS server implemented with libevhtp.
 class HttpServerImpl : public provider::HttpServer {
  public:
   class RequestImpl;
@@ -38,32 +39,21 @@
   std::vector<uint8_t> GetHttpsCertificateFingerprint() const override;
 
  private:
-  void GenerateX509();
-  static void ProcessRequestCallback(evhttp_request* req, void* arg);
-  void ProcessRequest(evhttp_request* req);
+  void GenerateX509(X509* x509, EVP_PKEY* pkey);
+  static void ProcessRequestCallback(evhtp_request_t* req, void* arg);
+  void ProcessRequest(evhtp_request_t* req);
   void ProcessReply(std::shared_ptr<RequestImpl> request,
                     int status_code,
                     const std::string& data,
                     const std::string& mime_type);
-  void NotFound(evhttp_request* req);
+  void NotFound(evhtp_request_t* req);
 
   std::map<std::string, RequestHandlerCallback> handlers_;
 
-  std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)> ec_key_{nullptr,
-                                                          &EC_KEY_free};
-
-  std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> pkey_{nullptr,
-                                                            &EVP_PKEY_free};
-
-  std::unique_ptr<X509, decltype(&X509_free)> x509_{nullptr, &X509_free};
-
-  std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)> ctx_{nullptr,
-                                                         &SSL_CTX_free};
   std::vector<uint8_t> cert_fingerprint_;
   EventTaskRunner* task_runner_{nullptr};
-  std::unique_ptr<evhttp, decltype(&evhttp_free)> httpd_{nullptr, &evhttp_free};
-  std::unique_ptr<evhttp, decltype(&evhttp_free)> httpsd_{nullptr,
-                                                          &evhttp_free};
+  EventPtr<evhtp_t> httpd_;
+  EventPtr<evhtp_t> httpsd_;
 
   base::WeakPtrFactory<HttpServerImpl> weak_ptr_factory_{this};
 };
diff --git a/examples/provider/event_task_runner.cc b/examples/provider/event_task_runner.cc
index 1d94612..a86ffff 100644
--- a/examples/provider/event_task_runner.cc
+++ b/examples/provider/event_task_runner.cc
@@ -31,7 +31,9 @@
   int16_t flags = EV_PERSIST | EV_ET;
   flags |= (what & kReadable) ? EV_READ : 0;
   flags |= (what & kWriteable) ? EV_WRITE : 0;
+#if LIBEVENT_VERSION_NUMBER >= 0x02010400
   flags |= (what & kClosed) ? EV_CLOSED : 0;
+#endif
   event* ioevent = event_new(base_.get(), fd, flags, FdEventHandler, this);
   EventPtr<event> ioeventPtr{ioevent};
   fd_task_map_.insert(
@@ -53,7 +55,9 @@
   sigfillset(&sa.sa_mask);
   sigaction(SIGINT, &sa, nullptr);
 
-  event_base_loop(g_event_base, EVLOOP_NO_EXIT_ON_EMPTY);
+  do {
+    event_base_loop(g_event_base, EVLOOP_ONCE);
+  } while (!event_base_got_exit(g_event_base));
   g_event_base = nullptr;
 }
 
diff --git a/examples/provider/file_config_store.cc b/examples/provider/file_config_store.cc
index a6c2e60..b215023 100644
--- a/examples/provider/file_config_store.cc
+++ b/examples/provider/file_config_store.cc
@@ -26,7 +26,7 @@
 
 std::string FileConfigStore::GetPath(const std::string& name) const {
   std::string path{kSettingsDir};
-  path += path + "weave_settings_" + model_id_;
+  path += "weave_settings_" + model_id_;
   if (!name.empty())
     path += "_" + name;
   return path + ".json";
diff --git a/examples/provider/wifi_manager.h b/examples/provider/wifi_manager.h
index 2bfc5ca..72f54df 100644
--- a/examples/provider/wifi_manager.h
+++ b/examples/provider/wifi_manager.h
@@ -35,6 +35,8 @@
                const DoneCallback& callback) override;
   void StartAccessPoint(const std::string& ssid) override;
   void StopAccessPoint() override;
+  bool IsWifi24Supported() const override {return true;};
+  bool IsWifi50Supported() const override {return false;};
 
   static bool HasWifiCapability();
 
diff --git a/include/weave/provider/test/fake_task_runner.h b/include/weave/provider/test/fake_task_runner.h
index bb79455..4080072 100644
--- a/include/weave/provider/test/fake_task_runner.h
+++ b/include/weave/provider/test/fake_task_runner.h
@@ -31,6 +31,7 @@
   void Run(size_t number_of_iterations = 1000);
   void Break();
   base::Clock* GetClock();
+  size_t GetTaskQueueSize() const;
 
  private:
   void SaveTask(const tracked_objects::Location& from_here,
diff --git a/include/weave/provider/test/mock_wifi.h b/include/weave/provider/test/mock_wifi.h
index 9fbe10f..7ede55e 100644
--- a/include/weave/provider/test/mock_wifi.h
+++ b/include/weave/provider/test/mock_wifi.h
@@ -23,6 +23,8 @@
                     const DoneCallback&));
   MOCK_METHOD1(StartAccessPoint, void(const std::string&));
   MOCK_METHOD0(StopAccessPoint, void());
+  MOCK_CONST_METHOD0(IsWifi24Supported, bool());
+  MOCK_CONST_METHOD0(IsWifi50Supported, bool());
 };
 
 }  // namespace test
diff --git a/include/weave/provider/wifi.h b/include/weave/provider/wifi.h
index 48ac651..9c7cfca 100644
--- a/include/weave/provider/wifi.h
+++ b/include/weave/provider/wifi.h
@@ -28,6 +28,9 @@
   // Stops WiFi access point.
   virtual void StopAccessPoint() = 0;
 
+  virtual bool IsWifi24Supported() const = 0;
+  virtual bool IsWifi50Supported() const = 0;
+
  protected:
   virtual ~Wifi() {}
 };
diff --git a/src/access_api_handler_unittest.cc b/src/access_api_handler_unittest.cc
index a142735..3e7f5d7 100644
--- a/src/access_api_handler_unittest.cc
+++ b/src/access_api_handler_unittest.cc
@@ -5,6 +5,7 @@
 #include "src/access_api_handler.h"
 
 #include <gtest/gtest.h>
+#include <weave/provider/test/fake_task_runner.h>
 #include <weave/test/mock_device.h>
 #include <weave/test/unittest_utils.h>
 
@@ -99,7 +100,8 @@
     return std::unique_ptr<base::DictionaryValue>{state->DeepCopy()};
   }
 
-  ComponentManagerImpl component_manager_;
+  StrictMock<provider::test::FakeTaskRunner> task_runner_;
+  ComponentManagerImpl component_manager_{&task_runner_};
   StrictMock<test::MockDevice> device_;
   StrictMock<MockAccessBlackListManager> access_manager_;
   std::unique_ptr<AccessApiHandler> handler_;
diff --git a/src/base_api_handler_unittest.cc b/src/base_api_handler_unittest.cc
index 8b0f0b2..2a202d1 100644
--- a/src/base_api_handler_unittest.cc
+++ b/src/base_api_handler_unittest.cc
@@ -8,6 +8,7 @@
 #include <base/time/default_clock.h>
 #include <base/values.h>
 #include <gtest/gtest.h>
+#include <weave/provider/test/fake_task_runner.h>
 #include <weave/provider/test/mock_config_store.h>
 #include <weave/provider/test/mock_http_client.h>
 #include <weave/test/mock_device.h>
@@ -93,7 +94,8 @@
   Config config_{&config_store_};
   StrictMock<provider::test::MockHttpClient> http_client_;
   std::unique_ptr<DeviceRegistrationInfo> dev_reg_;
-  ComponentManagerImpl component_manager_;
+  StrictMock<provider::test::FakeTaskRunner> task_runner_;
+  ComponentManagerImpl component_manager_{&task_runner_};
   std::unique_ptr<BaseApiHandler> handler_;
   StrictMock<test::MockDevice> device_;
 };
diff --git a/src/commands/cloud_command_proxy.h b/src/commands/cloud_command_proxy.h
index 13f4654..80efd70 100644
--- a/src/commands/cloud_command_proxy.h
+++ b/src/commands/cloud_command_proxy.h
@@ -29,7 +29,7 @@
 }
 
 // Command proxy which publishes command updates to the cloud.
-class CloudCommandProxy final : public CommandInstance::Observer {
+class CloudCommandProxy : public CommandInstance::Observer {
  public:
   CloudCommandProxy(CommandInstance* command_instance,
                     CloudCommandUpdateInterface* cloud_command_updater,
diff --git a/src/commands/cloud_command_proxy_unittest.cc b/src/commands/cloud_command_proxy_unittest.cc
index 013769d..0de67fe 100644
--- a/src/commands/cloud_command_proxy_unittest.cc
+++ b/src/commands/cloud_command_proxy_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <queue>
 
+#include <base/bind.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <weave/provider/test/fake_task_runner.h>
@@ -16,6 +17,7 @@
 #include "src/mock_component_manager.h"
 
 using testing::_;
+using testing::AnyNumber;
 using testing::DoAll;
 using testing::Invoke;
 using testing::Return;
@@ -62,6 +64,27 @@
   base::Time creation_time_;
 };
 
+class CloudCommandProxyWrapper : public CloudCommandProxy {
+ public:
+  CloudCommandProxyWrapper(CommandInstance* command_instance,
+                           CloudCommandUpdateInterface* cloud_command_updater,
+                           ComponentManager* component_manager,
+                           std::unique_ptr<BackoffEntry> backoff_entry,
+                           provider::TaskRunner* task_runner,
+                           const base::Closure& destruct_callback)
+      : CloudCommandProxy{command_instance, cloud_command_updater,
+                          component_manager, std::move(backoff_entry),
+                          task_runner},
+        destruct_callback_{destruct_callback} {}
+
+  ~CloudCommandProxyWrapper() {
+    destruct_callback_.Run();
+  }
+
+ private:
+  base::Closure destruct_callback_;
+};
+
 class CloudCommandProxyTest : public ::testing::Test {
  protected:
   void SetUp() override {
@@ -100,15 +123,21 @@
         new TestBackoffEntry{&policy, task_runner_.GetClock()}};
 
     // Finally construct the CloudCommandProxy we are going to test here.
-    std::unique_ptr<CloudCommandProxy> proxy{new CloudCommandProxy{
+    std::unique_ptr<CloudCommandProxy> proxy{new CloudCommandProxyWrapper{
         command_instance_.get(), &cloud_updater_, &component_manager_,
-        std::move(backoff), &task_runner_}};
+        std::move(backoff), &task_runner_,
+        base::Bind(&CloudCommandProxyTest::OnProxyDestroyed,
+                   base::Unretained(this))}};
     // CloudCommandProxy::CloudCommandProxy() subscribe itself to weave::Command
     // notifications. When weave::Command is being destroyed it sends
     // ::OnCommandDestroyed() and CloudCommandProxy deletes itself.
     proxy.release();
+
+    EXPECT_CALL(*this, OnProxyDestroyed()).Times(AnyNumber());
   }
 
+  MOCK_METHOD0(OnProxyDestroyed, void());
+
   ComponentManager::UpdateID current_state_update_id_{0};
   base::CallbackList<void(ComponentManager::UpdateID)> callbacks_;
   testing::StrictMock<MockCloudCommandUpdateInterface> cloud_updater_;
@@ -120,6 +149,14 @@
 
 }  // anonymous namespace
 
+TEST_F(CloudCommandProxyTest, EnsureDestroyed) {
+  EXPECT_CALL(*this, OnProxyDestroyed()).Times(1);
+  command_instance_.reset();
+  // Verify that CloudCommandProxy has been destroyed already and not at some
+  // point during the destruction of CloudCommandProxyTest class.
+  testing::Mock::VerifyAndClearExpectations(this);
+}
+
 TEST_F(CloudCommandProxyTest, ImmediateUpdate) {
   const char expected[] = "{'state':'done'}";
   EXPECT_CALL(cloud_updater_, UpdateCommand(kCmdID, MatchJson(expected), _));
diff --git a/src/commands/command_instance.cc b/src/commands/command_instance.cc
index fc9b0e7..590bbb1 100644
--- a/src/commands/command_instance.cc
+++ b/src/commands/command_instance.cc
@@ -284,7 +284,7 @@
 
 void CommandInstance::RemoveFromQueue() {
   if (queue_)
-    queue_->DelayedRemove(GetID());
+    queue_->RemoveLater(GetID());
 }
 
 }  // namespace weave
diff --git a/src/commands/command_instance.h b/src/commands/command_instance.h
index b1028d0..febe5c5 100644
--- a/src/commands/command_instance.h
+++ b/src/commands/command_instance.h
@@ -89,10 +89,7 @@
 
   // Sets the pointer to queue this command is part of.
   void AttachToQueue(CommandQueue* queue) { queue_ = queue; }
-  void DetachFromQueue() {
-    observers_.Clear();
-    queue_ = nullptr;
-  }
+  void DetachFromQueue() { queue_ = nullptr; }
 
  private:
   // Helper function to update the command status.
diff --git a/src/commands/command_queue.cc b/src/commands/command_queue.cc
index 134dc1c..f0d2228 100644
--- a/src/commands/command_queue.cc
+++ b/src/commands/command_queue.cc
@@ -18,6 +18,10 @@
 }
 }
 
+CommandQueue::CommandQueue(provider::TaskRunner* task_runner,
+                           base::Clock* clock)
+    : task_runner_{task_runner}, clock_{clock} {}
+
 void CommandQueue::AddCommandAddedCallback(const CommandCallback& callback) {
   on_command_added_.push_back(callback);
   // Send all pre-existed commands.
@@ -84,18 +88,19 @@
     it_handler->second.Run(pair.first->second);
   else if (!default_command_callback_.is_null())
     default_command_callback_.Run(pair.first->second);
-
-  Cleanup();
 }
 
-void CommandQueue::DelayedRemove(const std::string& id) {
+void CommandQueue::RemoveLater(const std::string& id) {
   auto p = map_.find(id);
   if (p == map_.end())
     return;
-  remove_queue_.push(std::make_pair(
-      base::Time::Now() + base::TimeDelta::FromMinutes(kRemoveCommandDelayMin),
-      id));
-  Cleanup();
+  auto remove_delay = base::TimeDelta::FromMinutes(kRemoveCommandDelayMin);
+  remove_queue_.push(std::make_pair(clock_->Now() + remove_delay, id));
+  if (remove_queue_.size() == 1) {
+    // The queue was empty, this is the first command to be removed, schedule
+    // a clean-up task.
+    ScheduleCleanup(remove_delay);
+  }
 }
 
 bool CommandQueue::Remove(const std::string& id) {
@@ -110,19 +115,26 @@
   return true;
 }
 
-void CommandQueue::Cleanup() {
-  while (!remove_queue_.empty() && remove_queue_.front().first < Now()) {
-    Remove(remove_queue_.front().second);
+void CommandQueue::Cleanup(const base::Time& cutoff_time) {
+  while (!remove_queue_.empty() && remove_queue_.top().first <= cutoff_time) {
+    Remove(remove_queue_.top().second);
     remove_queue_.pop();
   }
 }
 
-void CommandQueue::SetNowForTest(base::Time now) {
-  test_now_ = now;
+void CommandQueue::ScheduleCleanup(base::TimeDelta delay) {
+  task_runner_->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&CommandQueue::PerformScheduledCleanup,
+                 weak_ptr_factory_.GetWeakPtr()),
+      delay);
 }
 
-base::Time CommandQueue::Now() const {
-  return test_now_.is_null() ? base::Time::Now() : test_now_;
+void CommandQueue::PerformScheduledCleanup() {
+  base::Time now = clock_->Now();
+  Cleanup(now);
+  if (!remove_queue_.empty())
+    ScheduleCleanup(remove_queue_.top().first - now);
 }
 
 CommandInstance* CommandQueue::Find(const std::string& id) const {
diff --git a/src/commands/command_queue.h b/src/commands/command_queue.h
index 0f0a18b..a092c12 100644
--- a/src/commands/command_queue.h
+++ b/src/commands/command_queue.h
@@ -14,8 +14,10 @@
 
 #include <base/callback.h>
 #include <base/macros.h>
+#include <base/time/default_clock.h>
 #include <base/time/time.h>
 #include <weave/device.h>
+#include <weave/provider/task_runner.h>
 
 #include "src/commands/command_instance.h"
 
@@ -23,7 +25,7 @@
 
 class CommandQueue final {
  public:
-  CommandQueue() = default;
+  CommandQueue(provider::TaskRunner* task_runner, base::Clock* clock);
 
   // TODO: Remove AddCommandAddedCallback and AddCommandRemovedCallback.
   using CommandCallback = base::Callback<void(Command* command)>;
@@ -51,7 +53,7 @@
 
   // Selects command identified by |id| ready for removal. Command will actually
   // be removed after some time.
-  void DelayedRemove(const std::string& id);
+  void RemoveLater(const std::string& id);
 
   // Finds a command instance in the queue by the instance |id|. Returns
   // nullptr if the command with the given |id| is not found. The returned
@@ -64,23 +66,29 @@
   // Removes a command identified by |id| from the queue.
   bool Remove(const std::string& id);
 
-  // Removes old commands selected with DelayedRemove.
-  void Cleanup();
+  // Removes old commands scheduled by RemoveLater() to be deleted after
+  // |cutoff_time|.
+  void Cleanup(const base::Time& cutoff_time);
 
-  // Overrides CommandQueue::Now() for tests.
-  void SetNowForTest(base::Time now);
+  // Schedule a cleanup task to be run after the specified |delay|.
+  void ScheduleCleanup(base::TimeDelta delay);
 
-  // Returns current time.
-  base::Time Now() const;
+  // Perform removal of scheduled commands (by calling Cleanup()) and scheduling
+  // another cleanup task if the removal queue is still not empty.
+  void PerformScheduledCleanup();
 
-  // Overridden value to be returned from Now().
-  base::Time test_now_;
+  provider::TaskRunner* task_runner_{nullptr};
+  base::Clock* clock_{nullptr};
 
   // ID-to-CommandInstance map.
   std::map<std::string, std::shared_ptr<CommandInstance>> map_;
 
-  // Queue of commands to be removed.
-  std::queue<std::pair<base::Time, std::string>> remove_queue_;
+  // Queue of commands to be removed, keeps them sorted by the timestamp
+  // (earliest first). This is done to tolerate system clock changes.
+  template <typename T>
+  using InversePriorityQueue =
+      std::priority_queue<T, std::vector<T>, std::greater<T>>;
+  InversePriorityQueue<std::pair<base::Time, std::string>> remove_queue_;
 
   using CallbackList = std::vector<CommandCallback>;
   CallbackList on_command_added_;
@@ -88,6 +96,9 @@
   std::map<std::string, Device::CommandHandlerCallback> command_callbacks_;
   Device::CommandHandlerCallback default_command_callback_;
 
+  // WeakPtr factory for controlling the lifetime of command queue cleanup
+  // tasks.
+  base::WeakPtrFactory<CommandQueue> weak_ptr_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(CommandQueue);
 };
 
diff --git a/src/commands/command_queue_unittest.cc b/src/commands/command_queue_unittest.cc
index b4c5938..1e2e0ac 100644
--- a/src/commands/command_queue_unittest.cc
+++ b/src/commands/command_queue_unittest.cc
@@ -10,12 +10,18 @@
 
 #include <base/bind.h>
 #include <base/memory/weak_ptr.h>
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <weave/provider/test/fake_task_runner.h>
 
+#include "src/bind_lambda.h"
 #include "src/string_utils.h"
 
 namespace weave {
 
+using testing::Return;
+using testing::StrictMock;
+
 class CommandQueueTest : public testing::Test {
  public:
   std::unique_ptr<CommandInstance> CreateDummyCommandInstance(
@@ -30,11 +36,15 @@
   bool Remove(const std::string& id) { return queue_.Remove(id); }
 
   void Cleanup(const base::TimeDelta& interval) {
-    queue_.SetNowForTest(base::Time::Now() + interval);
-    return queue_.Cleanup();
+    return queue_.Cleanup(task_runner_.GetClock()->Now() + interval);
   }
 
-  CommandQueue queue_;
+  std::string GetFirstCommandToBeRemoved() const {
+    return queue_.remove_queue_.top().second;
+  }
+
+  StrictMock<provider::test::FakeTaskRunner> task_runner_;
+  CommandQueue queue_{&task_runner_, task_runner_.GetClock()};
 };
 
 // Keeps track of commands being added to and removed from the queue_.
@@ -105,12 +115,12 @@
   EXPECT_TRUE(queue_.IsEmpty());
 }
 
-TEST_F(CommandQueueTest, DelayedRemove) {
+TEST_F(CommandQueueTest, RemoveLater) {
   const std::string id1 = "id1";
   queue_.Add(CreateDummyCommandInstance("base.reboot", id1));
   EXPECT_EQ(1u, queue_.GetCount());
 
-  queue_.DelayedRemove(id1);
+  queue_.RemoveLater(id1);
   EXPECT_EQ(1u, queue_.GetCount());
 
   Cleanup(base::TimeDelta::FromMinutes(1));
@@ -120,6 +130,46 @@
   EXPECT_EQ(0u, queue_.GetCount());
 }
 
+TEST_F(CommandQueueTest, RemoveLaterOnCleanupTask) {
+  const std::string id1 = "id1";
+  queue_.Add(CreateDummyCommandInstance("base.reboot", id1));
+  EXPECT_EQ(1u, queue_.GetCount());
+
+  queue_.RemoveLater(id1);
+  EXPECT_EQ(1u, queue_.GetCount());
+  ASSERT_EQ(1u, task_runner_.GetTaskQueueSize());
+
+  task_runner_.RunOnce();
+
+  EXPECT_EQ(0u, queue_.GetCount());
+  EXPECT_EQ(0u, task_runner_.GetTaskQueueSize());
+}
+
+TEST_F(CommandQueueTest, CleanupMultipleCommands) {
+  const std::string id1 = "id1";
+  const std::string id2 = "id2";
+
+  queue_.Add(CreateDummyCommandInstance("base.reboot", id1));
+  queue_.Add(CreateDummyCommandInstance("base.reboot", id2));
+  auto remove_task = [this](const std::string& id) { queue_.RemoveLater(id); };
+  remove_task(id1);
+  task_runner_.PostDelayedTask(FROM_HERE, base::Bind(remove_task, id2),
+                               base::TimeDelta::FromSeconds(10));
+  EXPECT_EQ(2u, queue_.GetCount());
+  ASSERT_EQ(2u, task_runner_.GetTaskQueueSize());
+  task_runner_.RunOnce();  // Executes "remove_task(id2) @ T+10s".
+  ASSERT_EQ(2u, queue_.GetCount());
+  ASSERT_EQ(1u, task_runner_.GetTaskQueueSize());
+  EXPECT_EQ(id1, GetFirstCommandToBeRemoved());
+  task_runner_.RunOnce();  // Should remove task "id1" from queue.
+  ASSERT_EQ(1u, queue_.GetCount());
+  ASSERT_EQ(1u, task_runner_.GetTaskQueueSize());
+  EXPECT_EQ(id2, GetFirstCommandToBeRemoved());
+  task_runner_.RunOnce();  // Should remove task "id2" from queue.
+  EXPECT_EQ(0u, queue_.GetCount());
+  EXPECT_EQ(0u, task_runner_.GetTaskQueueSize());
+}
+
 TEST_F(CommandQueueTest, Dispatch) {
   FakeDispatcher dispatch(&queue_);
   const std::string id1 = "id1";
diff --git a/src/component_manager_impl.cc b/src/component_manager_impl.cc
index 550775d..dec4a48 100644
--- a/src/component_manager_impl.cc
+++ b/src/component_manager_impl.cc
@@ -31,8 +31,10 @@
 LIBWEAVE_EXPORT EnumToStringMap<UserRole>::EnumToStringMap()
     : EnumToStringMap(kMap) {}
 
-ComponentManagerImpl::ComponentManagerImpl(base::Clock* clock)
-    : clock_{clock ? clock : &default_clock_} {}
+ComponentManagerImpl::ComponentManagerImpl(provider::TaskRunner* task_runner,
+                                           base::Clock* clock)
+    : clock_{clock ? clock : &default_clock_},
+      command_queue_{task_runner, clock_} {}
 
 ComponentManagerImpl::~ComponentManagerImpl() {}
 
diff --git a/src/component_manager_impl.h b/src/component_manager_impl.h
index 8c4ad16..f3c5451 100644
--- a/src/component_manager_impl.h
+++ b/src/component_manager_impl.h
@@ -15,7 +15,8 @@
 
 class ComponentManagerImpl final : public ComponentManager {
  public:
-  explicit ComponentManagerImpl(base::Clock* clock = nullptr);
+  explicit ComponentManagerImpl(provider::TaskRunner* task_runner,
+                                base::Clock* clock = nullptr);
   ~ComponentManagerImpl() override;
 
   // Loads trait definition schema.
diff --git a/src/component_manager_unittest.cc b/src/component_manager_unittest.cc
index 63fedac..97dc00d 100644
--- a/src/component_manager_unittest.cc
+++ b/src/component_manager_unittest.cc
@@ -7,6 +7,7 @@
 #include <map>
 
 #include <gtest/gtest.h>
+#include <weave/provider/test/fake_task_runner.h>
 #include <weave/test/unittest_utils.h>
 
 #include "src/bind_lambda.h"
@@ -90,8 +91,9 @@
                                       {"t5", "t6"}, nullptr));
   }
 
+  StrictMock<provider::test::FakeTaskRunner> task_runner_;
   StrictMock<test::MockClock> clock_;
-  ComponentManagerImpl manager_{&clock_};
+  ComponentManagerImpl manager_{&task_runner_, &clock_};
 };
 
 }  // anonymous namespace
diff --git a/src/device_manager.cc b/src/device_manager.cc
index 8eed558..deb5404 100644
--- a/src/device_manager.cc
+++ b/src/device_manager.cc
@@ -31,7 +31,7 @@
                              provider::Wifi* wifi,
                              provider::Bluetooth* bluetooth)
     : config_{new Config{config_store}},
-      component_manager_{new ComponentManagerImpl} {
+      component_manager_{new ComponentManagerImpl{task_runner}} {
   if (http_server) {
     auth_manager_.reset(new privet::AuthManager(
         config_.get(), http_server->GetHttpsCertificateFingerprint()));
diff --git a/src/device_registration_info_unittest.cc b/src/device_registration_info_unittest.cc
index cd11ac9..7908c8b 100644
--- a/src/device_registration_info_unittest.cc
+++ b/src/device_registration_info_unittest.cc
@@ -208,7 +208,7 @@
       {},
       &clock_};
   std::unique_ptr<DeviceRegistrationInfo> dev_reg_;
-  ComponentManagerImpl component_manager_;
+  ComponentManagerImpl component_manager_{&task_runner_};
 };
 
 TEST_F(DeviceRegistrationInfoTest, GetServiceURL) {
diff --git a/src/privet/wifi_bootstrap_manager.cc b/src/privet/wifi_bootstrap_manager.cc
index 566da80..ce2016a 100644
--- a/src/privet/wifi_bootstrap_manager.cc
+++ b/src/privet/wifi_bootstrap_manager.cc
@@ -204,8 +204,12 @@
 }
 
 std::set<WifiType> WifiBootstrapManager::GetTypes() const {
-  // TODO(wiley) This should do some system work to figure this out.
-  return {WifiType::kWifi24};
+  std::set<WifiType> result;
+  if (wifi_->IsWifi24Supported())
+    result.insert(WifiType::kWifi24);
+  if (wifi_->IsWifi50Supported())
+    result.insert(WifiType::kWifi50);
+  return result;
 }
 
 void WifiBootstrapManager::OnConnectDone(const std::string& ssid,
@@ -255,9 +259,15 @@
 
 void WifiBootstrapManager::UpdateConnectionState() {
   connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
-
   Network::State service_state{network_->GetConnectionState()};
   VLOG(3) << "New network state: " << EnumToString(service_state);
+
+  // TODO: Make it true wifi state, currently it's rather online state.
+  if (service_state != Network::State::kOnline &&
+      config_->GetSettings().last_configured_ssid.empty()) {
+    return;
+  }
+
   switch (service_state) {
     case Network::State::kOffline:
       connection_state_ = ConnectionState{ConnectionState::kOffline};
diff --git a/src/privet/wifi_ssid_generator.cc b/src/privet/wifi_ssid_generator.cc
index 697e5d8..4ad1602 100644
--- a/src/privet/wifi_ssid_generator.cc
+++ b/src/privet/wifi_ssid_generator.cc
@@ -52,20 +52,27 @@
 }
 
 std::string WifiSsidGenerator::GenerateFlags() const {
-  return GenerateFlagsInternal(false);
+  return GenerateFlagsInternal();
 }
 
-std::string WifiSsidGenerator::GenerateFlagsInternal(bool for_ssid) const {
+std::string WifiSsidGenerator::GenerateFlagsInternal() const {
   std::bitset<6> flags1;
   // Device needs WiFi configuration.
   flags1[0] = wifi_ && IsSetupNeeded(wifi_->GetConnectionState());
+
   // Device needs GCD registration.
   flags1[1] = IsSetupNeeded(gcd_->GetConnectionState());
 
   std::bitset<6> flags2;
 
-  // Device is discoverable over WiFi.
-  flags2[0] = for_ssid || (wifi_ && !wifi_->GetHostedSsid().empty());
+  if (wifi_) {
+    std::set<WifiType> types = wifi_->GetTypes();
+    // Device supports 2.4Ghz WiFi networks.
+    flags2[0] = types.find(WifiType::kWifi24) != types.end();
+
+    // Device supports 5.0Ghz WiFi networks.
+    flags2[1] = types.find(WifiType::kWifi50) != types.end();
+  }
 
   std::string result{2, base64chars[0]};
   result[0] = base64chars[flags1.to_ulong()];
@@ -82,7 +89,7 @@
 
   std::string result =
       base::StringPrintf(kSsidFormat, name.c_str(), idx.c_str(),
-                         model_id.c_str(), GenerateFlagsInternal(true).c_str());
+                         model_id.c_str(), GenerateFlagsInternal().c_str());
   CHECK_EQ(result[result.size() - 11], '.');
   return result;
 }
diff --git a/src/privet/wifi_ssid_generator.h b/src/privet/wifi_ssid_generator.h
index 2b86f28..1197e73 100644
--- a/src/privet/wifi_ssid_generator.h
+++ b/src/privet/wifi_ssid_generator.h
@@ -30,7 +30,7 @@
 
   // Sets object to use |n| instead of random number for SSID generation.
   void SetRandomForTests(int n);
-  std::string GenerateFlagsInternal(bool for_ssid) const;
+  std::string GenerateFlagsInternal() const;
 
   const CloudDelegate* gcd_{nullptr};
   const WifiDelegate* wifi_{nullptr};
diff --git a/src/privet/wifi_ssid_generator_unittest.cc b/src/privet/wifi_ssid_generator_unittest.cc
index 10680c8..406576d 100644
--- a/src/privet/wifi_ssid_generator_unittest.cc
+++ b/src/privet/wifi_ssid_generator_unittest.cc
@@ -22,26 +22,10 @@
   WifiSsidGenerator ssid_generator_{&gcd_, &wifi_};
 };
 
-TEST_F(WifiSsidGeneratorTest, GenerateFlagsNoHostedAp) {
-  EXPECT_EQ(ssid_generator_.GenerateFlags().size(), 2u);
+TEST_F(WifiSsidGeneratorTest, GenerateFlagsWithWifi24) {
+  EXPECT_CALL(wifi_, GetTypes())
+      .WillRepeatedly(Return(std::set<WifiType>{WifiType::kWifi24}));
 
-  wifi_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
-  gcd_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
-  EXPECT_EQ("DA", ssid_generator_.GenerateFlags());
-
-  wifi_.connection_state_ = ConnectionState{ConnectionState::kOnline};
-  EXPECT_EQ("CA", ssid_generator_.GenerateFlags());
-
-  gcd_.connection_state_ = ConnectionState{ConnectionState::kOffline};
-  EXPECT_EQ("AA", ssid_generator_.GenerateFlags());
-
-  wifi_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
-  EXPECT_EQ("BA", ssid_generator_.GenerateFlags());
-}
-
-TEST_F(WifiSsidGeneratorTest, GenerateFlagsWithHostedAp) {
-  EXPECT_CALL(wifi_, GetHostedSsid())
-      .WillRepeatedly(Return(ssid_generator_.GenerateSsid()));
   EXPECT_EQ(ssid_generator_.GenerateFlags().size(), 2u);
 
   wifi_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
@@ -58,6 +42,26 @@
   EXPECT_EQ("BB", ssid_generator_.GenerateFlags());
 }
 
+TEST_F(WifiSsidGeneratorTest, GenerateFlagsWithWifi50) {
+  EXPECT_CALL(wifi_, GetTypes())
+      .WillRepeatedly(Return(std::set<WifiType>{WifiType::kWifi50}));
+
+  EXPECT_EQ(ssid_generator_.GenerateFlags().size(), 2u);
+
+  wifi_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
+  gcd_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
+  EXPECT_EQ("DC", ssid_generator_.GenerateFlags());
+
+  wifi_.connection_state_ = ConnectionState{ConnectionState::kOnline};
+  EXPECT_EQ("CC", ssid_generator_.GenerateFlags());
+
+  gcd_.connection_state_ = ConnectionState{ConnectionState::kOffline};
+  EXPECT_EQ("AC", ssid_generator_.GenerateFlags());
+
+  wifi_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
+  EXPECT_EQ("BC", ssid_generator_.GenerateFlags());
+}
+
 TEST_F(WifiSsidGeneratorTest, GenerateSsid31orLess) {
   EXPECT_LE(ssid_generator_.GenerateSsid().size(), 31u);
 }
diff --git a/src/test/fake_task_runner.cc b/src/test/fake_task_runner.cc
index 88e078b..68d5e32 100644
--- a/src/test/fake_task_runner.cc
+++ b/src/test/fake_task_runner.cc
@@ -52,6 +52,10 @@
   queue_.emplace(std::make_pair(test_clock_->Now() + delay, ++counter_), task);
 }
 
+size_t FakeTaskRunner::GetTaskQueueSize() const {
+  return queue_.size();
+}
+
 }  // namespace test
 }  // namespace provider
 }  // namespace weave
diff --git a/src/weave_unittest.cc b/src/weave_unittest.cc
index ebc66cd..b300f57 100644
--- a/src/weave_unittest.cc
+++ b/src/weave_unittest.cc
@@ -181,7 +181,10 @@
 
 class WeaveTest : public ::testing::Test {
  protected:
-  void SetUp() override {}
+  void SetUp() override {
+    EXPECT_CALL(wifi_, IsWifi24Supported()).WillRepeatedly(Return(true));
+    EXPECT_CALL(wifi_, IsWifi50Supported()).WillRepeatedly(Return(false));
+  }
 
   template <class UrlMatcher>
   void ExpectRequest(HttpClient::Method method,
diff --git a/third_party/get_libevent.sh b/third_party/get_libevent.sh
deleted file mode 100755
index 9985bc0..0000000
--- a/third_party/get_libevent.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/bash
-# Copyright 2015 The Weave Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Make libevent.
-# Example uses libevent to implement HTTPS server. This capability is
-# available only in version 2.1.x-alpha. Step could be replaced with apt-get
-# in future.
-cd $(dirname "$0")
-THIRD_PARTY=$(pwd)
-
-mkdir -p include lib
-
-rm -rf $THIRD_PARTY/libevent
-git clone https://github.com/libevent/libevent.git || exit 1
-cd libevent || exit 1
-
-./autogen.sh || exit 1
-./configure --disable-shared || exit 1
-make || exit 1
-if [ -z "$DISABLE_LIBEVENT_TEST" ]; then
-  echo -e "\n\nTesting libevent...\nCan take several minutes.\n"
-  make verify || exit 1
-fi
-cp -rf include/*.h include/event2 $THIRD_PARTY/include/ || exit 1
-cp -f .libs/lib* $THIRD_PARTY/lib/ || exit 1
-
-rm -rf $THIRD_PARTY/libevent
diff --git a/third_party/get_libevhtp.sh b/third_party/get_libevhtp.sh
new file mode 100755
index 0000000..c270813
--- /dev/null
+++ b/third_party/get_libevhtp.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# Copyright 2016 The Weave Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Make libevhtp.
+# Example uses libevhtp to implement HTTPS server. This step could be
+# replaced with apt-get in future (Debian jessie, Ubuntu vivid).
+cd $(dirname "$0")
+THIRD_PARTY=$(pwd)
+
+mkdir -p include lib
+
+rm -rf $THIRD_PARTY/libevhtp
+curl -L https://github.com/ellzey/libevhtp/archive/1.2.10.tar.gz | tar xz || exit 1
+mv libevhtp-1.2.10 $THIRD_PARTY/libevhtp || exit 1
+cd $THIRD_PARTY/libevhtp || exit 1
+
+cmake -D EVHTP_DISABLE_REGEX:BOOL=ON . || exit 1
+make evhtp || exit 1
+
+cp -rf evhtp-config.h evhtp.h evthr/evthr.h htparse/htparse.h $THIRD_PARTY/include/ || exit 1
+cp -f libevhtp.a $THIRD_PARTY/lib/ || exit 1
+
+rm -rf $THIRD_PARTY/libevhtp
diff --git a/third_party/third_party.mk b/third_party/third_party.mk
index 8a11e2d..7f651a2 100644
--- a/third_party/third_party.mk
+++ b/third_party/third_party.mk
@@ -64,15 +64,15 @@
 	rm -rf third_party/googletest
 
 ###
-# libevent (third_party, downloaded on build)
+# libevhtp (third_party, downloaded on build)
 
-third_party/include/event2/event.h :
-	@echo Downloading and building libevent...
-	DISABLE_LIBEVENT_TEST=1 third_party/get_libevent.sh
-	@echo Finished downloading and building libevent.
+third_party/lib/libevhtp.a : third_party/include/evhtp.h
+third_party/include/evhtp.h :
+	@echo Downloading and building libevhtp...
+	third_party/get_libevhtp.sh
+	@echo Finished downloading and building libevhtp.
 
-clean-libevent :
-	rm -rf third_party/include/ev* third_party/include/event2
-	rm -rf third_party/lib/libevent*
-	rm -rf third_party/libevent
-
+clean-libevhtp :
+	rm -rf third_party/include/evhtp.h third_party/include/evhtp-config.h third_party/include/evthr.h third_party/include/htparse.h
+	rm -rf third_party/lib/libevhtp.a
+	rm -rf third_party/libevhtp