aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitaly Buka <vitalybuka@google.com>2016-02-03 16:37:28 -0800
committerVitaly Buka <vitalybuka@google.com>2016-02-03 16:49:26 -0800
commitff46c9361512be430b2aea0e8e11b51c2b9671b5 (patch)
tree3836a79d53e7ab607d6c0b89ccd6cc8eefe30cb7
parent08be74de678930e6823f9fe7e460c35bb58040f9 (diff)
parent51c4d0d3184dfb5f2601367f06a46459126f377d (diff)
downloadlibweave-ff46c9361512be430b2aea0e8e11b51c2b9671b5.tar.gz
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
-rw-r--r--.gitignore2
-rw-r--r--Makefile6
-rw-r--r--README.md29
-rw-r--r--examples/examples.mk44
-rw-r--r--examples/provider/event_deleter.h23
-rw-r--r--examples/provider/event_http_server.cc146
-rw-r--r--examples/provider/event_http_server.h30
-rw-r--r--examples/provider/event_task_runner.cc6
-rw-r--r--examples/provider/file_config_store.cc2
-rw-r--r--examples/provider/wifi_manager.h2
-rw-r--r--include/weave/provider/test/fake_task_runner.h1
-rw-r--r--include/weave/provider/test/mock_wifi.h2
-rw-r--r--include/weave/provider/wifi.h3
-rw-r--r--src/access_api_handler_unittest.cc4
-rw-r--r--src/base_api_handler_unittest.cc4
-rw-r--r--src/commands/cloud_command_proxy.h2
-rw-r--r--src/commands/cloud_command_proxy_unittest.cc41
-rw-r--r--src/commands/command_instance.cc2
-rw-r--r--src/commands/command_instance.h5
-rw-r--r--src/commands/command_queue.cc40
-rw-r--r--src/commands/command_queue.h35
-rw-r--r--src/commands/command_queue_unittest.cc60
-rw-r--r--src/component_manager_impl.cc6
-rw-r--r--src/component_manager_impl.h3
-rw-r--r--src/component_manager_unittest.cc4
-rw-r--r--src/device_manager.cc2
-rw-r--r--src/device_registration_info_unittest.cc2
-rw-r--r--src/privet/wifi_bootstrap_manager.cc16
-rw-r--r--src/privet/wifi_ssid_generator.cc17
-rw-r--r--src/privet/wifi_ssid_generator.h2
-rw-r--r--src/privet/wifi_ssid_generator_unittest.cc28
-rw-r--r--src/test/fake_task_runner.cc4
-rw-r--r--src/weave_unittest.cc5
-rwxr-xr-xthird_party/get_libevent.sh29
-rwxr-xr-xthird_party/get_libevhtp.sh25
-rw-r--r--third_party/third_party.mk24
36 files changed, 425 insertions, 231 deletions
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 @@ CFLAGS := \
-Wwrite-strings
CFLAGS_Debug := \
- -O0 \
+ -O0 \
-g3
CFLAGS_Release := \
@@ -88,7 +88,6 @@ include file_lists.mk third_party/third_party.mk examples/examples.mk tests.mk
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 @@ all : out/$(BUILD_MODE)/libweave.so all-examples out/$(BUILD_MODE)/libweave_expo
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 @@ repo sync
```
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 @@ sudo apt-get install autoconf automake binutils g++ hostapd libavahi-client-dev
- 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,17 +94,16 @@ sudo apt-get install autoconf automake binutils g++ hostapd libavahi-client-dev
The `make --jobs/-j` flag is encouraged, to speed up build time. For example
```
-make all -j
+make -j
```
-### Build library
-
-```
-make
+which happens to be the same as
```
+make all -j
+````
-or
+### Build library
```
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 @@ out/$(BUILD_MODE)/examples_provider.a : $(examples_provider_obj_files)
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 @@ daemon_common_flags := \
-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 @@ namespace examples {
// 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 @@ std::string GetSslError() {
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 @@ HttpServerImpl::HttpServerImpl(EventTaskRunner* task_runner)
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);
-
- 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();
-
- 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();
-
- CHECK_EQ(1, SSL_CTX_check_private_key(ctx_.get())) << GetSslError();
-
- httpd_.reset(evhttp_new(task_runner_->GetEventBase()));
+ 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);
+
+ 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();
+
+ 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();
+
+ 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(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::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::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 @@ void HttpServerImpl::ProcessRequest(evhttp_request* req) {
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 @@ class HttpServerImpl : public provider::HttpServer {
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 @@ void EventTaskRunner::AddIoCompletionTask(
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 @@ void EventTaskRunner::Run() {
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 @@ FileConfigStore::FileConfigStore(const std::string& model_id,
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 @@ class WifiImpl : public provider::Wifi {
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 @@ class FakeTaskRunner : public TaskRunner {
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 @@ class MockWifi : public Wifi {
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 @@ class Wifi {
// 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 @@ class AccessApiHandlerTest : public ::testing::Test {
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 @@ class BaseApiHandlerTest : public ::testing::Test {
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 @@ class TaskRunner;
}
// 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 @@ class TestBackoffEntry : public BackoffEntry {
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 @@ class CloudCommandProxyTest : public ::testing::Test {
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 @@ class CloudCommandProxyTest : public ::testing::Test {
} // 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 @@ bool CommandInstance::SetStatus(Command::State status, ErrorPtr* error) {
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 @@ class CommandInstance final : public Command {
// 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 @@ std::string GetCommandHandlerKey(const std::string& component_path,
}
}
+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 @@ void CommandQueue::Add(std::unique_ptr<CommandInstance> instance) {
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 @@ bool CommandQueue::Remove(const std::string& id) {
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 @@ namespace weave {
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 @@ class CommandQueue final {
// 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 @@ class CommandQueue final {
// 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 @@ class CommandQueue final {
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 @@ class CommandQueueTest : public testing::Test {
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);
+ }
+
+ std::string GetFirstCommandToBeRemoved() const {
+ return queue_.remove_queue_.top().second;
}
- CommandQueue queue_;
+ 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 @@ TEST_F(CommandQueueTest, Remove) {
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 @@ TEST_F(CommandQueueTest, DelayedRemove) {
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 @@ template <>
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 @@ namespace weave {
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 @@ class ComponentManagerTest : public ::testing::Test {
{"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 @@ DeviceManager::DeviceManager(provider::ConfigStore* config_store,
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 @@ class DeviceRegistrationInfoTest : public ::testing::Test {
{},
&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::string WifiBootstrapManager::GetHostedSsid() const {
}
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::OnMonitorTimeout() {
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 @@ WifiSsidGenerator::WifiSsidGenerator(const CloudDelegate* cloud,
}
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 WifiSsidGenerator::GenerateSsid() const {
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 @@ class WifiSsidGenerator final {
// 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,40 +22,44 @@ class WifiSsidGeneratorTest : public testing::Test {
WifiSsidGenerator ssid_generator_{&gcd_, &wifi_};
};
-TEST_F(WifiSsidGeneratorTest, GenerateFlagsNoHostedAp) {
+TEST_F(WifiSsidGeneratorTest, GenerateFlagsWithWifi24) {
+ EXPECT_CALL(wifi_, GetTypes())
+ .WillRepeatedly(Return(std::set<WifiType>{WifiType::kWifi24}));
+
EXPECT_EQ(ssid_generator_.GenerateFlags().size(), 2u);
wifi_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
gcd_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
- EXPECT_EQ("DA", ssid_generator_.GenerateFlags());
+ EXPECT_EQ("DB", ssid_generator_.GenerateFlags());
wifi_.connection_state_ = ConnectionState{ConnectionState::kOnline};
- EXPECT_EQ("CA", ssid_generator_.GenerateFlags());
+ EXPECT_EQ("CB", ssid_generator_.GenerateFlags());
gcd_.connection_state_ = ConnectionState{ConnectionState::kOffline};
- EXPECT_EQ("AA", ssid_generator_.GenerateFlags());
+ EXPECT_EQ("AB", ssid_generator_.GenerateFlags());
wifi_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
- EXPECT_EQ("BA", ssid_generator_.GenerateFlags());
+ EXPECT_EQ("BB", ssid_generator_.GenerateFlags());
}
-TEST_F(WifiSsidGeneratorTest, GenerateFlagsWithHostedAp) {
- EXPECT_CALL(wifi_, GetHostedSsid())
- .WillRepeatedly(Return(ssid_generator_.GenerateSsid()));
+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("DB", ssid_generator_.GenerateFlags());
+ EXPECT_EQ("DC", ssid_generator_.GenerateFlags());
wifi_.connection_state_ = ConnectionState{ConnectionState::kOnline};
- EXPECT_EQ("CB", ssid_generator_.GenerateFlags());
+ EXPECT_EQ("CC", ssid_generator_.GenerateFlags());
gcd_.connection_state_ = ConnectionState{ConnectionState::kOffline};
- EXPECT_EQ("AB", ssid_generator_.GenerateFlags());
+ EXPECT_EQ("AC", ssid_generator_.GenerateFlags());
wifi_.connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
- EXPECT_EQ("BB", ssid_generator_.GenerateFlags());
+ EXPECT_EQ("BC", ssid_generator_.GenerateFlags());
}
TEST_F(WifiSsidGeneratorTest, GenerateSsid31orLess) {
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 @@ void FakeTaskRunner::PostDelayedTask(const tracked_objects::Location& from_here,
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 @@ std::set<typename Map::key_type> GetKeys(const Map& map) {
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 @@ clean-gtest :
rm -rf third_party/googletest
###
-# libevent (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.
-
-clean-libevent :
- rm -rf third_party/include/ev* third_party/include/event2
- rm -rf third_party/lib/libevent*
- rm -rf third_party/libevent
-
+# libevhtp (third_party, downloaded on build)
+
+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-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